Implement http2 TODO

To support HTTP2 simultaneously on http and https connections, the HTTP
connection classes formerly took the socket as a template option,
allowing passing ssl::stream<tcp::socket> or simply tcp socket.  With
the addition of the multiple-sockets option, this would cause two copies
of the template to be instantiated, increasing both compile times and
binary size.

This commit applies the same logic to http2connection as was applied to
HTTPConnection, adding an http type parameter to the constructor, which
allows switching between adapter and adapter.next_level() on each read
or write operation.  In compiled code, this means that the connection
classes are only specialized once.

Tested:
When configured for one of each http and https socket and http2
curl --http2 http://<ip>/redfish/v1
succeeds
curl --http2 https://<ip>/redfish/v1 succeeds

Change-Id: I8f33796edd5874d5b93d10a3f253cfadd4f6d7a4
Signed-off-by: Ed Tanous <etanous@nvidia.com>
diff --git a/http/http2_connection.hpp b/http/http2_connection.hpp
index 9cc1194..99604f5 100644
--- a/http/http2_connection.hpp
+++ b/http/http2_connection.hpp
@@ -8,6 +8,7 @@
 #include "complete_response_fields.hpp"
 #include "forward_unauthorized.hpp"
 #include "http_body.hpp"
+#include "http_connect_types.hpp"
 #include "http_request.hpp"
 #include "http_response.hpp"
 #include "logging.hpp"
@@ -46,14 +47,6 @@
 namespace crow
 {
 
-template <typename>
-struct IsTls : std::false_type
-{};
-
-template <typename T>
-struct IsTls<boost::asio::ssl::stream<T>> : std::true_type
-{};
-
 struct Http2StreamData
 {
     std::shared_ptr<Request> req = std::make_shared<Request>();
@@ -70,10 +63,13 @@
     using self_type = HTTP2Connection<Adaptor, Handler>;
 
   public:
-    HTTP2Connection(Adaptor&& adaptorIn, Handler* handlerIn,
-                    std::function<std::string()>& getCachedDateStrF) :
-        adaptor(std::move(adaptorIn)), ngSession(initializeNghttp2Session()),
-        handler(handlerIn), getCachedDateStr(getCachedDateStrF)
+    HTTP2Connection(boost::asio::ssl::stream<Adaptor>&& adaptorIn,
+                    Handler* handlerIn,
+                    std::function<std::string()>& getCachedDateStrF,
+                    HttpType httpTypeIn) :
+        httpType(httpTypeIn), adaptor(std::move(adaptorIn)),
+        ngSession(initializeNghttp2Session()), handler(handlerIn),
+        getCachedDateStr(getCachedDateStrF)
     {}
 
     void start()
@@ -573,21 +569,24 @@
             return;
         }
         isWriting = true;
-        boost::asio::async_write(
-            adaptor, boost::asio::const_buffer(data.data(), data.size()),
-            std::bind_front(afterWriteBuffer, shared_from_this()));
+        if (httpType == HttpType::HTTPS)
+        {
+            boost::asio::async_write(
+                adaptor, boost::asio::const_buffer(data.data(), data.size()),
+                std::bind_front(afterWriteBuffer, shared_from_this()));
+        }
+        else if (httpType == HttpType::HTTP)
+        {
+            boost::asio::async_write(
+                adaptor.next_layer(),
+                boost::asio::const_buffer(data.data(), data.size()),
+                std::bind_front(afterWriteBuffer, shared_from_this()));
+        }
     }
 
     void close()
     {
-        if constexpr (IsTls<Adaptor>::value)
-        {
-            adaptor.next_layer().close();
-        }
-        else
-        {
-            adaptor.close();
-        }
+        adaptor.next_layer().close();
     }
 
     void afterDoRead(const std::shared_ptr<self_type>& /*self*/,
@@ -622,9 +621,19 @@
     void doRead()
     {
         BMCWEB_LOG_DEBUG("{} doRead", logPtr(this));
-        adaptor.async_read_some(
-            boost::asio::buffer(inBuffer),
-            std::bind_front(&self_type::afterDoRead, this, shared_from_this()));
+        if (httpType == HttpType::HTTPS)
+        {
+            adaptor.async_read_some(boost::asio::buffer(inBuffer),
+                                    std::bind_front(&self_type::afterDoRead,
+                                                    this, shared_from_this()));
+        }
+        else if (httpType == HttpType::HTTP)
+        {
+            adaptor.next_layer().async_read_some(
+                boost::asio::buffer(inBuffer),
+                std::bind_front(&self_type::afterDoRead, this,
+                                shared_from_this()));
+        }
     }
 
     // A mapping from http2 stream ID to Stream Data
@@ -632,7 +641,8 @@
 
     std::array<uint8_t, 8192> inBuffer{};
 
-    Adaptor adaptor;
+    HttpType httpType = HttpType::BOTH;
+    boost::asio::ssl::stream<Adaptor> adaptor;
     bool isWriting = false;
 
     nghttp2_session ngSession;
diff --git a/http/http_connection.hpp b/http/http_connection.hpp
index bfbe580..1c24c61 100644
--- a/http/http_connection.hpp
+++ b/http/http_connection.hpp
@@ -282,34 +282,15 @@
 
     void upgradeToHttp2()
     {
-        // TODO HTTP2Connection needs adaptor moved to a similar abstraction as
-        // HTTPConnection
-        if (httpType == HttpType::HTTP)
+        auto http2 = std::make_shared<HTTP2Connection<Adaptor, Handler>>(
+            std::move(adaptor), handler, getCachedDateStr, httpType);
+        if (http2settings.empty())
         {
-            auto http2 = std::make_shared<HTTP2Connection<Adaptor, Handler>>(
-                std::move(adaptor.next_layer()), handler, getCachedDateStr);
-            if (http2settings.empty())
-            {
-                http2->start();
-            }
-            else
-            {
-                http2->startFromSettings(http2settings);
-            }
+            http2->start();
         }
         else
         {
-            auto http2 = std::make_shared<
-                HTTP2Connection<boost::asio::ssl::stream<Adaptor>, Handler>>(
-                std::move(adaptor), handler, getCachedDateStr);
-            if (http2settings.empty())
-            {
-                http2->start();
-            }
-            else
-            {
-                http2->startFromSettings(http2settings);
-            }
+            http2->startFromSettings(http2settings);
         }
     }