webserver: Move web server functionality into webservd

Moved libmicrohttpd from libwebserv to webservd daemon. Added the
D-Bus interface between the web server daemon and client library.

Updated privetd to use the new interface.

BUG=brillo:10
TEST=`FEATURES=test emerge-link libwebserv privetd`
CQ-DEPEND=CL:245780,CL:245118,CL:*195757

Change-Id: I26bfab64c6a0fd9460a47fd3fa9205c89abb943a
Reviewed-on: https://chromium-review.googlesource.com/245980
Reviewed-by: Alex Vakulenko <avakulenko@chromium.org>
Tested-by: Alex Vakulenko <avakulenko@chromium.org>
Commit-Queue: Alex Vakulenko <avakulenko@chromium.org>
diff --git a/libwebserv/connection.cc b/libwebserv/connection.cc
deleted file mode 100644
index 4e1ae8f..0000000
--- a/libwebserv/connection.cc
+++ /dev/null
@@ -1,158 +0,0 @@
-// Copyright 2014 The Chromium OS Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include <libwebserv/connection.h>
-
-#include <algorithm>
-#include <vector>
-
-#include <base/bind.h>
-#include <base/location.h>
-#include <base/logging.h>
-#include <base/task_runner.h>
-#include <chromeos/http/http_request.h>
-#include <libwebserv/request.h>
-#include <libwebserv/request_handler_interface.h>
-#include <libwebserv/response.h>
-#include <libwebserv/server.h>
-#include <microhttpd.h>
-
-namespace libwebserv {
-
-// Helper class to provide static callback methods to microhttpd library,
-// with the ability to access private methods of Connection class.
-class ConnectionHelper {
- public:
-  static int PostDataIterator(void* cls,
-                              MHD_ValueKind kind,
-                              const char* key,
-                              const char* filename,
-                              const char* content_type,
-                              const char* transfer_encoding,
-                              const char* data,
-                              uint64_t off,
-                              size_t size) {
-    Connection* server_connection = reinterpret_cast<Connection*>(cls);
-    if (!server_connection->ProcessPostData(
-        key, filename, content_type, transfer_encoding, data, off, size)) {
-      return MHD_NO;
-    }
-    return MHD_YES;
-  }
-};
-
-// Helper class to provide static callback methods to microhttpd library,
-// with the ability to access private methods of Request class.
-class RequestHelper {
- public:
-  static int ValueCallback(void* cls,
-                           MHD_ValueKind kind,
-                           const char* key,
-                           const char* value) {
-    auto self = reinterpret_cast<Request*>(cls);
-    std::string data;
-    if (value)
-      data = value;
-    if (kind == MHD_HEADER_KIND) {
-      self->headers_.emplace(Request::GetCanonicalHeaderName(key), data);
-    } else if (kind == MHD_COOKIE_KIND) {
-      // TODO(avakulenko): add support for cookies...
-    } else if (kind == MHD_POSTDATA_KIND) {
-      self->post_data_.emplace(key, data);
-    } else if (kind == MHD_GET_ARGUMENT_KIND) {
-      self->get_data_.emplace(key, data);
-    }
-    return MHD_YES;
-  }
-};
-
-Connection::Connection(const scoped_refptr<base::TaskRunner>& task_runner,
-                       MHD_Connection* connection,
-                       RequestHandlerInterface* handler)
-    : task_runner_(task_runner),
-      raw_connection_(connection),
-      handler_(handler) {
-}
-
-Connection::~Connection() {
-  if (post_processor_)
-    MHD_destroy_post_processor(post_processor_);
-}
-
-scoped_refptr<Connection> Connection::Create(Server* server,
-                                             const std::string& url,
-                                             const std::string& method,
-                                             MHD_Connection* connection,
-                                             RequestHandlerInterface* handler) {
-  scoped_refptr<Connection> result(
-      new Connection(server->task_runner_, connection, handler));
-  VLOG(1) << "Incoming HTTP connection (" << result.get() << ")."
-          << " Method='" << method << "', URL='" << url << "'";
-  result->post_processor_ = MHD_create_post_processor(
-      connection, 1024, &ConnectionHelper::PostDataIterator, result.get());
-  result->request_ = Request::Create(url, method);
-  result->response_ = Response::Create(result);
-  return result;
-}
-
-bool Connection::BeginRequestData() {
-  MHD_get_connection_values(raw_connection_, MHD_HEADER_KIND,
-                            &RequestHelper::ValueCallback, request_.get());
-  MHD_get_connection_values(raw_connection_, MHD_COOKIE_KIND,
-                            &RequestHelper::ValueCallback, request_.get());
-  MHD_get_connection_values(raw_connection_, MHD_POSTDATA_KIND,
-                            &RequestHelper::ValueCallback, request_.get());
-  MHD_get_connection_values(raw_connection_, MHD_GET_ARGUMENT_KIND,
-                            &RequestHelper::ValueCallback, request_.get());
-  return true;
-}
-
-bool Connection::AddRequestData(const void* data, size_t size) {
-  if (!post_processor_)
-    return request_->AddRawRequestData(data, size);
-  return MHD_post_process(post_processor_,
-                          static_cast<const char*>(data), size) == MHD_YES;
-}
-
-void Connection::EndRequestData() {
-  if (state_ == State::kIdle) {
-    state_ = State::kRequestSent;
-    // libmicrohttpd calls handlers on its own thread.
-    // Redirect this to the main IO thread of the server.
-    task_runner_->PostTask(
-        FROM_HERE,
-        base::Bind(&RequestHandlerInterface::HandleRequest,
-                   base::Unretained(handler_), base::Passed(&request_),
-                   base::Passed(&response_)));
-  } else if (state_ == State::kResponseReceived) {
-    VLOG(1) << "Sending HTTP response for connection (" << this
-            << "): " << response_status_code_
-            << ", data size = " << response_data_.size();
-    MHD_Response* resp = MHD_create_response_from_buffer(
-        response_data_.size(), response_data_.data(), MHD_RESPMEM_PERSISTENT);
-    for (const auto& pair : response_headers_) {
-      MHD_add_response_header(resp, pair.first.c_str(), pair.second.c_str());
-    }
-    CHECK_EQ(MHD_YES,
-             MHD_queue_response(raw_connection_, response_status_code_, resp))
-        << "Failed to queue response";
-    MHD_destroy_response(resp);  // |resp| is ref-counted.
-    state_ = State::kDone;
-  }
-}
-
-bool Connection::ProcessPostData(const char* key,
-                                 const char* filename,
-                                 const char* content_type,
-                                 const char* transfer_encoding,
-                                 const char* data,
-                                 uint64_t off,
-                                 size_t size) {
-  if (off == 0)
-    return  request_->AddPostFieldData(key, filename, content_type,
-                                       transfer_encoding, data, size);
-  return request_->AppendPostFieldData(key, data, size);
-}
-
-}  // namespace libwebserv
diff --git a/libwebserv/connection.h b/libwebserv/connection.h
deleted file mode 100644
index 73bb816..0000000
--- a/libwebserv/connection.h
+++ /dev/null
@@ -1,89 +0,0 @@
-// Copyright 2014 The Chromium OS Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef WEBSERVER_LIBWEBSERV_CONNECTION_H_
-#define WEBSERVER_LIBWEBSERV_CONNECTION_H_
-
-#include <map>
-#include <string>
-#include <vector>
-
-#include <base/macros.h>
-#include <base/memory/ref_counted.h>
-#include <base/memory/scoped_ptr.h>
-#include <chromeos/errors/error.h>
-#include <libwebserv/export.h>
-
-struct MHD_Connection;
-struct MHD_PostProcessor;
-
-namespace base {
-class TaskRunner;
-}  // namespace base
-
-namespace libwebserv {
-
-class Request;
-class RequestHandlerInterface;
-class Response;
-class Server;
-
-// A wrapper class around low-level HTTP connection.
-class LIBWEBSERV_EXPORT Connection final : public base::RefCounted<Connection> {
- public:
-  ~Connection();
-
-  // Factory creator method. Creates an instance of the connection and
-  // initializes some complex data members. This is safer and easier to
-  // report possible failures than reply on just the constructor.
-  static scoped_refptr<Connection> Create(Server* server,
-                                          const std::string& url,
-                                          const std::string& method,
-                                          MHD_Connection* connection,
-                                          RequestHandlerInterface* handler);
-
- private:
-  LIBWEBSERV_PRIVATE Connection(
-      const scoped_refptr<base::TaskRunner>& task_runner,
-      MHD_Connection* connection,
-      RequestHandlerInterface* handler);
-
-  // Helper callback methods used by Server's ConnectionHandler to transfer
-  // request headers and data to the Connection's Request object.
-  LIBWEBSERV_PRIVATE bool BeginRequestData();
-  LIBWEBSERV_PRIVATE bool AddRequestData(const void* data, size_t size);
-  LIBWEBSERV_PRIVATE void EndRequestData();
-
-  // Callback for libmicrohttpd's PostProcessor.
-  LIBWEBSERV_PRIVATE bool ProcessPostData(const char* key,
-                                          const char* filename,
-                                          const char* content_type,
-                                          const char* transfer_encoding,
-                                          const char* data,
-                                          uint64_t off,
-                                          size_t size);
-
-  scoped_refptr<base::TaskRunner> task_runner_;
-  MHD_Connection* raw_connection_{nullptr};
-  RequestHandlerInterface* handler_{nullptr};
-  MHD_PostProcessor* post_processor_{nullptr};
-  scoped_ptr<Request> request_;
-  scoped_ptr<Response> response_;
-
-  enum class State { kIdle, kRequestSent, kResponseReceived, kDone };
-  State state_{State::kIdle};
-  int response_status_code_{0};
-  std::vector<uint8_t> response_data_;
-  std::multimap<std::string, std::string> response_headers_;
-
-  friend class ConnectionHelper;
-  friend class Request;
-  friend class Response;
-  friend class ServerHelper;
-  DISALLOW_COPY_AND_ASSIGN(Connection);
-};
-
-}  // namespace libwebserv
-
-#endif  // WEBSERVER_LIBWEBSERV_CONNECTION_H_
diff --git a/libwebserv/dbus_bindings/org.chromium.WebServer.RequestHandler.xml b/libwebserv/dbus_bindings/org.chromium.WebServer.RequestHandler.xml
new file mode 100644
index 0000000..5eab71d
--- /dev/null
+++ b/libwebserv/dbus_bindings/org.chromium.WebServer.RequestHandler.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+
+<node name="/org/chromium/WebServer/RequestHandler"
+      xmlns:tp="http://telepathy.freedesktop.org/wiki/DbusSpec#extensions-v0">
+  <interface name="org.chromium.WebServer.RequestHandler">
+    <!-- Methods -->
+    <method name="ProcessRequest">
+      <tp:docstring>
+        Sends a new HTTP request to the handler.
+        Parameters:
+        - request_info - request metadata. Due to limitation of base::Callback
+                       on the number of parameters, we have to collapse a couple
+                       of distinct parameters into a larger struct, containing:
+                       - (s) protocol_handler_id - ID of the protocol handler.
+                       - (s) request_handler_id - ID of the registered request
+                                                  handler.
+                       - (s) request_id - unique ID of this request within the
+                                          protocol handler.
+                       - (s) url - The request URL (e.g. "/path/object").
+                       - (s) method - Request method (e.g. "GET", "POST", ...).
+        - headers - Request headers (key-value pairs)
+        - params - an array of request parameters which could be either
+                   URL params (specified after "?" in the request URL), or
+                   form fields in a POST request. Elements have the following
+                   structure:
+                   - (b) true = form field, false = URL param
+                   - (s) field_name
+                   - (s) field_value
+        - files - Information about uploaded files.
+                  The data is an array of FileInfo structures containing the
+                  following fields:
+                  - (i) file_id
+                  - (s) field_name
+                  - (s) file_name
+                  - (s) content_type
+                  - (s) transfer_encoding
+                  The actual contents of the file is obtained by calling
+                  GetFileData() on the request object
+        - body - Raw unparsed request data. Could be empty for POST requests
+                 that have form data/uploaded files already parsed into
+                 form_fields/files parameters.
+      </tp:docstring>
+      <arg name="request_info" type="(sssss)" direction="in"/>
+      <arg name="headers" type="a(ss)" direction="in"/>
+      <arg name="params" type="a(bss)" direction="in"/>
+      <arg name="files" type="a(issss)" direction="in"/>
+      <arg name="body" type="ay" direction="in"/>
+      <annotation name="org.chromium.DBus.Method.Kind" value="normal"/>
+    </method>
+  </interface>
+</node>
diff --git a/libwebserv/protocol_handler.cc b/libwebserv/protocol_handler.cc
new file mode 100644
index 0000000..9a10acf
--- /dev/null
+++ b/libwebserv/protocol_handler.cc
@@ -0,0 +1,207 @@
+// Copyright 2014 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "webserver/libwebserv/protocol_handler.h"
+
+#include <tuple>
+
+#include <base/logging.h>
+#include <chromeos/map_utils.h>
+
+#include "libwebserv/org.chromium.WebServer.RequestHandler.h"
+#include "webservd/dbus-proxies.h"
+#include "webserver/libwebserv/request.h"
+#include "webserver/libwebserv/request_handler_callback.h"
+#include "webserver/libwebserv/response.h"
+#include "webserver/libwebserv/server.h"
+
+namespace libwebserv {
+
+namespace {
+
+// A dummy callback for async D-Bus errors.
+void IgnoreError(chromeos::Error* error) {}
+
+}  // anonymous namespace
+
+const char ProtocolHandler::kHttp[] = "http";
+const char ProtocolHandler::kHttps[] = "https";
+
+ProtocolHandler::ProtocolHandler(const std::string& id, Server* server)
+    : id_{id}, server_{server} {}
+
+ProtocolHandler::~ProtocolHandler() {
+  // Remove any existing handlers, so the web server knows that we don't
+  // need them anymore.
+
+  // We need to get a copy of the map keys since removing the handlers will
+  // modify the map in the middle of the loop and that's not a good thing.
+  auto handler_ids = chromeos::GetMapKeys(request_handlers_);
+  for (int handler_id : handler_ids) {
+    RemoveHandler(handler_id);
+  }
+}
+
+std::string ProtocolHandler::GetID() const {
+  return id_;
+}
+
+uint16_t ProtocolHandler::GetPort() const {
+  CHECK(IsConnected());
+  return proxy_->port();
+}
+
+std::string ProtocolHandler::GetProtocol() const {
+  CHECK(IsConnected());
+  return proxy_->protocol();
+}
+
+chromeos::Blob ProtocolHandler::GetCertificateFingerprint() const {
+  CHECK(IsConnected());
+  return proxy_->certificate_fingerprint();
+}
+
+int ProtocolHandler::AddHandler(
+    const std::string& url,
+    const std::string& method,
+    std::unique_ptr<RequestHandlerInterface> handler) {
+  request_handlers_.emplace(++last_handler_id_,
+                            HandlerMapEntry{url, method, std::string{},
+                                            std::move(handler)});
+  if (proxy_) {
+    proxy_->AddRequestHandlerAsync(
+        url,
+        method,
+        server_->service_name_,
+        base::Bind(&ProtocolHandler::AddHandlerSuccess,
+                   weak_ptr_factory_.GetWeakPtr(),
+                   last_handler_id_),
+        base::Bind(&ProtocolHandler::AddHandlerError,
+                   weak_ptr_factory_.GetWeakPtr(),
+                   last_handler_id_));
+  }
+  return last_handler_id_;
+}
+
+int ProtocolHandler::AddHandlerCallback(
+    const std::string& url,
+    const std::string& method,
+    const base::Callback<RequestHandlerInterface::HandlerSignature>&
+        handler_callback) {
+  std::unique_ptr<RequestHandlerInterface> handler{
+      new RequestHandlerCallback{handler_callback}};
+  return AddHandler(url, method, std::move(handler));
+}
+
+bool ProtocolHandler::RemoveHandler(int handler_id) {
+  auto p = request_handlers_.find(handler_id);
+  if (p == request_handlers_.end())
+    return false;
+
+  if (proxy_) {
+    proxy_->RemoveRequestHandlerAsync(
+        p->second.remote_handler_id,
+        base::Bind(&base::DoNothing),
+        base::Bind(&IgnoreError));
+  }
+
+  request_handlers_.erase(p);
+  return true;
+}
+
+void ProtocolHandler::Connect(
+    org::chromium::WebServer::ProtocolHandlerProxy* proxy) {
+  proxy_ = proxy;
+  for (const auto& pair : request_handlers_) {
+    proxy_->AddRequestHandlerAsync(
+        pair.second.url,
+        pair.second.method,
+        server_->service_name_,
+        base::Bind(&ProtocolHandler::AddHandlerSuccess,
+                   weak_ptr_factory_.GetWeakPtr(),
+                   pair.first),
+        base::Bind(&ProtocolHandler::AddHandlerError,
+                   weak_ptr_factory_.GetWeakPtr(),
+                   pair.first));
+  }
+}
+
+void ProtocolHandler::Disconnect() {
+  proxy_ = nullptr;
+  remote_handler_id_map_.clear();
+}
+
+void ProtocolHandler::AddHandlerSuccess(int handler_id,
+                                        const std::string& remote_handler_id) {
+  auto p = request_handlers_.find(handler_id);
+  CHECK(p != request_handlers_.end());
+  p->second.remote_handler_id = remote_handler_id;
+
+  remote_handler_id_map_.emplace(remote_handler_id, handler_id);
+}
+
+void ProtocolHandler::AddHandlerError(int handler_id, chromeos::Error* error) {
+  // Nothing to do at the moment.
+}
+
+bool ProtocolHandler::ProcessRequest(const std::string& remote_handler_id,
+                                     const std::string& request_id,
+                                     std::unique_ptr<Request> request,
+                                     chromeos::ErrorPtr* error) {
+  auto id_iter = remote_handler_id_map_.find(remote_handler_id);
+  if (id_iter == remote_handler_id_map_.end()) {
+    chromeos::Error::AddToPrintf(error, FROM_HERE,
+                                 chromeos::errors::dbus::kDomain,
+                                 DBUS_ERROR_FAILED,
+                                 "Unknown request handler '%s'",
+                                 remote_handler_id.c_str());
+    return false;
+  }
+  auto handler_iter = request_handlers_.find(id_iter->second);
+  if (handler_iter == request_handlers_.end()) {
+    chromeos::Error::AddToPrintf(error, FROM_HERE,
+                                 chromeos::errors::dbus::kDomain,
+                                 DBUS_ERROR_FAILED,
+                                 "Handler # %d is no longer available",
+                                 id_iter->second);
+    return false;
+  }
+  handler_iter->second.handler->HandleRequest(
+      scoped_ptr<Request>(request.release()),
+      scoped_ptr<Response>(new Response{this, request_id}));
+  return true;
+}
+
+void ProtocolHandler::CompleteRequest(
+    const std::string& request_id,
+    int status_code,
+    const std::multimap<std::string, std::string>& headers,
+    const std::vector<uint8_t>& data) {
+  if (!proxy_) {
+    LOG(WARNING) << "Completing a request after the handler proxy is removed";
+    return;
+  }
+
+  std::vector<std::tuple<std::string, std::string>> header_list;
+  header_list.reserve(headers.size());
+  for (const auto& pair : headers)
+    header_list.emplace_back(pair.first, pair.second);
+
+  proxy_->CompleteRequestAsync(request_id, status_code, header_list, data,
+                               base::Bind(&base::DoNothing),
+                               base::Bind([](chromeos::Error*) {}));
+}
+
+void ProtocolHandler::GetFileData(
+    const std::string& request_id,
+    int file_id,
+    const base::Callback<void(const std::vector<uint8_t>&)>& success_callback,
+    const base::Callback<void(chromeos::Error*)>& error_callback) {
+  CHECK(proxy_);
+  proxy_->GetRequestFileDataAsync(
+      request_id, file_id, success_callback, error_callback);
+}
+
+
+}  // namespace libwebserv
diff --git a/libwebserv/protocol_handler.h b/libwebserv/protocol_handler.h
new file mode 100644
index 0000000..9ba7d11
--- /dev/null
+++ b/libwebserv/protocol_handler.h
@@ -0,0 +1,187 @@
+// Copyright 2015 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef WEBSERVER_LIBWEBSERV_PROTOCOL_HANDLER_H_
+#define WEBSERVER_LIBWEBSERV_PROTOCOL_HANDLER_H_
+
+#include <map>
+#include <memory>
+#include <string>
+#include <vector>
+
+#include <base/callback_forward.h>
+#include <base/macros.h>
+#include <base/memory/weak_ptr.h>
+#include <chromeos/errors/error.h>
+#include <chromeos/secure_blob.h>
+
+#include <libwebserv/export.h>
+#include <libwebserv/request_handler_interface.h>
+
+namespace org {
+namespace chromium {
+namespace WebServer {
+
+class ProtocolHandlerProxy;
+
+}  // namespace WebServer
+}  // namespace chromium
+}  // namespace org
+
+namespace libwebserv {
+
+class Server;
+class Request;
+
+// Wrapper around a protocol handler (e.g. HTTP or HTTPs).
+// ProtocolHandler allows consumers to add request handlers on a given protocol.
+// When the ProtocolHandler is connected, allows users to read port and protocol
+// information.
+class LIBWEBSERV_EXPORT ProtocolHandler final {
+ public:
+  explicit ProtocolHandler(const std::string& id, Server* server);
+  ~ProtocolHandler();
+
+  // Returns true if the protocol handler object is connected to the web server
+  // daemon's proxy object and is capable of processing incoming requests.
+  bool IsConnected() const { return proxy_ != nullptr; }
+
+  // Handler's unique ID. This is generally a GUID string, except for the
+  // default HTTP and HTTPS handlers which have IDs of "http" and "https"
+  // respectively.
+  std::string GetID() const;
+
+  // Returns the port the handler is bound to.
+  // ATTENTION: The handler must be connected to the web server before this
+  // method can be called.
+  uint16_t GetPort() const;
+
+  // Returns the transport protocol that is served by this handler.
+  // Can be either "http" or "https".
+  // ATTENTION: The handler must be connected to the web server before this
+  // method can be called.
+  std::string GetProtocol() const;
+
+  // Returns a SHA-256 fingerprint of HTTPS certificate used. Returns an empty
+  // byte buffer if this handler does not serve the HTTPS protocol.
+  // ATTENTION: The handler must be connected to the web server before this
+  // method can be called.
+  chromeos::Blob GetCertificateFingerprint() const;
+
+  // Adds a request handler for given |url|. If the |url| ends with a '/', this
+  // makes the handler respond to any URL beneath this path.
+  // Note that it is not possible to add a specific handler just for the root
+  // path "/". Doing so means "respond to any URL".
+  // |method| is optional request method verb, such as "GET" or "POST".
+  // If |method| is empty, the handler responds to any request verb.
+  // If there are more than one handler for a given request, the most specific
+  // match is chosen. For example, if there are the following handlers provided:
+  //    - A["/foo/",  ""]
+  //    - B["/foo/bar", "GET"]
+  //    - C["/foo/bar", ""]
+  // Here is what handlers are called when making certain requests:
+  //    - GET("/foo/bar")   => B[]
+  //    - POST("/foo/bar")  => C[]
+  //    - PUT("/foo/bar")   => C[]
+  //    - GET("/foo/baz")   => A[]
+  //    - GET("/foo")       => 404 Not Found
+  // This functions returns a handler ID which can be used later to remove
+  // the handler.
+  //
+  // The handler registration information is stored inside ProtocolHandler and
+  // is used to register the handlers with the web server daemon when it becomes
+  // available. This also happens when the web server goes away and then comes
+  // back (e.g. restarted). So, there is no need to re-register the handlers
+  // once the web server process is restarted.
+  int AddHandler(const std::string& url,
+                 const std::string& method,
+                 std::unique_ptr<RequestHandlerInterface> handler);
+
+  // Similar to AddHandler() above but the handler is just a callback function.
+  int AddHandlerCallback(
+      const std::string& url,
+      const std::string& method,
+      const base::Callback<RequestHandlerInterface::HandlerSignature>&
+          handler_callback);
+
+  // Removes the handler with the specified |handler_id|.
+  // Returns false if the handler with the given ID is not found.
+  bool RemoveHandler(int handler_id);
+
+  static const char kHttp[];
+  static const char kHttps[];
+
+ private:
+  friend class FileInfo;
+  friend class Server;
+  friend class Response;
+
+  struct LIBWEBSERV_PRIVATE HandlerMapEntry {
+    std::string url;
+    std::string method;
+    std::string remote_handler_id;
+    std::unique_ptr<RequestHandlerInterface> handler;
+  };
+
+  // Called by the Server class when the D-Bus proxy object gets connected
+  // to the web server daemon.
+
+  LIBWEBSERV_PRIVATE void Connect(
+      org::chromium::WebServer::ProtocolHandlerProxy* proxy);
+  // Called by the Server class when the D-Bus proxy object gets disconnected
+  // from the web server daemon.
+  LIBWEBSERV_PRIVATE void Disconnect();
+
+  // Asynchronous callbacks to handle successful or failed request handler
+  // registration over D-Bus.
+  LIBWEBSERV_PRIVATE void AddHandlerSuccess(
+      int handler_id, const std::string& remote_handler_id);
+  LIBWEBSERV_PRIVATE void AddHandlerError(int handler_id,
+                                          chromeos::Error* error);
+
+  // Called by Server when an incoming request is dispatched.
+  LIBWEBSERV_PRIVATE bool ProcessRequest(const std::string& remote_handler_id,
+                                         const std::string& request_id,
+                                         std::unique_ptr<Request> request,
+                                         chromeos::ErrorPtr* error);
+
+  // Called by Response object to finish the request and send response data.
+  LIBWEBSERV_PRIVATE void CompleteRequest(
+      const std::string& request_id,
+      int status_code,
+      const std::multimap<std::string, std::string>& headers,
+      const std::vector<uint8_t>& data);
+
+  // Makes a call to the (remote) web server request handler over D-Bus to
+  // obtain the file content of uploaded file (identified by |file_id|) during
+  // request with |request_id|.
+  LIBWEBSERV_PRIVATE void GetFileData(
+    const std::string& request_id,
+    int file_id,
+    const base::Callback<void(const std::vector<uint8_t>&)>& success_callback,
+    const base::Callback<void(chromeos::Error*)>& error_callback);
+
+  // Protocol Handler unique ID.
+  std::string id_;
+  // Back reference to the server object.
+  Server* server_{nullptr};
+  // Handler data map. The key is the client-facing request handler ID returned
+  // by AddHandler() when registering the handler.
+  std::map<int, HandlerMapEntry> request_handlers_;
+  // Map of remote handler IDs (GUID strings) to client-facing request handler
+  // IDs (int) which are returned by AddHandler() and used as a key in
+  // |request_handlers_|.
+  std::map<std::string, int> remote_handler_id_map_;
+  // The counter to generate new handler IDs.
+  int last_handler_id_{0};
+  // Remove D-Bus proxy for the server protocol handler object.
+  org::chromium::WebServer::ProtocolHandlerProxy* proxy_{nullptr};
+
+  base::WeakPtrFactory<ProtocolHandler> weak_ptr_factory_{this};
+  DISALLOW_COPY_AND_ASSIGN(ProtocolHandler);
+};
+
+}  // namespace libwebserv
+
+#endif  // WEBSERVER_LIBWEBSERV_PROTOCOL_HANDLER_H_
diff --git a/libwebserv/request.cc b/libwebserv/request.cc
index 37ea1c1..b51aa94 100644
--- a/libwebserv/request.cc
+++ b/libwebserv/request.cc
@@ -4,86 +4,49 @@
 
 #include <libwebserv/request.h>
 
-#include <libwebserv/connection.h>
+#include <base/callback.h>
+#include <chromeos/http/http_utils.h>
+
+#include <libwebserv/protocol_handler.h>
 
 namespace libwebserv {
 
-FileInfo::FileInfo(const std::string& file_name,
+FileInfo::FileInfo(ProtocolHandler* handler,
+                   int file_id,
+                   const std::string& request_id,
+                   const std::string& file_name,
                    const std::string& content_type,
                    const std::string& transfer_encoding)
-    : file_name_(file_name),
+    : handler_{handler},
+      file_id_{file_id},
+      request_id_{request_id},
+      file_name_(file_name),
       content_type_(content_type),
       transfer_encoding_(transfer_encoding) {
 }
 
-const std::vector<uint8_t>& FileInfo::GetData() const {
-  return data_;
+void FileInfo::GetData(
+    const base::Callback<void(const std::vector<uint8_t>&)>& success_callback,
+    const base::Callback<void(chromeos::Error*)>& error_callback) {
+  handler_->GetFileData(request_id_,
+                        file_id_,
+                        success_callback,
+                        error_callback);
 }
 
-Request::Request(const std::string& url, const std::string& method)
-    : url_{url}, method_{method} {
+Request::Request(ProtocolHandler* handler,
+                 const std::string& url,
+                 const std::string& method)
+    : handler_{handler}, url_{url}, method_{method} {
 }
 
 Request::~Request() {
 }
 
-scoped_ptr<Request> Request::Create(const std::string& url,
-                                    const std::string& method) {
-  // Can't use make_shared here since Request::Request is private.
-  return scoped_ptr<Request>(new Request(url, method));
-}
-
 const std::vector<uint8_t>& Request::GetData() const {
   return raw_data_;
 }
 
-bool Request::AddRawRequestData(const void* data, size_t size) {
-  const uint8_t* byte_data_ = static_cast<const uint8_t*>(data);
-  raw_data_.insert(raw_data_.end(), byte_data_, byte_data_ + size);
-  return true;
-}
-
-bool Request::AddPostFieldData(const char* key,
-                               const char* filename,
-                               const char* content_type,
-                               const char* transfer_encoding,
-                               const char* data,
-                               size_t size) {
-  if (filename) {
-    std::unique_ptr<FileInfo> file_info{
-        new FileInfo{filename, content_type ? content_type : "",
-                     transfer_encoding ? transfer_encoding : ""}};
-    file_info->data_.assign(data, data + size);
-    file_info_.emplace(key, std::move(file_info));
-    last_posted_data_was_file_ = true;
-    return true;
-  }
-  std::string value{data, size};
-  post_data_.emplace(key, value);
-  last_posted_data_was_file_ = false;
-  return true;
-}
-
-bool Request::AppendPostFieldData(const char* key,
-                                  const char* data,
-                                  size_t size) {
-  if (last_posted_data_was_file_) {
-    auto file_pair = file_info_.equal_range(key);
-    if (file_pair.first == file_info_.end())
-      return false;
-    FileInfo* file_info = file_pair.second->second.get();
-    file_info->data_.insert(file_info->data_.end(), data, data + size);
-    return true;
-  }
-
-  auto pair = post_data_.equal_range(key);
-  if (pair.first == post_data_.end())
-    return false;
-  --pair.second;  // Get the last form field with this name/key.
-  pair.second->second.append(data, size);
-  return true;
-}
-
 std::vector<PairOfStrings> Request::GetFormData() const {
   auto data = GetFormDataGet();
   auto post_data = GetFormDataPost();
@@ -162,30 +125,19 @@
 
 std::vector<std::string> Request::GetHeader(const std::string& name) const {
   std::vector<std::string> data;
-  auto pair = headers_.equal_range(GetCanonicalHeaderName(name));
-  while (pair.first != pair.second) {
-    data.push_back(pair.first->second);
-    ++pair.first;
+  auto range =
+      headers_.equal_range(chromeos::http::GetCanonicalHeaderName(name));
+  while (range.first != range.second) {
+    data.push_back(range.first->second);
+    ++range.first;
   }
   return data;
 }
 
-std::string Request::GetCanonicalHeaderName(const std::string& name) {
-  std::string canonical_name = name;
-  bool word_begin = true;
-  for (char& c : canonical_name) {
-    if (c == '-') {
-      word_begin = true;
-    } else {
-      if (word_begin) {
-        c = toupper(c);
-      } else {
-        c = tolower(c);
-      }
-      word_begin = false;
-    }
-  }
-  return canonical_name;
+std::string Request::GetFirstHeader(const std::string& name) const {
+  auto p = headers_.find(chromeos::http::GetCanonicalHeaderName(name));
+  return (p != headers_.end()) ? p->second : std::string{};
 }
 
+
 }  // namespace libwebserv
diff --git a/libwebserv/request.h b/libwebserv/request.h
index 6899b3d..f75622b 100644
--- a/libwebserv/request.h
+++ b/libwebserv/request.h
@@ -11,36 +11,50 @@
 #include <utility>
 #include <vector>
 
+#include <base/callback_forward.h>
 #include <base/macros.h>
 #include <base/memory/ref_counted.h>
 #include <base/memory/scoped_ptr.h>
+#include <chromeos/errors/error.h>
 #include <libwebserv/export.h>
 
 struct MHD_Connection;
 
 namespace libwebserv {
 
-class Connection;
+class ProtocolHandler;
+
 using PairOfStrings = std::pair<std::string, std::string>;
 
+// This class represents the file information about a file uploaded via
+// POST request using multipart/form-data request.
 class LIBWEBSERV_EXPORT FileInfo final {
  public:
-  FileInfo(const std::string& file_name,
-           const std::string& content_type,
-           const std::string& transfer_encoding);
-
-  const std::vector<uint8_t>& GetData() const;
   const std::string& GetFileName() const { return file_name_; }
   const std::string& GetContentType() const { return content_type_; }
   const std::string& GetTransferEncoding() const { return transfer_encoding_; }
+  void GetData(
+      const base::Callback<void(const std::vector<uint8_t>&)>& success_callback,
+      const base::Callback<void(chromeos::Error*)>& error_callback);
 
  private:
+  friend class Server;
+
+  LIBWEBSERV_PRIVATE FileInfo(ProtocolHandler* handler,
+                              int file_id,
+                              const std::string& request_id,
+                              const std::string& file_name,
+                              const std::string& content_type,
+                              const std::string& transfer_encoding);
+
+  ProtocolHandler* handler_{nullptr};
+  int file_id_{0};
+  std::string request_id_;
   std::string file_name_;
   std::string content_type_;
   std::string transfer_encoding_;
   std::vector<uint8_t> data_;
 
-  friend class Request;
   DISALLOW_COPY_AND_ASSIGN(FileInfo);
 };
 
@@ -49,10 +63,6 @@
  public:
   ~Request();
 
-  // Factory constructor method.
-  static scoped_ptr<Request> Create(const std::string& url,
-                                    const std::string& method);
-
   // Gets the request body data stream. Note that the stream is available
   // only for requests that provided data and if this data is not already
   // pre-parsed by the server (e.g. "application/x-www-form-urlencoded" and
@@ -100,32 +110,22 @@
   // Returns a list of key-value pairs for all the request headers.
   std::vector<PairOfStrings> GetHeaders() const;
 
-  // Returns the value(s) of a request head of given |name|.
+  // Returns the value(s) of a request header of given |name|.
   std::vector<std::string> GetHeader(const std::string& name) const;
 
+  // Returns the value of a request header of given |name|. If there are more
+  // than one header with this name, the value of the first header is returned.
+  // An empty string is returned if the header does not exist in the request.
+  std::string GetFirstHeader(const std::string& name) const;
+
  private:
-  LIBWEBSERV_PRIVATE Request(const std::string& url, const std::string& method);
+  friend class Server;
 
-  // Helper methods for processing request data coming from the raw HTTP
-  // connection.
-  // These methods parse the request headers and data so they can be accessed
-  // by request handlers later.
-  LIBWEBSERV_PRIVATE bool AddRawRequestData(const void* data, size_t size);
-  LIBWEBSERV_PRIVATE bool AddPostFieldData(const char* key,
-                                           const char* filename,
-                                           const char* content_type,
-                                           const char* transfer_encoding,
-                                           const char* data,
-                                           size_t size);
-  LIBWEBSERV_PRIVATE bool AppendPostFieldData(const char* key,
-                                              const char* data,
-                                              size_t size);
-  // Converts a request header name to canonical form (lowercase with uppercase
-  // first letter and each letter after a hyphen ('-')).
-  // "content-TYPE" will be converted to "Content-Type".
-  LIBWEBSERV_PRIVATE static std::string GetCanonicalHeaderName(
-      const std::string& name);
+  LIBWEBSERV_PRIVATE Request(ProtocolHandler* handler,
+                             const std::string& url,
+                             const std::string& method);
 
+  ProtocolHandler* handler_{nullptr};
   std::string url_;
   std::string method_;
   std::vector<uint8_t> raw_data_;
@@ -136,8 +136,6 @@
   std::multimap<std::string, std::unique_ptr<FileInfo>> file_info_;
   std::multimap<std::string, std::string> headers_;
 
-  friend class Connection;
-  friend class RequestHelper;
   DISALLOW_COPY_AND_ASSIGN(Request);
 };
 
diff --git a/libwebserv/response.cc b/libwebserv/response.cc
index c54747f..fc46e87 100644
--- a/libwebserv/response.cc
+++ b/libwebserv/response.cc
@@ -12,13 +12,12 @@
 #include <chromeos/http/http_request.h>
 #include <chromeos/mime_utils.h>
 #include <chromeos/strings/string_utils.h>
-#include <libwebserv/connection.h>
-#include <microhttpd.h>
+#include <libwebserv/protocol_handler.h>
 
 namespace libwebserv {
 
-Response::Response(const scoped_refptr<Connection>& connection)
-    : connection_(connection) {
+Response::Response(ProtocolHandler* handler, const std::string& request_id)
+    : handler_{handler}, request_id_{request_id} {
 }
 
 Response::~Response() {
@@ -28,11 +27,6 @@
   }
 }
 
-scoped_ptr<Response> Response::Create(
-    const scoped_refptr<Connection>& connection) {
-  return scoped_ptr<Response>(new Response(connection));
-}
-
 void Response::AddHeader(const std::string& header_name,
                          const std::string& value) {
   headers_.emplace(header_name, value);
@@ -99,12 +93,7 @@
 void Response::SendResponse() {
   CHECK(!reply_sent_) << "Response already sent";
   reply_sent_ = true;
-  CHECK(connection_->state_ == Connection::State::kRequestSent)
-      << "Unexpected connection state";
-  connection_->response_status_code_ = status_code_;
-  connection_->response_data_ = std::move(data_);
-  connection_->response_headers_ = std::move(headers_);
-  connection_->state_ = Connection::State::kResponseReceived;
+  handler_->CompleteRequest(request_id_, status_code_, headers_, data_);
 }
 
 }  // namespace libwebserv
diff --git a/libwebserv/response.h b/libwebserv/response.h
index 05465e3..616264d 100644
--- a/libwebserv/response.h
+++ b/libwebserv/response.h
@@ -12,31 +12,22 @@
 #include <vector>
 
 #include <base/macros.h>
-#include <base/memory/ref_counted.h>
-#include <base/memory/scoped_ptr.h>
 #include <libwebserv/export.h>
 
 namespace base {
 class Value;
 }  // namespace base
 
-struct MHD_Connection;
-
 namespace libwebserv {
 
-class Connection;
+class ProtocolHandler;
 
 // Response class is a proxy for HTTP response used by the request handler
 // to provide response HTTP headers and data.
-class LIBWEBSERV_EXPORT Response
-    : public std::enable_shared_from_this<Response> {
+class LIBWEBSERV_EXPORT Response final {
  public:
   ~Response();
 
-  // Factory constructor method.
-  static scoped_ptr<Response> Create(
-      const scoped_refptr<Connection>& connection);
-
   // Adds a single HTTP response header to the response.
   void AddHeader(const std::string& header_name, const std::string& value);
 
@@ -76,19 +67,20 @@
   void ReplyWithErrorNotFound();
 
  private:
-  LIBWEBSERV_PRIVATE explicit Response(
-      const scoped_refptr<Connection>& connection);
+  friend class ProtocolHandler;
+
+  LIBWEBSERV_PRIVATE Response(ProtocolHandler* handler,
+                              const std::string& request_id);
 
   LIBWEBSERV_PRIVATE void SendResponse();
 
-  scoped_refptr<Connection> connection_;
+  ProtocolHandler* handler_{nullptr};
+  std::string request_id_;
   int status_code_{0};
   std::vector<uint8_t> data_;
   std::multimap<std::string, std::string> headers_;
   bool reply_sent_{false};
 
-  friend class Connection;
-  friend class ResponseHelper;
   DISALLOW_COPY_AND_ASSIGN(Response);
 };
 
diff --git a/libwebserv/server.cc b/libwebserv/server.cc
index 196f178..2bf7c7d 100644
--- a/libwebserv/server.cc
+++ b/libwebserv/server.cc
@@ -4,230 +4,201 @@
 
 #include <libwebserv/server.h>
 
-#include <limits>
+#include <tuple>
 #include <vector>
 
-#include <base/logging.h>
-#include <base/message_loop/message_loop_proxy.h>
-#include <libwebserv/connection.h>
+#include <libwebserv/protocol_handler.h>
 #include <libwebserv/request.h>
-#include <libwebserv/request_handler_callback.h>
-#include <libwebserv/request_handler_interface.h>
-#include <libwebserv/response.h>
-#include <microhttpd.h>
+
+#include "libwebserv/org.chromium.WebServer.RequestHandler.h"
+#include "webservd/dbus-proxies.h"
 
 namespace libwebserv {
 
-namespace {
-// Simple static request handler that just returns "404 Not Found" error.
-class PageNotFoundHandler : public RequestHandlerInterface {
+class Server::RequestHandler final
+    : public org::chromium::WebServer::RequestHandlerInterface {
  public:
-  void HandleRequest(scoped_ptr<Request> request,
-                     scoped_ptr<Response> response) override {
-    response->ReplyWithErrorNotFound();
-  }
+  explicit RequestHandler(Server* server) : server_{server} {}
+  bool ProcessRequest(
+      chromeos::ErrorPtr* error,
+      const std::tuple<std::string, std::string, std::string, std::string,
+                       std::string>& in_request_info,
+      const std::vector<std::tuple<std::string, std::string>>& in_headers,
+      const std::vector<std::tuple<bool, std::string, std::string>>& in_params,
+      const std::vector<std::tuple<int32_t, std::string, std::string,
+                                   std::string, std::string>>& in_files,
+      const std::vector<uint8_t>& in_body) override;
+
+ private:
+  Server* server_{nullptr};
+  DISALLOW_COPY_AND_ASSIGN(RequestHandler);
 };
 
-}  // anonymous namespace
-
-// Helper class to provide static callback methods to microhttpd library,
-// with the ability to access private methods of Server class.
-class ServerHelper {
- public:
-  static int ConnectionHandler(void *cls,
-                               MHD_Connection* connection,
-                               const char* url,
-                               const char* method,
-                               const char* version,
-                               const char* upload_data,
-                               size_t* upload_data_size,
-                               void** con_cls) {
-    Server* server = reinterpret_cast<Server*>(cls);
-    if (nullptr == *con_cls) {
-      RequestHandlerInterface* handler = server->FindHandler(url, method);
-      if (!handler)
-        return MHD_NO;
-
-      auto server_connection =
-          Connection::Create(server, url, method, connection, handler);
-      if (!server_connection || !server_connection->BeginRequestData())
-        return MHD_NO;
-
-      *con_cls = server_connection.get();
-      server_connection->AddRef();
-    } else {
-      Connection* connection = reinterpret_cast<Connection*>(*con_cls);
-      if (*upload_data_size) {
-        if (!connection->AddRequestData(upload_data, *upload_data_size))
-          return MHD_NO;
-        *upload_data_size = 0;
-      } else {
-        connection->EndRequestData();
-      }
-    }
-    return MHD_YES;
+bool Server::RequestHandler::ProcessRequest(
+    chromeos::ErrorPtr* error,
+    const std::tuple<std::string, std::string, std::string, std::string,
+                     std::string>& in_request_info,
+    const std::vector<std::tuple<std::string, std::string>>& in_headers,
+    const std::vector<std::tuple<bool, std::string, std::string>>& in_params,
+    const std::vector<std::tuple<int32_t, std::string, std::string,
+                                 std::string, std::string>>& in_files,
+    const std::vector<uint8_t>& in_body) {
+  std::string protocol_handler_id = std::get<0>(in_request_info);
+  std::string request_handler_id = std::get<1>(in_request_info);
+  std::string request_id = std::get<2>(in_request_info);
+  std::string url = std::get<3>(in_request_info);
+  std::string method = std::get<4>(in_request_info);
+  ProtocolHandler* protocol_handler =
+      server_->GetProtocolHandler(protocol_handler_id);
+  if (!protocol_handler) {
+    chromeos::Error::AddToPrintf(error, FROM_HERE,
+                                 chromeos::errors::dbus::kDomain,
+                                 DBUS_ERROR_FAILED,
+                                 "Unknown protocol handler '%s'",
+                                 protocol_handler_id.c_str());
+    return false;
+  }
+  std::unique_ptr<Request> request{new Request{protocol_handler, url, method}};
+  // Convert request data into format required by the Request object.
+  for (const auto& tuple : in_params) {
+    if (std::get<0>(tuple))
+      request->post_data_.emplace(std::get<1>(tuple), std::get<2>(tuple));
+    else
+      request->get_data_.emplace(std::get<1>(tuple), std::get<2>(tuple));
   }
 
-  static void RequestCompleted(void* cls,
-                               MHD_Connection* connection,
-                               void** con_cls,
-                               MHD_RequestTerminationCode toe) {
-    reinterpret_cast<Connection*>(*con_cls)->Release();
-    *con_cls = nullptr;
-  }
-};
+  for (const auto& tuple : in_headers)
+    request->headers_.emplace(std::get<0>(tuple), std::get<1>(tuple));
 
-Server::Server() {}
+  for (const auto& tuple : in_files) {
+    request->file_info_.emplace(
+        std::get<1>(tuple),  // field_name
+        std::unique_ptr<FileInfo>{new FileInfo{
+            protocol_handler,
+            std::get<0>(tuple),     // file_id
+            request_id,
+            std::get<2>(tuple),     // file_name
+            std::get<3>(tuple),     // content_type
+            std::get<4>(tuple)}});  // transfer_encoding
+  }
+
+  request->raw_data_ = in_body;
+
+  return protocol_handler->ProcessRequest(request_handler_id,
+                                          request_id,
+                                          std::move(request),
+                                          error);
+}
+
+Server::Server()
+    : request_handler_{new RequestHandler{this}},
+      dbus_adaptor_{new org::chromium::WebServer::RequestHandlerAdaptor{
+          request_handler_.get()}} {}
 
 Server::~Server() {
-  Stop();
 }
 
-bool Server::Start(uint16_t port) {
-  return StartWithTLS(port, chromeos::SecureBlob{}, chromeos::Blob{});
+void Server::Connect(
+    const scoped_refptr<dbus::Bus>& bus,
+    const std::string& service_name,
+    const chromeos::dbus_utils::AsyncEventSequencer::CompletionAction& cb,
+    const base::Closure& on_server_online,
+    const base::Closure& on_server_offline) {
+  service_name_ = service_name;
+  dbus_object_.reset(new chromeos::dbus_utils::DBusObject{
+      nullptr, bus, dbus_adaptor_->GetObjectPath()});
+  dbus_adaptor_->RegisterWithDBusObject(dbus_object_.get());
+  dbus_object_->RegisterAsync(cb);
+  on_server_online_ = on_server_online;
+  on_server_offline_ = on_server_offline;
+  AddProtocolHandler(std::unique_ptr<ProtocolHandler>{
+      new ProtocolHandler{ProtocolHandler::kHttp, this}});
+  AddProtocolHandler(std::unique_ptr<ProtocolHandler>{
+    new ProtocolHandler{ProtocolHandler::kHttps, this}});
+  object_manager_.reset(new org::chromium::WebServer::ObjectManagerProxy{bus});
+  object_manager_->SetServerAddedCallback(
+      base::Bind(&Server::Online, base::Unretained(this)));
+  object_manager_->SetServerRemovedCallback(
+      base::Bind(&Server::Offline, base::Unretained(this)));
+  object_manager_->SetProtocolHandlerAddedCallback(
+      base::Bind(&Server::ProtocolHandlerAdded, base::Unretained(this)));
+  object_manager_->SetProtocolHandlerRemovedCallback(
+      base::Bind(&Server::ProtocolHandlerRemoved, base::Unretained(this)));
 }
 
-bool Server::StartWithTLS(uint16_t port,
-                          const chromeos::SecureBlob& private_key,
-                          const chromeos::Blob& certificate) {
-  if (server_) {
-    LOG(ERROR) << "Web server is already running.";
-    return false;
+void Server::Disconnect() {
+  object_manager_.reset();
+  on_server_offline_.Reset();
+  on_server_online_.Reset();
+  dbus_object_.reset();
+  protocol_handlers_.clear();
+}
+
+void Server::Online(org::chromium::WebServer::ServerProxy* server) {
+  proxy_ = server;
+  if (!on_server_online_.is_null())
+    on_server_online_.Run();
+}
+
+void Server::Offline(const dbus::ObjectPath& object_path) {
+  if (!on_server_offline_.is_null())
+    on_server_offline_.Run();
+  proxy_ = nullptr;
+}
+
+void Server::ProtocolHandlerAdded(
+    org::chromium::WebServer::ProtocolHandlerProxy* handler) {
+  protocol_handler_id_map_.emplace(handler->GetObjectPath(), handler->id());
+  ProtocolHandler* registered_handler = GetProtocolHandler(handler->id());
+  if (registered_handler) {
+    registered_handler->Connect(handler);
+    if (!on_protocol_handler_connected_.is_null())
+      on_protocol_handler_connected_.Run(registered_handler);
+  }
+}
+
+void Server::ProtocolHandlerRemoved(const dbus::ObjectPath& object_path) {
+  auto p = protocol_handler_id_map_.find(object_path);
+  if (p == protocol_handler_id_map_.end())
+    return;
+
+  ProtocolHandler* registered_handler = GetProtocolHandler(p->second);
+  if (registered_handler) {
+    if (!on_protocol_handler_disconnected_.is_null())
+      on_protocol_handler_disconnected_.Run(registered_handler);
+    registered_handler->Disconnect();
   }
 
-  // Either both keys and certificate must be specified or both muse be omitted.
-  CHECK_EQ(private_key.empty(), certificate.empty());
-
-  const bool use_tls = !private_key.empty();
-
-  task_runner_ = base::MessageLoopProxy::current();
-
-  LOG(INFO) << "Starting " << (use_tls ? "HTTPS" : "HTTP")
-            << " Server on port: " << port;
-  auto callback_addr =
-      reinterpret_cast<intptr_t>(&ServerHelper::RequestCompleted);
-  uint32_t flags = MHD_USE_THREAD_PER_CONNECTION | MHD_USE_DEBUG;
-
-  std::vector<MHD_OptionItem> options{
-    {MHD_OPTION_CONNECTION_LIMIT, 10, nullptr},
-    {MHD_OPTION_CONNECTION_TIMEOUT, 60, nullptr},
-    {MHD_OPTION_NOTIFY_COMPLETED, callback_addr, nullptr},
-  };
-
-  // libmicrohttpd expects both the key and certificate to be a zero-terminated
-  // strings. Make sure they are terminated properly.
-  chromeos::SecureBlob private_key_copy = private_key;
-  chromeos::Blob certificate_copy = certificate;
-  if (use_tls) {
-    flags |= MHD_USE_SSL;
-    private_key_copy.push_back(0);
-    certificate_copy.push_back(0);
-    options.push_back(
-        MHD_OptionItem{MHD_OPTION_HTTPS_MEM_KEY, 0, private_key_copy.data()});
-    options.push_back(
-        MHD_OptionItem{MHD_OPTION_HTTPS_MEM_CERT, 0, certificate_copy.data()});
-  }
-
-  options.push_back(MHD_OptionItem{MHD_OPTION_END, 0, nullptr});
-
-  server_ = MHD_start_daemon(flags, port, nullptr, nullptr,
-                             &ServerHelper::ConnectionHandler, this,
-                             MHD_OPTION_ARRAY, options.data(), MHD_OPTION_END);
-  if (!server_) {
-    LOG(ERROR) << "Failed to start the web server on port " << port;
-    return false;
-  }
-  LOG(INFO) << "Server started";
-  return true;
+  protocol_handler_id_map_.erase(p);
 }
 
-bool Server::Stop() {
-  if (server_) {
-    LOG(INFO) << "Shutting down the web server...";
-    MHD_stop_daemon(server_);
-    server_ = nullptr;
-    LOG(INFO) << "Server shutdown complete";
-  }
-  return true;
+ProtocolHandler* Server::GetProtocolHandler(const std::string& id) const {
+  auto p = protocol_handlers_.find(id);
+  return (p != protocol_handlers_.end()) ? p->second.get() : nullptr;
 }
 
-int Server::AddHandler(const base::StringPiece& url,
-                       const base::StringPiece& method,
-                       std::unique_ptr<RequestHandlerInterface> handler) {
-  request_handlers_.emplace(++last_handler_id_,
-                            HandlerMapEntry{url.as_string(),
-                                            method.as_string(),
-                                            std::move(handler)});
-  return last_handler_id_;
+ProtocolHandler* Server::GetDefaultHttpHandler() const {
+  return GetProtocolHandler(ProtocolHandler::kHttp);
 }
 
-int Server::AddHandlerCallback(
-    const base::StringPiece& url,
-    const base::StringPiece& method,
-    const base::Callback<RequestHandlerInterface::HandlerSignature>&
-        handler_callback) {
-  std::unique_ptr<RequestHandlerInterface> handler{
-      new RequestHandlerCallback{handler_callback}};
-  return AddHandler(url, method, std::move(handler));
+ProtocolHandler* Server::GetDefaultHttpsHandler() const {
+  return GetProtocolHandler(ProtocolHandler::kHttps);
 }
 
-bool Server::RemoveHandler(int handler_id) {
-  return (request_handlers_.erase(handler_id) > 0);
+void Server::OnProtocolHandlerConnected(
+    const base::Callback<void(ProtocolHandler*)>& callback) {
+  on_protocol_handler_connected_ = callback;
 }
 
-int Server::GetHandlerId(const base::StringPiece& url,
-                         const base::StringPiece& method) const {
-  for (const auto& pair : request_handlers_) {
-    if (pair.second.url == url && pair.second.method == method)
-      return pair.first;
-  }
-  return 0;
+void Server::OnProtocolHandlerDisconnected(
+    const base::Callback<void(ProtocolHandler*)>& callback) {
+  on_protocol_handler_disconnected_ = callback;
 }
 
-RequestHandlerInterface* Server::FindHandler(
-    const base::StringPiece& url,
-    const base::StringPiece& method) const {
-  static PageNotFoundHandler page_not_found_handler;
-
-  size_t score = std::numeric_limits<size_t>::max();
-  RequestHandlerInterface* handler = nullptr;
-  for (const auto& pair : request_handlers_) {
-    std::string handler_url = pair.second.url;
-    bool url_match = (handler_url == url);
-    bool method_match = (pair.second.method == method);
-
-    // Try exact match first. If everything matches, we have our handler.
-    if (url_match && method_match)
-      return pair.second.handler.get();
-
-    // Calculate the current handler's similarity score. The lower the score
-    // the better the match is...
-    size_t current_score = 0;
-    if (!url_match && !handler_url.empty() && handler_url.back() == '/') {
-      if (url.starts_with(handler_url)) {
-        url_match = true;
-        // Use the difference in URL length as URL match quality proxy.
-        // The longer URL, the more specific (better) match is.
-        // Multiply by 2 to allow for extra score point for matching the method.
-        current_score = (url.size() - handler_url.size()) * 2;
-      }
-    }
-
-    if (!method_match && pair.second.method.empty()) {
-      // If the handler didn't specify the method it handles, this means
-      // it doesn't care. However this isn't the exact match, so bump
-      // the score up one point.
-      method_match = true;
-      ++current_score;
-    }
-
-    if (url_match && method_match && current_score < score) {
-      score = current_score;
-      handler = pair.second.handler.get();
-    }
-  }
-
-  return handler ? handler : &page_not_found_handler;
+void Server::AddProtocolHandler(std::unique_ptr<ProtocolHandler> handler) {
+  // Make sure a handler with this ID isn't already registered.
+  CHECK(protocol_handlers_.find(handler->GetID()) == protocol_handlers_.end());
+  protocol_handlers_.emplace(handler->GetID(), std::move(handler));
 }
 
 }  // namespace libwebserv
diff --git a/libwebserv/server.h b/libwebserv/server.h
index 6221115..ba133df 100644
--- a/libwebserv/server.h
+++ b/libwebserv/server.h
@@ -9,110 +9,135 @@
 #include <memory>
 #include <string>
 
-#include <base/callback_forward.h>
 #include <base/macros.h>
-#include <base/memory/ref_counted.h>
-#include <base/strings/string_piece.h>
-#include <chromeos/secure_blob.h>
+#include <dbus/bus.h>
+#include <chromeos/dbus/async_event_sequencer.h>
+#include <chromeos/dbus/dbus_object.h>
 #include <libwebserv/export.h>
 #include <libwebserv/request_handler_interface.h>
 
-struct MHD_Daemon;
+namespace org {
+namespace chromium {
+namespace WebServer {
 
-namespace base {
-class TaskRunner;
-}  // namespace base
+class ObjectManagerProxy;
+class ProtocolHandlerProxy;
+class RequestHandlerAdaptor;
+class ServerProxy;
+
+}  // namespace WebServer
+}  // namespace chromium
+}  // namespace org
 
 namespace libwebserv {
 
 // Top-level wrapper class around HTTP server and provides an interface to
-// the web server. It allows the users to start the server and
-// register request handlers.
+// the web server.
 class LIBWEBSERV_EXPORT Server final {
  public:
   Server();
   ~Server();
 
-  // Starts the server and makes it listen to HTTP requests on the given port.
-  //
-  // Note that a valid message loop must exist before calling Start.
-  bool Start(uint16_t port);
+  // Establish a connection to the system webserver.
+  // |service_name| is the well known D-Bus name of the client's process, used
+  // to expose a callback D-Bus object the web server calls back with incoming
+  // requests.
+  // |on_server_online| and |on_server_offline| will notify the caller when the
+  // server comes up and down.
+  // Note that we can Connect() even before the webserver attaches to D-Bus,
+  // and appropriate state will be built up when the webserver appears on D-Bus.
+  void Connect(
+      const scoped_refptr<dbus::Bus>& bus,
+      const std::string& service_name,
+      const chromeos::dbus_utils::AsyncEventSequencer::CompletionAction& cb,
+      const base::Closure& on_server_online,
+      const base::Closure& on_server_offline);
 
-  // Starts the server and makes it listen to HTTPS requests on the given port.
-  //
-  // Note that a valid message loop must exist before calling StartWithTLS.
-  bool StartWithTLS(uint16_t port,
-                    const chromeos::SecureBlob& private_key,
-                    const chromeos::Blob& certificate);
+  // Disconnects from the web server and removes the library interface from
+  // D-Bus.
+  void Disconnect();
 
-  // Stops the server.
-  bool Stop();
+  // A helper method that returns the default handler for "http".
+  ProtocolHandler* GetDefaultHttpHandler() const;
 
-  // Adds a request handler for given |url|. If the |url| ends with a '/', this
-  // makes the handler respond to any URL beneath this path.
-  // Note that it is not possible to add a specific handler just for the root
-  // path "/". Doing so means "respond to any URL".
-  // |method| is optional request method verb, such as "GET" or "POST".
-  // If |method| is empty, the handler responds to any request verb.
-  // If there are more than one handler for a given request, the most specific
-  // match is chosen. For example, if there are the following handlers provided:
-  //    - A["/foo/",  ""]
-  //    - B["/foo/bar", "GET"]
-  //    - C["/foo/bar", ""]
-  // Here is what handlers are called when making certain requests:
-  //    - GET("/foo/bar")   => B[]
-  //    - POST("/foo/bar")  => C[]
-  //    - PUT("/foo/bar")   => C[]
-  //    - GET("/foo/baz")   => A[]
-  //    - GET("/foo")       => 404 Not Found
-  // This functions returns a handler ID which can be used later to remove
-  // the handler.
-  int AddHandler(const base::StringPiece& url,
-                 const base::StringPiece& method,
-                 std::unique_ptr<RequestHandlerInterface> handler);
+  // A helper method that returns the default handler for "https".
+  ProtocolHandler* GetDefaultHttpsHandler() const;
 
-  // Similar to AddHandler() above but the handler is just a callback function.
-  int AddHandlerCallback(
-      const base::StringPiece& url,
-      const base::StringPiece& method,
-      const base::Callback<RequestHandlerInterface::HandlerSignature>&
-          handler_callback);
+  // Returns true if the web server daemon is connected to DBus and our
+  // connection to it has been established.
+  bool IsConnected() const { return proxy_ != nullptr; }
 
-  // Removes the handler with the specified |handler_id|.
-  // Returns false if the handler with the given ID is not found.
-  bool RemoveHandler(int handler_id);
+  // Set a user-callback to be invoked when a protocol handler is connect to the
+  // server daemon.  Multiple calls to this method will overwrite previously set
+  // callbacks.
+  void OnProtocolHandlerConnected(
+      const base::Callback<void(ProtocolHandler*)>& callback);
 
-  // Finds the handler ID given the exact match criteria. Note that using
-  // this function could cause unexpected side effects if there are more than
-  // one handler registered for given URL/Method parameters.
-  // It is better to remember the handler ID from AddHandler() method and use
-  // that ID to remove the handler, instead of looking the handler up using
-  // URL/Method.
-  int GetHandlerId(const base::StringPiece& url,
-                   const base::StringPiece& method) const;
-
-  // Finds a handler for given URL/Method. This method does the criteria
-  // matching and not exact match performed by GetHandlerId. This is the method
-  // used to look up the handler for incoming HTTP requests.
-  RequestHandlerInterface* FindHandler(
-      const base::StringPiece& url,
-      const base::StringPiece& method) const;
+  // Set a user-callback to be invoked when a protocol handler is disconnected
+  // from the server daemon (e.g. on shutdown).  Multiple calls to this method
+  // will overwrite previously set callbacks.
+  void OnProtocolHandlerDisconnected(
+      const base::Callback<void(ProtocolHandler*)>& callback);
 
  private:
-  MHD_Daemon* server_ = nullptr;
-  scoped_refptr<base::TaskRunner> task_runner_;
+  friend class ProtocolHandler;
+  class RequestHandler;
 
-  struct LIBWEBSERV_PRIVATE HandlerMapEntry {
-    std::string url;
-    std::string method;
-    std::unique_ptr<RequestHandlerInterface> handler;
-  };
+  // Returns an existing protocol handler by ID.  See documentation in
+  // ProtocolHandler about IDs and how they work with webservd.
+  LIBWEBSERV_PRIVATE ProtocolHandler* GetProtocolHandler(
+      const std::string& id) const;
 
-  std::map<int, HandlerMapEntry> request_handlers_;
-  int last_handler_id_{0};
+  // Handler invoked when a connection is established to web server daemon.
+  LIBWEBSERV_PRIVATE void Online(org::chromium::WebServer::ServerProxy* server);
 
-  friend class ServerHelper;
-  friend class Connection;
+  // Handler invoked when the web server daemon connection is dropped.
+  LIBWEBSERV_PRIVATE void Offline(const dbus::ObjectPath& object_path);
+
+  // Handler invoked when a new protocol handler D-Bus proxy object becomes
+  // available.
+  LIBWEBSERV_PRIVATE void ProtocolHandlerAdded(
+      org::chromium::WebServer::ProtocolHandlerProxy* handler);
+
+  // Handler invoked when a protocol handler D-Bus proxy object disappears.
+  LIBWEBSERV_PRIVATE void ProtocolHandlerRemoved(
+      const dbus::ObjectPath& object_path);
+
+  LIBWEBSERV_PRIVATE void AddProtocolHandler(
+      std::unique_ptr<ProtocolHandler> handler);
+
+  // Private implementation of D-Bus RequestHandlerInterface called by the web
+  // server daemon whenever a new request is available to be processed.
+  std::unique_ptr<RequestHandler> request_handler_;
+  // D-Bus object adaptor for RequestHandlerInterface.
+  std::unique_ptr<org::chromium::WebServer::RequestHandlerAdaptor>
+      dbus_adaptor_;
+  // D-Bus object to handler registration of RequestHandlerInterface.
+  std::unique_ptr<chromeos::dbus_utils::DBusObject> dbus_object_;
+
+  // A mapping of protocol handler IDs to the associated object.
+  // Handler IDs are either GUIDs or the two well-known handler IDs.
+  std::map<std::string, std::unique_ptr<ProtocolHandler>> protocol_handlers_;
+  // A map between D-Bus object path of protocol handler and remote protocol
+  // handler ID.
+  std::map<dbus::ObjectPath, std::string> protocol_handler_id_map_;
+
+  // User-specified callbacks for server and protocol handler life-time events.
+  base::Closure on_server_online_;
+  base::Closure on_server_offline_;
+  base::Callback<void(ProtocolHandler*)> on_protocol_handler_connected_;
+  base::Callback<void(ProtocolHandler*)> on_protocol_handler_disconnected_;
+
+  // D-Bus object manager proxy that receives notification of web server
+  // daemon's D-Bus object creation and destruction.
+  std::unique_ptr<org::chromium::WebServer::ObjectManagerProxy> object_manager_;
+
+  // D-Bus proxy for the web server main object.
+  org::chromium::WebServer::ServerProxy* proxy_{nullptr};
+
+  // D-Bus service name used by the daemon hosting this object.
+  std::string service_name_;
+
   DISALLOW_COPY_AND_ASSIGN(Server);
 };