Beispiel #1
0
def test_multi_with_identity():
    body = b"test 123"
    compressed_body = brotli.compress(body)

    headers = [(b"Content-Encoding", b"br, identity")]
    response = httpcore.Response(200, headers=headers, content=compressed_body)
    assert response.content == body

    headers = [(b"Content-Encoding", b"identity, br")]
    response = httpcore.Response(200, headers=headers, content=compressed_body)
    assert response.content == body
Beispiel #2
0
def test_response():
    response = httpcore.Response(200)
    assert response.status == 200
    assert response.headers == []
    assert response.extensions == {}
    assert repr(response) == "<Response [200]>"
    assert repr(response.stream) == "<ByteStream [0 bytes]>"
Beispiel #3
0
def test_brotli():
    body = b"test 123"
    compressed_body = brotli.compress(body)

    headers = [(b"Content-Encoding", b"br")]
    response = httpcore.Response(200, headers=headers, content=compressed_body)
    assert response.content == body
Beispiel #4
0
async def test_stream_interface():
    response = httpcore.Response(200, content=b"Hello, world!")

    content = b""
    async for part in response.stream():
        content += part
    assert content == b"Hello, world!"
Beispiel #5
0
def test_httpcore_exception_mapping(server) -> None:
    """
    HTTPCore exception mapping works as expected.
    """
    def connect_failed(*args, **kwargs):
        raise httpcore.ConnectError()

    class TimeoutStream:
        def __iter__(self):
            raise httpcore.ReadTimeout()

        def close(self):
            pass

    with mock.patch("httpcore.ConnectionPool.handle_request",
                    side_effect=connect_failed):
        with pytest.raises(httpx.ConnectError):
            httpx.get(server.url)

    with mock.patch(
            "httpcore.ConnectionPool.handle_request",
            return_value=httpcore.Response(200,
                                           headers=[],
                                           content=TimeoutStream(),
                                           extensions={}),
    ):
        with pytest.raises(httpx.ReadTimeout):
            httpx.get(server.url)
Beispiel #6
0
def test_response_force_encoding():
    response = httpcore.Response(200, content="Snowman: ☃".encode("utf-8"))
    response.encoding = "iso-8859-1"
    assert response.status_code == 200
    assert response.reason_phrase == "OK"
    assert response.text == "Snowman: â\x98\x83"
    assert response.encoding == "iso-8859-1"
Beispiel #7
0
async def test_cannot_read_after_response_closed():
    response = httpcore.Response(200, content=streaming_body())

    await response.close()

    with pytest.raises(httpcore.ResponseClosed):
        await response.read()
Beispiel #8
0
async def test_raw_interface():
    response = httpcore.Response(200, content=b"Hello, world!")

    raw = b""
    async for part in response.raw():
        raw += part
    assert raw == b"Hello, world!"
Beispiel #9
0
def test_decoding_errors(header_value):
    headers = [(b"Content-Encoding", header_value)]
    body = b"test 123"
    compressed_body = brotli.compress(body)[3:]
    with pytest.raises(httpcore.exceptions.DecodingError):
        response = httpcore.Response(200, headers=headers, content=compressed_body)
        response.content
Beispiel #10
0
def test_response_default_encoding():
    """
    Default to utf-8 if all else fails.
    """
    response = httpcore.Response(200, content=b"")
    assert response.text == ""
    assert response.encoding == "utf-8"
Beispiel #11
0
def test_response_autodetect_encoding():
    """
    Autodetect encoding if there is no charset info in a Content-Type header.
    """
    content = "おはようございます。".encode("EUC-JP")
    response = httpcore.Response(200, content=content)
    assert response.text == "おはようございます。"
    assert response.encoding == "EUC-JP"
Beispiel #12
0
def test_deflate():
    body = b"test 123"
    compressor = zlib.compressobj(9, zlib.DEFLATED, -zlib.MAX_WBITS)
    compressed_body = compressor.compress(body) + compressor.flush()

    headers = [(b"Content-Encoding", b"deflate")]
    response = httpcore.Response(200, headers=headers, content=compressed_body)
    assert response.content == body
Beispiel #13
0
def test_response_non_text_encoding():
    """
    Default to apparent encoding for non-text content-type headers.
    """
    headers = {"Content-Type": "image/png"}
    response = httpcore.Response(200, content=b"xyz", headers=headers)
    assert response.text == "xyz"
    assert response.encoding == "ascii"
Beispiel #14
0
def test_response_content_type_encoding():
    """
    Use the charset encoding in the Content-Type header if possible.
    """
    headers = {"Content-Type": "text-plain; charset=latin-1"}
    content = "Latin 1: ÿ".encode("latin-1")
    response = httpcore.Response(200, content=content, headers=headers)
    assert response.text == "Latin 1: ÿ"
    assert response.encoding == "latin-1"
Beispiel #15
0
def test_response_fallback_to_autodetect():
    """
    Fallback to autodetection if we get an invalid charset in the Content-Type header.
    """
    headers = {"Content-Type": "text-plain; charset=invalid-codec-name"}
    content = "おはようございます。".encode("EUC-JP")
    response = httpcore.Response(200, content=content, headers=headers)
    assert response.text == "おはようございます。"
    assert response.encoding == "EUC-JP"
Beispiel #16
0
async def test_cannot_read_after_stream_consumed():
    response = httpcore.Response(200, content=streaming_body())

    content = b""
    async for part in response.stream():
        content += part

    with pytest.raises(httpcore.StreamConsumed):
        await response.read()
Beispiel #17
0
 def from_sync_httpx_response(cls, httpx_response, target, **kwargs):
     """
     Create a `httpcore` response from a `HTTPX` response.
     """
     return httpcore.Response(
         status=httpx_response.status_code,
         headers=httpx_response.headers.raw,
         content=httpx_response.stream,
         extensions=httpx_response.extensions,
     )
Beispiel #18
0
def test_response_set_explicit_encoding():
    headers = {
        "Content-Type": "text-plain; charset=utf-8"
    }  # Deliberately incorrect charset
    response = httpcore.Response(
        200, content="Latin 1: ÿ".encode("latin-1"), headers=headers
    )
    response.encoding = "latin-1"
    assert response.text == "Latin 1: ÿ"
    assert response.encoding == "latin-1"
Beispiel #19
0
async def test_streaming_response():
    response = httpcore.Response(200, content=streaming_body())

    assert response.status_code == 200
    assert not response.is_closed

    content = await response.read()

    assert content == b"Hello, world!"
    assert response.content == b"Hello, world!"
    assert response.is_closed
Beispiel #20
0
def test_response_default_text_encoding():
    """
    A media type of 'text/*' with no charset should default to ISO-8859-1.
    See: https://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.7.1
    """
    content = b"Hello, world!"
    headers = {"Content-Type": "text/plain"}
    response = httpcore.Response(200, content=content, headers=headers)
    assert response.status_code == 200
    assert response.encoding == "iso-8859-1"
    assert response.text == "Hello, world!"
Beispiel #21
0
async def test_streaming():
    body = b"test 123"
    compressor = zlib.compressobj(9, zlib.DEFLATED, zlib.MAX_WBITS | 16)

    async def compress(body):
        yield compressor.compress(body)
        yield compressor.flush()

    headers = [(b"Content-Encoding", b"gzip")]
    response = httpcore.Response(200, headers=headers, content=compress(body))
    assert not hasattr(response, "body")
    assert await response.read() == body
Beispiel #22
0
async def test_read_response():
    response = httpcore.Response(200, content=b"Hello, world!")

    assert response.status_code == 200
    assert response.text == "Hello, world!"
    assert response.encoding == "ascii"
    assert response.is_closed

    content = await response.read()

    assert content == b"Hello, world!"
    assert response.content == b"Hello, world!"
    assert response.is_closed
Beispiel #23
0
def test_multi():
    body = b"test 123"

    deflate_compressor = zlib.compressobj(9, zlib.DEFLATED, -zlib.MAX_WBITS)
    compressed_body = deflate_compressor.compress(body) + deflate_compressor.flush()

    gzip_compressor = zlib.compressobj(9, zlib.DEFLATED, zlib.MAX_WBITS | 16)
    compressed_body = (
        gzip_compressor.compress(compressed_body) + gzip_compressor.flush()
    )

    headers = [(b"Content-Encoding", b"deflate, gzip")]
    response = httpcore.Response(200, headers=headers, content=compressed_body)
    assert response.content == body
Beispiel #24
0
async def test_response_async_streaming():
    stream = AsyncByteIterator([b"Hello, ", b"world!"])
    response = httpcore.Response(200, content=stream)
    content = b"".join([chunk async for chunk in response.aiter_stream()])
    assert content == b"Hello, world!"

    # We streamed the response rather than reading it, so .content is not available.
    with pytest.raises(RuntimeError):
        response.content

    # Once we've streamed the response, we can't access the stream again.
    with pytest.raises(RuntimeError):
        async for chunk in response.aiter_stream():
            pass  # pragma: nocover
Beispiel #25
0
    async def send(  # type: ignore
            self, request: requests.PreparedRequest, *args: typing.Any,
            **kwargs: typing.Any) -> requests.Response:
        scheme, netloc, path, query, fragment = urlsplit(
            request.url)  # type: ignore

        default_port = {"http": 80, "ws": 80, "https": 443, "wss": 443}[scheme]

        if ":" in netloc:
            host, port_string = netloc.split(":", 1)
            port = int(port_string)
        else:
            host = netloc
            port = default_port

        # Include the 'host' header.
        if "host" in request.headers:
            headers = []  # type: typing.List[typing.Tuple[bytes, bytes]]
        elif port == default_port:
            headers = [(b"host", host.encode())]
        else:
            headers = [(b"host", (f"{host}:{port}").encode())]

        # Include other request headers.
        headers += [(key.lower().encode(), value.encode())
                    for key, value in request.headers.items()]

        scope = {
            "type": "http",
            "http_version": "1.1",
            "method": request.method,
            "path": unquote(path),
            "root_path": "",
            "scheme": scheme,
            "query_string": query.encode(),
            "headers": headers,
            "client": ["testclient", 50000],
            "server": [host, port],
            "extensions": {
                "http.response.template": {}
            },
        }

        async def receive():
            nonlocal request_complete, response_complete

            if request_complete:
                while not response_complete:
                    await asyncio.sleep(0.0001)
                return {"type": "http.disconnect"}

            body = request.body
            if isinstance(body, str):
                body_bytes = body.encode("utf-8")  # type: bytes
            elif body is None:
                body_bytes = b""
            elif isinstance(body, types.GeneratorType):
                try:
                    chunk = body.send(None)
                    if isinstance(chunk, str):
                        chunk = chunk.encode("utf-8")
                    return {
                        "type": "http.request",
                        "body": chunk,
                        "more_body": True
                    }
                except StopIteration:
                    request_complete = True
                    return {"type": "http.request", "body": b""}
            else:
                body_bytes = body

            request_complete = True
            return {"type": "http.request", "body": body_bytes}

        async def send(message) -> None:
            nonlocal raw_kwargs, response_started, response_complete, template, context

            if message["type"] == "http.response.start":
                assert (not response_started
                        ), 'Received multiple "http.response.start" messages.'
                raw_kwargs["status_code"] = message["status"]
                raw_kwargs["headers"] = message["headers"]
                response_started = True
            elif message["type"] == "http.response.body":
                assert (
                    response_started
                ), 'Received "http.response.body" without "http.response.start".'
                assert (
                    not response_complete
                ), 'Received "http.response.body" after response completed.'
                body = message.get("body", b"")
                more_body = message.get("more_body", False)
                if request.method != "HEAD":
                    raw_kwargs["content"] += body
                if not more_body:
                    response_complete = True
            elif message["type"] == "http.response.template":
                template = message["template"]
                context = message["context"]

        request_complete = False
        response_started = False
        response_complete = False
        raw_kwargs = {"content": b""}  # type: typing.Dict[str, typing.Any]
        template = None
        context = None

        try:
            await self.app(scope, receive, send)
        except BaseException as exc:
            if not self.suppress_exceptions:
                raise exc from None

        if not self.suppress_exceptions:
            assert response_started, "TestClient did not receive any response."
        elif not response_started:
            raw_kwargs = {"status_code": 500, "headers": []}

        raw = httpcore.Response(**raw_kwargs)
        response = self.build_response(request, raw)
        if template is not None:
            response.template = template
            response.context = context
        return response
Beispiel #26
0
def test_response():
    response = httpcore.Response(200, content=b"Hello, world!")
    assert response.status_code == 200
    assert response.reason_phrase == "OK"
    assert response.text == "Hello, world!"
Beispiel #27
0
async def test_response_async_read():
    stream = AsyncByteIterator([b"Hello, ", b"world!"])
    response = httpcore.Response(200, content=stream)
    assert await response.aread() == b"Hello, world!"
    assert response.content == b"Hello, world!"
Beispiel #28
0
def test_unknown_status_code():
    response = httpcore.Response(600)
    assert response.status_code == 600
    assert response.reason_phrase == ""
    assert response.text == ""
Beispiel #29
0
    async def send(  # type: ignore
        self,
        request: requests.PreparedRequest,
        gather_return: bool = False,
        *args: typing.Any,
        **kwargs: typing.Any,
    ) -> requests.Response:
        """This method is taken MOSTLY verbatim from requests-asyn. The
        difference is the capturing of a response on the ASGI call and then
        returning it on the response object. This is implemented to achieve:

        request, response = await app.asgi_client.get("/")

        You can see the original code here:
        https://github.com/encode/requests-async/blob/614f40f77f19e6c6da8a212ae799107b0384dbf9/requests_async/asgi.py#L51"""  # noqa
        scheme, netloc, path, query, fragment = urlsplit(
            request.url)  # type: ignore

        default_port = {"http": 80, "ws": 80, "https": 443, "wss": 443}[scheme]

        if ":" in netloc:
            host, port_string = netloc.split(":", 1)
            port = int(port_string)
        else:
            host = netloc
            port = default_port

        # Include the 'host' header.
        if "host" in request.headers:
            headers = []  # type: typing.List[typing.Tuple[bytes, bytes]]
        elif port == default_port:
            headers = [(b"host", host.encode())]
        else:
            headers = [(b"host", (f"{host}:{port}").encode())]

        # Include other request headers.
        headers += [(key.lower().encode(), value.encode())
                    for key, value in request.headers.items()]

        no_response = False
        if scheme in {"ws", "wss"}:
            subprotocol = request.headers.get("sec-websocket-protocol", None)
            if subprotocol is None:
                subprotocols = []  # type: typing.Sequence[str]
            else:
                subprotocols = [
                    value.strip() for value in subprotocol.split(",")
                ]

            scope = {
                "type": "websocket",
                "path": unquote(path),
                "root_path": "",
                "scheme": scheme,
                "query_string": query.encode(),
                "headers": headers,
                "client": ["testclient", 50000],
                "server": [host, port],
                "subprotocols": subprotocols,
            }
            no_response = True

        else:
            scope = {
                "type": "http",
                "http_version": "1.1",
                "method": request.method,
                "path": unquote(path),
                "root_path": "",
                "scheme": scheme,
                "query_string": query.encode(),
                "headers": headers,
                "client": ["testclient", 50000],
                "server": [host, port],
                "extensions": {
                    "http.response.template": {}
                },
            }

        async def receive():
            nonlocal request_complete, response_complete

            if request_complete:
                while not response_complete:
                    await asyncio.sleep(0.0001)
                return {"type": "http.disconnect"}

            body = request.body
            if isinstance(body, str):
                body_bytes = body.encode("utf-8")  # type: bytes
            elif body is None:
                body_bytes = b""
            elif isinstance(body, types.GeneratorType):
                try:
                    chunk = body.send(None)
                    if isinstance(chunk, str):
                        chunk = chunk.encode("utf-8")
                    return {
                        "type": "http.request",
                        "body": chunk,
                        "more_body": True,
                    }
                except StopIteration:
                    request_complete = True
                    return {"type": "http.request", "body": b""}
            else:
                body_bytes = body

            request_complete = True
            return {"type": "http.request", "body": body_bytes}

        request_complete = False
        response_started = False
        response_complete = False
        raw_kwargs = {"content": b""}  # type: typing.Dict[str, typing.Any]
        template = None
        context = None
        return_value = None

        async def send(message) -> None:
            nonlocal raw_kwargs, response_started, response_complete, template, context  # noqa

            if message["type"] == "http.response.start":
                assert (not response_started
                        ), 'Received multiple "http.response.start" messages.'
                raw_kwargs["status_code"] = message["status"]
                raw_kwargs["headers"] = message["headers"]
                response_started = True
            elif message["type"] == "http.response.body":
                assert response_started, ('Received "http.response.body" '
                                          'without "http.response.start".')
                assert (
                    not response_complete
                ), 'Received "http.response.body" after response completed.'
                body = message.get("body", b"")
                more_body = message.get("more_body", False)
                if request.method != "HEAD":
                    raw_kwargs["content"] += body
                if not more_body:
                    response_complete = True
            elif message["type"] == "http.response.template":
                template = message["template"]
                context = message["context"]

        try:
            return_value = await self.app(scope, receive, send)
        except BaseException as exc:
            if not self.suppress_exceptions:
                raise exc from None

        if no_response:
            response_started = True
            raw_kwargs = {"status_code": 204, "headers": []}

        if not self.suppress_exceptions:
            assert response_started, "TestClient did not receive any response."
        elif not response_started:
            raw_kwargs = {"status_code": 500, "headers": []}

        raw = httpcore.Response(**raw_kwargs)
        response = self.build_response(request, raw)
        if template is not None:
            response.template = template
            response.context = context

        if gather_return:
            response.return_value = return_value
        return response
Beispiel #30
0
def test_response_repr():
    response = httpcore.Response(200, content=b"Hello, world!")
    assert repr(response) == "<Response(200, 'OK')>"