2
0

BellHTTPServer.cpp 7.0 KB

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