HTTP1 header formatting moved to headers.format_headers and rewritten.
- New implementation is one line of code and twice faster than the old one. - Whole header block encoded to UTF-8 in one pass. - No longer supports custom encode method on header values. - Cookie objects now have __str__ in addition to encode, to work with this.
This commit is contained in:
parent
1e4b1c4d1a
commit
4537544fde
|
@ -130,6 +130,10 @@ class Cookie(dict):
|
||||||
:return: Cookie encoded in a codec of choosing.
|
:return: Cookie encoded in a codec of choosing.
|
||||||
:except: UnicodeEncodeError
|
:except: UnicodeEncodeError
|
||||||
"""
|
"""
|
||||||
|
return str(self).encode(encoding)
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
"""Format as a Set-Cookie header value."""
|
||||||
output = ["%s=%s" % (self.key, _quote(self.value))]
|
output = ["%s=%s" % (self.key, _quote(self.value))]
|
||||||
for key, value in self.items():
|
for key, value in self.items():
|
||||||
if key == "max-age":
|
if key == "max-age":
|
||||||
|
@ -147,4 +151,4 @@ class Cookie(dict):
|
||||||
else:
|
else:
|
||||||
output.append("%s=%s" % (self._keys[key], value))
|
output.append("%s=%s" % (self._keys[key], value))
|
||||||
|
|
||||||
return "; ".join(output).encode(encoding)
|
return "; ".join(output)
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
import re
|
import re
|
||||||
|
|
||||||
from typing import Dict, Iterable, Optional, Tuple
|
from typing import Any, Dict, Iterable, Optional, Tuple
|
||||||
from urllib.parse import unquote
|
from urllib.parse import unquote
|
||||||
|
|
||||||
|
HeaderIterable = Iterable[Tuple[str, Any]] # Values convertible to str
|
||||||
Options = Dict[str, str] # key=value fields in various headers
|
Options = Dict[str, str] # key=value fields in various headers
|
||||||
OptionsIterable = Iterable[Tuple[str, str]] # May contain duplicate keys
|
OptionsIterable = Iterable[Tuple[str, str]] # May contain duplicate keys
|
||||||
|
|
||||||
|
@ -165,3 +165,12 @@ def parse_host(host: str) -> Tuple[Optional[str], Optional[int]]:
|
||||||
return None, None
|
return None, None
|
||||||
host, port = m.groups()
|
host, port = m.groups()
|
||||||
return host.lower(), port and int(port)
|
return host.lower(), port and int(port)
|
||||||
|
|
||||||
|
|
||||||
|
def format_http1(headers: HeaderIterable) -> bytes:
|
||||||
|
"""Convert a headers iterable into HTTP/1 header format.
|
||||||
|
|
||||||
|
- Outputs UTF-8 bytes where each header line ends with \\r\\n.
|
||||||
|
- Values are converted into strings if necessary.
|
||||||
|
"""
|
||||||
|
return "".join(f"{name}: {val}\r\n" for name, val in headers).encode()
|
||||||
|
|
|
@ -7,6 +7,7 @@ from aiofiles import open as open_async
|
||||||
|
|
||||||
from sanic.compat import Header
|
from sanic.compat import Header
|
||||||
from sanic.cookies import CookieJar
|
from sanic.cookies import CookieJar
|
||||||
|
from sanic.headers import format_http1
|
||||||
from sanic.helpers import STATUS_CODES, has_message_body, remove_entity_headers
|
from sanic.helpers import STATUS_CODES, has_message_body, remove_entity_headers
|
||||||
|
|
||||||
|
|
||||||
|
@ -30,20 +31,7 @@ class BaseHTTPResponse:
|
||||||
return str(data).encode()
|
return str(data).encode()
|
||||||
|
|
||||||
def _parse_headers(self):
|
def _parse_headers(self):
|
||||||
headers = b""
|
return format_http1(self.headers.items())
|
||||||
for name, value in self.headers.items():
|
|
||||||
try:
|
|
||||||
headers += b"%b: %b\r\n" % (
|
|
||||||
name.encode(),
|
|
||||||
value.encode("utf-8"),
|
|
||||||
)
|
|
||||||
except AttributeError:
|
|
||||||
headers += b"%b: %b\r\n" % (
|
|
||||||
str(name).encode(),
|
|
||||||
str(value).encode("utf-8"),
|
|
||||||
)
|
|
||||||
|
|
||||||
return headers
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def cookies(self):
|
def cookies(self):
|
||||||
|
|
Loading…
Reference in New Issue
Block a user