diff --git a/hosts/ocaml/bin/sx_server.ml b/hosts/ocaml/bin/sx_server.ml index 66816226..c21dd1b9 100644 --- a/hosts/ocaml/bin/sx_server.ml +++ b/hosts/ocaml/bin/sx_server.ml @@ -25,14 +25,20 @@ open Sx_types (** Escape a string for embedding in an SX string literal. *) let escape_sx_string s = - let buf = Buffer.create (String.length s + 16) in - String.iter (function + let len = String.length s in + let buf = Buffer.create (len + 16) in + for i = 0 to len - 1 do + match s.[i] with | '"' -> Buffer.add_string buf "\\\"" | '\\' -> Buffer.add_string buf "\\\\" | '\n' -> Buffer.add_string buf "\\n" | '\r' -> Buffer.add_string buf "\\r" | '\t' -> Buffer.add_string buf "\\t" - | c -> Buffer.add_char buf c) s; + | '<' when i + 1 < len && s.[i + 1] = '/' -> + (* Escape *) + Buffer.add_string buf "<\\\\/" + | c -> Buffer.add_char buf c + done; Buffer.contents buf (** Serialize a value to SX text (for io-request args). *) @@ -1619,14 +1625,10 @@ let http_inject_shell_statics env static_dir sx_sxc = | _ -> () ) env.bindings; let raw_defs = Buffer.contents buf in - (* Don't inline component-defs — serve from /static/sx-components.sx. - Inlining breaks because SX source can contain literal which - the HTML parser uses to close the tag prematurely. *) - let component_defs = "" in - (* Cache the raw defs for the /static/sx-components.sx endpoint *) - Hashtbl.replace static_cache "/static/sx-components.sx" - (Printf.sprintf "HTTP/1.1 200 OK\r\nContent-Type: text/sx; charset=utf-8\r\nContent-Length: %d\r\nCache-Control: public, max-age=31536000, immutable\r\n\r\n%s" - (String.length raw_defs) raw_defs); + (* Component-defs are inlined in . *) + let component_defs = raw_defs in let component_hash = Digest.string component_defs |> Digest.to_hex in (* Compute file hashes for cache busting *) let sx_js_hash = file_hash (static_dir ^ "/scripts/sx-browser.js") in