format_http1_response

This commit is contained in:
L. Kärkkäinen 2019-09-05 11:43:23 +03:00
parent d248dbb72b
commit 7dc683913f
2 changed files with 35 additions and 45 deletions

View File

@ -3,6 +3,8 @@ import re
from typing import Any, Dict, Iterable, Optional, Tuple
from urllib.parse import unquote
from sanic.helpers import STATUS_CODES
HeaderIterable = Iterable[Tuple[str, Any]] # Values convertible to str
Options = Dict[str, str] # key=value fields in various headers
@ -175,3 +177,21 @@ def format_http1(headers: HeaderIterable) -> bytes:
- Values are converted into strings if necessary.
"""
return "".join(f"{name}: {val}\r\n" for name, val in headers).encode()
def format_http1_response(
status: int, headers: HeaderIterable, body=b""
) -> bytes:
"""Format a full HTTP/1.1 response.
- If `body` is included, content-length must be specified in headers.
"""
headers = format_http1(headers)
if status == 200:
return b"HTTP/1.1 200 OK\r\n%b\r\n%b" % (headers, body)
return b"HTTP/1.1 %d %b\r\n%b\r\n%b" % (
status,
STATUS_CODES.get(status, b"UNKNOWN"),
headers,
body,
)

View File

@ -7,8 +7,8 @@ from aiofiles import open as open_async
from sanic.compat import Header
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.headers import format_http1, format_http1_response
from sanic.helpers import has_message_body, remove_entity_headers
try:
@ -104,33 +104,17 @@ class StreamingHTTPResponse(BaseHTTPResponse):
def get_headers(
self, version="1.1", keep_alive=False, keep_alive_timeout=None
):
# This is all returned in a kind-of funky way
# We tried to make this as fast as possible in pure python
timeout_header = b""
if "Content-Type" not in self.headers:
self.headers["Content-Type"] = self.content_type
if keep_alive and keep_alive_timeout is not None:
timeout_header = b"Keep-Alive: %d\r\n" % keep_alive_timeout
self.headers["Keep-Alive"] = keep_alive_timeout
if self.chunked and version == "1.1":
self.headers["Transfer-Encoding"] = "chunked"
self.headers.pop("Content-Length", None)
self.headers["Content-Type"] = self.headers.get(
"Content-Type", self.content_type
)
headers = self._parse_headers()
if self.status == 200:
status = b"OK"
else:
status = STATUS_CODES.get(self.status)
return (b"HTTP/%b %d %b\r\n" b"%b" b"%b\r\n") % (
version.encode(),
self.status,
status,
timeout_header,
headers,
)
return format_http1_response(self.status, self.headers.items())
class HTTPResponse(BaseHTTPResponse):
@ -156,11 +140,8 @@ class HTTPResponse(BaseHTTPResponse):
self._cookies = None
def output(self, version="1.1", keep_alive=False, keep_alive_timeout=None):
# This is all returned in a kind-of funky way
# We tried to make this as fast as possible in pure python
timeout_header = b""
if keep_alive and keep_alive_timeout is not None:
timeout_header = b"Keep-Alive: %d\r\n" % keep_alive_timeout
if "Content-Type" not in self.headers:
self.headers["Content-Type"] = self.content_type
body = b""
if has_message_body(self.status):
@ -176,24 +157,13 @@ class HTTPResponse(BaseHTTPResponse):
if self.status in (304, 412):
self.headers = remove_entity_headers(self.headers)
headers = self._parse_headers()
if keep_alive and keep_alive_timeout is not None:
self.headers["Connection"] = "keep-alive"
self.headers["Keep-Alive"] = keep_alive_timeout
elif not keep_alive:
self.headers["Connection"] = "close"
if self.status == 200:
status = b"OK"
else:
status = STATUS_CODES.get(self.status, b"UNKNOWN RESPONSE")
return (
b"HTTP/%b %d %b\r\n" b"Connection: %b\r\n" b"%b" b"%b\r\n" b"%b"
) % (
version.encode(),
self.status,
status,
b"keep-alive" if keep_alive else b"close",
timeout_header,
headers,
body,
)
return format_http1_response(self.status, self.headers.items(), body)
@property
def cookies(self):