]> git.ipfire.org Git - thirdparty/httpx.git/commitdiff
Add `response.next_request` (#1334)
authorTom Christie <tom@tomchristie.com>
Thu, 1 Oct 2020 12:52:03 +0000 (13:52 +0100)
committerGitHub <noreply@github.com>
Thu, 1 Oct 2020 12:52:03 +0000 (13:52 +0100)
* Add response.next_request

* Add response.next_request

* Add response.next_request to the docs

docs/api.md
docs/compatibility.md
httpx/_client.py
httpx/_models.py
tests/client/test_redirects.py

index 710072c8ef7242a730f08ac0c6937690308dffa2..817467ec55b15d5e2521e3cbcda44eb9b38f563c 100644 (file)
@@ -31,7 +31,7 @@
 
 ::: httpx.delete
     :docstring:
-    
+
 ::: httpx.stream
     :docstring:
 
@@ -63,6 +63,7 @@
 * `.encoding` - **str**
 * `.is_redirect` - **bool**
 * `.request` - **Request**
+* `.next_request` - **Optional[Request]**
 * `.cookies` - **Cookies**
 * `.history` - **List[Response]**
 * `.elapsed` - **[timedelta](https://docs.python.org/3/library/datetime.html)**
index 593a8e22d2b10f99e7f701b0b456423b7c989f8a..016c15a7e60ef003cbf1cca0f68c16094f939200 100644 (file)
@@ -115,3 +115,17 @@ On the other hand, HTTPX uses [HTTPCore](https://github.com/encode/httpcore) as
 ## Query Parameters
 
 `requests` omits `params` whose values are `None` (e.g. `requests.get(..., params={"foo": None})`). This is not supported by HTTPX.
+
+## Determining the next redirect request
+
+When using `allow_redirects=False`, the `requests` library exposes an attribute `response.next`, which can be used to obtain the next redirect request.
+
+In HTTPX, this attribute is instead named `response.next_request`. For example:
+
+```python
+client = httpx.Client()
+request = client.build_request("GET", ...)
+while request is not None:
+    response = client.send(request, allow_redirects=False)
+    request = response.next_request
+```
index 553ac7609a975822a56bc29258078fd41346f493..5bbcc8623797222494bc4c83fa8a74e7d35e8e86 100644 (file)
@@ -832,6 +832,7 @@ class Client(BaseClient):
             history = history + [response]
 
             if not allow_redirects:
+                response.next_request = request
                 response.call_next = functools.partial(
                     self._send_handling_redirects,
                     request=request,
@@ -1475,6 +1476,7 @@ class AsyncClient(BaseClient):
             history = history + [response]
 
             if not allow_redirects:
+                response.next_request = request
                 response.call_next = functools.partial(
                     self._send_handling_redirects,
                     request=request,
index 4ef35ed88af2f024da23d5eb5d26b1c88908133c..f3301dd5d40a117d6ac149f93d4b9c481d086cde 100644 (file)
@@ -876,6 +876,10 @@ class Response:
 
         self._request: typing.Optional[Request] = request
 
+        # When allow_redirects=False and a redirect is received,
+        # the client will set `response.next_request`.
+        self.next_request: typing.Optional[Request] = None
+
         self.call_next: typing.Optional[typing.Callable] = None
 
         self.ext = {} if ext is None else ext
index 1c7911bc3521c7192654a22df4f62eb849c20240..3d5ed11d229faaf236eeada5de358721e5b254cd 100644 (file)
@@ -166,6 +166,20 @@ def test_disallow_redirects():
     assert len(response.history) == 1
 
 
+def test_next_request():
+    client = httpx.Client(transport=MockTransport(redirects))
+    request = client.build_request("POST", "https://example.org/redirect_303")
+    response = client.send(request, allow_redirects=False)
+    assert response.status_code == httpx.codes.SEE_OTHER
+    assert response.url == "https://example.org/redirect_303"
+    assert response.next_request is not None
+
+    response = client.send(response.next_request, allow_redirects=False)
+    assert response.status_code == httpx.codes.OK
+    assert response.url == "https://example.org/"
+    assert response.next_request is None
+
+
 def test_head_redirect():
     """
     Contrary to Requests, redirects remain enabled by default for HEAD requests.