diff --git a/httptools/parser/__init__.py b/httptools/parser/__init__.py index ba371f5..1d8df43 100644 --- a/httptools/parser/__init__.py +++ b/httptools/parser/__init__.py @@ -1,3 +1,4 @@ +from .protocol import HTTPProtocol from .parser import * # NoQA from .errors import * # NoQA from .url_parser import * # NoQA diff --git a/httptools/parser/parser.pyi b/httptools/parser/parser.pyi new file mode 100644 index 0000000..8a714bf --- /dev/null +++ b/httptools/parser/parser.pyi @@ -0,0 +1,57 @@ +from typing import Union, Any +from array import array +from .protocol import HTTPProtocol + +class HttpParser: + def __init__(self, protocol: Union[HTTPProtocol, Any]) -> None: + """ + protocol -- a Python object with the following methods + (all optional): + + - on_message_begin() + - on_url(url: bytes) + - on_header(name: bytes, value: bytes) + - on_headers_complete() + - on_body(body: bytes) + - on_message_complete() + - on_chunk_header() + - on_chunk_complete() + - on_status(status: bytes) + """ + + def get_http_version(self) -> str: + """Return an HTTP protocol version.""" + ... + + def should_keep_alive(self) -> bool: + """Return ``True`` if keep-alive mode is preferred.""" + ... + + def should_upgrade(self) -> bool: + """Return ``True`` if the parsed request is a valid Upgrade request. + The method exposes a flag set just before on_headers_complete. + Calling this method earlier will only yield `False`.""" + ... + + def feed_data(self, data: Union[bytes, bytearray, memoryview, array]) -> None: + """Feed data to the parser. + + Will eventually trigger callbacks on the ``protocol`` + object. + + On HTTP upgrade, this method will raise an + ``HttpParserUpgrade`` exception, with its sole argument + set to the offset of the non-HTTP data in ``data``. + """ + +class HttpRequestParser(HttpParser): + """Used for parsing http requests from the server's side""" + + def get_method(self) -> bytes: + """Return HTTP request method (GET, HEAD, etc)""" + +class HttpResponseParser(HttpParser): + """Used for parsing http requests from the client's side""" + + def get_status_code(self) -> int: + """Return the status code of the HTTP response""" diff --git a/httptools/parser/protocol.py b/httptools/parser/protocol.py new file mode 100644 index 0000000..c3b4234 --- /dev/null +++ b/httptools/parser/protocol.py @@ -0,0 +1,15 @@ +from typing import Protocol + + +class HTTPProtocol(Protocol): + """Used for providing static type-checking when parsing through the http protocol""" + + def on_message_begin() -> None: ... + def on_url(url: bytes) -> None: ... + def on_header(name: bytes, value: bytes) -> None: ... + def on_headers_complete() -> None: ... + def on_body(body: bytes) -> None: ... + def on_message_complete() -> None: ... + def on_chunk_header() -> None: ... + def on_chunk_complete() -> None: ... + def on_status(status: bytes) -> None: ... diff --git a/httptools/parser/url_parser.pyi b/httptools/parser/url_parser.pyi new file mode 100644 index 0000000..f3d3488 --- /dev/null +++ b/httptools/parser/url_parser.pyi @@ -0,0 +1,27 @@ +from typing import Union +from array import array + +class URL: + schema: bytes + host: bytes + port: int + path: bytes + query: bytes + fragment: bytes + userinfo: bytes + +def parse_url(url: Union[bytes, bytearray, memoryview, array]) -> URL: + """Parse URL strings into a structured Python object. + + Returns an instance of ``httptools.URL`` class with the + following attributes: + + - schema: bytes + - host: bytes + - port: int + - path: bytes + - query: bytes + - fragment: bytes + - userinfo: bytes + """ + ...