Server and Client

The hface.server and hface.client modules provide ready-to-use server and client implementations.

The modules are a Python alternative to the command-line interface. They offer a high-level facade to the connection layer.

Both the server and the client are asynchronous. The examples here use asyncio asyncio.run(), but Trio is supported too (thanks to AnyIO).

ASGI server example

hface.server.ASGIServer can run a server with an ASGI application:

import asyncio

from hface.server import ASGIServer, Endpoint
from hface.server.examples.hello import application


async def main():
    server = ASGIServer(application)
    server.tls_config.certfile = "certs/cert.pem"
    server.tls_config.keyfile = "certs/key.pem"
    endpoint = Endpoint("https", "localhost", 5443)
    await server.run([endpoint])


if __name__ == "__main__":
    asyncio.run(main())

(The example should run as it is. It is available in examples/server.py)

Proxy server example

hface.server.ProxyServer can run an HTTP proxy:

import asyncio

from hface.server import Endpoint, ProxyServer


async def main():
    server = ProxyServer()
    server.tls_config.certfile = "certs/cert.pem"
    server.tls_config.keyfile = "certs/key.pem"
    endpoint = Endpoint("https", "localhost", 6443)
    await server.run([endpoint])


if __name__ == "__main__":
    asyncio.run(main())

(The example should run as it is. It is available in examples/proxy_server.py)

HTTP client example

The hface.client.Client can be used to issue an HTTP request:

import asyncio

from hface.client import Client, Request


async def main():
    client = Client()
    client.tls_config.cafile = "certs/cacert.pem"
    async with client.session() as session:
        request = Request("GET", "https://localhost:5443/")
        response = await session.dispatch(request)
    print(response.status)
    print(response.content.decode())


if __name__ == "__main__":
    asyncio.run(main())

(The example should run as it is. It is available in examples/client.py)

Async context manager Client.session() must be entered to get ClientSession. The ClientSession.dispatch() makes HTTP requests.

The use of the context manager ensures that no background tasks are left running (background tasks are needed to maintain HTTP/2 and HTTP/3 connections).

The client has builtin support for HTTP proxies (in the tunneling mode only).

Proxy client example

It may be desired to tunnel non-HTTP traffic through an HTTP proxy. In such cases, it is possible to use directly hface.client.ProxyClient:

import asyncio

from anyio import EndOfStream

from hface.client import ProxyClient


async def main():
    proxy_client = ProxyClient("https://localhost:6443")
    proxy_client.tls_config.cafile = "certs/cacert.pem"
    async with proxy_client.session() as session:
        stream = await session.connect_tcp_tls(("localhost", 5443))
        await stream.send(
            b"GET / HTTP/1.1\r\n"
            b"Host: localhost\r\n"
            b"Connection: close\r\n"
            b"\r\n"
        )
        while True:
            try:
                chunk = await stream.receive()
            except EndOfStream:
                break
            print(chunk.decode(), end="")


if __name__ == "__main__":
    asyncio.run(main())

(The example should run as it is. It is available in examples/proxy_client.py)

Async context manager ProxyClient.session() must be used to get ProxyClientSession. This class implements ClientNetworking, so it can be used to open network connections.

Server API

ASGI server class

class hface.server.ASGIServer(app)

HTTP server with an ASGI application

tls_config: ServerTLSConfig

TLS certificate for the server.

Empty by default, must be configured to listen at https:// endpoints.

protocol: ServerProtocol = 'all'

Protocol or protocols to listen at.

http1_factory: HTTPOverTCPFactory

Sans-IO HTTP/1 implementation

http2_factory: HTTPOverTCPFactory

Sans-IO HTTP/2 implementation

http3_factory: HTTPOverQUICServerFactory

Sans-IO HTTP/3 implementation

await run(endpoints)

Run the server.

Parameters

endpoints (Sequence[Endpoint]) – endpoints to listen at

Proxy server class

class hface.server.ProxyServer
tls_config: ServerTLSConfig

TLS certificate for the server.

Empty by default, must be configured to listen at https:// endpoints.

protocol: ServerProtocol = 'all'

Protocol or protocols to listen at.

http1_factory: HTTPOverTCPFactory

Sans-IO HTTP/1 implementation

http2_factory: HTTPOverTCPFactory

Sans-IO HTTP/2 implementation

http3_factory: HTTPOverQUICServerFactory

Sans-IO HTTP/3 implementation

await run(endpoints)

Run the server.

Parameters

endpoints (Sequence[Endpoint]) – endpoints to listen at

Server models

class hface.server.Endpoint(scheme, host, port)

An endpoing where a server can listen.

scheme: str

Either "http" or "https".

host: str

A hostname or an IP address

port: int

A port number

classmethod parse(value)

Parse an endpoint from a string.

Parameters

value (str) – string value

Returns

a new instance

Return type

Endpoint

property tls: bool

Whether to use TLS

property address: Tuple[str, int]

A tuple with a host and a port

class hface.server.ServerProtocol(value)

Specifies for what connections a server should listen.

ALL = 'all'

Listen for all HTTP versions.

TCP = 'tcp'

Listen for HTTP/1 and HTTP/2 connections.

HTTP1 = 'http1'

Listen for HTTP/1 connections only.

HTTP2 = 'http2'

Listen for HTTP/2 connections only.

HTTP3 = 'http3'

Listen for HTTP/3 connections only.

Client API

Client class

class hface.client.Client

An HTTP client

Supports HTTP/1, HTTP/2, and HTTP/3. Optionally tunnels traffic through an HTTP proxy.

Client instances have no state. The Client.session() method must be used to open ClientSession to make HTTP requests.

tls_config: ClientTLSConfig

TLS configuration for the client.

protocol: ClientProtocol = 'tcp'

A protocol used to open connections.

proxy_origin: Origin | None = None

A proxy server

proxy_protocol: ClientProtocol = 'tcp'

A protocol used to open connections to the proxy server (if set)

http1_factory: HTTPOverTCPFactory

Sans-IO HTTP/1 implementation

http2_factory: HTTPOverTCPFactory

Sans-IO HTTP/2 implementation

http3_factory: HTTPOverQUICClientFactory

Sans-IO HTTP/3 implementation

async with session()

Start a new client session.

Return type

ClientSession

class hface.client.ClientSession(*, http_opener, task_group)

Active client session that can be used to issue HTTP requests.

Maintains a pool of HTTP connections that can be used to dispatch() request.

Use a Client to create instances of this class.

Parameters
  • http_opener (HTTPOpener) – Defines how to open new connections.

  • task_group (TaskGroup) – AnyIO task group for maintaining HTTP connections.

await aclose()

Close all connections.

await dispatch(request)

Perform an HTTP request and return an HTTP response.

Parameters

request (Request) – an HTTP request

Returns

an HTTP response

Return type

Response

Proxy class

class hface.client.ProxyClient(origin)

A client that tunnels traffic through HTTP proxies

This client sends CONNECT requests to an HTTP proxy to establish tunnels. The established tunnels can be used to transfer any TCP traffic, it is not limited to HTTP.

Supports HTTP/1, HTTP/2, and HTTP/3 proxies in the tunneling mode.

Instances of this class have no state, the session() must be used to establish ProxyClientSession.

Parameters

origin (Origin) – Proxy server to use

tls_config: ClientTLSConfig

TLS configuration for the client.

protocol: ClientProtocol = 'tcp'

A protocol used to open connections.

http1_factory: HTTPOverTCPFactory

Sans-IO HTTP/1 implementation

http2_factory: HTTPOverTCPFactory

Sans-IO HTTP/2 implementation

http3_factory: HTTPOverQUICClientFactory

Sans-IO HTTP/3 implementation

async with session()

Establish a new session with the proxy.

Return type

ProxyClientSession

class hface.client.ProxyClientSession(origin, *, http_opener, task_group)

An active session with an HTTP proxy.

Maintains pool of connections to the proxy (for HTTP/2 and HTTP/3 proxies the pool will not have more than one connection).

This class implements ClientNetworking, so it can be used to open new HTTP connections.

Use a ProxyClient to create instances of this class.

Parameters
  • origin (Origin) – Proxy server

  • http_opener (HTTPOpener) – Defines how to open new connections.

  • task_group (anyio.abc.TaskGroup) – AnyIO task group for maintaining HTTP connections.

await aclose()

Close all connections.

await connect_tcp(address)

Create a TCP-like stream connected to the given address.

Return type

ByteStream

Client models

class hface.client.Request(method, url, *, headers=None, content=None)

HTTP request

Parameters
  • method (str) – HTTP method

  • url (URL) – URL (either a string or an isntance)

  • headers (Sequence[Tuple[bytes, bytes]]) – HTTP headers (will be normalized to lowecase)

  • content (bytes) – Request body to send

method: str

HTTP method

url: URL

URL

headers: Sequence[Tuple[bytes, bytes]]

HTTP headers

content: bytes

Request body to send

property protocol_headers: Sequence[Tuple[bytes, bytes]]

HTTP headers including the pseudo one.

property pseudo_headers: Sequence[Tuple[bytes, bytes]]

Pseudo headers (":method", ":scheme", ":authority", ":path")

classmethod from_headers(protocol_headers)

Construct a new instance from headers (including pseudo headers).

Parameters

protocol_headers (Sequence[Tuple[bytes, bytes]]) – HTTP headers

Returns

a new instance

Return type

Request

class hface.client.Response(status=200, *, headers=None, content=b'')

HTTP response

Parameters
  • status (int) – HTTP status

  • headers (Sequence[Tuple[bytes, bytes]]) – HTTP headers

  • content (bytes) – Received HTTP body

status: int

HTTP status

headers: Sequence[Tuple[bytes, bytes]]

HTTP headers

content: bytes

Received HTTP body

property protocol_headers: Sequence[Tuple[bytes, bytes]]

HTTP headers including the pseudo one.

property pseudo_headers: Sequence[Tuple[bytes, bytes]]

Pseudo headers (":status")

classmethod from_headers(protocol_headers)

Construct a new instance from headers (including pseudo headers).

Parameters

protocol_headers (Sequence[Tuple[bytes, bytes]]) – HTTP headers

Returns

a new instance

Return type

Response

class hface.client.ClientProtocol(value)

Specifies for how to open connections to the server.

TCP = 'tcp'

Open TCP connections, use ALPN to choose beteween HTTP/1 and HTTP/2

HTTP1 = 'http1'

Open HTTP/1 connections

HTTP2 = 'http2'

Open HTTP/2 connections

HTTP3 = 'http3'

Open HTTP/3 connections. Use QUIC instead of TCP.

class hface.client.URL(scheme, host, port, path='/')
scheme: str

Either "http" or "https".

host: str

A hostname or an IP address

port: int

A port number

path: str

Path compoment

classmethod parse(value, default_scheme='http')

Parse an URL from a string.

Parameters
  • value (str) – string value

  • default_scheme (str) – default scheme

Returns

a new instance

Return type

URL

property origin: Origin

HTTP server referenced by this URL.

property authority: str

Authority part of this URL (host + port if non-default)

class hface.client.Origin(scheme, host, port)

HTTP origin server.

scheme: str

Either "http" or "https".

host: str

A hostname or an IP address

port: int

A port number

classmethod parse(value, *, default_scheme='http')

Parse an origin from a string.

Parameters
  • value (str) – string value

  • default_scheme (str) – default scheme

Returns

a new instance

Return type

Origin

property tls: bool

Whether to use TLS

property address: Tuple[str, int]

A tuple with a host and a port