Example #1
0
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-à/")
class TestHTTPProtocol(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)
        self.proto = self.factory.buildProtocol(('127.0.0.1', 0))
        self.tr = proto_helpers.StringTransport()
        self.proto.makeConnection(self.tr)

    def test_basic(self):
        """
        Tests basic HTTP parsing
        """
        # 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: somewhere.com\r\n" +
            b"\r\n"
        )
        # Get the resulting message off of the channel layer
        _, message = self.channel_layer.receive_many(["http.request"])
        self.assertEqual(message['http_version'], "1.1")
        self.assertEqual(message['method'], "GET")
        self.assertEqual(message['scheme'], "http")
        self.assertEqual(message['path'], "/te st-à/")
        self.assertEqual(message['query_string'], b"foo=+bar")
        self.assertEqual(message['headers'], [(b"host", b"somewhere.com")])
        self.assertFalse(message.get("body", None))
        self.assertTrue(message['reply_channel'])
        # Send back an example response
        self.factory.dispatch_reply(
            message['reply_channel'],
            {
                "status": 201,
                "status_text": b"Created",
                "content": b"OH HAI",
                "headers": [[b"X-Test", b"Boom!"]],
            }
        )
        # Make sure that comes back right on the protocol
        self.assertEqual(self.tr.value(), b"HTTP/1.1 201 Created\r\nTransfer-Encoding: chunked\r\nX-Test: Boom!\r\n\r\n6\r\nOH HAI\r\n0\r\n\r\n")

    def test_root_path_header(self):
        """
        Tests root path header handling
        """
        # 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: somewhere.com\r\n" +
            b"Daphne-Root-Path: /foobar%20/bar\r\n" +
            b"\r\n"
        )
        # Get the resulting message off of the channel layer, check root_path
        _, message = self.channel_layer.receive_many(["http.request"])
        self.assertEqual(message['root_path'], "/foobar /bar")
Example #3
0
 def setUp(self):
     """
     Make an in memory channel layer for testing
     """
     self.channel_layer = ChannelLayer()
     self.reply_channel = "http.response.test"
     self.start_response_value = None
     self.application = TestWsgiToAsgiAdapter(self.channel_layer)
Example #4
0
    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)
Example #5
0
class TestHTTPProtocol(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)
        self.proto = self.factory.buildProtocol(('127.0.0.1', 0))
        self.tr = proto_helpers.StringTransport()
        self.proto.makeConnection(self.tr)

    def test_basic(self):
        """
        Tests basic HTTP parsing
        """
        # 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: somewhere.com\r\n" + b"\r\n")
        # Get the resulting message off of the channel layer
        _, message = self.channel_layer.receive_many(["http.request"])
        self.assertEqual(message['http_version'], "1.1")
        self.assertEqual(message['method'], "GET")
        self.assertEqual(message['scheme'], "http")
        self.assertEqual(message['path'], "/te st-à/")
        self.assertEqual(message['query_string'], b"foo=+bar")
        self.assertEqual(message['headers'], [(b"host", b"somewhere.com")])
        self.assertFalse(message.get("body", None))
        self.assertTrue(message['reply_channel'])
        # Send back an example response
        self.factory.dispatch_reply(
            message['reply_channel'], {
                "status": 201,
                "status_text": b"Created",
                "content": b"OH HAI",
                "headers": [[b"X-Test", b"Boom!"]],
            })
        # Make sure that comes back right on the protocol
        self.assertEqual(
            self.tr.value(),
            b"HTTP/1.1 201 Created\r\nTransfer-Encoding: chunked\r\nX-Test: Boom!\r\n\r\n6\r\nOH HAI\r\n0\r\n\r\n"
        )

    def test_root_path_header(self):
        """
        Tests root path header handling
        """
        # 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: somewhere.com\r\n" +
                                b"Daphne-Root-Path: /foobar%20/bar\r\n" +
                                b"\r\n")
        # Get the resulting message off of the channel layer, check root_path
        _, message = self.channel_layer.receive_many(["http.request"])
        self.assertEqual(message['root_path'], "/foobar /bar")
Example #6
0
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])
Example #7
0
class WsgiToAsgiTests(TestCase):
    """
    Tests the WSGI-to-ASGI adapter.
    """
    def setUp(self):
        """
        Make an in memory channel layer for testing
        """
        self.channel_layer = ChannelLayer()
        self.reply_channel = "http.response.test"
        self.start_response_value = None
        self.application = TestWsgiToAsgiAdapter(self.channel_layer)

    def native_string(self, value):
        """
        Makes sure that the passed in string value comes out as a PEP3333
        "native string".
        """
        if six.PY2:
            if isinstance(value, unicode):
                return value.encode("latin1")
            else:
                return value
        else:
            if isinstance(value, bytes):
                return value.decode("latin1")
            else:
                return value

    def start_response(self, status, headers, exc_info=None):
        self.start_response_value = [status, headers, exc_info]

    def test_basic(self):
        # Example request
        ns = self.native_string
        environ = {
            "PATH_INFO": ns("/"),
            "CONTENT_TYPE": ns("text/html; charset=utf-8"),
            "REQUEST_METHOD": ns("GET"),
        }
        # Inject the response ahead of time
        self.channel_layer.send(self.reply_channel, {
            "status": 200,
            "content": b"Hi there!",
        })
        # Run WSGI adapter
        response = list(self.application(environ, self.start_response))
        # Make sure response looks fine
        self.assertEqual(response[0], b"Hi there!")
        self.assertEqual(self.start_response_value[0], b"200 OK")
Example #8
0
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
Example #9
0
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
Example #10
0
    def factory(name, **content):
        channel_layer = ChannelLayer()
        message = Message(content, name, channel_layer)
        settings.SESSION_FILE_PATH = str(tmpdir)
        message.channel_session = SessionStore()

        return message
Example #11
0
class InMemoryLayerTests(ConformanceTestCase):
    channel_layer = ChannelLayer(expiry=1, group_expiry=2)
    expiry_delay = 1.1

    def test_group_message_eviction(self):
        """
        Tests that when messages expire, group expiry also occurs.
        """
        # Add things to a group and send a message that should expire
        self.channel_layer.group_add("tgme_group", "tgme_test")
        self.channel_layer.send_group("tgme_group", {"value": "blue"})
        # Wait message expiry plus a tiny bit (must sum to less than group expiry)
        time.sleep(1.2)
        # Send new message to group, ensure message never arrives
        self.channel_layer.send_group("tgme_group", {"value": "blue"})
        channel, message = self.channel_layer.receive_many(["tgme_test"])
        self.assertIs(channel, None)
        self.assertIs(message, None)
Example #12
0
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
Example #13
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)
Example #14
0
class RequestTests(SimpleTestCase):
    """
    Tests that ASGI request handling correctly decodes HTTP requests.
    """
    def setUp(self):
        """
        Make an in memory channel layer for testing
        """
        self.channel_layer = ChannelLayer()
        self.make_message = lambda m, c: Message(m, c, self.channel_layer)

    def test_basic(self):
        """
        Tests that the handler can decode the most basic request message,
        with all optional fields omitted.
        """
        message = self.make_message(
            {
                "reply_channel": "test-reply",
                "http_version": "1.1",
                "method": "GET",
                "path": "/test/",
            }, "test")
        request = AsgiRequest(message)
        self.assertEqual(request.path, "/test/")
        self.assertEqual(request.method, "GET")
        self.assertFalse(request.body)
        self.assertNotIn("HTTP_HOST", request.META)
        self.assertNotIn("REMOTE_ADDR", request.META)
        self.assertNotIn("REMOTE_HOST", request.META)
        self.assertNotIn("REMOTE_PORT", request.META)
        self.assertNotIn("SERVER_NAME", request.META)
        self.assertNotIn("SERVER_PORT", request.META)
        self.assertFalse(request.GET)
        self.assertFalse(request.POST)
        self.assertFalse(request.COOKIES)

    def test_extended(self):
        """
        Tests a more fully-featured GET request
        """
        message = self.make_message(
            {
                "reply_channel": "test",
                "http_version": "1.1",
                "method": "GET",
                "path": "/test2/",
                "query_string": b"x=1&y=foo%20bar+baz",
                "headers": {
                    "host": b"example.com",
                    "cookie": b"test-time=1448995585123; test-value=yeah",
                },
                "client": ["10.0.0.1", 1234],
                "server": ["10.0.0.2", 80],
            }, "test")
        request = AsgiRequest(message)
        self.assertEqual(request.path, "/test2/")
        self.assertEqual(request.method, "GET")
        self.assertFalse(request.body)
        self.assertEqual(request.META["HTTP_HOST"], "example.com")
        self.assertEqual(request.META["REMOTE_ADDR"], "10.0.0.1")
        self.assertEqual(request.META["REMOTE_HOST"], "10.0.0.1")
        self.assertEqual(request.META["REMOTE_PORT"], 1234)
        self.assertEqual(request.META["SERVER_NAME"], "10.0.0.2")
        self.assertEqual(request.META["SERVER_PORT"], 80)
        self.assertEqual(request.GET["x"], "1")
        self.assertEqual(request.GET["y"], "foo bar baz")
        self.assertEqual(request.COOKIES["test-time"], "1448995585123")
        self.assertEqual(request.COOKIES["test-value"], "yeah")
        self.assertFalse(request.POST)

    def test_post_single(self):
        """
        Tests a POST body contained within a single message.
        """
        message = self.make_message(
            {
                "reply_channel": "test",
                "http_version": "1.1",
                "method": "POST",
                "path": "/test2/",
                "query_string": b"django=great",
                "body": b"ponies=are+awesome",
                "headers": {
                    "host": b"example.com",
                    "content-type": b"application/x-www-form-urlencoded",
                    "content-length": b"18",
                },
            }, "test")
        request = AsgiRequest(message)
        self.assertEqual(request.path, "/test2/")
        self.assertEqual(request.method, "POST")
        self.assertEqual(request.body, b"ponies=are+awesome")
        self.assertEqual(request.META["HTTP_HOST"], "example.com")
        self.assertEqual(request.META["CONTENT_TYPE"],
                         "application/x-www-form-urlencoded")
        self.assertEqual(request.GET["django"], "great")
        self.assertEqual(request.POST["ponies"], "are awesome")
        with self.assertRaises(KeyError):
            request.POST["django"]
        with self.assertRaises(KeyError):
            request.GET["ponies"]

    def test_post_multiple(self):
        """
        Tests a POST body across multiple messages (first part in 'body').
        """
        message = self.make_message(
            {
                "reply_channel": "test",
                "http_version": "1.1",
                "method": "POST",
                "path": "/test/",
                "body": b"there_a",
                "body_channel": "test-input",
                "headers": {
                    "host": b"example.com",
                    "content-type": b"application/x-www-form-urlencoded",
                    "content-length": b"21",
                },
            }, "test")
        self.channel_layer.send("test-input", {
            "content": b"re=fou",
            "more_content": True,
        })
        self.channel_layer.send("test-input", {
            "content": b"r+lights",
        })
        request = AsgiRequest(message)
        self.assertEqual(request.method, "POST")
        self.assertEqual(request.body, b"there_are=four+lights")
        self.assertEqual(request.META["CONTENT_TYPE"],
                         "application/x-www-form-urlencoded")
        self.assertEqual(request.POST["there_are"], "four lights")

    def test_post_files(self):
        """
        Tests POSTing files using multipart form data and multiple messages,
        with no body in the initial message.
        """
        body = (
            b'--BOUNDARY\r\n' +
            b'Content-Disposition: form-data; name="title"\r\n\r\n' +
            b'My First Book\r\n' + b'--BOUNDARY\r\n' +
            b'Content-Disposition: form-data; name="pdf"; filename="book.pdf"\r\n\r\n'
            + b'FAKEPDFBYTESGOHERE' + b'--BOUNDARY--')
        message = self.make_message(
            {
                "reply_channel": "test",
                "http_version": "1.1",
                "method": "POST",
                "path": "/test/",
                "body_channel": "test-input",
                "headers": {
                    "content-type": b"multipart/form-data; boundary=BOUNDARY",
                    "content-length": six.text_type(len(body)).encode("ascii"),
                },
            }, "test")
        self.channel_layer.send("test-input", {
            "content": body[:20],
            "more_content": True,
        })
        self.channel_layer.send("test-input", {
            "content": body[20:],
        })
        request = AsgiRequest(message)
        self.assertEqual(request.method, "POST")
        self.assertEqual(len(request.body), len(body))
        self.assertTrue(
            request.META["CONTENT_TYPE"].startswith("multipart/form-data"))
        self.assertFalse(request._post_parse_error)
        self.assertEqual(request.POST["title"], "My First Book")
        self.assertEqual(request.FILES["pdf"].read(), b"FAKEPDFBYTESGOHERE")
Example #15
0
class TestHTTPProtocol(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)
        self.proto = self.factory.buildProtocol(('127.0.0.1', 0))
        self.tr = proto_helpers.StringTransport()
        self.proto.makeConnection(self.tr)

    def test_basic(self):
        """
        Tests basic HTTP parsing
        """
        # 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: somewhere.com\r\n" + b"\r\n")
        # Get the resulting message off of the channel layer
        _, message = self.channel_layer.receive_many(["http.request"])
        self.assertEqual(message['http_version'], "1.1")
        self.assertEqual(message['method'], "GET")
        self.assertEqual(message['scheme'], "http")
        self.assertEqual(message['path'], "/te st-à/")
        self.assertEqual(message['query_string'], b"foo=+bar")
        self.assertEqual(message['headers'], [(b"host", b"somewhere.com")])
        self.assertFalse(message.get("body", None))
        self.assertTrue(message['reply_channel'])
        # Send back an example response
        self.factory.dispatch_reply(
            message['reply_channel'], {
                "status": 201,
                "status_text": b"Created",
                "content": b"OH HAI",
                "headers": [[b"X-Test", b"Boom!"]],
            })
        # Make sure that comes back right on the protocol
        self.assertEqual(
            self.tr.value(),
            b"HTTP/1.1 201 Created\r\nTransfer-Encoding: chunked\r\nX-Test: Boom!\r\n\r\n6\r\nOH HAI\r\n0\r\n\r\n"
        )

    def test_root_path_header(self):
        """
        Tests root path header handling
        """
        # 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: somewhere.com\r\n" +
                                b"Daphne-Root-Path: /foobar%20/bar\r\n" +
                                b"\r\n")
        # Get the resulting message off of the channel layer, check root_path
        _, message = self.channel_layer.receive_many(["http.request"])
        self.assertEqual(message['root_path'], "/foobar /bar")

    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_many(["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_many(
            ["http.disconnect"])
        self.assertEqual(disconnect_message['path'], "/te st-à/")

    def test_x_forwarded_for_ignored(self):
        """
        Tests basic HTTP parsing
        """
        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_many(["http.request"])
        self.assertEqual(message['client'], ['192.168.1.1', 54321])

    def test_x_forwarded_for_parsed(self):
        """
        Tests basic HTTP parsing
        """
        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_many(["http.request"])
        self.assertEqual(message['client'], ['10.1.2.3', 80])

    def test_x_forwarded_for_port_missing(self):
        """
        Tests basic HTTP parsing
        """
        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_many(["http.request"])
        self.assertEqual(message['client'], ['10.1.2.3', 0])
Example #16
0
class RequestTests(SimpleTestCase):
    """
    Tests that ASGI request handling correctly decodes HTTP requests.
    """

    def setUp(self):
        """
        Make an in memory channel layer for testing
        """
        self.channel_layer = ChannelLayer()
        self.make_message = lambda m, c: Message(m, c, self.channel_layer)

    def test_basic(self):
        """
        Tests that the handler can decode the most basic request message,
        with all optional fields omitted.
        """
        message = self.make_message({
            "reply_channel": "test-reply",
            "http_version": "1.1",
            "method": "GET",
            "path": "/test/",
        }, "test")
        request = AsgiRequest(message)
        self.assertEqual(request.path, "/test/")
        self.assertEqual(request.method, "GET")
        self.assertFalse(request.body)
        self.assertNotIn("HTTP_HOST", request.META)
        self.assertNotIn("REMOTE_ADDR", request.META)
        self.assertNotIn("REMOTE_HOST", request.META)
        self.assertNotIn("REMOTE_PORT", request.META)
        self.assertNotIn("SERVER_NAME", request.META)
        self.assertNotIn("SERVER_PORT", request.META)
        self.assertFalse(request.GET)
        self.assertFalse(request.POST)
        self.assertFalse(request.COOKIES)

    def test_extended(self):
        """
        Tests a more fully-featured GET request
        """
        message = self.make_message({
            "reply_channel": "test",
            "http_version": "1.1",
            "method": "GET",
            "path": "/test2/",
            "query_string": b"x=1&y=foo%20bar+baz",
            "headers": {
                "host": b"example.com",
                "cookie": b"test-time=1448995585123; test-value=yeah",
            },
            "client": ["10.0.0.1", 1234],
            "server": ["10.0.0.2", 80],
        }, "test")
        request = AsgiRequest(message)
        self.assertEqual(request.path, "/test2/")
        self.assertEqual(request.method, "GET")
        self.assertFalse(request.body)
        self.assertEqual(request.META["HTTP_HOST"], "example.com")
        self.assertEqual(request.META["REMOTE_ADDR"], "10.0.0.1")
        self.assertEqual(request.META["REMOTE_HOST"], "10.0.0.1")
        self.assertEqual(request.META["REMOTE_PORT"], 1234)
        self.assertEqual(request.META["SERVER_NAME"], "10.0.0.2")
        self.assertEqual(request.META["SERVER_PORT"], 80)
        self.assertEqual(request.GET["x"], "1")
        self.assertEqual(request.GET["y"], "foo bar baz")
        self.assertEqual(request.COOKIES["test-time"], "1448995585123")
        self.assertEqual(request.COOKIES["test-value"], "yeah")
        self.assertFalse(request.POST)

    def test_post_single(self):
        """
        Tests a POST body contained within a single message.
        """
        message = self.make_message({
            "reply_channel": "test",
            "http_version": "1.1",
            "method": "POST",
            "path": "/test2/",
            "query_string": b"django=great",
            "body": b"ponies=are+awesome",
            "headers": {
                "host": b"example.com",
                "content-type": b"application/x-www-form-urlencoded",
                "content-length": b"18",
            },
        }, "test")
        request = AsgiRequest(message)
        self.assertEqual(request.path, "/test2/")
        self.assertEqual(request.method, "POST")
        self.assertEqual(request.body, b"ponies=are+awesome")
        self.assertEqual(request.META["HTTP_HOST"], "example.com")
        self.assertEqual(request.META["CONTENT_TYPE"], "application/x-www-form-urlencoded")
        self.assertEqual(request.GET["django"], "great")
        self.assertEqual(request.POST["ponies"], "are awesome")
        with self.assertRaises(KeyError):
            request.POST["django"]
        with self.assertRaises(KeyError):
            request.GET["ponies"]

    def test_post_multiple(self):
        """
        Tests a POST body across multiple messages (first part in 'body').
        """
        message = self.make_message({
            "reply_channel": "test",
            "http_version": "1.1",
            "method": "POST",
            "path": "/test/",
            "body": b"there_a",
            "body_channel": "test-input",
            "headers": {
                "host": b"example.com",
                "content-type": b"application/x-www-form-urlencoded",
                "content-length": b"21",
            },
        }, "test")
        self.channel_layer.send("test-input", {
            "content": b"re=fou",
            "more_content": True,
        })
        self.channel_layer.send("test-input", {
            "content": b"r+lights",
        })
        request = AsgiRequest(message)
        self.assertEqual(request.method, "POST")
        self.assertEqual(request.body, b"there_are=four+lights")
        self.assertEqual(request.META["CONTENT_TYPE"], "application/x-www-form-urlencoded")
        self.assertEqual(request.POST["there_are"], "four lights")

    def test_post_files(self):
        """
        Tests POSTing files using multipart form data and multiple messages,
        with no body in the initial message.
        """
        body = (
            b'--BOUNDARY\r\n' +
            b'Content-Disposition: form-data; name="title"\r\n\r\n' +
            b'My First Book\r\n' +
            b'--BOUNDARY\r\n' +
            b'Content-Disposition: form-data; name="pdf"; filename="book.pdf"\r\n\r\n' +
            b'FAKEPDFBYTESGOHERE' +
            b'--BOUNDARY--'
        )
        message = self.make_message({
            "reply_channel": "test",
            "http_version": "1.1",
            "method": "POST",
            "path": "/test/",
            "body_channel": "test-input",
            "headers": {
                "content-type": b"multipart/form-data; boundary=BOUNDARY",
                "content-length": six.text_type(len(body)).encode("ascii"),
            },
        }, "test")
        self.channel_layer.send("test-input", {
            "content": body[:20],
            "more_content": True,
        })
        self.channel_layer.send("test-input", {
            "content": body[20:],
        })
        request = AsgiRequest(message)
        self.assertEqual(request.method, "POST")
        self.assertEqual(len(request.body), len(body))
        self.assertTrue(request.META["CONTENT_TYPE"].startswith("multipart/form-data"))
        self.assertFalse(request._post_parse_error)
        self.assertEqual(request.POST["title"], "My First Book")
        self.assertEqual(request.FILES["pdf"].read(), b"FAKEPDFBYTESGOHERE")
Example #17
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)
Example #18
0
 def setUp(self):
     """
     Make an in memory channel layer for testing
     """
     self.channel_layer = ChannelLayer()
     self.make_message = lambda m, c: Message(m, c, self.channel_layer)
Example #19
0
from asgiref.inmemory import ChannelLayer
from asgiref.conformance import make_tests

channel_layer = ChannelLayer(expiry=1)
InMemoryTests = make_tests(channel_layer, expiry_delay=1.1)
Example #20
0
class TestHTTPProtocol(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)
        self.proto = self.factory.buildProtocol(('127.0.0.1', 0))
        self.tr = proto_helpers.StringTransport()
        self.proto.makeConnection(self.tr)

    def assertStartsWith(self, data, prefix):
        real_prefix = data[:len(prefix)]
        self.assertEqual(real_prefix, prefix)

    def test_basic(self):
        """
        Tests basic HTTP parsing
        """
        # Send a simple request to the protocol
        self.proto.dataReceived(b"GET /test/?foo=bar HTTP/1.1\r\n" +
                                b"Host: somewhere.com\r\n" + b"\r\n")
        # Get the resulting message off of the channel layer
        _, message = self.channel_layer.receive_many(["http.request"])
        self.assertEqual(message['http_version'], "1.1")
        self.assertEqual(message['method'], "GET")
        self.assertEqual(message['scheme'], "http")
        self.assertEqual(message['path'], b"/test/")
        self.assertEqual(message['query_string'], b"foo=bar")
        self.assertEqual(message['headers'], {"host": b"somewhere.com"})
        self.assertFalse(message.get("body", None))
        self.assertTrue(message['reply_channel'])
        # Send back an example response
        self.factory.dispatch_reply(
            message['reply_channel'], {
                "status": 201,
                "status_text": b"Created",
                "content": b"OH HAI",
                "headers": [["X-Test", b"Boom!"]],
            })
        # Make sure that comes back right on the protocol
        self.assertEqual(
            self.tr.value(),
            b"HTTP/1.1 201 Created\r\nTransfer-Encoding: chunked\r\nX-Test: Boom!\r\n\r\n6\r\nOH HAI\r\n0\r\n\r\n"
        )

    def test_custom_status_text(self):
        """
        Tests basic HTTP parsing
        """
        # Send a simple request to the protocol
        self.proto.dataReceived(b"GET /test/?foo=bar HTTP/1.0\r\n" + b"\r\n")
        # Send back an example response
        _, message = self.channel_layer.receive_many(["http.request"])
        self.factory.dispatch_reply(message['reply_channel'], {
            "status": 484,
            "status_text": b"Daphne Is Awesome",
        })
        # Make sure that comes back right on the protocol
        self.assertStartsWith(self.tr.value(),
                              b"HTTP/1.0 484 Daphne Is Awesome\r\n")
Example #21
0
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)
Example #22
0
class TestWebSocketProtocol(TestCase):
    """
    Tests that the WebSocket protocol class correctly generates and parses messages.
    """

    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_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("websocket.send!"))

        # 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("websocket.send!"))

        # 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("websocket.send!"))

        # 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)
Example #23
0
 def setUp(self):
     """
     Make an in memory channel layer for testing
     """
     self.channel_layer = ChannelLayer()
     self.make_message = lambda m, c: Message(m, c, self.channel_layer)
Example #24
0
class TestHTTPProtocol(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)
        self.proto = self.factory.buildProtocol(('127.0.0.1', 0))
        self.tr = proto_helpers.StringTransport()
        self.proto.makeConnection(self.tr)

    def test_basic(self):
        """
        Tests basic HTTP parsing
        """
        # 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: somewhere.com\r\n" +
            b"\r\n"
        )
        # Get the resulting message off of the channel layer
        _, message = self.channel_layer.receive(["http.request"])
        self.assertEqual(message['http_version'], "1.1")
        self.assertEqual(message['method'], "GET")
        self.assertEqual(message['scheme'], "http")
        self.assertEqual(message['path'], "/te st-à/")
        self.assertEqual(message['query_string'], b"foo=+bar")
        self.assertEqual(message['headers'], [(b"host", b"somewhere.com")])
        self.assertFalse(message.get("body", None))
        self.assertTrue(message['reply_channel'])
        # Send back an example response
        self.factory.dispatch_reply(
            message['reply_channel'],
            {
                "status": 201,
                "status_text": b"Created",
                "content": b"OH HAI",
                "headers": [[b"X-Test", b"Boom!"]],
            }
        )
        # Make sure that comes back right on the protocol
        self.assertEqual(self.tr.value(), b"HTTP/1.1 201 Created\r\nTransfer-Encoding: chunked\r\nX-Test: Boom!\r\n\r\n6\r\nOH HAI\r\n0\r\n\r\n")

    def test_root_path_header(self):
        """
        Tests root path header handling
        """
        # 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: somewhere.com\r\n" +
            b"Daphne-Root-Path: /foobar%20/bar\r\n" +
            b"\r\n"
        )
        # Get the resulting message off of the channel layer, check root_path
        _, message = self.channel_layer.receive(["http.request"])
        self.assertEqual(message['root_path'], "/foobar /bar")

    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 test_x_forwarded_for_ignored(self):
        """
        Tests basic HTTP parsing
        """
        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):
        """
        Tests basic HTTP parsing
        """
        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):
        """
        Tests basic HTTP parsing
        """
        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])