Source code for runtimepy.net.http.common
"""
A module containing shared interfaces for HTTP.
"""
# built-in
from abc import ABC, abstractmethod
import http
from typing import Optional, TextIO, Union
# third-party
from vcorelib import DEFAULT_ENCODING
from vcorelib.logging import LoggerType
HTTPMethodlike = Union[str, http.HTTPMethod]
HEADER_LINESEP = "\r\n"
[docs]
def normalize_method(data: HTTPMethodlike) -> http.HTTPMethod:
"""Normalize HTTP method data."""
if not isinstance(data, http.HTTPMethod):
data = http.HTTPMethod[data]
return data
[docs]
class HeadersMixin(ABC):
"""A class implementing a mixin for HTTP header fields."""
def __init__(self, lines: list[str] = None) -> None:
"""Initialize this instance."""
self.headers: dict[str, str] = {}
if lines:
for header_raw in lines:
key, value = header_raw.split(":", maxsplit=1)
self[key] = value
def __getitem__(self, key: str) -> str:
"""Get a header key."""
return self.headers[key.lower()]
def __setitem__(self, key: str, value: str) -> None:
"""Set a header key."""
self.headers[key.lower()] = value.strip()
[docs]
def get(self, key: str, default: str = None) -> Optional[str]:
"""Get a possible header value."""
return self.headers.get(key.lower(), default)
@property
def content_length(self) -> int:
"""Get a value for context length."""
return int(self.get("content-length", "0")) # type: ignore
[docs]
def write_field_lines(self, stream: TextIO) -> None:
"""Write field lines to a stream."""
for key, value in self.headers.items():
stream.write(f"{key}: {value}")
stream.write(HEADER_LINESEP)
[docs]
@abstractmethod
def from_lines(self, lines: list[str]) -> None:
"""Update this request from line data."""
[docs]
@abstractmethod
def log(self, logger: LoggerType, out: bool, **kwargs) -> None:
"""Log information about this response header."""
@abstractmethod
def __str__(self) -> str:
"""Get this response as a string."""
def __bytes__(self) -> bytes:
"""Get this instances as bytes."""
return str(self).encode(encoding=DEFAULT_ENCODING)