code wiki / (root) / nx_https_ka_probe.nx

nx_https_ka_probe.nx source

↩ module page · 158 lines · 9822 B

1// nx_https_ka_probe.nx -- R4 ISOLATED PROOF: HTTP/1.1 KEEP-ALIVE connection reuse over ONE TLS session. 2// Operator 2026-07-01 chose R4 (connection reuse). nx_https_get_complete has 30 callers -> CANNOT modify it. 3// So this is a SELF-CONTAINED probe that replicates the send/read loop with a "Connection: keep-alive" request and 4// sends TWO GETs over ONE handshake -> proves the ~300ms certloop is paid ONCE for N fetches. Touches nothing existing. 5// If GREEN, the next step is a connection-pool layer in the research engine (also isolated). license_tier: ORIGINAL 6// expect_exit: 0 7import "nx_syscalls.nx" 8import "nx_tls13.nx" 9import "nx_tls13_record.nx" 10import "nx_tls13_read_record_from_fd.nx" 11import "nx_tls13_client_session.nx" 12import "nx_x509_trust_store.nx" 13import "nx_trust_store_load_from_certdata.nx" 14import "nx_tls13_client_validate_certificate.nx" 15import "nx_tls13_client_session_run.nx" 16import "nx_url.nx" 17import "nx_https_url_for_fetch.nx" 18import "nx_https_url_connect.nx" 19import "nx_http_response_parse.nx" 20const K_MAGIC_4096: i64 = 4096 21const K_MAGIC_16645: i64 = 16645 22const K_MAGIC_4194304: i64 = 4194304 23 24func kp(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(1,s,n); return 0 } 25func kn(v: i64) -> i64 { let b: *u8=sys_mmap(28); var m: i64=v; if m<0{m=0} let t: *u8=sys_mmap(28); var k: i64=0; if m==0{t[0]=48 as u8;k=1} while m>0{t[k]=(48+(m%10)) as u8;m=m/10;k=k+1} var i: i64=0; while i<k{b[i]=t[k-1-i];i=i+1} sys_write(1,b,k); return 0 } 26func ka_write_n(fd: i64, buf: *u8, n: i64) -> i64 { var off: i64=0; while off<n { let w: i64=sys_write(fd,(buf as i64+off) as *u8,n-off); if w<=0 {return 0-1} off=off+w } return 0 } 27 28// build "GET <path> HTTP/1.1\r\nHost: <host>\r\n<UA...>\r\nConnection: keep-alive\r\n\r\n" (mirrors nx_http_client_build_request but keep-alive) 29func ka_cat(out: *u8, o: i64, s: *u8) -> i64 { var j: i64=0; while s[j]!=(0 as u8) { out[o]=s[j]; o=o+1; j=j+1 } return o } 30func ka_build_req(path: *u8, path_len: i64, host: *u8, host_len: i64, out: *u8) -> i64 { 31 var o: i64 = 0 32 o = ka_cat(out, o, "GET " as *u8) 33 var pi: i64=0; while pi<path_len { out[o]=path[pi]; o=o+1; pi=pi+1 } 34 o = ka_cat(out, o, " HTTP/1.1\r\nHost: " as *u8) 35 var hi: i64=0; while hi<host_len { out[o]=host[hi]; o=o+1; hi=hi+1 } 36 o = ka_cat(out, o, "\r\nUser-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:128.0) Gecko/20100101 Firefox/128.0\r\nAccept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\nAccept-Language: en-US,en;q=0.5\r\nAccept-Encoding: identity\r\nConnection: keep-alive\r\n\r\n" as *u8) 37 return o 38} 39 40// find "\r\n\r\n"; -1 if absent 41func ka_hdr_end(buf: *u8, n: i64) -> i64 { var i: i64=0; while i+4<=n { if buf[i]==(13 as u8){if buf[i+1]==(10 as u8){if buf[i+2]==(13 as u8){if buf[i+3]==(10 as u8){return i}}}} i=i+1 } return 0-1 } 42func ka_lc(c: i64) -> i64 { if c>=65 { if c<=90 { return c+32 } } return c } 43func ka_clen(buf: *u8, hdr_end: i64) -> i64 { 44 let pat: *u8 = "content-length:" as *u8 45 var i: i64=0 46 while i<hdr_end { 47 var atline: i64=0 48 if i==0 { atline=1 } else { if buf[i-1]==(10 as u8) { atline=1 } } 49 if atline==1 { 50 var mm: i64=1; var j: i64=0 51 while j<15 { if ka_lc(buf[i+j] as i64)!=ka_lc(pat[j] as i64) { mm=0; j=15 } else { j=j+1 } } 52 if mm==1 { 53 var p: i64=i+15 54 var d: i64=0 55 while d==0 { if p>=hdr_end { d=1 } else { if buf[p]==(32 as u8) { p=p+1 } else { d=1 } } } 56 var v: i64=0; var any: i64=0; var go: i64=1 57 while go==1 { if p>=hdr_end { go=0 } else { let c: i64=buf[p] as i64; if c>=48 { if c<=57 { v=v*10+(c-48); any=1; p=p+1 } else { go=0 } } else { go=0 } } } 58 if any==1 { return v } 59 return 0-1 60 } 61 } 62 i=i+1 63 } 64 return 0-1 65} 66 67// Send ONE keep-alive GET over the (already-connected) session+fd, drain the Content-Length body, LEAVE fd open. 68// Returns bytes accumulated (POSITIVE) or negative on error. Mirrors nx_https_get_complete's send/read + cl-stop. 69func ka_get(s: *Tls13ClientSession, fd: i64, path: *u8, path_len: i64, host: *u8, host_len: i64, out_buf: *u8, out_cap: i64) -> i64 { 70 if s.state != NX_TLS13_CSESSION_STATE_CONNECTED { return 0-100 } 71 let req: *u8 = sys_mmap(K_MAGIC_4096) 72 let req_len: i64 = ka_build_req(path, path_len, host, host_len, req) 73 let rec_buf: *u8 = sys_mmap(req_len + 64) 74 let header_out: *u8 = rec_buf 75 let ct_out: *u8 = rec_buf + NX_TLS13_RECORD_HEADER_LEN 76 let tag_out: *u8 = rec_buf + NX_TLS13_RECORD_HEADER_LEN + req_len + 1 77 let enc_v: i64 = nx_tls13_record_encrypt_v2(s.cipher_suite, s.client_app_traffic_key, s.client_app_iv, s.client_app_seq, req, req_len, NX_TLS13_CT_APPLICATION_DATA, 0, header_out, ct_out, tag_out) 78 s.client_app_seq = s.client_app_seq + 1 79 if enc_v != NX_TLS13_REC_VERDICT_OK { return 0-101 } 80 let total_rec_len: i64 = NX_TLS13_RECORD_HEADER_LEN + req_len + 1 + NX_TLS13_RECORD_TAG_LEN 81 if ka_write_n(fd, rec_buf, total_rec_len) < 0 { return 0-102 } 82 var accumulated: i64 = 0 83 var body_target: i64 = 0 84 var hdr_parsed: i64 = 0 85 let rec_in: *u8 = sys_mmap(K_MAGIC_16645) 86 let plaintext: *u8 = sys_mmap(K_MAGIC_16645) 87 let pct: *i64 = sys_mmap(16) as *i64 88 let plen: *i64 = sys_mmap(16) as *i64 89 while accumulated < out_cap { 90 let rt: i64 = nx_tls13_read_record_from_fd(fd, rec_in, K_MAGIC_16645) 91 if rt < 0 { 92 let nv: i64 = 0 - rt 93 if nv == NX_TLS13_READ_REC_EOF { return accumulated } 94 if nv == NX_TLS13_READ_REC_PAYLOAD_EOF { return accumulated } 95 return 0-103 96 } 97 let rec_ct: *u8 = rec_in + NX_TLS13_RECORD_HEADER_LEN 98 let rec_ct_len: i64 = rt - NX_TLS13_RECORD_HEADER_LEN - NX_TLS13_RECORD_TAG_LEN 99 let rec_tag: *u8 = rec_in + rt - NX_TLS13_RECORD_TAG_LEN 100 let dv: i64 = nx_tls13_record_decrypt_v2(s.cipher_suite, s.server_app_traffic_key, s.server_app_iv, s.server_app_seq, rec_in, rec_ct, rec_ct_len, rec_tag, plaintext, pct, plen) 101 s.server_app_seq = s.server_app_seq + 1 102 if dv != NX_TLS13_REC_VERDICT_OK { return 0-104 } 103 if *pct == NX_TLS13_CT_ALERT { return accumulated } 104 if *pct == NX_TLS13_CT_APPLICATION_DATA { 105 let to_copy: i64 = *plen 106 if to_copy > out_cap - accumulated { return 0-105 } 107 var i: i64=0; while i<to_copy { out_buf[accumulated+i]=plaintext[i]; i=i+1 } 108 accumulated = accumulated + to_copy 109 if hdr_parsed==0 { let he: i64=ka_hdr_end(out_buf, accumulated); if he>=0 { hdr_parsed=1; let cl: i64=ka_clen(out_buf, he); if cl>=0 { body_target=he+4+cl } } } 110 if body_target>0 { if accumulated>=body_target { return accumulated } } // cl-stop: leave fd OPEN for reuse 111 } 112 } 113 return accumulated 114} 115 116func main() -> i64 { 117 kp("=== nx_https_ka_probe -- R4 keep-alive connection-reuse proof (2 GETs over 1 TLS handshake) ===\n" as *u8) 118 let r: i64 = nx_trust_store_load_from_certdata("data/mozilla_certdata.txt" as *u8, 512, K_MAGIC_4194304) 119 if r <= 0 { kp("trust load FAIL\n" as *u8); return 1 } 120 let store: *TrustStore = r as *TrustStore 121 let urlbuf: *u8 = sys_mmap(K_MAGIC_4096) 122 let u0: *u8 = "https://en.wikipedia.org/wiki/Three.js" as *u8 123 var ui: i64=0; while u0[ui]!=(0 as u8) { urlbuf[ui]=u0[ui]; ui=ui+1 } urlbuf[ui]=0 as u8 124 let target_raw: *u8 = sys_mmap(64); let target: *NxHttpsTarget = target_raw as *NxHttpsTarget 125 target.url = nx_url_new(); target.port = 0 126 if nx_https_url_for_fetch(urlbuf, target) != NX_HTTPS_URL_OK { kp("url FAIL\n" as *u8); return 1 } 127 let fd_p: *i64 = sys_mmap(16) as *i64 128 if nx_https_url_connect(target, urlbuf, sys_now_realtime_sec(), fd_p) != NX_HTTPS_CONNECT_OK { kp("connect FAIL\n" as *u8); return 1 } 129 let fd: i64 = fd_p[0] 130 let host: *u8 = urlbuf + target.url.host_off 131 let hlen: i64 = target.url.host_len 132 let cr: *u8 = sys_mmap(32); let priv: *u8 = sys_mmap(32) 133 var i: i64=0; while i<32 { cr[i]=(0xC0+i) as u8; priv[i]=(0xA0+i) as u8; i=i+1 } 134 let vc_raw: *u8 = sys_mmap(64); let vc: *TlsValidationContext = vc_raw as *TlsValidationContext 135 vc.store = store; vc.sni_host = host; vc.sni_host_len = hlen; vc.now_epoch = sys_now_realtime_sec() 136 kp(" handshake (ONE certloop for BOTH requests)...\n" as *u8) 137 let sr: i64 = nx_tls13_client_session_run(fd, host, hlen, cr, priv, vc) 138 if sr <= 0 { sys_close(fd); kp("handshake FAIL\n" as *u8); return 1 } 139 let session: *Tls13ClientSession = sr as *Tls13ClientSession 140 141 let cap: i64 = K_MAGIC_4194304 142 let out1: *u8 = sys_mmap(cap); let out2: *u8 = sys_mmap(cap) 143 let rr: *i64 = sys_mmap(128) as *i64 144 // REQUEST 1: /wiki/Three.js 145 let n1: i64 = ka_get(session, fd, "/wiki/WebGL" as *u8, 11, host, hlen, out1, cap) 146 var st1: i64 = 0; if n1>0 { if nx_http_response_parse(out1, n1, rr)==0 { st1=rr[1] } } 147 kp(" REQ1 /wiki/WebGL bytes="); kn(n1); kp(" status="); kn(st1); kp("\n" as *u8) 148 // REQUEST 2: /wiki/WebGL -- OVER THE SAME session+fd (no new handshake!) 149 let n2: i64 = ka_get(session, fd, "/wiki/WebGL" as *u8, 11, host, hlen, out2, cap) 150 var st2: i64 = 0; if n2>0 { if nx_http_response_parse(out2, n2, rr)==0 { st2=rr[1] } } 151 kp(" REQ2 /wiki/WebGL bytes="); kn(n2); kp(" status="); kn(st2); kp(" (reused connection, NO 2nd handshake)\n" as *u8) 152 sys_close(fd) 153 154 var green: i64=0; if n1>0 { if n2>0 { if st1==200 { if st2==200 { green=1 } } } } 155 if green==1 { kp("verdict=GREEN -- R4 PROVEN: 2 responses over 1 TLS handshake (certloop paid ONCE). Connection reuse works.\n" as *u8); return 0 } 156 kp("verdict=RED (n1="); kn(n1); kp(" st1="); kn(st1); kp(" n2="); kn(n2); kp(" st2="); kn(st2); kp(")\n" as *u8) 157 return 1 158}