Add Request properties for HTTP method info (#2516)
This commit is contained in:
parent
8e9342e188
commit
7827b1b41d
|
@ -34,6 +34,15 @@ class LocalCertCreator(str, Enum):
|
||||||
|
|
||||||
|
|
||||||
HTTP_METHODS = tuple(HTTPMethod.__members__.values())
|
HTTP_METHODS = tuple(HTTPMethod.__members__.values())
|
||||||
|
SAFE_HTTP_METHODS = (HTTPMethod.GET, HTTPMethod.HEAD, HTTPMethod.OPTIONS)
|
||||||
|
IDEMPOTENT_HTTP_METHODS = (
|
||||||
|
HTTPMethod.GET,
|
||||||
|
HTTPMethod.HEAD,
|
||||||
|
HTTPMethod.PUT,
|
||||||
|
HTTPMethod.DELETE,
|
||||||
|
HTTPMethod.OPTIONS,
|
||||||
|
)
|
||||||
|
CACHEABLE_HTTP_METHODS = (HTTPMethod.GET, HTTPMethod.HEAD)
|
||||||
DEFAULT_HTTP_CONTENT_TYPE = "application/octet-stream"
|
DEFAULT_HTTP_CONTENT_TYPE = "application/octet-stream"
|
||||||
DEFAULT_LOCAL_TLS_KEY = "key.pem"
|
DEFAULT_LOCAL_TLS_KEY = "key.pem"
|
||||||
DEFAULT_LOCAL_TLS_CERT = "cert.pem"
|
DEFAULT_LOCAL_TLS_CERT = "cert.pem"
|
||||||
|
|
|
@ -38,7 +38,12 @@ from httptools import parse_url
|
||||||
from httptools.parser.errors import HttpParserInvalidURLError
|
from httptools.parser.errors import HttpParserInvalidURLError
|
||||||
|
|
||||||
from sanic.compat import CancelledErrors, Header
|
from sanic.compat import CancelledErrors, Header
|
||||||
from sanic.constants import DEFAULT_HTTP_CONTENT_TYPE
|
from sanic.constants import (
|
||||||
|
CACHEABLE_HTTP_METHODS,
|
||||||
|
DEFAULT_HTTP_CONTENT_TYPE,
|
||||||
|
IDEMPOTENT_HTTP_METHODS,
|
||||||
|
SAFE_HTTP_METHODS,
|
||||||
|
)
|
||||||
from sanic.exceptions import BadRequest, BadURL, ServerError
|
from sanic.exceptions import BadRequest, BadURL, ServerError
|
||||||
from sanic.headers import (
|
from sanic.headers import (
|
||||||
AcceptContainer,
|
AcceptContainer,
|
||||||
|
@ -975,6 +980,33 @@ class Request:
|
||||||
|
|
||||||
return self.transport.scope
|
return self.transport.scope
|
||||||
|
|
||||||
|
@property
|
||||||
|
def is_safe(self) -> bool:
|
||||||
|
"""
|
||||||
|
:return: Whether the HTTP method is safe.
|
||||||
|
See https://datatracker.ietf.org/doc/html/rfc7231#section-4.2.1
|
||||||
|
:rtype: bool
|
||||||
|
"""
|
||||||
|
return self.method in SAFE_HTTP_METHODS
|
||||||
|
|
||||||
|
@property
|
||||||
|
def is_idempotent(self) -> bool:
|
||||||
|
"""
|
||||||
|
:return: Whether the HTTP method is iempotent.
|
||||||
|
See https://datatracker.ietf.org/doc/html/rfc7231#section-4.2.2
|
||||||
|
:rtype: bool
|
||||||
|
"""
|
||||||
|
return self.method in IDEMPOTENT_HTTP_METHODS
|
||||||
|
|
||||||
|
@property
|
||||||
|
def is_cacheable(self) -> bool:
|
||||||
|
"""
|
||||||
|
:return: Whether the HTTP method is cacheable.
|
||||||
|
See https://datatracker.ietf.org/doc/html/rfc7231#section-4.2.3
|
||||||
|
:rtype: bool
|
||||||
|
"""
|
||||||
|
return self.method in CACHEABLE_HTTP_METHODS
|
||||||
|
|
||||||
|
|
||||||
class File(NamedTuple):
|
class File(NamedTuple):
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -243,3 +243,54 @@ def test_request_stream_id(app):
|
||||||
|
|
||||||
_, resp = app.test_client.get("/")
|
_, resp = app.test_client.get("/")
|
||||||
assert resp.text == "Stream ID is only a property of a HTTP/3 request"
|
assert resp.text == "Stream ID is only a property of a HTTP/3 request"
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
"method,safe",
|
||||||
|
(
|
||||||
|
("DELETE", False),
|
||||||
|
("GET", True),
|
||||||
|
("HEAD", True),
|
||||||
|
("OPTIONS", True),
|
||||||
|
("PATCH", False),
|
||||||
|
("POST", False),
|
||||||
|
("PUT", False),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
def test_request_safe(method, safe):
|
||||||
|
request = Request(b"/", {}, None, method, None, None)
|
||||||
|
assert request.is_safe is safe
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
"method,idempotent",
|
||||||
|
(
|
||||||
|
("DELETE", True),
|
||||||
|
("GET", True),
|
||||||
|
("HEAD", True),
|
||||||
|
("OPTIONS", True),
|
||||||
|
("PATCH", False),
|
||||||
|
("POST", False),
|
||||||
|
("PUT", True),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
def test_request_idempotent(method, idempotent):
|
||||||
|
request = Request(b"/", {}, None, method, None, None)
|
||||||
|
assert request.is_idempotent is idempotent
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
"method,cacheable",
|
||||||
|
(
|
||||||
|
("DELETE", False),
|
||||||
|
("GET", True),
|
||||||
|
("HEAD", True),
|
||||||
|
("OPTIONS", False),
|
||||||
|
("PATCH", False),
|
||||||
|
("POST", False),
|
||||||
|
("PUT", False),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
def test_request_cacheable(method, cacheable):
|
||||||
|
request = Request(b"/", {}, None, method, None, None)
|
||||||
|
assert request.is_cacheable is cacheable
|
||||||
|
|
Loading…
Reference in New Issue
Block a user