mirror of
https://github.com/NixOS/nixpkgs.git
synced 2026-08-25 17:55:21 +00:00
Merge pull request #128214 from risicle/ris-fastapi-CVE-2021-32677-r20.09
[20.09] python3Packages.fastapi: add patch for CVE-2021-32677
This commit is contained in:
@@ -0,0 +1,151 @@
|
||||
Based on upstream https://github.com/tiangolo/fastapi/commit/fa7e3c996edf2d5482fff8f9d890ac2390dede4d.patch
|
||||
modified by ris to apply to 0.55.1
|
||||
diff --git a/fastapi/routing.py b/fastapi/routing.py
|
||||
index ac5e19d998..9b51f03cac 100644
|
||||
--- a/fastapi/routing.py
|
||||
+++ b/fastapi/routing.py
|
||||
@@ -1,3 +1,4 @@
|
||||
import asyncio
|
||||
+import email.message
|
||||
import inspect
|
||||
import json
|
||||
@@ -36,6 +37,7 @@
|
||||
)
|
||||
from pydantic import BaseModel
|
||||
from pydantic.error_wrappers import ErrorWrapper, ValidationError
|
||||
+from pydantic.fields import Undefined
|
||||
from starlette import routing
|
||||
from starlette.concurrency import run_in_threadpool
|
||||
from starlette.exceptions import HTTPException
|
||||
@@ -174,7 +175,7 @@ def get_request_handler(
|
||||
|
||||
async def app(request: Request) -> Response:
|
||||
try:
|
||||
- body = None
|
||||
+ body: Any = None
|
||||
if body_field:
|
||||
if is_body_form:
|
||||
body = await request.form()
|
||||
@@ -181,6 +183,18 @@ def get_request_handler(
|
||||
else:
|
||||
body_bytes = await request.body()
|
||||
if body_bytes:
|
||||
- body = await request.json()
|
||||
+ json_body: Any = Undefined
|
||||
+ content_type_value = request.headers.get("content-type")
|
||||
+ if content_type_value:
|
||||
+ message = email.message.Message()
|
||||
+ message["content-type"] = content_type_value
|
||||
+ if message.get_content_maintype() == "application":
|
||||
+ subtype = message.get_content_subtype()
|
||||
+ if subtype == "json" or subtype.endswith("+json"):
|
||||
+ json_body = await request.json()
|
||||
+ if json_body != Undefined:
|
||||
+ body = json_body
|
||||
+ else:
|
||||
+ body = body_bytes
|
||||
except Exception as e:
|
||||
logger.error(f"Error getting request body: {e}")
|
||||
diff --git a/tests/test_tutorial/test_body/test_tutorial001.py b/tests/test_tutorial/test_body/test_tutorial001.py
|
||||
index 38c6dbe876..c90240ae4c 100644
|
||||
--- a/tests/test_tutorial/test_body/test_tutorial001.py
|
||||
+++ b/tests/test_tutorial/test_body/test_tutorial001.py
|
||||
@@ -0,4 +0,6 @@
|
||||
+from unittest.mock import patch
|
||||
+
|
||||
import pytest
|
||||
from fastapi.testclient import TestClient
|
||||
|
||||
from body.tutorial001 import app
|
||||
@@ -173,6 +173,76 @@ def test_post_body(path, body, expected_status, expected_response):
|
||||
|
||||
|
||||
def test_post_broken_body():
|
||||
- response = client.post("/items/", data={"name": "Foo", "price": 50.5})
|
||||
- assert response.status_code == 400, response.text
|
||||
- assert response.json() == {"detail": "There was an error parsing the body"}
|
||||
+ response = client.post(
|
||||
+ "/items/",
|
||||
+ headers={"content-type": "application/json"},
|
||||
+ data="{some broken json}",
|
||||
+ )
|
||||
+ assert response.status_code == 400, response.text
|
||||
+ assert response.json() == {"detail": "There was an error parsing the body"}
|
||||
+
|
||||
+
|
||||
+def test_post_form_for_json():
|
||||
+ response = client.post("/items/", data={"name": "Foo", "price": 50.5})
|
||||
+ assert response.status_code == 422, response.text
|
||||
+ assert response.json() == {
|
||||
+ "detail": [
|
||||
+ {
|
||||
+ "loc": ["body", "item"],
|
||||
+ "msg": "value is not a valid dict",
|
||||
+ "type": "type_error.dict",
|
||||
+ }
|
||||
+ ]
|
||||
+ }
|
||||
+
|
||||
+
|
||||
+def test_explicit_content_type():
|
||||
+ response = client.post(
|
||||
+ "/items/",
|
||||
+ data='{"name": "Foo", "price": 50.5}',
|
||||
+ headers={"Content-Type": "application/json"},
|
||||
+ )
|
||||
+ assert response.status_code == 200, response.text
|
||||
+
|
||||
+
|
||||
+def test_geo_json():
|
||||
+ response = client.post(
|
||||
+ "/items/",
|
||||
+ data='{"name": "Foo", "price": 50.5}',
|
||||
+ headers={"Content-Type": "application/geo+json"},
|
||||
+ )
|
||||
+ assert response.status_code == 200, response.text
|
||||
+
|
||||
+
|
||||
+def test_wrong_headers():
|
||||
+ data = '{"name": "Foo", "price": 50.5}'
|
||||
+ invalid_dict = {
|
||||
+ "detail": [
|
||||
+ {
|
||||
+ "loc": ["body", "item"],
|
||||
+ "msg": "value is not a valid dict",
|
||||
+ "type": "type_error.dict",
|
||||
+ }
|
||||
+ ]
|
||||
+ }
|
||||
+
|
||||
+ response = client.post("/items/", data=data, headers={"Content-Type": "text/plain"})
|
||||
+ assert response.status_code == 422, response.text
|
||||
+ assert response.json() == invalid_dict
|
||||
+
|
||||
+ response = client.post(
|
||||
+ "/items/", data=data, headers={"Content-Type": "application/geo+json-seq"}
|
||||
+ )
|
||||
+ assert response.status_code == 422, response.text
|
||||
+ assert response.json() == invalid_dict
|
||||
+ response = client.post(
|
||||
+ "/items/", data=data, headers={"Content-Type": "application/not-really-json"}
|
||||
+ )
|
||||
+ assert response.status_code == 422, response.text
|
||||
+ assert response.json() == invalid_dict
|
||||
+
|
||||
+
|
||||
+def test_other_exceptions():
|
||||
+ with patch("json.loads", side_effect=Exception):
|
||||
+ response = client.post("/items/", json={"test": "test2"})
|
||||
+ assert response.status_code == 400, response.text
|
||||
diff --git a/tests/test_tutorial/test_custom_request_and_route/test_tutorial001.py b/tests/test_tutorial/test_custom_request_and_route/test_tutorial001.py
|
||||
index cc85a8a82a..3eb5822e28 100644
|
||||
--- a/tests/test_tutorial/test_custom_request_and_route/test_tutorial001.py
|
||||
+++ b/tests/test_tutorial/test_custom_request_and_route/test_tutorial001.py
|
||||
@@ -25,6 +25,7 @@ def test_gzip_request(compress):
|
||||
if compress:
|
||||
data = gzip.compress(data)
|
||||
headers["Content-Encoding"] = "gzip"
|
||||
+ headers["Content-Type"] = "application/json"
|
||||
response = client.post("/sum", data=data, headers=headers)
|
||||
assert response.json() == {"sum": n}
|
||||
|
||||
@@ -27,6 +27,10 @@ buildPythonPackage rec {
|
||||
sha256 = "1515nhwari48v0angyl5z3cfpvwn4al2nvqh0cjd9xgxzvm310s8";
|
||||
};
|
||||
|
||||
patches = [
|
||||
./0.55.1-CVE-2021-32677.patch
|
||||
];
|
||||
|
||||
postPatch = ''
|
||||
substituteInPlace pyproject.toml \
|
||||
--replace "starlette ==0.13.2" "starlette"
|
||||
|
||||
Reference in New Issue
Block a user