123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253 |
- import asyncio
- import logging
- import socket
- import zlib
- from abc import ABC, abstractmethod
- from collections.abc import Sized
- from http.cookies import BaseCookie, Morsel
- from typing import (
- TYPE_CHECKING,
- Any,
- Awaitable,
- Callable,
- Dict,
- Generator,
- Iterable,
- List,
- Optional,
- Tuple,
- TypedDict,
- Union,
- )
- from multidict import CIMultiDict
- from yarl import URL
- from .typedefs import LooseCookies
- if TYPE_CHECKING:
- from .web_app import Application
- from .web_exceptions import HTTPException
- from .web_request import BaseRequest, Request
- from .web_response import StreamResponse
- else:
- BaseRequest = Request = Application = StreamResponse = None
- HTTPException = None
- class AbstractRouter(ABC):
- def __init__(self) -> None:
- self._frozen = False
- def post_init(self, app: Application) -> None:
- """Post init stage.
- Not an abstract method for sake of backward compatibility,
- but if the router wants to be aware of the application
- it can override this.
- """
- @property
- def frozen(self) -> bool:
- return self._frozen
- def freeze(self) -> None:
- """Freeze router."""
- self._frozen = True
- @abstractmethod
- async def resolve(self, request: Request) -> "AbstractMatchInfo":
- """Return MATCH_INFO for given request"""
- class AbstractMatchInfo(ABC):
- __slots__ = ()
- @property # pragma: no branch
- @abstractmethod
- def handler(self) -> Callable[[Request], Awaitable[StreamResponse]]:
- """Execute matched request handler"""
- @property
- @abstractmethod
- def expect_handler(
- self,
- ) -> Callable[[Request], Awaitable[Optional[StreamResponse]]]:
- """Expect handler for 100-continue processing"""
- @property # pragma: no branch
- @abstractmethod
- def http_exception(self) -> Optional[HTTPException]:
- """HTTPException instance raised on router's resolving, or None"""
- @abstractmethod # pragma: no branch
- def get_info(self) -> Dict[str, Any]:
- """Return a dict with additional info useful for introspection"""
- @property # pragma: no branch
- @abstractmethod
- def apps(self) -> Tuple[Application, ...]:
- """Stack of nested applications.
- Top level application is left-most element.
- """
- @abstractmethod
- def add_app(self, app: Application) -> None:
- """Add application to the nested apps stack."""
- @abstractmethod
- def freeze(self) -> None:
- """Freeze the match info.
- The method is called after route resolution.
- After the call .add_app() is forbidden.
- """
- class AbstractView(ABC):
- """Abstract class based view."""
- def __init__(self, request: Request) -> None:
- self._request = request
- @property
- def request(self) -> Request:
- """Request instance."""
- return self._request
- @abstractmethod
- def __await__(self) -> Generator[Any, None, StreamResponse]:
- """Execute the view handler."""
- class ResolveResult(TypedDict):
- """Resolve result.
- This is the result returned from an AbstractResolver's
- resolve method.
- :param hostname: The hostname that was provided.
- :param host: The IP address that was resolved.
- :param port: The port that was resolved.
- :param family: The address family that was resolved.
- :param proto: The protocol that was resolved.
- :param flags: The flags that were resolved.
- """
- hostname: str
- host: str
- port: int
- family: int
- proto: int
- flags: int
- class AbstractResolver(ABC):
- """Abstract DNS resolver."""
- @abstractmethod
- async def resolve(
- self, host: str, port: int = 0, family: socket.AddressFamily = socket.AF_INET
- ) -> List[ResolveResult]:
- """Return IP address for given hostname"""
- @abstractmethod
- async def close(self) -> None:
- """Release resolver"""
- if TYPE_CHECKING:
- IterableBase = Iterable[Morsel[str]]
- else:
- IterableBase = Iterable
- ClearCookiePredicate = Callable[["Morsel[str]"], bool]
- class AbstractCookieJar(Sized, IterableBase):
- """Abstract Cookie Jar."""
- def __init__(self, *, loop: Optional[asyncio.AbstractEventLoop] = None) -> None:
- self._loop = loop or asyncio.get_running_loop()
- @property
- @abstractmethod
- def quote_cookie(self) -> bool:
- """Return True if cookies should be quoted."""
- @abstractmethod
- def clear(self, predicate: Optional[ClearCookiePredicate] = None) -> None:
- """Clear all cookies if no predicate is passed."""
- @abstractmethod
- def clear_domain(self, domain: str) -> None:
- """Clear all cookies for domain and all subdomains."""
- @abstractmethod
- def update_cookies(self, cookies: LooseCookies, response_url: URL = URL()) -> None:
- """Update cookies."""
- @abstractmethod
- def filter_cookies(self, request_url: URL) -> "BaseCookie[str]":
- """Return the jar's cookies filtered by their attributes."""
- class AbstractStreamWriter(ABC):
- """Abstract stream writer."""
- buffer_size: int = 0
- output_size: int = 0
- length: Optional[int] = 0
- @abstractmethod
- async def write(self, chunk: Union[bytes, bytearray, memoryview]) -> None:
- """Write chunk into stream."""
- @abstractmethod
- async def write_eof(self, chunk: bytes = b"") -> None:
- """Write last chunk."""
- @abstractmethod
- async def drain(self) -> None:
- """Flush the write buffer."""
- @abstractmethod
- def enable_compression(
- self, encoding: str = "deflate", strategy: int = zlib.Z_DEFAULT_STRATEGY
- ) -> None:
- """Enable HTTP body compression"""
- @abstractmethod
- def enable_chunking(self) -> None:
- """Enable HTTP chunked mode"""
- @abstractmethod
- async def write_headers(
- self, status_line: str, headers: "CIMultiDict[str]"
- ) -> None:
- """Write HTTP headers"""
- class AbstractAccessLogger(ABC):
- """Abstract writer to access log."""
- __slots__ = ("logger", "log_format")
- def __init__(self, logger: logging.Logger, log_format: str) -> None:
- self.logger = logger
- self.log_format = log_format
- @abstractmethod
- def log(self, request: BaseRequest, response: StreamResponse, time: float) -> None:
- """Emit log to logger."""
- @property
- def enabled(self) -> bool:
- """Check if logger is enabled."""
- return True
|