This is an automated email from the ASF dual-hosted git repository.

bennoe pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/mesos.git

commit 998c2e2cdfb5c79e611a3129a708eac661daa4b7
Author: Benno Evers <[email protected]>
AuthorDate: Mon Nov 25 15:59:27 2019 +0100

    Added support for new 'http+unix' URL scheme in libprocess.
    
    Added support for a new 'http+unix' URL scheme, to denote
    resources accessible by HTTP connections over unix domain
    sockets.
    
    The encoding looks like
    
        http+unix://<url-encoded filesystem path>/<http path>
    
    optionally followed by query and fragment sections.
    
    Review: https://reviews.apache.org/r/71814
---
 3rdparty/libprocess/include/process/http.hpp | 15 ++++++-
 3rdparty/libprocess/src/http.cpp             | 63 +++++++++++++++++++++++-----
 2 files changed, 67 insertions(+), 11 deletions(-)

diff --git a/3rdparty/libprocess/include/process/http.hpp 
b/3rdparty/libprocess/include/process/http.hpp
index 0013850..1882c62 100644
--- a/3rdparty/libprocess/include/process/http.hpp
+++ b/3rdparty/libprocess/include/process/http.hpp
@@ -55,8 +55,9 @@ namespace http {
 
 enum class Scheme {
   HTTP,
+  HTTP_UNIX,
 #ifdef USE_SSL_SOCKET
-  HTTPS
+  HTTPS,
 #endif
 };
 
@@ -132,6 +133,18 @@ struct URL
 
   URL(const std::string& _scheme,
       const std::string& _domain,
+      const std::string& _path,
+      const hashmap<std::string, std::string>& _query =
+        (hashmap<std::string, std::string>()),
+      const Option<std::string>& _fragment = None())
+    : scheme(_scheme),
+      domain(_domain),
+      path(_path),
+      query(_query),
+      fragment(_fragment) {}
+
+  URL(const std::string& _scheme,
+      const std::string& _domain,
       const uint16_t _port = 80,
       const std::string& _path = "/",
       const hashmap<std::string, std::string>& _query =
diff --git a/3rdparty/libprocess/src/http.cpp b/3rdparty/libprocess/src/http.cpp
index b487ce2..0f8dc56 100644
--- a/3rdparty/libprocess/src/http.cpp
+++ b/3rdparty/libprocess/src/http.cpp
@@ -1015,12 +1015,25 @@ string encode(const hashmap<string, string>& query)
 
 ostream& operator<<(ostream& stream, const URL& url)
 {
+  // TODO(bevers): The '//' sequence only follows the ':' if
+  // the next part begins with an "authority". This is required
+  // for the 'http' scheme, but not guaranteed in general.
   if (url.scheme.isSome()) {
     stream << url.scheme.get() << "://";
   }
 
   if (url.domain.isSome()) {
-    stream << url.domain.get();
+    // Optimize the most common case by not encoding for `http`
+    // and `https` schemes, since their domain part is already
+    // guaranteed to only contain unreserved characters.
+    bool encodeDomain = url.scheme.isNone() ||
+      (*url.scheme != "http" && *url.scheme != "https");
+
+    const std::string& host = encodeDomain
+      ? http::encode(url.domain.get())
+      : url.domain.get();
+
+    stream << host;
   } else if (url.ip.isSome()) {
     stream << url.ip.get();
   }
@@ -1079,7 +1092,9 @@ Pipe::Reader encode(const Request& request)
   // Need to specify the 'Host' header.
   CHECK(request.url.domain.isSome() || request.url.ip.isSome());
 
-  if (request.url.domain.isSome()) {
+  if (request.url.scheme == Some("http+unix")) {
+    headers["Host"] = "localhost";
+  } else if (request.url.domain.isSome()) {
     headers["Host"] = request.url.domain.get();
   } else if (request.url.ip.isSome()) {
     headers["Host"] = stringify(request.url.ip.get());
@@ -1505,6 +1520,7 @@ Future<Connection> connect(
 
   switch (scheme) {
     case Scheme::HTTP:
+    case Scheme::HTTP_UNIX:
       kind = SocketImpl::Kind::POLL;
       break;
 #ifdef USE_SSL_SOCKET
@@ -1525,6 +1541,7 @@ Future<Connection> connect(
   Future<Nothing> connected = [&]() {
     switch (scheme) {
       case Scheme::HTTP:
+      case Scheme::HTTP_UNIX:
         return socket->connect(address);
 #ifdef USE_SSL_SOCKET
       case Scheme::HTTPS:
@@ -1559,6 +1576,10 @@ Future<Connection> connect(
 
 Future<Connection> connect(const URL& url)
 {
+  // Default to 'http' if no scheme was specified.
+  string scheme = url.scheme.getOrElse("http");
+  bool inetAddressRequired = scheme == "http" || scheme == "https";
+
   // TODO(bmahler): Move address resolution into the URL class?
   Address address = inet4::Address::ANY_ANY();
 
@@ -1568,7 +1589,7 @@ Future<Connection> connect(const URL& url)
 
   if (url.ip.isSome()) {
     address.ip = url.ip.get();
-  } else {
+  } else if (inetAddressRequired) {
     Try<net::IP> ip = net::getIP(url.domain.get(), AF_INET);
 
     if (ip.isError()) {
@@ -1579,18 +1600,19 @@ Future<Connection> connect(const URL& url)
     address.ip = ip.get();
   }
 
-  if (url.port.isNone()) {
+  if (url.port.isNone() && inetAddressRequired) {
     return Failure("Expecting url.port to be set");
   }
 
-  address.port = url.port.get();
+  if (url.port.isSome()) {
+    address.port = url.port.get();
+  }
 
-  // Default to 'http' if no scheme was specified.
-  if (url.scheme.isNone() || url.scheme == string("http")) {
+  if (scheme == "http") {
     return connect(address, Scheme::HTTP, url.domain);
   }
 
-  if (url.scheme == string("https")) {
+  if (scheme == "https") {
 #ifdef USE_SSL_SOCKET
     return connect(address, Scheme::HTTPS, url.domain);
 #else
@@ -1598,6 +1620,24 @@ Future<Connection> connect(const URL& url)
 #endif
   }
 
+  if (scheme == "http+unix") {
+    if (!url.domain.isSome()) {
+      return Failure("'http+unix' scheme requires domain (filesystem path)");
+    }
+
+    Try<network::unix::Address> address =
+      network::unix::Address::create(url.domain.get());
+
+    if (address.isError()) {
+      return Failure(strings::format(
+          "Could not create address from %s: %s",
+          url.domain.get(),
+          address.error()).get());
+    }
+
+    return connect(*address, Scheme::HTTP, url.domain);
+  }
+
   return Failure("Unsupported URL scheme");
 }
 
@@ -2306,9 +2346,12 @@ Try<Server> Server::create(
 {
   SocketImpl::Kind kind = [&]() {
     switch (options.scheme) {
-      case Scheme::HTTP: return SocketImpl::Kind::POLL;
+      case Scheme::HTTP:
+      case Scheme::HTTP_UNIX:
+        return SocketImpl::Kind::POLL;
 #ifdef USE_SSL_SOCKET
-      case Scheme::HTTPS: return SocketImpl::Kind::SSL;
+      case Scheme::HTTPS:
+        return SocketImpl::Kind::SSL;
 #endif
     }
     UNREACHABLE();

Reply via email to