Fix JS files served as raw JSON envelope instead of JavaScript
Dev — Build & local smoke test / build-smoke (pull_request) Failing after 1m36s

http_parse_envelope() called json_parse() on the entire response envelope
(~47KB when body is obfuscated JS). The parser failed on large/complex content,
so is_envelope=0 and the raw JSON was sent — browsers got {"el_http_response":1,...}
instead of executable JavaScript, silently breaking all client-side code.

Fix: replace json_parse-of-full-envelope with a direct field scanner:
- "status" extracted via strtol
- "headers" object extracted via brace-depth scan, then json_parse only that
  small substring (always safe — headers are simple k/v string pairs < 1KB)
- "body" string extracted via jp_parse_string_raw — no intermediate allocation

Also: /js/* route now returns http_response(200, js_headers_json(), content)
with explicit Content-Type: application/javascript so the browser doesn't
apply the json-heuristic (obfuscated JS starting with '[' was detected as JSON,
which with X-Content-Type-Options: nosniff blocks script execution).
This commit is contained in:
2026-05-10 17:32:45 -05:00
parent 0263e51407
commit c99ca82302
2 changed files with 109 additions and 31 deletions
+18 -1
View File
@@ -907,6 +907,10 @@ fn handle_request_inner(method: String, path: String, body: String) -> String {
// Compiled client-side JS: /js/*
// Served from dist/js/ (compiled by elc --target=js at build time).
// LANDING_ROOT/js maps to the dist/js output directory in the image.
// Returns an http_response envelope with explicit Content-Type so the
// browser executes the file as JavaScript http_detect_content_type()
// mis-identifies minified/obfuscated JS as JSON because many obfuscated
// bundles start with '[' (which is also a JSON array opener).
if str_starts_with(path, "/js/") {
let rel: String = str_slice(path, 4, str_len(path))
let abs: String = src_dir + "/js/" + rel
@@ -914,7 +918,7 @@ fn handle_request_inner(method: String, path: String, body: String) -> String {
if str_eq(content, "") {
return "{\"__status__\":404,\"error\":\"not found\"}"
}
return content
return http_response(200, js_headers_json(), content)
}
// Brand assets: /brand/*
@@ -1936,6 +1940,19 @@ fn sec_headers_json() -> String {
+ "\"Content-Security-Policy\":\"default-src 'self'; script-src 'self' 'unsafe-inline' https://challenges.cloudflare.com https://cdn.jsdelivr.net https://www.googletagmanager.com https://www.google-analytics.com; style-src 'self' 'unsafe-inline'; frame-src https://challenges.cloudflare.com; connect-src 'self' https://api.stripe.com https://*.supabase.co; img-src 'self' data: https:; font-src 'self' data:\"}"
}
// Headers for compiled JS assets. Explicitly sets Content-Type so the browser
// treats them as JavaScript regardless of what http_detect_content_type()
// infers from the content (minified/obfuscated JS can trip the JSON heuristic).
fn js_headers_json() -> String {
"{\"Content-Type\":\"application/javascript; charset=utf-8\","
+ "\"Cache-Control\":\"public, max-age=3600\","
+ "\"Strict-Transport-Security\":\"max-age=63072000; includeSubDomains; preload\","
+ "\"X-Content-Type-Options\":\"nosniff\","
+ "\"X-Frame-Options\":\"SAMEORIGIN\","
+ "\"Referrer-Policy\":\"strict-origin-when-cross-origin\","
+ "\"Permissions-Policy\":\"geolocation=(), microphone=(), camera=()\"}"
}
fn handle_request(method: String, path: String, body: String) -> String {
let inner_resp: String = handle_request_inner(method, path, body)
// Detect envelope already set by inner handler (starts with