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. Load more
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 CU sys: 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 port HTTPSD: con 443; # Default IP port for HTTPS # For Inferno, won't be able to read more than this at one go anyway BLOCKSIZE: con 1460; # HTTP/1.1 Spec says 5, but we've seen more than that in non-looping redirs # MAXREDIR: con 10; # tstate bits THTTP_1_0, TPersist, TProxy, TSSL: con (1<<iota); # Header fields (in order: general, request, response, entity) HCacheControl, HConnection, HDate, HPragma, HTransferEncoding, HUpgrade, HVia, HKeepAlive, # extension HAccept, HAcceptCharset, HAcceptEncoding, HAcceptLanguage, HAuthorization, HExpect, HFrom, HHost, HIfModifiedSince, HIfMatch, HIfNoneMatch, HIfRange, HIfUnmodifiedSince, HMaxForwards, HProxyAuthorization, HRange, HReferer, HUserAgent, HCookie, # extension HAcceptRanges, HAge, HLocation, HProxyAuthenticate, HPublic, HRetryAfter, HServer, HSetProxy, HVary, HWarning, HWWWAuthenticate, HContentDisposition, HSetCookie, HRefresh, # extensions HWindowTarget, HPICSLabel, # more extensions HAllow, 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 lowercase hdrtable := 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 != "") {