summaryrefslogtreecommitdiff
path: root/methods
diff options
context:
space:
mode:
Diffstat (limited to 'methods')
-rw-r--r--methods/aptmethod.h4
-rw-r--r--methods/http.cc9
-rw-r--r--methods/http.h2
-rw-r--r--methods/https.cc12
-rw-r--r--methods/server.cc80
-rw-r--r--methods/server.h5
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 */