code wiki / _hdl_build / nx_sovgit_serve.nx
nx_sovgit_serve.nx source
↩ module page · 103 lines · 6010 B
1// nx_sovgit_serve.nx -- ★SOVGIT rung X1c: a minimal SOVEREIGN HTTP server (built on nx_http_server sockets, NO nginx/
2// framework) that serves our bare git repo over git's DUMB-HTTP protocol, so a STOCK `git clone http://HOST:18690/`
3// round-trips over the NETWORK. On startup it assembles the repo (X0 objects + refs + HEAD + config + dumb info/refs +
4// objects/info/packs), then accept-loops serving files statically. Reuses nx_sovgit_obj (X0/X1a). Runs forever (a test
5// harness launches it in the background, clones, then kills it). license_tier: ORIGINAL
6import "nx_sovgit_obj.nx"
7import "nx_http_server.nx"
8const K_MAGIC_18690: i64 = 18690
9const K_MAGIC_65536: i64 = 65536
10const K_MAGIC_262144: i64 = 262144
11
12func lg(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } sys_write(2, s, n); return 0 }
13func scopy(dst: *u8, at: i64, s: *u8) -> i64 { var i: i64 = 0; while s[i] != (0 as u8) { dst[at + i] = s[i]; i = i + 1 } return at + i }
14func udec(out: *u8, at: i64, v: i64) -> i64 {
15 let tmp: *u8 = sys_mmap(32); var x: i64 = v; var i: i64 = 31
16 if x == 0 { tmp[i] = 48 as u8; i = i - 1 }
17 while x > 0 { tmp[i] = (48 + x % 10) as u8; x = x / 10; i = i - 1 }
18 var a: i64 = at; var j: i64 = i + 1; while j < 32 { out[a] = tmp[j]; a = a + 1; j = j + 1 } return a
19}
20func wfile(path: *u8, buf: *u8, n: i64) -> i64 { let fd: i64 = sys_openat_wr(path, 0x1a4); if fd < 0 { return 0 - 1 } sys_write(fd, buf, n); sys_close(fd); return 0 }
21func wstr(path: *u8, s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } return wfile(path, s, n) }
22
23func assemble_repo() -> i64 {
24 sys_mkdir("knowledge/_sovgit_repo" as *u8, 0x1ed)
25 sys_mkdir("knowledge/_sovgit_repo/refs" as *u8, 0x1ed)
26 sys_mkdir("knowledge/_sovgit_repo/refs/heads" as *u8, 0x1ed)
27 sys_mkdir("knowledge/_sovgit_repo/info" as *u8, 0x1ed)
28 let objroot: *u8 = "knowledge/_sovgit_repo/objects" as *u8
29 let bhex: *u8 = sys_mmap(80); sg_write_loose(objroot, "blob" as *u8, "hello" as *u8, 5, bhex)
30 let raw: *u8 = sys_mmap(32); sg_oid_raw("blob" as *u8, "hello" as *u8, 5, raw)
31 let tree: *u8 = sys_mmap(128); let tlen: i64 = sg_tree_entry(tree, 0, "100644" as *u8, "hello.txt" as *u8, raw)
32 let thex: *u8 = sys_mmap(80); sg_write_loose(objroot, "tree" as *u8, tree, tlen, thex)
33 let cbody: *u8 = "tree 06d48a30caf6b4263876dbc71cec3bedfa08df79a4a59d55fbb9ea106a1ecc9c\nauthor t <t@t> 1700000000 +0000\ncommitter t <t@t> 1700000000 +0000\n\nmsg\n" as *u8
34 let clen: i64 = sg_slen(cbody)
35 let chex: *u8 = sys_mmap(80); sg_write_loose(objroot, "commit" as *u8, cbody, clen, chex)
36 let mref: *u8 = sys_mmap(80); var mo: i64 = sg_cpy(mref, 0, chex, 0, 64); mref[mo] = 10 as u8; mo = mo + 1
37 wfile("knowledge/_sovgit_repo/refs/heads/master" as *u8, mref, mo)
38 wstr("knowledge/_sovgit_repo/HEAD" as *u8, "ref: refs/heads/master\n" as *u8)
39 wstr("knowledge/_sovgit_repo/config" as *u8, "[core]\n repositoryformatversion = 1\n bare = true\n[extensions]\n objectformat = sha256\n" as *u8)
40 // dumb info/refs: <commit-hex>\trefs/heads/master\n
41 let ir: *u8 = sys_mmap(96); var io: i64 = sg_cpy(ir, 0, chex, 0, 64); ir[io] = 9 as u8; io = io + 1
42 io = scopy(ir, io, "refs/heads/master" as *u8); ir[io] = 10 as u8; io = io + 1
43 wfile("knowledge/_sovgit_repo/info/refs" as *u8, ir, io)
44 sys_mkdir("knowledge/_sovgit_repo/objects/info" as *u8, 0x1ed)
45 wstr("knowledge/_sovgit_repo/objects/info/packs" as *u8, "\n" as *u8)
46 return 0
47}
48
49// serve repo/<relpath> (relpath from req buffer, len rlen, starts with '/', may carry a ?query) to cfd.
50func serve(cfd: i64, relpath: *u8, rlen: i64, resp: *u8) -> i64 {
51 let fp: *u8 = sys_mmap(512)
52 var fo: i64 = scopy(fp, 0, "knowledge/_sovgit_repo" as *u8)
53 var i: i64 = 0; var bad: i64 = 0
54 while i < rlen {
55 let c: i64 = relpath[i] as i64
56 if c == 63 { i = rlen } else {
57 if c == 46 { if i + 1 < rlen { if relpath[i + 1] == (46 as u8) { bad = 1 } } }
58 fp[fo] = relpath[i]; fo = fo + 1; i = i + 1
59 }
60 }
61 fp[fo] = 0 as u8
62 var ro: i64 = 0
63 if bad == 1 { ro = scopy(resp, 0, "HTTP/1.1 400 Bad Request\r\nContent-Length: 0\r\nConnection: close\r\n\r\n" as *u8) } else {
64 let szp: *i64 = sys_mmap(16) as *i64
65 let body: *u8 = sys_read_file(fp, szp)
66 if (body as i64) == 0 { ro = scopy(resp, 0, "HTTP/1.1 404 Not Found\r\nContent-Length: 0\r\nConnection: close\r\n\r\n" as *u8) } else {
67 let n: i64 = szp[0]
68 ro = scopy(resp, 0, "HTTP/1.1 200 OK\r\nContent-Type: application/octet-stream\r\nContent-Length: " as *u8)
69 ro = udec(resp, ro, n)
70 ro = scopy(resp, ro, "\r\nConnection: close\r\n\r\n" as *u8)
71 ro = sg_cpy(resp, ro, body, 0, n)
72 }
73 }
74 nx_http_server_send_response(cfd, resp, ro)
75 return 0
76}
77
78func main() -> i64 {
79 assemble_repo()
80 lg("nx_sovgit_serve: repo assembled (knowledge/_sovgit_repo)\n" as *u8)
81 let addr: *u8 = sys_mmap(16); nx_http_server_addr_any(addr, K_MAGIC_18690)
82 let ov: *i64 = sys_mmap(16) as *i64
83 let lfd: i64 = nx_http_server_listen(addr, 16, ov)
84 if lfd < 0 { lg("nx_sovgit_serve: LISTEN FAILED\n" as *u8); sys_exit(1); return 1 }
85 lg("nx_sovgit_serve: listening 0.0.0.0:18690 (git dumb-HTTP)\n" as *u8)
86 let req: *u8 = sys_mmap(K_MAGIC_65536)
87 let resp: *u8 = sys_mmap(K_MAGIC_262144)
88 let om: *i64 = sys_mmap(16) as *i64
89 let opo: *i64 = sys_mmap(16) as *i64
90 let opl: *i64 = sys_mmap(16) as *i64
91 let ocl: *i64 = sys_mmap(16) as *i64
92 let obo: *i64 = sys_mmap(16) as *i64
93 let orn: *i64 = sys_mmap(16) as *i64
94 var run: i64 = 1
95 while run == 1 {
96 let cfd: i64 = nx_http_server_accept_one(lfd, ov)
97 if cfd >= 0 {
98 let rc: i64 = nx_http_server_read_request(cfd, req, K_MAGIC_65536, om, opo, opl, ocl, obo, orn)
99 if rc == 0 { serve(cfd, (req as i64 + opo[0]) as *u8, opl[0], resp) } else { sys_close(cfd) }
100 }
101 }
102 return 0
103}