diff options
Diffstat (limited to 'methods')
-rw-r--r-- | methods/aptmethod.h | 4 | ||||
-rw-r--r-- | methods/http.cc | 9 | ||||
-rw-r--r-- | methods/http.h | 2 | ||||
-rw-r--r-- | methods/https.cc | 12 | ||||
-rw-r--r-- | methods/server.cc | 80 | ||||
-rw-r--r-- | methods/server.h | 5 |
6 files changed, 69 insertions, 43 deletions
diff --git a/methods/aptmethod.h b/methods/aptmethod.h index 38f451708..04c4fa99b 100644 --- a/methods/aptmethod.h +++ b/methods/aptmethod.h @@ -86,10 +86,10 @@ public: } std::string ConfigFind(char const * const postfix, std::string const &defValue) const APT_NONNULL(2) { - for (auto && name: methodNames) + for (auto name = methodNames.rbegin(); name != methodNames.rend(); ++name) { std::string conf; - strprintf(conf, "Acquire::%s::%s", name.c_str(), postfix); + strprintf(conf, "Acquire::%s::%s", name->c_str(), postfix); auto const value = _config->Find(conf); if (value.empty() == false) return value; diff --git a/methods/http.cc b/methods/http.cc index 0358b50cd..11136bb9a 100644 --- a/methods/http.cc +++ b/methods/http.cc @@ -647,6 +647,13 @@ bool HttpServerState::InitHashes(HashStringList const &ExpectedHashes) /*{{{*/ return true; } /*}}}*/ +void HttpServerState::Reset(bool const Everything) /*{{{*/ +{ + ServerState::Reset(Everything); + if (Everything) + ServerFd = -1; +} + /*}}}*/ APT_PURE Hashes * HttpServerState::GetHashes() /*{{{*/ { @@ -899,7 +906,7 @@ void HttpMethod::SendReq(FetchItem *Itm) // Check for a partial file and send if-queries accordingly struct stat SBuf; - if (stat(Itm->DestFile.c_str(),&SBuf) >= 0 && SBuf.st_size > 0) + if (Server->RangesAllowed && stat(Itm->DestFile.c_str(),&SBuf) >= 0 && SBuf.st_size > 0) Req << "Range: bytes=" << std::to_string(SBuf.st_size) << "-\r\n" << "If-Range: " << TimeRFC1123(SBuf.st_mtime, false) << "\r\n"; else if (Itm->LastModified != 0) diff --git a/methods/http.h b/methods/http.h index 644e576f0..b7341f5f8 100644 --- a/methods/http.h +++ b/methods/http.h @@ -103,7 +103,7 @@ struct HttpServerState: public ServerState virtual bool WriteResponse(std::string const &Data) APT_OVERRIDE; public: - virtual void Reset() APT_OVERRIDE { ServerState::Reset(); ServerFd = -1; }; + virtual void Reset(bool const Everything = true) APT_OVERRIDE; virtual bool RunData(FileFd * const File) APT_OVERRIDE; virtual bool RunDataToDevNull() APT_OVERRIDE; diff --git a/methods/https.cc b/methods/https.cc index 283126f6b..b2d05136c 100644 --- a/methods/https.cc +++ b/methods/https.cc @@ -382,8 +382,15 @@ bool HttpsMethod::Fetch(FetchItem *Itm) headers = curl_slist_append(headers, "Accept: text/*"); } + // go for it - if the file exists, append on it + File = new FileFd(Itm->DestFile, FileFd::WriteAny); + if (Server == nullptr || Server->Comp(Itm->Uri) == false) + Server = CreateServerState(Itm->Uri); + else + Server->Reset(false); + // if we have the file send an if-range query with a range header - if (stat(Itm->DestFile.c_str(),&SBuf) >= 0 && SBuf.st_size > 0) + if (Server->RangesAllowed && stat(Itm->DestFile.c_str(),&SBuf) >= 0 && SBuf.st_size > 0) { std::string Buf; strprintf(Buf, "Range: bytes=%lli-", (long long) SBuf.st_size); @@ -397,9 +404,6 @@ bool HttpsMethod::Fetch(FetchItem *Itm) curl_easy_setopt(curl, CURLOPT_TIMEVALUE, Itm->LastModified); } - // go for it - if the file exists, append on it - File = new FileFd(Itm->DestFile, FileFd::WriteAny); - Server = CreateServerState(Itm->Uri); if (Server->InitHashes(Itm->ExpectedHashes) == false) return false; diff --git a/methods/server.cc b/methods/server.cc index 0888617b1..af7276bad 100644 --- a/methods/server.cc +++ b/methods/server.cc @@ -46,20 +46,9 @@ time_t ServerMethod::FailTime = 0; ServerState::RunHeadersResult ServerState::RunHeaders(FileFd * const File, const std::string &Uri) { - State = Header; - + Reset(false); Owner->Status(_("Waiting for headers")); - Major = 0; - Minor = 0; - Result = 0; - TotalFileSize = 0; - JunkSize = 0; - StartPos = 0; - Encoding = Closes; - HaveContent = false; - time(&Date); - do { string Data; @@ -101,25 +90,7 @@ bool ServerState::HeaderLine(string Line) if (Line.empty() == true) return true; - string::size_type Pos = Line.find(' '); - if (Pos == string::npos || Pos+1 > Line.length()) - { - // Blah, some servers use "connection:closes", evil. - Pos = Line.find(':'); - if (Pos == string::npos || Pos + 2 > Line.length()) - return _error->Error(_("Bad header line")); - Pos++; - } - - // Parse off any trailing spaces between the : and the next word. - string::size_type Pos2 = Pos; - while (Pos2 < Line.length() && isspace_ascii(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) + if (Line.size() > 4 && stringcasecmp(Line.data(), Line.data()+4, "HTTP") == 0) { // Evil servers return no version if (Line[4] == '/') @@ -163,6 +134,21 @@ bool ServerState::HeaderLine(string Line) return true; } + // Blah, some servers use "connection:closes", evil. + // and some even send empty header fields… + string::size_type Pos = Line.find(':'); + if (Pos == string::npos) + return _error->Error(_("Bad header line")); + ++Pos; + + // Parse off any trailing spaces between the : and the next word. + string::size_type Pos2 = Pos; + while (Pos2 < Line.length() && isspace_ascii(Line[Pos2]) != 0) + Pos2++; + + string const Tag(Line,0,Pos); + string const Val(Line,Pos2); + if (stringcasecmp(Tag,"Content-Length:") == 0) { if (Encoding == Closes) @@ -222,8 +208,16 @@ bool ServerState::HeaderLine(string Line) if (stringcasecmp(Tag,"Connection:") == 0) { if (stringcasecmp(Val,"close") == 0) + { Persistent = false; - if (stringcasecmp(Val,"keep-alive") == 0) + Pipeline = false; + /* Some servers send error pages (as they are dynamically generated) + for simplicity via a connection close instead of e.g. chunked, + so assuming an always closing server only if we get a file + close */ + if (Result >= 200 && Result < 300) + PipelineAllowed = false; + } + else if (stringcasecmp(Val,"keep-alive") == 0) Persistent = true; return true; } @@ -241,6 +235,15 @@ bool ServerState::HeaderLine(string Line) return true; } + if (stringcasecmp(Tag, "Accept-Ranges:") == 0) + { + std::string ranges = ',' + Val + ','; + ranges.erase(std::remove(ranges.begin(), ranges.end(), ' '), ranges.end()); + if (ranges.find(",bytes,") == std::string::npos) + RangesAllowed = false; + return true; + } + return true; } /*}}}*/ @@ -257,6 +260,19 @@ bool ServerState::AddPartialFileToHashes(FileFd &File) /*{{{*/ return GetHashes()->AddFD(File, StartPos); } /*}}}*/ +void ServerState::Reset(bool const Everything) /*{{{*/ +{ + Major = 0; Minor = 0; Result = 0; Code[0] = '\0'; + TotalFileSize = 0; JunkSize = 0; StartPos = 0; + Encoding = Closes; time(&Date); HaveContent = false; + State = Header; MaximumSize = 0; + if (Everything) + { + Persistent = false; Pipeline = false; PipelineAllowed = true; + RangesAllowed = true; + } +} + /*}}}*/ // ServerMethod::DealWithHeaders - Handle the retrieved header data /*{{{*/ // --------------------------------------------------------------------- diff --git a/methods/server.h b/methods/server.h index 1d114354f..c3adba87a 100644 --- a/methods/server.h +++ b/methods/server.h @@ -51,6 +51,7 @@ struct ServerState enum {Header, Data} State; bool Persistent; bool PipelineAllowed; + bool RangesAllowed; std::string Location; // This is a Persistent attribute of the server itself. @@ -84,9 +85,7 @@ struct ServerState bool AddPartialFileToHashes(FileFd &File); bool Comp(URI Other) const {return Other.Host == ServerName.Host && Other.Port == ServerName.Port;}; - virtual void Reset() {Major = 0; Minor = 0; Result = 0; Code[0] = '\0'; TotalFileSize = 0; JunkSize = 0; - StartPos = 0; Encoding = Closes; time(&Date); HaveContent = false; - State = Header; Persistent = false; Pipeline = false; MaximumSize = 0; PipelineAllowed = true;}; + virtual void Reset(bool const Everything = true); virtual bool WriteResponse(std::string const &Data) = 0; /** \brief Transfer the data from the socket */ |