From 429f7377cb6e3f0d6e68e94f2315a4c5e520ee0e Mon Sep 17 00:00:00 2001 From: MichaelYusko Date: Wed, 26 Jul 2017 19:32:23 +0300 Subject: [PATCH 1/4] Did the small changes for better readable --- sanic/response.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/sanic/response.py b/sanic/response.py index f4fb1ea6..902b21c6 100644 --- a/sanic/response.py +++ b/sanic/response.py @@ -109,8 +109,9 @@ class BaseHTTPResponse: class StreamingHTTPResponse(BaseHTTPResponse): __slots__ = ( - 'transport', 'streaming_fn', - 'status', 'content_type', 'headers', '_cookies') + 'transport', 'streaming_fn', 'status', + 'content_type', 'headers', '_cookies' + ) def __init__(self, streaming_fn, status=200, headers=None, content_type='text/plain'): From 9b3fbe45932b70d0872458e70cb39fd1688a3055 Mon Sep 17 00:00:00 2001 From: 7 Date: Wed, 2 Aug 2017 10:15:18 -0700 Subject: [PATCH 2/4] fixed small doc issue (#877) --- .gitignore | 1 + docs/sanic/testing.md | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 73e923d3..4a834a7a 100644 --- a/.gitignore +++ b/.gitignore @@ -14,3 +14,4 @@ settings.py docs/_build/ docs/_api/ build/* +.DS_Store diff --git a/docs/sanic/testing.md b/docs/sanic/testing.md index b8427a00..0aca9184 100644 --- a/docs/sanic/testing.md +++ b/docs/sanic/testing.md @@ -59,7 +59,7 @@ the available arguments to aiohttp can be found [in the documentation for ClientSession](https://aiohttp.readthedocs.io/en/stable/client_reference.html#client-session). -# pytest-sanic +## pytest-sanic [pytest-sanic](https://github.com/yunstanford/pytest-sanic) is a pytest plugin, it helps you to test your code asynchronously. Just write tests like, From f80a6ae228cb0576f2c4660845210ed9da4241d9 Mon Sep 17 00:00:00 2001 From: Eli Uriegas Date: Wed, 2 Aug 2017 19:11:53 -0700 Subject: [PATCH 3/4] Increment to 0.6.0 --- sanic/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sanic/__init__.py b/sanic/__init__.py index 4cc0710f..8f35a283 100644 --- a/sanic/__init__.py +++ b/sanic/__init__.py @@ -1,6 +1,6 @@ from sanic.app import Sanic from sanic.blueprints import Blueprint -__version__ = '0.5.4' +__version__ = '0.6.0' __all__ = ['Sanic', 'Blueprint'] From 375ed232167a433b20c223e9ffe2d1deb94afc17 Mon Sep 17 00:00:00 2001 From: Miguel Grinberg Date: Tue, 8 Aug 2017 11:21:52 -0700 Subject: [PATCH 4/4] Weboscket subprotocol negotiation Fixes #874 --- sanic/app.py | 7 +++++-- sanic/websocket.py | 14 +++++++++++++- tests/test_routes.py | 43 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 61 insertions(+), 3 deletions(-) diff --git a/sanic/app.py b/sanic/app.py index f0ccad86..a3acbecf 100644 --- a/sanic/app.py +++ b/sanic/app.py @@ -214,9 +214,12 @@ class Sanic: return handler # Decorator - def websocket(self, uri, host=None, strict_slashes=False): + def websocket(self, uri, host=None, strict_slashes=False, + subprotocols=None): """Decorate a function to be registered as a websocket route :param uri: path of the URL + :param subprotocols: optional list of strings with the supported + subprotocols :param host: :return: decorated function """ @@ -236,7 +239,7 @@ class Sanic: # On Python3.5 the Transport classes in asyncio do not # have a get_protocol() method as in uvloop protocol = request.transport._protocol - ws = await protocol.websocket_handshake(request) + ws = await protocol.websocket_handshake(request, subprotocols) # schedule the application handler # its future is kept in self.websocket_tasks in case it diff --git a/sanic/websocket.py b/sanic/websocket.py index 94320a5e..e8e9922f 100644 --- a/sanic/websocket.py +++ b/sanic/websocket.py @@ -41,7 +41,7 @@ class WebSocketProtocol(HttpProtocol): else: super().write_response(response) - async def websocket_handshake(self, request): + async def websocket_handshake(self, request, subprotocols=None): # let the websockets package do the handshake with the client headers = [] @@ -57,6 +57,17 @@ class WebSocketProtocol(HttpProtocol): except InvalidHandshake: raise InvalidUsage('Invalid websocket request') + subprotocol = None + if subprotocols and 'Sec-Websocket-Protocol' in request.headers: + # select a subprotocol + client_subprotocols = [p.strip() for p in request.headers[ + 'Sec-Websocket-Protocol'].split(',')] + for p in client_subprotocols: + if p in subprotocols: + subprotocol = p + set_header('Sec-Websocket-Protocol', subprotocol) + break + # write the 101 response back to the client rv = b'HTTP/1.1 101 Switching Protocols\r\n' for k, v in headers: @@ -69,5 +80,6 @@ class WebSocketProtocol(HttpProtocol): max_size=self.websocket_max_size, max_queue=self.websocket_max_queue ) + self.websocket.subprotocol = subprotocol self.websocket.connection_made(request.transport) return self.websocket diff --git a/tests/test_routes.py b/tests/test_routes.py index 04a682a0..b356c2d5 100644 --- a/tests/test_routes.py +++ b/tests/test_routes.py @@ -341,6 +341,7 @@ def test_websocket_route(): @app.websocket('/ws') async def handler(request, ws): + assert ws.subprotocol is None ev.set() request, response = app.test_client.get('/ws', headers={ @@ -352,6 +353,48 @@ def test_websocket_route(): assert ev.is_set() +def test_websocket_route_with_subprotocols(): + app = Sanic('test_websocket_route') + results = [] + + @app.websocket('/ws', subprotocols=['foo', 'bar']) + async def handler(request, ws): + results.append(ws.subprotocol) + + request, response = app.test_client.get('/ws', headers={ + 'Upgrade': 'websocket', + 'Connection': 'upgrade', + 'Sec-WebSocket-Key': 'dGhlIHNhbXBsZSBub25jZQ==', + 'Sec-WebSocket-Version': '13', + 'Sec-WebSocket-Protocol': 'bar'}) + assert response.status == 101 + + request, response = app.test_client.get('/ws', headers={ + 'Upgrade': 'websocket', + 'Connection': 'upgrade', + 'Sec-WebSocket-Key': 'dGhlIHNhbXBsZSBub25jZQ==', + 'Sec-WebSocket-Version': '13', + 'Sec-WebSocket-Protocol': 'bar, foo'}) + assert response.status == 101 + + request, response = app.test_client.get('/ws', headers={ + 'Upgrade': 'websocket', + 'Connection': 'upgrade', + 'Sec-WebSocket-Key': 'dGhlIHNhbXBsZSBub25jZQ==', + 'Sec-WebSocket-Version': '13', + 'Sec-WebSocket-Protocol': 'baz'}) + assert response.status == 101 + + request, response = app.test_client.get('/ws', headers={ + 'Upgrade': 'websocket', + 'Connection': 'upgrade', + 'Sec-WebSocket-Key': 'dGhlIHNhbXBsZSBub25jZQ==', + 'Sec-WebSocket-Version': '13'}) + assert response.status == 101 + + assert results == ['bar', 'bar', None, None] + + def test_route_duplicate(): app = Sanic('test_route_duplicate')