[xmpp] Websockets: streams or not streams?

Matthew Wild <mwild1@gmail.com> Wed, 23 October 2013 00:08 UTC

Return-Path: <mwild1@gmail.com>
X-Original-To: xmpp@ietfa.amsl.com
Delivered-To: xmpp@ietfa.amsl.com
Received: from localhost (localhost [127.0.0.1]) by ietfa.amsl.com (Postfix) with ESMTP id 7353E11E8114 for <xmpp@ietfa.amsl.com>; Tue, 22 Oct 2013 17:08:11 -0700 (PDT)
X-Virus-Scanned: amavisd-new at amsl.com
X-Spam-Flag: NO
X-Spam-Score: -2
X-Spam-Level:
X-Spam-Status: No, score=-2 tagged_above=-999 required=5 tests=[BAYES_00=-2.599, J_CHICKENPOX_66=0.6, NO_RELAYS=-0.001]
Received: from mail.ietf.org ([12.22.58.30]) by localhost (ietfa.amsl.com [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id RSh8VUcIadf8 for <xmpp@ietfa.amsl.com>; Tue, 22 Oct 2013 17:08:10 -0700 (PDT)
Received: from mail-vb0-x231.google.com (mail-vb0-x231.google.com [IPv6:2607:f8b0:400c:c02::231]) by ietfa.amsl.com (Postfix) with ESMTP id 6B16B11E829A for <xmpp@ietf.org>; Tue, 22 Oct 2013 17:08:06 -0700 (PDT)
Received: by mail-vb0-f49.google.com with SMTP id w16so40499vbb.8 for <xmpp@ietf.org>; Tue, 22 Oct 2013 17:08:05 -0700 (PDT)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=mime-version:from:date:message-id:subject:to:content-type; bh=//ISZxSyplFGcELO22wzYwpEOOKjrTW/y4u/Whl1RZA=; b=a19E23bL5yMkcT9iVJH4LKdsMrT/n1Lkz3Yz8cstBsjHOqJ6lf3Hv8DkS3d2owSbmK 81BZtR20144P1ffOrA5Mqo2Aag+YbASFBIyLAxhTh9ZS8J8pRTQtYcwA0Qdx6QpTVTns IIsBG81N68e1uPOhWTDDYJjJRsoo6CkLY1uSrb4lnxoA+LrK3TQrBUl/6WNXMsKEDI7/ kaLz2oSO02IKeEn87M1AK1FPvxom5nC6UuQqe3EddA/tMRvUZqiSamw/wLmaMCqkrcKq e3+6Qr7fudV2y016H6RiwbhgPgr8iPRUSJ4eViPzSOJZwvMAsieDMeyT4B/8OeoTPiqm BeNg==
X-Received: by 10.221.21.133 with SMTP id qs5mr1849957vcb.28.1382486885753; Tue, 22 Oct 2013 17:08:05 -0700 (PDT)
MIME-Version: 1.0
Received: by 10.220.12.131 with HTTP; Tue, 22 Oct 2013 17:07:44 -0700 (PDT)
From: Matthew Wild <mwild1@gmail.com>
Date: Wed, 23 Oct 2013 01:07:44 +0100
Message-ID: <CAJt9-x5RO1rmniQm=4ArPJJ8wYCCxPBFnE4gMKVKLu-bjFUyeg@mail.gmail.com>
To: XMPP Working Group <xmpp@ietf.org>
Content-Type: text/plain; charset="UTF-8"
Subject: [xmpp] Websockets: streams or not streams?
X-BeenThere: xmpp@ietf.org
X-Mailman-Version: 2.1.12
Precedence: list
List-Id: XMPP Working Group <xmpp.ietf.org>
List-Unsubscribe: <https://www.ietf.org/mailman/options/xmpp>, <mailto:xmpp-request@ietf.org?subject=unsubscribe>
List-Archive: <http://www.ietf.org/mail-archive/web/xmpp>
List-Post: <mailto:xmpp@ietf.org>
List-Help: <mailto:xmpp-request@ietf.org?subject=help>
List-Subscribe: <https://www.ietf.org/mailman/listinfo/xmpp>, <mailto:xmpp-request@ietf.org?subject=subscribe>
X-List-Received-Date: Wed, 23 Oct 2013 00:08:11 -0000

Florian Zeitz, Lance Stout, Paul Aurich, Waqas Hussain and myself have
just been having some discussion about the largest remaining open
issue in the websocket draft.

I'll start explaining from the beginning, assuming no prior knowledge,
because we're looking for input from as many people as possible in
order to reach a consensus (ha).

Unlike standard TCP which offers a stream of bytes, websockets provide
"framing", which means that the underlying stream is split into
individual frames.

We had a general consensus early on that it made sense to use these
frames to separate stanzas, which is especially useful because
generally Javascript clients do not have access to a streaming (e.g.
SAX) XML parser which is required for parsing unframed XMPP streams.
With framing, clients could (theoretically) take each frame and parse
it individually as a small standalone document.

However there is some awkwardness in this approach, because the
concept of a stream is quite central to traditional XMPP.

Here are the two questions we have:

1) If stanzas are going to be parsed as standalone documents, can they
inherit namespaces from the stream header like they can in normal
XMPP? Or should we require entities to always explicitly declare
namespaces on stanzas? (this includes for example adding
xmlns="jabber:client" xml:lang="xyz" to every stanza).

2) Should we keep the existing stream open and close mechanisms? They
are not standalone documents, and so websocket clients will still need
to handle them with special code.

Options for #1:

  Including namespaces will allow clients (libraries) to pass the data
in a frame directly into the XML parser they have.

  If we don't include namespaces (the current situation), clients are
resorting to hacks which include:
   - Not handling namespaces properly, perhaps assuming they are
always jabber:client
   - Capturing the stream header, and preprending it to every incoming
stanza by concatentating them together (example at
https://github.com/legastero/stanza.io/blob/master/lib/websocket.js#L59
)

However the concerns about adding namespaces explicitly to every stanza include:
  - Bandwidth increase
  - General noise and mess (look at it from a JSON fanatic's perspective)

Options for #2:

First option (current):

  OPEN:  <stream:stream xmlns:stream="..." xmlns="jabber:client"
id="abc123" xml:lang="en">
  CLOSE: </stream:stream>
  ERROR: <stream:error>...</stream:error>

  Benefits include:
     - Pretty much what we are used to already with traditional XMPP,
which means we are all familiar with it, and don't need to define
drastically new stuff

  Problems include:
    - Open and close are not standalone documents, which complicates
parsing for clients without streaming parsers. Again, this leads to
client hacks which include:
        * Parsing with regular expressions
        * Replacing the > at the end with />

Second option (goal: make everything a standalone document):

   OPEN: <stream:stream xmlns:stream="..." xmlns="jabber:client"
id="abc123" xml:lang="en" />
   CLOSE: ????
   ERROR: <stream:error xmlns:stream="..." xmlns="jabber:client"
id="abc123" xml:lang="en">...</stream:error>

   Benefits:
       - Re-uses what we already have

   Problems:
       - Not clear what we should use to signal stream closure
       - Although it's re-using what we already have, it is
overloading it somewhat (the 'stream' is no longer a stream...)

Third option (let's try a new way!):

    OPEN: <open xmlns="..." id="abc123" />
    CLOSE: <close xmlns="..." />
    ERROR: <error xmlns="http://etherx.jabber.org/streams">...</error>

   Benefits:
       - Clean, simple

   Problems:
       - Quite a departure from traditional streams now
       - Duplicates some things from the 'stream' element

Questions, comments, feedback welcome! It's worth noting that this
issue won't be unique to websockets, but will likely be re-used by any
transports that support framing (SCTP for example).

Regards,
Matthew