From 45a4174d5269661cfbd46e56acbbdc6551c6fbe2 Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Sat, 9 Jan 2016 23:36:58 +0200 Subject: Support https protocol for repository_location --- bpkg/manifest | 10 ++++++++ bpkg/manifest.cxx | 24 ++++++++++++------ tests/repository-location/driver.cxx | 49 ++++++++++++++++++++++++++++++++++++ 3 files changed, 75 insertions(+), 8 deletions(-) diff --git a/bpkg/manifest b/bpkg/manifest index d4c34d6..d443c49 100644 --- a/bpkg/manifest +++ b/bpkg/manifest @@ -458,6 +458,15 @@ namespace bpkg return port_; } + bool + secure () const + { + if (local ()) + throw std::logic_error ("local location"); + + return secure_; + } + // Note that this is not necessarily syntactically the same string // as what was used to initialize this location. But it should be // semantically equivalent. String representation of an empty @@ -471,6 +480,7 @@ namespace bpkg std::string host_; std::uint16_t port_; butl::dir_path path_; + bool secure_; }; inline std::ostream& diff --git a/bpkg/manifest.cxx b/bpkg/manifest.cxx index 48e7a99..ac746e6 100644 --- a/bpkg/manifest.cxx +++ b/bpkg/manifest.cxx @@ -1221,12 +1221,16 @@ namespace bpkg if (!b.empty () && b.relative ()) throw invalid_argument ("base relative filesystem path"); - if (::strncasecmp (l.c_str (), "http://", 7) == 0) + secure_ = false; + + if (::strncasecmp (l.c_str (), "http://", 7) == 0 || + (secure_ = ::strncasecmp (l.c_str (), "https://", 8) == 0)) { // Split location into host, port and path components. Calculate // canonical name part removing www. and pkg. prefixes. // - auto p (l.find ('/', 7)); + size_t host_offset (secure_ ? 8 : 7); + auto p (l.find ('/', host_offset)); // The remote repository location with no path specified is not a valid // one. Keep the path_ member empty so the later check for emptiness @@ -1241,7 +1245,7 @@ namespace bpkg // Put the lower-cased version of the host part into host_. // Chances are good it will stay unmodified. // - transform (l.cbegin () + 7, + transform (l.cbegin () + host_offset, p == string::npos ? l.cend () : l.cbegin () + p, back_inserter (host_), lowercase); @@ -1332,16 +1336,19 @@ namespace bpkg // speaking we can end up with comething bogus like "com" // if the host is "pkg.com". // + bool bpkg (false); if (host_.compare (0, 4, "www.") == 0 || - host_.compare (0, 4, "pkg.") == 0) - canonical_name_.assign (host_, 4, string::npos); + host_.compare (0, 4, "pkg.") == 0 || + (bpkg = host_.compare (0, 5, "bpkg.") == 0)) + canonical_name_.assign (host_, bpkg ? 5 : 4, string::npos); else canonical_name_ = host_; // For canonical name and for the HTTP protocol, treat a.com - // and a.com:80 as the same name. + // and a.com:80 as the same name. The same rule apply the HTTPS protocol + // and the port 443. // - if (port_ != 0 && port_ != 80) + if (port_ != 0 && port_ != (secure_ ? 443 : 80)) canonical_name_ += ':' + to_string (port_); } else @@ -1357,6 +1364,7 @@ namespace bpkg host_ = b.host_; port_ = b.port_; path_ = b.path_ / path_; + secure_ = b.secure_; // Set canonical name to the base location canonical name host // part. The path part of the canonical name is calculated below. @@ -1450,7 +1458,7 @@ namespace bpkg if (local ()) return path_.string (); - string p ("http://" + host_); + string p ((secure_ ? "https://" : "http://") + host_); if (port_ != 0) p += ":" + to_string (port_); diff --git a/tests/repository-location/driver.cxx b/tests/repository-location/driver.cxx index cbd76f9..5d88b0d 100644 --- a/tests/repository-location/driver.cxx +++ b/tests/repository-location/driver.cxx @@ -99,6 +99,7 @@ main (int argc, char* argv[]) assert (bad_location ("aaa/bbb")); assert (bad_location ("/aaa/bbb")); assert (bad_location ("http://aa")); + assert (bad_location ("https://aa")); assert (bad_location ("http://aa/")); assert (bad_location ("http://aa/b/..")); assert (bad_location ("http://aa/.")); @@ -153,11 +154,25 @@ main (int argc, char* argv[]) repository_location l ("http://www.a.com:80/1/aa/bb"); assert (l.string () == "http://www.a.com:80/1/aa/bb"); assert (l.canonical_name () == "a.com/aa/bb"); + assert (!l.secure ()); + } + { + repository_location l ("https://www.a.com:443/1/aa/bb"); + assert (l.string () == "https://www.a.com:443/1/aa/bb"); + assert (l.canonical_name () == "a.com/aa/bb"); + assert (l.secure ()); } { repository_location l ("http://www.a.com:8080/dd/1/aa/bb"); assert (l.string () == "http://www.a.com:8080/dd/1/aa/bb"); assert (l.canonical_name () == "a.com:8080/aa/bb"); + assert (!l.secure ()); + } + { + repository_location l ("https://www.a.com:444/dd/1/aa/bb"); + assert (l.string () == "https://www.a.com:444/dd/1/aa/bb"); + assert (l.canonical_name () == "a.com:444/aa/bb"); + assert (l.secure ()); } { repository_location l ("http://a.com/a/b/../c/1/aa/../bb"); @@ -165,11 +180,26 @@ main (int argc, char* argv[]) assert (l.canonical_name () == "a.com/bb"); } { + repository_location l ("https://a.com/a/b/../c/1/aa/../bb"); + assert (l.string () == "https://a.com/a/c/1/bb"); + assert (l.canonical_name () == "a.com/bb"); + } + { repository_location l ("http://www.CPPget.org/qw/1/a/b/"); assert (l.string () == "http://www.cppget.org/qw/1/a/b"); assert (l.canonical_name () == "cppget.org/a/b"); } { + repository_location l ("http://pkg.CPPget.org/qw/1/a/b/"); + assert (l.string () == "http://pkg.cppget.org/qw/1/a/b"); + assert (l.canonical_name () == "cppget.org/a/b"); + } + { + repository_location l ("http://bpkg.CPPget.org/qw/1/a/b/"); + assert (l.string () == "http://bpkg.cppget.org/qw/1/a/b"); + assert (l.canonical_name () == "cppget.org/a/b"); + } + { repository_location l ("http://abc.cppget.org/qw/1/a/b/"); assert (l.string () == "http://abc.cppget.org/qw/1/a/b"); assert (l.canonical_name () == "abc.cppget.org/a/b"); @@ -180,6 +210,11 @@ main (int argc, char* argv[]) assert (l.canonical_name () == "www.cppget.org/a/b"); } { + repository_location l ("http://bpkg.www.cppget.org/qw/1/a/b/"); + assert (l.string () == "http://bpkg.www.cppget.org/qw/1/a/b"); + assert (l.canonical_name () == "www.cppget.org/a/b"); + } + { repository_location l ("http://cppget.org/qw//1/a//b/"); assert (l.string () == "http://cppget.org/qw/1/a/b"); assert (l.canonical_name () == "cppget.org/a/b"); @@ -195,6 +230,12 @@ main (int argc, char* argv[]) assert (l2.canonical_name () == "stable.cppget.org/math"); } { + repository_location l1 ("https://stable.cppget.org/1/misc"); + repository_location l2 ("../../1/math", l1); + assert (l2.string () == "https://stable.cppget.org/1/math"); + assert (l2.canonical_name () == "stable.cppget.org/math"); + } + { repository_location l1 ("http://stable.cppget.org/1/misc"); repository_location l2 ("../math", l1); assert (l2.string () == "http://stable.cppget.org/1/math"); @@ -205,6 +246,14 @@ main (int argc, char* argv[]) repository_location l2 ("../1/math", l1); assert (l2.string () == "http://www.stable.cppget.org:8080/1/math"); assert (l2.canonical_name () == "stable.cppget.org:8080/math"); + assert (!l2.secure ()); + } + { + repository_location l1 ("https://www.stable.cppget.org:444/1"); + repository_location l2 ("../1/math", l1); + assert (l2.string () == "https://www.stable.cppget.org:444/1/math"); + assert (l2.canonical_name () == "stable.cppget.org:444/math"); + assert (l2.secure ()); } { repository_location l1 ("/var/r1/1/misc"); -- cgit v1.1