Skip to content

Commit 41968b2

Browse files
committed
wsgi: properly pass through requests headers
1 parent 399f45a commit 41968b2

5 files changed

Lines changed: 49 additions & 1 deletion

File tree

examples/bottle-app.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ def info():
2727
"vcpu_time_ms": vcpu_time,
2828
"request_method": request.environ.get("REQUEST_METHOD"),
2929
"path_info": request.environ.get("PATH_INFO"),
30+
"request_headers": dict(request.headers),
3031
}
3132

3233

examples/flask-app.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ def info():
2828
"request_method": request.environ.get("REQUEST_METHOD"),
2929
"path_info": request.environ.get("PATH_INFO"),
3030
"python_version": sys.version,
31+
"request_headers": dict(request.headers),
3132
}
3233

3334

fastly_compute/wsgi.py

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,49 @@ def start_response(
8686
"HTTP_HOST": url.netloc or "localhost",
8787
}
8888

89+
# Add incoming HTTP headers to environ (WSGI spec requires HTTP_ prefix)
90+
# Use cursor-based iteration to read all header names
91+
cursor = 0
92+
while True:
93+
header_names_str, next_cursor = req.get_header_names(
94+
max_len=8192, cursor=cursor
95+
)
96+
if not header_names_str:
97+
break
98+
99+
# Header names are NUL-separated
100+
header_names_split = (
101+
header_names_str.rstrip("\0").split("\0") if header_names_str else []
102+
)
103+
104+
for header_name in header_names_split:
105+
if not header_name:
106+
continue
107+
108+
# Get the header value
109+
header_value_bytes = req.get_header_value(header_name, max_len=8192)
110+
if header_value_bytes is None:
111+
continue
112+
113+
# See https://peps.python.org/pep-3333/ - ISO-8859-1 encoding
114+
# should be used for bytes values across this boundary.
115+
header_value_str = header_value_bytes.decode("iso-8859-1")
116+
117+
# Special handling for Content-Type and Content-Length (no HTTP_ prefix)
118+
if header_name.lower() == "content-type":
119+
environ["CONTENT_TYPE"] = header_value_str
120+
elif header_name.lower() == "content-length":
121+
environ["CONTENT_LENGTH"] = header_value_str
122+
else:
123+
# Convert to WSGI format: HTTP_ prefix, uppercase, hyphens to underscores
124+
wsgi_key = "HTTP_" + header_name.upper().replace("-", "_")
125+
environ[wsgi_key] = header_value_str
126+
127+
# If there are more headers, continue with next cursor
128+
if next_cursor is None:
129+
break
130+
cursor = next_cursor
131+
89132
try:
90133
# Call the WSGI app and collect response body chunks
91134
for body_chunk in app(environ, start_response):

tests/test_app.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,8 @@ def test_custom_headers(self):
5757
headers = {"X-Custom-Header": "test-value"}
5858
response = self.get("/info", headers=headers)
5959
assert response.status_code == 200
60+
data = response.json()
61+
assert data["request_headers"]["X-Custom-Header"] == "test-value"
6062

6163
def test_error_endpoint_handling(self):
6264
"""Test that the error endpoint returns 500 and triggers viceroy output display."""

tests/test_flask_example.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ def test_hello_endpoint(self):
1717

1818
def test_info_endpoint(self):
1919
"""Test the info endpoint returns expected JSON with WIT data."""
20-
response = self.get("/info")
20+
response = self.get("/info", headers={"Test-Header": "test-value"})
2121

2222
assert response.status_code == 200
2323
assert response.headers.get("content-type", "").startswith("application/json")
@@ -32,6 +32,7 @@ def test_info_endpoint(self):
3232
# Check WIT API data
3333
assert "vcpu_time_ms" in data
3434
assert isinstance(data["vcpu_time_ms"], int)
35+
assert data["request_headers"]["Test-Header"] == "test-value"
3536

3637
def test_error_endpoint_handling(self):
3738
"""Test that the error endpoint returns 500."""

0 commit comments

Comments
 (0)