Skip to content

Commit 063b5bf

Browse files
authored
♻️ Do not accept underscore headers when using convert_underscores=True (the default) (#15589)
1 parent 22b02e2 commit 063b5bf

2 files changed

Lines changed: 39 additions & 0 deletions

File tree

‎fastapi/dependencies/utils.py‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -826,6 +826,10 @@ def request_params_to_args(
826826
if value is not None:
827827
params_to_process[get_validation_alias(field)] = value
828828
processed_keys.add(alias or get_validation_alias(field))
829+
# For headers with convert_underscores=True, mark both the converted
830+
# header name and the original field alias as processed to avoid
831+
# accepting the original alias as an extra header.
832+
processed_keys.add(get_validation_alias(field))
829833

830834
for key in received_params.keys():
831835
if key not in processed_keys:

‎tests/test_query_cookie_header_model_extra_params.py‎

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,10 @@ class Model(BaseModel):
1111
model_config = {"extra": "allow"}
1212

1313

14+
class AuthHeaders(BaseModel):
15+
x_user_id: str
16+
17+
1418
@app.get("/query")
1519
async def query_model_with_extra(data: Model = Query()):
1620
return data
@@ -26,6 +30,11 @@ async def cookies_model_with_extra(data: Model = Cookie()):
2630
return data
2731

2832

33+
@app.get("/header-requires-hyphen")
34+
async def header_model_requires_hyphen(data: AuthHeaders = Header()):
35+
return data
36+
37+
2938
def test_query_pass_extra_list():
3039
client = TestClient(app)
3140
resp = client.get(
@@ -91,6 +100,32 @@ def test_header_pass_extra_single():
91100
assert resp_json["param2"] == "456"
92101

93102

103+
def test_header_model_prefers_hyphenated_header_with_convert_underscores():
104+
client = TestClient(app)
105+
106+
resp = client.get(
107+
"/header-requires-hyphen",
108+
headers=[
109+
("x-user-id", "hyphenated-value"),
110+
("x_user_id", "underscore-value"),
111+
],
112+
)
113+
114+
assert resp.status_code == 200
115+
assert resp.json() == {"x_user_id": "hyphenated-value"}
116+
117+
118+
def test_header_model_rejects_underscore_header_with_convert_underscores():
119+
client = TestClient(app)
120+
121+
resp = client.get(
122+
"/header-requires-hyphen", headers={"x_user_id": "underscore-value"}
123+
)
124+
125+
assert resp.status_code == 422
126+
assert resp.json()["detail"][0]["loc"] == ["header", "x_user_id"]
127+
128+
94129
def test_cookie_pass_extra_list():
95130
client = TestClient(app)
96131
client.cookies = [

0 commit comments

Comments
 (0)