Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat (status_codes): update HTTP status constants wrt RFC 9110 #2330

Merged
merged 14 commits into from
Sep 27, 2024
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
4 changes: 2 additions & 2 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -573,7 +573,7 @@ Note that this example assumes that the
msg = ('The size of the request is too large. The body must not '
'exceed ' + str(limit) + ' bytes in length.')

raise falcon.HTTPPayloadTooLarge(
raise falcon.HTTPContentTooLarge(
title='Request body is too large', description=msg)

return hook
Expand Down Expand Up @@ -830,7 +830,7 @@ Here's the ASGI version of the app from above. Note that it uses the
msg = ('The size of the request is too large. The body must not '
'exceed ' + str(limit) + ' bytes in length.')

raise falcon.HTTPPayloadTooLarge(
raise falcon.HTTPContentTooLarge(
title='Request body is too large', description=msg)

return hook
Expand Down
11 changes: 11 additions & 0 deletions docs/_newsfragments/2276.newandimproved.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
The class ``falcon.HTTPPayloadTooLarge`` was renamed to
:class:`falcon.HTTPContentTooLarge`, together with the accompanying HTTP
:ref:`status code <status>` update, in order to reflect the newest HTTP
semantics as per
`RFC 9110, Section 15.5.14 <https://datatracker.ietf.org/doc/html/rfc9110#status.413>`__.
(The old class name remains available as a deprecated compatibility alias.)

In addition, one new :ref:`status code constant <status>` was added:
``falcon.HTTP_421`` (also available as ``falcon.HTTP_MISDIRECTED_REQUEST``)
in accordance with
`RFC 9110, Section 15.5.20 <https://datatracker.ietf.org/doc/html/rfc9110#status.421>`__.
2 changes: 1 addition & 1 deletion docs/api/errors.rst
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ Predefined Errors
.. autoclass:: falcon.HTTPPreconditionFailed
:members:

.. autoclass:: falcon.HTTPPayloadTooLarge
.. autoclass:: falcon.HTTPContentTooLarge
:members:

.. autoclass:: falcon.HTTPUriTooLong
Expand Down
4 changes: 2 additions & 2 deletions docs/api/status.rst
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ HTTPStatus
HTTP_GONE = HTTP_410
HTTP_LENGTH_REQUIRED = HTTP_411
HTTP_PRECONDITION_FAILED = HTTP_412
HTTP_REQUEST_ENTITY_TOO_LARGE = HTTP_413
HTTP_CONTENT_TOO_LARGE = HTTP_413
HTTP_REQUEST_URI_TOO_LONG = HTTP_414
HTTP_UNSUPPORTED_MEDIA_TYPE = HTTP_415
HTTP_REQUESTED_RANGE_NOT_SATISFIABLE = HTTP_416
Expand Down Expand Up @@ -168,7 +168,7 @@ HTTPStatus
HTTP_410 = '410 Gone'
HTTP_411 = '411 Length Required'
HTTP_412 = '412 Precondition Failed'
HTTP_413 = '413 Payload Too Large'
HTTP_413 = '413 Content Too Large'
HTTP_414 = '414 URI Too Long'
HTTP_415 = '415 Unsupported Media Type'
HTTP_416 = '416 Range Not Satisfiable'
Expand Down
2 changes: 1 addition & 1 deletion examples/things_advanced.py
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ def hook(req, resp, resource, params):
'exceed ' + str(limit) + ' bytes in length.'
)

raise falcon.HTTPPayloadTooLarge(
raise falcon.HTTPContentTooLarge(
title='Request body is too large', description=msg
)

Expand Down
2 changes: 1 addition & 1 deletion examples/things_advanced_asgi.py
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ async def hook(req, resp, resource, params):
'exceed ' + str(limit) + ' bytes in length.'
)

raise falcon.HTTPPayloadTooLarge(
raise falcon.HTTPContentTooLarge(
title='Request body is too large', description=msg
)

Expand Down
5 changes: 3 additions & 2 deletions falcon/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@
'HTTPNotAcceptable',
'HTTPNotFound',
'HTTPNotImplemented',
'HTTPContentTooLarge',
'HTTPPayloadTooLarge',
'HTTPPreconditionFailed',
'HTTPPreconditionRequired',
Expand Down Expand Up @@ -303,7 +304,6 @@
'HTTP_PROCESSING',
'HTTP_PROXY_AUTHENTICATION_REQUIRED',
'HTTP_REQUESTED_RANGE_NOT_SATISFIABLE',
'HTTP_REQUEST_ENTITY_TOO_LARGE',
'HTTP_REQUEST_HEADER_FIELDS_TOO_LARGE',
'HTTP_REQUEST_TIMEOUT',
'HTTP_REQUEST_URI_TOO_LONG',
Expand Down Expand Up @@ -354,6 +354,7 @@
from falcon.errors import HTTPBadGateway
from falcon.errors import HTTPBadRequest
from falcon.errors import HTTPConflict
from falcon.errors import HTTPContentTooLarge
from falcon.errors import HTTPFailedDependency
from falcon.errors import HTTPForbidden
from falcon.errors import HTTPGatewayTimeout
Expand Down Expand Up @@ -529,6 +530,7 @@
from falcon.status_codes import HTTP_BAD_GATEWAY
from falcon.status_codes import HTTP_BAD_REQUEST
from falcon.status_codes import HTTP_CONFLICT
from falcon.status_codes import HTTP_CONTENT_TOO_LARGE
vytas7 marked this conversation as resolved.
Show resolved Hide resolved
from falcon.status_codes import HTTP_CONTINUE
from falcon.status_codes import HTTP_CREATED
from falcon.status_codes import HTTP_EARLY_HINTS
Expand Down Expand Up @@ -567,7 +569,6 @@
from falcon.status_codes import HTTP_PRECONDITION_REQUIRED
from falcon.status_codes import HTTP_PROCESSING
from falcon.status_codes import HTTP_PROXY_AUTHENTICATION_REQUIRED
from falcon.status_codes import HTTP_REQUEST_ENTITY_TOO_LARGE
from falcon.status_codes import HTTP_REQUEST_HEADER_FIELDS_TOO_LARGE
from falcon.status_codes import HTTP_REQUEST_TIMEOUT
from falcon.status_codes import HTTP_REQUEST_URI_TOO_LONG
Expand Down
20 changes: 16 additions & 4 deletions falcon/errors.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,11 @@
from __future__ import annotations

from datetime import datetime
from typing import Iterable, Optional, TYPE_CHECKING, Union
from typing import Any, Iterable, Optional, TYPE_CHECKING, Union

from falcon.http_error import HTTPError
import falcon.status_codes as status
from falcon.util import deprecation
from falcon.util.misc import dt_to_http

if TYPE_CHECKING:
Expand Down Expand Up @@ -73,7 +74,7 @@
'HTTPNotAcceptable',
'HTTPNotFound',
'HTTPNotImplemented',
'HTTPPayloadTooLarge',
'HTTPContentTooLarge',
'HTTPPreconditionFailed',
'HTTPPreconditionRequired',
'HTTPRangeNotSatisfiable',
Expand Down Expand Up @@ -952,8 +953,8 @@
)


class HTTPPayloadTooLarge(HTTPError):
"""413 Payload Too Large.
class HTTPContentTooLarge(HTTPError):
vytas7 marked this conversation as resolved.
Show resolved Hide resolved
"""413 Content Too Large.

The server is refusing to process a request because the request
payload is larger than the server is willing or able to process.
Expand Down Expand Up @@ -1025,6 +1026,17 @@
)


# TODO(vytas): Remove in Falcon 5.0.
class HTTPPayloadTooLarge(HTTPContentTooLarge):
"""Compatibility alias of :class:`falcon.HTTPContentTooLarge`."""

@deprecation.deprecated(
'HTTPPayloadTooLarge is deprecated; use HTTPContentTooLarge instead.'
)
def __init__(self, *args: Any, **kwargs: Any) -> None:
super().__init__(*args, **kwargs)

Check warning on line 1037 in falcon/errors.py

View check run for this annotation

Codecov / codecov/patch

falcon/errors.py#L1037

Added line #L1037 was not covered by tests


class HTTPUriTooLong(HTTPError):
"""414 URI Too Long.

Expand Down
6 changes: 4 additions & 2 deletions falcon/status_codes.py
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,9 @@
HTTP_LENGTH_REQUIRED: Final[str] = HTTP_411
HTTP_412: Final[str] = '412 Precondition Failed'
HTTP_PRECONDITION_FAILED: Final[str] = HTTP_412
HTTP_413: Final[str] = '413 Payload Too Large'
HTTP_413: Final[str] = '413 Content Too Large'
HTTP_CONTENT_TOO_LARGE: Final[str] = HTTP_413
HTTP_PAYLOAD_TOO_LARGE: Final[str] = HTTP_413
HTTP_REQUEST_ENTITY_TOO_LARGE: Final[str] = HTTP_413
HTTP_414: Final[str] = '414 URI Too Long'
HTTP_REQUEST_URI_TOO_LONG: Final[str] = HTTP_414
Expand Down Expand Up @@ -330,6 +332,7 @@
'HTTP_BAD_GATEWAY',
'HTTP_BAD_REQUEST',
'HTTP_CONFLICT',
'HTTP_CONTENT_TOO_LARGE',
'HTTP_CONTINUE',
'HTTP_CREATED',
'HTTP_EARLY_HINTS',
Expand Down Expand Up @@ -369,7 +372,6 @@
'HTTP_PROCESSING',
'HTTP_PROXY_AUTHENTICATION_REQUIRED',
'HTTP_REQUESTED_RANGE_NOT_SATISFIABLE',
'HTTP_REQUEST_ENTITY_TOO_LARGE',
'HTTP_REQUEST_HEADER_FIELDS_TOO_LARGE',
'HTTP_REQUEST_TIMEOUT',
'HTTP_REQUEST_URI_TOO_LONG',
Expand Down
18 changes: 12 additions & 6 deletions tests/test_error.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
(falcon.HTTPGone, status.HTTP_410),
(falcon.HTTPLengthRequired, status.HTTP_411),
(falcon.HTTPPreconditionFailed, status.HTTP_412),
(falcon.HTTPPayloadTooLarge, status.HTTP_413),
(falcon.HTTPContentTooLarge, status.HTTP_413),
(falcon.HTTPUriTooLong, status.HTTP_414),
(falcon.HTTPUnsupportedMediaType, status.HTTP_415),
(falcon.HTTPUnprocessableEntity, status.HTTP_422),
Expand Down Expand Up @@ -81,7 +81,7 @@ def test_with_default_title_and_desc_args(err, title, args):
falcon.HTTPGone,
falcon.HTTPLengthRequired,
falcon.HTTPPreconditionFailed,
falcon.HTTPPayloadTooLarge,
falcon.HTTPContentTooLarge,
falcon.HTTPUriTooLong,
falcon.HTTPUnsupportedMediaType,
falcon.HTTPUnprocessableEntity,
Expand Down Expand Up @@ -128,7 +128,7 @@ def test_with_title_desc_and_headers(err):
falcon.HTTPGone,
falcon.HTTPLengthRequired,
falcon.HTTPPreconditionFailed,
falcon.HTTPPayloadTooLarge,
falcon.HTTPContentTooLarge,
falcon.HTTPUriTooLong,
falcon.HTTPUnsupportedMediaType,
falcon.HTTPUnprocessableEntity,
Expand Down Expand Up @@ -195,7 +195,7 @@ def test_args_kw_only(err, args):
[
falcon.HTTPServiceUnavailable,
falcon.HTTPTooManyRequests,
falcon.HTTPPayloadTooLarge,
falcon.HTTPContentTooLarge,
],
)
def test_with_retry_after(err):
Expand All @@ -210,7 +210,7 @@ def test_with_retry_after(err):
[
falcon.HTTPServiceUnavailable,
falcon.HTTPTooManyRequests,
falcon.HTTPPayloadTooLarge,
falcon.HTTPContentTooLarge,
],
)
def test_with_retry_after_and_headers(err):
Expand Down Expand Up @@ -283,7 +283,7 @@ def test_custom_400(err, args, title, desc):
'a, b',
True,
),
(falcon.HTTPPayloadTooLarge, 'Retry-After', 'retry_after', 123, '123', False),
(falcon.HTTPContentTooLarge, 'Retry-After', 'retry_after', 123, '123', False),
(
falcon.HTTPRangeNotSatisfiable,
'Content-Range',
Expand Down Expand Up @@ -350,3 +350,9 @@ def test_override_header_list(
assert header_name in value.headers
assert isinstance(value.headers, dict)
assert value.headers[header_name] == res


def test_http_payload_too_large_deprecation():
with pytest.warns(match='HTTPContentTooLarge'):
err = errors.HTTPPayloadTooLarge()
assert err.title == '413 Content Too Large'
4 changes: 2 additions & 2 deletions tests/test_httperror.py
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,7 @@ def on_get(self, req, resp):

class RequestEntityTooLongResource:
def on_get(self, req, resp):
raise falcon.HTTPPayloadTooLarge(
raise falcon.HTTPContentTooLarge(
title='Request Rejected', description='Request Body Too Large'
)

Expand All @@ -181,7 +181,7 @@ def __init__(self, retry_after):
self.retry_after = retry_after

def on_get(self, req, resp):
raise falcon.HTTPPayloadTooLarge(
raise falcon.HTTPContentTooLarge(
title='Request Rejected',
description='Request Body Too Large',
retry_after=self.retry_after,
Expand Down
2 changes: 1 addition & 1 deletion tests/test_status_codes.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ def test_statuses_are_in_compliance_with_http_from_python313(self, status):
if status_code >= 700:
pytest.skip('Codes above 700 are not defined in http package')
http_status = http.HTTPStatus(status_code)
if status_code in [413, 418, 422]:
if status_code in [418, 422]:
assert http_status.phrase != message
else:
assert http_status.phrase == message
Expand Down