Skip to content

Commit 343255f

Browse files
committed
requests: Add support for relative redirect URLs.
A redirection URL in the "Location:" header may be relative and start with a "/". Handle such cases. Signed-off-by: Damien George <damien@micropython.org>
1 parent acf98ad commit 343255f

3 files changed

Lines changed: 55 additions & 2 deletions

File tree

python-ecosys/requests/manifest.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
1-
metadata(version="0.11.0", pypi="requests")
1+
metadata(version="0.11.1", pypi="requests")
22

33
package("requests")

python-ecosys/requests/requests/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,8 @@ def request(
172172
elif l.startswith(b"Location:") and not 200 <= status <= 299:
173173
if status in [301, 302, 303, 307, 308]:
174174
redirect = str(l[10:-2], "utf-8")
175+
if redirect.startswith("/"):
176+
redirect = proto + "//" + host + ":" + str(port) + redirect
175177
else:
176178
raise NotImplementedError("Redirect %d not yet supported" % status)
177179
if parse_headers is False:

python-ecosys/requests/test_requests.py

Lines changed: 52 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,10 @@
55
class Socket:
66
def __init__(self):
77
self._write_buffer = io.BytesIO()
8-
self._read_buffer = io.BytesIO(b"HTTP/1.0 200 OK\r\n\r\n")
8+
self._read_buffer = io.BytesIO(Socket.RESPONSES.pop(0))
9+
10+
def close(self):
11+
pass
912

1013
def connect(self, address):
1114
pass
@@ -34,12 +37,20 @@ def socket(af=AF_INET, type=SOCK_STREAM, proto=IPPROTO_TCP):
3437
# ruff: noqa: E402
3538
import requests
3639

40+
SERVER_RESPONSE_200_OK = b"HTTP/1.0 200 OK\r\n\r\n"
41+
42+
43+
def set_server_responses(*buffers):
44+
Socket.RESPONSES = list(buffers)
45+
3746

3847
def format_message(response):
3948
return response.raw._write_buffer.getvalue().decode("utf8")
4049

4150

4251
def test_simple_get():
52+
set_server_responses(SERVER_RESPONSE_200_OK)
53+
4354
response = requests.request("GET", "http://example.com")
4455

4556
assert response.raw._write_buffer.getvalue() == (
@@ -48,6 +59,8 @@ def test_simple_get():
4859

4960

5061
def test_get_auth():
62+
set_server_responses(SERVER_RESPONSE_200_OK)
63+
5164
response = requests.request(
5265
"GET", "http://example.com", auth=("test-username", "test-password")
5366
)
@@ -61,6 +74,8 @@ def test_get_auth():
6174

6275

6376
def test_get_custom_header():
77+
set_server_responses(SERVER_RESPONSE_200_OK)
78+
6479
response = requests.request("GET", "http://example.com", headers={"User-Agent": "test-agent"})
6580

6681
assert response.raw._write_buffer.getvalue() == (
@@ -72,6 +87,8 @@ def test_get_custom_header():
7287

7388

7489
def test_post_json():
90+
set_server_responses(SERVER_RESPONSE_200_OK)
91+
7592
response = requests.request("GET", "http://example.com", json="test")
7693

7794
assert response.raw._write_buffer.getvalue() == (
@@ -85,6 +102,8 @@ def test_post_json():
85102

86103

87104
def test_post_chunked_data():
105+
set_server_responses(SERVER_RESPONSE_200_OK)
106+
88107
def chunks():
89108
yield "test"
90109

@@ -101,6 +120,8 @@ def chunks():
101120

102121

103122
def test_overwrite_get_headers():
123+
set_server_responses(SERVER_RESPONSE_200_OK)
124+
104125
response = requests.request(
105126
"GET", "http://example.com", headers={"Host": "test.com", "Connection": "keep-alive"}
106127
)
@@ -111,6 +132,8 @@ def test_overwrite_get_headers():
111132

112133

113134
def test_overwrite_post_json_headers():
135+
set_server_responses(SERVER_RESPONSE_200_OK)
136+
114137
response = requests.request(
115138
"GET",
116139
"http://example.com",
@@ -129,6 +152,8 @@ def test_overwrite_post_json_headers():
129152

130153

131154
def test_overwrite_post_chunked_data_headers():
155+
set_server_responses(SERVER_RESPONSE_200_OK)
156+
132157
def chunks():
133158
yield "test"
134159

@@ -146,13 +171,37 @@ def chunks():
146171

147172

148173
def test_do_not_modify_headers_argument():
174+
set_server_responses(SERVER_RESPONSE_200_OK)
175+
149176
global do_not_modify_this_dict
150177
do_not_modify_this_dict = {}
151178
requests.request("GET", "http://example.com", headers=do_not_modify_this_dict)
152179

153180
assert do_not_modify_this_dict == {}, do_not_modify_this_dict
154181

155182

183+
def test_redirect_with_protocol():
184+
set_server_responses(
185+
b"HTTP/1.0 301 OK\r\nLocation: http://example.com/index\r\n\r\n", SERVER_RESPONSE_200_OK
186+
)
187+
188+
response = requests.request("GET", "http://example.com")
189+
190+
assert response.raw._write_buffer.getvalue() == (
191+
b"GET /index HTTP/1.0\r\n" + b"Connection: close\r\n" + b"Host: example.com\r\n\r\n"
192+
), format_message(response)
193+
194+
195+
def test_redirect_without_protocol():
196+
set_server_responses(b"HTTP/1.0 301 OK\r\nLocation: /index\r\n\r\n", SERVER_RESPONSE_200_OK)
197+
198+
response = requests.request("GET", "http://example.com")
199+
200+
assert response.raw._write_buffer.getvalue() == (
201+
b"GET /index HTTP/1.0\r\n" + b"Connection: close\r\n" + b"Host: example.com\r\n\r\n"
202+
), format_message(response)
203+
204+
156205
test_simple_get()
157206
test_get_auth()
158207
test_get_custom_header()
@@ -162,3 +211,5 @@ def test_do_not_modify_headers_argument():
162211
test_overwrite_post_json_headers()
163212
test_overwrite_post_chunked_data_headers()
164213
test_do_not_modify_headers_argument()
214+
test_redirect_with_protocol()
215+
test_redirect_without_protocol()

0 commit comments

Comments
 (0)