async def test_incrementing_cookie_version_denies_access():
    app = GitHubAuth(
        hello_world_app,
        client_id="x_client_id",
        client_secret="x_client_secret",
        require_auth=True,
    )
    cookie = signed_auth_cookie_header(app)
    scope = {
        "type": "http",
        "http_version": "1.0",
        "method": "GET",
        "path": "/",
        "headers": [[b"cookie", cookie]],
    }
    instance = ApplicationCommunicator(app, scope)
    await instance.send_input({"type": "http.request"})
    output = await instance.receive_output(1)
    assert 200 == output["status"]
    # Try it again with a different cookie version
    app = GitHubAuth(
        hello_world_app,
        client_id="x_client_id",
        client_secret="x_client_secret",
        require_auth=True,
        cookie_version=2,
    )
    instance = ApplicationCommunicator(app, scope)
    await instance.send_input({"type": "http.request"})
    output = await instance.receive_output(1)
    assert 302 == output["status"]
Beispiel #2
0
    async def _connect(self, path: str = None):
        self.path = path or self.path
        queries = self.queries
        if isinstance(queries, Mapping):
            qsl = [f"{quote_plus(k)}={quote_plus(v)}" for k, v in queries.items()]
        else:
            qsl = [f"{quote_plus(k)}={quote_plus(v)}" for k, v in queries]
        qs = "&".join(qsl).encode("ascii")
        headers = [
            (k.encode("latin-1"), v.encode("latin-1")) for k, v in self.headers.items()
        ]
        scope = {
            "type": "websocket",
            "asgi": {"spec_version": "2.1"},
            "scheme": "ws",
            "http_version": "1.1",
            "path": self.path,
            "raw_path": quote_plus(self.path).encode("ascii"),
            "query_string": qs,
            "root_path": "",
            "headers": headers,
            "client": self._client,
            "subprotocols": [
                x
                for x in self.headers.get("sec-websocket-protocol", "").split(", ")
                if x
            ],
        }

        self._connection = ApplicationCommunicator(self._app_ref["app"], scope)
        await self._connection.send_input({"type": "websocket.connect"})
        message = await (self._connection.receive_output(self.timeout))
        if message["type"] != "websocket.accept":
            raise RuntimeError("Connection refused.")
async def test_allow_orgs(require_auth_app):
    require_auth_app.allow_orgs = ["my-org"]
    scope = {
        "type": "http",
        "http_version": "1.0",
        "method": "GET",
        "path": "/-/auth-callback",
        "query_string": b"code=github-code-here",
    }
    instance = ApplicationCommunicator(require_auth_app, scope)
    await instance.send_input({"type": "http.request"})
    output = await instance.receive_output(1)
    # Should return forbidden
    assert {
        "type": "http.response.start",
        "status": 403
    } == {
        "type": output["type"],
        "status": output["status"],
    }
    # Try again with an org they are a member of
    require_auth_app.allow_orgs = ["demouser-org"]
    instance = ApplicationCommunicator(require_auth_app, scope)
    await instance.send_input({"type": "http.request"})
    output = await instance.receive_output(1)
    assert 302 == output["status"]
async def test_cacheable_assets(require_auth_app):
    # Anything with a path matching cacheable_prefixes should not
    # have a cache-control: private header
    require_auth_app.cacheable_prefixes = ["/-/static/"]
    scope = {
        "type": "http",
        "http_version": "1.0",
        "method": "GET",
        "path": "/-/static/blah.js",
        "headers": [[b"cookie", signed_auth_cookie_header(require_auth_app)]],
    }
    instance = ApplicationCommunicator(require_auth_app, scope)
    await instance.send_input({"type": "http.request"})
    output = await instance.receive_output(1)
    assert [
        [b"content-type", b"text/html; charset=UTF-8"],
        [b"cache-control", b"max-age=123"],
    ] == output["headers"]
    # BUT... if we reset cacheable_prefixes to [] it should behave as default:
    require_auth_app.cacheable_prefixes = []
    instance = ApplicationCommunicator(require_auth_app, scope)
    await instance.send_input({"type": "http.request"})
    output = await instance.receive_output(1)
    assert [
        [b"content-type", b"text/html; charset=UTF-8"],
        [b"cache-control", b"private"],
    ] == output["headers"]
async def test_scope_auth_allows_access(require_auth_app):
    scope = {
        "type": "http",
        "http_version": "1.0",
        "method": "GET",
        "path": "/",
        "headers": [],
        "auth": {
            "id": 1,
            "name": "authed"
        },
    }
    instance = ApplicationCommunicator(require_auth_app, scope)
    await instance.send_input({"type": "http.request"})
    output = await instance.receive_output(1)
    assert {
        "type":
        "http.response.start",
        "status":
        200,
        "headers": [
            [b"content-type", b"text/html; charset=UTF-8"],
            [b"cache-control", b"private"],
        ],
    } == output
    # Should have got back the auth information we passed in
    output = await instance.receive_output(1)
    body_data = json.loads(output["body"].decode("utf8"))
    assert "world" == body_data["hello"]
    auth = body_data["auth"]
    assert 1 == auth["id"]
    assert "authed" == auth["name"]
async def test_logout(require_auth_app):
    instance = ApplicationCommunicator(
        require_auth_app,
        {"type": "http", "http_version": "1.0", "method": "GET", "path": "/-/logout"},
    )
    await instance.send_input({"type": "http.request"})
    output = await instance.receive_output(1)
    assert {"type": "http.response.start", "status": 302} == {
        "type": output["type"],
        "status": output["status"],
    }
    headers = tuple([tuple(pair) for pair in output["headers"]])
    assert (b"location", b"/") in headers
    assert (b"set-cookie", b"asgi_auth_logout=stay-logged-out; Path=/") in headers
    assert (b"content-type", b"text/html; charset=UTF-8") in headers
    assert (b"cache-control", b"private") in headers
    # asgi_auth should have been set with max-age and expiry
    asgi_auth_cookie = [
        p[1]
        for p in headers
        if p[0] == b"set-cookie" and p[1].startswith(b"asgi_auth=")
    ][0]
    assert b"Max-Age=0" in asgi_auth_cookie
    assert b"Path=/" in asgi_auth_cookie
    assert b"expires=" in asgi_auth_cookie
async def test_signed_cookie_allows_access(path, require_auth_app):
    scope = {
        "type": "http",
        "http_version": "1.0",
        "method": "GET",
        "path": path,
        "headers": [
            [b"cookie", signed_auth_cookie_header(require_auth_app)],
            [b"cache-control", b"private"],
        ],
    }
    instance = ApplicationCommunicator(require_auth_app, scope)
    await instance.send_input({"type": "http.request"})
    output = await instance.receive_output(1)
    assert {
        "type": "http.response.start",
        "status": 200,
        "headers": [
            [b"content-type", b"text/html; charset=UTF-8"],
            [b"cache-control", b"private"],
        ],
    } == output
    # Should have got back the auth information we passed in
    output = await instance.receive_output(1)
    body_data = json.loads(output["body"].decode("utf8"))
    assert "world" == body_data["hello"]
    auth = body_data["auth"]
    assert "123" == auth["id"]
    assert "GitHub User" == auth["name"]
    assert "demouser" == auth["username"]
    assert "*****@*****.**" == auth["email"]
    assert isinstance(auth["ts"], int)
Beispiel #8
0
    async def test_concurrent_async_uses_multiple_thread_pools(self):
        sync_waiter.active_threads.clear()

        # Send 2 requests concurrently
        application = get_asgi_application()
        scope = self.async_request_factory._base_scope(path="/wait/")
        communicators = []
        for _ in range(2):
            communicators.append(ApplicationCommunicator(application, scope))
            await communicators[-1].send_input({"type": "http.request"})

        # Each request must complete with a status code of 200
        # If requests aren't scheduled concurrently, the barrier in the
        # sync_wait view will time out, resulting in a 500 status code.
        for communicator in communicators:
            response_start = await communicator.receive_output()
            self.assertEqual(response_start["type"], "http.response.start")
            self.assertEqual(response_start["status"], 200)
            response_body = await communicator.receive_output()
            self.assertEqual(response_body["type"], "http.response.body")
            self.assertEqual(response_body["body"], b"Hello World!")
            # Give response.close() time to finish.
            await communicator.wait()

        # The requests should have scheduled on different threads. Note
        # active_threads is a set (a thread can only appear once), therefore
        # length is a sufficient check.
        self.assertEqual(len(sync_waiter.active_threads), 2)

        sync_waiter.active_threads.clear()
Beispiel #9
0
async def test_wsgi_stops_iterating_after_content_length_bytes():
    """
    Makes sure WsgiToAsgi does not iterate after than Content-Length bytes
    """
    def wsgi_application(environ, start_response):
        start_response("200 OK", [("Content-Length", "4")])
        yield b"0123"
        pytest.fail("WsgiToAsgi should not iterate after Content-Length bytes")
        yield b"4567"

    application = WsgiToAsgi(wsgi_application)
    instance = ApplicationCommunicator(
        application,
        {
            "type": "http",
            "http_version": "1.0",
            "method": "GET",
            "path": "/",
            "query_string": b"",
            "headers": [],
        },
    )
    await instance.send_input({"type": "http.request"})
    assert (await instance.receive_output(1)) == {
        "type": "http.response.start",
        "status": 200,
        "headers": [(b"content-length", b"4")],
    }
    assert (await instance.receive_output(1)) == {
        "type": "http.response.body",
        "body": b"0123",
        "more_body": True,
    }
    assert (await instance.receive_output(1)) == {"type": "http.response.body"}
Beispiel #10
0
async def test_background_jobs(tracked_requests):
    with app_with_scout() as app:
        communicator = ApplicationCommunicator(
            app, asgi_http_scope(path="/background-jobs/"))
        await communicator.send_input({"type": "http.request"})
        response_start = await communicator.receive_output()
        response_body = await communicator.receive_output()
        await communicator.wait()

    assert response_start["type"] == "http.response.start"
    assert response_start["status"] == 200
    assert response_body["body"] == b"Triggering background jobs"
    assert len(tracked_requests) == 3

    sync_tracked_request = tracked_requests[1]
    assert len(sync_tracked_request.complete_spans) == 1
    sync_span = sync_tracked_request.complete_spans[0]
    assert sync_span.operation == (
        "Job/tests.integration.test_starlette_py36plus." +
        "app_with_scout.<locals>.background_jobs.<locals>.sync_noop")

    async_tracked_request = tracked_requests[2]
    assert len(async_tracked_request.complete_spans) == 1
    async_span = async_tracked_request.complete_spans[0]
    assert async_span.operation == (
        "Job/tests.integration.test_starlette_py36plus." +
        "app_with_scout.<locals>.background_jobs.<locals>.async_noop")
Beispiel #11
0
 async def test_headers(self):
     application = get_asgi_application()
     communicator = ApplicationCommunicator(
         application,
         self.async_request_factory._base_scope(
             path="/meta/",
             headers=[
                 [b"content-type", b"text/plain; charset=utf-8"],
                 [b"content-length", b"77"],
                 [b"referer", b"Scotland"],
                 [b"referer", b"Wales"],
             ],
         ),
     )
     await communicator.send_input({"type": "http.request"})
     response_start = await communicator.receive_output()
     self.assertEqual(response_start["type"], "http.response.start")
     self.assertEqual(response_start["status"], 200)
     self.assertEqual(
         set(response_start["headers"]),
         {
             (b"Content-Length", b"19"),
             (b"Content-Type", b"text/plain; charset=utf-8"),
         },
     )
     response_body = await communicator.receive_output()
     self.assertEqual(response_body["type"], "http.response.body")
     self.assertEqual(response_body["body"], b"From Scotland,Wales")
Beispiel #12
0
 async def test_static_file_response(self):
     application = ASGIStaticFilesHandler(get_asgi_application())
     # Construct HTTP request.
     scope = self.async_request_factory._base_scope(path="/static/file.txt")
     communicator = ApplicationCommunicator(application, scope)
     await communicator.send_input({"type": "http.request"})
     # Get the file content.
     file_path = TEST_STATIC_ROOT / "file.txt"
     with open(file_path, "rb") as test_file:
         test_file_contents = test_file.read()
     # Read the response.
     stat = file_path.stat()
     response_start = await communicator.receive_output()
     self.assertEqual(response_start["type"], "http.response.start")
     self.assertEqual(response_start["status"], 200)
     self.assertEqual(
         set(response_start["headers"]),
         {
             (b"Content-Length", str(
                 len(test_file_contents)).encode("ascii")),
             (b"Content-Type", b"text/plain"),
             (b"Content-Disposition", b'inline; filename="file.txt"'),
             (b"Last-Modified", http_date(stat.st_mtime).encode("ascii")),
         },
     )
     response_body = await communicator.receive_output()
     self.assertEqual(response_body["type"], "http.response.body")
     self.assertEqual(response_body["body"], test_file_contents)
     # Allow response.close() to finish.
     await communicator.wait()
Beispiel #13
0
async def test_handler_body_multiple():
    """
    Tests request handling with a multi-part body
    """
    scope = {
        "type": "http",
        "http_version": "1.1",
        "method": "GET",
        "path": "/test/"
    }
    handler = ApplicationCommunicator(MockHandler(), scope)
    await handler.send_input({
        "type": "http.request",
        "body": b"chunk one",
        "more_body": True
    })
    await handler.send_input({
        "type": "http.request",
        "body": b" \x01 ",
        "more_body": True
    })
    await handler.send_input({"type": "http.request", "body": b"chunk two"})
    await handler.receive_output(1)  # response start
    await handler.receive_output(1)  # response body
    scope, body_stream = MockHandler.request_class.call_args[0]
    body_stream.seek(0)
    assert body_stream.read() == b"chunk one \x01 chunk two"
Beispiel #14
0
    async def test_request_lifecycle_signals_dispatched_with_thread_sensitive(
            self):
        class SignalHandler:
            """Track threads handler is dispatched on."""
            threads = []

            def __call__(self, **kwargs):
                self.threads.append(threading.current_thread())

        signal_handler = SignalHandler()
        request_started.connect(signal_handler)
        request_finished.connect(signal_handler)

        # Perform a basic request.
        application = get_asgi_application()
        scope = self.async_request_factory._base_scope(path='/')
        communicator = ApplicationCommunicator(application, scope)
        await communicator.send_input({'type': 'http.request'})
        response_start = await communicator.receive_output()
        self.assertEqual(response_start['type'], 'http.response.start')
        self.assertEqual(response_start['status'], 200)
        response_body = await communicator.receive_output()
        self.assertEqual(response_body['type'], 'http.response.body')
        self.assertEqual(response_body['body'], b'Hello World!')
        # Give response.close() time to finish.
        await communicator.wait()

        # At this point, AsyncToSync does not have a current executor. Thus
        # SyncToAsync falls-back to .single_thread_executor.
        target_thread = next(iter(SyncToAsync.single_thread_executor._threads))
        request_started_thread, request_finished_thread = signal_handler.threads
        self.assertEqual(request_started_thread, target_thread)
        self.assertEqual(request_finished_thread, target_thread)
        request_started.disconnect(signal_handler)
        request_finished.disconnect(signal_handler)
async def test_auth_callback_calls_github_apis_and_sets_cookie(
        redirect_path, require_auth_app):
    cookie = SimpleCookie()
    cookie["asgi_auth_redirect"] = redirect_path
    cookie["asgi_auth_redirect"]["path"] = "/"
    instance = ApplicationCommunicator(
        require_auth_app,
        {
            "type":
            "http",
            "http_version":
            "1.0",
            "method":
            "GET",
            "path":
            "/-/auth-callback",
            "query_string":
            b"code=github-code-here",
            "headers":
            [[b"cookie",
              cookie.output(header="").lstrip().encode("utf8")]],
        },
    )
    await instance.send_input({"type": "http.request"})
    output = await instance.receive_output(1)
    assert_redirects_and_sets_cookie(require_auth_app, output, redirect_path)
async def test_require_auth_false(require_auth_app):
    scope = {"type": "http", "http_version": "1.0", "method": "GET", "path": "/"}
    # Should redirect if require_auth=True:
    instance = ApplicationCommunicator(require_auth_app, scope)
    await instance.send_input({"type": "http.request"})
    output = await instance.receive_output(1)
    assert 302 == output["status"]
    # Should 200 if require_auth=False
    require_auth_app.require_auth = False
    instance = ApplicationCommunicator(require_auth_app, scope)
    await instance.send_input({"type": "http.request"})
    output2 = await instance.receive_output(1)
    assert 200 == output2["status"]
    # And scope["auth"] should have been None
    body = await instance.receive_output(1)
    assert {"hello": "world", "auth": None} == json.loads(body["body"].decode("utf8"))
Beispiel #17
0
 async def test_disconnect(self):
     application = get_asgi_application()
     scope = self.async_request_factory._base_scope(path="/")
     communicator = ApplicationCommunicator(application, scope)
     await communicator.send_input({"type": "http.disconnect"})
     with self.assertRaises(asyncio.TimeoutError):
         await communicator.receive_output()
Beispiel #18
0
    async def test_request_lifecycle_signals_dispatched_with_thread_sensitive(
            self):
        class SignalHandler:
            """Track threads handler is dispatched on."""

            threads = []

            def __call__(self, **kwargs):
                self.threads.append(threading.current_thread())

        signal_handler = SignalHandler()
        request_started.connect(signal_handler)
        request_finished.connect(signal_handler)

        # Perform a basic request.
        application = get_asgi_application()
        scope = self.async_request_factory._base_scope(path="/")
        communicator = ApplicationCommunicator(application, scope)
        await communicator.send_input({"type": "http.request"})
        response_start = await communicator.receive_output()
        self.assertEqual(response_start["type"], "http.response.start")
        self.assertEqual(response_start["status"], 200)
        response_body = await communicator.receive_output()
        self.assertEqual(response_body["type"], "http.response.body")
        self.assertEqual(response_body["body"], b"Hello World!")
        # Give response.close() time to finish.
        await communicator.wait()

        # AsyncToSync should have executed the signals in the same thread.
        request_started_thread, request_finished_thread = signal_handler.threads
        self.assertEqual(request_started_thread, request_finished_thread)
        request_started.disconnect(signal_handler)
        request_finished.disconnect(signal_handler)
Beispiel #19
0
async def test_asgi_debug():
    captured = []
    app = asgi_debug(hello_world_app, log_to=captured.append)
    instance = ApplicationCommunicator(app, {
        "type": "http",
        "http_version": "1.0",
        "method": "GET",
        "path": "/"
    })
    await instance.send_input({"type": "http.request"})
    assert (await instance.receive_output(1)) == {
        "type": "http.response.start",
        "status": 200,
        "headers": [[b"content-type", b"application/json"]],
    }
    assert (await instance.receive_output(1)) == {
        "type": "http.response.body",
        "body": b'{"hello": "world"}',
    }
    assert [
        "{'http_version': '1.0', 'method': 'GET', 'path': '/', 'type': 'http'}",
        "\n",
        "{'headers': [[b'content-type', b'application/json']],\n 'status': 200,\n 'type': 'http.response.start'}",
        "\n",
        "{'body': b'{\"hello\": \"world\"}', 'type': 'http.response.body'}",
        "\n",
    ] == captured
async def test_redirects_to_github_with_asgi_auth_redirect_cookie(
    path, require_auth_app
):
    instance = ApplicationCommunicator(
        require_auth_app,
        {"type": "http", "http_version": "1.0", "method": "GET", "path": path},
    )
    await instance.send_input({"type": "http.request"})
    output = await instance.receive_output(1)
    assert "http.response.start" == output["type"]
    assert 302 == output["status"]
    headers = tuple([tuple(pair) for pair in output["headers"]])
    assert (
        b"location",
        b"https://github.com/login/oauth/authorize?scope=user:email&client_id=x_client_id",
    ) in headers
    assert (b"cache-control", b"private") in headers
    simple_cookie = SimpleCookie()
    for key, value in headers:
        if key == b"set-cookie":
            simple_cookie.load(value.decode("utf8"))
    assert path == simple_cookie["asgi_auth_redirect"].value
    assert (await instance.receive_output(1)) == {
        "type": "http.response.body",
        "body": b"",
    }
Beispiel #21
0
 async def test_headers(self):
     application = get_asgi_application()
     communicator = ApplicationCommunicator(
         application,
         self._get_scope(
             path='/meta/',
             headers=[
                 [b'content-type', b'text/plain; charset=utf-8'],
                 [b'content-length', b'77'],
                 [b'referer', b'Scotland'],
                 [b'referer', b'Wales'],
             ],
         ),
     )
     await communicator.send_input({'type': 'http.request'})
     response_start = await communicator.receive_output()
     self.assertEqual(response_start['type'], 'http.response.start')
     self.assertEqual(response_start['status'], 200)
     self.assertEqual(
         set(response_start['headers']),
         {
             (b'Content-Length', b'19'),
             (b'Content-Type', b'text/plain; charset=utf-8'),
         },
     )
     response_body = await communicator.receive_output()
     self.assertEqual(response_body['type'], 'http.response.body')
     self.assertEqual(response_body['body'], b'From Scotland,Wales')
Beispiel #22
0
 async def test_file_response(self):
     """
     Makes sure that FileResponse works over ASGI.
     """
     application = get_asgi_application()
     # Construct HTTP request.
     communicator = ApplicationCommunicator(application,
                                            self._get_scope(path='/file/'))
     await communicator.send_input({'type': 'http.request'})
     # Get the file content.
     with open(test_filename, 'rb') as test_file:
         test_file_contents = test_file.read()
     # Read the response.
     response_start = await communicator.receive_output()
     self.assertEqual(response_start['type'], 'http.response.start')
     self.assertEqual(response_start['status'], 200)
     self.assertEqual(
         set(response_start['headers']),
         {
             (b'Content-Length', str(
                 len(test_file_contents)).encode('ascii')),
             (b'Content-Type', b'text/plain'
              if sys.platform == 'win32' else b'text/x-python'),
             (b'Content-Disposition', b'inline; filename="urls.py"'),
         },
     )
     response_body = await communicator.receive_output()
     self.assertEqual(response_body['type'], 'http.response.body')
     self.assertEqual(response_body['body'], test_file_contents)
Beispiel #23
0
 async def test_static_file_response(self):
     application = ASGIStaticFilesHandler(get_asgi_application())
     # Construct HTTP request.
     scope = self.async_request_factory._base_scope(path='/static/file.txt')
     communicator = ApplicationCommunicator(application, scope)
     await communicator.send_input({'type': 'http.request'})
     # Get the file content.
     file_path = TEST_STATIC_ROOT / 'file.txt'
     with open(file_path, 'rb') as test_file:
         test_file_contents = test_file.read()
     # Read the response.
     stat = file_path.stat()
     response_start = await communicator.receive_output()
     self.assertEqual(response_start['type'], 'http.response.start')
     self.assertEqual(response_start['status'], 200)
     self.assertEqual(
         set(response_start['headers']),
         {
             (b'Content-Length', str(
                 len(test_file_contents)).encode('ascii')),
             (b'Content-Type', b'text/plain'),
             (b'Content-Disposition', b'inline; filename="file.txt"'),
             (b'Last-Modified', http_date(stat.st_mtime).encode('ascii')),
         },
     )
     response_body = await communicator.receive_output()
     self.assertEqual(response_body['type'], 'http.response.body')
     self.assertEqual(response_body['body'], test_file_contents)
     # Allow response.close() to finish.
     await communicator.wait()
Beispiel #24
0
async def test_distributed_tracing(scope, tracer):
    app = TraceMiddleware(basic_app, tracer=tracer)
    headers = [
        (http_propagation.HTTP_HEADER_PARENT_ID.encode(), "1234".encode()),
        (http_propagation.HTTP_HEADER_TRACE_ID.encode(), "5678".encode()),
    ]
    scope["headers"] = headers
    instance = ApplicationCommunicator(app, scope)
    await instance.send_input({"type": "http.request", "body": b""})
    response_start = await instance.receive_output(1)
    assert response_start == {
        "type": "http.response.start",
        "status": 200,
        "headers": [[b"Content-Type", b"text/plain"]],
    }
    response_body = await instance.receive_output(1)
    assert response_body == {
        "type": "http.response.body",
        "body": b"*",
    }

    spans = tracer.writer.pop_traces()
    assert len(spans) == 1
    assert len(spans[0]) == 1
    request_span = spans[0][0]
    assert request_span.name == "asgi.request"
    assert request_span.span_type == "web"
    assert request_span.parent_id == 1234
    assert request_span.trace_id == 5678
    assert request_span.error == 0
    assert request_span.get_tag("http.status_code") == "200"
    _check_span_tags(scope, request_span)
Beispiel #25
0
 async def test_disconnect(self):
     application = get_asgi_application()
     communicator = ApplicationCommunicator(application,
                                            self._get_scope(path='/'))
     await communicator.send_input({'type': 'http.disconnect'})
     with self.assertRaises(asyncio.TimeoutError):
         await communicator.receive_output()
Beispiel #26
0
async def test_query_string(scope, tracer):
    with override_http_config("asgi", dict(trace_query_string=True)):
        app = TraceMiddleware(basic_app, tracer=tracer)
        scope["query_string"] = "foo=bar"
        instance = ApplicationCommunicator(app, scope)
        await instance.send_input({"type": "http.request", "body": b""})
        response_start = await instance.receive_output(1)
        assert response_start == {
            "type": "http.response.start",
            "status": 200,
            "headers": [[b"Content-Type", b"text/plain"]],
        }
        response_body = await instance.receive_output(1)
        assert response_body == {
            "type": "http.response.body",
            "body": b"*",
        }

        spans = tracer.writer.pop_traces()
        assert len(spans) == 1
        assert len(spans[0]) == 1
        request_span = spans[0][0]
        assert request_span.name == "asgi.request"
        assert request_span.span_type == "web"
        assert request_span.error == 0
        assert request_span.get_tag("http.status_code") == "200"
        _check_span_tags(scope, request_span)
Beispiel #27
0
async def test_double_callable_asgi(scope, tracer):
    app = TraceMiddleware(double_callable_app, tracer=tracer)
    instance = ApplicationCommunicator(app, scope)
    await instance.send_input({"type": "http.request", "body": b""})
    response_start = await instance.receive_output(1)
    assert response_start == {
        "type": "http.response.start",
        "status": 200,
        "headers": [[b"Content-Type", b"text/plain"]],
    }
    response_body = await instance.receive_output(1)
    assert response_body == {
        "type": "http.response.body",
        "body": b"*",
    }

    spans = tracer.writer.pop_traces()
    assert len(spans) == 1
    assert len(spans[0]) == 1
    request_span = spans[0][0]
    assert request_span.name == "asgi.request"
    assert request_span.span_type == "web"
    assert request_span.error == 0
    assert request_span.get_tag("http.status_code") == "200"
    _check_span_tags(scope, request_span)
Beispiel #28
0
async def test_wsgi_empty_body():
    """
    Makes sure WsgiToAsgi handles an empty body response correctly
    """
    def wsgi_application(environ, start_response):
        start_response("200 OK", [])
        return []

    application = WsgiToAsgi(wsgi_application)
    instance = ApplicationCommunicator(
        application,
        {
            "type": "http",
            "http_version": "1.0",
            "method": "GET",
            "path": "/",
            "query_string": b"",
            "headers": [],
        },
    )
    await instance.send_input({"type": "http.request"})

    # response.start should always be send
    assert (await instance.receive_output(1)) == {
        "type": "http.response.start",
        "status": 200,
        "headers": [],
    }

    assert (await instance.receive_output(1)) == {"type": "http.response.body"}
Beispiel #29
0
async def test_handler_body_multiple():
    """
    Tests request handling with a multi-part body
    """
    scope = {
        "type": "http",
        "http_version": "1.1",
        "method": "GET",
        "path": "/test/",
    }
    handler = ApplicationCommunicator(MockHandler, scope)
    await handler.send_input({
        "type": "http.request",
        "body": b"chunk one",
        "more_body": True,
    })
    await handler.send_input({
        "type": "http.request",
        "body": b" \x01 ",
        "more_body": True,
    })
    await handler.send_input({
        "type": "http.request",
        "body": b"chunk two",
    })
    await handler.receive_output(1)  # response start
    await handler.receive_output(1)  # response body
    MockHandler.request_class.assert_called_with(scope,
                                                 b"chunk one \x01 chunk two")
Beispiel #30
0
async def test_double_to_single_communicator():
    """
    Test that the new application works
    """
    new_app = double_to_single_callable(double_application_function)
    instance = ApplicationCommunicator(new_app, {"value": "woohoo"})
    await instance.send_input({"value": 42})
    assert await instance.receive_output() == {"scope": "woohoo", "message": 42}