Skip to content

Repository files navigation

SmallServer

SmallServer is a small, SmallOS-native HTTP framework for Python 3.10+. It serves bounded HTTP/1.1 requests and optional cleartext prior-knowledge HTTP/2, supports exact and timeout-bounded regex routes, optional RFC 6455 WebSockets, and provides explicit lifecycle and third-party execution controls.

from smallserver import Response, SmallServer

app = SmallServer()


@app.get("/health")
async def health(request):
    return Response.json({"status": "ok"})


if __name__ == "__main__":
    app.listen(host="127.0.0.1", port=8000)

Install the pinned SmallOS v1.2.0 release, the package, and test tools:

python3 -m pip install -r requirements.txt
python3 -m pip install -e '.[test]'
python3 demo.py

Application code can use blocking app.listen() without importing SmallOS. Advanced applications can supply their own runtime, schedule the server without starting it, and own execution adapters for blocking or asyncio-native libraries.

Optional protocol and routing extras

HTTP/2 uses the bounded hyper-h2 4.x integration:

python3 -m pip install -e '.[http2]'

Select protocol="http2" on listen() or serve(). The implementation supports cleartext prior knowledge, multiplexed stream handlers, bounded flow control, and GOAWAY. HTTP/2 TLS/ALPN remains deferred until SmallOS exposes a server-side TLS kernel capability.

Timeout-bounded regex routes require the optional matching engine:

python3 -m pip install -e '.[regex-routes]'

Static lookup remains dependency-free and takes precedence over regex routes. Regex routes use full-path matching, run in registration order, and expose only named captures through immutable request.path_params:

@app.get_regex(r"/users/(?P<user_id>[0-9]+)")
async def get_user(request):
    return Response.json({"user_id": request.path_params["user_id"]})

Pattern, path, capture, and matching-time limits are configurable with RegexRouteConfig. On HTTP/1.1 and HTTP/2 listeners, a match timeout becomes a sanitized 500 response; direct dispatch() raises RouteMatchTimeout. An optional network-listener route_error_observer receives only an immutable RouteErrorEvent with an opaque route ID and category; it never receives the request target, headers, body, traceback, or exception graph.

WebSockets use the optional wsproto integration:

python3 -m pip install -e '.[websocket]'

WebSocket Upgrade routes use a separate static route table, so an ordinary GET and a WebSocket route can coexist at one path:

from smallserver import WebSocket


@app.websocket("/echo", origins={"https://app.example.com"})
async def echo(websocket: WebSocket) -> None:
    await websocket.accept()
    async for message in websocket:
        if message.is_text:
            await websocket.send_text(message.text)
        else:
            await websocket.send_bytes(message.bytes)

Configure the managed SmallOS runtime

When listen() creates the runtime, ServerConfig.managed_runtime passes the relevant scheduler and client defaults into SmallOS before the listener binds:

from smallserver import ManagedRuntimeConfig, ServerConfig

config = ServerConfig(
    max_connections=200,
    managed_runtime=ManagedRuntimeConfig(
        task_capacity=512,
        priority_levels=8,
        io_buffer_length=2048,
        eternal_watchers=False,
        client_defaults={
            "http": {"max_response_size": 8 * 1024 * 1024},
        },
    ),
)

app.listen(host="127.0.0.1", port=8000, config=config)

This bridge is only for SmallServer-owned runtimes. If you supply runtime=, configure it directly with SmallOS(config=...); SmallServer rejects managed_runtime rather than mutating caller-owned scheduler state. For HTTP/1.1, task_capacity must reserve at least max_connections + 2 task slots for the listener and shutdown-control tasks, and both server task priorities must be below priority_levels. Configuring a regex route-error observer adds one dedicated SmallOS task, so that mode requires at least max_connections + 3 slots. HTTP/2 needs additional headroom for its bounded connection-control and stream-handler tasks.

Current boundaries

HTTP/1.1 serves one request per connection. Keep-alive, pipelining, TLS, automatic path templates, WebSocket compression, RFC 8441 WebSockets over HTTP/2, HTTP/1.1 h2c upgrade, and automatic protocol detection are not implemented. Regex routes are an explicit optional route form, not automatic path templates.

Documentation

See demo.py for all five supported HTTP methods and a WebSocket route, examples/http2_prior_knowledge.py for HTTP/2, examples/manual_runtime.py for caller-owned SmallOS startup, examples/websocket_echo.py for bounded WebSocket echo handling, and examples/adapters_demo.py for blocking and asyncio escape hatches.

Releases

Release pull requests merge from develop into main with a new project.version. Successful CI on that exact main commit creates a tagged GitHub release containing checked wheel and source archives. See RELEASING.md for the complete process and the current reason PyPI publication remains disabled.

SmallServer is early-stage software. Review the documented limits and lifecycle contract before deploying it outside controlled environments.

About

Web Framework Using the SmallOS runtime

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages