mirror of
https://github.com/LukeHagar/vercel.git
synced 2025-12-09 04:22:07 +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()
|
query = url.query.encode()
|
||||||
path = url.path
|
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 = {
|
scope = {
|
||||||
'server': (headers.get('host', 'lambda'), headers.get('x-forwarded-port', 80)),
|
'server': (headers.get('host', 'lambda'), headers.get('x-forwarded-port', 80)),
|
||||||
'client': (headers.get(
|
'client': (headers.get(
|
||||||
@@ -285,7 +293,7 @@ elif 'app' in __vc_variables:
|
|||||||
'scheme': headers.get('x-forwarded-proto', 'http'),
|
'scheme': headers.get('x-forwarded-proto', 'http'),
|
||||||
'root_path': '',
|
'root_path': '',
|
||||||
'query_string': query,
|
'query_string': query,
|
||||||
'headers': [[k.lower().encode(), v.encode()] for k, v in headers.items()],
|
'headers': headers_encoded,
|
||||||
'type': 'http',
|
'type': 'http',
|
||||||
'http_version': '1.1',
|
'http_version': '1.1',
|
||||||
'method': payload['method'],
|
'method': payload['method'],
|
||||||
|
|||||||
Reference in New Issue
Block a user