class TestHTTPResponse(TestCase): """ Tests that the HTTP protocol class correctly generates and parses messages. """ def setUp(self): self.channel_layer = ChannelLayer() self.factory = HTTPFactory(self.channel_layer, send_channel="test!") self.proto = self.factory.buildProtocol(('127.0.0.1', 0)) self.tr = proto_helpers.StringTransport() self.proto.makeConnection(self.tr) def test_http_disconnect_sets_path_key(self): """ Tests http disconnect has the path key set, see https://channels.readthedocs.io/en/latest/asgi.html#disconnect """ # Send a simple request to the protocol self.proto.dataReceived(b"GET /te%20st-%C3%A0/?foo=bar HTTP/1.1\r\n" + b"Host: anywhere.com\r\n" + b"\r\n") # Get the request message _, message = self.channel_layer.receive(["http.request"]) # Send back an example response self.factory.dispatch_reply(message['reply_channel'], { "status": 200, "status_text": b"OK", "content": b"DISCO", }) # Get the disconnection notification _, disconnect_message = self.channel_layer.receive(["http.disconnect"]) self.assertEqual(disconnect_message['path'], "/te st-à/")
def __init__(self): self.last_message = None self.channel_layer = ChannelLayer() self.factory = HTTPFactory(self.channel_layer, send_channel="test!") self.proto = self.factory.buildProtocol(('127.0.0.1', 0)) self.transport = proto_helpers.StringTransport() self.proto.makeConnection(self.transport)
def _run_through_daphne(request, channel_name): """ Returns Daphne's channel message for a given request. This helper requires a fair bit of scaffolding and can certainly be improved, but it works for now. """ channel_layer = ChannelLayer() factory = HTTPFactory(channel_layer, send_channel="test!") proto = factory.buildProtocol(('127.0.0.1', 0)) transport = proto_helpers.StringTransport() proto.makeConnection(transport) proto.dataReceived(request) _, message = channel_layer.receive([channel_name]) return message, factory, transport
class WebSocketConnection(object): """ Helper class that makes it easier to test Dahpne's WebSocket support. """ def __init__(self): self.last_message = None self.channel_layer = ChannelLayer() self.factory = HTTPFactory(self.channel_layer, send_channel="test!") self.proto = self.factory.buildProtocol(('127.0.0.1', 0)) self.transport = proto_helpers.StringTransport() self.proto.makeConnection(self.transport) def receive(self, request): """ Low-level method to let Daphne handle HTTP/WebSocket data """ self.proto.dataReceived(request) _, self.last_message = self.channel_layer.receive( ['websocket.connect']) return self.last_message def send(self, content): """ Method to respond with a channel message """ if self.last_message is None: # Auto-connect for convenience. self.connect() self.factory.dispatch_reply(self.last_message['reply_channel'], content) response = self.transport.value() self.transport.clear() return response def connect(self, path='/', params=None, headers=None): """ High-level method to perform the WebSocket handshake """ request = factories.build_websocket_upgrade(path, params, headers or []) message = self.receive(request) return message
class TestProxyHandling(unittest.TestCase): """ Tests that concern interaction of Daphne with proxies. They live in a separate test case, because they're not part of the spec. """ def setUp(self): self.channel_layer = ChannelLayer() self.factory = HTTPFactory(self.channel_layer) self.proto = self.factory.buildProtocol(('127.0.0.1', 0)) self.tr = proto_helpers.StringTransport() self.proto.makeConnection(self.tr) def test_x_forwarded_for_ignored(self): self.proto.dataReceived( b"GET /te%20st-%C3%A0/?foo=+bar HTTP/1.1\r\n" + b"Host: somewhere.com\r\n" + b"X-Forwarded-For: 10.1.2.3\r\n" + b"X-Forwarded-Port: 80\r\n" + b"\r\n" ) # Get the resulting message off of the channel layer _, message = self.channel_layer.receive(["http.request"]) self.assertEqual(message['client'], ['192.168.1.1', 54321]) def test_x_forwarded_for_parsed(self): self.factory.proxy_forwarded_address_header = 'X-Forwarded-For' self.factory.proxy_forwarded_port_header = 'X-Forwarded-Port' self.proto.dataReceived( b"GET /te%20st-%C3%A0/?foo=+bar HTTP/1.1\r\n" + b"Host: somewhere.com\r\n" + b"X-Forwarded-For: 10.1.2.3\r\n" + b"X-Forwarded-Port: 80\r\n" + b"\r\n" ) # Get the resulting message off of the channel layer _, message = self.channel_layer.receive(["http.request"]) self.assertEqual(message['client'], ['10.1.2.3', 80]) def test_x_forwarded_for_port_missing(self): self.factory.proxy_forwarded_address_header = 'X-Forwarded-For' self.factory.proxy_forwarded_port_header = 'X-Forwarded-Port' self.proto.dataReceived( b"GET /te%20st-%C3%A0/?foo=+bar HTTP/1.1\r\n" + b"Host: somewhere.com\r\n" + b"X-Forwarded-For: 10.1.2.3\r\n" + b"\r\n" ) # Get the resulting message off of the channel layer _, message = self.channel_layer.receive(["http.request"]) self.assertEqual(message['client'], ['10.1.2.3', 0])
def setUp(self): self.channel_layer = ChannelLayer() self.factory = HTTPFactory(self.channel_layer) self.proto = self.factory.buildProtocol(('127.0.0.1', 0)) self.tr = proto_helpers.StringTransport() self.proto.makeConnection(self.tr)
class TestWebSocketProtocol(TestCase): """ Tests that the WebSocket protocol class correcly generates and parses messages. """ def setUp(self): self.channel_layer = ChannelLayer() self.factory = HTTPFactory(self.channel_layer, send_channel="test!") self.proto = self.factory.buildProtocol(('127.0.0.1', 0)) self.tr = proto_helpers.StringTransport() self.proto.makeConnection(self.tr) def test_basic(self): # Send a simple request to the protocol self.proto.dataReceived( b"GET /chat HTTP/1.1\r\n" b"Host: somewhere.com\r\n" b"Upgrade: websocket\r\n" b"Connection: Upgrade\r\n" b"Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw==\r\n" b"Sec-WebSocket-Protocol: chat, superchat\r\n" b"Sec-WebSocket-Version: 13\r\n" b"Origin: http://example.com\r\n" b"\r\n") # Get the resulting message off of the channel layer _, message = self.channel_layer.receive(["websocket.connect"]) self.assertEqual(message['path'], "/chat") self.assertEqual(message['query_string'], "") self.assertEqual(sorted(message['headers']), [(b'connection', b'Upgrade'), (b'host', b'somewhere.com'), (b'origin', b'http://example.com'), (b'sec-websocket-key', b'x3JJHMbDL1EzLkh9GBhXDw=='), (b'sec-websocket-protocol', b'chat, superchat'), (b'sec-websocket-version', b'13'), (b'upgrade', b'websocket')]) self.assertTrue(message['reply_channel'].startswith("test!")) # Accept the connection self.factory.dispatch_reply(message['reply_channel'], {'accept': True}) # Make sure that we get a 101 Switching Protocols back response = self.tr.value() self.assertIn(b"HTTP/1.1 101 Switching Protocols\r\n", response) self.assertIn( b"Sec-WebSocket-Accept: HSmrc0sMlYUkAGmm5OPpG2HaGWk=\r\n", response) self.tr.clear() # Send some text self.factory.dispatch_reply(message['reply_channel'], {'text': "Hello World!"}) response = self.tr.value() self.assertEqual(response, b"\x81\x0cHello World!") self.tr.clear() # Send some bytes self.factory.dispatch_reply(message['reply_channel'], {'bytes': b"\xaa\xbb\xcc\xdd"}) response = self.tr.value() self.assertEqual(response, b"\x82\x04\xaa\xbb\xcc\xdd") self.tr.clear() # Close the connection self.factory.dispatch_reply(message['reply_channel'], {'close': True}) response = self.tr.value() self.assertEqual(response, b"\x88\x02\x03\xe8") self.tr.clear() def test_connection_with_file_origin_is_accepted(self): # Send a simple request to the protocol self.proto.dataReceived( b"GET /chat HTTP/1.1\r\n" b"Host: somewhere.com\r\n" b"Upgrade: websocket\r\n" b"Connection: Upgrade\r\n" b"Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw==\r\n" b"Sec-WebSocket-Protocol: chat, superchat\r\n" b"Sec-WebSocket-Version: 13\r\n" b"Origin: file://\r\n" b"\r\n") # Get the resulting message off of the channel layer _, message = self.channel_layer.receive(["websocket.connect"]) self.assertIn((b'origin', b'file://'), message['headers']) self.assertTrue(message['reply_channel'].startswith("test!")) # Accept the connection self.factory.dispatch_reply(message['reply_channel'], {'accept': True}) # Make sure that we get a 101 Switching Protocols back response = self.tr.value() self.assertIn(b"HTTP/1.1 101 Switching Protocols\r\n", response) self.assertIn( b"Sec-WebSocket-Accept: HSmrc0sMlYUkAGmm5OPpG2HaGWk=\r\n", response) def test_connection_with_no_origin_is_accepted(self): # Send a simple request to the protocol self.proto.dataReceived( b"GET /chat HTTP/1.1\r\n" b"Host: somewhere.com\r\n" b"Upgrade: websocket\r\n" b"Connection: Upgrade\r\n" b"Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw==\r\n" b"Sec-WebSocket-Protocol: chat, superchat\r\n" b"Sec-WebSocket-Version: 13\r\n" b"\r\n") # Get the resulting message off of the channel layer _, message = self.channel_layer.receive(["websocket.connect"]) self.assertNotIn( b'origin', [header_tuple[0] for header_tuple in message['headers']]) self.assertTrue(message['reply_channel'].startswith("test!")) # Accept the connection self.factory.dispatch_reply(message['reply_channel'], {'accept': True}) # Make sure that we get a 101 Switching Protocols back response = self.tr.value() self.assertIn(b"HTTP/1.1 101 Switching Protocols\r\n", response) self.assertIn( b"Sec-WebSocket-Accept: HSmrc0sMlYUkAGmm5OPpG2HaGWk=\r\n", response)