You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mesos.apache.org by bm...@apache.org on 2015/12/29 04:32:48 UTC

[1/5] mesos git commit: Added Path::extension for obtaining file extensions.

Repository: mesos
Updated Branches:
  refs/heads/master ca40d2942 -> 1b865afb5


Added Path::extension for obtaining file extensions.

Review: https://reviews.apache.org/r/41751


Project: http://git-wip-us.apache.org/repos/asf/mesos/repo
Commit: http://git-wip-us.apache.org/repos/asf/mesos/commit/4ad002f2
Tree: http://git-wip-us.apache.org/repos/asf/mesos/tree/4ad002f2
Diff: http://git-wip-us.apache.org/repos/asf/mesos/diff/4ad002f2

Branch: refs/heads/master
Commit: 4ad002f2a0bf6d75ed95542d2a1f485e257feafa
Parents: ca40d29
Author: Benjamin Mahler <be...@gmail.com>
Authored: Mon Dec 28 13:44:13 2015 -0800
Committer: Benjamin Mahler <be...@gmail.com>
Committed: Mon Dec 28 19:09:34 2015 -0800

----------------------------------------------------------------------
 .../3rdparty/stout/include/stout/path.hpp       | 29 ++++++++++++++++++++
 .../3rdparty/stout/tests/path_tests.cpp         | 23 ++++++++++++++++
 2 files changed, 52 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mesos/blob/4ad002f2/3rdparty/libprocess/3rdparty/stout/include/stout/path.hpp
----------------------------------------------------------------------
diff --git a/3rdparty/libprocess/3rdparty/stout/include/stout/path.hpp b/3rdparty/libprocess/3rdparty/stout/include/stout/path.hpp
index 0b986f0..386188b 100644
--- a/3rdparty/libprocess/3rdparty/stout/include/stout/path.hpp
+++ b/3rdparty/libprocess/3rdparty/stout/include/stout/path.hpp
@@ -147,6 +147,35 @@ public:
     return value.substr(0, end + 1);
   }
 
+  /**
+   * Returns the file extension of the path, including the dot.
+   *
+   * Returns None if the basename contains no dots, or consists
+   * entirely of dots (i.e. '.', '..').
+   *
+   * Examples:
+   *
+   *   path         | extension
+   *   ----------   | -----------
+   *   "a.txt"      |  ".txt"
+   *   "a.tar.gz"   |  ".gz"
+   *   ".bashrc"    |  ".bashrc"
+   *   "a"          |  None
+   *   "."          |  None
+   *   ".."         |  None
+   */
+  inline Option<std::string> extension() const
+  {
+    std::string _basename = basename();
+    size_t index = _basename.rfind(".");
+
+    if (_basename == "." || _basename == ".." || index == std::string::npos) {
+      return None();
+    }
+
+    return _basename.substr(index);
+  }
+
   // Implicit conversion from Path to string.
   operator std::string() const
   {

http://git-wip-us.apache.org/repos/asf/mesos/blob/4ad002f2/3rdparty/libprocess/3rdparty/stout/tests/path_tests.cpp
----------------------------------------------------------------------
diff --git a/3rdparty/libprocess/3rdparty/stout/tests/path_tests.cpp b/3rdparty/libprocess/3rdparty/stout/tests/path_tests.cpp
index 821dbb1..4374e64 100644
--- a/3rdparty/libprocess/3rdparty/stout/tests/path_tests.cpp
+++ b/3rdparty/libprocess/3rdparty/stout/tests/path_tests.cpp
@@ -93,6 +93,29 @@ TEST(PathTest, Dirname)
 }
 
 
+TEST(PathTest, Extension)
+{
+  EXPECT_NONE(Path(".").extension());
+  EXPECT_NONE(Path("..").extension());
+
+  EXPECT_NONE(Path("a").extension());
+  EXPECT_NONE(Path("/a").extension());
+  EXPECT_NONE(Path("/").extension());
+
+  EXPECT_NONE(Path("/a.b/c").extension());
+
+  EXPECT_SOME_EQ(".txt", Path("a.txt").extension());
+  EXPECT_SOME_EQ(".txt", Path("/a/b.txt").extension());
+  EXPECT_SOME_EQ(".txt", Path("/a.b/c.txt").extension());
+
+  EXPECT_SOME_EQ(".gz", Path("a.tar.gz").extension());
+  EXPECT_SOME_EQ(".gz", Path("/a.tar.gz").extension());
+
+  EXPECT_SOME_EQ(".bashrc", Path(".bashrc").extension());
+  EXPECT_SOME_EQ(".bashrc", Path("/.bashrc").extension());
+}
+
+
 TEST(PathTest, Join)
 {
   EXPECT_EQ("a/b/c", path::join("a", "b", "c"));


[5/5] mesos git commit: Fixed a compilation issue in slave_tests.cpp.

Posted by bm...@apache.org.
Fixed a compilation issue in slave_tests.cpp.


Project: http://git-wip-us.apache.org/repos/asf/mesos/repo
Commit: http://git-wip-us.apache.org/repos/asf/mesos/commit/1b865afb
Tree: http://git-wip-us.apache.org/repos/asf/mesos/tree/1b865afb
Diff: http://git-wip-us.apache.org/repos/asf/mesos/diff/1b865afb

Branch: refs/heads/master
Commit: 1b865afb5d699fd71e74df2342d4687ed53cbf12
Parents: 19dfc49
Author: Benjamin Mahler <be...@gmail.com>
Authored: Mon Dec 28 18:03:41 2015 -0800
Committer: Benjamin Mahler <be...@gmail.com>
Committed: Mon Dec 28 19:22:16 2015 -0800

----------------------------------------------------------------------
 src/tests/slave_tests.cpp | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mesos/blob/1b865afb/src/tests/slave_tests.cpp
----------------------------------------------------------------------
diff --git a/src/tests/slave_tests.cpp b/src/tests/slave_tests.cpp
index 90d56b9..68d7517 100644
--- a/src/tests/slave_tests.cpp
+++ b/src/tests/slave_tests.cpp
@@ -83,7 +83,6 @@ using testing::Eq;
 using testing::Invoke;
 using testing::Return;
 using testing::SaveArg;
-using testing::Sequence;
 
 namespace mesos {
 namespace internal {
@@ -1543,7 +1542,7 @@ TEST_F(SlaveTest, ContainerUpdatedBeforeTaskReachesExecutor)
   // `containerizer->update` or `exec->launchTask`. We want to make
   // sure that containerizer update always finishes before the task is
   // sent to the executor.
-  Sequence sequence;
+  testing::Sequence sequence;
 
   EXPECT_CALL(containerizer, update(_, _))
     .InSequence(sequence)


[2/5] mesos git commit: Use Path::extension to simplify mesos code.

Posted by bm...@apache.org.
Use Path::extension to simplify mesos code.

Review: https://reviews.apache.org/r/41753


Project: http://git-wip-us.apache.org/repos/asf/mesos/repo
Commit: http://git-wip-us.apache.org/repos/asf/mesos/commit/0c3061ea
Tree: http://git-wip-us.apache.org/repos/asf/mesos/tree/0c3061ea
Diff: http://git-wip-us.apache.org/repos/asf/mesos/diff/0c3061ea

Branch: refs/heads/master
Commit: 0c3061ea23cdb19cde2547ad0eeffe0e10438a22
Parents: 0b11957
Author: Benjamin Mahler <be...@gmail.com>
Authored: Mon Dec 28 13:53:44 2015 -0800
Committer: Benjamin Mahler <be...@gmail.com>
Committed: Mon Dec 28 19:09:36 2015 -0800

----------------------------------------------------------------------
 src/files/files.cpp | 10 ++++------
 1 file changed, 4 insertions(+), 6 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mesos/blob/0c3061ea/src/files/files.cpp
----------------------------------------------------------------------
diff --git a/src/files/files.cpp b/src/files/files.cpp
index ec036ec..dd64976 100644
--- a/src/files/files.cpp
+++ b/src/files/files.cpp
@@ -452,12 +452,10 @@ Future<Response> FilesProcess::download(const Request& request)
     strings::format("attachment; filename=%s", basename).get();
 
   // Attempt to detect the mime type.
-  size_t index = basename.find_last_of('.');
-  if (index != string::npos) {
-    string extension = basename.substr(index);
-    if (mime::types.count(extension) > 0) {
-      response.headers["Content-Type"] = mime::types[extension];
-    }
+  Option<string> extension = Path(resolvedPath.get()).extension();
+
+  if (extension.isSome() && mime::types.count(extension.get()) > 0) {
+    response.headers["Content-Type"] = mime::types[extension.get()];
   }
 
   return response;


[4/5] mesos git commit: Updated HTTP authentication to be performed during Event visitation.

Posted by bm...@apache.org.
Updated HTTP authentication to be performed during Event visitation.

Currently HTTP authentication is done in the global context of the
ProcessManager. This poses ordering issues that are absent if done
within the Process execution context. Also, users are unable to
customize authentication behavior when overriding HttpEvent
visitation.

Review: https://reviews.apache.org/r/41375/


Project: http://git-wip-us.apache.org/repos/asf/mesos/repo
Commit: http://git-wip-us.apache.org/repos/asf/mesos/commit/19dfc49f
Tree: http://git-wip-us.apache.org/repos/asf/mesos/tree/19dfc49f
Diff: http://git-wip-us.apache.org/repos/asf/mesos/diff/19dfc49f

Branch: refs/heads/master
Commit: 19dfc49fe58e264842a90f991e214563d6834190
Parents: 0c3061e
Author: Alexander Rojas <al...@mesosphere.io>
Authored: Mon Dec 28 11:33:52 2015 -0800
Committer: Benjamin Mahler <be...@gmail.com>
Committed: Mon Dec 28 19:22:14 2015 -0800

----------------------------------------------------------------------
 3rdparty/libprocess/Makefile.am                 |   4 +-
 3rdparty/libprocess/include/process/event.hpp   |   9 +-
 3rdparty/libprocess/include/process/process.hpp |  44 +++-
 .../libprocess/src/authentication_router.cpp    | 218 -------------------
 .../libprocess/src/authentication_router.hpp    |  75 -------
 .../libprocess/src/authenticator_manager.cpp    | 158 ++++++++++++++
 .../libprocess/src/authenticator_manager.hpp    |  68 ++++++
 3rdparty/libprocess/src/process.cpp             | 200 ++++++++---------
 3rdparty/libprocess/src/tests/http_tests.cpp    |  13 +-
 9 files changed, 363 insertions(+), 426 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mesos/blob/19dfc49f/3rdparty/libprocess/Makefile.am
----------------------------------------------------------------------
diff --git a/3rdparty/libprocess/Makefile.am b/3rdparty/libprocess/Makefile.am
index 82778bb..6749fd4 100644
--- a/3rdparty/libprocess/Makefile.am
+++ b/3rdparty/libprocess/Makefile.am
@@ -43,8 +43,8 @@ PICOJSON = 3rdparty/picojson-$(PICOJSON_VERSION)
 noinst_LTLIBRARIES = libprocess.la
 
 libprocess_la_SOURCES =		\
-  src/authentication_router.hpp	\
-  src/authentication_router.cpp	\
+  src/authenticator_manager.hpp	\
+  src/authenticator_manager.cpp	\
   src/clock.cpp			\
   src/config.hpp		\
   src/decoder.hpp		\

http://git-wip-us.apache.org/repos/asf/mesos/blob/19dfc49f/3rdparty/libprocess/include/process/event.hpp
----------------------------------------------------------------------
diff --git a/3rdparty/libprocess/include/process/event.hpp b/3rdparty/libprocess/include/process/event.hpp
index d7f3447..a03824c 100644
--- a/3rdparty/libprocess/include/process/event.hpp
+++ b/3rdparty/libprocess/include/process/event.hpp
@@ -117,11 +117,9 @@ struct HttpEvent : Event
 {
   HttpEvent(
       http::Request* _request,
-      Promise<http::Response>* _response,
-      const Option<std::string>& _principal = None())
+      Promise<http::Response>* _response)
     : request(_request),
-      response(_response),
-      principal(_principal) {}
+      response(_response) {}
 
   virtual ~HttpEvent()
   {
@@ -140,9 +138,6 @@ struct HttpEvent : Event
   http::Request* const request;
   Promise<http::Response>* response;
 
-  // This will be set for authenticated requests.
-  Option<std::string> principal;
-
 private:
   // Not copyable, not assignable.
   HttpEvent(const HttpEvent&);

http://git-wip-us.apache.org/repos/asf/mesos/blob/19dfc49f/3rdparty/libprocess/include/process/process.hpp
----------------------------------------------------------------------
diff --git a/3rdparty/libprocess/include/process/process.hpp b/3rdparty/libprocess/include/process/process.hpp
index d3eb698..1e4126f 100644
--- a/3rdparty/libprocess/include/process/process.hpp
+++ b/3rdparty/libprocess/include/process/process.hpp
@@ -38,6 +38,9 @@
 
 namespace process {
 
+// Forward declaration.
+class Sequence;
+
 namespace firewall {
 
 /**
@@ -61,7 +64,6 @@ void install(std::vector<Owned<FirewallRule>>&& rules);
 
 } // namespace firewall {
 
-
 class ProcessBase : public EventVisitor
 {
 public:
@@ -237,10 +239,12 @@ protected:
 
   /**
    * Any function which takes a `process::http::Request` and an
-   * `Option<std::string>` and returns a `process::http::Response`.
+   * `Option<std::string>` principal and returns a
+   * `process::http::Response`.
    *
-   * If the string is set, it represents the authenticated principal
-   * for the request.
+   * If the authentication principal string is set, the realm
+   * requires authentication and authentication succeeded. If
+   * it is not set, the realm does not require authentication.
    *
    * The default visit implementation for HTTP events invokes
    * installed HTTP handlers.
@@ -355,15 +359,37 @@ private:
   // Delegates for messages.
   std::map<std::string, UPID> delegates;
 
+  // Definition of an HTTP endpoint. The endpoint can be
+  // associated with an authentication realm, in which case:
+  //
+  //  (1) `realm` and `authenticatedHandler` will be set.
+  //      Libprocess will perform HTTP authentication for
+  //      all requests to this endpoint (by default during
+  //      HttpEvent visitation). The authentication principal
+  //      will be passed to the `authenticatedHandler`.
+  //
+  //  Otherwise, if the endpoint is not associated with an
+  //  authentication realm:
+  //
+  //  (2) Only `handler` will be set, and no authentication
+  //      takes place.
+  struct HttpEndpoint
+  {
+    Option<HttpRequestHandler> handler;
+
+    Option<std::string> realm;
+    Option<AuthenticatedHttpRequestHandler> authenticatedHandler;
+  };
+
   // Handlers for messages and HTTP requests.
   struct {
     std::map<std::string, MessageHandler> message;
+    std::map<std::string, HttpEndpoint> http;
 
-    // `HttpRequestHandlers` are equivalent to their authenticated
-    // counterparts where the principal is always `None`. Therefore
-    // we convert the regular handler to an authenticated one in
-    // order to store only a single map here.
-    std::map<std::string, AuthenticatedHttpRequestHandler> http;
+    // Used for delivering HTTP requests in the correct order.
+    // Initialized lazily to avoid ProcessBase requiring
+    // another Process!
+    Owned<Sequence> httpSequence;
   } handlers;
 
   // Definition of a static asset.

http://git-wip-us.apache.org/repos/asf/mesos/blob/19dfc49f/3rdparty/libprocess/src/authentication_router.cpp
----------------------------------------------------------------------
diff --git a/3rdparty/libprocess/src/authentication_router.cpp b/3rdparty/libprocess/src/authentication_router.cpp
deleted file mode 100644
index 930a9ee..0000000
--- a/3rdparty/libprocess/src/authentication_router.cpp
+++ /dev/null
@@ -1,218 +0,0 @@
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License
-
-#include "authentication_router.hpp"
-
-#include <string>
-
-#include <process/authenticator.hpp>
-#include <process/dispatch.hpp>
-#include <process/future.hpp>
-#include <process/http.hpp>
-#include <process/id.hpp>
-#include <process/owned.hpp>
-#include <process/process.hpp>
-
-#include <stout/hashmap.hpp>
-#include <stout/nothing.hpp>
-#include <stout/path.hpp>
-
-using std::string;
-
-namespace process {
-namespace http {
-namespace authentication {
-
-
-class AuthenticationRouterProcess : public Process<AuthenticationRouterProcess>
-{
-public:
-  AuthenticationRouterProcess();
-
-  Future<Nothing> setAuthenticator(
-      const string& realm,
-      Owned<Authenticator> authenticator);
-
-  Future<Nothing> unsetAuthenticator(
-      const string& realm);
-
-  Future<Nothing> addEndpoint(
-      const string& endpoint,
-      const string& realm);
-
-  Future<Nothing> removeEndpoint(
-      const string& realm);
-
-  Future<Option<AuthenticationResult>> authenticate(
-      const Request& request);
-
-private:
-  hashmap<string, Owned<Authenticator>> authenticators_;
-  hashmap<string, string> endpoints_;
-};
-
-
-AuthenticationRouterProcess::AuthenticationRouterProcess()
-  : ProcessBase(ID::generate("AuthenticationRouter")) {}
-
-
-Future<Nothing> AuthenticationRouterProcess::setAuthenticator(
-    const string& realm,
-    Owned<Authenticator> authenticator)
-{
-  CHECK_NOTNULL(authenticator.get());
-  authenticators_[realm] = authenticator;
-  return Nothing();
-}
-
-
-Future<Nothing> AuthenticationRouterProcess::unsetAuthenticator(
-    const string& realm)
-{
-  authenticators_.erase(realm);
-  return Nothing();
-}
-
-
-Future<Nothing> AuthenticationRouterProcess::addEndpoint(
-    const string& endpoint,
-    const string& realm)
-{
-  endpoints_[endpoint] = realm;
-  return Nothing();
-}
-
-
-Future<Nothing> AuthenticationRouterProcess::removeEndpoint(
-    const string& endpoint)
-{
-  endpoints_.erase(endpoint);
-  return Nothing();
-}
-
-
-Future<Option<AuthenticationResult>> AuthenticationRouterProcess::authenticate(
-    const Request& request)
-{
-  // Finds the longest prefix path which matches a realm.
-  Option<string> realm;
-  string name = request.url.path;
-
-  while (Path(name).dirname() != name) {
-    if (endpoints_.contains(name)) {
-      realm = endpoints_[name];
-      break;
-    }
-
-    name = Path(name).dirname();
-  }
-
-  if (realm.isNone()) {
-    return None(); // Request doesn't need authentication.
-  }
-
-  if (!authenticators_.contains(realm.get())) {
-    VLOG(2) << "Request for '" << request.url.path << "' requires"
-            << " authentication in realm '" << realm.get() << "'"
-            << " but no authenticator found";
-    return None();
-  }
-
-  return authenticators_[realm.get()]->authenticate(request)
-    .then([](const AuthenticationResult& authentication)
-        -> Future<Option<AuthenticationResult>> {
-      // Validate that exactly 1 member is set!
-      size_t count =
-        (authentication.principal.isSome()    ? 1 : 0) +
-        (authentication.unauthorized.isSome() ? 1 : 0) +
-        (authentication.forbidden.isSome()    ? 1 : 0);
-
-      if (count != 1) {
-        return Failure("Expecting one of 'principal', 'unauthorized',"
-                       " or 'forbidden' to be set");
-      }
-
-      return authentication;
-    });
-}
-
-
-AuthenticationRouter::AuthenticationRouter()
-  : process(new AuthenticationRouterProcess())
-{
-  spawn(process.get());
-}
-
-
-AuthenticationRouter::~AuthenticationRouter()
-{
-  terminate(process.get());
-  wait(process.get());
-}
-
-
-Future<Nothing> AuthenticationRouter::setAuthenticator(
-    const string& realm,
-    Owned<Authenticator> authenticator)
-{
-  return dispatch(
-      process.get(),
-      &AuthenticationRouterProcess::setAuthenticator,
-      realm,
-      authenticator);
-}
-
-
-Future<Nothing> AuthenticationRouter::unsetAuthenticator(
-    const string& realm)
-{
-  return dispatch(
-      process.get(),
-      &AuthenticationRouterProcess::unsetAuthenticator,
-      realm);
-}
-
-
-Future<Nothing> AuthenticationRouter::addEndpoint(
-    const string& endpoint,
-    const string& realm)
-{
-  return dispatch(
-      process.get(),
-      &AuthenticationRouterProcess::addEndpoint,
-      endpoint,
-      realm);
-}
-
-
-Future<Nothing> AuthenticationRouter::removeEndpoint(
-    const string& realm)
-{
-  return dispatch(
-      process.get(),
-      &AuthenticationRouterProcess::removeEndpoint,
-      realm);
-}
-
-
-Future<Option<AuthenticationResult>> AuthenticationRouter::authenticate(
-    const Request& request)
-{
-  return dispatch(
-      process.get(),
-      &AuthenticationRouterProcess::authenticate,
-      request);
-}
-
-} // namespace authentication {
-} // namespace http {
-} // namespace process {

http://git-wip-us.apache.org/repos/asf/mesos/blob/19dfc49f/3rdparty/libprocess/src/authentication_router.hpp
----------------------------------------------------------------------
diff --git a/3rdparty/libprocess/src/authentication_router.hpp b/3rdparty/libprocess/src/authentication_router.hpp
deleted file mode 100644
index c251651..0000000
--- a/3rdparty/libprocess/src/authentication_router.hpp
+++ /dev/null
@@ -1,75 +0,0 @@
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License
-
-#ifndef __PROCESS_AUTHENTICATION_ROUTER_HPP__
-#define __PROCESS_AUTHENTICATION_ROUTER_HPP__
-
-#include <string>
-
-#include <process/authenticator.hpp>
-#include <process/future.hpp>
-#include <process/http.hpp>
-#include <process/owned.hpp>
-
-#include <stout/nothing.hpp>
-#include <stout/option.hpp>
-
-namespace process {
-namespace http {
-namespace authentication {
-
-class AuthenticationRouterProcess;
-
-
-// Manages the authentication routing via authentication
-// "realms". Endpoints may map to a realm. Each realm may
-// have an authenticator, through which all requests to
-// matching endpoints must be authenticated.
-class AuthenticationRouter
-{
-public:
-  AuthenticationRouter();
-  ~AuthenticationRouter();
-
-  // Sets the authenticator for the realm; this will
-  // overwrite any previous authenticator for the realm.
-  Future<Nothing> setAuthenticator(
-      const std::string& realm,
-      Owned<Authenticator> authenticator);
-
-  // Unsets the authenticator for the realm.
-  Future<Nothing> unsetAuthenticator(const std::string& realm);
-
-  // TODO(arojas): Consider making the realm a property
-  // of the endpoint handler in `ProcessBase` rather than
-  // having the router maintain the mapping.
-  Future<Nothing> addEndpoint(
-      const std::string& endpoint,
-      const std::string& realm);
-
-  Future<Nothing> removeEndpoint(const std::string& endpoint);
-
-  // Authenticates the request, will return None if no
-  // authentication is required. None occurs when either
-  // the request endpoint does not match a realm, or there
-  // is no authenticator for the realm.
-  Future<Option<AuthenticationResult>> authenticate(const Request& request);
-
-private:
-  Owned<AuthenticationRouterProcess> process;
-};
-
-} // namespace authentication {
-} // namespace http {
-} // namespace process {
-
-#endif // __PROCESS_REALM_MANAGER_HPP__

http://git-wip-us.apache.org/repos/asf/mesos/blob/19dfc49f/3rdparty/libprocess/src/authenticator_manager.cpp
----------------------------------------------------------------------
diff --git a/3rdparty/libprocess/src/authenticator_manager.cpp b/3rdparty/libprocess/src/authenticator_manager.cpp
new file mode 100644
index 0000000..7def832
--- /dev/null
+++ b/3rdparty/libprocess/src/authenticator_manager.cpp
@@ -0,0 +1,158 @@
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License
+
+#include "authenticator_manager.hpp"
+
+#include <string>
+
+#include <process/authenticator.hpp>
+#include <process/dispatch.hpp>
+#include <process/future.hpp>
+#include <process/http.hpp>
+#include <process/id.hpp>
+#include <process/owned.hpp>
+#include <process/process.hpp>
+
+#include <stout/hashmap.hpp>
+#include <stout/nothing.hpp>
+#include <stout/path.hpp>
+
+using std::string;
+
+namespace process {
+namespace http {
+namespace authentication {
+
+
+class AuthenticatorManagerProcess : public Process<AuthenticatorManagerProcess>
+{
+public:
+  AuthenticatorManagerProcess();
+
+  Future<Nothing> setAuthenticator(
+      const string& realm,
+      Owned<Authenticator> authenticator);
+
+  Future<Nothing> unsetAuthenticator(
+      const string& realm);
+
+  Future<Option<AuthenticationResult>> authenticate(
+      const Request& request,
+      const string& realm);
+
+private:
+  hashmap<string, Owned<Authenticator>> authenticators_;
+};
+
+
+AuthenticatorManagerProcess::AuthenticatorManagerProcess()
+  : ProcessBase(ID::generate("AuthenticationRouter")) {}
+
+
+Future<Nothing> AuthenticatorManagerProcess::setAuthenticator(
+    const string& realm,
+    Owned<Authenticator> authenticator)
+{
+  CHECK_NOTNULL(authenticator.get());
+  authenticators_[realm] = authenticator;
+  return Nothing();
+}
+
+
+Future<Nothing> AuthenticatorManagerProcess::unsetAuthenticator(
+    const string& realm)
+{
+  authenticators_.erase(realm);
+  return Nothing();
+}
+
+
+Future<Option<AuthenticationResult>> AuthenticatorManagerProcess::authenticate(
+    const Request& request,
+    const string& realm)
+{
+  if (!authenticators_.contains(realm)) {
+    VLOG(2) << "Request for '" << request.url.path << "' requires"
+            << " authentication in realm '" << realm << "'"
+            << " but no authenticator found";
+    return None();
+  }
+
+  return authenticators_[realm]->authenticate(request)
+    .then([](const AuthenticationResult& authentication)
+        -> Future<Option<AuthenticationResult>> {
+      // Validate that exactly 1 member is set!
+      size_t count =
+        (authentication.principal.isSome()    ? 1 : 0) +
+        (authentication.unauthorized.isSome() ? 1 : 0) +
+        (authentication.forbidden.isSome()    ? 1 : 0);
+
+      if (count != 1) {
+        return Failure("Expecting one of 'principal', 'unauthorized',"
+                       " or 'forbidden' to be set");
+      }
+
+      return authentication;
+    });
+}
+
+
+AuthenticatorManager::AuthenticatorManager()
+  : process(new AuthenticatorManagerProcess())
+{
+  spawn(process.get());
+}
+
+
+AuthenticatorManager::~AuthenticatorManager()
+{
+  terminate(process.get());
+  wait(process.get());
+}
+
+
+Future<Nothing> AuthenticatorManager::setAuthenticator(
+    const string& realm,
+    Owned<Authenticator> authenticator)
+{
+  return dispatch(
+      process.get(),
+      &AuthenticatorManagerProcess::setAuthenticator,
+      realm,
+      authenticator);
+}
+
+
+Future<Nothing> AuthenticatorManager::unsetAuthenticator(
+    const string& realm)
+{
+  return dispatch(
+      process.get(),
+      &AuthenticatorManagerProcess::unsetAuthenticator,
+      realm);
+}
+
+
+Future<Option<AuthenticationResult>> AuthenticatorManager::authenticate(
+    const Request& request,
+    const string& realm)
+{
+  return dispatch(
+      process.get(),
+      &AuthenticatorManagerProcess::authenticate,
+      request,
+      realm);
+}
+
+} // namespace authentication {
+} // namespace http {
+} // namespace process {

http://git-wip-us.apache.org/repos/asf/mesos/blob/19dfc49f/3rdparty/libprocess/src/authenticator_manager.hpp
----------------------------------------------------------------------
diff --git a/3rdparty/libprocess/src/authenticator_manager.hpp b/3rdparty/libprocess/src/authenticator_manager.hpp
new file mode 100644
index 0000000..0dc8fd2
--- /dev/null
+++ b/3rdparty/libprocess/src/authenticator_manager.hpp
@@ -0,0 +1,68 @@
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License
+
+#ifndef __PROCESS_AUTHENTICATION_ROUTER_HPP__
+#define __PROCESS_AUTHENTICATION_ROUTER_HPP__
+
+#include <string>
+
+#include <process/authenticator.hpp>
+#include <process/future.hpp>
+#include <process/http.hpp>
+#include <process/owned.hpp>
+
+#include <stout/nothing.hpp>
+#include <stout/option.hpp>
+
+namespace process {
+namespace http {
+namespace authentication {
+
+class AuthenticatorManagerProcess;
+
+
+// Manages the realm -> Authenticator mapping for HTTP
+// authentication in libprocess. Endpoints may map to
+// a realm. Each realm may have an authenticator set
+// here, through which all requests to matching
+// endpoints will be authenticated.
+class AuthenticatorManager
+{
+public:
+  AuthenticatorManager();
+  ~AuthenticatorManager();
+
+  // Sets the authenticator for the realm; this will
+  // overwrite any previous authenticator for the realm.
+  Future<Nothing> setAuthenticator(
+      const std::string& realm,
+      Owned<Authenticator> authenticator);
+
+  // Unsets the authenticator for the realm.
+  Future<Nothing> unsetAuthenticator(const std::string& realm);
+
+  // Authenticates the request, will return None if no
+  // authentication is required because there is no
+  // authenticator for the realm.
+  Future<Option<AuthenticationResult>> authenticate(
+      const Request& request,
+      const std::string& realm);
+
+private:
+  Owned<AuthenticatorManagerProcess> process;
+};
+
+} // namespace authentication {
+} // namespace http {
+} // namespace process {
+
+#endif // __PROCESS_REALM_MANAGER_HPP__

http://git-wip-us.apache.org/repos/asf/mesos/blob/19dfc49f/3rdparty/libprocess/src/process.cpp
----------------------------------------------------------------------
diff --git a/3rdparty/libprocess/src/process.cpp b/3rdparty/libprocess/src/process.cpp
index 404206a..7fd278a 100644
--- a/3rdparty/libprocess/src/process.cpp
+++ b/3rdparty/libprocess/src/process.cpp
@@ -95,7 +95,7 @@
 #include <stout/thread_local.hpp>
 #include <stout/unreachable.hpp>
 
-#include "authentication_router.hpp"
+#include "authenticator_manager.hpp"
 #include "config.hpp"
 #include "decoder.hpp"
 #include "encoder.hpp"
@@ -123,7 +123,7 @@ using process::http::ServiceUnavailable;
 
 using process::http::authentication::Authenticator;
 using process::http::authentication::AuthenticationResult;
-using process::http::authentication::AuthenticationRouter;
+using process::http::authentication::AuthenticatorManager;
 
 using process::network::Address;
 using process::network::Socket;
@@ -193,10 +193,6 @@ public:
   // responses have been processed (e.g., waited for and sent).
   void handle(const Future<Response>& future, const Request& request);
 
-  // All requests must go through authentication here before being
-  // passed on to the route handlers.
-  Future<Option<AuthenticationResult>> authenticate(const Request& request);
-
 protected:
   void initialize() override;
 
@@ -483,7 +479,7 @@ static ProcessManager* process_manager = NULL;
 static Gate* gate = new Gate();
 
 // Used for authenticating HTTP requests.
-static AuthenticationRouter* authentication_router = NULL;
+static AuthenticatorManager* authenticator_manager = NULL;
 
 // Filter. Synchronized support for using the filterer needs to be
 // recursive in case a filterer wants to do anything fancy (which is
@@ -513,7 +509,7 @@ Future<Nothing> setAuthenticator(
 {
   process::initialize();
 
-  return authentication_router->setAuthenticator(realm, authenticator);
+  return authenticator_manager->setAuthenticator(realm, authenticator);
 }
 
 
@@ -521,7 +517,7 @@ Future<Nothing> unsetAuthenticator(const string& realm)
 {
   process::initialize();
 
-  return authentication_router->unsetAuthenticator(realm);
+  return authenticator_manager->unsetAuthenticator(realm);
 }
 
 } // namespace authentication {
@@ -976,7 +972,7 @@ void initialize(const string& delegate)
   spawn(new System(), true);
 
   // Create the global HTTP authentication router.
-  authentication_router = new AuthenticationRouter();
+  authenticator_manager = new AuthenticatorManager();
 
   // Ensure metrics process is running.
   // TODO(bmahler): Consider initializing this consistently with
@@ -1106,22 +1102,6 @@ void HttpProxy::handle(const Future<Response>& future, const Request& request)
 }
 
 
-Future<Option<AuthenticationResult>> HttpProxy::authenticate(
-    const Request& request)
-{
-  // Start the authentication immediately so that
-  // authentications run in parallel, but expose
-  // a future that is only satisfied after all
-  // previous authentications are satisfied (in
-  // order to respect HTTP pipelining).
-  Future<Option<AuthenticationResult>> authentication =
-    authentication_router->authenticate(request);
-
-  return authentications->add<Option<AuthenticationResult>>(
-      [=]() { return authentication; });
-}
-
-
 void HttpProxy::next()
 {
   if (items.size() > 0) {
@@ -2421,66 +2401,9 @@ void ProcessManager::handle(
     // order of requests to account for HTTP/1.1 pipelining.
     dispatch(proxy, &HttpProxy::handle, promise->future(), *request);
 
-    // NOTE: We capture `process_manager` in the lambda below, but
-    // it may have been deleted while authentication was in progress.
-    // This is problematic for libprocess finalization, a potential
-    // workaround is to ensure that the authentication future is
-    // satisfied within a Process' execution context.
-    dispatch(proxy, &HttpProxy::authenticate, *request)
-      .onAny([this, request, promise, receiver](
-          const Future<Option<AuthenticationResult>>& authentication) {
-        if (!authentication.isReady()) {
-          promise->set(InternalServerError());
-
-          VLOG(1) << "Returning '" << promise->future()->status << "'"
-                  << " for '" << request->url.path << "'"
-                  << " (authentication failed: "
-                  << (authentication.isFailed()
-                      ? authentication.failure()
-                      : "discarded")
-                  << ")";
-
-          delete request;
-          delete promise;
-          return;
-        }
-
-        // NOTE: The `receiver` process may have terminated while
-        // authentication was in progress. In this case `deliver`
-        // will fail and delete the `HttpEvent` which results in
-        // an `InternalServerError` response.
-
-        if (authentication->isNone()) {
-          // Request didn't need authentication or authentication
-          // is not applicable, just forward the request.
-          //
-          // TODO(benh): Use the sender PID in order to capture
-          // happens-before timing relationships for testing.
-          deliver(receiver, new HttpEvent(request, promise));
-          return;
-        }
-
-        if (authentication.get()->unauthorized.isSome()) {
-          // Request was not authenticated, challenged issued.
-          promise->set(authentication.get()->unauthorized.get());
-          delete request;
-          delete promise;
-        } else if (authentication.get()->forbidden.isSome()) {
-          // Request was not authenticated, no challenge issued.
-          promise->set(authentication.get()->forbidden.get());
-          delete request;
-          delete promise;
-        } else {
-          // Authentication succeeded.
-          const Option<string>& principal = authentication.get()->principal;
-
-          CHECK_SOME(principal); // The authentication router validates this.
-
-          // TODO(benh): Use the sender PID in order to capture
-          // happens-before timing relationships for testing.
-          deliver(receiver, new HttpEvent(request, promise, principal));
-        }
-      });
+    // TODO(benh): Use the sender PID in order to capture
+    // happens-before timing relationships for testing.
+    deliver(receiver, new HttpEvent(request, promise));
 
     return;
   }
@@ -2708,13 +2631,6 @@ void ProcessManager::cleanup(ProcessBase* process)
     delete event;
   }
 
-  // Remove all routes from the authentication router, we don't
-  // need to wait for these operations to complete.
-  foreachkey (const string& endpoint, process->handlers.http) {
-    authentication_router->removeEndpoint(
-        '/' + process->self().id + '/' + endpoint);
-  }
-
   // Possible gate non-libprocess threads are waiting at.
   Gate* gate = NULL;
 
@@ -3225,11 +3141,17 @@ void ProcessBase::visit(const HttpEvent& event)
   VLOG(1) << "Handling HTTP event for process '" << pid.id << "'"
           << " with path: '" << event.request->url.path << "'";
 
+  // Lazily initialize the Sequence needed for ordering requests
+  // across authentication.
+  if (handlers.httpSequence.get() == NULL) {
+    handlers.httpSequence.reset(new Sequence());
+  }
+
   CHECK(event.request->url.path.find('/') == 0); // See ProcessManager::handle.
 
   // Split the path by '/'.
   vector<string> tokens = strings::tokenize(event.request->url.path, "/");
-  CHECK(tokens.size() >= 1);
+  CHECK(!tokens.empty());
   CHECK_EQ(pid.id, http::decode(tokens[0]).get());
 
   // First look to see if there is an HTTP handler that can handle the
@@ -3242,15 +3164,77 @@ void ProcessBase::visit(const HttpEvent& event)
   name = strings::trim(name, strings::PREFIX, "/");
 
   while (Path(name).dirname() != name) {
-    if (handlers.http.count(name) > 0) {
-      // Now call the handler and associate the response with the promise.
-      event.response->associate(
-          handlers.http[name](*event.request, event.principal));
+    if (handlers.http.count(name) == 0) {
+      name = Path(name).dirname();
+      continue;
+    }
 
-      return;
+    HttpEndpoint endpoint = handlers.http[name];
+    Future<Option<AuthenticationResult>> authentication = None();
+
+    if (endpoint.realm.isSome()) {
+      authentication = authenticator_manager->authenticate(
+          *event.request, endpoint.realm.get());
     }
 
-    name = Path(name).dirname();
+    // Sequence the authentication future to ensure the handlers
+    // are invoked in the same order that requests arrive.
+    authentication = handlers.httpSequence->add<Option<AuthenticationResult>>(
+        [authentication]() { return authentication; });
+
+    Request request = *event.request;
+    Promise<Response>* response = new Promise<Response>();
+    event.response->associate(response->future());
+
+    authentication
+      .onAny(defer(self(), [endpoint, request, response](
+          const Future<Option<AuthenticationResult>>& authentication) {
+        if (!authentication.isReady()) {
+          response->set(InternalServerError());
+
+          VLOG(1) << "Returning '" << response->future()->status << "'"
+                  << " for '" << request.url.path << "'"
+                  << " (authentication failed: "
+                  << (authentication.isFailed()
+                      ? authentication.failure()
+                      : "discarded") << ")";
+
+          delete response;
+          return;
+        }
+
+        if (authentication->isNone()) {
+          // Request didn't need authentication or authentication
+          // is not applicable, just forward the request.
+          if (endpoint.realm.isNone()) {
+            response->associate(endpoint.handler.get()(request));
+          } else {
+            response->associate(endpoint.authenticatedHandler.get()(
+                request, None()));
+          }
+
+          delete response;
+          return;
+        }
+
+        if (authentication.get()->unauthorized.isSome()) {
+          // Request was not authenticated, challenged issued.
+          response->set(authentication.get()->unauthorized.get());
+        } else if (authentication.get()->forbidden.isSome()) {
+          // Request was not authenticated, no challenge issued.
+          response->set(authentication.get()->forbidden.get());
+        } else {
+          Option<string> principal = authentication.get()->principal;
+
+          response->associate(endpoint.authenticatedHandler.get()(
+              request, principal));
+        }
+
+        delete response;
+        return;
+    }));
+
+    return;
   }
 
   // If no HTTP handler is found look in assets.
@@ -3321,11 +3305,10 @@ void ProcessBase::route(
   // Routes must start with '/'.
   CHECK(name.find('/') == 0);
 
-  auto wrapper = [handler](const Request& request, const Option<string>&) {
-    return handler(request);
-  };
+  HttpEndpoint endpoint;
+  endpoint.handler = handler;
 
-  handlers.http[name.substr(1)] = wrapper;
+  handlers.http[name.substr(1)] = endpoint;
 
   dispatch(help, &Help::add, pid.id, name, help_);
 }
@@ -3339,11 +3322,12 @@ void ProcessBase::route(
 {
   // Routes must start with '/'.
   CHECK(name.find('/') == 0);
-  handlers.http[name.substr(1)] = handler;
 
-  // Add the endpoint to the authentication router, we don't need
-  // to wait for the operation to complete.
-  authentication_router->addEndpoint('/' + self().id + name, realm);
+  HttpEndpoint endpoint;
+  endpoint.realm = realm;
+  endpoint.authenticatedHandler = handler;
+
+  handlers.http[name.substr(1)] = endpoint;
 
   dispatch(help, &Help::add, pid.id, name, help_);
 }

http://git-wip-us.apache.org/repos/asf/mesos/blob/19dfc49f/3rdparty/libprocess/src/tests/http_tests.cpp
----------------------------------------------------------------------
diff --git a/3rdparty/libprocess/src/tests/http_tests.cpp b/3rdparty/libprocess/src/tests/http_tests.cpp
index 1926150..016e3c1 100644
--- a/3rdparty/libprocess/src/tests/http_tests.cpp
+++ b/3rdparty/libprocess/src/tests/http_tests.cpp
@@ -1208,8 +1208,7 @@ public:
 };
 
 
-// TODO(bmahler): These are disabled while MESOS-4142 is fixed.
-class DISABLED_HttpAuthenticationTest : public ::testing::Test
+class HttpAuthenticationTest : public ::testing::Test
 {
 protected:
   Future<Nothing> setAuthenticator(
@@ -1239,7 +1238,7 @@ private:
 
 // Ensures that when there is no authenticator for a realm,
 // requests are not authenticated (i.e. the principal is None).
-TEST_F(DISABLED_HttpAuthenticationTest, NoAuthenticator)
+TEST_F(HttpAuthenticationTest, NoAuthenticator)
 {
   Http http;
 
@@ -1254,7 +1253,7 @@ TEST_F(DISABLED_HttpAuthenticationTest, NoAuthenticator)
 
 
 // Tests that an authentication Unauthorized result is exposed correctly.
-TEST_F(DISABLED_HttpAuthenticationTest, Unauthorized)
+TEST_F(HttpAuthenticationTest, Unauthorized)
 {
   MockAuthenticator* authenticator = new MockAuthenticator();
   setAuthenticator("realm", Owned<Authenticator>(authenticator));
@@ -1282,7 +1281,7 @@ TEST_F(DISABLED_HttpAuthenticationTest, Unauthorized)
 
 
 // Tests that an authentication Forbidden result is exposed correctly.
-TEST_F(DISABLED_HttpAuthenticationTest, Forbidden)
+TEST_F(HttpAuthenticationTest, Forbidden)
 {
   MockAuthenticator* authenticator = new MockAuthenticator();
   setAuthenticator("realm", Owned<Authenticator>(authenticator));
@@ -1303,7 +1302,7 @@ TEST_F(DISABLED_HttpAuthenticationTest, Forbidden)
 
 
 // Tests that a successful authentication hits the endpoint.
-TEST_F(DISABLED_HttpAuthenticationTest, Authenticated)
+TEST_F(HttpAuthenticationTest, Authenticated)
 {
   MockAuthenticator* authenticator = new MockAuthenticator();
   setAuthenticator("realm", Owned<Authenticator>(authenticator));
@@ -1330,7 +1329,7 @@ TEST_F(DISABLED_HttpAuthenticationTest, Authenticated)
 
 // Tests that HTTP pipelining is respected even when
 // authentications are satisfied out-of-order.
-TEST_F(DISABLED_HttpAuthenticationTest, Pipelining)
+TEST_F(HttpAuthenticationTest, Pipelining)
 {
   MockAuthenticator* authenticator = new MockAuthenticator();
   setAuthenticator("realm", Owned<Authenticator>(authenticator));


[3/5] mesos git commit: Use Path::extension to simplify libprocess code.

Posted by bm...@apache.org.
Use Path::extension to simplify libprocess code.

Review: https://reviews.apache.org/r/41752


Project: http://git-wip-us.apache.org/repos/asf/mesos/repo
Commit: http://git-wip-us.apache.org/repos/asf/mesos/commit/0b119575
Tree: http://git-wip-us.apache.org/repos/asf/mesos/tree/0b119575
Diff: http://git-wip-us.apache.org/repos/asf/mesos/diff/0b119575

Branch: refs/heads/master
Commit: 0b1195753d3128817fa178969b2f242169eebfa8
Parents: 4ad002f
Author: Benjamin Mahler <be...@gmail.com>
Authored: Mon Dec 28 13:48:49 2015 -0800
Committer: Benjamin Mahler <be...@gmail.com>
Committed: Mon Dec 28 19:09:36 2015 -0800

----------------------------------------------------------------------
 3rdparty/libprocess/src/process.cpp | 11 ++++-------
 1 file changed, 4 insertions(+), 7 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mesos/blob/0b119575/3rdparty/libprocess/src/process.cpp
----------------------------------------------------------------------
diff --git a/3rdparty/libprocess/src/process.cpp b/3rdparty/libprocess/src/process.cpp
index cff635e..404206a 100644
--- a/3rdparty/libprocess/src/process.cpp
+++ b/3rdparty/libprocess/src/process.cpp
@@ -3267,13 +3267,10 @@ void ProcessBase::visit(const HttpEvent& event)
     }
 
     // Try and determine the Content-Type from an extension.
-    string basename = Path(response.path).basename();
-    size_t index = basename.find_last_of('.');
-    if (index != string::npos) {
-      string extension = basename.substr(index);
-      if (assets[name].types.count(extension) > 0) {
-        response.headers["Content-Type"] = assets[name].types[extension];
-      }
+    Option<string> extension = Path(response.path).extension();
+
+    if (extension.isSome() && assets[name].types.count(extension.get()) > 0) {
+      response.headers["Content-Type"] = assets[name].types[extension.get()];
     }
 
     // TODO(benh): Use "text/plain" for assets that don't have an