Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -301,6 +301,14 @@ arrive as strings and usually need a separate model that keeps coercion. See
[Strict API boundary models](docs/strict-models.md) for runnable examples and
exact validation responses.

For a strict JSON endpoint, use
`@validate_http(body=CreateUserRequest, response_model=CreateUserResponse, require_json_content_type=True)`.
The compatibility default is `False`: valid JSON is parsed even when labeled
`text/plain` or sent without `Content-Type`. Strict mode accepts `application/json`
and `application/*+json`; a non-empty body with another or missing media type
returns `415`. An empty body still returns the missing-body `422`, not `415`.
See [JSON Content-Type configuration](docs/configuration.md#require_json_content_type).

Start the Functions host locally:

```bash
Expand Down
11 changes: 11 additions & 0 deletions docs/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,17 @@ their parsing limits.

### `require_json_content_type`

**Recommended for new public JSON endpoints:** set this option explicitly to
`True`. Existing applications keep the relaxed `False` default for compatibility;
it parses valid JSON regardless of the header, including `text/plain` or an absent
header. The relaxed default alone is not evidence of an exploitable vulnerability.

Migration: first update clients to send `application/json` (or a supported
`application/*+json` type), then opt individual routes into strict mode and test
their `415` responses. No runtime warning or default change is introduced here.
Any future default change requires a separately reviewed breaking-release
migration decision and usage evidence; it must not silently ship in a patch.

Set `require_json_content_type=True` with `body=` to reject non-empty bodies
whose media type is neither `application/json` nor `application/*+json` with
`415 Unsupported Media Type`. Matching is case-insensitive and ignores
Expand Down
15 changes: 11 additions & 4 deletions tests/test_body_policies.py
Original file line number Diff line number Diff line change
Expand Up @@ -141,12 +141,19 @@ def test_missing_media_type_with_empty_body_keeps_missing_body_response(
assert response.status_code == 422
assert json.loads(response.get_body())["detail"][0]["type"] == "missing"

@pytest.mark.parametrize(
"headers",
[
{"Content-Type": "application/json"},
{"Content-Type": "application/problem+json"},
{"Content-Type": "text/plain"},
{},
],
)
def test_default_still_parses_json_regardless_of_media_type(
self, mock_request_factory: RequestFactory
self, headers: dict[str, str], mock_request_factory: RequestFactory
) -> None:
response = _body_handler()(
mock_request_factory(body=b'{"name":"Ada"}', headers={"Content-Type": "text/plain"})
)
response = _body_handler()(mock_request_factory(body=b'{"name":"Ada"}', headers=headers))

assert response.status_code == 200

Expand Down
Loading