mirror of
https://github.com/LukeHagar/vercel.git
synced 2025-12-07 21:07:46 +00:00
[python] Cope with duplicate header values (#9205)
There are times when a request can arrive for a Python function with headers as a list. One of those examples is this header `x-vercel-proxied-for` which apparently is set twice. Example: `[b'x-vercel-proxied-for', [b'207.81.134.243', b'172.71.147.74']]` I took a quick scan through the other Python server implementations and I don't think any of them manipulate the value of the HTTP headers, the way the ASGI one does so I think we are good there. To reproduce: `curl https://..../ -H "foo: bar" -H "foo: bar"` Will fail. Fixes: https://github.com/vercel/vercel/issues/9132
This commit is contained in:
14
packages/python/test/fixtures/32-fail-duplicate-header/index.py
vendored
Normal file
14
packages/python/test/fixtures/32-fail-duplicate-header/index.py
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
async def app(scope, receive, send):
|
||||
assert scope["type"] == "http"
|
||||
await send(
|
||||
{
|
||||
"type": "http.response.start",
|
||||
"status": 200,
|
||||
}
|
||||
)
|
||||
await send(
|
||||
{
|
||||
"type": "http.response.body",
|
||||
"body": b"hello world"
|
||||
}
|
||||
)
|
||||
18
packages/python/test/fixtures/32-fail-duplicate-header/probe.js
vendored
Normal file
18
packages/python/test/fixtures/32-fail-duplicate-header/probe.js
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
const execa = require('execa');
|
||||
|
||||
module.exports = async function ({ deploymentUrl, fetch }) {
|
||||
const probeUrl = `https://${deploymentUrl}`;
|
||||
const result = await execa('curl', [
|
||||
probeUrl,
|
||||
'-s',
|
||||
'-H',
|
||||
'foo: bar',
|
||||
'-H',
|
||||
'foo: bar',
|
||||
]);
|
||||
if (result.stdout.includes('FUNCTION_INVOCATION_FAILED')) {
|
||||
throw new Error(
|
||||
'Duplicate headers should not cause a function invocation failure'
|
||||
);
|
||||
}
|
||||
};
|
||||
9
packages/python/test/fixtures/32-fail-duplicate-header/vercel.json
vendored
Normal file
9
packages/python/test/fixtures/32-fail-duplicate-header/vercel.json
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"version": 2,
|
||||
"builds": [
|
||||
{
|
||||
"src": "*.py",
|
||||
"use": "@vercel/python"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -276,6 +276,14 @@ elif 'app' in __vc_variables:
|
||||
query = url.query.encode()
|
||||
path = url.path
|
||||
|
||||
headers_encoded = []
|
||||
for k, v in headers.items():
|
||||
# Cope with repeated headers in the encoding.
|
||||
if isinstance(v, list):
|
||||
headers_encoded.append([k.lower().encode(), [i.encode() for i in v]])
|
||||
else:
|
||||
headers_encoded.append([k.lower().encode(), v.encode()])
|
||||
|
||||
scope = {
|
||||
'server': (headers.get('host', 'lambda'), headers.get('x-forwarded-port', 80)),
|
||||
'client': (headers.get(
|
||||
@@ -285,7 +293,7 @@ elif 'app' in __vc_variables:
|
||||
'scheme': headers.get('x-forwarded-proto', 'http'),
|
||||
'root_path': '',
|
||||
'query_string': query,
|
||||
'headers': [[k.lower().encode(), v.encode()] for k, v in headers.items()],
|
||||
'headers': headers_encoded,
|
||||
'type': 'http',
|
||||
'http_version': '1.1',
|
||||
'method': payload['method'],
|
||||
|
||||
Reference in New Issue
Block a user