X-Git-Url: https://git.saurik.com/apt.git/blobdiff_plain/7330f4df8b31e66f6557bf49c9c90ad9a73ff459..0d303f1764645284b33924c9be8bf29f0a32ca5c:/methods/server.cc diff --git a/methods/server.cc b/methods/server.cc index a2128441c..c4689ff12 100644 --- a/methods/server.cc +++ b/methods/server.cc @@ -10,32 +10,27 @@ // Include Files /*{{{*/ #include -#include #include #include #include -#include -#include +#include +#include +#include +#include +#include +#include #include #include -#include +#include #include -#include -#include -#include -#include -#include #include +#include #include +#include +#include -// Internet stuff -#include - -#include "config.h" -#include "connect.h" -#include "rfc2553emu.h" -#include "http.h" +#include "server.h" #include /*}}}*/ @@ -49,7 +44,8 @@ time_t ServerMethod::FailTime = 0; // --------------------------------------------------------------------- /* Returns 0 if things are OK, 1 if an IO error occurred and 2 if a header parse error occurred */ -ServerState::RunHeadersResult ServerState::RunHeaders(FileFd * const File) +ServerState::RunHeadersResult ServerState::RunHeaders(FileFd * const File, + const std::string &Uri) { State = Header; @@ -71,7 +67,7 @@ ServerState::RunHeadersResult ServerState::RunHeaders(FileFd * const File) continue; if (Owner->Debug == true) - clog << Data; + clog << "Answer for: " << Uri << endl << Data; for (string::const_iterator I = Data.begin(); I < Data.end(); ++I) { @@ -86,7 +82,7 @@ ServerState::RunHeadersResult ServerState::RunHeaders(FileFd * const File) if (Result == 100) continue; - // Tidy up the connection persistance state. + // Tidy up the connection persistence state. if (Encoding == Closes && HaveContent == true) Persistent = false; @@ -119,10 +115,10 @@ bool ServerState::HeaderLine(string Line) string::size_type Pos2 = Pos; while (Pos2 < Line.length() && isspace(Line[Pos2]) != 0) Pos2++; - + string Tag = string(Line,0,Pos); string Val = string(Line,Pos2); - + if (stringcasecmp(Tag.c_str(),Tag.c_str()+4,"HTTP") == 0) { // Evil servers return no version @@ -146,7 +142,7 @@ bool ServerState::HeaderLine(string Line) return _error->Error(_("The HTTP server sent an invalid reply header")); } - /* Check the HTTP response header to get the default persistance + /* Check the HTTP response header to get the default persistence state. */ if (Major < 1) Persistent = false; @@ -159,14 +155,14 @@ bool ServerState::HeaderLine(string Line) } return true; - } - + } + if (stringcasecmp(Tag,"Content-Length:") == 0) { if (Encoding == Closes) Encoding = Stream; HaveContent = true; - + // The length is already set from the Content-Range header if (StartPos != 0) return true; @@ -184,7 +180,7 @@ bool ServerState::HeaderLine(string Line) HaveContent = true; return true; } - + if (stringcasecmp(Tag,"Content-Range:") == 0) { HaveContent = true; @@ -201,12 +197,12 @@ bool ServerState::HeaderLine(string Line) return _error->Error(_("This HTTP server has broken range support")); return true; } - + if (stringcasecmp(Tag,"Transfer-Encoding:") == 0) { HaveContent = true; if (stringcasecmp(Val,"chunked") == 0) - Encoding = Chunked; + Encoding = Chunked; return true; } @@ -218,7 +214,7 @@ bool ServerState::HeaderLine(string Line) Persistent = true; return true; } - + if (stringcasecmp(Tag,"Last-Modified:") == 0) { if (RFC1123StrToTime(Val.c_str(), Date) == false) @@ -291,11 +287,15 @@ ServerMethod::DealWithHeaders(FetchResult &Res) } else { - NextURI = DeQuoteString(Server->Location); - URI tmpURI = NextURI; - // Do not allow a redirection to switch protocol - if (tmpURI.Access == "http") - return TRY_AGAIN_OR_REDIRECT; + NextURI = DeQuoteString(Server->Location); + URI tmpURI = NextURI; + URI Uri = Queue->Uri; + // same protocol redirects are okay + if (tmpURI.Access == Uri.Access) + return TRY_AGAIN_OR_REDIRECT; + // as well as http to https + else if (Uri.Access == "http" && tmpURI.Access == "https") + return TRY_AGAIN_OR_REDIRECT; } /* else pass through for error message */ } @@ -324,10 +324,10 @@ ServerMethod::DealWithHeaders(FetchResult &Res) failure */ if (Server->Result < 200 || Server->Result >= 300) { - char err[255]; - snprintf(err,sizeof(err)-1,"HttpError%i",Server->Result); + std::string err; + strprintf(err, "HttpError%u", Server->Result); SetFailReason(err); - _error->Error("%u %s",Server->Result,Server->Code); + _error->Error("%u %s", Server->Result, Server->Code); if (Server->HaveContent == true) return ERROR_WITH_CONTENT_PAGE; return ERROR_UNRECOVERABLE; @@ -362,20 +362,20 @@ ServerMethod::DealWithHeaders(FetchResult &Res) /*}}}*/ // ServerMethod::SigTerm - Handle a fatal signal /*{{{*/ // --------------------------------------------------------------------- -/* This closes and timestamps the open file. This is neccessary to get +/* This closes and timestamps the open file. This is necessary to get resume behavoir on user abort */ void ServerMethod::SigTerm(int) { if (FailFd == -1) _exit(100); + + struct timeval times[2]; + times[0].tv_sec = FailTime; + times[1].tv_sec = FailTime; + times[0].tv_usec = times[1].tv_usec = 0; + utimes(FailFile.c_str(), times); close(FailFd); - - // Timestamp - struct utimbuf UBuf; - UBuf.actime = FailTime; - UBuf.modtime = FailTime; - utime(FailFile.c_str(),&UBuf); - + _exit(100); } /*}}}*/ @@ -393,9 +393,16 @@ bool ServerMethod::Fetch(FetchItem *) for (FetchItem *I = Queue; I != 0 && Depth < (signed)PipelineDepth; I = I->Next, Depth++) { - // If pipelining is disabled, we only queue 1 request - if (Server->Pipeline == false && Depth >= 0) - break; + if (Depth >= 0) + { + // If pipelining is disabled, we only queue 1 request + if (Server->Pipeline == false) + break; + // if we have no hashes, do at most one such request + // as we can't fixup pipeling misbehaviors otherwise + else if (I->ExpectedHashes.usable() == false) + break; + } // Make sure we stick with the same server if (Server->Comp(I->Uri) == false) @@ -409,7 +416,7 @@ bool ServerMethod::Fetch(FetchItem *) } return true; -}; +} /*}}}*/ // ServerMethod::Loop - Main loop /*{{{*/ int ServerMethod::Loop() @@ -479,7 +486,7 @@ int ServerMethod::Loop() Fetch(0); // Fetch the next URL header data from the server. - switch (Server->RunHeaders(File)) + switch (Server->RunHeaders(File, Queue->Uri)) { case ServerState::RUN_HEADERS_OK: break; @@ -525,6 +532,13 @@ int ServerMethod::Loop() // Run the data bool Result = true; + + // ensure we don't fetch too much + // we could do "Server->MaximumSize = Queue->MaximumSize" here + // but that would break the clever pipeline messup detection + // so instead we use the size of the biggest item in the queue + Server->MaximumSize = FindMaximumObjectSizeInQueue(); + if (Server->HaveContent) Result = Server->RunData(File); @@ -539,16 +553,46 @@ int ServerMethod::Loop() File = 0; // Timestamp - struct utimbuf UBuf; - time(&UBuf.actime); - UBuf.actime = Server->Date; - UBuf.modtime = Server->Date; - utime(Queue->DestFile.c_str(),&UBuf); + struct timeval times[2]; + times[0].tv_sec = times[1].tv_sec = Server->Date; + times[0].tv_usec = times[1].tv_usec = 0; + utimes(Queue->DestFile.c_str(), times); // Send status to APT if (Result == true) { - Res.TakeHashes(*Server->GetHashes()); + Hashes * const resultHashes = Server->GetHashes(); + HashStringList const hashList = resultHashes->GetHashStringList(); + if (PipelineDepth != 0 && Queue->ExpectedHashes.usable() == true && Queue->ExpectedHashes != hashList) + { + // we did not get the expected hash… mhhh: + // could it be that server/proxy messed up pipelining? + FetchItem * BeforeI = Queue; + for (FetchItem *I = Queue->Next; I != 0 && I != QueueBack; I = I->Next) + { + if (I->ExpectedHashes.usable() == true && I->ExpectedHashes == hashList) + { + // yes, he did! Disable pipelining and rewrite queue + if (Server->Pipeline == true) + { + // FIXME: fake a warning message as we have no proper way of communicating here + std::string out; + strprintf(out, _("Automatically disabled %s due to incorrect response from server/proxy. (man 5 apt.conf)"), "Acquire::http::PipelineDepth"); + std::cerr << "W: " << out << std::endl; + Server->Pipeline = false; + // we keep the PipelineDepth value so that the rest of the queue can be fixed up as well + } + Rename(Res.Filename, I->DestFile); + Res.Filename = I->DestFile; + BeforeI->Next = I->Next; + I->Next = Queue; + Queue = I; + break; + } + BeforeI = I; + } + } + Res.TakeHashes(*resultHashes); URIDone(Res); } else @@ -568,7 +612,10 @@ int ServerMethod::Loop() QueueBack = Queue; } else + { + Server->Close(); Fail(true); + } } break; } @@ -661,5 +708,15 @@ int ServerMethod::Loop() } return 0; +} + /*}}}*/ + /*{{{*/ +unsigned long long +ServerMethod::FindMaximumObjectSizeInQueue() const +{ + unsigned long long MaxSizeInQueue = 0; + for (FetchItem *I = Queue; I != 0 && I != QueueBack; I = I->Next) + MaxSizeInQueue = std::max(MaxSizeInQueue, I->MaximumSize); + return MaxSizeInQueue; } /*}}}*/