| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250 | 
							- #include "BellHTTPServer.h"
 
- #include <string.h>   // for memcpy
 
- #include <cassert>    // for assert
 
- #include <exception>  // for exception
 
- #include <mutex>      // for scoped_lock
 
- #include <regex>      // for sregex_token_iterator, regex
 
- #include "BellLogger.h"   // for AbstractLogger, BELL_LOG, bell
 
- #include "CivetServer.h"  // for CivetServer, CivetWebSocketHandler
 
- #include "civetweb.h"     // for mg_get_request_info, mg_printf, mg_set_user...
 
- using namespace bell;
 
- class WebSocketHandler : public CivetWebSocketHandler {
 
-  public:
 
-   BellHTTPServer::WSDataHandler dataHandler;
 
-   BellHTTPServer::WSStateHandler stateHandler;
 
-   WebSocketHandler(BellHTTPServer::WSDataHandler dataHandler,
 
-                    BellHTTPServer::WSStateHandler stateHandler) {
 
-     this->dataHandler = dataHandler;
 
-     this->stateHandler = stateHandler;
 
-   }
 
-   virtual bool handleConnection(CivetServer* server,
 
-                                 struct mg_connection* conn) {
 
-     this->stateHandler(conn, BellHTTPServer::WSState::CONNECTED);
 
-     return true;
 
-   }
 
-   virtual void handleReadyState(CivetServer* server,
 
-                                 struct mg_connection* conn) {
 
-     this->stateHandler(conn, BellHTTPServer::WSState::READY);
 
-   }
 
-   virtual bool handleData(CivetServer* server, struct mg_connection* conn,
 
-                           int flags, char* data, size_t data_len) {
 
-     if ((flags & 0xf) == MG_WEBSOCKET_OPCODE_CONNECTION_CLOSE) {
 
-       // Received close message from client. Close the connection.
 
-       this->stateHandler(conn, BellHTTPServer::WSState::CLOSED);
 
-       return false;
 
-     }
 
-     this->dataHandler(conn, data, data_len);
 
-     return true;
 
-   }
 
-   virtual void handleClose(CivetServer* server, struct mg_connection* conn) {
 
-     stateHandler(conn, BellHTTPServer::WSState::CLOSED);
 
-   }
 
- };
 
- std::vector<std::string> BellHTTPServer::Router::split(
 
-     const std::string str, const std::string regex_str) {
 
-   std::regex regexz(regex_str);
 
-   return {std::sregex_token_iterator(str.begin(), str.end(), regexz, -1),
 
-           std::sregex_token_iterator()};
 
- }
 
- void BellHTTPServer::Router::insert(const std::string& route,
 
-                                     HTTPHandler& value) {
 
-   auto parts = split(route, "/");
 
-   auto currentNode = &root;
 
-   for (int index = 0; index < parts.size(); index++) {
 
-     auto part = parts[index];
 
-     if (part[0] == ':') {
 
-       currentNode->isParam = true;
 
-       currentNode->paramName = part.substr(1);
 
-       part = "";
 
-     } else if (part[0] == '*') {
 
-       currentNode->isCatchAll = true;
 
-       currentNode->value = value;
 
-       return;
 
-     }
 
-     if (!currentNode->children.count(part)) {
 
-       currentNode->children[part] = std::make_unique<RouterNode>();
 
-     }
 
-     currentNode = currentNode->children[part].get();
 
-   }
 
-   currentNode->value = value;
 
- }
 
- BellHTTPServer::Router::HandlerAndParams BellHTTPServer::Router::find(
 
-     const std::string& route) {
 
-   auto parts = split(route, "/");
 
-   auto currentNode = &root;
 
-   std::unordered_map<std::string, std::string> params;
 
-   for (int index = 0; index < parts.size(); index++) {
 
-     auto part = parts[index];
 
-     if (currentNode->children.count(part)) {
 
-       currentNode = currentNode->children[part].get();
 
-     } else if (currentNode->isParam) {
 
-       params[currentNode->paramName] = part;
 
-       if (currentNode->children.count("")) {
 
-         currentNode = currentNode->children[""].get();
 
-       } else {
 
-         return {nullptr, Params()};
 
-       }
 
-     } else if (currentNode->isCatchAll) {
 
-       params["**"] = '*';
 
-       return {currentNode->value, params};
 
-     } else {
 
-       return {nullptr, Params()};
 
-     }
 
-   }
 
-   if (currentNode->value != nullptr) {
 
-     return {currentNode->value, params};
 
-   }
 
-   return {nullptr, Params()};
 
- }
 
- bool BellHTTPServer::handleGet(CivetServer* server,
 
-                                struct mg_connection* conn) {
 
-   std::scoped_lock lock(this->responseMutex);
 
-   auto requestInfo = mg_get_request_info(conn);
 
-   auto handler = getRequestsRouter.find(requestInfo->local_uri);
 
-   if (handler.first == nullptr) {
 
-     if (this->notFoundHandler != nullptr) {
 
-       this->notFoundHandler(conn);
 
-       return true;
 
-     }
 
-     return false;
 
-   }
 
-   mg_set_user_connection_data(conn, &handler.second);
 
-   try {
 
-     auto reply = handler.first(conn);
 
-     if (reply->body == nullptr) {
 
-       return true;
 
-     }
 
-     mg_printf(
 
-         conn,
 
-         "HTTP/1.1 %d OK\r\nContent-Type: "
 
-         "%s\r\nAccess-Control-Allow-Origin: *\r\nConnection: close\r\n\r\n",
 
-         reply->status, reply->headers["Content-Type"].c_str());
 
-     mg_write(conn, reply->body, reply->bodySize);
 
-     return true;
 
-   } catch (std::exception& e) {
 
-     BELL_LOG(error, "HttpServer", "Exception occured in handler: %s", e.what());
 
-     return false;
 
-   }
 
- }
 
- bool BellHTTPServer::handlePost(CivetServer* server,
 
-                                 struct mg_connection* conn) {
 
-   std::scoped_lock lock(this->responseMutex);
 
-   auto requestInfo = mg_get_request_info(conn);
 
-   auto handler = postRequestsRouter.find(requestInfo->local_uri);
 
-   if (handler.first == nullptr) {
 
-     return false;
 
-   }
 
-   mg_set_user_connection_data(conn, &handler.second);
 
-   try {
 
-     auto reply = handler.first(conn);
 
-     if (reply->body == nullptr) {
 
-       return true;
 
-     }
 
-     mg_printf(
 
-         conn,
 
-         "HTTP/1.1 %d OK\r\nContent-Type: "
 
-         "%s\r\nAccess-Control-Allow-Origin: *\r\nConnection: close\r\n\r\n",
 
-         reply->status, reply->headers["Content-Type"].c_str());
 
-     mg_write(conn, reply->body, reply->bodySize);
 
-     return true;
 
-   } catch (std::exception& e) {
 
-     BELL_LOG(error, "HttpServer", "Exception occured in handler: %s", e.what());
 
-     return false;
 
-   }
 
- }
 
- BellHTTPServer::BellHTTPServer(int serverPort) {
 
-   mg_init_library(0);
 
-   BELL_LOG(info, "HttpServer", "Server listening on port %d", serverPort);
 
-   this->serverPort = serverPort;
 
-   auto port = std::to_string(this->serverPort);
 
-   civetWebOptions.push_back("listening_ports");
 
-   civetWebOptions.push_back(port);
 
-   server = std::make_unique<CivetServer>(civetWebOptions);
 
- }
 
- std::unique_ptr<BellHTTPServer::HTTPResponse> BellHTTPServer::makeJsonResponse(
 
-     const std::string& json, int status) {
 
-   auto response = std::make_unique<BellHTTPServer::HTTPResponse>();
 
-   response->body = (uint8_t*)malloc(json.size());
 
-   response->bodySize = json.size();
 
-   response->headers["Content-Type"] = "application/json";
 
-   response->status = status;
 
-   memcpy(response->body, json.c_str(), json.size());
 
-   return response;
 
- }
 
- std::unique_ptr<BellHTTPServer::HTTPResponse>
 
- BellHTTPServer::makeEmptyResponse() {
 
-   auto response = std::make_unique<BellHTTPServer::HTTPResponse>();
 
-   return response;
 
- }
 
- void BellHTTPServer::registerGet(const std::string& url,
 
-                                  BellHTTPServer::HTTPHandler handler) {
 
-   server->addHandler(url, this);
 
-   getRequestsRouter.insert(url, handler);
 
- }
 
- void BellHTTPServer::registerPost(const std::string& url,
 
-                                   BellHTTPServer::HTTPHandler handler) {
 
-   server->addHandler(url, this);
 
-   postRequestsRouter.insert(url, handler);
 
- }
 
- void BellHTTPServer::registerWS(const std::string& url,
 
-                                 BellHTTPServer::WSDataHandler dataHandler,
 
-                                 BellHTTPServer::WSStateHandler stateHandler) {
 
-   server->addWebSocketHandler(url,
 
-                               new WebSocketHandler(dataHandler, stateHandler));
 
- }
 
- void BellHTTPServer::registerNotFound(HTTPHandler handler) {
 
-   this->notFoundHandler = handler;
 
- }
 
- std::unordered_map<std::string, std::string> BellHTTPServer::extractParams(
 
-     struct mg_connection* conn) {
 
-   void* data = mg_get_user_connection_data(conn);
 
-   assert(data != nullptr);
 
-   std::unordered_map<std::string, std::string>& params =
 
-       *(std::unordered_map<std::string, std::string>*)data;
 
-   return params;
 
- }
 
 
  |