| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258 | #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;std::mutex BellHTTPServer::initMutex;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) {  std::lock_guard lock(initMutex);  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);}BellHTTPServer::~BellHTTPServer() {  std::lock_guard lock(initMutex);  mg_exit_library();}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;}
 |