Skip to content

Commit 057e190

Browse files
committed
Add public TLS and protocol limits
1 parent e6a9529 commit 057e190

4 files changed

Lines changed: 577 additions & 47 deletions

File tree

README.md

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,18 @@ The current phase provides:
1818
- bounded multi-client windows through `WindowOptions.max_clients`;
1919
- bounded concurrent evaluations through
2020
`WindowOptions.max_pending_evals`;
21+
- explicit connection, WebSocket message, call, argument, binding, event, and
22+
script limits through `App.Options.limits`;
2123
- window navigation, close, raw-data, and JavaScript broadcasts with
2224
per-client results;
2325
- targeted and broadcast fire-and-forget JavaScript through `Client.run` and
2426
`Window.run`;
2527
- connected, disconnected, click, and intercepted navigation events through
2628
`Window.onEvent`;
29+
- same-origin WebSocket validation for hosted content and external-page Origin
30+
validation for `.external_url`;
31+
- loopback-only listening by default and caller-provided TLS for explicit
32+
public listening;
2733
- default-browser launching and deterministic shutdown.
2834

2935
```zig
@@ -100,9 +106,29 @@ pending evaluation slots.
100106
External pages use `.content = .{ .external_url = "http://..." }`.
101107
`Window.url` returns the external page, while `Window.bridgeUrl` returns the
102108
capability-scoped script URL that the caller-owned page must load. The bridge
103-
connects its WebSocket to the script's origin instead of the page's origin.
104-
HTTPS external pages require HTTPS bridge serving, which is part of the TLS
105-
work.
109+
connects its WebSocket to the script's origin instead of the page's origin,
110+
and the server accepts the external page's Origin for that window.
111+
112+
Non-loopback listening requires both explicit public mode and TLS:
113+
114+
```zig
115+
var app = webui.App.init(gpa, .{
116+
.address = "0.0.0.0",
117+
.public = true,
118+
.tls = .{
119+
.certificate_pem = @embedFile("certificate.pem"),
120+
.private_key_pem = @embedFile("private-key.pem"),
121+
},
122+
.limits = .{
123+
.max_connections = 128,
124+
.max_unauthenticated_connections = 16,
125+
.max_ws_message_size = 1 << 20,
126+
},
127+
});
128+
```
129+
130+
The certificate and private key are parsed by `App.start()` and released by
131+
`Running.stop()`. zig-webui never generates a self-signed certificate.
106132

107133
See the
108134
[pure Zig refactor plan](docs/PURE_ZIG_REFACTOR.md) for the complete scope and

docs/PURE_ZIG_REFACTOR.md

Lines changed: 122 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,15 @@ races, and synchronous access to the actual `port = 0` address through
3636

3737
## Product Boundaries
3838

39+
### Complete capability parity target
40+
41+
- Cover every user-visible capability in upstream WebUI `2.5.0-beta.4` at
42+
commit `337a183cea0a9c5daee16acb77eed2d5443bbbb0`.
43+
- Use Zig-native ownership, errors, names, and types instead of copying C
44+
signatures.
45+
- Treat the API coverage ledger as the completion contract. Every entry must
46+
end as implemented or as an explicit Zig standard-library replacement.
47+
3948
### Required for the first release
4049

4150
- One application managing multiple windows.
@@ -54,16 +63,17 @@ races, and synchronous access to the actual `port = 0` address through
5463

5564
- A C API, `src/c.zig`, extern struct ABI, or interface compatibility APIs.
5665
- Zig 0.14 or 0.15 compatibility. Zig 0.16 is the baseline.
66+
- Automatic self-signed certificate generation.
5767

58-
### Explicit first-release non-goals
68+
### Deferred capability parity
5969

6070
- WebView2, GTK/WebKit, or WKWebView.
6171
- Deno, Node, or Bun server-side runtimes.
6272
- Automatic reload, proxies, or browser profile management.
63-
- Automatic self-signed certificate generation.
64-
- Complete compatibility with every upstream browser and command-line flag.
73+
- Browser selection, managed processes, and window-control flags.
6574

66-
Add these only after the core release and only when real use requires them.
75+
These do not block the external-browser core, but they are required before
76+
declaring complete upstream capability parity.
6777

6878
## Do Not Translate `webui.c` Line by Line
6979

@@ -274,9 +284,9 @@ protocol input never panics.
274284

275285
## Upstream WebUI API Coverage Ledger
276286

277-
This ledger tracks upstream WebUI `2.5.0-beta.4` capabilities independently
278-
of the implementation phases. Upstream C names are identifiers for
279-
traceability, not a commitment to reproduce the C API shape in Zig.
287+
This ledger tracks upstream WebUI `2.5.0-beta.4` at commit
288+
`337a183cea0a9c5daee16acb77eed2d5443bbbb0`. Upstream C names are identifiers
289+
for traceability, not a commitment to reproduce the C API shape in Zig.
280290
Coverage is determined only from `src/root.zig` and its reachable pure Zig
281291
modules. Deleted legacy wrapper, test, and example files do not count as
282292
implementations.
@@ -309,8 +319,6 @@ implementations.
309319
| `webui_set_profile()`, `webui_delete_profile()`, `webui_delete_all_profiles()` | Managed browser profiles are not implemented. |
310320
| `webui_set_proxy()` | Browser proxy configuration is not implemented. |
311321
| `webui_get_parent_process_id()`, `webui_get_child_process_id()` | Browser process tracking is not implemented. |
312-
| `webui_set_public()` | A guarded public-listening option with Origin validation and explicit limits is not implemented. |
313-
| `webui_set_tls_certificate()` | Caller-provided TLS certificate and private-key configuration is not implemented. |
314322
| `webui_set_runtime()` | Deno, Node.js, and Bun execution for served files is not implemented. |
315323
| `webui_show_wv()`, `webui_set_close_handler_wv()`, `webui_get_hwnd()`, `webui_win32_get_hwnd()` | Native WebView hosting and native window handles are outside the pure Zig browser core. |
316324

@@ -350,13 +358,114 @@ not implementation gaps:
350358
| `webui_close_client()`, `webui_navigate_client()`, `webui_send_raw_client()` | `Client.close()`, `Client.navigate()`, and `Client.sendRaw()`. |
351359
| `webui_navigate()`, `webui_send_raw()` | `Window.navigate()` and `Window.sendRaw()`. |
352360
| `webui_set_config(multi_client)` | `WindowOptions.max_clients`. |
361+
| `webui_set_public()` | `App.Options.public` permits non-loopback listening only with TLS; Origin and explicit connection and protocol limits are enforced. |
362+
| `webui_set_tls_certificate()` | `App.Options.tls` accepts caller-provided PEM certificate and private-key bytes. |
353363
| `webui_set_port()`, `webui_get_port()`, `webui_get_free_port()` | `App.Options.port`, including `0` for automatic selection, and the running window URL. |
354364
| `webui_set_root_folder()`, `webui_set_file_handler()`, `webui_set_file_handler_window()`, `webui_return_http()` | Initial `.directory` or `.custom` content and `Response`. Runtime replacement remains listed above. |
355365
| `webui_get_mime_type()` | Linsang resource handling. |
356366
| `webui_encode()`, `webui_decode()`, `webui_malloc()`, `webui_free()`, `webui_memcpy()` | Zig standard library and allocators. |
357367
| `webui_get_last_error_number()`, `webui_get_last_error_message()` | Zig error unions. |
358368
| `webui_interface_*()` | Permanently omitted with the C ABI compatibility layer. |
359369

370+
## Capability Parity Implementation Order
371+
372+
Each work package must add its focused unit or integration checks and update
373+
the coverage ledger in the same commit.
374+
375+
### Network trust boundary
376+
377+
- Add explicit loopback and public listening modes.
378+
- Implement caller-provided TLS certificate and private-key configuration.
379+
- Validate WebSocket Origin values.
380+
- Add connection, unauthenticated connection, WebSocket message, binding
381+
name, call payload, argument, script, and pending-call limits.
382+
- Implement optional cookie authorization without weakening capability URLs.
383+
384+
This completes the behavior represented by `webui_set_public()`,
385+
`webui_set_tls_certificate()`, and `webui_set_config(use_cookies)`.
386+
387+
### Calls, bindings, and browser bridge
388+
389+
- Add `Call.float()`, `Call.replyFloat()`, and `Call.replyBool()`.
390+
- Make element-name bindings dispatch the same binding for DOM events while
391+
preserving explicit `webui.call()` support.
392+
- Implement bridge `setLogging()`, `encode()`, `decode()`,
393+
`setEventCallback()`, `event`, `isHighContrast()`, and
394+
`allowNavigation()`.
395+
- Preserve string, number, boolean, and `Uint8Array` call arguments.
396+
397+
This completes `webui_bind()`, the remaining typed argument and return
398+
methods, and the public browser bridge surface.
399+
400+
### Handler and event lifecycle
401+
402+
- Add an owned delayed-response handle for asynchronous binding responses.
403+
- Add per-window serialized or concurrent event execution.
404+
- Add optional wait-for-connection behavior and a connection timeout.
405+
- Add a caller-provided logger.
406+
- Expose only stable event metadata that has no C ABI dependency.
407+
408+
This completes the remaining `webui_set_config()` behavior,
409+
`webui_set_event_blocking()`, `webui_set_timeout()`, and
410+
`webui_set_logger()`.
411+
412+
### Dynamic content and client state
413+
414+
- Allow window content and resource handlers to be replaced safely.
415+
- Add targeted `Client.show()` behavior.
416+
- Add a window connected/shown query.
417+
- Add an application default directory.
418+
- Add inline and file-backed window icons.
419+
420+
This completes `webui_show()`, `webui_show_client()`, `webui_is_shown()`,
421+
the dynamic root and file-handler methods, `webui_set_default_root_folder()`,
422+
`webui_set_icon()`, and `webui_set_icon_file()`.
423+
424+
### Managed browsers and window controls
425+
426+
- Discover supported browsers and select the best or an explicit browser.
427+
- Support a custom browser executable directory and caller-provided argv.
428+
- Expose a general URL opener.
429+
- Launch and retain managed browser processes and expose their process IDs.
430+
- Implement kiosk, focus, minimize, maximize, hidden, resizable, geometry,
431+
frameless, transparent, and high-contrast controls where the selected
432+
browser and platform support them.
433+
- Implement managed profiles and proxy configuration.
434+
435+
This completes the browser selection, browser process, window control,
436+
profile, and proxy methods in the ledger.
437+
438+
### File monitoring and server-side runtimes
439+
440+
- Monitor directory content and reload connected clients on changes.
441+
- Run served JavaScript and TypeScript through explicitly selected Deno,
442+
Node.js, or Bun executables.
443+
- Keep runtime execution disabled by default and pass commands as argv.
444+
445+
This completes `webui_set_config(folder_monitor)` and
446+
`webui_set_runtime()`.
447+
448+
### Native WebViews
449+
450+
- Keep WebView support in an optional module so the browser core remains pure
451+
Zig and has no bundled C, C++, or Objective-C implementation.
452+
- Implement WebView2, GTK/WebKit, and WKWebView adapters using system
453+
frameworks.
454+
- Add close interception and native window-handle access.
455+
456+
This completes `webui_show_wv()`, `webui_set_close_handler_wv()`,
457+
`webui_get_hwnd()`, and `webui_win32_get_hwnd()`. Platform ABI declarations
458+
inside the optional module require a separate design review; the public
459+
zig-webui API remains Zig-native.
460+
461+
### Parity closure
462+
463+
- Give every ledger row an implemented or replacement status.
464+
- Add retained examples for bindings, dynamic content, public TLS, managed
465+
browsers, runtimes, and WebViews.
466+
- Run protocol fuzzing, browser end-to-end tests, leak checks, and all target
467+
builds before publishing the breaking release.
468+
360469
## Tests and Completion Criteria
361470

362471
Keep at least one direct test for every non-trivial parser. The final gate is:
@@ -397,7 +506,8 @@ zig build -Dtarget=aarch64-macos
397506

398507
## Next Implementation Work
399508

400-
Begin phase 4:
509+
Continue capability parity:
401510

402-
1. Validate WebSocket origins and add explicit protocol size limits.
403-
2. Add caller-provided TLS configuration before enabling public listening.
511+
1. Add optional cookie authorization.
512+
2. Add `Call.float()`, `Call.replyFloat()`, and `Call.replyBool()`.
513+
3. Complete the public browser bridge API.

0 commit comments

Comments
 (0)