Add HTTPS/TLS support for the built-in web server - #564
Conversation
…rver options The listen statement gains two optional clauses: listen on port 8443 secured with certificate "cert.pem" and key "key.pem" as server listen on port 8443 secured as server (paths from .wflcfg) listen on port 8080 redirecting to port 8443 as server (native 301) - secured/certificate/key/redirecting are positional marker words, not reserved keywords, so existing programs using them as variables keep working; keyword count stays 178 - bare 'secured' takes paths from new .wflcfg settings web_server_tls_cert_file / web_server_tls_key_file (in-language paths win; plain listen never becomes HTTPS via config) - redirect servers answer 301 natively in warp, preserving host, path, and query (target port omitted when 443) - certificate/key files are pre-validated with rustls-pemfile for actionable errors; TLS bind uses try_bind_with_graceful_shutdown to avoid warp's in-task panics - warp built with the tls feature (adds rustls 0.21 alongside sqlx's 0.23; noted in Dev diary) - tests: 14 parser cases incl. merged-identifier forms, 7 end-to-end TLS tests with rcgen certs, TLS section in run_web_tests scripts, CI-SKIP'd TestPrograms/web_server_tls.wfl - docs: HTTPS section in web-servers.md, config reference entries, marker-word notes in keyword references, Dev diary + CHANGELOG Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Vs7eRcLpvVztrNXLWo5GND
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
|
Warning Review limit reached
Next review available in: 50 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: ⛔ Files ignored due to path filters (1)
📒 Files selected for processing (2)
📝 WalkthroughWalkthroughAdds HTTPS/TLS support for WFL web servers, including secured listeners, HTTP→HTTPS redirects, TLS config defaults, runtime validation, parser/typechecker support, tests, and documentation updates. ChangesHTTPS/TLS listen and redirect feature
Estimated code review effort: 4 (Complex) | ~60 minutes Sequence Diagram(s)sequenceDiagram
participant WebParser
participant Interpreter
participant Warp
participant TLSFiles
WebParser->>Interpreter: ListenStatement{tls, redirect_to_port}
alt redirect_to_port set
Interpreter->>Warp: serve 301 redirect responses
else tls set
Interpreter->>TLSFiles: validate_tls_pem_files(cert, key)
TLSFiles-->>Interpreter: validation result
Interpreter->>Warp: bind HTTPS server
else
Interpreter->>Warp: bind plain HTTP server
end
Possibly related PRs
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Pull request overview
Adds first-class HTTPS/TLS support to WFL’s built-in listen web server statement (plus native HTTP→HTTPS redirects), integrating with the existing parser/typechecker/analyzer/interpreter pipeline and documenting/testing the new syntax and behavior.
Changes:
- Extended
listensyntax/AST to supportsecured ...TLS listeners andredirecting to port ...redirect listeners, including merged-identifier handling in the parser. - Implemented TLS and redirect server startup in the interpreter (warp + tokio-rustls), plus startup validation for PEM cert/key files and host header parsing for redirects.
- Added config keys, tests (parser + integration), docs, scripts, and dependency updates to support and verify HTTPS.
Reviewed changes
Copilot reviewed 22 out of 23 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
tests/web_server_tls_test.rs |
End-to-end HTTPS/redirect/config TLS integration tests using rcgen + reqwest. |
tests/web_server_tls_parser_test.rs |
Parser coverage for new listen variants and merged-identifier edge cases. |
TestPrograms/web_server_tls.wfl.ast.txt |
AST snapshot for the new example program. |
TestPrograms/web_server_tls.wfl |
Example WFL program demonstrating HTTPS + redirect server usage. |
src/wfl_config/checker.rs |
Registers the new .wflcfg TLS settings for validation/help text. |
src/typechecker/mod.rs |
Type-check rules for TLS cert/key path expressions and redirect target port. |
src/transpiler/javascript.rs |
Warns that JS transpilation doesn’t support secured/redirecting options. |
src/parser/stmt/web.rs |
Parses the new listen options and handles merged identifier tokens. |
src/parser/ast.rs |
Adds TlsListenConfig and extends ListenStatement with TLS/redirect fields. |
src/interpreter/mod.rs |
Implements TLS server startup, redirect server behavior, and PEM validation helpers. |
src/config.rs |
Adds config fields + parsing + unit tests for TLS cert/key defaults. |
src/analyzer/mod.rs |
Analyzer now walks TLS path expressions and redirect port expressions. |
scripts/run_web_tests.sh |
Adds an HTTPS/redirect test for the example program (openssl + curl). |
scripts/run_web_tests.ps1 |
Adds Windows HTTPS/redirect test for the example program (openssl + IWR). |
Docs/reference/reserved-keywords.md |
Documents marker-words-as-identifiers (not reserved keywords). |
Docs/reference/keyword-reference.md |
Cross-links marker-word behavior clarification. |
Docs/reference/configuration-reference.md |
Documents new TLS config keys and precedence rules. |
Docs/04-advanced-features/web-servers.md |
Adds HTTPS/TLS and redirect documentation + examples. |
Dev diary/2026-07-04-https-tls-web-server.md |
Design write-up of TLS/redirect approach and tradeoffs. |
CHANGELOG.md |
Notes HTTPS, redirect servers, config keys, and validation behavior. |
Cargo.toml |
Enables warp TLS feature; adds rustls-pemfile; adds rcgen dev-dep. |
Cargo.lock |
Dependency graph updates for warp TLS + rcgen and transitive rustls crates. |
.wflcfg |
Adds commented-out defaults for the new TLS config settings. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (2)
src/parser/stmt/web.rs (1)
27-127: 🎯 Functional Correctness | 🔵 Trivial | 💤 Low valueMutual-exclusion check is one-directional.
Lines 109-118 explicitly reject
secured ... redirecting ..., but there's no symmetric check forredirecting ... secured ...(e.g.listen on port 8080 redirecting to port 8443 secured as name). It won't be silently accepted — it will fail later at the genericexpect_token(Token::KeywordAs, ...)in line 130 with "Expected 'as' after port" — but the error message won't clearly explain the real problem (combining both clauses).♻️ Optional: symmetric rejection after the `redirecting` branch
Some("redirecting") => { self.expect_token(Token::KeywordTo, "Expected 'to' after 'redirecting'")?; self.expect_token(Token::KeywordPort, "Expected 'port' after 'redirecting to'")?; // Primary expression only, so the following "as" stays available. redirect_to_port = Some(self.parse_primary_expression()?); + + if let Some(token) = self.cursor.peek() + && let Token::Identifier(id) = &token.token + && (id == "secured" || id.starts_with("secured ")) + { + return Err(ParseError::from_token( + "'secured' and 'redirecting to port' cannot be combined on one listen statement" + .to_string(), + token, + )); + } }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/parser/stmt/web.rs` around lines 27 - 127, The mutual-exclusion handling in the listen-statement parser is only checked in the secured path, so the `redirecting` branch can still fall through and produce a misleading generic parse error. Add a symmetric validation in `parse listen` logic in `src/parser/stmt/web.rs` around the `redirecting` handling to detect a following `secured` marker (including merged identifier forms) and վերադարձ an explicit error stating the two clauses cannot be combined, mirroring the existing `secured`-then-`redirecting` check.src/interpreter/mod.rs (1)
5037-5144: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueFull request/response
routesfilter is built even for the redirect-only branch.
routes(with its per-request closures, UUID generation, and channel wiring) is constructed unconditionally before branching onredirect_to_port/tls, but it's never used whenredirect_to_portisSome. This is cheap (filter construction, not execution) so it's not a runtime hotspot, but it's dead work worth trimming for clarity.Also applies to: 5161-5372
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/interpreter/mod.rs` around lines 5037 - 5144, The full warp routes filter is being constructed unconditionally even when the redirect-only branch is selected, which leaves dead setup work in the server startup path. Move the `routes` construction into the branch where it is actually used, so it is only built when `redirect_to_port` is not `Some` and the `tls`/main server path is taken. Keep the existing handler logic inside the route-building block, and use the `routes` symbol plus the surrounding `redirect_to_port` and `tls` branching to place the change correctly.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@Docs/04-advanced-features/web-servers.md`:
- Around line 630-633: The configuration example in the web server docs uses an
unlabeled code fence, which should be marked as INI for linting and syntax
highlighting. Update the fenced block around the web_server_tls_cert_file and
web_server_tls_key_file settings to use the ini language tag, keeping the
content unchanged.
---
Nitpick comments:
In `@src/interpreter/mod.rs`:
- Around line 5037-5144: The full warp routes filter is being constructed
unconditionally even when the redirect-only branch is selected, which leaves
dead setup work in the server startup path. Move the `routes` construction into
the branch where it is actually used, so it is only built when
`redirect_to_port` is not `Some` and the `tls`/main server path is taken. Keep
the existing handler logic inside the route-building block, and use the `routes`
symbol plus the surrounding `redirect_to_port` and `tls` branching to place the
change correctly.
In `@src/parser/stmt/web.rs`:
- Around line 27-127: The mutual-exclusion handling in the listen-statement
parser is only checked in the secured path, so the `redirecting` branch can
still fall through and produce a misleading generic parse error. Add a symmetric
validation in `parse listen` logic in `src/parser/stmt/web.rs` around the
`redirecting` handling to detect a following `secured` marker (including merged
identifier forms) and վերադարձ an explicit error stating the two clauses cannot
be combined, mirroring the existing `secured`-then-`redirecting` check.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: f092d5ac-fbb2-4b7b-8b83-5152a38db480
⛔ Files ignored due to path filters (1)
Cargo.lockis excluded by!**/*.lock
📒 Files selected for processing (22)
.wflcfgCHANGELOG.mdCargo.tomlDev diary/2026-07-04-https-tls-web-server.mdDocs/04-advanced-features/web-servers.mdDocs/reference/configuration-reference.mdDocs/reference/keyword-reference.mdDocs/reference/reserved-keywords.mdTestPrograms/web_server_tls.wflTestPrograms/web_server_tls.wfl.ast.txtscripts/run_web_tests.ps1scripts/run_web_tests.shsrc/analyzer/mod.rssrc/config.rssrc/interpreter/mod.rssrc/parser/ast.rssrc/parser/stmt/web.rssrc/transpiler/javascript.rssrc/typechecker/mod.rssrc/wfl_config/checker.rstests/web_server_tls_parser_test.rstests/web_server_tls_test.rs
- Normalize Windows backslash cert paths to forward slashes in TLS tests: backslashes in embedded WFL string literals broke the lexer on windows-latest (Integration Tests failure) - Validate redirect target port is a whole number in 1..=65535 instead of silently saturating via the float->u16 cast; add regression test - Gate the run_web_tests.ps1 HTTPS probe on PowerShell 6+ so Windows PowerShell 5.1 skips gracefully (-SkipCertificateCheck unavailable) - Correct Dev diary rustls versions (tokio-rustls 0.25 / rustls 0.22.4) - Fix test file port-range comment (8210-8219) and label the .wflcfg doc fence as ini Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Vs7eRcLpvVztrNXLWo5GND
Copilot review: the direct rustls-pemfile = "1" dependency compiled a second major alongside the v2 that warp's tls feature uses. Port validate_tls_pem_files to the v2 iterator API (Pkcs1Key/Pkcs8Key/Sec1Key variants) so this crate shares warp's copy. The remaining v1 in the lockfile is a pre-existing transitive dependency of reqwest 0.11, untouched by this PR. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Vs7eRcLpvVztrNXLWo5GND
Summary
This PR adds full HTTPS/TLS support to WFL's built-in web server, enabling secure connections without requiring a reverse proxy. Three new optional clauses extend the
listenstatement:listen on port 8443 secured with certificate "cert.pem" and key "key.pem" as serverlisten on port 8443 secured as server(reads from.wflcfg)listen on port 8080 redirecting to port 8443 as serverKey Changes
Parser & AST
ListenStatementwith optionaltls: Option<TlsListenConfig>andredirect_to_port: Option<Expression>fieldsTlsListenConfigstruct to hold certificate and key path expressionssecured,certificate,key, andredirecting(not reserved keywords, preserving backward compatibility)port my_port secured→Identifier("my_port secured")) by detecting and splitting these tokens before expression parsingInterpreter
strip_host_port()helper to extract hostname from Host header while preserving IPv6 bracketsvalidate_tls_pem_files()to validate certificate/key files at startup with actionable error messageswarpwithtokio-rustls301 Moved Permanently, preserving path and query string while swapping scheme and portclose server) but never feed their request channelsConfiguration
web_server_tls_cert_fileandweb_server_tls_key_filetoWflConfigsecuredform; explicit paths in code always winlistenstatements never become HTTPS via config (prevents silent conversion of HTTP servers)Type Checking & Analysis
Text)Number)Documentation & Testing
web_server_tls_parser_test.rs) covering all syntax variants and merged identifier handlingweb_server_tls_test.rs) with self-signed certificates viarcgenTestPrograms/web_server_tls.wfl)Build & Scripts
Cargo.tomlto enablewarpTLS feature (addstokio-rustls0.24 →rustls0.21, coexisting with existingrustls0.23)run_web_tests.ps1and.sh) to generate self-signed certificates and test HTTPS functionalityNotable Implementation Details
No new keywords:
secured,certificate,key, andredirectingare plain identifiers matched positionally by the parser. This preserves backward compatibility with existing programs that use these words as variable names (e.g.,store key as "secret").Merged identifier handling: The lexer fuses adjacent identifiers into single tokens. The parser detects and splits these before parsing port expressions, since
withis a concatenation operator and would otherwise be absorbed into the expression.Redirect server design: Redirect servers answer requests natively without reaching the WFL request loop, so
wait for requeston a redirect server times out. This is intentional—the server exists solely to redirect traffic.Config precedence: TLS intent always lives in the program;
.wflcfgonly supplies defaults for the baresecuredform. This prevents silent HTTPS conversion when running dual HTTP/HTTPS setups.https://claude.ai/code/session_01Vs7eRcLpvVztrNXLWo5GND
Summary by CodeRabbit
listen ... secured, with optional HTTP→HTTPS301redirects vialisten ... redirecting.securedlisteners.