Skip to content

Add HTTPS/TLS support for the built-in web server - #564

Merged
logbie merged 5 commits into
mainfrom
claude/wfl-https-support-j3sn6a
Jul 4, 2026
Merged

Add HTTPS/TLS support for the built-in web server#564
logbie merged 5 commits into
mainfrom
claude/wfl-https-support-j3sn6a

Conversation

@logbie

@logbie logbie commented Jul 4, 2026

Copy link
Copy Markdown
Collaborator

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 listen statement:

  1. Explicit certificate paths: listen on port 8443 secured with certificate "cert.pem" and key "key.pem" as server
  2. Config-driven paths: listen on port 8443 secured as server (reads from .wflcfg)
  3. HTTP→HTTPS redirect: listen on port 8080 redirecting to port 8443 as server

Key Changes

Parser & AST

  • Extended ListenStatement with optional tls: Option<TlsListenConfig> and redirect_to_port: Option<Expression> fields
  • Added TlsListenConfig struct to hold certificate and key path expressions
  • Implemented contextual identifier parsing for secured, certificate, key, and redirecting (not reserved keywords, preserving backward compatibility)
  • Handled lexer's multi-word identifier merging (e.g., port my_port securedIdentifier("my_port secured")) by detecting and splitting these tokens before expression parsing

Interpreter

  • Added strip_host_port() helper to extract hostname from Host header while preserving IPv6 brackets
  • Added validate_tls_pem_files() to validate certificate/key files at startup with actionable error messages
  • Implemented TLS server initialization using warp with tokio-rustls
  • Implemented redirect server that answers all requests with 301 Moved Permanently, preserving path and query string while swapping scheme and port
  • Redirect servers register like normal servers (enabling close server) but never feed their request channels

Configuration

  • Added web_server_tls_cert_file and web_server_tls_key_file to WflConfig
  • Config values only apply to bare secured form; explicit paths in code always win
  • Plain listen statements never become HTTPS via config (prevents silent conversion of HTTP servers)

Type Checking & Analysis

  • Added type validation for certificate/key path expressions (must be Text)
  • Added type validation for redirect target port (must be Number)

Documentation & Testing

  • Added comprehensive HTTPS section to web server documentation with examples
  • Added parser tests (web_server_tls_parser_test.rs) covering all syntax variants and merged identifier handling
  • Added integration tests (web_server_tls_test.rs) with self-signed certificates via rcgen
  • Added example program (TestPrograms/web_server_tls.wfl)
  • Updated configuration reference and keyword documentation
  • Added dev diary entry explaining design decisions

Build & Scripts

  • Updated Cargo.toml to enable warp TLS feature (adds tokio-rustls 0.24 → rustls 0.21, coexisting with existing rustls 0.23)
  • Updated web test scripts (run_web_tests.ps1 and .sh) to generate self-signed certificates and test HTTPS functionality

Notable Implementation Details

No new keywords: secured, certificate, key, and redirecting are 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 with is 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 request on a redirect server times out. This is intentional—the server exists solely to redirect traffic.

Config precedence: TLS intent always lives in the program; .wflcfg only supplies defaults for the bare secured form. This prevents silent HTTPS conversion when running dual HTTP/HTTPS setups.

https://claude.ai/code/session_01Vs7eRcLpvVztrNXLWo5GND

Summary by CodeRabbit

  • New Features
    • Added HTTPS/TLS for web server listeners via listen ... secured, with optional HTTP→HTTPS 301 redirects via listen ... redirecting.
    • Added configuration defaults for TLS certificate/key paths used by bare secured listeners.
    • Support for running HTTP and HTTPS listeners side by side.
  • Bug Fixes
    • Improved TLS file validation at startup with clearer, actionable error reporting.
    • Redirects preserve the original path and query while switching to the HTTPS target.
  • Documentation
    • Expanded web server and configuration references with HTTPS/TLS and redirect examples, plus clarification on TLS “marker words” behavior.

…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
Copilot AI review requested due to automatic review settings July 4, 2026 05:38
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

@coderabbitai

coderabbitai Bot commented Jul 4, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Warning

Review limit reached

@logbie, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 50 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

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 configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: f1cc649d-0f6a-4945-b613-0369b80a9c9f

📥 Commits

Reviewing files that changed from the base of the PR and between 0572850 and 3e48f7a.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (2)
  • Cargo.toml
  • src/interpreter/mod.rs
📝 Walkthrough

Walkthrough

Adds 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.

Changes

HTTPS/TLS listen and redirect feature

Layer / File(s) Summary
AST and parser support
src/parser/ast.rs, src/parser/stmt/web.rs
Adds TlsListenConfig and new tls / redirect_to_port listen fields, and extends parsing for secured and redirecting forms.
Analysis and type validation
src/analyzer/mod.rs, src/typechecker/mod.rs
Analyzer visits the new expressions and type checking enforces text paths and numeric redirect ports.
TLS config defaults and parsing
src/config.rs, src/wfl_config/checker.rs, .wflcfg
Adds web server TLS default-path settings, parses them from config, registers them for checking, and documents example values.
Interpreter TLS and redirect execution
src/interpreter/mod.rs, src/transpiler/javascript.rs, Cargo.toml
Implements TLS file validation, redirect response generation, HTTPS startup, plain HTTP fallback, transpiler warnings, and TLS-related dependency updates.
Tests, example program, and web test runners
tests/web_server_tls_parser_test.rs, tests/web_server_tls_test.rs, TestPrograms/web_server_tls.wfl, TestPrograms/web_server_tls.wfl.ast.txt, scripts/run_web_tests.sh, scripts/run_web_tests.ps1
Adds parser and integration coverage, a TLS example script and AST fixture, and CI/web test runner updates for generating certs and validating redirect/HTTPS behavior.
Documentation and changelog
CHANGELOG.md, Dev diary/2026-07-04-https-tls-web-server.md, Docs/04-advanced-features/web-servers.md, Docs/reference/configuration-reference.md, Docs/reference/keyword-reference.md, Docs/reference/reserved-keywords.md
Documents TLS, redirects, marker words, config defaults, current limitations, and related reference material.

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
Loading

Possibly related PRs

  • WebFirstLanguage/wfl#169: Both PRs modify listen and web-server handling in src/interpreter/mod.rs, with this PR extending that groundwork to TLS and redirects.
  • WebFirstLanguage/wfl#262: This PR extends the JavaScript transpiler’s ListenStatement handling introduced there with warnings for the new TLS/redirect options.
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and accurately summarizes the PR’s main change: adding HTTPS/TLS support to the built-in web server.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch claude/wfl-https-support-j3sn6a

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 listen syntax/AST to support secured ... TLS listeners and redirecting 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.

Comment thread src/interpreter/mod.rs
Comment thread tests/web_server_tls_test.rs Outdated
Comment thread Dev diary/2026-07-04-https-tls-web-server.md Outdated
Comment thread scripts/run_web_tests.ps1 Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (2)
src/parser/stmt/web.rs (1)

27-127: 🎯 Functional Correctness | 🔵 Trivial | 💤 Low value

Mutual-exclusion check is one-directional.

Lines 109-118 explicitly reject secured ... redirecting ..., but there's no symmetric check for redirecting ... 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 generic expect_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 value

Full request/response routes filter is built even for the redirect-only branch.

routes (with its per-request closures, UUID generation, and channel wiring) is constructed unconditionally before branching on redirect_to_port/tls, but it's never used when redirect_to_port is Some. 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

📥 Commits

Reviewing files that changed from the base of the PR and between 576730b and a6ab539.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (22)
  • .wflcfg
  • CHANGELOG.md
  • Cargo.toml
  • Dev diary/2026-07-04-https-tls-web-server.md
  • Docs/04-advanced-features/web-servers.md
  • Docs/reference/configuration-reference.md
  • Docs/reference/keyword-reference.md
  • Docs/reference/reserved-keywords.md
  • TestPrograms/web_server_tls.wfl
  • TestPrograms/web_server_tls.wfl.ast.txt
  • scripts/run_web_tests.ps1
  • scripts/run_web_tests.sh
  • src/analyzer/mod.rs
  • src/config.rs
  • src/interpreter/mod.rs
  • src/parser/ast.rs
  • src/parser/stmt/web.rs
  • src/transpiler/javascript.rs
  • src/typechecker/mod.rs
  • src/wfl_config/checker.rs
  • tests/web_server_tls_parser_test.rs
  • tests/web_server_tls_test.rs

Comment thread Docs/04-advanced-features/web-servers.md Outdated
claude and others added 2 commits July 4, 2026 06:03
- 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
@logbie logbie self-assigned this Jul 4, 2026
Copilot AI review requested due to automatic review settings July 4, 2026 07:47

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 22 out of 23 changed files in this pull request and generated 2 comments.

Comment thread src/interpreter/mod.rs
Comment thread Cargo.toml
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
@logbie
logbie merged commit dce7f98 into main Jul 4, 2026
19 checks passed
@logbie
logbie deleted the claude/wfl-https-support-j3sn6a branch July 4, 2026 08:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants