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}