nx_edge_serve_static.nx source
↩ module page · 112 lines · 3784 B
1// nx_edge_serve_static.nx -- substrate primitive that turns a
2// CONNECTED Tls13ServerSession into a one-shot HTTPS serving call.
3//
4// What this ships:
5// nx_edge_build_http_response(content, content_len, out, out_cap)
6// Builds a minimal HTTP/1.1 200 OK response with Content-Length
7// header and the given body. Returns total bytes written.
8//
9// nx_edge_serve_static_response(session, content, content_len, out, out_cap)
10// After handshake completes (state CONNECTED), this builds an
11// HTTP/1.1 response wrapping `content` and AEAD-encrypts it as
12// a TLS application_data record under server_app_traffic_key + iv.
13// Returns total bytes written to `out` (the wire bytes to send
14// to the client over the TCP socket).
15//
16// This is the final substrate brick between the substrate's TLS 1.3
17// server arc (10 stones + app_send/recv shipped) and an operator-
18// runnable HTTPS daemon. Operator integration steps documented in
19// docs/NISHIFAMILY_DEPLOY_RUNBOOK_2026_05_20.md.
20//
21// license_tier: ORIGINAL
22
23import "nx_syscalls.nx"
24import "nx_tls13_server_session.nx"
25import "nx_tls13_server_session_app_data.nx"
26
27// Append a C-string to a byte buffer; returns new write position.
28func edge_put_cstr(out: *u8, pos: i64, s: *u8) -> i64 {
29 var i: i64 = 0
30 var p: i64 = pos
31 while s[i] != 0 {
32 out[p] = s[i]
33 p = p + 1
34 i = i + 1
35 }
36 return p
37}
38
39// Write a positive integer as decimal ASCII; returns new write position.
40func edge_put_int(out: *u8, pos: i64, value: i64) -> i64 {
41 var p: i64 = pos
42 if value == 0 {
43 out[p] = 0x30 as u8
44 return p + 1
45 }
46 let scratch: *u8 = sys_mmap(24)
47 var n: i64 = 0
48 var v: i64 = value
49 while v > 0 {
50 scratch[n] = ((0x30 + (v % 10)) & 0xff) as u8
51 v = v / 10
52 n = n + 1
53 }
54 var j: i64 = n - 1
55 while j >= 0 {
56 out[p] = scratch[j]
57 p = p + 1
58 j = j - 1
59 }
60 return p
61}
62
63// Build a minimal HTTP/1.1 200 OK response wrapping content.
64// Returns total bytes written.
65func nx_edge_build_http_response(
66 content: *u8, content_len: i64,
67 out: *u8, out_cap: i64
68) -> i64 {
69 if (content as i64) == 0 { return -1 }
70 if content_len < 0 { return -1 }
71 // Pre-size: status line ~17 + headers ~80 + body
72 if out_cap < 100 + content_len { return -1 }
73
74 var p: i64 = 0
75 p = edge_put_cstr(out, p, "HTTP/1.1 200 OK\r\n")
76 p = edge_put_cstr(out, p, "Content-Type: text/html; charset=utf-8\r\n")
77 p = edge_put_cstr(out, p, "Content-Length: ")
78 p = edge_put_int(out, p, content_len)
79 p = edge_put_cstr(out, p, "\r\nConnection: close\r\n\r\n")
80
81 var ci: i64 = 0
82 while ci < content_len {
83 out[p + ci] = content[ci]
84 ci = ci + 1
85 }
86 return p + content_len
87}
88
89// Serve a static HTML/text response: build HTTP/1.1 200 OK + encrypt
90// as a TLS application_data record. Caller supplies the CONNECTED
91// session. Returns wire-byte count or negative verdict.
92func nx_edge_serve_static_response(
93 session: *Tls13ServerSession,
94 content: *u8, content_len: i64,
95 out: *u8, out_cap: i64
96) -> i64 {
97 if (session as i64) == 0 { return 0 - NX_TLS13_SSESSION_BAD_STATE }
98 if session.state != NX_TLS13_SSTATE_CONNECTED {
99 return 0 - NX_TLS13_SSESSION_BAD_STATE
100 }
101
102 // 1. Build the plaintext HTTP/1.1 response
103 let http_cap: i64 = 256 + content_len
104 let http_buf: *u8 = sys_mmap(http_cap)
105 let http_len: i64 = nx_edge_build_http_response(
106 content, content_len, http_buf, http_cap)
107 if http_len < 0 { return 0 - NX_TLS13_SSESSION_INTERNAL }
108
109 // 2. Encrypt the HTTP response as a TLS application_data record
110 return nx_tls13_server_session_app_send(
111 session, http_buf, http_len, out, out_cap)
112}