nx_navigation_test.nx source
↩ module page · 144 lines · 6952 B
1// nx_navigation_test.nx -- combined KAT for link extraction +
2// 3xx redirect resolution. Together these primitives unlock
3// anchor-click navigation in the bits-up browser.
4//
5// expect_exit: 0
6// license_tier: ORIGINAL
7
8import "nx_syscalls.nx"
9import "nx_html_extract_links.nx"
10import "nx_http_resolve_redirect.nx"
11
12func _fail(n: i64) -> i64 {
13 let b: *u8 = sys_mmap(16)
14 b[0]=0x46; b[1]=0x41; b[2]=0x49; b[3]=0x4C; b[4]=0x3D
15 sys_write(2, b, 5)
16 var x: i64 = n
17 if x < 0 { let m: *u8 = sys_mmap(4); m[0]=0x2D; sys_write(2, m, 1); x = 0 - x }
18 if x == 0 { let z: *u8 = sys_mmap(4); z[0]=0x30; sys_write(2, z, 1) }
19 else {
20 let buf: *u8 = sys_mmap(16)
21 var pos: i64 = 0
22 while x > 0 { buf[pos] = (0x30 + (x % 10)) as u8; x = x / 10; pos = pos + 1 }
23 let out: *u8 = sys_mmap(16)
24 var i: i64 = 0
25 while i < pos { out[i] = buf[pos - 1 - i]; i = i + 1 }
26 sys_write(2, out, pos)
27 }
28 let nl: *u8 = sys_mmap(4); nl[0]=0x0A; sys_write(2, nl, 1)
29 return 0
30}
31
32func _bytes_eq_lit(buf: *u8, off: i64, n: i64, lit: *u8) -> i64 {
33 var i: i64 = 0
34 while i < n {
35 if buf[off + i] != lit[i] { return 0 }
36 i = i + 1
37 }
38 if lit[n] != 0 { return 0 }
39 return 1
40}
41
42func _strlen(s: *u8) -> i64 {
43 var n: i64 = 0
44 while s[n] != 0 { n = n + 1 }
45 return n
46}
47
48func main() -> i64 {
49 // ============================================================
50 // Section A: nx_html_extract_links
51 // ============================================================
52 let html: *u8 = "<html><head><script>var s='<a href=\"trap.html\">TRAP</a>';</script></head><body><a href=\"about.html\">about</a><A HREF='/contact'>c</A><a href=\"https://other.com/x\">x</a><a href=\"//cdn/y.html\">y</a></body></html>"
53 var hlen: i64 = 0
54 while html[hlen] != 0 { hlen = hlen + 1 }
55
56 let base: *u8 = "https://www.example.com/path/page.html"
57 let blen: i64 = _strlen(base)
58
59 let url_buf: *u8 = sys_mmap(2048)
60 let offsets: *i64 = sys_mmap(256) as *i64
61 let lengths: *i64 = sys_mmap(256) as *i64
62
63 let n: i64 = nx_html_extract_links(html, hlen, base, blen,
64 url_buf, 2048, offsets, lengths, 32)
65 if n != 4 { _fail(1000 + n); return 1 } // 4 real links, NOT script trap
66
67 if _bytes_eq_lit(url_buf, offsets[0], lengths[0], "https://www.example.com/path/about.html" as *u8) != 1 { _fail(2); return 2 }
68 if _bytes_eq_lit(url_buf, offsets[1], lengths[1], "https://www.example.com/contact" as *u8) != 1 { _fail(3); return 3 }
69 if _bytes_eq_lit(url_buf, offsets[2], lengths[2], "https://other.com/x" as *u8) != 1 { _fail(4); return 4 }
70 if _bytes_eq_lit(url_buf, offsets[3], lengths[3], "https://cdn/y.html" as *u8) != 1 { _fail(5); return 5 }
71
72 // ============================================================
73 // Section B: status predicates
74 // ============================================================
75 if nx_redirect_status_is_followable(301) != 1 { _fail(10); return 10 }
76 if nx_redirect_status_is_followable(302) != 1 { _fail(11); return 11 }
77 if nx_redirect_status_is_followable(303) != 1 { _fail(12); return 12 }
78 if nx_redirect_status_is_followable(307) != 1 { _fail(13); return 13 }
79 if nx_redirect_status_is_followable(308) != 1 { _fail(14); return 14 }
80 if nx_redirect_status_is_followable(200) != 0 { _fail(15); return 15 }
81 if nx_redirect_status_is_followable(304) != 0 { _fail(16); return 16 } // not-modified, NOT followable
82 if nx_redirect_status_is_followable(404) != 0 { _fail(17); return 17 }
83
84 if nx_redirect_status_is_permanent(301) != 1 { _fail(20); return 20 }
85 if nx_redirect_status_is_permanent(308) != 1 { _fail(21); return 21 }
86 if nx_redirect_status_is_permanent(302) != 0 { _fail(22); return 22 }
87 if nx_redirect_status_is_permanent(303) != 0 { _fail(23); return 23 }
88 if nx_redirect_status_is_permanent(307) != 0 { _fail(24); return 24 }
89
90 if nx_redirect_status_preserves_method(307) != 1 { _fail(30); return 30 }
91 if nx_redirect_status_preserves_method(308) != 1 { _fail(31); return 31 }
92 if nx_redirect_status_preserves_method(301) != 0 { _fail(32); return 32 }
93 if nx_redirect_status_preserves_method(302) != 0 { _fail(33); return 33 }
94 if nx_redirect_status_preserves_method(303) != 0 { _fail(34); return 34 }
95
96 // ============================================================
97 // Section C: nx_http_resolve_redirect
98 // ============================================================
99 // C1: absolute Location
100 let r1: *u8 = "HTTP/1.1 302 Found\r\nLocation: https://new.example.com/\r\nContent-Length: 0\r\n\r\n"
101 let r1n: i64 = _strlen(r1)
102 let next_url: *u8 = sys_mmap(2048)
103 let next_len_p: *i64 = sys_mmap(8) as *i64
104 var rc: i64 = nx_http_resolve_redirect(r1, r1n, 302,
105 base, blen,
106 next_url, 2048, next_len_p)
107 if rc != NX_REDIRECT_RESOLVED { _fail(40 + rc); return 40 }
108 if _bytes_eq_lit(next_url, 0, next_len_p[0], "https://new.example.com/" as *u8) != 1 { _fail(41); return 41 }
109
110 // C2: relative path Location resolves against base
111 let r2: *u8 = "HTTP/1.1 301 Moved Permanently\r\nLocation: /new-path\r\nContent-Length: 0\r\n\r\n"
112 let r2n: i64 = _strlen(r2)
113 rc = nx_http_resolve_redirect(r2, r2n, 301, base, blen,
114 next_url, 2048, next_len_p)
115 if rc != NX_REDIRECT_RESOLVED { _fail(50 + rc); return 50 }
116 if _bytes_eq_lit(next_url, 0, next_len_p[0], "https://www.example.com/new-path" as *u8) != 1 { _fail(51); return 51 }
117
118 // C3: case-insensitive header name (location: not Location:)
119 let r3: *u8 = "HTTP/1.1 303 See Other\r\nlocation: thanks.html\r\nContent-Length: 0\r\n\r\n"
120 let r3n: i64 = _strlen(r3)
121 rc = nx_http_resolve_redirect(r3, r3n, 303, base, blen,
122 next_url, 2048, next_len_p)
123 if rc != NX_REDIRECT_RESOLVED { _fail(60 + rc); return 60 }
124 if _bytes_eq_lit(next_url, 0, next_len_p[0], "https://www.example.com/path/thanks.html" as *u8) != 1 { _fail(61); return 61 }
125
126 // C4: non-3xx status declines politely
127 let r4: *u8 = "HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n"
128 let r4n: i64 = _strlen(r4)
129 rc = nx_http_resolve_redirect(r4, r4n, 200, base, blen,
130 next_url, 2048, next_len_p)
131 if rc != NX_REDIRECT_NOT_3XX { _fail(70); return 70 }
132
133 // C5: 3xx without Location header
134 let r5: *u8 = "HTTP/1.1 302 Found\r\nContent-Length: 0\r\n\r\n"
135 let r5n: i64 = _strlen(r5)
136 rc = nx_http_resolve_redirect(r5, r5n, 302, base, blen,
137 next_url, 2048, next_len_p)
138 if rc != NX_REDIRECT_NO_LOCATION { _fail(80); return 80 }
139
140 let pass: *u8 = sys_mmap(16)
141 pass[0]=0x50; pass[1]=0x41; pass[2]=0x53; pass[3]=0x53; pass[4]=0x0A
142 sys_write(1, pass, 5)
143 return 0
144}