BellHTTPServer.cpp 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258
  1. #include "BellHTTPServer.h"
  2. #include <string.h> // for memcpy
  3. #include <cassert> // for assert
  4. #include <exception> // for exception
  5. #include <mutex> // for scoped_lock
  6. #include <regex> // for sregex_token_iterator, regex
  7. #include "BellLogger.h" // for AbstractLogger, BELL_LOG, bell
  8. #include "CivetServer.h" // for CivetServer, CivetWebSocketHandler
  9. #include "civetweb.h" // for mg_get_request_info, mg_printf, mg_set_user...
  10. using namespace bell;
  11. std::mutex BellHTTPServer::initMutex;
  12. class WebSocketHandler : public CivetWebSocketHandler {
  13. public:
  14. BellHTTPServer::WSDataHandler dataHandler;
  15. BellHTTPServer::WSStateHandler stateHandler;
  16. WebSocketHandler(BellHTTPServer::WSDataHandler dataHandler,
  17. BellHTTPServer::WSStateHandler stateHandler) {
  18. this->dataHandler = dataHandler;
  19. this->stateHandler = stateHandler;
  20. }
  21. virtual bool handleConnection(CivetServer* server,
  22. struct mg_connection* conn) {
  23. this->stateHandler(conn, BellHTTPServer::WSState::CONNECTED);
  24. return true;
  25. }
  26. virtual void handleReadyState(CivetServer* server,
  27. struct mg_connection* conn) {
  28. this->stateHandler(conn, BellHTTPServer::WSState::READY);
  29. }
  30. virtual bool handleData(CivetServer* server, struct mg_connection* conn,
  31. int flags, char* data, size_t data_len) {
  32. if ((flags & 0xf) == MG_WEBSOCKET_OPCODE_CONNECTION_CLOSE) {
  33. // Received close message from client. Close the connection.
  34. this->stateHandler(conn, BellHTTPServer::WSState::CLOSED);
  35. return false;
  36. }
  37. this->dataHandler(conn, data, data_len);
  38. return true;
  39. }
  40. virtual void handleClose(CivetServer* server, struct mg_connection* conn) {
  41. stateHandler(conn, BellHTTPServer::WSState::CLOSED);
  42. }
  43. };
  44. std::vector<std::string> BellHTTPServer::Router::split(
  45. const std::string str, const std::string regex_str) {
  46. std::regex regexz(regex_str);
  47. return {std::sregex_token_iterator(str.begin(), str.end(), regexz, -1),
  48. std::sregex_token_iterator()};
  49. }
  50. void BellHTTPServer::Router::insert(const std::string& route,
  51. HTTPHandler& value) {
  52. auto parts = split(route, "/");
  53. auto currentNode = &root;
  54. for (int index = 0; index < parts.size(); index++) {
  55. auto part = parts[index];
  56. if (part[0] == ':') {
  57. currentNode->isParam = true;
  58. currentNode->paramName = part.substr(1);
  59. part = "";
  60. } else if (part[0] == '*') {
  61. currentNode->isCatchAll = true;
  62. currentNode->value = value;
  63. return;
  64. }
  65. if (!currentNode->children.count(part)) {
  66. currentNode->children[part] = std::make_unique<RouterNode>();
  67. }
  68. currentNode = currentNode->children[part].get();
  69. }
  70. currentNode->value = value;
  71. }
  72. BellHTTPServer::Router::HandlerAndParams BellHTTPServer::Router::find(
  73. const std::string& route) {
  74. auto parts = split(route, "/");
  75. auto currentNode = &root;
  76. std::unordered_map<std::string, std::string> params;
  77. for (int index = 0; index < parts.size(); index++) {
  78. auto part = parts[index];
  79. if (currentNode->children.count(part)) {
  80. currentNode = currentNode->children[part].get();
  81. } else if (currentNode->isParam) {
  82. params[currentNode->paramName] = part;
  83. if (currentNode->children.count("")) {
  84. currentNode = currentNode->children[""].get();
  85. } else {
  86. return {nullptr, Params()};
  87. }
  88. } else if (currentNode->isCatchAll) {
  89. params["**"] = '*';
  90. return {currentNode->value, params};
  91. } else {
  92. return {nullptr, Params()};
  93. }
  94. }
  95. if (currentNode->value != nullptr) {
  96. return {currentNode->value, params};
  97. }
  98. return {nullptr, Params()};
  99. }
  100. bool BellHTTPServer::handleGet(CivetServer* server,
  101. struct mg_connection* conn) {
  102. std::scoped_lock lock(this->responseMutex);
  103. auto requestInfo = mg_get_request_info(conn);
  104. auto handler = getRequestsRouter.find(requestInfo->local_uri);
  105. if (handler.first == nullptr) {
  106. if (this->notFoundHandler != nullptr) {
  107. this->notFoundHandler(conn);
  108. return true;
  109. }
  110. return false;
  111. }
  112. mg_set_user_connection_data(conn, &handler.second);
  113. try {
  114. auto reply = handler.first(conn);
  115. if (reply->body == nullptr) {
  116. return true;
  117. }
  118. mg_printf(
  119. conn,
  120. "HTTP/1.1 %d OK\r\nContent-Type: "
  121. "%s\r\nAccess-Control-Allow-Origin: *\r\nConnection: close\r\n\r\n",
  122. reply->status, reply->headers["Content-Type"].c_str());
  123. mg_write(conn, reply->body, reply->bodySize);
  124. return true;
  125. } catch (std::exception& e) {
  126. BELL_LOG(error, "HttpServer", "Exception occured in handler: %s", e.what());
  127. return false;
  128. }
  129. }
  130. bool BellHTTPServer::handlePost(CivetServer* server,
  131. struct mg_connection* conn) {
  132. std::scoped_lock lock(this->responseMutex);
  133. auto requestInfo = mg_get_request_info(conn);
  134. auto handler = postRequestsRouter.find(requestInfo->local_uri);
  135. if (handler.first == nullptr) {
  136. return false;
  137. }
  138. mg_set_user_connection_data(conn, &handler.second);
  139. try {
  140. auto reply = handler.first(conn);
  141. if (reply->body == nullptr) {
  142. return true;
  143. }
  144. mg_printf(
  145. conn,
  146. "HTTP/1.1 %d OK\r\nContent-Type: "
  147. "%s\r\nAccess-Control-Allow-Origin: *\r\nConnection: close\r\n\r\n",
  148. reply->status, reply->headers["Content-Type"].c_str());
  149. mg_write(conn, reply->body, reply->bodySize);
  150. return true;
  151. } catch (std::exception& e) {
  152. BELL_LOG(error, "HttpServer", "Exception occured in handler: %s", e.what());
  153. return false;
  154. }
  155. }
  156. BellHTTPServer::BellHTTPServer(int serverPort) {
  157. std::lock_guard lock(initMutex);
  158. mg_init_library(0);
  159. BELL_LOG(info, "HttpServer", "Server listening on port %d", serverPort);
  160. this->serverPort = serverPort;
  161. auto port = std::to_string(this->serverPort);
  162. civetWebOptions.push_back("listening_ports");
  163. civetWebOptions.push_back(port);
  164. server = std::make_unique<CivetServer>(civetWebOptions);
  165. }
  166. BellHTTPServer::~BellHTTPServer() {
  167. std::lock_guard lock(initMutex);
  168. mg_exit_library();
  169. }
  170. std::unique_ptr<BellHTTPServer::HTTPResponse> BellHTTPServer::makeJsonResponse(
  171. const std::string& json, int status) {
  172. auto response = std::make_unique<BellHTTPServer::HTTPResponse>();
  173. response->body = (uint8_t*)malloc(json.size());
  174. response->bodySize = json.size();
  175. response->headers["Content-Type"] = "application/json";
  176. response->status = status;
  177. memcpy(response->body, json.c_str(), json.size());
  178. return response;
  179. }
  180. std::unique_ptr<BellHTTPServer::HTTPResponse>
  181. BellHTTPServer::makeEmptyResponse() {
  182. auto response = std::make_unique<BellHTTPServer::HTTPResponse>();
  183. return response;
  184. }
  185. void BellHTTPServer::registerGet(const std::string& url,
  186. BellHTTPServer::HTTPHandler handler) {
  187. server->addHandler(url, this);
  188. getRequestsRouter.insert(url, handler);
  189. }
  190. void BellHTTPServer::registerPost(const std::string& url,
  191. BellHTTPServer::HTTPHandler handler) {
  192. server->addHandler(url, this);
  193. postRequestsRouter.insert(url, handler);
  194. }
  195. void BellHTTPServer::registerWS(const std::string& url,
  196. BellHTTPServer::WSDataHandler dataHandler,
  197. BellHTTPServer::WSStateHandler stateHandler) {
  198. server->addWebSocketHandler(url,
  199. new WebSocketHandler(dataHandler, stateHandler));
  200. }
  201. void BellHTTPServer::registerNotFound(HTTPHandler handler) {
  202. this->notFoundHandler = handler;
  203. }
  204. std::unordered_map<std::string, std::string> BellHTTPServer::extractParams(
  205. struct mg_connection* conn) {
  206. void* data = mg_get_user_connection_data(conn);
  207. assert(data != nullptr);
  208. std::unordered_map<std::string, std::string>& params =
  209. *(std::unordered_map<std::string, std::string>*)data;
  210. return params;
  211. }