Exemple #1
0
def test_iter_raw():
    stream = IteratorStream(iterator=streaming_body())
    response = httpx.Response(200, stream=stream, request=REQUEST)

    raw = b""
    for part in response.iter_raw():
        raw += part
    assert raw == b"Hello, world!"
Exemple #2
0
def test_cannot_read_after_stream_consumed():
    stream = IteratorStream(iterator=streaming_body())
    response = httpx.Response(200, stream=stream, request=REQUEST)

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

    with pytest.raises(httpx.StreamConsumed):
        response.read()
Exemple #3
0
def test_sync_streaming_response():
    stream = IteratorStream(iterator=streaming_body())
    response = httpx.Response(200, stream=stream, request=REQUEST)

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

    content = response.read()

    assert content == b"Hello, world!"
    assert response.content == b"Hello, world!"
    assert response.is_closed
Exemple #4
0
def test_iter_raw_increments_updates_counter():
    stream = IteratorStream(iterator=streaming_body())

    response = httpx.Response(
        200,
        stream=stream,
    )

    num_downloaded = response.num_bytes_downloaded
    for part in response.iter_raw():
        assert len(part) == (response.num_bytes_downloaded - num_downloaded)
        num_downloaded = response.num_bytes_downloaded
Exemple #5
0
def test_cannot_read_after_response_closed():
    is_closed = False

    def close_func():
        nonlocal is_closed
        is_closed = True

    stream = IteratorStream(iterator=streaming_body(), close_func=close_func)
    response = httpx.Response(200, stream=stream, request=REQUEST)

    response.close()
    assert is_closed

    with pytest.raises(httpx.ResponseClosed):
        response.read()
    def _request(
        self,
        method: bytes,
        url: typing.Tuple[bytes, bytes, int, bytes],
        headers: typing.List[typing.Tuple[bytes, bytes]],
        stream: ContentStream,
        timeout: typing.Mapping[str, typing.Optional[float]] = None,
    ) -> typing.Tuple[bytes, int, bytes, typing.List[typing.Tuple[
            bytes, bytes]], ContentStream]:
        scheme, host, port, path = url
        if scheme not in (b"http", b"https"):
            raise httpcore.UnsupportedProtocol(
                f"Scheme {scheme!r} not supported.")

        path, _, query = path.partition(b"?")
        if path == b"/no_redirect":
            return b"HTTP/1.1", httpx.codes.OK, b"OK", [], ByteStream(b"")

        elif path == b"/redirect_301":

            def body():
                yield b"<a href='https://example.org/'>here</a>"

            status_code = httpx.codes.MOVED_PERMANENTLY
            headers = [(b"location", b"https://example.org/")]
            stream = IteratorStream(iterator=body())
            return b"HTTP/1.1", status_code, b"Moved Permanently", headers, stream

        elif path == b"/redirect_302":
            status_code = httpx.codes.FOUND
            headers = [(b"location", b"https://example.org/")]
            return b"HTTP/1.1", status_code, b"Found", headers, ByteStream(b"")

        elif path == b"/redirect_303":
            status_code = httpx.codes.SEE_OTHER
            headers = [(b"location", b"https://example.org/")]
            return b"HTTP/1.1", status_code, b"See Other", headers, ByteStream(
                b"")

        elif path == b"/relative_redirect":
            status_code = httpx.codes.SEE_OTHER
            headers = [(b"location", b"/")]
            return b"HTTP/1.1", status_code, b"See Other", headers, ByteStream(
                b"")

        elif path == b"/malformed_redirect":
            status_code = httpx.codes.SEE_OTHER
            headers = [(b"location", b"https://:443/")]
            return b"HTTP/1.1", status_code, b"See Other", headers, ByteStream(
                b"")

        elif path == b"/invalid_redirect":
            status_code = httpx.codes.SEE_OTHER
            headers = [(b"location", "https://😇/".encode("utf-8"))]
            return b"HTTP/1.1", status_code, b"See Other", headers, ByteStream(
                b"")

        elif path == b"/no_scheme_redirect":
            status_code = httpx.codes.SEE_OTHER
            headers = [(b"location", b"//example.org/")]
            return b"HTTP/1.1", status_code, b"See Other", headers, ByteStream(
                b"")

        elif path == b"/multiple_redirects":
            params = parse_qs(query.decode("ascii"))
            count = int(params.get("count", "0")[0])
            redirect_count = count - 1
            code = httpx.codes.SEE_OTHER if count else httpx.codes.OK
            phrase = b"See Other" if count else b"OK"
            location = b"/multiple_redirects"
            if redirect_count:
                location += b"?count=" + str(redirect_count).encode("ascii")
            headers = [(b"location", location)] if count else []
            return b"HTTP/1.1", code, phrase, headers, ByteStream(b"")

        if path == b"/redirect_loop":
            code = httpx.codes.SEE_OTHER
            headers = [(b"location", b"/redirect_loop")]
            return b"HTTP/1.1", code, b"See Other", headers, ByteStream(b"")

        elif path == b"/cross_domain":
            code = httpx.codes.SEE_OTHER
            headers = [(b"location",
                        b"https://example.org/cross_domain_target")]
            return b"HTTP/1.1", code, b"See Other", headers, ByteStream(b"")

        elif path == b"/cross_domain_target":
            headers_dict = {
                key.decode("ascii"): value.decode("ascii")
                for key, value in headers
            }
            stream = ByteStream(json.dumps({"headers": headers_dict}).encode())
            return b"HTTP/1.1", 200, b"OK", [], stream

        elif path == b"/redirect_body":
            code = httpx.codes.PERMANENT_REDIRECT
            headers = [(b"location", b"/redirect_body_target")]
            return b"HTTP/1.1", code, b"Permanent Redirect", headers, ByteStream(
                b"")

        elif path == b"/redirect_no_body":
            code = httpx.codes.SEE_OTHER
            headers = [(b"location", b"/redirect_body_target")]
            return b"HTTP/1.1", code, b"See Other", headers, ByteStream(b"")

        elif path == b"/redirect_body_target":
            content = b"".join(stream)
            headers_dict = {
                key.decode("ascii"): value.decode("ascii")
                for key, value in headers
            }
            stream = ByteStream(
                json.dumps({
                    "body": content.decode(),
                    "headers": headers_dict
                }).encode())
            return b"HTTP/1.1", 200, b"OK", [], stream

        elif path == b"/cross_subdomain":
            host = get_header_value(headers, "host")
            if host != "www.example.org":
                headers = [(b"location",
                            b"https://www.example.org/cross_subdomain")]
                return (
                    b"HTTP/1.1",
                    httpx.codes.PERMANENT_REDIRECT,
                    b"Permanent Redirect",
                    headers,
                    ByteStream(b""),
                )
            else:
                return b"HTTP/1.1", 200, b"OK", [], ByteStream(
                    b"Hello, world!")

        elif path == b"/redirect_custom_scheme":
            status_code = httpx.codes.MOVED_PERMANENTLY
            headers = [(b"location", b"market://details?id=42")]
            return (
                b"HTTP/1.1",
                status_code,
                b"Moved Permanently",
                headers,
                ByteStream(b""),
            )

        stream = ByteStream(
            b"Hello, world!") if method != b"HEAD" else ByteStream(b"")

        return b"HTTP/1.1", 200, b"OK", [], stream