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}