Make references to crow less obvious

Recently, a number of people in the community have made the (admittedly
easy) mistake that we use a significant portion of crow.

Today, we use crow for the router, and the "app" structure, and even
those have been significantly modified to meet the bmc needs.  All other
components have been replaced with Boost beast.  This commit removes the
crow mentions from the Readme, and moves the crow folder to "http" to
camouflage it a little.  No code content has changed.

Tested:
Code compiles.  No functional change made to any executable code.

Signed-off-by: Ed Tanous <ed.tanous@intel.com>
Change-Id: Iceb57b26306cc8bdcfc77f3874246338864fd118
diff --git a/http/websocket.h b/http/websocket.h
new file mode 100644
index 0000000..61b3e5a
--- /dev/null
+++ b/http/websocket.h
@@ -0,0 +1,250 @@
+#pragma once
+#include <array>
+#include <boost/algorithm/string/predicate.hpp>
+#include <boost/asio/buffer.hpp>
+#include <boost/beast/websocket.hpp>
+#include <functional>
+
+#include "http_request.h"
+
+#ifdef BMCWEB_ENABLE_SSL
+#include <boost/beast/websocket/ssl.hpp>
+#endif
+
+namespace crow
+{
+namespace websocket
+{
+struct Connection : std::enable_shared_from_this<Connection>
+{
+  public:
+    explicit Connection(const crow::Request& reqIn) :
+        req(reqIn), userdataPtr(nullptr){};
+
+    virtual void sendBinary(const std::string_view msg) = 0;
+    virtual void sendBinary(std::string&& msg) = 0;
+    virtual void sendText(const std::string_view msg) = 0;
+    virtual void sendText(std::string&& msg) = 0;
+    virtual void close(const std::string_view msg = "quit") = 0;
+    virtual boost::asio::io_context& get_io_context() = 0;
+    virtual ~Connection() = default;
+
+    void userdata(void* u)
+    {
+        userdataPtr = u;
+    }
+    void* userdata()
+    {
+        return userdataPtr;
+    }
+
+    crow::Request req;
+
+  private:
+    void* userdataPtr;
+};
+
+template <typename Adaptor> class ConnectionImpl : public Connection
+{
+  public:
+    ConnectionImpl(
+        const crow::Request& reqIn, Adaptor adaptorIn,
+        std::function<void(Connection&)> open_handler,
+        std::function<void(Connection&, const std::string&, bool)>
+            message_handler,
+        std::function<void(Connection&, const std::string&)> close_handler,
+        std::function<void(Connection&)> error_handler) :
+        Connection(reqIn),
+        ws(std::move(adaptorIn)), inString(), inBuffer(inString, 131088),
+        openHandler(std::move(open_handler)),
+        messageHandler(std::move(message_handler)),
+        closeHandler(std::move(close_handler)),
+        errorHandler(std::move(error_handler))
+    {
+        BMCWEB_LOG_DEBUG << "Creating new connection " << this;
+    }
+
+    boost::asio::io_context& get_io_context() override
+    {
+        return static_cast<boost::asio::io_context&>(
+            ws.get_executor().context());
+    }
+
+    void start()
+    {
+        BMCWEB_LOG_DEBUG << "starting connection " << this;
+
+        using bf = boost::beast::http::field;
+
+        std::string_view protocol =
+            req.getHeaderValue(bf::sec_websocket_protocol);
+
+        // Perform the websocket upgrade
+        ws.async_accept_ex(
+            req.req,
+            [protocol{std::string(protocol)}](
+                boost::beast::websocket::response_type& m) {
+                if (!protocol.empty())
+                {
+                    m.insert(bf::sec_websocket_protocol, protocol);
+                }
+
+                m.insert(bf::strict_transport_security, "max-age=31536000; "
+                                                        "includeSubdomains; "
+                                                        "preload");
+                m.insert(bf::pragma, "no-cache");
+                m.insert(bf::cache_control, "no-Store,no-Cache");
+                m.insert("Content-Security-Policy", "default-src 'self'");
+                m.insert("X-XSS-Protection", "1; "
+                                             "mode=block");
+                m.insert("X-Content-Type-Options", "nosniff");
+            },
+            [this, self(shared_from_this())](boost::system::error_code ec) {
+                if (ec)
+                {
+                    BMCWEB_LOG_ERROR << "Error in ws.async_accept " << ec;
+                    return;
+                }
+                acceptDone();
+            });
+    }
+
+    void sendBinary(const std::string_view msg) override
+    {
+        ws.binary(true);
+        outBuffer.emplace_back(msg);
+        doWrite();
+    }
+
+    void sendBinary(std::string&& msg) override
+    {
+        ws.binary(true);
+        outBuffer.emplace_back(std::move(msg));
+        doWrite();
+    }
+
+    void sendText(const std::string_view msg) override
+    {
+        ws.text(true);
+        outBuffer.emplace_back(msg);
+        doWrite();
+    }
+
+    void sendText(std::string&& msg) override
+    {
+        ws.text(true);
+        outBuffer.emplace_back(std::move(msg));
+        doWrite();
+    }
+
+    void close(const std::string_view msg) override
+    {
+        ws.async_close(
+            boost::beast::websocket::close_code::normal,
+            [self(shared_from_this())](boost::system::error_code ec) {
+                if (ec == boost::asio::error::operation_aborted)
+                {
+                    return;
+                }
+                if (ec)
+                {
+                    BMCWEB_LOG_ERROR << "Error closing websocket " << ec;
+                    return;
+                }
+            });
+    }
+
+    void acceptDone()
+    {
+        BMCWEB_LOG_DEBUG << "Websocket accepted connection";
+
+        if (openHandler)
+        {
+            openHandler(*this);
+        }
+        doRead();
+    }
+
+    void doRead()
+    {
+        ws.async_read(inBuffer,
+                      [this, self(shared_from_this())](
+                          boost::beast::error_code ec, std::size_t bytes_read) {
+                          if (ec)
+                          {
+                              if (ec != boost::beast::websocket::error::closed)
+                              {
+                                  BMCWEB_LOG_ERROR << "doRead error " << ec;
+                              }
+                              if (closeHandler)
+                              {
+                                  std::string_view reason = ws.reason().reason;
+                                  closeHandler(*this, std::string(reason));
+                              }
+                              return;
+                          }
+                          if (messageHandler)
+                          {
+                              messageHandler(*this, inString, ws.got_text());
+                          }
+                          inBuffer.consume(bytes_read);
+                          inString.clear();
+                          doRead();
+                      });
+    }
+
+    void doWrite()
+    {
+        // If we're already doing a write, ignore the request, it will be picked
+        // up when the current write is complete
+        if (doingWrite)
+        {
+            return;
+        }
+
+        if (outBuffer.empty())
+        {
+            // Done for now
+            return;
+        }
+        doingWrite = true;
+        ws.async_write(
+            boost::asio::buffer(outBuffer.front()),
+            [this, self(shared_from_this())](boost::beast::error_code ec,
+                                             std::size_t bytes_written) {
+                doingWrite = false;
+                outBuffer.erase(outBuffer.begin());
+                if (ec == boost::beast::websocket::error::closed)
+                {
+                    // Do nothing here.  doRead handler will call the
+                    // closeHandler.
+                    close("Write error");
+                    return;
+                }
+                if (ec)
+                {
+                    BMCWEB_LOG_ERROR << "Error in ws.async_write " << ec;
+                    return;
+                }
+                doWrite();
+            });
+    }
+
+  private:
+    boost::beast::websocket::stream<Adaptor> ws;
+
+    std::string inString;
+    boost::asio::dynamic_string_buffer<std::string::value_type,
+                                       std::string::traits_type,
+                                       std::string::allocator_type>
+        inBuffer;
+    std::vector<std::string> outBuffer;
+    bool doingWrite = false;
+
+    std::function<void(Connection&)> openHandler;
+    std::function<void(Connection&, const std::string&, bool)> messageHandler;
+    std::function<void(Connection&, const std::string&)> closeHandler;
+    std::function<void(Connection&)> errorHandler;
+};
+} // namespace websocket
+} // namespace crow