code wiki / _hdl_build / nx_bench_fetch.nx
nx_bench_fetch.nx source
↩ module page · 130 lines · 5817 B
1// nx_bench_fetch.nx -- THE GENERIC SOVEREIGN URL->FILE FETCHER (rule 15 DRY; eats the hardcoded-URL
2// fetcher-family duplication class).
3//
4// WHY IT EXISTS: the ecosystem has ~119 `*_research_fetch` organs, each a copy of the same TLS+save body
5// with its URLs BAKED IN. I wrote two more this session (swebv, gmmlu) before the third instance made the
6// pattern obvious -- rule 15 says extract at 3. Every one of those copies also inherited the same latent
7// bugs (the ff_putn no-write class, the missing self-mkdir) precisely because they were copies. This organ
8// is the one body they should all have called: URL and destination are ARGUMENTS, not source edits.
9//
10// nx_bench_fetch <url> <outpath> [force]
11// outpath MUST be under knowledge/fetched/ or /tmp/ (boundary defense, rule 12)
12// idempotent: an existing outpath is a HAVE-SKIP unless `force` is passed
13// prints: status=<http> bytes=<n> SAVED | HAVE-SKIP | FETCH-FAIL | SAVE-FAIL | GZIP-skip
14// exit 0 saved-or-skipped | 2 usage/denied | 3 fetch failed
15//
16// SELF-MKDIRS knowledge/fetched (rule 20: a tool that needs a dir makes it -- the missing-dir bug that
17// silently SAVE-FAIL'd 119 organs, seq191).
18// license_tier: ORIGINAL No hw writes (Rule 26). expect_exit: 0
19import "nx_syscalls.nx"
20import "nx_x509_trust_store.nx"
21import "nx_trust_store_load_from_certdata.nx"
22import "nx_https_fetch_follow.nx"
23
24const BF_CAP: i64 = 8388608
25const BF_ROOTS_MAX: i64 = 512
26const BF_CERTBUF: i64 = 4194304
27const BF_HOPS: i64 = 6
28const BF_MODE: i64 = 0x1a4
29const BF_DMODE: i64 = 0x1ed
30const BF_MKDIRAT: i64 = 258
31const BF_ATFDCWD: i64 = 0 - 100
32const BF_D0: i64 = 48
33const BF_B10: i64 = 10
34const BF_NUMB: i64 = 24
35const BF_STDERR: i64 = 2
36const BF_EXIT_USAGE: i64 = 2
37const BF_EXIT_FETCH: i64 = 3
38const BF_ARGC_MIN: i64 = 3
39const BF_ARGC_FORCE: i64 = 4
40
41func bf_slen(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } return n }
42func bf_w(s: *u8) -> i64 { sys_write(1, s, bf_slen(s)); return 0 }
43func bf_werr(s: *u8) -> i64 { sys_write(BF_STDERR, s, bf_slen(s)); return 0 }
44func bf_wn(v: i64) -> i64 {
45 if v == 0 { sys_write(1, "0" as *u8, 1); return 0 }
46 var m: i64 = v
47 if m < 0 { sys_write(1, "-" as *u8, 1); m = 0 - m }
48 let d: *u8 = sys_mmap(BF_NUMB)
49 var k: i64 = 0
50 while m > 0 { d[k] = (BF_D0 + (m % BF_B10)) as u8; m = m / BF_B10; k = k + 1 }
51 let o: *u8 = sys_mmap(BF_NUMB)
52 var i: i64 = 0
53 while i < k { o[i] = d[k - 1 - i]; i = i + 1 }
54 sys_write(1, o, k)
55 return 0
56}
57// does s start with pfx?
58func bf_pfx(s: *u8, pfx: *u8) -> i64 {
59 var i: i64 = 0
60 while pfx[i] != (0 as u8) { if s[i] != pfx[i] { return 0 } i = i + 1 }
61 return 1
62}
63func bf_has(s: *u8, sub: *u8) -> i64 {
64 let n: i64 = bf_slen(s)
65 let m: i64 = bf_slen(sub)
66 if m == 0 { return 0 }
67 var i: i64 = 0
68 while i + m <= n {
69 var j: i64 = 0
70 var ok: i64 = 1
71 while j < m { if s[i+j] != sub[j] { ok = 0; j = m } else { j = j + 1 } }
72 if ok == 1 { return 1 }
73 i = i + 1
74 }
75 return 0
76}
77func bf_exists(p: *u8) -> i64 {
78 let fd: i64 = sys_openat_rd(p)
79 if fd < 0 { return 0 }
80 sys_close(fd)
81 return 1
82}
83func bf_mkdir(p: *u8) -> i64 { return __syscall(BF_MKDIRAT, BF_ATFDCWD, p as i64, BF_DMODE, 0, 0, 0) }
84
85func main(argc: i64, argv: *i64) -> i64 {
86 if argc < BF_ARGC_MIN { bf_werr("usage: nx_bench_fetch <url> <outpath-under-knowledge/fetched-or-/tmp> [force]\n" as *u8); sys_exit(BF_EXIT_USAGE); return BF_EXIT_USAGE }
87 let url: *u8 = argv[1] as *u8
88 let outp: *u8 = argv[2] as *u8
89 var force: i64 = 0
90 if argc >= BF_ARGC_FORCE { force = 1 }
91
92 // BOUNDARY DEFENSE (rule 12): destination is confined, traversal refused by construction.
93 if bf_has(outp, ".." as *u8) == 1 { bf_werr("BF-REFUSED traversal in outpath\n" as *u8); sys_exit(BF_EXIT_USAGE); return BF_EXIT_USAGE }
94 var okdst: i64 = 0
95 if bf_pfx(outp, "knowledge/fetched/" as *u8) == 1 { okdst = 1 }
96 if bf_pfx(outp, "/tmp/" as *u8) == 1 { okdst = 1 }
97 if okdst == 0 { bf_werr("BF-REFUSED outpath must be under knowledge/fetched/ or /tmp/\n" as *u8); sys_exit(BF_EXIT_USAGE); return BF_EXIT_USAGE }
98 // only https is fetchable (the sovereign client is TLS-only by construction)
99 if bf_pfx(url, "https://" as *u8) == 0 { bf_werr("BF-REFUSED url must be https://\n" as *u8); sys_exit(BF_EXIT_USAGE); return BF_EXIT_USAGE }
100
101 bf_mkdir("knowledge" as *u8)
102 bf_mkdir("knowledge/fetched" as *u8)
103
104 if force == 0 { if bf_exists(outp) == 1 { bf_w(outp); bf_w(" HAVE-SKIP (pass `force` to refetch)\n" as *u8); sys_exit(0); return 0 } }
105
106 let r: i64 = nx_trust_store_load_from_certdata("data/mozilla_certdata.txt" as *u8, BF_ROOTS_MAX, BF_CERTBUF)
107 if r <= 0 { bf_werr("BF-FAIL certdata load failed (need data/mozilla_certdata.txt in cwd)\n" as *u8); sys_exit(BF_EXIT_FETCH); return BF_EXIT_FETCH }
108 let store: *TrustStore = r as *TrustStore
109 let out: *u8 = sys_mmap(BF_CAP)
110 let status: *i64 = sys_mmap(8) as *i64
111 let n: i64 = nx_https_fetch_follow(url, store, out, BF_CAP, BF_HOPS, status)
112 bf_w(url)
113 bf_w(" status=" as *u8)
114 bf_wn(status[0])
115 bf_w(" bytes=" as *u8)
116 bf_wn(n)
117 if n <= 0 { bf_w(" FETCH-FAIL\n" as *u8); sys_exit(BF_EXIT_FETCH); return BF_EXIT_FETCH }
118 var gz: i64 = 0
119 if n >= 2 { if out[0] == 0x1f as u8 { if out[1] == 0x8b as u8 { gz = 1 } } }
120 if gz == 1 { bf_w(" GZIP-skip (body is gzip; sovereign client requested identity)\n" as *u8); sys_exit(BF_EXIT_FETCH); return BF_EXIT_FETCH }
121 let fd: i64 = sys_openat_wr(outp, BF_MODE)
122 if fd < 0 { bf_w(" SAVE-FAIL\n" as *u8); sys_exit(BF_EXIT_FETCH); return BF_EXIT_FETCH }
123 sys_write(fd, out, n)
124 sys_close(fd)
125 bf_w(" SAVED -> " as *u8)
126 bf_w(outp)
127 bf_w("\n" as *u8)
128 sys_exit(0)
129 return 0
130}