Beispiel #1
0
 def test_put_short_response_not_keep_alive(self):
     session = wsgi.HttpSession(self.mock_sock, None, {})
     kernels.run(
         session._put_short_response(http.HTTPStatus.OK, False),
         timeout=0.01,
     )
     self.assert_send(b'HTTP/1.1 200 OK\r\nConnection: close\r\n\r\n')
Beispiel #2
0
    def test_run_application_sendfile(self):
        mock_file = unittest.mock.Mock()

        mock_app = unittest.mock.AsyncMock()
        mock_app.return_value = wsgi.FileWrapper(mock_file)

        session = wsgi.HttpSession(None, mock_app, {})
        context = wsgi._ApplicationContext()

        run_task = tasks.spawn(session._run_application(context, {}))
        get_task = tasks.spawn(self.get_body_chunks(context))

        kernels.run(timeout=0.01)

        self.assertTrue(context._chunks.is_closed())

        self.assertTrue(run_task.is_completed())
        run_task.get_result_nonblocking()

        self.assertTrue(get_task.is_completed())
        self.assertEqual(get_task.get_result_nonblocking(), [])

        self.assertIs(context.file, mock_file)
        # `close` is not called because ownership is transferred to
        # context.
        mock_file.close.assert_not_called()
Beispiel #3
0
 def test_handle_request_100_continue(self):
     session = wsgi.HttpSession(self.mock_sock, None, {})
     for conn_header, keep_alive, expect_keep_alive in [
         ('Keep-Alive', True, True),
         ('Keep-Alive', False, True),
         ('close', True, False),
         ('close', False, False),
         (None, True, True),
         (None, False, False),
     ]:
         with self.subTest((conn_header, keep_alive, expect_keep_alive)):
             environ = {'HTTP_EXPECT': '100-Continue'}
             if conn_header is not None:
                 environ['HTTP_CONNECTION'] = conn_header
             if expect_keep_alive:
                 kernels.run(
                     session._handle_request(environ, keep_alive),
                     timeout=0.01,
                 )
                 self.assert_send(b'HTTP/1.1 100 Continue\r\n'
                                  b'Connection: keep-alive\r\n'
                                  b'\r\n')
             else:
                 with self.assertRaises(wsgi._SessionExit):
                     kernels.run(
                         session._handle_request(environ, keep_alive),
                         timeout=0.01,
                     )
                 self.assert_send(b'HTTP/1.1 100 Continue\r\n'
                                  b'Connection: close\r\n'
                                  b'\r\n')
Beispiel #4
0
    def test_run_application_non_aiter(self):
        mock_app = unittest.mock.AsyncMock()
        mock_app.return_value = [b'x', b'', b'', b'', b'y']

        session = wsgi.HttpSession(None, mock_app, {})
        context = wsgi._ApplicationContext()

        run_task = tasks.spawn(session._run_application(context, {}))
        get_task = tasks.spawn(self.get_body_chunks(context))

        kernels.run(timeout=0.01)

        self.assertTrue(context._chunks.is_closed())

        self.assertTrue(run_task.is_completed())
        run_task.get_result_nonblocking()

        self.assertTrue(get_task.is_completed())
        self.assertEqual(get_task.get_result_nonblocking(), [b'x', b'y'])
Beispiel #5
0
    def test_run_application_aiter(self):
        class MockBody:
            def __init__(self):
                self._iter = iter([b'x', b'', b'', b'', b'y'])
                self.closed = False

            def __aiter__(self):
                return self

            async def __anext__(self):
                try:
                    return next(self._iter)
                except StopIteration:
                    raise StopAsyncIteration from None

            def close(self):
                self.closed = True

        mock_body = MockBody()
        mock_app = unittest.mock.AsyncMock()
        mock_app.side_effect = [mock_body]

        session = wsgi.HttpSession(None, mock_app, {})
        context = wsgi._ApplicationContext()

        run_task = tasks.spawn(session._run_application(context, {}))
        get_task = tasks.spawn(self.get_body_chunks(context))

        kernels.run(timeout=0.01)

        self.assertTrue(mock_body.closed)
        self.assertTrue(context._chunks.is_closed())

        self.assertTrue(run_task.is_completed())
        run_task.get_result_nonblocking()

        self.assertTrue(get_task.is_completed())
        self.assertEqual(get_task.get_result_nonblocking(), [b'x', b'y'])
Beispiel #6
0
    def test_handle_request(self):
        http_500_keep_alive = (b'HTTP/1.1 500 Internal Server Error\r\n'
                               b'Connection: keep-alive\r\n'
                               b'\r\n', )
        http_500_not_keep_alive = (b'HTTP/1.1 500 Internal Server Error\r\n'
                                   b'Connection: close\r\n'
                                   b'\r\n', )

        session = wsgi.HttpSession(self.mock_sock, None, {})
        session._send_response = unittest.mock.AsyncMock()
        session._run_application = unittest.mock.AsyncMock()
        for (
                keep_alive,
                send_response,
                run_application,
                has_begun,
                expect_keep_alive,
                expect_send,
        ) in [
            (True, None, None, True, True, ()),
            (True, wsgi._SessionExit, None, True, False, ()),
            (True, None, wsgi._SessionExit, True, False, ()),
            (True, ValueError, None, True, False, ()),
            (True, None, ValueError, True, False, ()),
            (True, ValueError, None, False, True, http_500_keep_alive),
            (True, None, ValueError, False, True, http_500_keep_alive),
                # NOTE: If keep_alive is false, send_response cannot be
                # None.  This is the expected behavior of send_response, and
                # our mock has to respect that.
            (False, wsgi._SessionExit, None, True, False, ()),
            (False, wsgi._SessionExit, ValueError, True, False, ()),
            (False, ValueError, None, True, False, ()),
            (False, ValueError, None, False, False, http_500_not_keep_alive),
        ]:
            with self.subTest((
                    keep_alive,
                    send_response,
                    run_application,
                    has_begun,
                    expect_keep_alive,
                    expect_send,
            )):
                self.mock_sock.send.reset_mock()
                session._response_queue._has_begun = has_begun
                self.assertEqual(session._response_queue.has_begun(),
                                 has_begun)
                session._send_response.side_effect = send_response
                session._run_application.side_effect = run_application

                if expect_keep_alive:
                    kernels.run(
                        session._handle_request({}, keep_alive),
                        timeout=0.01,
                    )
                else:
                    with self.assertRaises(wsgi._SessionExit):
                        kernels.run(
                            session._handle_request({}, keep_alive),
                            timeout=0.01,
                        )
                self.assert_send(*expect_send)
Beispiel #7
0
    def test_send_response_sendfile(self, mock_os):

        mock_file = unittest.mock.Mock()
        mock_os.fstat.return_value.st_size = 99
        self.mock_sock.sendfile.return_value = 99

        def make_context(status, headers):
            context = wsgi._ApplicationContext()
            context._status = status
            context._headers = headers
            context.sendfile(mock_file)
            context.end_body_chunks()
            return context

        session = wsgi.HttpSession(self.mock_sock, None, {})
        for (
                context,
                expect_headers,
                expect_not_session_exit,
        ) in [
                # header: none
            (
                make_context(http.HTTPStatus.OK, []),
                b'HTTP/1.1 200 OK\r\n'
                b'Connection: keep-alive\r\n'
                b'Content-Length: 99\r\n\r\n',
                True,
            ),
                # header: content-length
            (
                make_context(http.HTTPStatus.OK, [(b'cOnTeNt-LeNgTh', b'99')]),
                b'HTTP/1.1 200 OK\r\n'
                b'cOnTeNt-LeNgTh: 99\r\n'
                b'Connection: keep-alive\r\n\r\n',
                True,
            ),
                # header: wrong content-length
            (
                make_context(http.HTTPStatus.OK, [(b'cOnTeNt-LeNgTh', b'10')]),
                b'HTTP/1.1 200 OK\r\n'
                b'cOnTeNt-LeNgTh: 10\r\n'
                b'Connection: keep-alive\r\n\r\n',
                False,
            ),
        ]:
            with self.subTest((
                    context,
                    expect_headers,
                    expect_not_session_exit,
            )):
                self.mock_sock.reset_mock()
                mock_file.reset_mock()

                send_task = tasks.spawn(
                    session._send_response(context, {}, True))
                kernels.run(timeout=0.01)

                self.assertTrue(send_task.is_completed())
                if expect_not_session_exit:
                    send_task.get_result_nonblocking()
                else:
                    with self.assertRaises(wsgi._SessionExit):
                        send_task.get_result_nonblocking()

                self.assertTrue(context._is_committed)
                self.assertFalse(session._response_queue._has_begun)
                self.assertFalse(
                    session._response_queue._headers_sent.is_set())
                self.mock_sock.assert_has_calls([
                    unittest.mock.call.send(expect_headers),
                    unittest.mock.call.sendfile(mock_file),
                ])
                mock_file.close.assert_called_once()
Beispiel #8
0
    def test_send_response_put_body_chunks(self):
        def make_context(status, headers, *body_chunks):
            context = wsgi._ApplicationContext()
            context._status = status
            context._headers = headers
            context._chunks = queues.Queue()  # Unset capacity for test.
            for chunk in body_chunks:
                context._chunks.put_nonblocking(chunk)
            context.end_body_chunks()
            return context

        session = wsgi.HttpSession(self.mock_sock, None, {})
        for (
                context,
                keep_alive,
                expect_data_per_call,
                expect_not_session_exit,
        ) in [
                # header: none ; body: none ; omit_body: false
            (
                make_context(http.HTTPStatus.OK, []),
                True,
                [
                    b'HTTP/1.1 200 OK\r\n'
                    b'Connection: keep-alive\r\n'
                    b'Content-Length: 0\r\n'
                    b'\r\n',
                ],
                True,
            ),
                # header: custom ; body: one chunk ; omit_body: false
            (
                make_context(http.HTTPStatus.NOT_FOUND, [(b'x', b'y')],
                             b'foo bar'),
                False,
                [
                    b'HTTP/1.1 404 Not Found\r\n'
                    b'x: y\r\n'
                    b'Connection: close\r\n'
                    b'Content-Length: 7\r\n'
                    b'\r\n',
                    b'foo bar',
                ],
                False,
            ),
                # header: connection ; body: multiple chunks ; omit_body: false
            (
                make_context(
                    http.HTTPStatus.OK,
                    [(b'connection', b'KeeP-Alive')],
                    b'spam',
                    b' ',
                    b'egg',
                ),
                False,
                [
                    b'HTTP/1.1 200 OK\r\n'
                    b'connection: KeeP-Alive\r\n'
                    b'Content-Length: 8\r\n'
                    b'\r\n',
                    b'spam',
                    b' ',
                    b'egg',
                ],
                True,
            ),
                # header: connection, content-length ; body: multiple chunks
                # omit_body: false
            (
                make_context(
                    http.HTTPStatus.OK,
                    [(b'Connection', b'close'), (b'cOnTeNt-LeNgTh', b'8')],
                    b'spam',
                    b' ',
                    b'egg',
                ),
                True,
                [
                    b'HTTP/1.1 200 OK\r\n'
                    b'Connection: close\r\n'
                    b'cOnTeNt-LeNgTh: 8\r\n'
                    b'\r\n',
                    b'spam',
                    b' ',
                    b'egg',
                ],
                False,
            ),
                # header: none ; body: multiple chunks
                # omit_body: true
            (
                make_context(http.HTTPStatus.NOT_MODIFIED, [], b'x', b' ',
                             b'y'),
                True,
                [
                    b'HTTP/1.1 304 Not Modified\r\n'
                    b'Connection: keep-alive\r\n'
                    b'Content-Length: 3\r\n'
                    b'\r\n',
                ],
                True,
            ),
                # header: wrong content-length; body: multiple chunks
                # omit_body: false
            (
                make_context(
                    http.HTTPStatus.OK,
                    [(b'content-length', b'8')],
                    b'a',
                    b' ',
                    b'b',
                ),
                True,
                [
                    b'HTTP/1.1 200 OK\r\n'
                    b'content-length: 8\r\n'
                    b'Connection: keep-alive\r\n'
                    b'\r\n',
                    b'a',
                    b' ',
                    b'b',
                ],
                False,
            ),
        ]:
            with self.subTest((
                    context,
                    keep_alive,
                    expect_data_per_call,
                    expect_not_session_exit,
            )):
                self.mock_sock.send.reset_mock()

                send_task = tasks.spawn(
                    session._send_response(context, {}, keep_alive))
                kernels.run(timeout=0.01)

                self.assertTrue(send_task.is_completed())
                if expect_not_session_exit:
                    send_task.get_result_nonblocking()
                else:
                    with self.assertRaises(wsgi._SessionExit):
                        send_task.get_result_nonblocking()

                self.assertTrue(context._is_committed)
                self.assertFalse(session._response_queue._has_begun)
                self.assertFalse(
                    session._response_queue._headers_sent.is_set())
                self.assert_send(*expect_data_per_call)
                self.mock_sock.sendfile.assert_not_called()