@@ -572,6 +572,135 @@ func write_tls_python_utils() {
572572 py.append_view(" except Exception:\n")
573573 py.append_view(" pass\n")
574574 py.append_view(" s.close()\n")
575+ py.append_view("def read_http_request(c):\n")
576+ py.append_view(" data=b''\n")
577+ py.append_view(" while b'\\r\\n\\r\\n' not in data:\n")
578+ py.append_view(" d=c.recv(4096)\n")
579+ py.append_view(" if not d:return None,None,None\n")
580+ py.append_view(" data+=d\n")
581+ py.append_view(" head,rest=data.split(b'\\r\\n\\r\\n',1)\n")
582+ py.append_view(" lines=head.split(b'\\r\\n')\n")
583+ py.append_view(" parts=lines[0].split(b' ')\n")
584+ py.append_view(" method=parts[0].decode();path=parts[1].decode() if len(parts)>1 else '/'\n")
585+ py.append_view(" hdrs={}\n")
586+ py.append_view(" for h in lines[1:]:\n")
587+ py.append_view(" if b':' in h:\n")
588+ py.append_view(" k,v=h.split(b':',1);hdrs[k.strip().lower().decode()]=v.strip().decode()\n")
589+ py.append_view(" clen=int(hdrs.get('content-length','0'))\n")
590+ py.append_view(" while len(rest)<clen:\n")
591+ py.append_view(" d=c.recv(65536)\n")
592+ py.append_view(" if not d:break\n")
593+ py.append_view(" rest+=d\n")
594+ py.append_view(" return (method,path,hdrs,rest[:clen])\n")
595+ py.append_view("def httpsrv(cert,key,port,nconn=8):\n")
596+ py.append_view(" ctx=ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)\n")
597+ py.append_view(" ctx.load_cert_chain(cert,key)\n")
598+ py.append_view(" s=socket.socket()\n")
599+ py.append_view(" s.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)\n")
600+ py.append_view(" s.bind(('127.0.0.1',int(port)))\n")
601+ py.append_view(" s.listen(int(nconn))\n")
602+ py.append_view(" s.settimeout(60)\n")
603+ py.append_view(" for i in range(int(nconn)):\n")
604+ py.append_view(" try:\n")
605+ py.append_view(" c,a=s.accept()\n")
606+ py.append_view(" except Exception as e:\n")
607+ py.append_view(" print('HTTPS_SRV_ACCEPT_ERR:'+str(e),file=sys.stderr)\n")
608+ py.append_view(" break\n")
609+ py.append_view(" try:\n")
610+ py.append_view(" t=ctx.wrap_socket(c,server_side=True)\n")
611+ py.append_view(" m,p,h,b=read_http_request(t)\n")
612+ py.append_view(" if m is None:t.close();continue\n")
613+ py.append_view(" if p.startswith('/status/'):\n")
614+ py.append_view(" code=int(p.split('/')[2]);body=b's';hdr={'Content-Length':'1'}\n")
615+ py.append_view(" elif p=='/hello' and m in ('GET','HEAD'):\n")
616+ py.append_view(" code=200;body=b'world';hdr={'Content-Length':'5','X-Custom':'chemical-test','Content-Type':'text/plain'}\n")
617+ py.append_view(" elif p=='/echo' and m=='POST':\n")
618+ py.append_view(" code=200;body=b;hdr={'Content-Length':str(len(b)),'X-Content-Type':h.get('content-type','')}\n")
619+ py.append_view(" elif p.startswith('/size/'):\n")
620+ py.append_view(" n=int(p.split('/')[2]);code=200;body=bytes([j%251 for j in range(n)]);hdr={'Content-Length':str(n),'Content-Type':'application/octet-stream'}\n")
621+ py.append_view(" elif p.startswith('/query'):\n")
622+ py.append_view(" q=p.split('?',1)[1] if '?' in p else '';code=200;body=q.encode();hdr={'Content-Length':str(len(body))}\n")
623+ py.append_view(" elif p=='/hdrs':\n")
624+ py.append_view(" body=(h.get('x-test','')+'|'+h.get('user-agent','')).encode();code=200\n")
625+ py.append_view(" hdr={'Content-Length':str(len(body))}\n")
626+ py.append_view(" elif p=='/chunked':\n")
627+ py.append_view(" payload=b'chunked-body-data'\n")
628+ py.append_view(" resp=b'HTTP/1.1 200 OK\\r\\nTransfer-Encoding: chunked\\r\\n\\r\\n'\n")
629+ py.append_view(" resp+=format(len(payload)//2,'x').encode()+b'\\r\\n'+payload[:len(payload)//2]+b'\\r\\n'\n")
630+ py.append_view(" resp+=format(len(payload)-len(payload)//2,'x').encode()+b'\\r\\n'+payload[len(payload)//2:]+b'\\r\\n0\\r\\n\\r\\n'\n")
631+ py.append_view(" t.sendall(resp);t.close();continue\n")
632+ py.append_view(" elif p=='/put' and m=='PUT':\n")
633+ py.append_view(" code=200;body=b'put:'+b;hdr={'Content-Length':str(len(body))}\n")
634+ py.append_view(" elif p=='/patch' and m=='PATCH':\n")
635+ py.append_view(" code=200;body=b'patched';hdr={'Content-Length':'7'}\n")
636+ py.append_view(" elif p=='/del' and m=='DELETE':\n")
637+ py.append_view(" code=200;body=b'deleted';hdr={'Content-Length':'7'}\n")
638+ py.append_view(" else:\n")
639+ py.append_view(" code=404;body=b'not found';hdr={'Content-Length':'9'}\n")
640+ py.append_view(" resp=('HTTP/1.1 '+str(code)+' T\\r\\n').encode()\n")
641+ py.append_view(" for k,v in hdr.items():resp+=(k+': '+v+'\\r\\n').encode()\n")
642+ py.append_view(" resp+=b'Connection: close\\r\\n\\r\\n'+body\n")
643+ py.append_view(" t.sendall(resp)\n")
644+ py.append_view(" t.close()\n")
645+ py.append_view(" except Exception as e:\n")
646+ py.append_view(" print('HTTPS_SRV_ERR:'+str(e),file=sys.stderr)\n")
647+ py.append_view(" s.close()\n")
648+ py.append_view("def hcli(host,port,outfile,mode,cafile=None,ciphers=None):\n")
649+ py.append_view(" import http.client,hashlib,time\n")
650+ py.append_view(" try:\n")
651+ py.append_view(" if cafile:\n")
652+ py.append_view(" cc=ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT);cc.load_verify_locations(cafile)\n")
653+ py.append_view(" else:\n")
654+ py.append_view(" cc=ssl._create_unverified_context()\n")
655+ py.append_view(" if ciphers:cc.set_ciphers(ciphers)\n")
656+ py.append_view(" ok=False;why=''\n")
657+ py.append_view(" if mode=='get':\n")
658+ py.append_view(" cn=http.client.HTTPSConnection(host,int(port),context=cc,timeout=15)\n")
659+ py.append_view(" cn.request('GET','/integrate');r=cn.getresponse();d=r.read()\n")
660+ py.append_view(" ok=(r.status==200 and d==b'SRV_OK');why='status=%s body=%r'%(r.status,d[:40])\n")
661+ py.append_view(" cn.close()\n")
662+ py.append_view(" elif mode=='post':\n")
663+ py.append_view(" payload=bytes([j%251 for j in range(50000)])\n")
664+ py.append_view(" cn=http.client.HTTPSConnection(host,int(port),context=cc,timeout=30)\n")
665+ py.append_view(" cn.request('POST','/integrate',body=payload,headers={'Content-Type':'application/octet-stream'})\n")
666+ py.append_view(" r=cn.getresponse();d=r.read()\n")
667+ py.append_view(" ok=(r.status==200 and d==payload);why='status=%s len=%d'%(r.status,len(d))\n")
668+ py.append_view(" cn.close()\n")
669+ py.append_view(" elif mode=='slowpost':\n")
670+ py.append_view(" payload=bytes([(j*7)%251 for j in range(20000)])\n")
671+ py.append_view(" s=socket.create_connection((host,int(port)),timeout=20)\n")
672+ py.append_view(" ts=cc.wrap_socket(s,server_hostname=host)\n")
673+ py.append_view(" head=b'POST /integrate HTTP/1.1\\r\\nHost: '+host.encode()+b'\\r\\nContent-Length: 20000\\r\\nConnection: close\\r\\n\\r\\n'\n")
674+ py.append_view(" ts.sendall(head)\n")
675+ py.append_view(" off=0\n")
676+ py.append_view(" while off<len(payload):\n")
677+ py.append_view(" ts.sendall(payload[off:off+1024]);time.sleep(0.01);off+=1024\n")
678+ py.append_view(" buf=b''\n")
679+ py.append_view(" while True:\n")
680+ py.append_view(" d=ts.recv(65536)\n")
681+ py.append_view(" if not d:break\n")
682+ py.append_view(" buf+=d\n")
683+ py.append_view(" ts.close()\n")
684+ py.append_view(" body=buf.split(b'\\r\\n\\r\\n',1)[1] if b'\\r\\n\\r\\n' in buf else b''\n")
685+ py.append_view(" ok=(body==payload);why='resp_len=%d'%len(body)\n")
686+ py.append_view(" elif mode=='keepalive':\n")
687+ py.append_view(" cn=http.client.HTTPSConnection(host,int(port),context=cc,timeout=15)\n")
688+ py.append_view(" cn.request('GET','/integrate?a=1');r1=cn.getresponse();d1=r1.read()\n")
689+ py.append_view(" cn.request('GET','/integrate?a=2');r2=cn.getresponse();d2=r2.read()\n")
690+ py.append_view(" ok=(r1.status==200 and d1==b'SRV_OK:a=1' and r2.status==200 and d2==b'SRV_OK:a=2')\n")
691+ py.append_view(" why='r1=%s/%r r2=%s/%r'%(r1.status,d1,r2.status,d2)\n")
692+ py.append_view(" cn.close()\n")
693+ py.append_view(" elif mode=='bigresp':\n")
694+ py.append_view(" cn=http.client.HTTPSConnection(host,int(port),context=cc,timeout=60)\n")
695+ py.append_view(" cn.request('GET','/big');r=cn.getresponse();d=r.read()\n")
696+ py.append_view(" want=bytes([j%251 for j in range(300000)])\n")
697+ py.append_view(" ok=(r.status==200 and d==want);why='status=%s len=%d'%(r.status,len(d))\n")
698+ py.append_view(" cn.close()\n")
699+ py.append_view(" f=open(outfile,'w')\n")
700+ py.append_view(" f.write(('RESULT:OK' if ok else 'RESULT:FAIL '+why))\n")
701+ py.append_view(" f.close()\n")
702+ py.append_view(" except Exception as e:\n")
703+ py.append_view(" f=open(outfile,'w');f.write('RESULT:FAIL exception '+str(e));f.close()\n")
575704 py.append_view("cmd=sys.argv[1]\n")
576705 py.append_view("if cmd=='cert':\n")
577706 py.append_view(" gen_cert(sys.argv[2],sys.argv[3],sys.argv[4],sys.argv[5] if len(sys.argv)>5 else 'ec')\n")
@@ -602,5 +731,9 @@ func write_tls_python_utils() {
602731 py.append_view(" echo_srv(sys.argv[2],sys.argv[3],sys.argv[4],sys.argv[5] if len(sys.argv)>5 else 1,sys.argv[6] if len(sys.argv)>6 else 16384)\n")
603732 py.append_view("elif cmd=='plaintcp':\n")
604733 py.append_view(" plaintcp(sys.argv[2],sys.argv[3],sys.argv[4] if len(sys.argv)>4 else 1)\n")
734+ py.append_view("elif cmd=='httpsrv':\n")
735+ py.append_view(" httpsrv(sys.argv[2],sys.argv[3],sys.argv[4],sys.argv[5] if len(sys.argv)>5 else 8)\n")
736+ py.append_view("elif cmd=='hcli':\n")
737+ py.append_view(" hcli(sys.argv[2],sys.argv[3],sys.argv[4],sys.argv[5] if len(sys.argv)>5 else 'get',sys.argv[6] if len(sys.argv)>6 and sys.argv[6 ]!= '-' else None,sys.argv[7 ] if len (sys.argv)> 7 and sys.argv[7 ]!= '-' else None)\n")
605738 test_write_file(" /tmp/tls_utils.py\0 " as *char, py.data() as *u8, py.size())
606739}
0 commit comments