← eval_submission_nothink

fastapi_14978

failed WRONG_FIX wrong_fix · 23 tool calls · 89 s · fastapi/fastapi

Task input

🔒️ Add `strict_content_type` checking for JSON requests

🔒️ Add `strict_content_type` checking for JSON requests

Tool calls (24)

#ToolArgumentsResult
1run_command
{
 "command": "grep -rn \"json\" fastapi/params.py fastapi/routing.py fastapi/requests.py | head -20"
}
{"status": "ok", "stdout": "fastapi/params.py:72: json_schema_extra: dict[str, Any] | None = None,\nfastapi/params.py:111: current_json_schema_extra = json_sche
full
{"status": "ok", "stdout": "fastapi/params.py:72:        json_schema_extra: dict[str, Any] | None = None,\nfastapi/params.py:111:        current_json_schema_extra = json_schema_extra or extra\nfastapi/params.py:125:                \"json_schema_extra\": current_json_schema_extra,\nfastapi/params.py:183:        json_schema_extra: dict[str, Any] | None = None,\nfastapi/params.py:217:            json_schema_extra=json_schema_extra,\nfastapi/params.py:267:        json_schema_extra: dict[str, Any] | None = None,\nfastapi/params.py:299:            json_schema_extra=json_schema_extra,\nfastapi/params.py:350:        json_schema_extra: dict[str, Any] | None = None,\nfastapi/params.py:383:            json_schema_extra=json_schema_extra,\nfastapi/params.py:433:        json_schema_extra: dict[str, Any] | None = None,\nfastapi/params.py:465:            json_schema_extra=json_schema_extra,\nfastapi/params.py:478:        media_type: str = \"application/json\",\nfastapi/params.py:515:        json_schema_extra: dict[str, Any] | None = None,\nfastapi/params.py:556:        current_json_schema_extra = json_schema_extra or extra\nfastapi/params.py:569:                \"json_schema_extra\": current_json_schema_extra,\nfastapi/params.py:626:        json_schema_extra: dict[str, Any] | None = None,\nfastapi/params.py:659:            json_schema_extra=json_schema_extra,\nfastapi/params.py:708:        json_schema_extra: dict[str, Any] | None = None,\nfastapi/params.py:741:            json_schema_extra=json_schema_extra,\nfastapi/routing.py:5:import json\n", "exit_code": 0}
2run_command
{
 "command": "grep -rn \"Body\" fastapi/params.py"
}
{"status": "ok", "stdout": "470:class Body(FieldInfo): # type: ignore[misc]\n582:class Form(Body): # type: ignore[misc]\n", "exit_code": 0}
full
{"status": "ok", "stdout": "470:class Body(FieldInfo):  # type: ignore[misc]\n582:class Form(Body):  # type: ignore[misc]\n", "exit_code": 0}
3read_file
{
 "filepath": "fastapi/params.py",
 "start_line": 470,
 "end_line": 510
}
{"status": "ok", "filepath": "fastapi/params.py", "content": "class Body(FieldInfo): # type: ignore[misc]\n def __init__(\n self,\n default: Any = Undefined,\n
full
{"status": "ok", "filepath": "fastapi/params.py", "content": "class Body(FieldInfo):  # type: ignore[misc]\n    def __init__(\n        self,\n        default: Any = Undefined,\n        *,\n        default_factory: Callable[[], Any] | None = _Unset,\n        annotation: Any | None = None,\n        embed: bool | None = None,\n        media_type: str = \"application/json\",\n        alias: str | None = None,\n        alias_priority: int | None = _Unset,\n        validation_alias: str | AliasPath | AliasChoices | None = None,\n        serialization_alias: str | None = None,\n        title: str | None = None,\n        description: str | None = None,\n        gt: float | None = None,\n        ge: float | None = None,\n        lt: float | None = None,\n        le: float | None = None,\n        min_length: int | None = None,\n        max_length: int | None = None,\n        pattern: str | None = None,\n        regex: Annotated[\n            str | None,\n            deprecated(\n                \"Deprecated in FastAPI 0.100.0 and Pydantic v2, use `pattern` instead.\"\n            ),\n        ] = None,\n        discriminator: str | None = None,\n        strict: bool | None = _Unset,\n        multiple_of: float | None = _Unset,\n        allow_inf_nan: bool | None = _Unset,\n        max_digits: int | None = _Unset,\n        decimal_places: int | None = _Unset,\n        examples: list[Any] | None = None,\n        example: Annotated[\n            Any | None,\n            deprecated(\n                \"Deprecated in OpenAPI 3.1.0 that now uses JSON Schema 2020-12, \"\n                \"although still supported. Use examples instead.\"\n            ),\n", "start_line": 470, "end_line": 510, "total_lines": 755, "is_truncated": false}
4read_file
{
 "end_line": 550,
 "filepath": "fastapi/params.py",
 "start_line": 511
}
{"status": "ok", "filepath": "fastapi/params.py", "content": " ] = _Unset,\n openapi_examples: dict[str, Example] | None = None,\n deprecated: deprecated | str
full
{"status": "ok", "filepath": "fastapi/params.py", "content": "        ] = _Unset,\n        openapi_examples: dict[str, Example] | None = None,\n        deprecated: deprecated | str | bool | None = None,\n        include_in_schema: bool = True,\n        json_schema_extra: dict[str, Any] | None = None,\n        **extra: Any,\n    ):\n        self.embed = embed\n        self.media_type = media_type\n        if example is not _Unset:\n            warnings.warn(\n                \"`example` has been deprecated, please use `examples` instead\",\n                category=FastAPIDeprecationWarning,\n                stacklevel=4,\n            )\n        self.example = example\n        self.include_in_schema = include_in_schema\n        self.openapi_examples = openapi_examples\n        kwargs = dict(\n            default=default,\n            default_factory=default_factory,\n            alias=alias,\n            title=title,\n            description=description,\n            gt=gt,\n            ge=ge,\n            lt=lt,\n            le=le,\n            min_length=min_length,\n            max_length=max_length,\n            discriminator=discriminator,\n            multiple_of=multiple_of,\n            allow_inf_nan=allow_inf_nan,\n            max_digits=max_digits,\n            decimal_places=decimal_places,\n            **extra,\n        )\n        if examples is not None:\n            kwargs[\"examples\"] = examples\n        if regex is not None:\n", "start_line": 511, "end_line": 550, "total_lines": 755, "is_truncated": false}
5run_command
{
 "command": "grep -rn \"strict_content_type\" ."
}
{"status": "error", "error_type": "CommandError", "error_message": "Command failed with exit code 1", "details": {"stdout": "", "stderr": "", "exit_code": 1}}
full
{"status": "error", "error_type": "CommandError", "error_message": "Command failed with exit code 1", "details": {"stdout": "", "stderr": "", "exit_code": 1}}
6run_command
{
 "command": "grep -rn \"get_body\" fastapi/"
}
{"status": "ok", "stdout": "fastapi/dependencies/utils.py:968:def get_body_field(\nfastapi/routing.py:41: get_body_field,\nfastapi/routing.py:694: self.body_fie
full
{"status": "ok", "stdout": "fastapi/dependencies/utils.py:968:def get_body_field(\nfastapi/routing.py:41:    get_body_field,\nfastapi/routing.py:694:        self.body_field = get_body_field(\n", "exit_code": 0}
7read_file
{
 "end_line": 1050,
 "filepath": "fastapi/dependencies/utils.py",
 "start_line": 900
}
{"status": "ok", "filepath": "fastapi/dependencies/utils.py", "content": " assert isinstance(value, sequence_types)\n results: list[bytes | str] = []\n for sub_
full
{"status": "ok", "filepath": "fastapi/dependencies/utils.py", "content": "            assert isinstance(value, sequence_types)\n            results: list[bytes | str] = []\n            for sub_value in value:\n                results.append(await sub_value.read())\n            value = serialize_sequence_value(field=field, value=results)\n        if value is not None:\n            values[get_validation_alias(field)] = value\n    field_aliases = {get_validation_alias(field) for field in body_fields}\n    for key in received_body.keys():\n        if key not in field_aliases:\n            param_values = received_body.getlist(key)\n            if len(param_values) == 1:\n                values[key] = param_values[0]\n            else:\n                values[key] = param_values\n    return values\n\n\nasync def request_body_to_args(\n    body_fields: list[ModelField],\n    received_body: dict[str, Any] | FormData | None,\n    embed_body_fields: bool,\n) -> tuple[dict[str, Any], list[dict[str, Any]]]:\n    values: dict[str, Any] = {}\n    errors: list[dict[str, Any]] = []\n    assert body_fields, \"request_body_to_args() should be called with fields\"\n    single_not_embedded_field = len(body_fields) == 1 and not embed_body_fields\n    first_field = body_fields[0]\n    body_to_process = received_body\n\n    fields_to_extract: list[ModelField] = body_fields\n\n    if (\n        single_not_embedded_field\n        and lenient_issubclass(first_field.field_info.annotation, BaseModel)\n        and isinstance(received_body, FormData)\n    ):\n        fields_to_extract = get_cached_model_fields(first_field.field_info.annotation)\n\n    if isinstance(received_body, FormData):\n        body_to_process = await _extract_form_body(fields_to_extract, received_body)\n\n    if single_not_embedded_field:\n        loc: tuple[str, ...] = (\"body\",)\n        v_, errors_ = _validate_value_with_model_field(\n            field=first_field, value=body_to_process, values=values, loc=loc\n       
8run_command
{
 "command": "grep -rn \"await request.json()\" fastapi/"
}
{"status": "ok", "stdout": "fastapi/routing.py:373: json_body = await request.json()\nfastapi/routing.py:380: json_body = await request.json()\n", "exit_code":
full
{"status": "ok", "stdout": "fastapi/routing.py:373:                            json_body = await request.json()\nfastapi/routing.py:380:                                    json_body = await request.json()\n", "exit_code": 0}
9read_file
{
 "end_line": 400,
 "filepath": "fastapi/routing.py",
 "start_line": 350
}
{"status": "ok", "filepath": "fastapi/routing.py", "content": " _extract_endpoint_context(dependant.call)\n if dependant.call\n else EndpointContext()\n )\n\n i
full
{"status": "ok", "filepath": "fastapi/routing.py", "content": "            _extract_endpoint_context(dependant.call)\n            if dependant.call\n            else EndpointContext()\n        )\n\n        if dependant.path:\n            # For mounted sub-apps, include the mount path prefix\n            mount_path = request.scope.get(\"root_path\", \"\").rstrip(\"/\")\n            endpoint_ctx[\"path\"] = f\"{request.method} {mount_path}{dependant.path}\"\n\n        # Read body and auto-close files\n        try:\n            body: Any = None\n            if body_field:\n                if is_body_form:\n                    body = await request.form()\n                    file_stack.push_async_callback(body.close)\n                else:\n                    body_bytes = await request.body()\n                    if body_bytes:\n                        json_body: Any = Undefined\n                        content_type_value = request.headers.get(\"content-type\")\n                        if not content_type_value:\n                            json_body = await request.json()\n                        else:\n                            message = email.message.Message()\n                            message[\"content-type\"] = content_type_value\n                            if message.get_content_maintype() == \"application\":\n                                subtype = message.get_content_subtype()\n                                if subtype == \"json\" or subtype.endswith(\"+json\"):\n                                    json_body = await request.json()\n                        if json_body != Undefined:\n                            body = json_body\n                        else:\n                            body = body_bytes\n        except json.JSONDecodeError as e:\n            validation_error = RequestValidationError(\n                [\n                    {\n                        \"type\": \"json_invalid\",\n                        \"loc\": (\"body\", e.pos),\n     
10read_file
{
 "end_line": 530,
 "filepath": "fastapi/params.py",
 "start_line": 470
}
{"status": "ok", "filepath": "fastapi/params.py", "content": "class Body(FieldInfo): # type: ignore[misc]\n def __init__(\n self,\n default: Any = Undefined,\n
full
{"status": "ok", "filepath": "fastapi/params.py", "content": "class Body(FieldInfo):  # type: ignore[misc]\n    def __init__(\n        self,\n        default: Any = Undefined,\n        *,\n        default_factory: Callable[[], Any] | None = _Unset,\n        annotation: Any | None = None,\n        embed: bool | None = None,\n        media_type: str = \"application/json\",\n        alias: str | None = None,\n        alias_priority: int | None = _Unset,\n        validation_alias: str | AliasPath | AliasChoices | None = None,\n        serialization_alias: str | None = None,\n        title: str | None = None,\n        description: str | None = None,\n        gt: float | None = None,\n        ge: float | None = None,\n        lt: float | None = None,\n        le: float | None = None,\n        min_length: int | None = None,\n        max_length: int | None = None,\n        pattern: str | None = None,\n        regex: Annotated[\n            str | None,\n            deprecated(\n                \"Deprecated in FastAPI 0.100.0 and Pydantic v2, use `pattern` instead.\"\n            ),\n        ] = None,\n        discriminator: str | None = None,\n        strict: bool | None = _Unset,\n        multiple_of: float | None = _Unset,\n        allow_inf_nan: bool | None = _Unset,\n        max_digits: int | None = _Unset,\n        decimal_places: int | None = _Unset,\n        examples: list[Any] | None = None,\n        example: Annotated[\n            Any | None,\n            deprecated(\n                \"Deprecated in OpenAPI 3.1.0 that now uses JSON Schema 2020-12, \"\n                \"although still supported. Use examples instead.\"\n            ),\n        ] = _Unset,\n        openapi_examples: dict[str, Example] | None = None,\n        deprecated: deprecated | str | bool | None = None,\n        include_in_schema: bool = True,\n        json_schema_extra: dict[str, Any] | None = None,\n        **extra: Any,\n    ):\n        self.embed = embed\n        self.media_type = media_type
11edit_file
{
 "filepath": "fastapi/params.py",
 "new_string": "        media_type: str = \\\"application/json\\\",\n        strict_content_type: bool = False,\n        alias: str | None = None,",
 "old_string": "        media_type: str = \\\"application/json\\\",\n        alias: str | None = None,"
}
{"status": "error", "error_type": "FileEditError", "error_message": "old_string not found in file (tried exact, flexible and regex matching)"}
full
{"status": "error", "error_type": "FileEditError", "error_message": "old_string not found in file (tried exact, flexible and regex matching)"}
12read_file
{
 "end_line": 480,
 "filepath": "fastapi/params.py",
 "start_line": 470
}
{"status": "ok", "filepath": "fastapi/params.py", "content": "class Body(FieldInfo): # type: ignore[misc]\n def __init__(\n self,\n default: Any = Undefined,\n
full
{"status": "ok", "filepath": "fastapi/params.py", "content": "class Body(FieldInfo):  # type: ignore[misc]\n    def __init__(\n        self,\n        default: Any = Undefined,\n        *,\n        default_factory: Callable[[], Any] | None = _Unset,\n        annotation: Any | None = None,\n        embed: bool | None = None,\n        media_type: str = \"application/json\",\n        alias: str | None = None,\n        alias_priority: int | None = _Unset,\n", "start_line": 470, "end_line": 480, "total_lines": 755, "is_truncated": false}
13edit_file
{
 "filepath": "fastapi/params.py",
 "new_string": "        media_type: str = \\\"application/json\\\",\n        strict_content_type: bool = False,\n        alias: str | None = None,",
 "old_string": "        media_type: str = \\\"application/json\\\",\n        alias: str | None = None,"
}
{"status": "error", "error_type": "FileEditError", "error_message": "old_string not found in file (tried exact, flexible and regex matching)"}
full
{"status": "error", "error_type": "FileEditError", "error_message": "old_string not found in file (tried exact, flexible and regex matching)"}
14read_file
{
 "end_line": 520,
 "filepath": "fastapi/params.py",
 "start_line": 470
}
{"status": "ok", "filepath": "fastapi/params.py", "content": "class Body(FieldInfo): # type: ignore[misc]\n def __init__(\n self,\n default: Any = Undefined,\n
full
{"status": "ok", "filepath": "fastapi/params.py", "content": "class Body(FieldInfo):  # type: ignore[misc]\n    def __init__(\n        self,\n        default: Any = Undefined,\n        *,\n        default_factory: Callable[[], Any] | None = _Unset,\n        annotation: Any | None = None,\n        embed: bool | None = None,\n        media_type: str = \"application/json\",\n        alias: str | None = None,\n        alias_priority: int | None = _Unset,\n        validation_alias: str | AliasPath | AliasChoices | None = None,\n        serialization_alias: str | None = None,\n        title: str | None = None,\n        description: str | None = None,\n        gt: float | None = None,\n        ge: float | None = None,\n        lt: float | None = None,\n        le: float | None = None,\n        min_length: int | None = None,\n        max_length: int | None = None,\n        pattern: str | None = None,\n        regex: Annotated[\n            str | None,\n            deprecated(\n                \"Deprecated in FastAPI 0.100.0 and Pydantic v2, use `pattern` instead.\"\n            ),\n        ] = None,\n        discriminator: str | None = None,\n        strict: bool | None = _Unset,\n        multiple_of: float | None = _Unset,\n        allow_inf_nan: bool | None = _Unset,\n        max_digits: int | None = _Unset,\n        decimal_places: int | None = _Unset,\n        examples: list[Any] | None = None,\n        example: Annotated[\n            Any | None,\n            deprecated(\n                \"Deprecated in OpenAPI 3.1.0 that now uses JSON Schema 2020-12, \"\n                \"although still supported. Use examples instead.\"\n            ),\n        ] = _Unset,\n        openapi_examples: dict[str, Example] | None = None,\n        deprecated: deprecated | str | bool | None = None,\n        include_in_schema: bool = True,\n        json_schema_extra: dict[str, Any] | None = None,\n        **extra: Any,\n    ):\n        self.embed = embed\n        self.media_type = media_type
15edit_file
{
 "filepath": "fastapi/params.py",
 "new_string": "        media_type: str = \"application/json\",\n        strict_content_type: bool = False,\n        alias: str | None = None,",
 "old_string": "        media_type: str = \"application/json\",\n        alias: str | None = None,"
}
{"status": "ok", "filepath": "fastapi/params.py", "occurrences": 1, "strategy": "exact", "diff": "--- a/fastapi/params.py\n+++ b/fastapi/params.py\n@@ -476,6 +4
full
{"status": "ok", "filepath": "fastapi/params.py", "occurrences": 1, "strategy": "exact", "diff": "--- a/fastapi/params.py\n+++ b/fastapi/params.py\n@@ -476,6 +476,7 @@\n         annotation: Any | None = None,\n         embed: bool | None = None,\n         media_type: str = \"application/json\",\n+        strict_content_type: bool = False,\n         alias: str | None = None,\n         alias_priority: int | None = _Unset,\n         validation_alias: str | AliasPath | AliasChoices | None = None,\n", "is_truncated": false}
16edit_file
{
 "filepath": "fastapi/params.py",
 "new_string": "        self.embed = embed\n        self.media_type = media_type\n        self.strict_content_type = strict_content_type\n        if example is not _Unset:",
 "old_string": "        self.embed = embed\n        self.media_type = media_type\n        if example is not _Unset:"
}
{"status": "ok", "filepath": "fastapi/params.py", "occurrences": 1, "strategy": "exact", "diff": "--- a/fastapi/params.py\n+++ b/fastapi/params.py\n@@ -518,6 +5
full
{"status": "ok", "filepath": "fastapi/params.py", "occurrences": 1, "strategy": "exact", "diff": "--- a/fastapi/params.py\n+++ b/fastapi/params.py\n@@ -518,6 +518,7 @@\n     ):\n         self.embed = embed\n         self.media_type = media_type\n+        self.strict_content_type = strict_content_type\n         if example is not _Unset:\n             warnings.warn(\n                 \"`example` has been deprecated, please use `examples` instead\",\n", "is_truncated": false}
17read_file
{
 "end_line": 390,
 "filepath": "fastapi/routing.py",
 "start_line": 360
}
{"status": "ok", "filepath": "fastapi/routing.py", "content": " # Read body and auto-close files\n try:\n body: Any = None\n if body_field:\n if is_body_form:\n
full
{"status": "ok", "filepath": "fastapi/routing.py", "content": "        # Read body and auto-close files\n        try:\n            body: Any = None\n            if body_field:\n                if is_body_form:\n                    body = await request.form()\n                    file_stack.push_async_callback(body.close)\n                else:\n                    body_bytes = await request.body()\n                    if body_bytes:\n                        json_body: Any = Undefined\n                        content_type_value = request.headers.get(\"content-type\")\n                        if not content_type_value:\n                            json_body = await request.json()\n                        else:\n                            message = email.message.Message()\n                            message[\"content-type\"] = content_type_value\n                            if message.get_content_maintype() == \"application\":\n                                subtype = message.get_content_subtype()\n                                if subtype == \"json\" or subtype.endswith(\"+json\"):\n                                    json_body = await request.json()\n                        if json_body != Undefined:\n                            body = json_body\n                        else:\n                            body = body_bytes\n        except json.JSONDecodeError as e:\n            validation_error = RequestValidationError(\n                [\n                    {\n                        \"type\": \"json_invalid\",\n                        \"loc\": (\"body\", e.pos),\n", "start_line": 360, "end_line": 390, "total_lines": 4643, "is_truncated": false}
18read_file
{
 "end_line": 360,
 "filepath": "fastapi/routing.py",
 "start_line": 340
}
{"status": "ok", "filepath": "fastapi/routing.py", "content": "\n async def app(request: Request) -> Response:\n response: Response | None = None\n file_stack =
full
{"status": "ok", "filepath": "fastapi/routing.py", "content": "\n    async def app(request: Request) -> Response:\n        response: Response | None = None\n        file_stack = request.scope.get(\"fastapi_middleware_astack\")\n        assert isinstance(file_stack, AsyncExitStack), (\n            \"fastapi_middleware_astack not found in request scope\"\n        )\n\n        # Extract endpoint context for error messages\n        endpoint_ctx = (\n            _extract_endpoint_context(dependant.call)\n            if dependant.call\n            else EndpointContext()\n        )\n\n        if dependant.path:\n            # For mounted sub-apps, include the mount path prefix\n            mount_path = request.scope.get(\"root_path\", \"\").rstrip(\"/\")\n            endpoint_ctx[\"path\"] = f\"{request.method} {mount_path}{dependant.path}\"\n\n        # Read body and auto-close files\n", "start_line": 340, "end_line": 360, "total_lines": 4643, "is_truncated": false}
19read_file
{
 "end_line": 355,
 "filepath": "fastapi/routing.py",
 "start_line": 345
}
{"status": "ok", "filepath": "fastapi/routing.py", "content": " \"fastapi_middleware_astack not found in request scope\"\n )\n\n # Extract endpoint context for
full
{"status": "ok", "filepath": "fastapi/routing.py", "content": "            \"fastapi_middleware_astack not found in request scope\"\n        )\n\n        # Extract endpoint context for error messages\n        endpoint_ctx = (\n            _extract_endpoint_context(dependant.call)\n            if dependant.call\n            else EndpointContext()\n        )\n\n        if dependant.path:\n", "start_line": 345, "end_line": 355, "total_lines": 4643, "is_truncated": false}
20read_file
{
 "end_line": 360,
 "filepath": "fastapi/routing.py",
 "start_line": 350
}
{"status": "ok", "filepath": "fastapi/routing.py", "content": " _extract_endpoint_context(dependant.call)\n if dependant.call\n else EndpointContext()\n )\n\n i
full
{"status": "ok", "filepath": "fastapi/routing.py", "content": "            _extract_endpoint_context(dependant.call)\n            if dependant.call\n            else EndpointContext()\n        )\n\n        if dependant.path:\n            # For mounted sub-apps, include the mount path prefix\n            mount_path = request.scope.get(\"root_path\", \"\").rstrip(\"/\")\n            endpoint_ctx[\"path\"] = f\"{request.method} {mount_path}{dependant.path}\"\n\n        # Read body and auto-close files\n", "start_line": 350, "end_line": 360, "total_lines": 4643, "is_truncated": false}
21read_file
{
 "end_line": 370,
 "filepath": "fastapi/routing.py",
 "start_line": 360
}
{"status": "ok", "filepath": "fastapi/routing.py", "content": " # Read body and auto-close files\n try:\n body: Any = None\n if body_field:\n if is_body_form:\n
full
{"status": "ok", "filepath": "fastapi/routing.py", "content": "        # Read body and auto-close files\n        try:\n            body: Any = None\n            if body_field:\n                if is_body_form:\n                    body = await request.form()\n                    file_stack.push_async_callback(body.close)\n                else:\n                    body_bytes = await request.body()\n                    if body_bytes:\n                        json_body: Any = Undefined\n", "start_line": 360, "end_line": 370, "total_lines": 4643, "is_truncated": false}
22edit_file
{
 "filepath": "fastapi/routing.py",
 "new_string": "                        if not content_type_value:\n                            if getattr(body_field, \"strict_content_type\", False):\n                                raise HTTPException(\n                                    status_code=415,\n                                    detail=\"Unsupported Media Type\",\n                                )\n                            json_body = await request.json()\n                        else:",
 "old_string": "                        if not content_type_value:\n                            json_body = await request.json()\n                        else:"
}
{"status": "ok", "filepath": "fastapi/routing.py", "occurrences": 1, "strategy": "exact", "diff": "--- a/fastapi/routing.py\n+++ b/fastapi/routing.py\n@@ -370,6
full
{"status": "ok", "filepath": "fastapi/routing.py", "occurrences": 1, "strategy": "exact", "diff": "--- a/fastapi/routing.py\n+++ b/fastapi/routing.py\n@@ -370,6 +370,11 @@\n                         json_body: Any = Undefined\n                         content_type_value = request.headers.get(\"content-type\")\n                         if not content_type_value:\n+                            if getattr(body_field, \"strict_content_type\", False):\n+                                raise HTTPException(\n+                                    status_code=415,\n+                                    detail=\"Unsupported Media Type\",\n+                                )\n                             json_body = await request.json()\n                         else:\n                             message = email.message.Message()\n", "is_truncated": false}
23edit_file
{
 "filepath": "fastapi/routing.py",
 "new_string": "                                if subtype == \"json\" or subtype.endswith(\"+json\"):\n                                    json_body = await request.json()\n                                elif getattr(body_field, \"strict_content_type\", False):\n                                    raise HTTPException(\n                                        status_code=415,\n                                        detail=\"Unsupported Media Type\",\n                                    )\n                        if json_body != Undefined:",
 "old_string": "                                if subtype == \"json\" or subtype.endswith(\"+json\"):\n                                    json_body = await request.json()\n                        if json_body != Undefined:"
}
{"status": "ok", "filepath": "fastapi/routing.py", "occurrences": 1, "strategy": "exact", "diff": "--- a/fastapi/routing.py\n+++ b/fastapi/routing.py\n@@ -383,6
full
{"status": "ok", "filepath": "fastapi/routing.py", "occurrences": 1, "strategy": "exact", "diff": "--- a/fastapi/routing.py\n+++ b/fastapi/routing.py\n@@ -383,6 +383,11 @@\n                                 subtype = message.get_content_subtype()\n                                 if subtype == \"json\" or subtype.endswith(\"+json\"):\n                                     json_body = await request.json()\n+                                elif getattr(body_field, \"strict_content_type\", False):\n+                                    raise HTTPException(\n+                                        status_code=415,\n+                                        detail=\"Unsupported Media Type\",\n+                                    )\n                         if json_body != Undefined:\n                             body = json_body\n                         else:\n", "is_truncated": false}
24submit_patch
[]
{"status": "ok", "patch_size": 2395, "files_changed": 2}
full
{"status": "ok", "patch_size": 2395, "files_changed": 2}

Patch

diff --git a/fastapi/params.py b/fastapi/params.py
index 68f98708..10319db1 100644
--- a/fastapi/params.py
+++ b/fastapi/params.py
@@ -476,6 +476,7 @@ class Body(FieldInfo):  # type: ignore[misc]
         annotation: Any | None = None,
         embed: bool | None = None,
         media_type: str = "application/json",
+        strict_content_type: bool = False,
         alias: str | None = None,
         alias_priority: int | None = _Unset,
         validation_alias: str | AliasPath | AliasChoices | None = None,
@@ -517,6 +518,7 @@ class Body(FieldInfo):  # type: ignore[misc]
     ):
         self.embed = embed
         self.media_type = media_type
+        self.strict_content_type = strict_content_type
         if example is not _Unset:
             warnings.warn(
                 "`example` has been deprecated, please use `examples` instead",
diff --git a/fastapi/routing.py b/fastapi/routing.py
index 528c9629..2558b87d 100644
--- a/fastapi/routing.py
+++ b/fastapi/routing.py
@@ -370,6 +370,11 @@ def get_request_handler(
                         json_body: Any = Undefined
                         content_type_value = request.headers.get("content-type")
                         if not content_type_value:
+                            if getattr(body_field, "strict_content_type", False):
+                                raise HTTPException(
+                                    status_code=415,
+                                    detail="Unsupported Media Type",
+                                )
                             json_body = await request.json()
                         else:
                             message = email.message.Message()
@@ -378,6 +383,11 @@ def get_request_handler(
                                 subtype = message.get_content_subtype()
                                 if subtype == "json" or subtype.endswith("+json"):
                                     json_body = await request.json()
+                                elif getattr(body_field, "strict_content_type", False):
+                                    raise HTTPException(
+                                        status_code=415,
+                                        detail="Unsupported Media Type",
+                                    )
                         if json_body != Undefined:
                             body = json_body
                         else:

Test output

show
==================================== ERRORS ====================================
__________ ERROR collecting tests/test_strict_content_type_nested.py ___________
tests/test_strict_content_type_nested.py:8: in <module>
    inner_strict = APIRouter(prefix="/strict", strict_content_type=True)
                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
E   TypeError: APIRouter.__init__() got an unexpected keyword argument 'strict_content_type'
=============================== warnings summary ===============================
../../../../../../kaggle/tmp/envs/overlays/starlette-0.52.1-py3-none-any/starlette/testclient.py:45
  /kaggle/tmp/envs/overlays/starlette-0.52.1-py3-none-any/starlette/testclient.py:45: DeprecationWarning: The anyio.abc.BlockingPortal alias is deprecated, use anyio.from_thread.BlockingPortal instead.
    _PortalFactoryType = Callable[[], AbstractContextManager[anyio.abc.BlockingPortal]]

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 warning, 1 error in 0.71s