async def test_mounted_transport(): transport = MockTransport(unmounted) mounts = {"custom://": MockTransport(mounted)} async with httpx.AsyncClient(transport=transport, mounts=mounts) as client: response = await client.get("https://www.example.com") assert response.status_code == 200 assert response.json() == {"app": "unmounted"} response = await client.get("custom://www.example.com") assert response.status_code == 200 assert response.json() == {"app": "mounted"}
async def test_auth_invalid_type() -> None: app = App() with pytest.raises(TypeError): client = httpx.AsyncClient( transport=MockTransport(app), auth="not a tuple, not a callable", # type: ignore ) async with httpx.AsyncClient(transport=MockTransport(app)) as client: with pytest.raises(TypeError): await client.get(auth="not a tuple, not a callable") # type: ignore with pytest.raises(TypeError): client.auth = "not a tuple, not a callable" # type: ignore
def test_same_domain_redirect(): client = httpx.Client(transport=MockTransport(redirects)) url = "https://example.org/cross_domain" headers = {"Authorization": "abc"} response = client.get(url, headers=headers) assert response.url == "https://example.org/cross_domain_target" assert response.json()["headers"]["authorization"] == "abc"
async def test_digest_auth_no_specified_qop() -> None: url = "https://example.org/" auth = DigestAuth(username="******", password="******") app = DigestApp(qop="") async with httpx.AsyncClient(transport=MockTransport(app)) as client: response = await client.get(url, auth=auth) assert response.status_code == 200 assert len(response.history) == 1 authorization = typing.cast(dict, response.json())["auth"] scheme, _, fields = authorization.partition(" ") assert scheme == "Digest" response_fields = [field.strip() for field in fields.split(",")] digest_data = dict(field.split("=") for field in response_fields) assert "qop" not in digest_data assert "nc" not in digest_data assert "cnonce" not in digest_data assert digest_data["username"] == '"tomchristie"' assert digest_data["realm"] == '"*****@*****.**"' assert len(digest_data["nonce"]) == 64 + 2 # extra quotes assert digest_data["uri"] == '"/"' assert len(digest_data["response"]) == 64 + 2 assert len(digest_data["opaque"]) == 64 + 2 assert digest_data["algorithm"] == "SHA-256"
async def test_async_too_many_redirects_calling_next(): async with httpx.AsyncClient(transport=MockTransport(redirects)) as client: url = "https://example.org/multiple_redirects?count=21" response = await client.get(url, allow_redirects=False) with pytest.raises(httpx.TooManyRedirects): while response.is_redirect: response = await response.anext()
def test_can_stream_if_no_redirect(): client = httpx.Client(transport=MockTransport(redirects)) url = "https://example.org/redirect_301" with client.stream("GET", url, allow_redirects=False) as response: assert not response.is_closed assert response.status_code == httpx.codes.MOVED_PERMANENTLY assert response.headers["location"] == "https://example.org/"
def test_setting_client_cookies_to_cookiejar() -> None: """ Send a request including a cookie, using a `CookieJar` instance. """ url = "http://example.org/echo_cookies" cookies = CookieJar() cookie = Cookie( version=0, name="example-name", value="example-value", port=None, port_specified=False, domain="", domain_specified=False, domain_initial_dot=False, path="/", path_specified=True, secure=False, expires=None, discard=True, comment=None, comment_url=None, rest={"HttpOnly": ""}, rfc2109=False, ) cookies.set_cookie(cookie) client = httpx.Client(transport=MockTransport(get_and_set_cookies)) client.cookies = cookies # type: ignore response = client.get(url) assert response.status_code == 200 assert response.json() == {"cookies": "example-name=example-value"}
def test_no_redirect(): client = httpx.Client(transport=MockTransport(redirects)) url = "https://example.com/no_redirect" response = client.get(url) assert response.status_code == 200 with pytest.raises(httpx.NotRedirectResponse): response.next()
def test_redirect_cookie_behavior(): client = httpx.Client(transport=MockTransport(cookie_sessions)) # The client is not logged in. response = client.get("https://example.com/") assert response.url == "https://example.com/" assert response.text == "Not logged in" # Login redirects to the homepage, setting a session cookie. response = client.post("https://example.com/login") assert response.url == "https://example.com/" assert response.text == "Logged in" # The client is logged in. response = client.get("https://example.com/") assert response.url == "https://example.com/" assert response.text == "Logged in" # Logout redirects to the homepage, expiring the session cookie. response = client.post("https://example.com/logout") assert response.url == "https://example.com/" assert response.text == "Not logged in" # The client is not logged in. response = client.get("https://example.com/") assert response.url == "https://example.com/" assert response.text == "Not logged in"
def test_header_update(): url = "http://example.org/echo_headers" client = httpx.Client(transport=MockTransport(echo_headers)) first_response = client.get(url) client.headers.update({ "User-Agent": "python-myclient/0.2.1", "Another-Header": "AThing" }) second_response = client.get(url) assert first_response.status_code == 200 assert first_response.json() == { "headers": { "accept": "*/*", "accept-encoding": "gzip, deflate, br", "connection": "keep-alive", "host": "example.org", "user-agent": f"python-httpx/{httpx.__version__}", } } assert second_response.status_code == 200 assert second_response.json() == { "headers": { "accept": "*/*", "accept-encoding": "gzip, deflate, br", "another-header": "AThing", "connection": "keep-alive", "host": "example.org", "user-agent": "python-myclient/0.2.1", } }
async def test_async_event_hooks(): events = [] async def on_request(request): events.append({"event": "request", "headers": dict(request.headers)}) async def on_response(response): events.append({"event": "response", "headers": dict(response.headers)}) event_hooks = {"request": [on_request], "response": [on_response]} async with httpx.AsyncClient(event_hooks=event_hooks, transport=MockTransport(app)) as http: await http.get("http://127.0.0.1:8000/", auth=("username", "password")) assert events == [ { "event": "request", "headers": { "host": "127.0.0.1:8000", "user-agent": f"python-httpx/{httpx.__version__}", "accept": "*/*", "accept-encoding": "gzip, deflate, br", "connection": "keep-alive", "authorization": "Basic dXNlcm5hbWU6cGFzc3dvcmQ=", }, }, { "event": "response", "headers": { "server": "testserver" }, }, ]
def test_sync_too_many_redirects_calling_next(): client = httpx.Client(transport=MockTransport(redirects)) url = "https://example.org/multiple_redirects?count=21" response = client.get(url, allow_redirects=False) with pytest.raises(httpx.TooManyRedirects): while response.is_redirect: response = response.next()
def test_malformed_redirect(): # https://github.com/encode/httpx/issues/771 client = httpx.Client(transport=MockTransport(redirects)) response = client.get("http://example.org/malformed_redirect") assert response.status_code == httpx.codes.OK assert response.url == "https://example.org:443/" assert len(response.history) == 1
async def test_digest_auth_qop_must_be_auth_or_auth_int() -> None: url = "https://example.org/" auth = DigestAuth(username="******", password="******") app = DigestApp(qop="not-auth") async with httpx.AsyncClient(transport=MockTransport(app)) as client: with pytest.raises(ProtocolError): await client.get(url, auth=auth)
async def test_digest_auth_qop_auth_int_not_implemented() -> None: url = "https://example.org/" auth = DigestAuth(username="******", password="******") app = DigestApp(qop="auth-int") async with httpx.AsyncClient(transport=MockTransport(app)) as client: with pytest.raises(NotImplementedError): await client.get(url, auth=auth)
def test_client_closed_state_using_with_block(): with httpx.Client(transport=MockTransport(hello_world)) as client: assert not client.is_closed client.get("http://example.com") assert client.is_closed with pytest.raises(RuntimeError): client.get("http://example.com")
def test_all_mounted_transport(): mounts = {"all://": MockTransport(mounted)} client = httpx.Client(mounts=mounts) response = client.get("https://www.example.com") assert response.status_code == 200 assert response.json() == {"app": "mounted"}
def test_multipart_invalid_value(value): client = httpx.Client(transport=MockTransport(echo_request_content)) data = {"text": value} files = {"file": io.BytesIO(b"<file content>")} with pytest.raises(TypeError) as e: client.post("http://127.0.0.1:8000/", data=data, files=files) assert "Invalid type for value" in str(e.value)
async def test_auth_hidden_header() -> None: url = "https://example.org/" auth = ("example-username", "example-password") app = App() async with httpx.AsyncClient(transport=MockTransport(app)) as client: response = await client.get(url, auth=auth) assert "'authorization': '[secure]'" in str(response.request.headers)
def test_get_cookie() -> None: url = "http://example.org/set_cookie" client = httpx.Client(transport=MockTransport(get_and_set_cookies)) response = client.get(url) assert response.status_code == 200 assert response.cookies["example-name"] == "example-value" assert client.cookies["example-name"] == "example-value"
def test_cannot_redirect_streaming_body(): client = httpx.Client(transport=MockTransport(redirects)) url = "https://example.org/redirect_body" def streaming_body(): yield b"Example request body" # pragma: nocover with pytest.raises(httpx.RequestBodyUnavailable): client.post(url, data=streaming_body())
def test_sync_digest_auth_raises_protocol_error_on_malformed_header( auth_header: str, ) -> None: url = "https://example.org/" auth = DigestAuth(username="******", password="******") app = App(auth_header=auth_header, status_code=401) with httpx.Client(transport=MockTransport(app)) as client: with pytest.raises(ProtocolError): client.get(url, auth=auth)
async def test_basic_auth_in_url() -> None: url = "https://*****:*****@example.org/" app = App() async with httpx.AsyncClient(transport=MockTransport(app)) as client: response = await client.get(url) assert response.status_code == 200 assert response.json() == {"auth": "Basic dG9tY2hyaXN0aWU6cGFzc3dvcmQxMjM="}
def test_cannot_redirect_streaming_body(): client = httpx.Client(transport=MockTransport(redirects)) url = "https://example.org/redirect_body" def streaming_body(): yield b"Example request body" # pragma: nocover with pytest.raises(httpx.StreamConsumed): client.post(url, content=streaming_body())
async def test_digest_auth_incorrect_credentials() -> None: url = "https://example.org/" auth = DigestAuth(username="******", password="******") app = DigestApp(send_response_after_attempt=2) async with httpx.AsyncClient(transport=MockTransport(app)) as client: response = await client.get(url, auth=auth) assert response.status_code == 401 assert len(response.history) == 1
async def test_digest_auth_qop_including_spaces_and_auth_returns_auth(qop: str) -> None: url = "https://example.org/" auth = DigestAuth(username="******", password="******") app = DigestApp(qop=qop) async with httpx.AsyncClient(transport=MockTransport(app)) as client: response = await client.get(url, auth=auth) assert response.status_code == 200 assert len(response.history) == 1
def test_multiple_redirects(): client = httpx.Client(transport=MockTransport(redirects)) response = client.get("https://example.org/multiple_redirects?count=20") assert response.status_code == httpx.codes.OK assert response.url == "https://example.org/multiple_redirects" assert len(response.history) == 20 assert response.history[0].url == "https://example.org/multiple_redirects?count=20" assert response.history[1].url == "https://example.org/multiple_redirects?count=19" assert len(response.history[0].history) == 0 assert len(response.history[1].history) == 1
async def test_auth_header_has_priority_over_netrc() -> None: os.environ["NETRC"] = str(FIXTURES_DIR / ".netrc") url = "http://netrcexample.org" app = App() async with httpx.AsyncClient(transport=MockTransport(app)) as client: response = await client.get(url, headers={"Authorization": "Override"}) assert response.status_code == 200 assert response.json() == {"auth": "Override"}
async def test_auth_disable_per_request() -> None: url = "https://example.org/" auth = ("tomchristie", "password123") app = App() async with httpx.AsyncClient(transport=MockTransport(app), auth=auth) as client: response = await client.get(url, auth=None) assert response.status_code == 200 assert response.json() == {"auth": None}
def test_client_queryparams_echo(): url = "http://example.org/echo_queryparams" client_queryparams = "first=str" request_queryparams = {"second": "dict"} client = httpx.Client(transport=MockTransport(hello_world), params=client_queryparams) response = client.get(url, params=request_queryparams) assert response.status_code == 200 assert response.url == "http://example.org/echo_queryparams?first=str&second=dict"