#include <apt-pkg/configuration.h>
#include <apt-pkg/error.h>
+#include <algorithm>
#include <locale>
#include <string>
+#include <vector>
#include <sys/time.h>
#include <sys/types.h>
#include <apti18n.h>
+static bool hasDoubleColon(std::string const &n)
+{
+ return n.find("::") != std::string::npos;
+}
+
class aptMethod : public pkgAcqMethod
{
protected:
- std::string Binary;
+ std::string const Binary;
public:
virtual bool Configuration(std::string Message) APT_OVERRIDE
return true;
}
- bool CalculateHashes(FetchItem const * const Itm, FetchResult &Res) const
+ bool CalculateHashes(FetchItem const * const Itm, FetchResult &Res) const APT_NONNULL(2)
{
Hashes Hash(Itm->ExpectedHashes);
FileFd Fd;
va_end(args);
}
- bool TransferModificationTimes(char const * const From, char const * const To, time_t &LastModified)
+ std::vector<std::string> methodNames;
+ void setPostfixForMethodNames(char const * const postfix) APT_NONNULL(2)
+ {
+ methodNames.erase(std::remove_if(methodNames.begin(), methodNames.end(), hasDoubleColon), methodNames.end());
+ decltype(methodNames) toAdd;
+ for (auto && name: methodNames)
+ toAdd.emplace_back(name + "::" + postfix);
+ std::move(toAdd.begin(), toAdd.end(), std::back_inserter(methodNames));
+ }
+ bool DebugEnabled() const
+ {
+ if (methodNames.empty())
+ return false;
+ auto const sni = std::find_if_not(methodNames.crbegin(), methodNames.crend(), hasDoubleColon);
+ if (unlikely(sni == methodNames.crend()))
+ return false;
+ auto const ln = methodNames[methodNames.size() - 1];
+ // worst case: all three are the same
+ std::string confln, confsn, confpn;
+ strprintf(confln, "Debug::Acquire::%s", ln.c_str());
+ strprintf(confsn, "Debug::Acquire::%s", sni->c_str());
+ auto const pni = sni->substr(0, sni->find('+'));
+ strprintf(confpn, "Debug::Acquire::%s", pni.c_str());
+ return _config->FindB(confln,_config->FindB(confsn, _config->FindB(confpn, false)));
+ }
+ std::string ConfigFind(char const * const postfix, std::string const &defValue) const APT_NONNULL(2)
+ {
+ for (auto && name: methodNames)
+ {
+ std::string conf;
+ strprintf(conf, "Acquire::%s::%s", name.c_str(), postfix);
+ auto const value = _config->Find(conf);
+ if (value.empty() == false)
+ return value;
+ }
+ return defValue;
+ }
+ std::string ConfigFind(std::string const &postfix, std::string const &defValue) const
+ {
+ return ConfigFind(postfix.c_str(), defValue);
+ }
+ bool ConfigFindB(char const * const postfix, bool const defValue) const APT_NONNULL(2)
+ {
+ return StringToBool(ConfigFind(postfix, defValue ? "yes" : "no"), defValue);
+ }
+ int ConfigFindI(char const * const postfix, int const defValue) const APT_NONNULL(2)
+ {
+ char *End;
+ std::string const value = ConfigFind(postfix, "");
+ auto const Res = strtol(value.c_str(), &End, 0);
+ if (value.c_str() == End)
+ return defValue;
+ return Res;
+ }
+
+ bool TransferModificationTimes(char const * const From, char const * const To, time_t &LastModified) APT_NONNULL(2, 3)
{
if (strcmp(To, "/dev/null") == 0)
return true;
return true;
}
- aptMethod(char const * const Binary, char const * const Ver, unsigned long const Flags) :
- pkgAcqMethod(Ver, Flags), Binary(Binary)
+ aptMethod(std::string &&Binary, char const * const Ver, unsigned long const Flags) APT_NONNULL(3) :
+ pkgAcqMethod(Ver, Flags), Binary(Binary), methodNames({Binary})
{
try {
std::locale::global(std::locale(""));
URI Get = Itm->Uri;
string File = Get.Path;
- Debug = _config->FindB("Debug::Acquire::cdrom", false);
+ Debug = DebugEnabled();
if (Debug)
clog << "CDROMMethod::Fetch " << Itm->Uri << endl;
return true;
}
- bool AutoDetect = _config->FindB("Acquire::cdrom::AutoDetect", true);
+ bool const AutoDetect = ConfigFindB("AutoDetect", true);
CDROM = _config->FindDir("Acquire::cdrom::mount");
if (Debug)
clog << "Looking for CDROM at " << CDROM << endl;
vector<Signer> &SoonWorthlessSigners,
vector<string> &NoPubKeySigners)
{
- bool const Debug = _config->FindB("Debug::Acquire::gpgv", false);
+ bool const Debug = DebugEnabled();
if (Debug == true)
std::clog << "inside VerifyGetSigners" << std::endl;
std::move(NoPubKeySigners.begin(), NoPubKeySigners.end(), std::back_inserter(Res.GPGVOutput));
URIDone(Res);
- if (_config->FindB("Debug::Acquire::gpgv", false))
- {
+ if (DebugEnabled())
std::clog << "apt-key succeeded\n";
- }
return true;
}
// CircleBuf::CircleBuf - Circular input buffer /*{{{*/
// ---------------------------------------------------------------------
/* */
-CircleBuf::CircleBuf(unsigned long long Size)
+CircleBuf::CircleBuf(HttpMethod const * const Owner, unsigned long long Size)
: Size(Size), Hash(NULL), TotalWriten(0)
{
Buf = new unsigned char[Size];
Reset();
- CircleBuf::BwReadLimit = _config->FindI("Acquire::http::Dl-Limit",0)*1024;
+ CircleBuf::BwReadLimit = Owner->ConfigFindI("Dl-Limit", 0) * 1024;
}
/*}}}*/
// CircleBuf::Reset - Reset to the default state /*{{{*/
}
// HttpServerState::HttpServerState - Constructor /*{{{*/
-HttpServerState::HttpServerState(URI Srv,HttpMethod *Owner) : ServerState(Srv, Owner), In(64*1024), Out(4*1024)
+HttpServerState::HttpServerState(URI Srv,HttpMethod *Owner) : ServerState(Srv, Owner), In(Owner, 64*1024), Out(Owner, 4*1024)
{
- TimeOut = _config->FindI("Acquire::http::Timeout",TimeOut);
+ TimeOut = Owner->ConfigFindI("Timeout", TimeOut);
Reset();
}
/*}}}*/
// Determine the proxy setting
AutoDetectProxy(ServerName);
- string SpecificProxy = _config->Find("Acquire::http::Proxy::" + ServerName.Host);
+ string SpecificProxy = Owner->ConfigFind("Proxy::" + ServerName.Host, "");
if (!SpecificProxy.empty())
{
if (SpecificProxy == "DIRECT")
}
else
{
- string DefProxy = _config->Find("Acquire::http::Proxy");
+ string DefProxy = Owner->ConfigFind("Proxy", "");
if (!DefProxy.empty())
{
Proxy = DefProxy;
FD_SET(FileFD,&wfds);
// Add stdin
- if (_config->FindB("Acquire::http::DependOnSTDIN", true) == true)
+ if (Owner->ConfigFindB("DependOnSTDIN", true) == true)
FD_SET(STDIN_FILENO,&rfds);
// Figure out the max fd
void HttpMethod::SendReq(FetchItem *Itm)
{
URI Uri = Itm->Uri;
+ {
+ auto const plus = Binary.find('+');
+ if (plus != std::string::npos)
+ Uri.Access = Binary.substr(plus + 1);
+ }
// The HTTP server expects a hostname with a trailing :port
std::stringstream Req;
if (Server->Proxy.empty() == true || Server->Proxy.Host.empty())
requesturi = Uri.Path;
else
- requesturi = Itm->Uri;
+ requesturi = Uri;
// The "+" is encoded as a workaround for a amazon S3 bug
// see LP bugs #1003633 and #1086997.
Req << "Host: " << ProperHost << "\r\n";
// generate a cache control header (if needed)
- if (_config->FindB("Acquire::http::No-Cache",false) == true)
+ if (ConfigFindB("No-Cache",false) == true)
Req << "Cache-Control: no-cache\r\n"
<< "Pragma: no-cache\r\n";
else if (Itm->IndexFile == true)
- Req << "Cache-Control: max-age=" << std::to_string(_config->FindI("Acquire::http::Max-Age",0)) << "\r\n";
- else if (_config->FindB("Acquire::http::No-Store",false) == true)
+ Req << "Cache-Control: max-age=" << std::to_string(ConfigFindI("Max-Age", 0)) << "\r\n";
+ else if (ConfigFindB("No-Store", false) == true)
Req << "Cache-Control: no-store\r\n";
// If we ask for uncompressed files servers might respond with content-
// see 657029, 657560 and co, so if we have no extension on the request
// ask for text only. As a sidenote: If there is nothing to negotate servers
// seem to be nice and ignore it.
- if (_config->FindB("Acquire::http::SendAccept", true) == true)
+ if (ConfigFindB("SendAccept", true) == true)
{
size_t const filepos = Itm->Uri.find_last_of('/');
string const file = Itm->Uri.substr(filepos + 1);
Req << "Authorization: Basic "
<< Base64Encode(Uri.User + ":" + Uri.Password) << "\r\n";
- Req << "User-Agent: " << _config->Find("Acquire::http::User-Agent",
+ Req << "User-Agent: " << ConfigFind("User-Agent",
"Debian APT-HTTP/1.3 (" PACKAGE_VERSION ")") << "\r\n";
Req << "\r\n";
Server->WriteResponse(Req.str());
}
/*}}}*/
-// HttpMethod::Configuration - Handle a configuration message /*{{{*/
-// ---------------------------------------------------------------------
-/* We stash the desired pipeline depth */
-bool HttpMethod::Configuration(string Message)
-{
- if (ServerMethod::Configuration(Message) == false)
- return false;
-
- AllowRedirect = _config->FindB("Acquire::http::AllowRedirect",true);
- PipelineDepth = _config->FindI("Acquire::http::Pipeline-Depth",
- PipelineDepth);
- Debug = _config->FindB("Debug::Acquire::http",false);
-
- return true;
-}
- /*}}}*/
std::unique_ptr<ServerState> HttpMethod::CreateServerState(URI const &uri)/*{{{*/
{
return std::unique_ptr<ServerState>(new HttpServerState(uri, this));
return FILE_IS_OPEN;
}
/*}}}*/
+HttpMethod::HttpMethod(std::string &&pProg) : ServerMethod(pProg.c_str(), "1.2", Pipeline | SendConfig)/*{{{*/
+{
+ auto addName = std::inserter(methodNames, methodNames.begin());
+ if (Binary != "http")
+ addName = "http";
+ auto const plus = Binary.find('+');
+ if (plus != std::string::npos)
+ addName = Binary.substr(0, plus);
+ File = 0;
+ Server = 0;
+}
+ /*}}}*/
// Dump everything
void Stats();
- explicit CircleBuf(unsigned long long Size);
+ CircleBuf(HttpMethod const * const Owner, unsigned long long Size);
~CircleBuf();
};
public:
virtual void SendReq(FetchItem *Itm) APT_OVERRIDE;
- virtual bool Configuration(std::string Message) APT_OVERRIDE;
-
virtual std::unique_ptr<ServerState> CreateServerState(URI const &uri) APT_OVERRIDE;
virtual void RotateDNS() APT_OVERRIDE;
virtual DealWithHeadersResult DealWithHeaders(FetchResult &Res) APT_OVERRIDE;
public:
friend struct HttpServerState;
- HttpMethod() : ServerMethod("http", "1.2",Pipeline | SendConfig)
- {
- File = 0;
- Server = 0;
- };
+ explicit HttpMethod(std::string &&pProg);
};
#endif
#include "http.h"
-int main()
+int main(int, const char *argv[])
{
// ignore SIGPIPE, this can happen on write() if the socket
// closes the connection (this is dealt with via ServerDie())
signal(SIGPIPE, SIG_IGN);
-
- return HttpMethod().Loop();
+ std::string Binary = flNotDir(argv[0]);
+ if (Binary.find('+') == std::string::npos && Binary != "http")
+ Binary.append("+http");
+ return HttpMethod(std::move(Binary)).Loop();
}
#include <sys/time.h>
#include <unistd.h>
#include <stdio.h>
-#include <iostream>
-#include <sstream>
#include <ctype.h>
#include <stdlib.h>
+#include <array>
+#include <iostream>
+#include <sstream>
+
+
#include "https.h"
#include <apti18n.h>
// HttpsServerState::HttpsServerState - Constructor /*{{{*/
HttpsServerState::HttpsServerState(URI Srv,HttpsMethod * Owner) : ServerState(Srv, Owner), Hash(NULL)
{
- TimeOut = _config->FindI("Acquire::https::Timeout",TimeOut);
+ TimeOut = Owner->ConfigFindI("Timeout", TimeOut);
Reset();
}
/*}}}*/
curl_easy_setopt(curl, CURLOPT_PROXY, "");
// Determine the proxy setting - try https first, fallback to http and use env at last
- string UseProxy = _config->Find("Acquire::https::Proxy::" + ServerName.Host,
- _config->Find("Acquire::http::Proxy::" + ServerName.Host).c_str());
-
+ string UseProxy = ConfigFind("Proxy::" + ServerName.Host, "");
if (UseProxy.empty() == true)
- UseProxy = _config->Find("Acquire::https::Proxy", _config->Find("Acquire::http::Proxy").c_str());
-
- // User want to use NO proxy, so nothing to setup
+ UseProxy = ConfigFind("Proxy", "");
+ // User wants to use NO proxy, so nothing to setup
if (UseProxy == "DIRECT")
return true;
- // Parse no_proxy, a comma (,) separated list of domains we don't want to use
+ // Parse no_proxy, a comma (,) separated list of domains we don't want to use
// a proxy for so we stop right here if it is in the list
if (getenv("no_proxy") != 0 && CheckDomainList(ServerName.Host,getenv("no_proxy")) == true)
return true;
if (UseProxy.empty() == true)
{
- const char* result = getenv("https_proxy");
+ const char* result = nullptr;
+ if (std::find(methodNames.begin(), methodNames.end(), "https") != methodNames.end())
+ result = getenv("https_proxy");
// FIXME: Fall back to http_proxy is to remain compatible with
// existing setups and behaviour of apt.conf. This should be
// deprecated in the future (including apt.conf). Most other
// programs do not fall back to http proxy settings and neither
// should Apt.
- if (result == NULL)
- result = getenv("http_proxy");
- UseProxy = result == NULL ? "" : result;
+ if (result == nullptr && std::find(methodNames.begin(), methodNames.end(), "http") != methodNames.end())
+ result = getenv("http_proxy");
+ UseProxy = result == nullptr ? "" : result;
}
// Determine what host and port to use based on the proxy settings
struct curl_slist *headers=NULL;
char curl_errorstr[CURL_ERROR_SIZE];
URI Uri = Itm->Uri;
- string remotehost = Uri.Host;
+ setPostfixForMethodNames(Uri.Host.c_str());
+ AllowRedirect = ConfigFindB("AllowRedirect", true);
+ Debug = DebugEnabled();
// TODO:
// - http::Pipeline-Depth
// - error checking/reporting
// - more debug options? (CURLOPT_DEBUGFUNCTION?)
+ {
+ auto const plus = Binary.find('+');
+ if (plus != std::string::npos)
+ Uri.Access = Binary.substr(plus + 1);
+ }
curl_easy_reset(curl);
if (SetupProxy() == false)
curl_easy_setopt(curl, CURLOPT_NOPROGRESS, true);
curl_easy_setopt(curl, CURLOPT_FILETIME, true);
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 0);
- // only allow curl to handle https, not the other stuff it supports
- curl_easy_setopt(curl, CURLOPT_PROTOCOLS, CURLPROTO_HTTPS);
- curl_easy_setopt(curl, CURLOPT_REDIR_PROTOCOLS, CURLPROTO_HTTPS);
-
- // SSL parameters are set by default to the common (non mirror-specific) value
- // if available (or a default one) and gets overload by mirror-specific ones.
-
- // File containing the list of trusted CA.
- string cainfo = _config->Find("Acquire::https::CaInfo","");
- string knob = "Acquire::https::"+remotehost+"::CaInfo";
- cainfo = _config->Find(knob.c_str(),cainfo.c_str());
- if(cainfo.empty() == false)
- curl_easy_setopt(curl, CURLOPT_CAINFO,cainfo.c_str());
-
- // Check server certificate against previous CA list ...
- bool peer_verify = _config->FindB("Acquire::https::Verify-Peer",true);
- knob = "Acquire::https::" + remotehost + "::Verify-Peer";
- peer_verify = _config->FindB(knob.c_str(), peer_verify);
- curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, peer_verify);
-
- // ... and hostname against cert CN or subjectAltName
- bool verify = _config->FindB("Acquire::https::Verify-Host",true);
- knob = "Acquire::https::"+remotehost+"::Verify-Host";
- verify = _config->FindB(knob.c_str(),verify);
- int const default_verify = (verify == true) ? 2 : 0;
- curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, default_verify);
-
- // Also enforce issuer of server certificate using its cert
- string issuercert = _config->Find("Acquire::https::IssuerCert","");
- knob = "Acquire::https::"+remotehost+"::IssuerCert";
- issuercert = _config->Find(knob.c_str(),issuercert.c_str());
- if(issuercert.empty() == false)
- curl_easy_setopt(curl, CURLOPT_ISSUERCERT,issuercert.c_str());
-
- // For client authentication, certificate file ...
- string pem = _config->Find("Acquire::https::SslCert","");
- knob = "Acquire::https::"+remotehost+"::SslCert";
- pem = _config->Find(knob.c_str(),pem.c_str());
- if(pem.empty() == false)
- curl_easy_setopt(curl, CURLOPT_SSLCERT, pem.c_str());
-
- // ... and associated key.
- string key = _config->Find("Acquire::https::SslKey","");
- knob = "Acquire::https::"+remotehost+"::SslKey";
- key = _config->Find(knob.c_str(),key.c_str());
- if(key.empty() == false)
- curl_easy_setopt(curl, CURLOPT_SSLKEY, key.c_str());
-
- // Allow forcing SSL version to SSLv3 or TLSv1 (SSLv2 is not
- // supported by GnuTLS).
- long final_version = CURL_SSLVERSION_DEFAULT;
- string sslversion = _config->Find("Acquire::https::SslForceVersion","");
- knob = "Acquire::https::"+remotehost+"::SslForceVersion";
- sslversion = _config->Find(knob.c_str(),sslversion.c_str());
- if(sslversion == "TLSv1")
- final_version = CURL_SSLVERSION_TLSv1;
- else if(sslversion == "SSLv3")
- final_version = CURL_SSLVERSION_SSLv3;
- curl_easy_setopt(curl, CURLOPT_SSLVERSION, final_version);
-
- // CRL file
- string crlfile = _config->Find("Acquire::https::CrlFile","");
- knob = "Acquire::https::"+remotehost+"::CrlFile";
- crlfile = _config->Find(knob.c_str(),crlfile.c_str());
- if(crlfile.empty() == false)
- curl_easy_setopt(curl, CURLOPT_CRLFILE, crlfile.c_str());
+ if (std::find(methodNames.begin(), methodNames.end(), "https") != methodNames.end())
+ {
+ curl_easy_setopt(curl, CURLOPT_PROTOCOLS, CURLPROTO_HTTPS);
+ curl_easy_setopt(curl, CURLOPT_REDIR_PROTOCOLS, CURLPROTO_HTTPS);
+
+ // File containing the list of trusted CA.
+ std::string const cainfo = ConfigFind("CaInfo", "");
+ if(cainfo.empty() == false)
+ curl_easy_setopt(curl, CURLOPT_CAINFO, cainfo.c_str());
+ // Check server certificate against previous CA list ...
+ curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, ConfigFindB("Verify-Peer", true) ? 1 : 0);
+ // ... and hostname against cert CN or subjectAltName
+ curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, ConfigFindB("Verify-Host", true) ? 2 : 0);
+ // Also enforce issuer of server certificate using its cert
+ std::string const issuercert = ConfigFind("IssuerCert", "");
+ if(issuercert.empty() == false)
+ curl_easy_setopt(curl, CURLOPT_ISSUERCERT, issuercert.c_str());
+ // For client authentication, certificate file ...
+ std::string const pem = ConfigFind("SslCert", "");
+ if(pem.empty() == false)
+ curl_easy_setopt(curl, CURLOPT_SSLCERT, pem.c_str());
+ // ... and associated key.
+ std::string const key = ConfigFind("SslKey", "");
+ if(key.empty() == false)
+ curl_easy_setopt(curl, CURLOPT_SSLKEY, key.c_str());
+ // Allow forcing SSL version to SSLv3 or TLSv1
+ long final_version = CURL_SSLVERSION_DEFAULT;
+ std::string const sslversion = ConfigFind("SslForceVersion", "");
+ if(sslversion == "TLSv1")
+ final_version = CURL_SSLVERSION_TLSv1;
+ else if(sslversion == "TLSv1.0")
+ final_version = CURL_SSLVERSION_TLSv1_0;
+ else if(sslversion == "TLSv1.1")
+ final_version = CURL_SSLVERSION_TLSv1_1;
+ else if(sslversion == "TLSv1.2")
+ final_version = CURL_SSLVERSION_TLSv1_2;
+ else if(sslversion == "SSLv3")
+ final_version = CURL_SSLVERSION_SSLv3;
+ curl_easy_setopt(curl, CURLOPT_SSLVERSION, final_version);
+ // CRL file
+ std::string const crlfile = ConfigFind("CrlFile", "");
+ if(crlfile.empty() == false)
+ curl_easy_setopt(curl, CURLOPT_CRLFILE, crlfile.c_str());
+ }
+ else
+ {
+ curl_easy_setopt(curl, CURLOPT_PROTOCOLS, CURLPROTO_HTTP);
+ curl_easy_setopt(curl, CURLOPT_REDIR_PROTOCOLS, CURLPROTO_HTTP);
+ }
// cache-control
- if(_config->FindB("Acquire::https::No-Cache",
- _config->FindB("Acquire::http::No-Cache",false)) == false)
+ if(ConfigFindB("No-Cache", false) == false)
{
// cache enabled
- if (_config->FindB("Acquire::https::No-Store",
- _config->FindB("Acquire::http::No-Store",false)) == true)
+ if (ConfigFindB("No-Store", false) == true)
headers = curl_slist_append(headers,"Cache-Control: no-store");
- stringstream ss;
- ioprintf(ss, "Cache-Control: max-age=%u", _config->FindI("Acquire::https::Max-Age",
- _config->FindI("Acquire::http::Max-Age",0)));
- headers = curl_slist_append(headers, ss.str().c_str());
+ std::string ss;
+ strprintf(ss, "Cache-Control: max-age=%u", ConfigFindI("Max-Age", 0));
+ headers = curl_slist_append(headers, ss.c_str());
} else {
// cache disabled by user
headers = curl_slist_append(headers, "Cache-Control: no-cache");
headers = curl_slist_append(headers, "Pragma: no-cache");
}
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
-
// speed limit
- int const dlLimit = _config->FindI("Acquire::https::Dl-Limit",
- _config->FindI("Acquire::http::Dl-Limit",0))*1024;
+ int const dlLimit = ConfigFindI("Dl-Limit", 0) * 1024;
if (dlLimit > 0)
curl_easy_setopt(curl, CURLOPT_MAX_RECV_SPEED_LARGE, dlLimit);
// set header
- curl_easy_setopt(curl, CURLOPT_USERAGENT,
- _config->Find("Acquire::https::User-Agent",
- _config->Find("Acquire::http::User-Agent",
- "Debian APT-CURL/1.0 (" PACKAGE_VERSION ")").c_str()).c_str());
+ curl_easy_setopt(curl, CURLOPT_USERAGENT, ConfigFind("User-Agent", "Debian APT-CURL/1.0 (" PACKAGE_VERSION ")").c_str());
// set timeout
- int const timeout = _config->FindI("Acquire::https::Timeout",
- _config->FindI("Acquire::http::Timeout",120));
+ int const timeout = ConfigFindI("Timeout", 120);
curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, timeout);
//set really low lowspeed timeout (see #497983)
curl_easy_setopt(curl, CURLOPT_LOW_SPEED_LIMIT, DL_MIN_SPEED);
// see 657029, 657560 and co, so if we have no extension on the request
// ask for text only. As a sidenote: If there is nothing to negotate servers
// seem to be nice and ignore it.
- if (_config->FindB("Acquire::https::SendAccept", _config->FindB("Acquire::http::SendAccept", true)) == true)
+ if (ConfigFindB("SendAccept", true))
{
size_t const filepos = Itm->Uri.find_last_of('/');
string const file = Itm->Uri.substr(filepos + 1);
return true;
}
/*}}}*/
-// HttpsMethod::Configuration - Handle a configuration message /*{{{*/
-bool HttpsMethod::Configuration(string Message)
+std::unique_ptr<ServerState> HttpsMethod::CreateServerState(URI const &uri)/*{{{*/
{
- if (ServerMethod::Configuration(Message) == false)
- return false;
-
- AllowRedirect = _config->FindB("Acquire::https::AllowRedirect",
- _config->FindB("Acquire::http::AllowRedirect", true));
- Debug = _config->FindB("Debug::Acquire::https",false);
-
- return true;
+ return std::unique_ptr<ServerState>(new HttpsServerState(uri, this));
}
/*}}}*/
-std::unique_ptr<ServerState> HttpsMethod::CreateServerState(URI const &uri)/*{{{*/
+HttpsMethod::HttpsMethod(std::string &&pProg) : ServerMethod(std::move(pProg),"1.2",Pipeline | SendConfig)/*{{{*/
{
- return std::unique_ptr<ServerState>(new HttpsServerState(uri, this));
+ auto addName = std::inserter(methodNames, methodNames.begin());
+ addName = "http";
+ auto const plus = Binary.find('+');
+ if (plus != std::string::npos)
+ {
+ addName = Binary.substr(plus + 1);
+ auto base = Binary.substr(0, plus);
+ if (base != "https")
+ addName = base;
+ }
+ if (std::find(methodNames.begin(), methodNames.end(), "https") != methodNames.end())
+ curl_global_init(CURL_GLOBAL_SSL);
+ else
+ curl_global_init(CURL_GLOBAL_NOTHING);
+ curl = curl_easy_init();
}
/*}}}*/
-
-int main()
+HttpsMethod::~HttpsMethod() /*{{{*/
{
- return HttpsMethod().Run();
+ curl_easy_cleanup(curl);
}
-
+ /*}}}*/
+int main(int, const char *argv[]) /*{{{*/
+{
+ std::string Binary = flNotDir(argv[0]);
+ if (Binary.find('+') == std::string::npos && Binary != "https")
+ Binary.append("+https");
+ return HttpsMethod(std::move(Binary)).Run();
+}
+ /*}}}*/
public:
- virtual bool Configuration(std::string Message) APT_OVERRIDE;
virtual std::unique_ptr<ServerState> CreateServerState(URI const &uri) APT_OVERRIDE;
using pkgAcqMethod::FetchResult;
using pkgAcqMethod::FetchItem;
- HttpsMethod() : ServerMethod("https","1.2",Pipeline | SendConfig)
- {
- curl_global_init(CURL_GLOBAL_SSL);
- curl = curl_easy_init();
- };
-
- ~HttpsMethod()
- {
- curl_easy_cleanup(curl);
- };
+ explicit HttpsMethod(std::string &&pProg);
+ virtual ~HttpsMethod();
};
#include <apt-pkg/strutl.h>
*/
MirrorMethod::MirrorMethod()
- : HttpMethod(), DownloadedMirrorFile(false), Debug(false)
+ : HttpMethod("mirror"), DownloadedMirrorFile(false), Debug(false)
{
}
{
if (pkgAcqMethod::Configuration(Message) == false)
return false;
- Debug = _config->FindB("Debug::Acquire::mirror",false);
+ Debug = DebugEnabled();
return true;
}
protected:
virtual bool URIAcquire(std::string const &Message, FetchItem *Itm) APT_OVERRIDE {
- Debug = _config->FindB("Debug::pkgAcquire::RRed", false);
+ Debug = DebugEnabled();
URI Get = Itm->Uri;
std::string Path = Get.Host + Get.Path; // rred:/path - no host
/*}}}*/
// RSHMethod::RSHMethod - Constructor /*{{{*/
-// ---------------------------------------------------------------------
-/* */
-RSHMethod::RSHMethod(std::string const &pProg) : aptMethod(pProg.c_str(),"1.0",SendConfig), Prog(pProg)
+RSHMethod::RSHMethod(std::string &&pProg) : aptMethod(std::move(pProg),"1.0",SendConfig)
{
signal(SIGTERM,SigTerm);
signal(SIGINT,SigTerm);
{
// enabling privilege dropping for this method requires configuration…
// … which is otherwise lifted straight from root, so use it by default.
- _config->Set(std::string("Binary::") + Prog + "::APT::Sandbox::User", "");
+ _config->Set(std::string("Binary::") + Binary + "::APT::Sandbox::User", "");
if (aptMethod::Configuration(Message) == false)
return false;
- std::string const timeconf = std::string("Acquire::") + Prog + "::Timeout";
+ std::string const timeconf = std::string("Acquire::") + Binary + "::Timeout";
TimeOut = _config->FindI(timeconf, TimeOut);
- std::string const optsconf = std::string("Acquire::") + Prog + "::Options";
+ std::string const optsconf = std::string("Acquire::") + Binary + "::Options";
RshOptions = _config->Tree(optsconf.c_str());
return true;
// Connect to the server
if (Server == 0 || Server->Comp(Get) == false) {
delete Server;
- Server = new RSHConn(Prog, Get);
+ Server = new RSHConn(Binary, Get);
}
// Could not connect is a transient error..
class RSHMethod : public aptMethod
{
- std::string const Prog;
virtual bool Fetch(FetchItem *Itm) APT_OVERRIDE;
virtual bool Configuration(std::string Message) APT_OVERRIDE;
public:
- explicit RSHMethod(std::string const &Prog);
+ explicit RSHMethod(std::string &&Prog);
};
#endif
{
NextURI = DeQuoteString(Server->Location);
URI tmpURI = NextURI;
- if (tmpURI.Access == "http" && Binary == "https+http")
+ if (tmpURI.Access.find('+') != std::string::npos)
{
- tmpURI.Access = "https+http";
- NextURI = tmpURI;
+ _error->Error("Server tried to trick us into using a specific implementation: %s", tmpURI.Access.c_str());
+ if (Server->HaveContent == true)
+ return ERROR_WITH_CONTENT_PAGE;
+ return ERROR_UNRECOVERABLE;
+ }
+ URI Uri = Queue->Uri;
+ if (Binary.find('+') != std::string::npos)
+ {
+ auto base = Binary.substr(0, Binary.find('+'));
+ if (base != tmpURI.Access)
+ {
+ tmpURI.Access = base + '+' + tmpURI.Access;
+ if (tmpURI.Access == Binary)
+ {
+ std::string tmpAccess = Uri.Access;
+ std::swap(tmpURI.Access, Uri.Access);
+ NextURI = tmpURI;
+ std::swap(tmpURI.Access, Uri.Access);
+ }
+ else
+ NextURI = tmpURI;
+ }
}
if (Queue->Uri == NextURI)
{
return ERROR_WITH_CONTENT_PAGE;
return ERROR_UNRECOVERABLE;
}
- URI Uri = Queue->Uri;
+ Uri.Access = Binary;
// same protocol redirects are okay
if (tmpURI.Access == Uri.Access)
return TRY_AGAIN_OR_REDIRECT;
else if ((Uri.Access == "http" || Uri.Access == "https+http") && tmpURI.Access == "https")
return TRY_AGAIN_OR_REDIRECT;
else
- _error->Error("Redirection from %s to '%s' is forbidden", Uri.Access.c_str(), NextURI.c_str());
+ {
+ auto const tmpplus = tmpURI.Access.find('+');
+ if (tmpplus != std::string::npos && tmpURI.Access.substr(tmpplus + 1) == "https")
+ {
+ auto const uriplus = Uri.Access.find('+');
+ if (uriplus == std::string::npos)
+ {
+ if (Uri.Access == tmpURI.Access.substr(0, tmpplus)) // foo -> foo+https
+ return TRY_AGAIN_OR_REDIRECT;
+ }
+ else if (Uri.Access.substr(uriplus + 1) == "http" &&
+ Uri.Access.substr(0, uriplus) == tmpURI.Access.substr(0, tmpplus)) // foo+http -> foo+https
+ return TRY_AGAIN_OR_REDIRECT;
+ }
+ }
+ _error->Error("Redirection from %s to '%s' is forbidden", Uri.Access.c_str(), NextURI.c_str());
}
/* else pass through for error message */
}
if (Result != -1 && (Result != 0 || Queue == 0))
{
if(FailReason.empty() == false ||
- _config->FindB("Acquire::http::DependOnSTDIN", true) == true)
+ ConfigFindB("DependOnSTDIN", true) == true)
return 100;
else
return 0;
// Connect to the server
if (Server == 0 || Server->Comp(Queue->Uri) == false)
+ {
Server = CreateServerState(Queue->Uri);
+ setPostfixForMethodNames(::URI(Queue->Uri).Host.c_str());
+ AllowRedirect = ConfigFindB("AllowRedirect", true);
+ PipelineDepth = ConfigFindI("Pipeline-Depth", 10);
+ Debug = DebugEnabled();
+ }
/* If the server has explicitly said this is the last connection
then we pre-emptively shut down the pipeline and tear down
return MaxSizeInQueue;
}
/*}}}*/
-ServerMethod::ServerMethod(char const * const Binary, char const * const Ver,unsigned long const Flags) :/*{{{*/
- aptMethod(Binary, Ver, Flags), Server(nullptr), File(NULL), PipelineDepth(10),
+ServerMethod::ServerMethod(std::string &&Binary, char const * const Ver,unsigned long const Flags) :/*{{{*/
+ aptMethod(std::move(Binary), Ver, Flags), Server(nullptr), File(NULL), PipelineDepth(10),
AllowRedirect(false), Debug(false)
{
}
virtual std::unique_ptr<ServerState> CreateServerState(URI const &uri) = 0;
virtual void RotateDNS() = 0;
- ServerMethod(char const * const Binary, char const * const Ver,unsigned long const Flags);
+ ServerMethod(std::string &&Binary, char const * const Ver,unsigned long const Flags);
virtual ~ServerMethod() {};
};
class StoreMethod : public aptMethod
{
- std::string const Prog;
virtual bool Fetch(FetchItem *Itm) APT_OVERRIDE;
public:
- explicit StoreMethod(std::string const &pProg) : aptMethod(pProg.c_str(),"1.2",SingleInstance | SendConfig), Prog(pProg) {};
+ explicit StoreMethod(std::string &&pProg) : aptMethod(std::move(pProg),"1.2",SingleInstance | SendConfig)
+ {
+ if (Binary != "store")
+ methodNames.insert(methodNames.begin(), "store");
+ }
};
static bool OpenFileWithCompressorByName(FileFd &fileFd, std::string const &Filename, unsigned int const Mode, std::string const &Name)
FileFd From;
if (_config->FindB("Method::Compress", false) == false)
{
- if (OpenFileWithCompressorByName(From, Path, FileFd::ReadOnly, Prog) == false)
+ if (OpenFileWithCompressorByName(From, Path, FileFd::ReadOnly, Binary) == false)
return false;
if(From.IsCompressed() && From.FileSize() == 0)
return _error->Error(_("Empty files can't be valid archives"));
{
if (_config->FindB("Method::Compress", false) == false)
To.Open(Itm->DestFile, FileFd::WriteOnly | FileFd::Create | FileFd::Atomic, FileFd::Extension);
- else if (OpenFileWithCompressorByName(To, Itm->DestFile, FileFd::WriteOnly | FileFd::Create | FileFd::Empty, Prog) == false)
+ else if (OpenFileWithCompressorByName(To, Itm->DestFile, FileFd::WriteOnly | FileFd::Create | FileFd::Empty, Binary) == false)
return false;
if (To.IsOpen() == false || To.Failed() == true)
# check that downgrades from https to http are not allowed
webserverconfig 'aptwebserver::support::http' 'true'
sed -i -e "s#:${APTHTTPPORT}/redirectme#:${APTHTTPSPORT}/downgrademe#" -e 's# http:# https:#' rootdir/etc/apt/sources.list.d/*
-testfailure aptget update --allow-insecure-repositories
+testfailure aptget update --allow-insecure-repositories -o Acquire::https::Timeout=1
ln -s "${OLDMETHODS}/http" "${NEWMETHODS}/http-ng"
changetowebserver
+webserverconfig 'aptwebserver::redirect::replace::/redirectme/' "http://localhost:${APTHTTPPORT}/"
sed -i -e 's# http:# http-ng:#' $(find rootdir/etc/apt/sources.list.d -name '*-deb-src.list')
-testsuccess apt update
+testsuccess apt update -o Debug::Acquire::http-ng=1
cp rootdir/tmp/testsuccess.output update.log
# all requests are folded into the first Release file
testsuccess grep ' http-ng://' update.log
testfailure grep ' http://' update.log
+# see if method-specific debug was enabled
+testsuccess grep '^Answer for: http-ng:' update.log
+
+rm -rf rootdir/var/lib/apt/lists
+sed -i -e "s#:${APTHTTPPORT}/#:${APTHTTPPORT}/redirectme#" rootdir/etc/apt/sources.list.d/*
+testsuccess apt update -o Debug::Acquire::http-ng=1
+cp rootdir/tmp/testsuccess.output update.log
+# all requests are folded into the first Release file
+testsuccess grep ' http-ng://' update.log
+testfailure grep '^[^L].* http://' update.log
+# see if method-specific debug was enabled
+testsuccess grep '^Answer for: http-ng:' update.log
Debug::pkgAcquire::Worker "true";
Debug::Acquire::http "true";
Debug::pkgAcquire "true";
-Debug::pkgAcquire::rred "true";' > rootdir/etc/apt/apt.conf.d/rreddebug.conf
+Debug::Acquire::rred "true";' > rootdir/etc/apt/apt.conf.d/rreddebug.conf
testcase() {
testrun -o Acquire::PDiffs::Merge=0 -o APT::Get::List-Cleanup=1 "$@"