X-Git-Url: https://git.saurik.com/apt.git/blobdiff_plain/b2e465d6d32d2dc884f58b94acb7e35f671a87fe..6990342e905a3dde459ce79d596d863c07f9ea61:/methods/http.cc diff --git a/methods/http.cc b/methods/http.cc index 7347e8349..cb63ada49 100644 --- a/methods/http.cc +++ b/methods/http.cc @@ -1,6 +1,6 @@ // -*- mode: cpp; mode: fold -*- // Description /*{{{*/ -// $Id: http.cc,v 1.47 2001/02/20 07:03:18 jgg Exp $ +// $Id: http.cc,v 1.59 2004/05/08 19:42:35 mdz Exp $ /* ###################################################################### HTTP Aquire Method - This is the HTTP aquire method for APT. @@ -28,7 +28,7 @@ #include #include #include -#include +#include #include #include @@ -37,6 +37,9 @@ #include #include #include +#include +#include +#include // Internet stuff #include @@ -46,6 +49,7 @@ #include "http.h" /*}}}*/ +using namespace std; string HttpMethod::FailFile; int HttpMethod::FailFd = -1; @@ -54,13 +58,20 @@ unsigned long PipelineDepth = 10; unsigned long TimeOut = 120; bool Debug = false; +unsigned long CircleBuf::BwReadLimit=0; +unsigned long CircleBuf::BwTickReadData=0; +struct timeval CircleBuf::BwReadTick={0,0}; +const unsigned int CircleBuf::BW_HZ=10; + // CircleBuf::CircleBuf - Circular input buffer /*{{{*/ // --------------------------------------------------------------------- /* */ -CircleBuf::CircleBuf(unsigned long Size) : Size(Size), MD5(0) +CircleBuf::CircleBuf(unsigned long Size) : Size(Size), Hash(0) { Buf = new unsigned char[Size]; Reset(); + + CircleBuf::BwReadLimit = _config->FindI("Acquire::http::Dl-Limit",0)*1024; } /*}}}*/ // CircleBuf::Reset - Reset to the default state /*{{{*/ @@ -73,10 +84,10 @@ void CircleBuf::Reset() StrPos = 0; MaxGet = (unsigned int)-1; OutQueue = string(); - if (MD5 != 0) + if (Hash != 0) { - delete MD5; - MD5 = new MD5Summation; + delete Hash; + Hash = new Hashes; } }; /*}}}*/ @@ -86,16 +97,45 @@ void CircleBuf::Reset() is non-blocking.. */ bool CircleBuf::Read(int Fd) { + unsigned long BwReadMax; + while (1) { // Woops, buffer is full if (InP - OutP == Size) return true; - + + // what's left to read in this tick + BwReadMax = CircleBuf::BwReadLimit/BW_HZ; + + if(CircleBuf::BwReadLimit) { + struct timeval now; + gettimeofday(&now,0); + + unsigned long d = (now.tv_sec-CircleBuf::BwReadTick.tv_sec)*1000000 + + now.tv_usec-CircleBuf::BwReadTick.tv_usec; + if(d > 1000000/BW_HZ) { + CircleBuf::BwReadTick = now; + CircleBuf::BwTickReadData = 0; + } + + if(CircleBuf::BwTickReadData >= BwReadMax) { + usleep(1000000/BW_HZ); + return true; + } + } + // Write the buffer segment int Res; - Res = read(Fd,Buf + (InP%Size),LeftRead()); + if(CircleBuf::BwReadLimit) { + Res = read(Fd,Buf + (InP%Size), + BwReadMax > LeftRead() ? LeftRead() : BwReadMax); + } else + Res = read(Fd,Buf + (InP%Size),LeftRead()); + if(Res > 0 && BwReadLimit > 0) + CircleBuf::BwTickReadData += Res; + if (Res == 0) return false; if (Res < 0) @@ -138,7 +178,7 @@ void CircleBuf::FillOut() unsigned long Sz = LeftRead(); if (OutQueue.length() - StrPos < Sz) Sz = OutQueue.length() - StrPos; - memcpy(Buf + (InP%Size),OutQueue.begin() + StrPos,Sz); + memcpy(Buf + (InP%Size),OutQueue.c_str() + StrPos,Sz); // Advance StrPos += Sz; @@ -182,8 +222,8 @@ bool CircleBuf::Write(int Fd) return false; } - if (MD5 != 0) - MD5->Add(Buf + (OutP%Size),Res); + if (Hash != 0) + Hash->Add(Buf + (OutP%Size),Res); OutP += Res; } @@ -199,25 +239,24 @@ bool CircleBuf::WriteTillEl(string &Data,bool Single) { if (Buf[I%Size] != '\n') continue; - for (I++; I < InP && Buf[I%Size] == '\r'; I++); + ++I; if (Single == false) { - if (Buf[I%Size] != '\n') - continue; - for (I++; I < InP && Buf[I%Size] == '\r'; I++); + if (I < InP && Buf[I%Size] == '\r') + ++I; + if (I >= InP || Buf[I%Size] != '\n') + continue; + ++I; } - if (I > InP) - I = InP; - Data = ""; while (OutP < I) { unsigned long Sz = LeftWrite(); if (Sz == 0) return false; - if (I - OutP < LeftWrite()) + if (I - OutP < Sz) Sz = I - OutP; Data += string((char *)(Buf + (OutP%Size)),Sz); OutP += Sz; @@ -285,27 +324,13 @@ bool ServerState::Open() else Proxy = getenv("http_proxy"); - // Parse no_proxy, a , separated list of hosts + // Parse no_proxy, a , separated list of domains if (getenv("no_proxy") != 0) { - const char *Start = getenv("no_proxy"); - for (const char *Cur = Start; true ; Cur++) - { - if (*Cur != ',' && *Cur != 0) - continue; - if (stringcasecmp(ServerName.Host.begin(),ServerName.Host.end(), - Start,Cur) == 0) - { - Proxy = ""; - break; - } - - Start = Cur + 1; - if (*Cur == 0) - break; - } - } - + if (CheckDomainList(ServerName.Host,getenv("no_proxy")) == true) + Proxy = ""; + } + // Determine what host and port to use based on the proxy settings int Port = 0; string Host; @@ -347,7 +372,7 @@ int ServerState::RunHeaders() { State = Header; - Owner->Status("Waiting for file"); + Owner->Status(_("Waiting for headers")); Major = 0; Minor = 0; @@ -371,7 +396,7 @@ int ServerState::RunHeaders() { string::const_iterator J = I; for (; J != Data.end() && *J != '\n' && *J != '\r';J++); - if (HeaderLine(string(I,J-I)) == false) + if (HeaderLine(string(I,J)) == false) return 2; I = J; } @@ -493,7 +518,7 @@ bool ServerState::HeaderLine(string Line) // The http server might be trying to do something evil. if (Line.length() >= MAXLEN) - return _error->Error("Got a single header line over %u chars",MAXLEN); + return _error->Error(_("Got a single header line over %u chars"),MAXLEN); string::size_type Pos = Line.find(' '); if (Pos == string::npos || Pos+1 > Line.length()) @@ -501,7 +526,7 @@ bool ServerState::HeaderLine(string Line) // Blah, some servers use "connection:closes", evil. Pos = Line.find(':'); if (Pos == string::npos || Pos + 2 > Line.length()) - return _error->Error("Bad header line"); + return _error->Error(_("Bad header line")); Pos++; } @@ -513,21 +538,21 @@ bool ServerState::HeaderLine(string Line) string Tag = string(Line,0,Pos); string Val = string(Line,Pos2); - if (stringcasecmp(Tag.begin(),Tag.begin()+4,"HTTP") == 0) + if (stringcasecmp(Tag.c_str(),Tag.c_str()+4,"HTTP") == 0) { // Evil servers return no version if (Line[4] == '/') { if (sscanf(Line.c_str(),"HTTP/%u.%u %u %[^\n]",&Major,&Minor, &Result,Code) != 4) - return _error->Error("The http server sent an invalid reply header"); + return _error->Error(_("The HTTP server sent an invalid reply header")); } else { Major = 0; Minor = 9; if (sscanf(Line.c_str(),"HTTP %u %[^\n]",&Result,Code) != 2) - return _error->Error("The http server sent an invalid reply header"); + return _error->Error(_("The HTTP server sent an invalid reply header")); } /* Check the HTTP response header to get the default persistance @@ -556,7 +581,7 @@ bool ServerState::HeaderLine(string Line) return true; if (sscanf(Val.c_str(),"%lu",&Size) != 1) - return _error->Error("The http server sent an invalid Content-Length header"); + return _error->Error(_("The HTTP server sent an invalid Content-Length header")); return true; } @@ -571,9 +596,9 @@ bool ServerState::HeaderLine(string Line) HaveContent = true; if (sscanf(Val.c_str(),"bytes %lu-%*u/%lu",&StartPos,&Size) != 2) - return _error->Error("The http server sent an invalid Content-Range header"); + return _error->Error(_("The HTTP server sent an invalid Content-Range header")); if ((unsigned)StartPos > Size) - return _error->Error("This http server has broken range support"); + return _error->Error(_("This HTTP server has broken range support")); return true; } @@ -597,7 +622,7 @@ bool ServerState::HeaderLine(string Line) if (stringcasecmp(Tag,"Last-Modified:") == 0) { if (StrToTime(Val,Date) == false) - return _error->Error("Unknown date format"); + return _error->Error(_("Unknown date format")); return true; } @@ -641,13 +666,13 @@ void HttpMethod::SendReq(FetchItem *Itm,CircleBuf &Out) and a no-store directive for archives. */ 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"); - else + // only generate a cache control header if we actually want to + // use a cache + if (_config->FindB("Acquire::http::No-Cache",false) == false) { if (Itm->IndexFile == true) sprintf(Buf+strlen(Buf),"Cache-Control: max-age=%u\r\n", - _config->FindI("Acquire::http::Max-Age",60*60*24)); + _config->FindI("Acquire::http::Max-Age",0)); else { if (_config->FindB("Acquire::http::No-Store",false) == true) @@ -655,6 +680,10 @@ void HttpMethod::SendReq(FetchItem *Itm,CircleBuf &Out) } } } + // generate a no-cache header if needed + if (_config->FindB("Acquire::http::No-Cache",false) == true) + strcat(Buf,"Cache-Control: no-cache\r\nPragma: no-cache\r\n"); + string Req = Buf; @@ -684,7 +713,7 @@ void HttpMethod::SendReq(FetchItem *Itm,CircleBuf &Out) Req += string("Authorization: Basic ") + Base64Encode(Uri.User + ":" + Uri.Password) + "\r\n"; - Req += "User-Agent: Debian APT-HTTP/1.2\r\n\r\n"; + Req += "User-Agent: Debian APT-HTTP/1.3\r\n\r\n"; if (Debug == true) cerr << Req << endl; @@ -737,11 +766,15 @@ bool HttpMethod::Go(bool ToFile,ServerState *Srv) tv.tv_usec = 0; int Res = 0; if ((Res = select(MaxFd+1,&rfds,&wfds,0,&tv)) < 0) - return _error->Errno("select","Select failed"); + { + if (errno == EINTR) + return true; + return _error->Errno("select",_("Select failed")); + } if (Res == 0) { - _error->Error("Connection timed out"); + _error->Error(_("Connection timed out")); return ServerDie(Srv); } @@ -764,7 +797,7 @@ bool HttpMethod::Go(bool ToFile,ServerState *Srv) if (FileFD != -1 && FD_ISSET(FileFD,&wfds)) { if (Srv->In.Write(FileFD) == false) - return _error->Errno("write","Error writing to output file"); + return _error->Errno("write",_("Error writing to output file")); } // Handle commands from APT @@ -785,14 +818,17 @@ bool HttpMethod::Flush(ServerState *Srv) { if (File != 0) { - SetNonBlock(File->Fd(),false); + // on GNU/kFreeBSD, apt dies on /dev/null because non-blocking + // can't be set + if (File->Name() != "/dev/null") + SetNonBlock(File->Fd(),false); if (Srv->In.WriteSpace() == false) return true; while (Srv->In.WriteSpace() == true) { if (Srv->In.Write(File->Fd()) == false) - return _error->Errno("write","Error writing to file"); + return _error->Errno("write",_("Error writing to file")); if (Srv->In.IsLimit() == true) return true; } @@ -813,11 +849,14 @@ bool HttpMethod::ServerDie(ServerState *Srv) // Dump the buffer to the file if (Srv->State == ServerState::Data) { - SetNonBlock(File->Fd(),false); + // on GNU/kFreeBSD, apt dies on /dev/null because non-blocking + // can't be set + if (File->Name() != "/dev/null") + SetNonBlock(File->Fd(),false); while (Srv->In.WriteSpace() == true) { if (Srv->In.Write(File->Fd()) == false) - return _error->Errno("write","Error writing to the file"); + return _error->Errno("write",_("Error writing to the file")); // Done if (Srv->In.IsLimit() == true) @@ -831,9 +870,9 @@ bool HttpMethod::ServerDie(ServerState *Srv) { Srv->Close(); if (LErrno == 0) - return _error->Error("Error reading from server Remote end closed connection"); + return _error->Error(_("Error reading from server. Remote end closed connection")); errno = LErrno; - return _error->Errno("read","Error reading from server"); + return _error->Errno("read",_("Error reading from server")); } else { @@ -906,16 +945,16 @@ int HttpMethod::DealWithHeaders(FetchResult &Res,ServerState *Srv) // Set the start point lseek(File->Fd(),0,SEEK_END); - delete Srv->In.MD5; - Srv->In.MD5 = new MD5Summation; + delete Srv->In.Hash; + Srv->In.Hash = new Hashes; - // Fill the MD5 Hash if the file is non-empty (resume) + // Fill the Hash if the file is non-empty (resume) if (Srv->StartPos > 0) { lseek(File->Fd(),0,SEEK_SET); - if (Srv->In.MD5->AddFD(File->Fd(),Srv->StartPos) == false) + if (Srv->In.Hash->AddFD(File->Fd(),Srv->StartPos) == false) { - _error->Errno("read","Problem hashing file"); + _error->Errno("read",_("Problem hashing file")); return 5; } lseek(File->Fd(),0,SEEK_END); @@ -1064,7 +1103,7 @@ int HttpMethod::Loop() // The header data is bad case 2: { - _error->Error("Bad header Data"); + _error->Error(_("Bad header data")); Fail(true); RotateDNS(); continue; @@ -1081,7 +1120,7 @@ int HttpMethod::Loop() if (FailCounter >= 2) { - Fail("Connection failed",true); + Fail(_("Connection failed"),true); FailCounter = 0; } @@ -1123,7 +1162,7 @@ int HttpMethod::Loop() // Send status to APT if (Result == true) { - Res.MD5Sum = Server->In.MD5->Result(); + Res.TakeHashes(*Server->In.Hash); URIDone(Res); } else @@ -1149,6 +1188,9 @@ int HttpMethod::Loop() // Hard internal error, kill the connection and fail case 5: { + delete File; + File = 0; + Fail(); RotateDNS(); Server->Close(); @@ -1169,7 +1211,7 @@ int HttpMethod::Loop() } default: - Fail("Internal error"); + Fail(_("Internal error")); break; } @@ -1182,7 +1224,11 @@ int HttpMethod::Loop() int main() { + setlocale(LC_ALL, ""); + HttpMethod Mth; return Mth.Loop(); } + +