webserver: Added support for any number of protocol handlers

Web server daemon can now be configured with any number of protocol
handlers (HTTP and HTTPS) on various TCP ports. Added corresponding
support for arbitrary protocol handlers.

Also added some helpful VLOG(1) trace messages for debugging
server<->client protocol handler connection handshake.

BUG=brillo:158
TEST=`FEATURES=test emerge-link webserver privetd`
     Manually testing on a device with custom config file.

Change-Id: I03a090dd995cf5e994cd232c94328e1d89d14a59
Reviewed-on: https://chromium-review.googlesource.com/250511
Trybot-Ready: Alex Vakulenko <avakulenko@chromium.org>
Tested-by: Alex Vakulenko <avakulenko@chromium.org>
Reviewed-by: Christopher Wiley <wiley@chromium.org>
Commit-Queue: Alex Vakulenko <avakulenko@chromium.org>
diff --git a/libwebserv/server.cc b/libwebserv/server.cc
index 2bf7c7d..4b8403e 100644
--- a/libwebserv/server.cc
+++ b/libwebserv/server.cc
@@ -111,10 +111,6 @@
   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)));
@@ -135,6 +131,7 @@
 }
 
 void Server::Online(org::chromium::WebServer::ServerProxy* server) {
+  VLOG(1) << "Web server is on-line.";
   proxy_ = server;
   if (!on_server_online_.is_null())
     on_server_online_.Run();
@@ -144,10 +141,14 @@
   if (!on_server_offline_.is_null())
     on_server_offline_.Run();
   proxy_ = nullptr;
+  VLOG(1) << "Web server is off-line.";
 }
 
 void Server::ProtocolHandlerAdded(
     org::chromium::WebServer::ProtocolHandlerProxy* handler) {
+  VLOG(1) << "Server-side protocol handler with ID '" << handler->id()
+          << "' is on-line.";
+
   protocol_handler_id_map_.emplace(handler->GetObjectPath(), handler->id());
   ProtocolHandler* registered_handler = GetProtocolHandler(handler->id());
   if (registered_handler) {
@@ -162,6 +163,9 @@
   if (p == protocol_handler_id_map_.end())
     return;
 
+  VLOG(1) << "Server-side protocol handler with ID '" << p->second
+          << "' is off-line.";
+
   ProtocolHandler* registered_handler = GetProtocolHandler(p->second);
   if (registered_handler) {
     if (!on_protocol_handler_disconnected_.is_null())
@@ -172,16 +176,23 @@
   protocol_handler_id_map_.erase(p);
 }
 
-ProtocolHandler* Server::GetProtocolHandler(const std::string& id) const {
+ProtocolHandler* Server::GetProtocolHandler(const std::string& id) {
   auto p = protocol_handlers_.find(id);
-  return (p != protocol_handlers_.end()) ? p->second.get() : nullptr;
+  if (p == protocol_handlers_.end()) {
+    VLOG(1) << "Creating a client-side instance of web server's protocol "
+            << "handler with ID '" << id << "'";
+    p = protocol_handlers_.emplace(
+        id,
+        std::unique_ptr<ProtocolHandler>{new ProtocolHandler{id, this}}).first;
+  }
+  return p->second.get();
 }
 
-ProtocolHandler* Server::GetDefaultHttpHandler() const {
+ProtocolHandler* Server::GetDefaultHttpHandler() {
   return GetProtocolHandler(ProtocolHandler::kHttp);
 }
 
-ProtocolHandler* Server::GetDefaultHttpsHandler() const {
+ProtocolHandler* Server::GetDefaultHttpsHandler() {
   return GetProtocolHandler(ProtocolHandler::kHttps);
 }
 
@@ -195,10 +206,4 @@
   on_protocol_handler_disconnected_ = callback;
 }
 
-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 ba133df..5e8f88a 100644
--- a/libwebserv/server.h
+++ b/libwebserv/server.h
@@ -58,10 +58,21 @@
   void Disconnect();
 
   // A helper method that returns the default handler for "http".
-  ProtocolHandler* GetDefaultHttpHandler() const;
+  ProtocolHandler* GetDefaultHttpHandler();
 
   // A helper method that returns the default handler for "https".
-  ProtocolHandler* GetDefaultHttpsHandler() const;
+  ProtocolHandler* GetDefaultHttpsHandler();
+
+  // Returns an existing protocol handler by ID.  If the handler with the
+  // requested |id| does not exist, a new one will be created.   See
+  // documentation in ProtocolHandler about IDs and how they work with
+  // webservd.
+  //
+  // The created handler is purely client side, and depends on the server
+  // being configured to open a corresponding handler with the given ID.
+  // Because clients and the server come up asynchronously, we allow clients
+  // to register anticipated handlers before server starts up.
+  ProtocolHandler* GetProtocolHandler(const std::string& id);
 
   // Returns true if the web server daemon is connected to DBus and our
   // connection to it has been established.
@@ -83,11 +94,6 @@
   friend class ProtocolHandler;
   class RequestHandler;
 
-  // 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;
-
   // Handler invoked when a connection is established to web server daemon.
   LIBWEBSERV_PRIVATE void Online(org::chromium::WebServer::ServerProxy* server);
 
@@ -103,9 +109,6 @@
   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_;