code wiki / _hdl_build / nx_email_webmail_gate.nx

nx_email_webmail_gate.nx source

↩ module page · 157 lines · 6309 B

1// nx_email_webmail_gate.nx -- LIVE: the webmail UI over a real HTTP socket. 2// 3// Seeds the R3 store with 2 messages for self@jasonewest.com, then fork: 4// parent = the webmail server (nx_webmail_serve_conn over accept), child = 5// a real HTTP/1.1 client making 3 GETs: 6// 1. GET / -> HTML lists BOTH subjects ("Welcome" + "Second Note") 7// 2. GET /del?n=0 -> redraw NO LONGER shows "Welcome" (soft-deleted) 8// 3. GET / -> still no "Welcome", still "Second Note" 9// Then the parent verifies the store: message #0 tombstoned, #1 live. 10// 11// Evidence -> knowledge/status/webmail.log (WEBMAILGATE ... verdict=GREEN) 12// license_tier: ORIGINAL 13import "nx_email_webmail.nx" 14import "nx_connect.nx" // bounded connect: a raw sys_connect hangs ~127s on a black-holed host 15import "nx_syscalls.nx" 16 17const WM_PORT: i64 = 0x2555 18const WM_LOG: *u8 = "knowledge/status/webmail.log" 19const WM_PREFIX: *u8 = "knowledge/status/wmail/" 20const WM_BOX: *u8 = "self@jasonewest.com" 21 22func g_addr(out: *u8, port: i64) -> i64 { 23 out[0] = 2 as u8; out[1] = 0 as u8 24 out[2] = ((port >> 8) & 0xff) as u8; out[3] = (port & 0xff) as u8 25 out[4] = 127 as u8; out[5] = 0 as u8; out[6] = 0 as u8; out[7] = 1 as u8 26 var i: i64 = 8 27 while i < 16 { out[i] = 0 as u8; i = i + 1 } 28 return 0 29} 30func g_writes(fd: i64, s: *u8) -> i64 { 31 var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } 32 var w: i64 = 0 33 while w < n { let k: i64 = sys_write(fd, (s as i64 + w) as *u8, n - w); if k <= 0 { return 0 - 1 } w = w + k } 34 return 0 35} 36func slen(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } return n } 37func contains(hay: *u8, hlen: i64, needle: *u8) -> i64 { 38 let nl: i64 = slen(needle) 39 var i: i64 = 0 40 while i + nl <= hlen { 41 var k: i64 = 0; var hit: i64 = 1 42 while k < nl { if (hay[i + k] & 0xff) != (needle[k] & 0xff) { hit = 0; k = nl } else { k = k + 1 } } 43 if hit == 1 { return 1 } 44 i = i + 1 45 } 46 return 0 47} 48// one HTTP GET; reads the whole response (Connection: close) into out. len. 49func http_get(addr: *u8, path: *u8, out: *u8, cap: i64) -> i64 { 50 let cfd: i64 = sys_socket(AF_INET, SOCK_STREAM, 0) 51 if cfd < 0 { return 0 - 1 } 52 if nx_connect_bounded(cfd, addr, 16, NX_CONN_DEFAULT_MS) < 0 { return 0 - 2 } 53 g_writes(cfd, "GET " as *u8) 54 g_writes(cfd, path) 55 g_writes(cfd, " HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n\r\n" as *u8) 56 var n: i64 = 0 57 while n < cap - 1 { 58 let r: i64 = sys_read(cfd, (out as i64 + n) as *u8, cap - 1 - n) 59 if r <= 0 { n = n } else { n = n + r } 60 if r <= 0 { sys_close(cfd); return n } 61 } 62 sys_close(cfd) 63 return n 64} 65 66func g_run_client(addr: *u8) -> i64 { 67 var spin: i64 = 0 68 while spin < 400000 { spin = spin + 1 } 69 let buf: *u8 = sys_mmap(262144) 70 // 1. inbox shows both 71 let n1: i64 = http_get(addr, "/" as *u8, buf, 262144) 72 if n1 <= 0 { return 11 } 73 if contains(buf, n1, "Welcome" as *u8) != 1 { return 12 } 74 if contains(buf, n1, "Second Note" as *u8) != 1 { return 13 } 75 // 2. delete #0 76 let n2: i64 = http_get(addr, "/del?n=0" as *u8, buf, 262144) 77 if n2 <= 0 { return 14 } 78 if contains(buf, n2, "Welcome" as *u8) != 0 { return 15 } // gone 79 if contains(buf, n2, "Second Note" as *u8) != 1 { return 16 } // remains 80 // 3. inbox redraw confirms 81 let n3: i64 = http_get(addr, "/" as *u8, buf, 262144) 82 if n3 <= 0 { return 17 } 83 if contains(buf, n3, "Welcome" as *u8) != 0 { return 18 } 84 if contains(buf, n3, "Second Note" as *u8) != 1 { return 19 } 85 return 0 86} 87 88func main() -> i64 { 89 sys_mkdir("knowledge/status/wmail" as *u8, 511) 90 let rfd: i64 = sys_openat_wr("knowledge/status/wmail/manifest.txt" as *u8, 420) 91 if rfd >= 0 { sys_close(rfd) } 92 93 // seed two messages 94 let m0: *u8 = "Subject: Welcome\r\nFrom: ops@jasonewest.com\r\n\r\nWelcome to Nishi Mail.\r\n" as *u8 95 let m1: *u8 = "Subject: Second Note\r\nFrom: alice@remote.test\r\n\r\nSecond message body here.\r\n" as *u8 96 nx_mbox_append(WM_PREFIX, WM_BOX, m0, slen(m0), 1) 97 nx_mbox_append(WM_PREFIX, WM_BOX, m1, slen(m1), 2) 98 99 let segctr: *i64 = sys_mmap(8) as *i64 100 segctr[0] = 100 101 102 let addr: *u8 = sys_mmap(16) 103 g_addr(addr, WM_PORT) 104 let lfd: i64 = sys_socket(AF_INET, SOCK_STREAM, 0) 105 if lfd < 0 { sys_exit(93); return 93 } 106 if sys_bind(lfd, addr, 16) < 0 { sys_exit(94); return 94 } 107 if sys_listen(lfd, 8) < 0 { sys_exit(95); return 95 } 108 109 let pid: i64 = sys_fork() 110 if pid < 0 { sys_exit(96); return 96 } 111 if pid == 0 { 112 let crc: i64 = g_run_client(addr) 113 sys_exit(crc); return crc 114 } 115 116 // parent serves 3 connections 117 var served: i64 = 0 118 while served < 3 { 119 let scfd: i64 = sys_accept(lfd) 120 if scfd < 0 { served = 3 } else { 121 nx_webmail_serve_conn(scfd, WM_PREFIX, WM_BOX, segctr) 122 sys_close(scfd) 123 served = served + 1 124 } 125 } 126 127 let status: *i64 = sys_mmap(8) as *i64 128 sys_wait4(pid, status, 0) 129 let child_code: i64 = (status[0] >> 8) & 0xff 130 131 // verify store: #0 tombstoned, #1 live 132 let pp: *i64 = sys_mmap(8) as *i64 133 let ll: *i64 = sys_mmap(8) as *i64 134 let g0: i64 = nx_mbox_get_n(WM_PREFIX, WM_BOX, 0, pp, ll) 135 let g1: i64 = nx_mbox_get_n(WM_PREFIX, WM_BOX, 1, pp, ll) 136 var store_ok: i64 = 0 137 if g0 == 0 && g1 == 1 { store_ok = 1 } 138 139 var green: i64 = 0 140 if child_code == 0 && store_ok == 1 { green = 1 } 141 142 var fd: i64 = 1 143 while fd >= 1 { 144 g_writes(fd, "WEBMAILGATE authored=organ http=loopback mailbox=self@jasonewest.com " as *u8) 145 if child_code == 0 { g_writes(fd, "list_shows_both=PASS delete_works=PASS redraw_reflects_delete=PASS " as *u8) } 146 else { g_writes(fd, "client_checks=FAIL " as *u8) } 147 if store_ok == 1 { g_writes(fd, "store_tombstoned=PASS " as *u8) } else { g_writes(fd, "store_tombstoned=FAIL " as *u8) } 148 if green == 1 { g_writes(fd, "verdict=GREEN\n" as *u8) } else { g_writes(fd, "verdict=RED\n" as *u8) } 149 if fd == 1 { 150 let lf: i64 = sys_openat_append(WM_LOG, 420) 151 if lf >= 1 { fd = lf } else { fd = 0 } 152 } else { sys_close(fd); fd = 0 } 153 } 154 155 if green == 1 { sys_exit(0); return 0 } 156 sys_exit(1); return 1 157}