chumicro-http-server-experimental 0.18.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (29) hide show
  1. chumicro_http_server_experimental-0.18.0/.gitignore +99 -0
  2. chumicro_http_server_experimental-0.18.0/PKG-INFO +187 -0
  3. chumicro_http_server_experimental-0.18.0/README.md +155 -0
  4. chumicro_http_server_experimental-0.18.0/VERSION +1 -0
  5. chumicro_http_server_experimental-0.18.0/docs/api.md +25 -0
  6. chumicro_http_server_experimental-0.18.0/docs/guide.md +307 -0
  7. chumicro_http_server_experimental-0.18.0/docs/img/favicon.png +0 -0
  8. chumicro_http_server_experimental-0.18.0/docs/index.md +50 -0
  9. chumicro_http_server_experimental-0.18.0/docs/stylesheets/extra.css +151 -0
  10. chumicro_http_server_experimental-0.18.0/examples/_generated/example_runtime_config_http_server_simple_server.msgpack +1 -0
  11. chumicro_http_server_experimental-0.18.0/examples/helpers.py +340 -0
  12. chumicro_http_server_experimental-0.18.0/examples/simple_server.py +110 -0
  13. chumicro_http_server_experimental-0.18.0/pyproject.toml +89 -0
  14. chumicro_http_server_experimental-0.18.0/src/chumicro_http_server/__init__.py +87 -0
  15. chumicro_http_server_experimental-0.18.0/src/chumicro_http_server/_wire.py +811 -0
  16. chumicro_http_server_experimental-0.18.0/src/chumicro_http_server/server.py +1166 -0
  17. chumicro_http_server_experimental-0.18.0/src/chumicro_http_server/sockets_factory.py +53 -0
  18. chumicro_http_server_experimental-0.18.0/src/chumicro_http_server/streaming.py +461 -0
  19. chumicro_http_server_experimental-0.18.0/src/chumicro_http_server/testing.py +71 -0
  20. chumicro_http_server_experimental-0.18.0/tests/conftest.py +1 -0
  21. chumicro_http_server_experimental-0.18.0/tests/test_http_caseinsensitive_dict.py +105 -0
  22. chumicro_http_server_experimental-0.18.0/tests/test_http_from_config.py +255 -0
  23. chumicro_http_server_experimental-0.18.0/tests/test_http_server_e2e.py +399 -0
  24. chumicro_http_server_experimental-0.18.0/tests/test_http_server_misc.py +259 -0
  25. chumicro_http_server_experimental-0.18.0/tests/test_http_server_request_routing.py +380 -0
  26. chumicro_http_server_experimental-0.18.0/tests/test_http_streaming_e2e.py +426 -0
  27. chumicro_http_server_experimental-0.18.0/tests/test_http_streaming_wire.py +268 -0
  28. chumicro_http_server_experimental-0.18.0/tests/test_http_wire_parse.py +327 -0
  29. chumicro_http_server_experimental-0.18.0/tests/test_http_wire_response.py +202 -0
@@ -0,0 +1,99 @@
1
+ .DS_Store
2
+ .idea/*
3
+ !.idea/modules.xml
4
+ !.idea/chumicro.iml
5
+ !.idea/runConfigurations/
6
+ !.idea/inspectionProfiles/
7
+ .venv/
8
+ .tools/
9
+ __pycache__/
10
+ *.py[cod]
11
+ .pytest_cache/
12
+ .ruff_cache/
13
+ .coverage
14
+ coverage.xml
15
+ htmlcov/
16
+ build/
17
+ dist/
18
+ site/
19
+ .site/
20
+ *.egg-info/
21
+
22
+ # Generated by docs build from support/docs/ and zensical
23
+ libraries/*/docs/stylesheets/
24
+ libraries/*/docs/img/
25
+ libraries/*/docs/assets/
26
+ workbench/*/docs/stylesheets/
27
+ workbench/*/docs/img/
28
+ workbench/*/docs/assets/
29
+
30
+ .mypy_cache/
31
+ .scratch/
32
+
33
+ # Generated runtime-config msgpack from `chumicro-workspace deploy-example`
34
+ # — the `_generated/` build-artifact convention, never committed beside
35
+ # the tracked example source.
36
+ libraries/*/examples/_generated/
37
+
38
+ # Pre-upgrade backups of edited curated library trees, written by
39
+ # `chumicro-workspace library update` before it replaces a tree —
40
+ # tool-managed, never committed; recover local edits from here.
41
+ _library-backups/
42
+
43
+ # Agent-tooling scratch dir (worktrees, per-user settings). Track only:
44
+ # * the `skills` symlink so Claude Code auto-discovers the canonical skills
45
+ # tree at `.github/skills/` from the location it expects (`.claude/skills/`).
46
+ # * `settings.json` — team-shared agent permissions for chumicro dev tooling
47
+ # (chumicro-workspace / chumicro-deploy / chumicro-repl). `.local.json`
48
+ # stays ignored for per-user overrides.
49
+ .claude/*
50
+ !.claude/agents
51
+ !.claude/skills
52
+ !.claude/settings.json
53
+
54
+ # .agents/ — install tree the add-skill tool writes when pulling downloaded
55
+ # marketplace skills from `skills-lock.json`. The canonical, tracked copy of
56
+ # every downloaded skill lives under `.github/skills/`; this is a redundant
57
+ # per-checkout install tree, so track the manifest plus `.github/skills/` and
58
+ # ignore this duplicate.
59
+ .agents/
60
+
61
+ devices.yml
62
+
63
+ # Legacy: chumicro-dev-config.toml. Retired in Phase 4 of the unification
64
+ # workstream — networking-library functional-test conftests now read from
65
+ # workspace.yml via `chumicro_workspace.compose_runtime_config`. Kept
66
+ # gitignored for one cycle so contributors with a left-over copy from the
67
+ # pre-Phase-4 era don't accidentally commit it.
68
+ chumicro-dev-config.toml
69
+
70
+ # workspace.yml — workspace machinery (library_sources, deploy_targets,
71
+ # quality, environments). Materialised by ``python scripts/run.py setup``
72
+ # from `_workspace_template/workspace.yml` (this repo's specific opinions
73
+ # — tracked, ships as the starter) or chumicro-workspace's workbench-owned
74
+ # starter. Gitignored so the auto-populated ``library_sources:`` block
75
+ # (paths into a sibling chumicro/ checkout) doesn't reach git. Root-
76
+ # anchored so `_workspace_template/workspace.yml` stays trackable.
77
+ /workspace.yml
78
+
79
+ # secrets.toml — workspace-wide credentials + device defaults that flow
80
+ # into runtime_config.msgpack at deploy time. Materialised on first
81
+ # ``setup`` from `_workspace_template/secrets.toml` (this repo's specific
82
+ # opinions — tracked, ships as the starter) or the workbench-owned
83
+ # starter. Never committed — contains real wifi passwords / broker auth.
84
+ # Root-anchored so `_workspace_template/secrets.toml` stays trackable.
85
+ /secrets.toml
86
+
87
+ # .envrc — direnv hook for per-checkout shell setup (e.g. auto-sourcing
88
+ # the venv on cd). Per-user / per-machine; not part of the canonical
89
+ # workflow.
90
+ .envrc
91
+
92
+ # Firmware blobs. `chumicro-deploy flash-firmware` and friends default
93
+ # to `./firmware.bin` for the downloaded image; the file is build /
94
+ # board artifact, not source. Use `.scratch/` for one-off testing or
95
+ # pass an explicit destination to keep blobs out of the working tree.
96
+ /firmware.bin
97
+ firmware-*.bin
98
+ *.uf2
99
+
@@ -0,0 +1,187 @@
1
+ Metadata-Version: 2.4
2
+ Name: chumicro-http-server-experimental
3
+ Version: 0.18.0
4
+ Summary: Non-blocking HTTP/1.1 server for CircuitPython, MicroPython, and CPython.
5
+ Project-URL: Homepage, https://github.com/ChuMicro/ChuMicro
6
+ Project-URL: Documentation, https://chumicro.github.io/ChuMicro/http_server/experimental/
7
+ Project-URL: Source, https://github.com/ChuMicro/ChuMicro/tree/main/libraries/http_server
8
+ Project-URL: Issues, https://github.com/ChuMicro/ChuMicro/issues
9
+ Project-URL: Bundle, https://github.com/ChuMicro/ChuMicro-Bundle-Experimental
10
+ Author: ChuMicro
11
+ License-Expression: MIT
12
+ Keywords: circuitpython,embedded,esp32,http,microcontroller,micropython,rp2040
13
+ Classifier: Development Status :: 2 - Pre-Alpha
14
+ Classifier: Intended Audience :: Developers
15
+ Classifier: Operating System :: OS Independent
16
+ Classifier: Programming Language :: Python :: 3
17
+ Classifier: Programming Language :: Python :: 3 :: Only
18
+ Classifier: Topic :: Software Development :: Embedded Systems
19
+ Classifier: Topic :: System :: Hardware
20
+ Requires-Python: >=3.11
21
+ Requires-Dist: chumicro-config-experimental
22
+ Requires-Dist: chumicro-sockets-experimental
23
+ Requires-Dist: chumicro-timing-experimental
24
+ Provides-Extra: test
25
+ Requires-Dist: chumicro-pytest-device; extra == 'test'
26
+ Requires-Dist: chumicro-requests; extra == 'test'
27
+ Requires-Dist: chumicro-test-harness; extra == 'test'
28
+ Requires-Dist: chumicro-wifi; extra == 'test'
29
+ Requires-Dist: chumicro-workspace; extra == 'test'
30
+ Requires-Dist: pytest; extra == 'test'
31
+ Description-Content-Type: text/markdown
32
+
33
+ # chumicro-http-server
34
+
35
+ <img src="https://raw.githubusercontent.com/ChuMicro/ChuMicro/main/support/docs/chumicro_tip.png"
36
+ align="left" width="64" style="margin-right: 16px; margin-bottom: 8px;">
37
+
38
+ **A non-blocking HTTP/1.1 server with `@route` — serve requests while your LED keeps blinking.**
39
+
40
+ Routing with `@server.route` (method dispatch, path parameters), bounded multi-connection, per-tick byte budgets, and a streaming request parser — all without blocking your main loop. Serves TLS on every supported board pair except CircuitPython on RP2040 (CYW43 substrate limitation; documented inline). Self-contained — no `chumicro-requests` dependency on the device.
41
+
42
+ <br clear="left">
43
+
44
+ > Part of the [ChuMicro](https://github.com/ChuMicro/ChuMicro) family — small, focused Python libraries for microcontrollers and laptops. [Browse all libraries.](https://github.com/ChuMicro/ChuMicro/tree/main/libraries)
45
+
46
+ ## Install
47
+
48
+ ```bash
49
+ # CircuitPython (after `circup bundle-add ChuMicro/ChuMicro-Bundle`)
50
+ circup install chumicro-http-server
51
+
52
+ # MicroPython
53
+ mpremote mip install github:ChuMicro/ChuMicro-Bundle/chumicro_http_server
54
+
55
+ # CPython
56
+ pip install chumicro-http-server
57
+ ```
58
+
59
+ For bundle setup, pre-compiled `.mpy` bundles, the experimental channel, and details on PyPI naming, see the [chumicro INSTALL guide](https://github.com/ChuMicro/ChuMicro/blob/main/INSTALL.md).
60
+
61
+ ## Quick example
62
+
63
+ ```python
64
+ from chumicro_http_server import HttpServer, build_response
65
+ from chumicro_sockets import listener
66
+ from chumicro_timing import ticks_ms
67
+
68
+ server = HttpServer(
69
+ transport_factory=lambda: listener(host="0.0.0.0", port=8080),
70
+ )
71
+
72
+ @server.route("/")
73
+ def index(request):
74
+ return build_response(200, html="<h1>Hello from a Pi Pico W</h1>")
75
+
76
+ @server.route("/sensor", methods=["POST"])
77
+ def sensor(request):
78
+ payload = request.json()
79
+ return build_response(201, json={"ok": True})
80
+
81
+ @server.route("/widgets/<id>")
82
+ def widget(request):
83
+ return build_response(200, json={"id": request.path_params["id"]})
84
+
85
+ while True:
86
+ if server.check(ticks_ms()):
87
+ server.handle(ticks_ms())
88
+ ```
89
+
90
+ ## What's included
91
+
92
+ | Symbol | Purpose |
93
+ |---|---|
94
+ | `HttpServer` | Runner-shaped HTTP/1.1 server; `check(now_ms)` / `handle(now_ms)`. |
95
+ | `Request` | Per-request value object: `method`, `path`, `query`, `headers`, `body`, `json()`, `text()`. |
96
+ | `Response` | Outbound response: `status_code`, `reason`, `headers`, `body`. |
97
+ | `build_response(status, *, body, json, text, html, headers)` | Convenience builder with sensible Content-Type defaults. |
98
+ | `streaming.build_streaming_response(status, *, source, content_length, headers)` | Opt-in `chumicro_http_server.streaming` submodule — serve a body larger than the heap from a fill-a-buffer `source(buffer) -> int` (Content-Length or chunked framing, fixed staging window). |
99
+ | `RequestParser` | Streaming request parser (request line + headers + Content-Length body). |
100
+ | `parse_query` / `split_target` | URL helpers. |
101
+ | `ServerError` + subclasses | Typed exception hierarchy, independent of `chumicro_requests` so the server can ship without the client library. |
102
+
103
+ Each request is served on a fresh accepted socket and `Connection: close` is added to every response — HTTP/1.1 keep-alive and connection pooling are not supported. Chunked request bodies are not supported either; use `Content-Length`.
104
+
105
+ Need to return a body bigger than the heap — a log dump, a file, a long export? Return a **streaming response** from the opt-in `chumicro_http_server.streaming` submodule and the server drains it from a fill-a-buffer source one small window at a time, choosing Content-Length or chunked framing for you:
106
+
107
+ ```python
108
+ from chumicro_http_server.streaming import build_streaming_response, SOURCE_EOF
109
+
110
+ @server.route("/log")
111
+ def log_dump(request):
112
+ def source(buffer):
113
+ n = read_next_block_into(buffer) # your storage read; 0 <= n <= len(buffer)
114
+ return n if n else SOURCE_EOF # -1 signals end of body
115
+ return build_streaming_response(200, source=source)
116
+ ```
117
+
118
+ See the [user guide](https://chumicro.github.io/ChuMicro/http_server/stable/guide/#streaming-large-response-bodies) for the source contract, framing rules, fairness, and staging-window sizing.
119
+
120
+ ## Where this fits
121
+
122
+ Depends on [`chumicro-sockets`](../sockets/) (TCP listener) and [`chumicro-timing`](../timing/) (ticks). Pairs with [`chumicro-websockets`](../websockets/) for combined HTTP + WS deployments. Self-contained otherwise — the shared HTTP/1.1 primitives (case-insensitive header dict, charset parsing) are inlined locally, so a server-only board never ships [`chumicro-requests`](../requests/).
123
+
124
+ ## Platform support
125
+
126
+ Works on CPython, MicroPython, and CircuitPython. Pure Python — no native extensions.
127
+
128
+ ### TLS server (HTTPS)
129
+
130
+ `chumicro-http-server` itself is transport-agnostic — pass a TLS-wrapped
131
+ listener from
132
+ [`chumicro_sockets.ssl_context_with_cert_and_key_paths`](https://github.com/ChuMicro/ChuMicro/tree/main/libraries/sockets)
133
+ into `transport_factory` and the same `HttpServer` runs HTTPS. Live
134
+ verification across the supported board matrix:
135
+
136
+ | Runtime + board | TLS server status | Notes |
137
+ |---|---|---|
138
+ | CircuitPython on ESP32-S2 (Lolin S2) | ✅ Works | Bench-tested ~5 KB context (RSA-2048); each connection adds tens of KB during handshake — leave headroom. |
139
+ | CircuitPython on rp2 (Pi Pico W / Pi Pico 2 W) | ❌ Refused (`UnsupportedSSLConfigError`) | `chumicro_sockets.listener(tls=True)` raises up-front; the underlying CYW43 TLS path raises `OSError(32)` mid-handshake AND wedges the chip's station-mode state. Use ESP32-family or MicroPython on rp2. |
140
+ | MicroPython on ESP32-S2 | ✅ Works | Hardware-accelerated handshake; ~1 KB heap. |
141
+ | MicroPython on rp2 (Pi Pico W) | ✅ Works (RSA-2048 only) | DER-encoded key; ~25 KB handshake heap; ECC keys fail at context build. |
142
+
143
+ > **Why the CP-on-rp2 row?** The CYW43 stack's TLS server path raises `OSError(32)` mid-handshake and wedges the chip's station state until a USB power-cycle. No upstream fix is in flight; for HTTPS server work on rp2, use MicroPython.
144
+
145
+ The TLS handshake is synchronous inside `wrap_socket(..., server_side=True)`:
146
+ the listener stalls until it completes — single-digit to tens of
147
+ milliseconds on the supported board class with a local TLS client, longer
148
+ on a slow uplink as TLS rounds-trip. Once the handshake completes, the
149
+ per-connection state machine resumes its runner-shaped,
150
+ LED-blink-friendly progression.
151
+
152
+ ## Examples
153
+
154
+ | Example | What it shows |
155
+ |---|---|
156
+ | `simple_server.py` | Single-board HTTP server with `GET /`, `GET /api/uptime`, `POST /api/echo` routes. Drive it with `curl` from your laptop. Cross-runtime (CP + MP) — runtime marker on the file gates hardware-only deploys. For a two-physical-board demo see the workspace template's `two_board_handshake/` example. |
157
+
158
+ ## Wiring wifi credentials for examples and functional tests
159
+
160
+ The hardware-prefixed examples + real-network suites in `functional_tests/test_real_*.py` need wifi credentials. See [`docs/wiring-wifi-credentials.md`](https://github.com/ChuMicro/ChuMicro/blob/main/docs/wiring-wifi-credentials.md) for the workspace-based and raw single-file paths. The library itself never reads TOML — it takes a `transport_factory` and goes; config wiring is application-layer.
161
+
162
+ ## Contributing
163
+
164
+ Working on `chumicro-http-server` itself? Clone the [mono-repo](https://github.com/ChuMicro/ChuMicro) if you haven't already — the rest of the workflow assumes you're inside that workspace.
165
+
166
+ ```bash
167
+ pip install -e .[test]
168
+ pytest tests/ # host-side tests
169
+ pytest functional_tests/ # on-device tests (needs a board registered in devices.yml)
170
+ ```
171
+
172
+ Register a board before running functional tests: `chumicro-workspace add-device <id> --address <port>`.
173
+
174
+ ## Docs
175
+
176
+ 📖 **[Stable docs](https://chumicro.github.io/ChuMicro/http-server/stable/)** · **[Experimental docs](https://chumicro.github.io/ChuMicro/http-server/experimental/)**
177
+
178
+ ## Find this library
179
+
180
+ - **PyPI:** [chumicro-http-server](https://pypi.org/project/chumicro-http-server/)
181
+ - **Bundle:** [ChuMicro-Bundle](https://github.com/ChuMicro/ChuMicro-Bundle/tree/main/chumicro_http_server) (CircuitPython & MicroPython)
182
+ - **Experimental bundle:** [ChuMicro-Bundle-Experimental](https://github.com/ChuMicro/ChuMicro-Bundle-Experimental/tree/main/chumicro_http_server)
183
+ - **Source:** [libraries/http_server](https://github.com/ChuMicro/ChuMicro/tree/main/libraries/http_server)
184
+
185
+ ## License
186
+
187
+ [MIT](https://github.com/ChuMicro/ChuMicro/blob/main/LICENSE)
@@ -0,0 +1,155 @@
1
+ # chumicro-http-server
2
+
3
+ <img src="https://raw.githubusercontent.com/ChuMicro/ChuMicro/main/support/docs/chumicro_tip.png"
4
+ align="left" width="64" style="margin-right: 16px; margin-bottom: 8px;">
5
+
6
+ **A non-blocking HTTP/1.1 server with `@route` — serve requests while your LED keeps blinking.**
7
+
8
+ Routing with `@server.route` (method dispatch, path parameters), bounded multi-connection, per-tick byte budgets, and a streaming request parser — all without blocking your main loop. Serves TLS on every supported board pair except CircuitPython on RP2040 (CYW43 substrate limitation; documented inline). Self-contained — no `chumicro-requests` dependency on the device.
9
+
10
+ <br clear="left">
11
+
12
+ > Part of the [ChuMicro](https://github.com/ChuMicro/ChuMicro) family — small, focused Python libraries for microcontrollers and laptops. [Browse all libraries.](https://github.com/ChuMicro/ChuMicro/tree/main/libraries)
13
+
14
+ ## Install
15
+
16
+ ```bash
17
+ # CircuitPython (after `circup bundle-add ChuMicro/ChuMicro-Bundle`)
18
+ circup install chumicro-http-server
19
+
20
+ # MicroPython
21
+ mpremote mip install github:ChuMicro/ChuMicro-Bundle/chumicro_http_server
22
+
23
+ # CPython
24
+ pip install chumicro-http-server
25
+ ```
26
+
27
+ For bundle setup, pre-compiled `.mpy` bundles, the experimental channel, and details on PyPI naming, see the [chumicro INSTALL guide](https://github.com/ChuMicro/ChuMicro/blob/main/INSTALL.md).
28
+
29
+ ## Quick example
30
+
31
+ ```python
32
+ from chumicro_http_server import HttpServer, build_response
33
+ from chumicro_sockets import listener
34
+ from chumicro_timing import ticks_ms
35
+
36
+ server = HttpServer(
37
+ transport_factory=lambda: listener(host="0.0.0.0", port=8080),
38
+ )
39
+
40
+ @server.route("/")
41
+ def index(request):
42
+ return build_response(200, html="<h1>Hello from a Pi Pico W</h1>")
43
+
44
+ @server.route("/sensor", methods=["POST"])
45
+ def sensor(request):
46
+ payload = request.json()
47
+ return build_response(201, json={"ok": True})
48
+
49
+ @server.route("/widgets/<id>")
50
+ def widget(request):
51
+ return build_response(200, json={"id": request.path_params["id"]})
52
+
53
+ while True:
54
+ if server.check(ticks_ms()):
55
+ server.handle(ticks_ms())
56
+ ```
57
+
58
+ ## What's included
59
+
60
+ | Symbol | Purpose |
61
+ |---|---|
62
+ | `HttpServer` | Runner-shaped HTTP/1.1 server; `check(now_ms)` / `handle(now_ms)`. |
63
+ | `Request` | Per-request value object: `method`, `path`, `query`, `headers`, `body`, `json()`, `text()`. |
64
+ | `Response` | Outbound response: `status_code`, `reason`, `headers`, `body`. |
65
+ | `build_response(status, *, body, json, text, html, headers)` | Convenience builder with sensible Content-Type defaults. |
66
+ | `streaming.build_streaming_response(status, *, source, content_length, headers)` | Opt-in `chumicro_http_server.streaming` submodule — serve a body larger than the heap from a fill-a-buffer `source(buffer) -> int` (Content-Length or chunked framing, fixed staging window). |
67
+ | `RequestParser` | Streaming request parser (request line + headers + Content-Length body). |
68
+ | `parse_query` / `split_target` | URL helpers. |
69
+ | `ServerError` + subclasses | Typed exception hierarchy, independent of `chumicro_requests` so the server can ship without the client library. |
70
+
71
+ Each request is served on a fresh accepted socket and `Connection: close` is added to every response — HTTP/1.1 keep-alive and connection pooling are not supported. Chunked request bodies are not supported either; use `Content-Length`.
72
+
73
+ Need to return a body bigger than the heap — a log dump, a file, a long export? Return a **streaming response** from the opt-in `chumicro_http_server.streaming` submodule and the server drains it from a fill-a-buffer source one small window at a time, choosing Content-Length or chunked framing for you:
74
+
75
+ ```python
76
+ from chumicro_http_server.streaming import build_streaming_response, SOURCE_EOF
77
+
78
+ @server.route("/log")
79
+ def log_dump(request):
80
+ def source(buffer):
81
+ n = read_next_block_into(buffer) # your storage read; 0 <= n <= len(buffer)
82
+ return n if n else SOURCE_EOF # -1 signals end of body
83
+ return build_streaming_response(200, source=source)
84
+ ```
85
+
86
+ See the [user guide](https://chumicro.github.io/ChuMicro/http_server/stable/guide/#streaming-large-response-bodies) for the source contract, framing rules, fairness, and staging-window sizing.
87
+
88
+ ## Where this fits
89
+
90
+ Depends on [`chumicro-sockets`](../sockets/) (TCP listener) and [`chumicro-timing`](../timing/) (ticks). Pairs with [`chumicro-websockets`](../websockets/) for combined HTTP + WS deployments. Self-contained otherwise — the shared HTTP/1.1 primitives (case-insensitive header dict, charset parsing) are inlined locally, so a server-only board never ships [`chumicro-requests`](../requests/).
91
+
92
+ ## Platform support
93
+
94
+ Works on CPython, MicroPython, and CircuitPython. Pure Python — no native extensions.
95
+
96
+ ### TLS server (HTTPS)
97
+
98
+ `chumicro-http-server` itself is transport-agnostic — pass a TLS-wrapped
99
+ listener from
100
+ [`chumicro_sockets.ssl_context_with_cert_and_key_paths`](https://github.com/ChuMicro/ChuMicro/tree/main/libraries/sockets)
101
+ into `transport_factory` and the same `HttpServer` runs HTTPS. Live
102
+ verification across the supported board matrix:
103
+
104
+ | Runtime + board | TLS server status | Notes |
105
+ |---|---|---|
106
+ | CircuitPython on ESP32-S2 (Lolin S2) | ✅ Works | Bench-tested ~5 KB context (RSA-2048); each connection adds tens of KB during handshake — leave headroom. |
107
+ | CircuitPython on rp2 (Pi Pico W / Pi Pico 2 W) | ❌ Refused (`UnsupportedSSLConfigError`) | `chumicro_sockets.listener(tls=True)` raises up-front; the underlying CYW43 TLS path raises `OSError(32)` mid-handshake AND wedges the chip's station-mode state. Use ESP32-family or MicroPython on rp2. |
108
+ | MicroPython on ESP32-S2 | ✅ Works | Hardware-accelerated handshake; ~1 KB heap. |
109
+ | MicroPython on rp2 (Pi Pico W) | ✅ Works (RSA-2048 only) | DER-encoded key; ~25 KB handshake heap; ECC keys fail at context build. |
110
+
111
+ > **Why the CP-on-rp2 row?** The CYW43 stack's TLS server path raises `OSError(32)` mid-handshake and wedges the chip's station state until a USB power-cycle. No upstream fix is in flight; for HTTPS server work on rp2, use MicroPython.
112
+
113
+ The TLS handshake is synchronous inside `wrap_socket(..., server_side=True)`:
114
+ the listener stalls until it completes — single-digit to tens of
115
+ milliseconds on the supported board class with a local TLS client, longer
116
+ on a slow uplink as TLS rounds-trip. Once the handshake completes, the
117
+ per-connection state machine resumes its runner-shaped,
118
+ LED-blink-friendly progression.
119
+
120
+ ## Examples
121
+
122
+ | Example | What it shows |
123
+ |---|---|
124
+ | `simple_server.py` | Single-board HTTP server with `GET /`, `GET /api/uptime`, `POST /api/echo` routes. Drive it with `curl` from your laptop. Cross-runtime (CP + MP) — runtime marker on the file gates hardware-only deploys. For a two-physical-board demo see the workspace template's `two_board_handshake/` example. |
125
+
126
+ ## Wiring wifi credentials for examples and functional tests
127
+
128
+ The hardware-prefixed examples + real-network suites in `functional_tests/test_real_*.py` need wifi credentials. See [`docs/wiring-wifi-credentials.md`](https://github.com/ChuMicro/ChuMicro/blob/main/docs/wiring-wifi-credentials.md) for the workspace-based and raw single-file paths. The library itself never reads TOML — it takes a `transport_factory` and goes; config wiring is application-layer.
129
+
130
+ ## Contributing
131
+
132
+ Working on `chumicro-http-server` itself? Clone the [mono-repo](https://github.com/ChuMicro/ChuMicro) if you haven't already — the rest of the workflow assumes you're inside that workspace.
133
+
134
+ ```bash
135
+ pip install -e .[test]
136
+ pytest tests/ # host-side tests
137
+ pytest functional_tests/ # on-device tests (needs a board registered in devices.yml)
138
+ ```
139
+
140
+ Register a board before running functional tests: `chumicro-workspace add-device <id> --address <port>`.
141
+
142
+ ## Docs
143
+
144
+ 📖 **[Stable docs](https://chumicro.github.io/ChuMicro/http-server/stable/)** · **[Experimental docs](https://chumicro.github.io/ChuMicro/http-server/experimental/)**
145
+
146
+ ## Find this library
147
+
148
+ - **PyPI:** [chumicro-http-server](https://pypi.org/project/chumicro-http-server/)
149
+ - **Bundle:** [ChuMicro-Bundle](https://github.com/ChuMicro/ChuMicro-Bundle/tree/main/chumicro_http_server) (CircuitPython & MicroPython)
150
+ - **Experimental bundle:** [ChuMicro-Bundle-Experimental](https://github.com/ChuMicro/ChuMicro-Bundle-Experimental/tree/main/chumicro_http_server)
151
+ - **Source:** [libraries/http_server](https://github.com/ChuMicro/ChuMicro/tree/main/libraries/http_server)
152
+
153
+ ## License
154
+
155
+ [MIT](https://github.com/ChuMicro/ChuMicro/blob/main/LICENSE)
@@ -0,0 +1 @@
1
+ 0.18.0
@@ -0,0 +1,25 @@
1
+ # API Reference
2
+
3
+ ## `chumicro_http_server`
4
+
5
+ ::: chumicro_http_server
6
+
7
+ ## `chumicro_http_server.streaming`
8
+
9
+ Opt-in submodule for streamed response bodies — import it explicitly.
10
+ A server that never streams never loads it.
11
+
12
+ ::: chumicro_http_server.streaming
13
+
14
+ ---
15
+
16
+ <div class="chumicro-footer" markdown>
17
+
18
+ [← Home](index.md)
19
+
20
+ [Source](https://github.com/ChuMicro/ChuMicro/tree/main/libraries/http_server) · \
21
+ [PyPI](https://pypi.org/project/chumicro-http_server/) · \
22
+ [Bundle](https://github.com/ChuMicro/ChuMicro-Bundle) · \
23
+ [Experimental Bundle](https://github.com/ChuMicro/ChuMicro-Bundle-Experimental)
24
+
25
+ </div>