diff --git a/backend/tests/test_knowledge_management_extension.py b/backend/tests/test_knowledge_management_extension.py index 7d6c5d61ec..c5b53ee330 100644 --- a/backend/tests/test_knowledge_management_extension.py +++ b/backend/tests/test_knowledge_management_extension.py @@ -229,6 +229,29 @@ async def test_router_upload_is_bounded_and_errors_are_sanitized(api, monkeypatc assert len(calls) == 1 +@pytest.mark.parametrize( + "content_type", + [ + "Application/Octet-Stream; charset=binary", + "application/octet-stream ; charset=binary", + "APPLICATION/OCTET-STREAM", + ], + ids=["mixed-case-with-parameter", "space-before-parameter", "uppercase"], +) +@pytest.mark.asyncio +async def test_router_upload_accepts_normalized_media_type(api, content_type): + app, _, calls, _ = api + async with httpx.AsyncClient(transport=httpx.ASGITransport(app=app), base_url="http://test") as client: + response = await client.post( + API_BASE + "/files?filename=guide.txt", + content=b"knowledge", + headers={"content-type": content_type}, + ) + + assert response.status_code == 202 + assert calls[-1].url.path.endswith("/file") + + @pytest.mark.asyncio async def test_router_fails_closed_without_host_resolver(api): from deerflow_extension_api.auth import EXTENSION_PRINCIPAL_RESOLVER_KEY diff --git a/examples/deerflow-extension-knowledge-management/deerflow_extension_knowledge_management/router.py b/examples/deerflow-extension-knowledge-management/deerflow_extension_knowledge_management/router.py index dc3105d2df..6a0d14874f 100644 --- a/examples/deerflow-extension-knowledge-management/deerflow_extension_knowledge_management/router.py +++ b/examples/deerflow-extension-knowledge-management/deerflow_extension_knowledge_management/router.py @@ -74,7 +74,8 @@ def build_router(provider: ManagementProvider) -> APIRouter: @router.post(prefix + "/files", status_code=202) async def upload(request: Request, connection: str, base: str, filename: str, context: ManagementContext = Depends(_context)): - if request.headers.get("content-type", "").split(";", 1)[0] != "application/octet-stream": + media_type = request.headers.get("content-type", "").split(";", 1)[0].strip().lower() + if media_type != "application/octet-stream": raise HTTPException(415, "Use application/octet-stream") try: options = ProcessingOptions.model_validate_json(request.headers.get("x-processing-options", "{}"))