forsyth20121205-174063a80cc13 years agoHistory
1040 lines · 24.6 KB · Brainfuck
RawDownload
implement Transport; include "common.m";include "transport.m";include "date.m"; #D: Date;# sslhs: SSLHS;ssl3: SSL3;Context: import ssl3;# Inferno supported cipher suites:ssl_suites := array [] of {	byte 0, byte 16r03,	# RSA_EXPORT_WITH_RC4_40_MD5	byte 0, byte 16r04,	# RSA_WITH_RC4_128_MD5	byte 0, byte 16r05,	# RSA_WITH_RC4_128_SHA	byte 0, byte 16r06,	# RSA_EXPORT_WITH_RC2_CBC_40_MD5	byte 0, byte 16r07,	# RSA_WITH_IDEA_CBC_SHA	byte 0, byte 16r08,	# RSA_EXPORT_WITH_DES40_CBC_SHA	byte 0, byte 16r09,	# RSA_WITH_DES_CBC_SHA	byte 0, byte 16r0A,	# RSA_WITH_3DES_EDE_CBC_SHA		byte 0, byte 16r0B,	# DH_DSS_EXPORT_WITH_DES40_CBC_SHA	byte 0, byte 16r0C,	# DH_DSS_WITH_DES_CBC_SHA	byte 0, byte 16r0D,	# DH_DSS_WITH_3DES_EDE_CBC_SHA	byte 0, byte 16r0E,	# DH_RSA_EXPORT_WITH_DES40_CBC_SHA	byte 0, byte 16r0F,	# DH_RSA_WITH_DES_CBC_SHA	byte 0, byte 16r10,	# DH_RSA_WITH_3DES_EDE_CBC_SHA	byte 0, byte 16r11,	# DHE_DSS_EXPORT_WITH_DES40_CBC_SHA	byte 0, byte 16r12,	# DHE_DSS_WITH_DES_CBC_SHA	byte 0, byte 16r13,	# DHE_DSS_WITH_3DES_EDE_CBC_SHA	byte 0, byte 16r14,	# DHE_RSA_EXPORT_WITH_DES40_CBC_SHA	byte 0, byte 16r15,	# DHE_RSA_WITH_DES_CBC_SHA	byte 0, byte 16r16,	# DHE_RSA_WITH_3DES_EDE_CBC_SHA		byte 0, byte 16r17,	# DH_anon_EXPORT_WITH_RC4_40_MD5	byte 0, byte 16r18,	# DH_anon_WITH_RC4_128_MD5	byte 0, byte 16r19,	# DH_anon_EXPORT_WITH_DES40_CBC_SHA	byte 0, byte 16r1A,	# DH_anon_WITH_DES_CBC_SHA	byte 0, byte 16r1B,	# DH_anon_WITH_3DES_EDE_CBC_SHA		byte 0, byte 16r1C,	# FORTEZZA_KEA_WITH_NULL_SHA	byte 0, byte 16r1D,	# FORTEZZA_KEA_WITH_FORTEZZA_CBC_SHA	byte 0, byte 16r1E,	# FORTEZZA_KEA_WITH_RC4_128_SHA}; ssl_comprs := array [] of {byte 0}; # local copies from CUsys: Sys;U: Url;	Parsedurl: import U;S: String;C: Ctype;T: StringIntTab;CU: CharonUtils;	Netconn, ByteSource, Header, config, Nameval : import CU; ctype: array of byte;	# local copy of C->ctype HTTPD:		con 80;		# Default IP portHTTPSD:		con 443;	# Default IP port for HTTPS # For Inferno, won't be able to read more than this at one go anywayBLOCKSIZE:	con 1460; # HTTP/1.1 Spec says 5, but we've seen more than that in non-looping redirs# MAXREDIR:	con 10; # tstate bitsTHTTP_1_0, TPersist, TProxy, TSSL: con (1<<iota); # Header fields (in order: general, request, response, entity)HCacheControl, HConnection, HDate, HPragma, HTransferEncoding,	HUpgrade, HVia,	HKeepAlive, # extensionHAccept, HAcceptCharset, HAcceptEncoding, HAcceptLanguage,	HAuthorization, HExpect, HFrom, HHost, HIfModifiedSince,	HIfMatch, HIfNoneMatch, HIfRange, HIfUnmodifiedSince,	HMaxForwards, HProxyAuthorization, HRange, HReferer,	HUserAgent,	HCookie, # extensionHAcceptRanges, HAge, HLocation, HProxyAuthenticate, HPublic,	HRetryAfter, HServer, HSetProxy, HVary, HWarning,	HWWWAuthenticate,	HContentDisposition, HSetCookie, HRefresh, # extensions	HWindowTarget, HPICSLabel, # more extensionsHAllow, HContentBase, HContentEncoding, HContentLanguage,	HContentLength, HContentLocation, HContentMD5,	HContentRange, HContentType, HETag, HExpires,	HLastModified,	HXReqTime, HXRespTime, HXUrl, # our extensions, for cached entities	NumHfields: con iota; # (track above enumeration)hdrnames := array[] of {	"Cache-Control",	"Connection",	"Date",	"Pragma",	"Transfer-Encoding",	"Upgrade",	"Via",	"Keep-Alive",	"Accept",	"Accept-Charset",	"Accept-Encoding",	"Accept-Language",	"Authorization",	"Expect",	"From",	"Host", 	"If-Modified-Since",	"If-Match",	"If-None-Match",	"If-Range",	"If-Unmodified-Since",	"Max-Forwards",	"Proxy-Authorization",	"Range",	"Refererer",	"User-Agent",	"Cookie",	"Accept-Ranges",	"Age", 	"Location",	"Proxy-Authenticate",	"Public",	"Retry-After",	"Server",	"Set-Proxy",	"Vary",	"Warning",	"WWW-Authenticate",	"Content-Disposition",	"Set-Cookie",	"Refresh",	"Window-Target",	"PICS-Label",	"Allow", 	"Content-Base", 	"Content-Encoding",	"Content-Language",	"Content-Length",	"Content-Location",	"Content-MD5",	"Content-Range",	"Content-Type",	"ETag",	"Expires",	"Last-Modified",	"X-Req-Time",	"X-Resp-Time",	"X-Url"}; # For fast lookup; track above, and keep sorted and lowercasehdrtable := array[] of { T->StringInt	("accept", HAccept),	("accept-charset", HAcceptCharset),	("accept-encoding", HAcceptEncoding),	("accept-language", HAcceptLanguage),	("accept-ranges", HAcceptRanges),	("age", HAge),	("allow", HAllow),	("authorization", HAuthorization),	("cache-control", HCacheControl),	("connection", HConnection),	("content-base", HContentBase),	("content-disposition", HContentDisposition),	("content-encoding", HContentEncoding),	("content-language", HContentLanguage),	("content-length", HContentLength),	("content-location", HContentLocation),	("content-md5", HContentMD5),	("content-range", HContentRange),	("content-type", HContentType),	("cookie", HCookie),	("date", HDate),	("etag", HETag),	("expect", HExpect),	("expires", HExpires),	("from", HFrom),	("host", HHost),	("if-modified-since", HIfModifiedSince),	("if-match", HIfMatch),	("if-none-match", HIfNoneMatch),	("if-range", HIfRange),	("if-unmodified-since", HIfUnmodifiedSince),	("keep-alive", HKeepAlive),	("last-modified", HLastModified),	("location", HLocation),	("max-forwards", HMaxForwards),	("pics-label", HPICSLabel),	("pragma", HPragma),	("proxy-authenticate", HProxyAuthenticate),	("proxy-authorization", HProxyAuthorization),	("public", HPublic),	("range", HRange),	("referer", HReferer),	("refresh", HRefresh),	("retry-after", HRetryAfter),	("server", HServer),	("set-cookie", HSetCookie),	("set-proxy", HSetProxy),	("transfer-encoding", HTransferEncoding),	("upgrade", HUpgrade),	("user-agent", HUserAgent),	("vary", HVary),	("via", HVia),	("warning", HWarning),	("window-target", HWindowTarget),	("www-authenticate", HWWWAuthenticate),	("x-req-time", HXReqTime),	("x-resp-time", HXRespTime),	("x-url", HXUrl)}; HTTP_Header: adt {	startline: string; 	# following four fields only filled in if this is a response header	protomajor: int;	protominor: int;	code: int;	reason: string;	iossl: int; # true for ssl  	vals: array of string;	cookies: list of string; 	new: fn() : ref HTTP_Header; 	read: fn(h: self ref HTTP_Header, fd: ref sys->FD, sslx: ref SSL3->Context, buf: array of byte) : (string, int, int); 	write: fn(h: self ref HTTP_Header, fd: ref sys->FD, sslx: ref SSL3->Context) : int;	usessl: fn(h: self ref HTTP_Header);	addval: fn(h: self ref HTTP_Header, key: int, val: string);	getval: fn(h: self ref HTTP_Header, key: int) : string;}; mediatable: array of T->StringInt; agent : string;dbg := 0;warn := 0;sptab : con " \t"; init(cu: CharonUtils){	CU = cu;	sys = load Sys Sys->PATH;	S = load String String->PATH;	U = load Url Url->PATH; 	if (U != nil)		U->init();	C = cu->C;	T = load StringIntTab StringIntTab->PATH;#	D = load Date CU->loadpath(Date->PATH);#	if (D == nil)#		CU->raise(sys->sprint("EXInternal: can't load Date: %r"));#	D->init(cu);	ctype = C->ctype;	# sslhs = nil;	# load on demand	ssl3 = nil; # load on demand	mediatable = CU->makestrinttab(CU->mnames);	agent = (CU->config).agentname;	dbg = int (CU->config).dbg['n'];	warn = dbg || int (CU->config).dbg['w'];} connect(nc: ref Netconn, bs: ref ByteSource){	if(nc.scheme == "https")		nc.tstate |= TSSL;	if(config.httpminor == 0)		nc.tstate |= THTTP_1_0;	dialhost := nc.host;	dialport := string nc.port;	if(nc.scheme != "https" && config.httpproxy != nil && need_proxy(nc.host)) {		nc.tstate |= TProxy;		dialhost = config.httpproxy.host;		if(config.httpproxy.port != "")			dialport = config.httpproxy.port;	}	addr := "tcp!" + dialhost + "!" + dialport;	err := "";	if(dbg)		sys->print("http %d: dialing %s\n", nc.id, addr);	rv: int;	(rv, nc.conn) = sys->dial(addr, nil);	if(rv < 0) {		syserr := sys->sprint("%r");		if(S->prefix("cs: dialup", syserr))			err = syserr[4:];		else if(S->prefix("cs: dns: no translation found", syserr))			err = "unknown host";		else			err = sys->sprint("couldn't connect: %s", syserr);	}	else {		if(dbg)			sys->print("http %d: connected\n", nc.id);		if(nc.tstate&TSSL) {			#if(sslhs == nil) {			#	sslhs = load SSLHS SSLHS->PATH;			#	if(sslhs == nil)			#		err = sys->sprint("can't load SSLHS: %r");			#	else			#		sslhs->init(2);			#}			#if(err == "")			#	(err, nc.conn) = sslhs->client(nc.conn.dfd, addr);			if(nc.tstate&TProxy) # tunelling SSL through proxy				err = tunnel_ssl(nc);	 		vers := 0; 			if(err == "") {				if(ssl3 == nil) {	 				m := load SSL3 SSL3->PATH; 					if(m == nil) 						err = "can't load SSL3 module";					else if((err = m->init()) == nil)						ssl3 = m;				}				if(config.usessl == CU->NOSSL)					err = "ssl is configured off";				else if((config.usessl & CU->SSLV23) == CU->SSLV23)					vers = 23;	 			else if(config.usessl & CU->SSLV2)					vers = 2;	 			else if(config.usessl & CU->SSLV3)					vers = 3;			} 			if(err == "") { 				nc.sslx = ssl3->Context.new(); 				if(config.devssl) 					nc.sslx.use_devssl(); 				info := ref SSL3->Authinfo(ssl_suites, ssl_comprs, nil,  						0, nil, nil, nil);vers = 3; 				(err, nc.vers) =  nc.sslx.client(nc.conn.dfd, addr, vers, info); 			}		}	}	if(err == "") {		nc.connected = 1;		nc.state = CU->NCgethdr;	}	else {		if(dbg)			sys->print("http %d: connection failed: %s\n", nc.id, err);		bs.err = err;#constate("connect", nc.conn);		closeconn(nc);	}} constate(msg: string, conn: Sys->Connection){	fd := conn.dfd;	fdfd := -1;	if (fd != nil)		fdfd = fd.fd;	sys->print("connstate(%s, %d) ", msg, fdfd);	sfd := sys->open(conn.dir + "/status", Sys->OREAD);	if (sfd == nil) {		sys->print("cannot open %s/status: %r\n", conn.dir);		return;	}	buf := array [1024] of byte;	n := sys->read(sfd, buf, len buf);	s := sys->sprint("error: %r");	if (n > 0)		s = string buf[:n];	sys->print("%s status: %s\n", conn.dir, s);} tunnel_ssl(nc: ref Netconn) : string{	httpvers: string;	if(nc.state&THTTP_1_0)		httpvers = "1.0";	else		httpvers = "1.1";	req := "CONNECT " + nc.host + ":" + string nc.port + " HTTP/" + httpvers; 	n := sys->fprint(nc.conn.dfd, "%s\r\n\r\n", req);	if(n < 0)		return sys->sprint("proxy: %r");	buf := array [Sys->ATOMICIO] of byte;	n = sys->read(nc.conn.dfd, buf, Sys->ATOMICIO);	if(n < 0)		return sys->sprint("proxy: %r");;	resp := string buf[0:n];	(m, s) := sys->tokenize(resp, " "); 	if(m < 2)		return "proxy: " + resp;	if(hd tl s != "200"){		(nil, e) := sys->tokenize(resp, "\n\r");		return hd e;	}	return "";} need_proxy(h: string) : int{	doms := config.noproxydoms;	lh := len h;	for(; doms != nil; doms = tl doms) {		dom := hd doms;		ld := len dom;		if(lh >= ld && h[lh-ld:] == dom)			return 0; # domain is on the no proxy list	}	return 1;} writereq(nc: ref Netconn, bs: ref ByteSource){	#	# Prepare the request	#	req := bs.req;	u := ref *req.url;	requ, httpvers: string;	#if(nc.tstate&TProxy)	if((nc.tstate&TProxy) && !(nc.tstate&TSSL)) {		u.frag = nil;		requ = u.tostring();	} else {		requ = u.path;		if(u.query != "")			requ += "?" + u.query;	}	if(nc.tstate&THTTP_1_0)		httpvers = "1.0";	else		httpvers = "1.1";	reqhdr := HTTP_Header.new(); 	if(nc.tstate&TSSL) 		reqhdr.usessl();	reqhdr.startline = CU->hmeth[req.method] + " " +  requ + " HTTP/" + httpvers;	if(u.port != "")		reqhdr.addval(HHost, u.host+ ":" + u.port);	else		reqhdr.addval(HHost, u.host);	reqhdr.addval(HUserAgent, agent);	reqhdr.addval(HAccept, "*/*; *");#	if(cr != nil && (cr.status == CRRevalidate || cr.status == CRMustRevalidate)) {#		if(cr.etag != "")#			reqhdr.addval(HIfNoneMatch, cr.etag);#		else#			reqhdr.addval(HIfModifiedSince, D->dateconv(cr.notafter));#	}	if(req.auth != "")		reqhdr.addval(HAuthorization, "Basic " + req.auth);	if(req.method == CU->HPost) {		reqhdr.addval(HContentLength, string (len req.body));		reqhdr.addval(HContentType, "application/x-www-form-urlencoded");	}        if((CU->config).docookies > 0) {                cookies := CU->getcookies(u.host, u.path, nc.tstate&TSSL);		if (cookies != nil)                       reqhdr.addval(HCookie, cookies);        }	#	# Issue the request	#	err := "";	if(dbg > 1) {		sys->print("http %d: writing request:\n", nc.id);		reqhdr.write(sys->fildes(1), nil);	}	rv := reqhdr.write(nc.conn.dfd, nc.sslx);	if(rv >= 0 && req.method == CU->HPost) {		if(dbg > 1)			sys->print("http %d: writing body:\n%s\n", nc.id, string req.body); 		if((nc.tstate&TSSL) && nc.sslx != nil) 			rv = nc.sslx.write(req.body, len req.body); 		else 			rv = sys->write(nc.conn.dfd, req.body, len req.body);	}	if(rv < 0) {		err = sys->sprint("error writing to host: %r");#constate("writereq", nc.conn);	}	if(err != "") {		if(dbg)			sys->print("http %d: error: %s", nc.id, err);		bs.err = err;		closeconn(nc);	}}  gethdr(nc: ref Netconn, bs: ref ByteSource){	resph := HTTP_Header.new(); 	if(nc.tstate&TSSL) 		resph.usessl();	hbuf := array[8000] of byte; 	(err, i, j) := resph.read(nc.conn.dfd, nc.sslx, hbuf);	if(err != "") {

Lines 1–500 of 1040.