code wiki / (root) / nx_redirect_resolve.nx

nx_redirect_resolve.nx source

↩ module page · 68 lines · 3212 B

1// nx_redirect_resolve.nx -- redirect-Location policy for the sovereign 2// nish browser (X-HTTP-RELLOC-001). 3// 4// Composes the proven RFC3986 ยง5.2 resolver (nx_url_resolve) with an 5// https-only safety gate, so the redirect follower accepts RELATIVE 6// Locations (/path, //host/path, ../x, ?q, #f) in addition to absolute 7// https:// ones -- while preserving nish's invariant that it never 8// follows a redirect off https (no http: downgrade, no cross-scheme 9// jump). This is the WIRING the live fetcher was missing; the 10// resolution math already existed and is KAT-proven in nx_url_resolve. 11// 12// Policy (single source of truth = the resolver + one prefix check): 13// 1. Resolve `loc` against the absolute base URL via nx_url_resolve. 14// - absolute ref with a scheme -> used verbatim (resolver Case 2) 15// - scheme-relative //host/path -> inherits base scheme 16// - path-absolute /p, relative p, ?q, #f -> merged against base 17// 2. Require the resolved target to start with "https://". Absolute 18// http:// / ftp: / mailto: targets fail this and are NOT followed 19// (return 0) -- exactly nish's prior https-only behaviour, now 20// applied to the RESOLVED target so relative refs (which inherit 21// https from the base) pass and downgrades still don't. 22// 23// Returns 1 (followable; out = NUL-terminated absolute https target, 24// *out_len_p = its length) or 0 (do not follow: empty/overflow/non-https). 25// 26// expect_exit: 0 27// license_tier: ORIGINAL 28// genealogy_id: international-research-sources/ietf/rfc_3986 29// lineage_id: nishi_redirect_resolve_q10 30 31import "nx_syscalls.nx" 32import "nx_url_resolve.nx" 33 34// True iff s[0..8) == "https://". Byte-exact, no allocation. 35func _rr_is_https_prefix(s: *u8, n: i64) -> i64 { 36 if n < 8 { return 0 } 37 if (s[0] & 0xff) != 0x68 { return 0 } // h 38 if (s[1] & 0xff) != 0x74 { return 0 } // t 39 if (s[2] & 0xff) != 0x74 { return 0 } // t 40 if (s[3] & 0xff) != 0x70 { return 0 } // p 41 if (s[4] & 0xff) != 0x73 { return 0 } // s 42 if (s[5] & 0xff) != 0x3a { return 0 } // : 43 if (s[6] & 0xff) != 0x2f { return 0 } // / 44 if (s[7] & 0xff) != 0x2f { return 0 } // / 45 return 1 46} 47 48// Resolve a redirect Location against the current absolute URL `base` 49// (NUL-termination not required; base_len is authoritative). out MUST 50// NOT alias base (the resolver copies base into out while building). 51// Writes a NUL-terminated absolute https target to out on success. 52func nx_redirect_resolve(base: *u8, base_len: i64, 53 loc: *u8, loc_len: i64, 54 out: *u8, out_cap: i64, 55 out_len_p: *i64) -> i64 { 56 out_len_p[0] = 0 57 if loc_len <= 0 { return 0 } 58 if base_len <= 0 { return 0 } 59 // Reserve one byte for the NUL terminator we append. 60 let rc: i64 = nx_url_resolve(base, base_len, loc, loc_len, out, out_cap - 1, out_len_p) 61 if rc != NX_URL_RESOLVE_OK { out_len_p[0] = 0; return 0 } 62 let rl: i64 = out_len_p[0] 63 if rl <= 0 { return 0 } 64 if rl >= out_cap { out_len_p[0] = 0; return 0 } 65 if _rr_is_https_prefix(out, rl) == 0 { out_len_p[0] = 0; return 0 } // https-only 66 out[rl] = 0 as u8 67 return 1 68}