From 09b2a12be1fcb8234b1c947f87d6f031c4d08953 Mon Sep 17 00:00:00 2001 From: Andrew Godwin Date: Wed, 5 Oct 2016 15:59:55 -0700 Subject: [PATCH] Change to accept being part of send/close --- channels/worker.py | 2 +- docs/asgi.rst | 51 ++++++++++++++++++----------------------- docs/releases/1.0.0.rst | 27 +++++++++++++++++++++- 3 files changed, 49 insertions(+), 31 deletions(-) diff --git a/channels/worker.py b/channels/worker.py index 658f370..9c23074 100644 --- a/channels/worker.py +++ b/channels/worker.py @@ -122,7 +122,7 @@ class Worker(object): # They want to deny a WebSocket connection. if message.channel.name != "websocket.connect": raise ValueError("You cannot DenyConnection from a non-websocket.connect handler.") - message.reply_channel.send({"accept": False}) + message.reply_channel.send({"close": True}) except ConsumeLater: # They want to not handle it yet. Re-inject it with a number-of-tries marker. content['__retries__'] = content.get("__retries__", 0) + 1 diff --git a/docs/asgi.rst b/docs/asgi.rst index 0a5b68b..0165a28 100644 --- a/docs/asgi.rst +++ b/docs/asgi.rst @@ -735,7 +735,7 @@ server must close the connection with either HTTP status code ``503`` or WebSocket close code ``1013``. This message must be responded to on the ``reply_channel`` with a -*Connection Reply* message before the socket will pass messages on the +*Send/Close/Accept* message before the socket will pass messages on the ``receive`` channel. The protocol server should ideally send this message during the handshake phase of the WebSocket and not complete the handshake until it gets a reply, returning HTTP status code ``403`` if the connection is @@ -743,10 +743,6 @@ denied. If this is not possible, it must buffer WebSocket frames and not send them onto ``websocket.receive`` until a reply is received, and if the connection is rejected, return WebSocket close code ``4403``. -Receiving a WebSocket *Send/Close* message while waiting for a -*Connection Reply* must make the server accept the connection and then send -the message immediately. - Channel: ``websocket.connect`` Keys: @@ -782,25 +778,6 @@ Keys: * ``order``: The integer value ``0``. -Connection Reply -'''''''''''''''' - -Sent back on the reply channel from an application when a ``connect`` message -is received to say if the connection should be accepted or dropped. - -Behaviour on WebSocket rejection is defined in the Connection section above. - -If received while the socket is already accepted, the protocol server should -log an error, but not do anything. - -Channel: ``websocket.send!`` - -Keys: - -* ``accept``: If the connection should be accepted (``True``) or rejected and - dropped (``False``). - - Receive ''''''' @@ -852,14 +829,27 @@ Keys: ``order`` values in ``websocket.receive``. -Send/Close -'''''''''' +Send/Close/Accept +''''''''''''''''' Sends a data frame to the client and/or closes the connection from the -server end. If ``ChannelFull`` is raised, wait and try again. +server end and/or accepts a connection. If ``ChannelFull`` is raised, wait +and try again. -If sent while the connection is waiting for acceptance or rejection, -will accept the connection before the frame is sent. +If received while the connection is waiting for acceptance after a ``connect`` +message: + +* If ``bytes`` or ``text`` is present, accept the connection and send the data. +* If ``accept`` is ``True``, accept the connection and do nothing else. +* If ``close`` is ``True``, reject the connection. If ``bytes`` or ``text`` is + also set, it should accept the connection, send the frame, then immediately + close the connection. + +If received while the connection is established: + +* If ``bytes`` or ``text`` is present, send the data. +* If ``close`` is ``True``, close the connection after any send. +* ``accept`` is ignored. Channel: ``websocket.send!`` @@ -872,6 +862,9 @@ Keys: * ``close``: Boolean saying if the connection should be closed after data is sent, if any. Optional, default ``False``. +* ``accept``: Boolean saying if the connection should be accepted without + sending a frame if it is in the handshake phase. + A maximum of one of ``bytes`` or ``text`` may be provided. If both are provided, the protocol server should ignore the message entirely. diff --git a/docs/releases/1.0.0.rst b/docs/releases/1.0.0.rst index 8ac2359..019d312 100644 --- a/docs/releases/1.0.0.rst +++ b/docs/releases/1.0.0.rst @@ -52,7 +52,7 @@ you can still do that by passing the ``immediately`` argument:: Channel("thumbnailing-tasks").send({"id": 34245}, immediately=True) -This should be entirely backwards compatible, and may actually fix race +This should be mostly backwards compatible, and may actually fix race conditions in some apps that were pre-existing. @@ -60,3 +60,28 @@ Demultiplexer Overhaul ~~~~~~~~~~~~~~~~~~~~~~ TBD + + +Backwards Incompatible Changes +------------------------------ + +Connect Consumers +~~~~~~~~~~~~~~~~~ + +If you have a custom consumer for ``websocket.connect``, you must ensure that +it either: + +* Sends at least one message onto the ``reply_channel`` that generates a + WebSocket frame (either ``bytes`` or ``text`` is set), either directly + or via a group. +* Sends a message onto the ``reply_channel`` that is ``{"accept": True}``, + to accept a connection without sending data. +* Sends a message onto the ``reply_channel`` that is ``{"close": True}``, + to reject a connection mid-handshake. + +Many consumers already do the former, but if your connect consumer does not +send anything you MUST now send an accept message or the socket will remain +in the handshaking phase forever and you'll never get any messages. + +All built-in Channels consumers (e.g. in the generic consumers) have been +upgraded to do this.