Compare commits

..

1 Commits

4 changed files with 57 additions and 22 deletions

View File

@@ -149,13 +149,11 @@ class CookieRequestParameters(RequestParameters):
except KeyError:
return super().get(name, default)
def getlist(
self, name: str, default: Optional[Any] = None
) -> Optional[Any]:
def getlist(self, name: str) -> list[Any]:
try:
return self._get_prefixed_cookie(name)
except KeyError:
return super().getlist(name, default)
return super().getlist(name)
def _get_prefixed_cookie(self, name: str) -> Any:
getitem = super().__getitem__

View File

@@ -152,20 +152,24 @@ class HTTPReceiver(Receiver, Stream):
size = len(response.body) if response.body else 0
headers = response.headers
status = response.status
want_body = (
if not has_message_body(status) and (
size
or "content-length" in headers
or "transfer-encoding" in headers
)
headers.pop("transfer-encoding", None) # Not used with HTTP/3
if want_body and not has_message_body(status):
):
headers.pop("content-length", None)
headers.pop("transfer-encoding", None)
logger.warning( # no cov
f"Message body set in response on {self.request.path}. "
f"A {status} response may only have headers, no body."
)
elif size and "content-length" not in headers:
headers["content-length"] = size
elif "content-length" not in headers:
if size:
headers["content-length"] = size
else:
headers["transfer-encoding"] = "chunked"
headers = [
(b":status", str(response.status).encode()),
*response.processed_headers,
@@ -191,8 +195,18 @@ class HTTPReceiver(Receiver, Stream):
self.headers_sent = True
self.stage = Stage.RESPONSE
if self.response.body and not self.head_only:
self._send(self.response.body, False)
elif self.head_only:
self.future.cancel()
def respond(self, response: BaseHTTPResponse) -> BaseHTTPResponse:
"""Prepare response to client"""
logger.debug( # no cov
f"{Colors.BLUE}[respond]:{Colors.END} {response}",
extra={"verbosity": 2},
)
if self.stage is not Stage.HANDLER:
self.stage = Stage.FAILED
raise RuntimeError("Response already started")
@@ -215,14 +229,38 @@ class HTTPReceiver(Receiver, Stream):
async def send(self, data: bytes, end_stream: bool) -> None:
"""Send data to client"""
logger.debug( # no cov
f"{Colors.BLUE}[send]: {Colors.GREEN}data={data.decode()} "
f"end_stream={end_stream}{Colors.END}",
extra={"verbosity": 2},
)
self._send(data, end_stream)
def _send(self, data: bytes, end_stream: bool) -> None:
if not self.headers_sent:
self.send_headers()
if self.stage is not Stage.RESPONSE:
raise ServerError(f"not ready to send: {self.stage}")
if data and self.head_only:
data = b""
# Chunked
if (
self.response
and self.response.headers.get("transfer-encoding") == "chunked"
):
size = len(data)
if end_stream:
data = (
b"%x\r\n%b\r\n0\r\n\r\n" % (size, data)
if size
else b"0\r\n\r\n"
)
elif size:
data = b"%x\r\n%b\r\n" % (size, data)
logger.debug( # no cov
f"{Colors.BLUE}[transmitting]{Colors.END}",
extra={"verbosity": 2},
)
self.protocol.connection.send_data(
stream_id=self.request.stream_id,
data=data,

View File

@@ -19,15 +19,14 @@ class RequestParameters(dict):
return super().get(name, [default])[0]
def getlist(
self, name: str, default: Optional[Any] = None
) -> Optional[Any]:
self, name: str
) -> list[Any]:
"""Return the entire list
Args:
name (str): The name of the parameter
default (Optional[Any], optional): The default value. Defaults to None.
Returns:
Optional[Any]: The entire list
list[Any]: The entire list of values or [] if not found
""" # noqa: E501
return super().get(name, default)
return super().get(name) or []

View File

@@ -445,10 +445,10 @@ def test_cookie_accessors(app: Sanic):
"four": request.cookies.get("four", "fallback"),
},
"getlist": {
"one": request.cookies.getlist("one", ["fallback"]),
"two": request.cookies.getlist("two", ["fallback"]),
"three": request.cookies.getlist("three", ["fallback"]),
"four": request.cookies.getlist("four", ["fallback"]),
"one": request.cookies.getlist("one"),
"two": request.cookies.getlist("two"),
"three": request.cookies.getlist("three"),
"four": request.cookies.getlist("four"),
},
"getattr": {
"one": request.cookies.one,
@@ -484,7 +484,7 @@ def test_cookie_accessors(app: Sanic):
"one": ["1"],
"two": ["2"],
"three": ["3"],
"four": ["fallback"],
"four": [],
},
"getattr": {
"one": "1",