code wiki / (root) / nx_http_backend_gate_t314.nx

nx_http_backend_gate_t314.nx source

↩ module page · 71 lines · 4955 B

1// nx_http_backend_gate_t314.nx -- Tests HTTP response parsing and body handling with various content-length and transfer-encoding scenarios. 2import "nx_tool_http_backend_candidate_t314.nx" 3import "nx_itoa_lib.nx" 4static tg_ok:i64 5static tg_all:i64 6func tg_check(name:*u8,good:i64)->i64 { tg_all=tg_all+1;if good==1 {tg_ok=tg_ok+1;sys_write(1,"PASS " as *u8,5)}else{sys_write(1,"FAIL " as *u8,5)}sys_write(1,name,thb_slen(name));sys_write(1,"\n" as *u8,1);return good } 7func tg_parse(name:*u8,src:*u8,want:i64,body:i64)->i64 { 8 var out:i64=0;var code:i64=0;var len:i64=0 9 let r:i64=nx_http_response_complete(src,thb_slen(src),(&out) as *u8,__size_of(i64),&code,&len) 10 var good:i64=0;if r==want {if want!=0 {good=1}else{if len==body {good=1}}} 11 return tg_check(name,good) 12} 13func tg_exchange(lfd:i64,port:i64,reply:*u8,delay:i64,budget:i64,expect:i64,name:*u8)->i64 { 14 let pid:i64=sys_fork() 15 if pid<0 { return tg_check(name,0) } 16 if pid==0 { 17 let fd:i64=sys_accept(lfd);sys_close(lfd) 18 if fd<0 {sys_exit(2);return 2} 19 let b:*u8=sys_mmap(4096) 20 sys_set_socket_timeout(fd,2) 21 let rn:i64=sys_read(fd,b,4096) 22 if rn<=0 {sys_close(fd);sys_exit(3);return 3} 23 if delay>0 {sys_sleep_ms(delay)} 24 let fl:i64=nx_fcntl(fd,NX_F_GETFL,0);nx_fcntl(fd,NX_F_SETFL,fl|NX_O_NONBLOCK) 25 var written:i64=0;fb_send_until(fd,reply,thb_slen(reply),sys_now_ms()+2000,&written) 26 sys_close(fd);sys_exit(0);return 0 27 } 28 var e:NxHttpBackendEvidence 29 let raw:*u8=sys_mmap(4096) 30 let out:*u8=sys_mmap(4096) 31 let req:*u8="GET /fixture HTTP/1.0\r\nHost: localhost\r\nConnection: close\r\n\r\n" as *u8 32 let deadline:i64=sys_now_ms()+budget 33 var result:i64=thb_fetch_result("127.0.0.1" as *u8,9,port,req,thb_slen(req),raw,4096,deadline,&e) 34 if result==THB_OK {result=thb_body_result(raw,e.received_bytes,out,4096,&e)} 35 var ws:i64=0;let reaped:i64=sys_wait4(pid,&ws,0) 36 var good:i64=0;if result==expect {if reaped==pid {if ws==0 {good=1}}} 37 tg_check(name,good) 38 sys_write(1,"evidence state=" as *u8,15);nxi_out(result);sys_write(1," stage=" as *u8,7);nxi_out(e.stage);sys_write(1," status=" as *u8,8);nxi_out(e.http_status);sys_write(1," elapsed_ms=" as *u8,12);nxi_out(e.end_ms-e.begin_ms);sys_write(1," bytes=" as *u8,7);nxi_out(e.received_bytes);sys_write(1," reaped=" as *u8,8);nxi_out(reaped==pid);sys_write(1,"\n" as *u8,1) 39 return good 40} 41func main(argc:i64,av:*i64)->i64 { 42 tg_parse("complete-length","HTTP/1.1 200 OK\r\nContent-Length: 5\r\n\r\nhello" as *u8,0,5) 43 tg_parse("truncated-length","HTTP/1.1 200 OK\r\nContent-Length: 6\r\n\r\nhello" as *u8,8,0) 44 tg_parse("excess-length","HTTP/1.1 200 OK\r\nContent-Length: 4\r\n\r\nhello" as *u8,8,0) 45 tg_parse("bad-length","HTTP/1.1 200 OK\r\nContent-Length: 5x\r\n\r\nhello" as *u8,9,0) 46 tg_parse("length-overflow","HTTP/1.1 200 OK\r\nContent-Length: 9223372036854775808\r\n\r\n" as *u8,9,0) 47 tg_parse("duplicate-equal","HTTP/1.1 200 OK\r\nContent-Length: 5\r\nContent-Length: 5\r\n\r\nhello" as *u8,0,5) 48 tg_parse("duplicate-conflict","HTTP/1.1 200 OK\r\nContent-Length: 5\r\nContent-Length: 4\r\n\r\nhello" as *u8,9,0) 49 tg_parse("te-cl","HTTP/1.1 200 OK\r\nContent-Length: 0\r\nTransfer-Encoding: chunked\r\n\r\n0\r\n\r\n" as *u8,9,0) 50 tg_parse("chunked","HTTP/1.1 200 OK\r\nTransfer-Encoding: chunked\r\n\r\n5\r\nhello\r\n0\r\n\r\n" as *u8,0,5) 51 tg_parse("chunk-trailer-missing","HTTP/1.1 200 OK\r\nTransfer-Encoding: chunked\r\n\r\n0\r\n" as *u8,8,0) 52 tg_parse("chunk-trailing-extra","HTTP/1.1 200 OK\r\nTransfer-Encoding: chunked\r\n\r\n0\r\n\r\nx" as *u8,9,0) 53 tg_parse("unknown-encoding","HTTP/1.1 200 OK\r\nContent-Encoding: gzip\r\n\r\nx" as *u8,10,0) 54 tg_parse("missing-colon-line","HTTP/1.1 200 OK\r\nBad\r\nContent-Length: 0\r\n\r\n" as *u8,6,0) 55 tg_parse("closed-body","HTTP/1.0 200 OK\r\n\r\nhello" as *u8,0,5) 56 if argc!=2 {sys_write(1,"port argument required\n" as *u8,23);return 2} 57 let port:i64=thb_atoi(av[1] as *u8,0,thb_slen(av[1] as *u8)) 58 let lfd:i64=sys_socket(2,1,0);if lfd<0 {return 3} 59 let addr:*u8=sys_mmap(16);thb_sockaddr(addr,port,127,0,0,1) 60 if sys_bind(lfd,addr,16)<0 {sys_close(lfd);return 4} 61 if sys_listen(lfd,1)<0 {sys_close(lfd);return 5} 62 tg_exchange(lfd,port,"HTTP/1.1 200 OK\r\nContent-Length: 5\r\n\r\nhello" as *u8,0,2000,THB_OK,"loopback-success") 63 tg_exchange(lfd,port,"HTTP/1.1 200 OK\r\nContent-Length: 5\r\n\r\nhello" as *u8,50,2000,THB_OK,"loopback-delayed") 64 tg_exchange(lfd,port,"HTTP/1.1 200 OK\r\nContent-Length: 5\r\n\r\nhello" as *u8,200,50,THB_TIMEOUT,"loopback-deadline") 65 tg_exchange(lfd,port,"HTTP/1.1 503 Busy\r\nContent-Length: 0\r\n\r\n" as *u8,0,2000,THB_UPSTREAM,"loopback-non2xx") 66 tg_exchange(lfd,port,"HTTP/1.1 200 OK\r\nContent-Length: 9\r\n\r\nhello" as *u8,0,2000,THB_FRAMING,"loopback-truncated") 67 tg_exchange(lfd,port,"garbage\r\n\r\n" as *u8,0,2000,THB_FRAMING,"loopback-malformed") 68 sys_close(lfd) 69 sys_write(1,"RESULT " as *u8,7);nxi_out(tg_ok);sys_write(1,"/" as *u8,1);nxi_out(tg_all);sys_write(1,"\n" as *u8,1) 70 if tg_ok!=tg_all {return 1}return 0 71}