[devel] [PATCH for apt 24/38] Improve ipv6 address handling
Aleksei Nikiforov
darktemplar на altlinux.org
Вт Дек 10 18:23:29 MSK 2019
Introduce new class URIAddress for parsing, storing,
and converting back to string various address types,
including ipv4-addresses, ipv6-addresses and hostnames.
In addition to hostname, address may contain interface name and port number.
---
apt/apt-pkg/acquire.cc | 2 +-
apt/apt-pkg/contrib/strutl.cc | 282 ++++++++++++++++++++++++--------
apt/apt-pkg/contrib/strutl.h | 35 +++-
apt/apt-pkg/rpm/rpmindexfile.cc | 2 +-
apt/methods/cdrom.cc | 8 +-
apt/methods/connect.cc | 34 ++--
apt/methods/connect.h | 2 +-
apt/methods/file.cc | 2 +-
apt/methods/ftp.cc | 40 ++---
apt/methods/ftp.h | 2 +-
apt/methods/gpg.cc | 2 +-
apt/methods/gzip.cc | 2 +-
apt/methods/http.cc | 49 ++----
apt/methods/http.h | 2 +-
apt/methods/rsh.cc | 4 +-
apt/methods/rsh.h | 2 +-
apt/methods/rsync.cc | 10 +-
apt/test/uri.cc | 14 +-
18 files changed, 319 insertions(+), 175 deletions(-)
diff --git a/apt/apt-pkg/acquire.cc b/apt/apt-pkg/acquire.cc
index e1e6d7c..79784af 100644
--- a/apt/apt-pkg/acquire.cc
+++ b/apt/apt-pkg/acquire.cc
@@ -236,7 +236,7 @@ string pkgAcquire::QueueName(const string &Uri,MethodConfig const *&Config)
if (Config->SingleInstance == true || QueueMode == QueueAccess)
return U.Access;
- return U.Access + ':' + U.Host;
+ return U.Access + ':' + U.Address.to_hostname();
}
/*}}}*/
// Acquire::GetConfig - Fetch the configuration information /*{{{*/
diff --git a/apt/apt-pkg/contrib/strutl.cc b/apt/apt-pkg/contrib/strutl.cc
index 4d5025a..52d1995 100644
--- a/apt/apt-pkg/contrib/strutl.cc
+++ b/apt/apt-pkg/contrib/strutl.cc
@@ -35,6 +35,9 @@
#include <errno.h>
#include <stdarg.h>
+#include <algorithm>
+#include <utility>
+
using namespace std;
/*}}}*/
@@ -1058,27 +1061,211 @@ bool CheckDomainList(const string &Host, const string &List)
}
/*}}}*/
+URIAddress::URIAddress()
+ : is_ipv6addr(false)
+{
+}
+
+URIAddress::URIAddress(const std::string &host_uri)
+ : is_ipv6addr(false)
+{
+ from_string(host_uri);
+}
+
+URIAddress::URIAddress(const URIAddress &other)
+ : hostname(other.hostname)
+ , interface(other.interface)
+ , port(other.port)
+ , is_ipv6addr(other.is_ipv6addr)
+{
+}
+
+URIAddress::URIAddress(URIAddress &&other)
+ : hostname(std::move(other.hostname))
+ , interface(std::move(other.interface))
+ , port(std::move(other.port))
+ , is_ipv6addr(std::move(other.is_ipv6addr))
+{
+}
+
+URIAddress& URIAddress::operator=(const std::string &host_uri)
+{
+ from_string(host_uri);
+
+ return *this;
+}
+
+URIAddress& URIAddress::operator=(const URIAddress &other)
+{
+ if (&other != this)
+ {
+ this->hostname = other.hostname;
+ this->interface = other.interface;
+ this->port = other.port;
+ this->is_ipv6addr = other.is_ipv6addr;
+ }
+
+ return *this;
+}
+
+URIAddress& URIAddress::operator=(URIAddress &&other)
+{
+ if (&other != this)
+ {
+ this->hostname = std::move(other.hostname);
+ this->interface = std::move(other.interface);
+ this->port = std::move(other.port);
+ this->is_ipv6addr = std::move(other.is_ipv6addr);
+ }
+
+ return *this;
+}
+
+bool URIAddress::operator==(const std::string &host_uri) const
+{
+ URIAddress other(host_uri);
+
+ return (*this == other);
+}
+
+bool URIAddress::operator==(const URIAddress &other) const
+{
+ return (this->hostname == other.hostname)
+ && (this->interface == other.interface)
+ && (this->port == other.port)
+ && (this->is_ipv6addr == other.is_ipv6addr);
+}
+
+std::string URIAddress::to_string() const
+{
+ std::string result = to_hostname();
+
+ if (result.empty())
+ {
+ return result;
+ }
+
+ if (port)
+ {
+ result += ':';
+ result += std::to_string(*port);
+ }
+
+ return result;
+}
+
+std::string URIAddress::to_hostname() const
+{
+ std::string result = hostname_and_interface();
+
+ if (result.empty())
+ {
+ return std::string();
+ }
+
+ if (!is_ipv6addr)
+ {
+ return result;
+ }
+
+ return std::string("[") + result + std::string("]");
+}
+
+std::string URIAddress::hostname_and_interface() const
+{
+ if (hostname.empty())
+ {
+ return std::string();
+ }
+
+ if (interface.empty())
+ {
+ return hostname;
+ }
+
+ return hostname + '%' + interface;
+}
+
+void URIAddress::from_string(const std::string &host_uri)
+{
+ std::string remainder = host_uri;
+
+ // first look for port delimiter, outside of brackets
+ size_t index = remainder.size();
+ for ( ; (index > 0) && (remainder[index - 1] != ']') && (remainder[index - 1] != ':'); --index)
+ {
+ }
+
+ if ((index > 0) && (remainder[index - 1] == ':'))
+ {
+ if (index < remainder.size())
+ {
+ port = atoi(remainder.substr(index).c_str());
+ }
+ else
+ {
+ port = std::experimental::optional<uint16_t>();
+ }
+
+ remainder = remainder.substr(0, index > 0 ? index - 1 : 0);
+ }
+ else
+ {
+ port = std::experimental::optional<uint16_t>();
+ }
+
+ if ((remainder.front() == '[') && (remainder.back() == ']'))
+ {
+ is_ipv6addr = true;
+ remainder = remainder.substr(1, remainder.size() - 2);
+ }
+ else
+ {
+ is_ipv6addr = false;
+ }
+
+ size_t percent_pos = remainder.find_last_of('%');
+ if (percent_pos != std::string::npos)
+ {
+ hostname = remainder.substr(0, percent_pos);
+
+ if (percent_pos < remainder.size() - 1)
+ {
+ interface = remainder.substr(percent_pos + 1);
+ }
+ else
+ {
+ interface = std::string();
+ }
+ }
+ else
+ {
+ hostname = remainder;
+ interface = std::string();
+ }
+}
+
// URI::CopyFrom - Copy from an object /*{{{*/
// ---------------------------------------------------------------------
/* This parses the URI into all of its components */
void URI::CopyFrom(const string &U)
{
- auto I = U.begin();
+ string::const_iterator I = U.begin();
// Locate the first colon, this separates the scheme
- for (; I < U.end() && *I != ':' ; I++);
- auto FirstColon = I;
+ for (; I < U.end() && *I != ':' ; ++I);
+ string::const_iterator FirstColon = I;
/* Determine if this is a host type URI with a leading double //
and then search for the first single / */
- auto SingleSlash = I;
+ string::const_iterator SingleSlash = I;
if (I + 3 < U.end() && I[1] == '/' && I[2] == '/')
SingleSlash += 3;
/* Find the / indicating the end of the hostname, ignoring /'s in the
square brackets */
bool InBracket = false;
- for (; SingleSlash < U.end() && (*SingleSlash != '/' || InBracket == true); SingleSlash++)
+ for (; SingleSlash < U.end() && (*SingleSlash != '/' || InBracket == true); ++SingleSlash)
{
if (*SingleSlash == '[')
InBracket = true;
@@ -1090,9 +1277,9 @@ void URI::CopyFrom(const string &U)
SingleSlash = U.end();
// We can now write the access and path specifiers
- Access = string(U,0,FirstColon - U.begin());
+ Access.assign(U.begin(),FirstColon);
if (SingleSlash != U.end())
- Path = string(U,SingleSlash - U.begin());
+ Path.assign(SingleSlash,U.end());
if (Path.empty() == true)
Path = "/";
@@ -1111,64 +1298,33 @@ void URI::CopyFrom(const string &U)
I = FirstColon + 1;
if (I > SingleSlash)
I = SingleSlash;
- for (; I < SingleSlash && *I != ':'; I++);
- auto SecondColon = I;
-
- // Search for the @ after the colon
- for (; I < SingleSlash && *I != '@'; I++);
- auto At = I;
+
+ // Search for the @ separating user:pass from host
+ auto const RevAt = std::find(
+ std::string::const_reverse_iterator(SingleSlash),
+ std::string::const_reverse_iterator(I), '@');
+ string::const_iterator const At = RevAt.base() == I ? SingleSlash : std::prev(RevAt.base());
+ // and then look for the colon between user and pass
+ string::const_iterator const SecondColon = std::find(I, At, ':');
+
+ std::string Host;
// Now write the host and user/pass
if (At == SingleSlash)
{
if (FirstColon < SingleSlash)
- Host = string(U,FirstColon - U.begin(),SingleSlash - FirstColon);
+ Host.assign(FirstColon,SingleSlash);
}
else
{
- Host = string(U,At - U.begin() + 1,SingleSlash - At - 1);
- User = string(U,FirstColon - U.begin(),SecondColon - FirstColon);
+ Host.assign(At+1,SingleSlash);
+ // username and password must be encoded (RFC 3986)
+ User.assign(DeQuoteString(std::string(FirstColon,SecondColon)));
if (SecondColon < At)
- Password = string(U,SecondColon - U.begin() + 1,At - SecondColon - 1);
+ Password.assign(DeQuoteString(std::string(SecondColon+1,At)));
}
- // Now we parse the RFC 2732 [] hostnames.
- unsigned long PortEnd = 0;
- InBracket = false;
- for (unsigned I = 0; I != Host.length();)
- {
- if (Host[I] == '[')
- {
- InBracket = true;
- Host.erase(I,1);
- continue;
- }
-
- if (InBracket == true && Host[I] == ']')
- {
- InBracket = false;
- Host.erase(I,1);
- PortEnd = I;
- continue;
- }
- I++;
- }
-
- // Tsk, weird.
- if (InBracket == true)
- {
- Host = string();
- return;
- }
-
- // Now we parse off a port number from the hostname
- Port = 0;
- string::size_type Pos = Host.rfind(':');
- if (Pos == string::npos || Pos < PortEnd)
- return;
-
- Port = atoi(string(Host,Pos+1).c_str());
- Host = string(Host,0,Pos);
+ Address = URIAddress(Host);
}
/*}}}*/
// URI::operator string - Convert the URI to a string /*{{{*/
@@ -1181,7 +1337,7 @@ URI::operator string()
if (Access.empty() == false)
Res = Access + ':';
- if (Host.empty() == false)
+ if (Address.hostname.empty() == false)
{
if (Access.empty() == false)
Res += "//";
@@ -1194,19 +1350,7 @@ URI::operator string()
Res += "@";
}
- // Add RFC 2732 escaping characters
- if (Access.empty() == false &&
- (Host.find('/') != string::npos || Host.find(':') != string::npos))
- Res += '[' + Host + ']';
- else
- Res += Host;
-
- if (Port != 0)
- {
- char S[30];
- sprintf(S,":%u",Port);
- Res += S;
- }
+ Res += Address.to_string();
}
if (Path.empty() == false)
@@ -1229,7 +1373,7 @@ string URI::SiteOnly(const string &URI)
U.User.clear();
U.Password.clear();
U.Path.clear();
- U.Port = 0;
+ U.Address.port = std::experimental::optional<uint16_t>();
return U;
}
/*}}}*/
diff --git a/apt/apt-pkg/contrib/strutl.h b/apt/apt-pkg/contrib/strutl.h
index 8a063f3..a13b32b 100644
--- a/apt/apt-pkg/contrib/strutl.h
+++ b/apt/apt-pkg/contrib/strutl.h
@@ -26,6 +26,8 @@
#include <time.h>
#include <cstring>
+#include <experimental/optional>
+
using std::string;
using std::vector;
using std::ostream;
@@ -104,6 +106,34 @@ APT_MKSTRCMP2(stringcasecmp,stringcasecmp);
inline const char *DeNull(const char *s) {return (s == 0?"(null)":s);};
+class URIAddress
+{
+public:
+ URIAddress();
+ URIAddress(const URIAddress &other);
+ URIAddress(URIAddress &&other);
+
+ explicit URIAddress(const std::string &host_uri);
+
+ URIAddress& operator=(const std::string &host_uri);
+ URIAddress& operator=(const URIAddress &other);
+ URIAddress& operator=(URIAddress &&other);
+
+ bool operator==(const std::string &host_uri) const;
+ bool operator==(const URIAddress &other) const;
+
+ std::string to_string() const;
+ void from_string(const std::string &host_uri);
+
+ std::string to_hostname() const;
+ std::string hostname_and_interface() const;
+
+ std::string hostname;
+ std::string interface;
+ std::experimental::optional<uint16_t> port;
+ bool is_ipv6addr;
+};
+
class URI
{
void CopyFrom(const string &From);
@@ -113,9 +143,8 @@ class URI
string Access;
string User;
string Password;
- string Host;
+ URIAddress Address;
string Path;
- unsigned int Port;
operator string();
inline void operator =(const string &From) {CopyFrom(From);};
@@ -123,7 +152,7 @@ class URI
static string SiteOnly(const string &URI);
URI(const string &Path) {CopyFrom(Path);};
- URI() : Port(0) {};
+ URI() {};
};
struct SubstVar
diff --git a/apt/apt-pkg/rpm/rpmindexfile.cc b/apt/apt-pkg/rpm/rpmindexfile.cc
index b4523b9..ad011a7 100644
--- a/apt/apt-pkg/rpm/rpmindexfile.cc
+++ b/apt/apt-pkg/rpm/rpmindexfile.cc
@@ -367,7 +367,7 @@ bool rpmPkgListIndex::Merge(pkgCacheGenerator &Gen,OpProgress &Prog) const
Prog.SubProgress(0,Info(MainType()));
::URI Tmp(URI);
- if (Gen.SelectFile(PackageFile,Tmp.Host,*this) == false)
+ if (Gen.SelectFile(PackageFile,Tmp.Address.to_hostname(),*this) == false)
{
delete Handler;
return _error->Error(_("Problem with SelectFile %s"),PackageFile.c_str());
diff --git a/apt/methods/cdrom.cc b/apt/methods/cdrom.cc
index 9e04c3e..cfe0869 100644
--- a/apt/methods/cdrom.cc
+++ b/apt/methods/cdrom.cc
@@ -198,7 +198,7 @@ bool CDROMMethod::Fetch(FetchItem *Itm)
}
// All non IMS queries for package files fail.
- if (Itm->IndexFile == true || GetID(Get.Host).empty() == true)
+ if (Itm->IndexFile == true || GetID(Get.Address.to_hostname()).empty() == true)
{
Fail(_("Please use apt-cdrom to make this media recognized by APT."
" apt-get update cannot be used to add new Media"));
@@ -206,7 +206,7 @@ bool CDROMMethod::Fetch(FetchItem *Itm)
}
// We already have a CD inserted, but it is the wrong one
- if (CurrentID.empty() == false && Database.Find("CD::" + CurrentID) != Get.Host)
+ if (CurrentID.empty() == false && Database.Find("CD::" + CurrentID) != Get.Address.to_hostname())
{
Fail(_("Wrong CD"),true);
return true;
@@ -229,7 +229,7 @@ bool CDROMMethod::Fetch(FetchItem *Itm)
clog << "ID " << Version << " " << NewID << endl;
// A hit
- if (Database.Find("CD::" + NewID) == Get.Host)
+ if (Database.Find("CD::" + NewID) == Get.Address.to_hostname())
{
Hit = true;
break;
@@ -243,7 +243,7 @@ bool CDROMMethod::Fetch(FetchItem *Itm)
if (UnmountCdrom(CDROM) == false)
return _error->Error(_("Unable to unmount media in %s, it may still be in use."),
CDROM.c_str());
- if (MediaFail(Get.Host,CDROM) == false)
+ if (MediaFail(Get.Address.to_hostname(),CDROM) == false)
{
CurrentID = "FAIL";
Fail(_("Wrong media"),true);
diff --git a/apt/methods/connect.cc b/apt/methods/connect.cc
index a25d6b4..a9edd7f 100644
--- a/apt/methods/connect.cc
+++ b/apt/methods/connect.cc
@@ -42,7 +42,7 @@
/*}}}*/
static string LastHost;
-static int LastPort = 0;
+static std::string LastPort;
static struct addrinfo *LastHostAddr = 0;
static struct addrinfo *LastUsed = 0;
@@ -153,25 +153,25 @@ static bool DoConnect(struct addrinfo *Addr,const string &Host,
// Connect - Connect to a server /*{{{*/
// ---------------------------------------------------------------------
/* Performs a connection to the server */
-bool Connect(const string &Host,int Port,const char *Service,int DefPort,std::unique_ptr<MethodFd> &Fd,
+bool Connect(const URIAddress &address,const char *Service,int DefPort,std::unique_ptr<MethodFd> &Fd,
unsigned long TimeOut,pkgAcqMethod *Owner)
{
if (_error->PendingError() == true)
return false;
// Convert the port name/number
- char ServStr[300];
- if (Port != 0)
- snprintf(ServStr,sizeof(ServStr),"%u",(unsigned) Port);
+ std::string ServStr;
+ if (address.port)
+ ServStr = std::to_string(*(address.port));
else
- snprintf(ServStr,sizeof(ServStr),"%s",Service);
+ ServStr = Service;
/* We used a cached address record.. Yes this is against the spec but
the way we have setup our rotating dns suggests that this is more
sensible */
- if (LastHost != Host || LastPort != Port)
+ if (LastHost != address.to_hostname() || LastPort != ServStr)
{
- Owner->Status(_("Connecting to %s"),Host.c_str());
+ Owner->Status(_("Connecting to %s"),address.to_hostname().c_str());
// Free the old address structure
if (LastHostAddr != 0)
@@ -191,31 +191,31 @@ bool Connect(const string &Host,int Port,const char *Service,int DefPort,std::un
while (1)
{
int Res;
- if ((Res = getaddrinfo(Host.c_str(),ServStr,&Hints,&LastHostAddr)) != 0 ||
+ if ((Res = getaddrinfo(address.hostname_and_interface().c_str(),ServStr.c_str(),&Hints,&LastHostAddr)) != 0 ||
LastHostAddr == 0)
{
if (Res == EAI_NONAME || Res == EAI_SERVICE)
{
if (DefPort != 0)
{
- snprintf(ServStr,sizeof(ServStr),"%u",(unsigned) DefPort);
+ ServStr = std::to_string((unsigned) DefPort);
DefPort = 0;
continue;
}
- return _error->Error(_("Could not resolve '%s'"),Host.c_str());
+ return _error->Error(_("Could not resolve '%s'"),address.to_hostname().c_str());
}
if (Res == EAI_AGAIN)
return _error->Error(_("Temporary failure resolving '%s'"),
- Host.c_str());
+ address.to_hostname().c_str());
return _error->Error(_("Something wicked happened resolving '%s:%s' (%i)"),
- Host.c_str(),ServStr,Res);
+ address.to_hostname().c_str(),ServStr.c_str(),Res);
}
break;
}
- LastHost = Host;
- LastPort = Port;
+ LastHost = address.to_hostname();
+ LastPort = ServStr;
}
// When we have an IP rotation stay with the last IP.
@@ -225,7 +225,7 @@ bool Connect(const string &Host,int Port,const char *Service,int DefPort,std::un
while (CurHost != 0)
{
- if (DoConnect(CurHost,Host,TimeOut,Fd,Owner) == true)
+ if (DoConnect(CurHost,address.to_hostname(),TimeOut,Fd,Owner) == true)
{
LastUsed = CurHost;
return true;
@@ -256,7 +256,7 @@ bool Connect(const string &Host,int Port,const char *Service,int DefPort,std::un
if (_error->PendingError() == true)
return false;
- return _error->Error(_("Unable to connect to %s %s:"),Host.c_str(),ServStr);
+ return _error->Error(_("Unable to connect to %s %s:"),address.to_hostname().c_str(),ServStr.c_str());
}
/*}}}*/
diff --git a/apt/methods/connect.h b/apt/methods/connect.h
index e0cafba..89b4b8c 100644
--- a/apt/methods/connect.h
+++ b/apt/methods/connect.h
@@ -36,7 +36,7 @@ struct MethodFd
virtual bool HasPending();
};
-bool Connect(const string &To,int Port,const char *Service,int DefPort,
+bool Connect(const URIAddress &address,const char *Service,int DefPort,
std::unique_ptr<MethodFd> &Fd,unsigned long TimeOut,pkgAcqMethod *Owner);
void RotateDNS();
diff --git a/apt/methods/file.cc b/apt/methods/file.cc
index f3a13d2..d849ca6 100644
--- a/apt/methods/file.cc
+++ b/apt/methods/file.cc
@@ -42,7 +42,7 @@ bool FileMethod::Fetch(FetchItem *Itm)
URI Get = Itm->Uri;
string File = Get.Path;
FetchResult Res;
- if (Get.Host.empty() == false)
+ if (Get.Address.to_hostname().empty() == false)
return _error->Error(_("Invalid URI, local URIS must not start with //"));
// See if the file exists
diff --git a/apt/methods/ftp.cc b/apt/methods/ftp.cc
index 00a5502..e79e70d 100644
--- a/apt/methods/ftp.cc
+++ b/apt/methods/ftp.cc
@@ -119,7 +119,7 @@ bool FTPConn::Open(pkgAcqMethod *Owner)
if (getenv("ftp_proxy") == 0)
{
string DefProxy = _config->Find("Acquire::ftp::Proxy");
- string SpecificProxy = _config->Find("Acquire::ftp::Proxy::" + ServerName.Host);
+ string SpecificProxy = _config->Find("Acquire::ftp::Proxy::" + ServerName.Address.to_hostname());
if (SpecificProxy.empty() == false)
{
if (SpecificProxy == "DIRECT")
@@ -136,30 +136,14 @@ bool FTPConn::Open(pkgAcqMethod *Owner)
// Parse no_proxy, a , separated list of domains
if (getenv("no_proxy") != 0)
{
- if (CheckDomainList(ServerName.Host,getenv("no_proxy")) == true)
+ if (CheckDomainList(ServerName.Address.to_hostname(),getenv("no_proxy")) == true)
Proxy = "";
}
-
- // Determine what host and port to use based on the proxy settings
- int Port = 0;
- string Host;
- if (Proxy.empty() == true)
- {
- if (ServerName.Port != 0)
- Port = ServerName.Port;
- Host = ServerName.Host;
- }
- else
- {
- if (Proxy.Port != 0)
- Port = Proxy.Port;
- Host = Proxy.Host;
- }
/* Connect to the remote server. Since FTP is connection oriented we
want to make sure we get a new server every time we reconnect */
RotateDNS();
- if (Connect(Host,Port,"ftp",21,ServerFd,TimeOut,Owner) == false)
+ if (Connect(Proxy.empty() ? ServerName.Address : Proxy.Address,"ftp",21,ServerFd,TimeOut,Owner) == false)
return false;
// Login must be before getpeername otherwise dante won't work.
@@ -223,8 +207,8 @@ bool FTPConn::Login()
}
// Enter passive mode
- if (_config->Exists("Acquire::FTP::Passive::" + ServerName.Host) == true)
- TryPassive = _config->FindB("Acquire::FTP::Passive::" + ServerName.Host,true);
+ if (_config->Exists("Acquire::FTP::Passive::" + ServerName.Address.to_hostname()) == true)
+ TryPassive = _config->FindB("Acquire::FTP::Passive::" + ServerName.Address.to_hostname(),true);
else
TryPassive = _config->FindB("Acquire::FTP::Passive",true);
}
@@ -251,8 +235,8 @@ bool FTPConn::Login()
// Substitute the variables into the command
char SitePort[20];
- if (ServerName.Port != 0)
- sprintf(SitePort,"%u",ServerName.Port);
+ if (ServerName.Address.port)
+ sprintf(SitePort,"%u",*(ServerName.Address.port));
else
strcpy(SitePort,"21");
string Tmp = Opts->Value;
@@ -261,7 +245,7 @@ bool FTPConn::Login()
Tmp = SubstVar(Tmp,"$(SITE_USER)",User);
Tmp = SubstVar(Tmp,"$(SITE_PASS)",Pass);
Tmp = SubstVar(Tmp,"$(SITE_PORT)",SitePort);
- Tmp = SubstVar(Tmp,"$(SITE)",ServerName.Host);
+ Tmp = SubstVar(Tmp,"$(SITE)",ServerName.Address.to_hostname());
// Send the command
if (WriteMsg(Tag,Msg,"%s",Tmp.c_str()) == false)
@@ -272,8 +256,8 @@ bool FTPConn::Login()
// Enter passive mode
TryPassive = false;
- if (_config->Exists("Acquire::FTP::Passive::" + ServerName.Host) == true)
- TryPassive = _config->FindB("Acquire::FTP::Passive::" + ServerName.Host,true);
+ if (_config->Exists("Acquire::FTP::Passive::" + ServerName.Address.to_hostname()) == true)
+ TryPassive = _config->FindB("Acquire::FTP::Passive::" + ServerName.Address.to_hostname(),true);
else
{
if (_config->Exists("Acquire::FTP::Proxy::Passive") == true)
@@ -284,8 +268,8 @@ bool FTPConn::Login()
}
// Force the use of extended commands
- if (_config->Exists("Acquire::FTP::ForceExtended::" + ServerName.Host) == true)
- ForceExtended = _config->FindB("Acquire::FTP::ForceExtended::" + ServerName.Host,true);
+ if (_config->Exists("Acquire::FTP::ForceExtended::" + ServerName.Address.to_hostname()) == true)
+ ForceExtended = _config->FindB("Acquire::FTP::ForceExtended::" + ServerName.Address.to_hostname(),true);
else
ForceExtended = _config->FindB("Acquire::FTP::ForceExtended",false);
diff --git a/apt/methods/ftp.h b/apt/methods/ftp.h
index b4a30fe..5828eea 100644
--- a/apt/methods/ftp.h
+++ b/apt/methods/ftp.h
@@ -41,7 +41,7 @@ class FTPConn
public:
- bool Comp(URI Other) {return Other.Host == ServerName.Host && Other.Port == ServerName.Port;};
+ bool Comp(URI Other) {return Other.Address == ServerName.Address;};
// Raw connection IO
bool ReadResp(unsigned int &Ret,string &Text);
diff --git a/apt/methods/gpg.cc b/apt/methods/gpg.cc
index 2925908..7179cef 100644
--- a/apt/methods/gpg.cc
+++ b/apt/methods/gpg.cc
@@ -337,7 +337,7 @@ void removeTmpDir(const string &path, int sigCount)
bool GPGMethod::Fetch(FetchItem *Itm)
{
URI Get = Itm->Uri;
- string Path = Get.Host + Get.Path; // To account for relative paths
+ string Path = Get.Address.to_hostname() + Get.Path; // To account for relative paths
string KeyList;
FetchResult Res;
diff --git a/apt/methods/gzip.cc b/apt/methods/gzip.cc
index db61e69..9ecc368 100644
--- a/apt/methods/gzip.cc
+++ b/apt/methods/gzip.cc
@@ -45,7 +45,7 @@ class GzipMethod : public pkgAcqMethod
bool GzipMethod::Fetch(FetchItem *Itm)
{
URI Get = Itm->Uri;
- string Path = Get.Host + Get.Path; // To account for relative paths
+ string Path = Get.Address.to_hostname() + Get.Path; // To account for relative paths
string GzPathOption = "Dir::bin::"+string(Prog);
diff --git a/apt/methods/http.cc b/apt/methods/http.cc
index c9a37de..9302495 100644
--- a/apt/methods/http.cc
+++ b/apt/methods/http.cc
@@ -293,7 +293,7 @@ bool ServerState::Open()
if (getenv("http_proxy") == 0)
{
string DefProxy = _config->Find("Acquire::http::Proxy");
- string SpecificProxy = _config->Find("Acquire::http::Proxy::" + ServerName.Host);
+ string SpecificProxy = _config->Find("Acquire::http::Proxy::" + ServerName.Address.to_hostname());
if (SpecificProxy.empty() == false)
{
if (SpecificProxy == "DIRECT")
@@ -310,37 +310,23 @@ bool ServerState::Open()
// Parse no_proxy, a , separated list of domains
if (getenv("no_proxy") != 0)
{
- if (CheckDomainList(ServerName.Host,getenv("no_proxy")) == true)
+ if (CheckDomainList(ServerName.Address.to_hostname(),getenv("no_proxy")) == true)
Proxy = "";
}
#endif /* !USE_TLS */
-
- // Determine what host and port to use based on the proxy settings
- int Port = 0;
- string Host;
-#ifndef USE_TLS
- if (Proxy.empty() == true || Proxy.Host.empty() == true)
- {
-#endif /* !USE_TLS */
- if (ServerName.Port != 0)
- Port = ServerName.Port;
- Host = ServerName.Host;
-#ifndef USE_TLS
- }
- else
- {
- if (Proxy.Port != 0)
- Port = Proxy.Port;
- Host = Proxy.Host;
- }
-#endif /* !USE_TLS */
// Connect to the remote server
- if (Connect(Host,Port,service_name,default_port,ServerFd,TimeOut,Owner) == false)
+ if (Connect(
+#ifndef USE_TLS
+ Proxy.empty() ? ServerName.Address : Proxy.Address,
+#else /* USE_TLS */
+ ServerName.Address,
+#endif /* USE_TLS */
+ service_name,default_port,ServerFd,TimeOut,Owner) == false)
return false;
#ifdef USE_TLS
- if (!UnwrapTLS(ServerName.Host, ServerFd, TimeOut, Owner))
+ if (!UnwrapTLS(ServerName.Address.to_hostname(), ServerFd, TimeOut, Owner))
return false;
#endif /* USE_TLS */
@@ -639,12 +625,7 @@ void HttpMethod::SendReq(FetchItem *Itm,CircleBuf &Out)
// The HTTP server expects a hostname with a trailing :port
char Buf[1000];
- string ProperHost = Uri.Host;
- if (Uri.Port != 0)
- {
- sprintf(Buf,":%u",Uri.Port);
- ProperHost += Buf;
- }
+ string ProperHost = Uri.Address.to_string();
// Just in case.
if (Itm->Uri.length() >= sizeof(Buf))
@@ -944,7 +925,7 @@ int HttpMethod::DealWithHeaders(FetchResult &Res,ServerState *Srv)
{
for (CurrentAuth = AuthList.begin(); CurrentAuth != AuthList.end();
++CurrentAuth)
- if (CurrentAuth->Host == Srv->ServerName.Host)
+ if (CurrentAuth->Host == Srv->ServerName.Address.to_hostname())
{
AuthUser = CurrentAuth->User;
AuthPass = CurrentAuth->Password;
@@ -957,7 +938,7 @@ int HttpMethod::DealWithHeaders(FetchResult &Res,ServerState *Srv)
// Nope - get username and password
if (CurrentAuth == AuthList.end())
{
- Description = ParsedURI.Host;
+ Description = ParsedURI.Address.to_hostname();
#ifdef USE_TLS
if (ParsedURI.Access == "https")
@@ -969,13 +950,13 @@ int HttpMethod::DealWithHeaders(FetchResult &Res,ServerState *Srv)
// Got new credentials; save them
AuthRec NewAuthInfo;
- NewAuthInfo.Host = Srv->ServerName.Host;
+ NewAuthInfo.Host = Srv->ServerName.Address.to_hostname();
NewAuthInfo.User = AuthUser;
NewAuthInfo.Password = AuthPass;
for (CurrentAuth = AuthList.begin(); CurrentAuth != AuthList.end();
++CurrentAuth)
- if (CurrentAuth->Host == Srv->ServerName.Host)
+ if (CurrentAuth->Host == Srv->ServerName.Address.to_hostname())
{
*CurrentAuth = NewAuthInfo;
break;
diff --git a/apt/methods/http.h b/apt/methods/http.h
index 9e4d2be..0a8362a 100644
--- a/apt/methods/http.h
+++ b/apt/methods/http.h
@@ -110,7 +110,7 @@ struct ServerState
URI ServerName;
bool HeaderLine(const string &Line);
- bool Comp(URI Other) {return Other.Host == ServerName.Host && Other.Port == ServerName.Port;};
+ bool Comp(URI Other) {return Other.Address == ServerName.Address;};
void Reset() {Major = 0; Minor = 0; Result = 0; Size = 0; StartPos = 0;
Encoding = Closes; time(&Date); ServerFd.reset();
Pipeline = true; };
diff --git a/apt/methods/rsh.cc b/apt/methods/rsh.cc
index 8bc47b0..2371e4a 100644
--- a/apt/methods/rsh.cc
+++ b/apt/methods/rsh.cc
@@ -77,7 +77,7 @@ bool RSHConn::Open()
if (Process != -1)
return true;
- if (Connect(ServerName.Host,ServerName.User) == false)
+ if (Connect(ServerName.Address.to_hostname(),ServerName.User) == false)
return false;
return true;
@@ -428,7 +428,7 @@ bool RSHMethod::Fetch(FetchItem *Itm)
// We say this mainly because the pause here is for the
// ssh connection that is still going
- Status(_("Connecting to %s"), Get.Host.c_str());
+ Status(_("Connecting to %s"), Get.Address.to_hostname().c_str());
// Get the files information
unsigned long long Size;
diff --git a/apt/methods/rsh.h b/apt/methods/rsh.h
index e99c59c..010a28f 100644
--- a/apt/methods/rsh.h
+++ b/apt/methods/rsh.h
@@ -33,7 +33,7 @@ class RSHConn
// Raw connection IO
bool WriteMsg(string &Text,bool Sync,const char *Fmt,...);
bool Connect(const string &Host, const string &User);
- bool Comp(URI Other) {return Other.Host == ServerName.Host && Other.Port == ServerName.Port;};
+ bool Comp(URI Other) {return Other.Address == ServerName.Address;};
// Connection control
bool Open();
diff --git a/apt/methods/rsync.cc b/apt/methods/rsync.cc
index efc1c0e..f28bb5a 100644
--- a/apt/methods/rsync.cc
+++ b/apt/methods/rsync.cc
@@ -353,11 +353,7 @@ bool RsyncMethod::RsyncConnExec::Get(pkgAcqMethod *Owner, FetchResult &FRes, con
}
}
- char port[12];
- if (srv.Port!=0)
- snprintf(port, sizeof(port), ":%u", srv.Port);
- else port[0] = 0;
- argv.add( "rsync://" + srv.Host + port + From);
+ argv.add( "rsync://" + srv.Address.to_string() + From);
argv.add(To);
if ( pipe(p) ) {
@@ -519,12 +515,12 @@ bool RsyncMethod::Fetch(FetchItem *Itm)
Res.ResumePoint = st.st_size;
}
- string proxy = _config->Find(string("Acquire::rsync::proxy::")+Get.Host);
+ string proxy = _config->Find(string("Acquire::rsync::proxy::")+Get.Address.to_hostname());
if ( proxy.empty() )
proxy = _config->Find("Acquire::rsync::proxy");
if (Debug)
- cerr << endl << "RSYNC: Proxy(" << Get.Host << "): " << proxy << endl;
+ cerr << endl << "RSYNC: Proxy(" << Get.Address.to_hostname() << "): " << proxy << endl;
// Don't compare now for the same server uri
delete server;
diff --git a/apt/test/uri.cc b/apt/test/uri.cc
index ec652de..535aedb 100644
--- a/apt/test/uri.cc
+++ b/apt/test/uri.cc
@@ -7,9 +7,12 @@ void Test(const char *Foo)
{
URI U(Foo);
- printf("%s a='%s' u='%s' p='%s' port='%u'\n h='%s' p='%s'\n",
+ printf("%s a='%s' u='%s' p='%s'\n h='%s' i='%s' port='%s' ipv6='%s'\n p='%s'\n",
Foo,U.Access.c_str(),U.User.c_str(),U.Password.c_str(),
- U.Port,U.Host.c_str(),U.Path.c_str());
+ U.Address.hostname.c_str(), U.Address.interface.c_str(),
+ U.Address.port ? std::to_string(*(U.Address.port)).c_str() : "(nil)",
+ U.Address.is_ipv6addr ? "true" : "false",
+ U.Path.c_str());
}
int main()
@@ -22,10 +25,17 @@ int main()
Test("gzip:./bar/cow");
// RFC 2732 stuff
+ Test("http://127.0.0.1/foo");
+ Test("http://127.0.0.1:80/foo");
Test("http://[1080::8:800:200C:417A]/foo");
Test("http://[::FFFF:129.144.52.38]:80/index.html");
Test("http://[::FFFF:129.144.52.38:]:80/index.html");
Test("http://[::FFFF:129.144.52.38:]/index.html");
+ Test("http://[::FFFF:129.144.52.38%eth0]/index.html");
+ Test("http://[::FFFF:129.144.52.38%]/index.html");
+ Test("http://[::FFFF:129.144.52.38%l]/index.html");
+ Test("http://[::FFFF:129.144.52.38]:/index.html");
+ Test("http://[::FFFF:129.144.52.38]:8/index.html");
/* My Evil Corruption of RFC 2732 to handle CDROM names! Fun for
the whole family! */
--
2.24.0
Подробная информация о списке рассылки Devel