code wiki / (root) / nx_mgmt_private_response_candidate_t189.nx

nx_mgmt_private_response_candidate_t189.nx source

↩ module page · 137 lines · 7595 B

1// Private response handoff used by nx_mgmt_call; never emits upstream body bytes. 2// Trusted parent directory; exclusive pending name serializes cooperating callers. 3// Does not claim hostile-directory race resistance or crash-orphan recovery. 4import "nx_fio.nx" 5const MPR_NOENT:i64=0-2 6const MPR_BAD_RESPONSE:i64=0-74 7struct NxMgmtPrivateResponse{ 8 path:*u8,tmp:*u8,parent:*u8,allocation:i64,fd:i64,dirfd:i64, 9 code:i64,status:i64,sent:i64,visible:i64,durable:i64,body_bytes:i64, 10 owned:i64,dev:i64,ino:i64,stage:*u8, 11 stat:*u8,write:*NxFileWriteResult, 12} 13func mpr_len(s:*u8)->i64{var n:i64=0;while s[n]!=(0 as u8){n=n+1};return n} 14func mpr_word(s:*u8,o:i64)->i64{return *((s+o) as *i64)} 15func mpr_init(r:*NxMgmtPrivateResponse)->i64{ 16 r.path=0 as *u8;r.tmp=0 as *u8;r.parent=0 as *u8;r.allocation=0;r.fd=0-1;r.dirfd=0-1 17 r.code=0;r.status=0;r.sent=0;r.visible=0;r.durable=0;r.body_bytes=0;r.owned=0;r.dev=0;r.ino=0 18 r.stage="input";r.stat=0 as *u8;r.write=0 as *NxFileWriteResult;return 0 19} 20// Any existing final entry (including symlink/FIFO) is occupied. Nonblocking, 21// no-follow inspection cannot be trapped waiting on a FIFO or dangling symlink. 22func mpr_absent(path:*u8)->i64{ 23 let fd:i64=__syscall(SYS_OPENAT,AT_FDCWD,path,O_RDONLY|O_NONBLOCK|O_NOFOLLOW|O_CLOEXEC,0,0,0) 24 if fd>=0{let closed:i64=sys_close(fd);if closed!=0{return closed};return FIO_EEXIST} 25 if fd==MPR_NOENT{return 0};return fd 26} 27func mpr_begin(path:*u8,r:*NxMgmtPrivateResponse)->i64{ 28 mpr_init(r);r.path=path 29 if (path as i64)==0{return FIO_EINVAL} 30 let n:i64=mpr_len(path);if n<=0||n>(9223372036854775807-NX_STAT_X64_BYTES-__size_of(NxFileWriteResult))/2-17{return FIO_EINVAL} 31 r.code=mpr_absent(path);if r.code!=0{r.stage="destination-occupied-or-unreadable";return r.code} 32 let path_capacity:i64=((n+17)/8)*8 33 r.allocation=path_capacity*2+NX_STAT_X64_BYTES+__size_of(NxFileWriteResult) 34 r.tmp=sys_mmap_try(r.allocation) 35 if (r.tmp as i64)<=0{r.tmp=0 as *u8;r.code=0-12;r.stage="private-workspace";return r.code} 36 r.parent=r.tmp+path_capacity;r.stat=r.parent+path_capacity;r.write=(r.stat+NX_STAT_X64_BYTES) as *NxFileWriteResult 37 let suffix:*u8=".pending";var i:i64=0;var slash:i64=0-1 38 while i<n{r.tmp[i]=path[i];if path[i]==47 as u8{slash=i};i=i+1} 39 var j:i64=0;while suffix[j]!=(0 as u8){r.tmp[n+j]=suffix[j];j=j+1};r.tmp[n+j]=0 as u8 40 if slash<0{r.parent[0]=46 as u8;r.parent[1]=0 as u8}else{ 41 var end:i64=slash;if end==0{end=1};i=0;while i<end{r.parent[i]=path[i];i=i+1};r.parent[end]=0 as u8 42 } 43 r.stage="private-parent";r.dirfd=sys_openat_directory(r.parent) 44 if r.dirfd<0{r.code=r.dirfd;return r.code} 45 r.stage="private-reserve";r.fd=sys_openat_exclusive(r.tmp,MODE_0600) 46 if r.fd<0{r.code=r.fd;return r.code};r.owned=1 47 r.code=sys_fstat_fd(r.fd,r.stat) 48 if r.code==0{ 49 r.dev=mpr_word(r.stat,NX_STAT_X64_DEVICE_OFFSET);r.ino=mpr_word(r.stat,NX_STAT_X64_INODE_OFFSET) 50 if sys_stat_permissions(r.stat)!=MODE_0600{r.code=0-13} 51 } 52 return r.code 53} 54func mpr_cleanup(r:*NxMgmtPrivateResponse)->i64{ 55 if r.fd>=0{let rc:i64=sys_close(r.fd);r.fd=0-1;if r.code==0&&rc!=0{r.code=rc}} 56 if r.owned==1&&r.visible==0{ 57 let st:i64=sys_fstatat(r.tmp,r.stat) 58 if st==0&&mpr_word(r.stat,NX_STAT_X64_DEVICE_OFFSET)==r.dev&&mpr_word(r.stat,NX_STAT_X64_INODE_OFFSET)==r.ino{ 59 let rc:i64=fio_unlink(r.tmp);if rc==0{r.owned=0}else{if r.code==0{r.code=rc}} 60 } 61 } 62 if r.dirfd>=0{let rc:i64=sys_close(r.dirfd);r.dirfd=0-1;if r.code==0&&rc!=0{r.code=rc}} 63 if (r.tmp as i64)>0{let rc:i64=sys_munmap_direct(r.tmp,r.allocation);r.tmp=0 as *u8;if r.code==0&&rc!=0{r.code=rc}} 64 return r.code 65} 66func mpr_eq(b:*u8,n:i64,s:*u8)->i64{ 67 if n!=mpr_len(s){return 0};var i:i64=0 68 while i<n{var a:i64=b[i] as i64;var c:i64=s[i] as i64;if a>=65&&a<=90{a=a+32};if c>=65&&c<=90{c=c+32};if a!=c{return 0};i=i+1};return 1 69} 70func mpr_decimal(b:*u8,n:i64)->i64{ 71 if n<=0{return 0-1};var v:i64=0;var i:i64=0 72 while i<n{let d:i64=(b[i] as i64)-48;if d<0||d>9||v>(9223372036854775807-d)/10{return 0-1};v=v*10+d;i=i+1};return v 73} 74// Exact Content-Length response only. Unsupported transfer encoding, duplicate 75// length, incomplete capture and malformed status fail without publishing a body. 76func mpr_body(b:*u8,n:i64,capacity:i64,r:*NxMgmtPrivateResponse)->i64{ 77 r.stage="http-framing";r.code=MPR_BAD_RESPONSE 78 if n<13||n>=capacity{return r.code} 79 if mpr_eq(b,7,"HTTP/1.")!=1||(b[7]!=48 as u8&&b[7]!=49 as u8)||b[8]!=32 as u8||b[12]!=32 as u8{return r.code} 80 let status:i64=mpr_decimal(b+9,3);if status<100||status>599{return r.code};r.status=status 81 var p:i64=0 82 while p+1<n{if b[p]==13 as u8&&b[p+1]==10 as u8{break};p=p+1} 83 if p+1>=n{return r.code};p=p+2 84 var length:i64=0-1;var body:i64=0-1 85 while p+1<n{ 86 if b[p]==13 as u8&&b[p+1]==10 as u8{body=p+2;break} 87 var end:i64=p;while end+1<n{if b[end]==13 as u8&&b[end+1]==10 as u8{break};end=end+1} 88 if end+1>=n{return r.code} 89 var colon:i64=p;while colon<end&&b[colon]!=58 as u8{colon=colon+1};if colon==end{return r.code} 90 var first:i64=colon+1;while first<end&&(b[first]==32 as u8||b[first]==9 as u8){first=first+1} 91 var last:i64=end;while last>first&&(b[last-1]==32 as u8||b[last-1]==9 as u8){last=last-1} 92 if mpr_eq(b+p,colon-p,"transfer-encoding")==1{return r.code} 93 if mpr_eq(b+p,colon-p,"content-length")==1{ 94 if length>=0{return r.code};length=mpr_decimal(b+first,last-first);if length<0{return r.code} 95 } 96 p=end+2 97 } 98 if body<0||length<0||length!=n-body{return r.code} 99 r.body_bytes=length;r.code=0;return body 100} 101func mpr_publish(b:*u8,n:i64,capacity:i64,r:*NxMgmtPrivateResponse)->i64{ 102 let body:i64=mpr_body(b,n,capacity,r);if body<0{return r.code} 103 if r.status<200||r.status>=300{r.code=0-71;r.stage="upstream-http-refusal";return r.code} 104 r.stage="private-write";r.code=fio_write_sync_fd(r.fd,b+body,r.body_bytes,r.write);r.fd=0-1 105 if r.code!=0{return r.code} 106 r.stage="private-publish-precondition";r.code=mpr_absent(r.path);if r.code!=0{return r.code} 107 r.code=sys_fstatat(r.tmp,r.stat) 108 if r.code!=0||mpr_word(r.stat,NX_STAT_X64_DEVICE_OFFSET)!=r.dev||mpr_word(r.stat,NX_STAT_X64_INODE_OFFSET)!=r.ino{r.code=0-17;return r.code} 109 r.stage="private-publish";r.code=sys_renameat(r.tmp,r.path);if r.code!=0{return r.code} 110 r.visible=1;r.owned=0;r.stage="private-directory-sync" 111 r.code=fio_write_sync_fd(r.dirfd,0 as *u8,0,r.write);r.dirfd=0-1 112 if r.code==0{r.durable=1;r.stage="private-response-retained"};return r.code 113} 114func mpr_put(s:*u8)->i64{ 115 let n:i64=mpr_len(s);var at:i64=0;while at<n{let w:i64=sys_write(1,s+at,n-at);if w==FIO_EINTR{continue};if w<=0{return 0-1};at=at+w};return 0 116} 117func mpr_num(v:i64)->i64{ 118 if v<0{if mpr_put("-")!=0{return 0-1}} 119 return mpr_digits(v) 120} 121func mpr_digits(v:i64)->i64{ 122 if v<=0-10||v>=10{if mpr_digits(v/10)!=0{return 0-1}} 123 var digit:i64=v%10;if digit<0{digit=0-digit} 124 var w:i64=sys_write(1,"0123456789"+digit,1);while w==FIO_EINTR{w=sys_write(1,"0123456789"+digit,1)};if w!=1{return 0-1};return 0 125} 126func mpr_report(r:*NxMgmtPrivateResponse)->i64{ 127 if mpr_put("{\"action\":\"PRIVATE-RESPONSE\",\"upstream_status\":")!=0||mpr_num(r.status)!=0{return 0-1} 128 if mpr_put(",\"request_sent\":")!=0{return 0-1} 129 if r.sent<0{if mpr_put("null")!=0{return 0-1}}else{if mpr_num(r.sent)!=0{return 0-1}} 130 if mpr_put(",\"visible\":")!=0||mpr_num(r.visible)!=0{return 0-1} 131 if mpr_put(",\"durable\":")!=0||mpr_num(r.durable)!=0{return 0-1} 132 if mpr_put(",\"temporary_owned\":")!=0||mpr_num(r.owned)!=0{return 0-1} 133 if mpr_put(",\"body_bytes\":")!=0||mpr_num(r.body_bytes)!=0{return 0-1} 134 if mpr_put(",\"code\":")!=0||mpr_num(r.code)!=0{return 0-1} 135 if mpr_put(",\"stage\":\"")!=0||mpr_put(r.stage)!=0||mpr_put("\"}\n")!=0{return 0-1} 136 return 0 137}