--- http.cc 2005-05-17 21:16:11.000000000 +0200 +++ ../../http.cc 2005-05-19 22:01:28.000000000 +0200 @@ -1,5 +1,6 @@ // -*- mode: cpp; mode: fold -*- // Description /*{{{*/ +// Added Digest Support for HTTP proxies by Giuseppe Scrivano 2005/05/17 // $Id: http.cc,v 1.59 2004/05/08 19:42:35 mdz Exp $ /* ###################################################################### @@ -40,6 +41,7 @@ #include #include #include +#include // Internet stuff #include @@ -330,19 +332,20 @@ { close(ServerFd); ServerFd = -1; + Reset(); return true; } /*}}}*/ // ServerState::RunHeaders - Get the headers before the data /*{{{*/ // --------------------------------------------------------------------- -/* Returns 0 if things are OK, 1 if an IO error occursed and 2 if a header - parse error occured */ +/* Returns 0 if things are OK, 1 if an IO error occursed, 2 if a header + parse error occured, 3 to send again last request(used by the digest scheme) */ int ServerState::RunHeaders() { State = Header; Owner->Status(_("Waiting for headers")); - + Pipeline = true; Major = 0; Minor = 0; Result = 0; @@ -373,7 +376,9 @@ // 100 Continue is a Nop... if (Result == 100) continue; - + // Resend the request if the server wants digest. + if(ProxyAuth == Digest && Result == 407) + return 3; // Tidy up the connection persistance state. if (Encoding == Closes && HaveContent == true) Persistent = false; @@ -529,12 +534,7 @@ if (Major < 1) Persistent = false; else - { - if (Major == 1 && Minor <= 0) - Persistent = false; - else Persistent = true; - } return true; } @@ -560,6 +560,20 @@ return true; } + if (stringcasecmp(Tag,"Proxy-Authenticate:") == 0) + { + string::size_type Pos = Line.find("Digest"); + if(Pos != (-1)) + { + ProxyAuth=Digest; + Pipeline = false; + return ParseDigest(Line); + } + + ProxyAuth=Basic; + return true; + } + if (stringcasecmp(Tag,"Content-Range:") == 0) { HaveContent = true; @@ -597,6 +611,53 @@ return true; } + +/* Copy the digest data in the buffers. */ +bool ServerState::ParseDigest(string Line) +{ + int Len; + int Pos = Line.find("realm"); + string TmpNonce; + if(Pos == (-1)) + return false; + + + for(Len=Pos+7; Line[Len] && Line[Len]!='\"'; Len++); + if(!Line[Len]) + return false; + + ProxyRealm.assign(Line, Pos+7, Len-Pos-7); + Pos = Line.find("opaque"); + if(Pos != (-1)) + { + for(Len=Pos+8; Line[Len] && Line[Len]!='\"'; Len++); + if(!Line[Len]) + return false; + + ProxyOpaque.assign(Line, Pos+8, Len-Pos-8); + } + else + ProxyOpaque.assign(""); + Pos = Line.find("nonce"); + if(Pos == (-1)) + return false; + + + for(Len=Pos+7; Line[Len] && Line[Len]!='\"'; Len++); + if(!Line[Pos]) + return false; + + TmpNonce.assign(Line, Pos+7, Len-Pos-7); + + if(TmpNonce.compare(ProxyNonce) == 0) + ProxyNc = 0; + + ProxyNonce.assign(TmpNonce); + ProxyCnonce.assign("stupidCnonce"); + + return true; +} + /*}}}*/ // HttpMethod::SendReq - Send the HTTP request /*{{{*/ @@ -636,7 +697,7 @@ sprintf(Buf,"GET %s HTTP/1.1\r\nHost: %s\r\n", Itm->Uri.c_str(),ProperHost.c_str()); if (_config->FindB("Acquire::http::No-Cache",false) == true) - strcat(Buf,"Cache-Control: no-cache\r\nPragma: no-cache\r\n"); + strcat(Buf,"Proxy-Connection: keep-alive\r\nCache-Control: no-cache\r\nPragma: no-cache\r\n"); else { if (Itm->IndexFile == true) @@ -670,13 +731,68 @@ } } + + if(Server->ProxyAuth == ServerState::Digest) + { + /* Digest auth scheme for proxy. */ + MD5Summation A1; + MD5Summation A2; + char Nc[9]; + string Tmp(""); + int i; + int slashesCount; + string DigUri; + MD5Summation Response; + + for(i=0, slashesCount=0; Itm->Uri[i] && slashesCount < 3; i++) + if(Itm->Uri[i] == '/') + slashesCount++; + DigUri = Itm->Uri.substr(i); + + for(i=0; i< 8; i++) + Nc[i]='0'; + + Nc[i] ='\0'; + Tmp = Proxy.User + string(":") + Server->ProxyRealm + string(":") + Proxy.Password; + A1.Add(Tmp.c_str()); + Tmp = string("GET:") + DigUri; + A2.Add(Tmp.c_str()); + + { + ostringstream TmpStream; + Server->ProxyNc++; + TmpStream << hex << Server->ProxyNc; + strcpy(&Nc[8-TmpStream.str().length()], TmpStream.str().c_str()); + Nc[8] ='\0'; + + TmpStream.str(string("")); + TmpStream << (A1.Result().Value()) << (":") << Server->ProxyNonce + << (":") << hex << string(Nc) << (":") << Server->ProxyCnonce + << (":auth:") << (A2.Result().Value()); + + Response.Add(TmpStream.str().c_str()); + + } + + Req += string("Proxy-Connection: keep-alive\r\nProxy-Authorization: Digest username=\"") + + Proxy.User + string("\", nonce=\"") + Server->ProxyNonce + string("\", uri=\"") + + DigUri + string("\", qop=auth, realm=\"")+ Server->ProxyRealm + string("\", cnonce=\"") + + Server->ProxyCnonce + string("\", nc=") + string(Nc) + string(", ") + + (Server->ProxyOpaque.length() + ? (string("opaque=\"") + Server->ProxyOpaque + string("\", ")) + : string ("") ) + string("response=\"")+ string(Response.Result().Value()) + + string("\"\r\n"); + } + else + { if (Proxy.User.empty() == false || Proxy.Password.empty() == false) - Req += string("Proxy-Authorization: Basic ") + + Req += string("Proxy-Connection: keep-alive\r\nProxy-Authorization: Basic ") + Base64Encode(Proxy.User + ":" + Proxy.Password) + "\r\n"; if (Uri.User.empty() == false || Uri.Password.empty() == false) Req += string("Authorization: Basic ") + Base64Encode(Uri.User + ":" + Uri.Password) + "\r\n"; + } Req += "User-Agent: Debian APT-HTTP/1.3\r\n\r\n"; @@ -958,7 +1074,8 @@ I = I->Next, Depth++) { // If pipelining is disabled, we only queue 1 request - if (Server->Pipeline == false && Depth >= 0) + if (( (Server->ProxyAuth==ServerState::Digest) || + (Server->Pipeline==false)) && (Depth>=0)) break; // Make sure we stick with the same server @@ -1002,8 +1119,9 @@ signal(SIGINT,SigTerm); Server = 0; - + int reFetch = 0; int FailCounter = 0; + while (1) { // We have no commands, wait for some to arrive @@ -1007,6 +1125,8 @@ while (1) { // We have no commands, wait for some to arrive + if(reFetch == 0) + { if (Queue == 0) { if (WaitFd(STDIN_FILENO) == false) @@ -1049,9 +1169,19 @@ Server = 0; continue; } - + Server->Pipeline = false; + Server->Persistent= true; // Fill the pipeline. Fetch(0); + } + else + { + SendReq(Queue,Server->Out); + reFetch = 0; + } + + // Decide what to do. + FetchResult Res; // Fetch the next URL header data from the server. switch (Server->RunHeaders()) @@ -1067,7 +1197,19 @@ RotateDNS(); continue; } + case 3: + { + Res.Filename = Queue->DestFile; + /* Flush the data before send a new request. */ + File = new FileFd("/dev/null",FileFd::WriteExists); + Server->RunData(); + delete File; + File = 0; + Server->Out.Reset(); + reFetch = 1; + continue; + } // The server closed a connection during the header get.. default: case 1: @@ -1088,8 +1230,6 @@ } }; - // Decide what to do. - FetchResult Res; Res.Filename = Queue->DestFile; switch (DealWithHeaders(Res,Server)) { --- http.h 2005-05-17 21:16:11.000000000 +0200 +++ /../../http.h 2005-05-17 20:27:51.000000000 +0200 @@ -86,6 +86,15 @@ unsigned int Result; char Code[MAXLEN]; + /*! Digest stuff. */ + string ProxyRealm; + string ProxyOpaque; + string ProxyNonce; + string ProxyCnonce; + unsigned int ProxyNc; + + enum{Basic, Digest} ProxyAuth; + // These are some statistics from the last parsed header lines unsigned long Size; signed long StartPos; @@ -110,13 +119,17 @@ bool Comp(URI Other) {return Other.Host == ServerName.Host && Other.Port == ServerName.Port;}; void Reset() {Major = 0; Minor = 0; Result = 0; Size = 0; StartPos = 0; Encoding = Closes; time(&Date); ServerFd = -1; - Pipeline = true;}; + Pipeline = true; ProxyRealm.assign(""); ProxyOpaque.assign(""); + ProxyNonce.assign(""); ProxyCnonce.assign(""); + ProxyNc=0; ProxyAuth=Basic;}; int RunHeaders(); bool RunData(); bool Open(); bool Close(); + bool ParseDigest(string line); + ServerState(URI Srv,HttpMethod *Owner); ~ServerState() {Close();}; };