diff --git a/include/http_data.h b/include/http_data.h index 695fbfff..7080bbc5 100644 --- a/include/http_data.h +++ b/include/http_data.h @@ -6,6 +6,7 @@ #include #include #include "json.hpp" +#include "string_utils.h" #define H2O_USE_LIBUV 0 extern "C" { @@ -96,26 +97,25 @@ struct http_res { enum class ROUTE_CODES { NOT_FOUND = -1, - RETURN_EARLY = -2, + ALREADY_HANDLED = -2, }; struct http_req { h2o_req_t* _req; std::string http_method; - int route_index; + int route_hash; std::map params; std::string body; - http_req(): route_index(-1) {} + http_req(): route_hash(-1) {} - http_req(h2o_req_t* _req, const std::string & http_method, size_t route_index, - const std::map & params, - std::string body): _req(_req), http_method(http_method), route_index(route_index), - params(params), body(body) {} + http_req(h2o_req_t* _req, const std::string & http_method, size_t route_hash, + const std::map & params, std::string body): + _req(_req), http_method(http_method), route_hash(route_hash), params(params), body(body) {} void deserialize(const std::string& serialized_content) { nlohmann::json content = nlohmann::json::parse(serialized_content); - route_index = content["route_index"]; + route_hash = content["route_hash"]; body = content["body"]; for (nlohmann::json::iterator it = content["params"].begin(); it != content["params"].end(); ++it) { @@ -127,7 +127,7 @@ struct http_req { std::string serialize() const { nlohmann::json content; - content["route_index"] = route_index; + content["route_hash"] = route_hash; content["params"] = params; content["body"] = body; @@ -149,6 +149,12 @@ struct route_path { inline bool operator< (const route_path& rhs) const { return true; } + + uint64_t route_hash() { + std::string path = StringUtils::join(path_parts, "/"); + std::string method_path = http_method + path; + return StringUtils::hash_wy(method_path.c_str(), method_path.size()); + } }; struct h2o_custom_generator_t { diff --git a/include/http_server.h b/include/http_server.h index 1df64b13..6e39074c 100644 --- a/include/http_server.h +++ b/include/http_server.h @@ -34,7 +34,7 @@ private: std::string version; - std::vector routes; // TODO: must be a hashmap? + std::unordered_map routes; const std::string listen_address; diff --git a/include/string_utils.h b/include/string_utils.h index 4c0641dd..61c879de 100644 --- a/include/string_utils.h +++ b/include/string_utils.h @@ -46,7 +46,7 @@ struct StringUtils { } } - static std::string join(std::vector vec, std::string delimiter, size_t start_index = 0) { + static std::string join(std::vector vec, const std::string& delimiter, size_t start_index = 0) { std::stringstream ss; for(size_t i = start_index; i < vec.size(); i++) { if(i != start_index) { diff --git a/src/core_api.cpp b/src/core_api.cpp index 6ed43feb..ae10cae4 100644 --- a/src/core_api.cpp +++ b/src/core_api.cpp @@ -613,21 +613,16 @@ bool async_write_request(void *data) { AsyncIndexArg* index_arg = static_cast(data); std::unique_ptr index_arg_guard(index_arg); - if(index_arg->req->route_index == static_cast(ROUTE_CODES::NOT_FOUND)) { + if(index_arg->req->route_hash == static_cast(ROUTE_CODES::NOT_FOUND)) { // route not found - return false; - } else if(index_arg->req->route_index == static_cast(ROUTE_CODES::RETURN_EARLY)) { - // respond without calling internal route - server->send_response(index_arg->req, index_arg->res); - return true; + index_arg->res->send_400("Not found."); + } else if(index_arg->req->route_hash != static_cast(ROUTE_CODES::ALREADY_HANDLED)) { + // call the underlying http handler + route_path* found_rpath = nullptr; + server->get_route(index_arg->req->route_hash, &found_rpath); + found_rpath->handler(*index_arg->req, *index_arg->res); } - route_path* found_rpath; - server->get_route(index_arg->req->route_index, &found_rpath); - - // call the underlying http handler - found_rpath->handler(*index_arg->req, *index_arg->res); - if(index_arg->req->_req != nullptr) { // we have to return a response to the client server->send_response(index_arg->req, index_arg->res); diff --git a/src/http_server.cpp b/src/http_server.cpp index 82cb12d2..dc2c4f06 100644 --- a/src/http_server.cpp +++ b/src/http_server.cpp @@ -24,6 +24,8 @@ HttpServer::HttpServer(const std::string & version, const std::string & listen_a hostconf = h2o_config_register_host(&config, h2o_iovec_init(H2O_STRLIT("default")), 65535); register_handler(hostconf, "/", catch_all_handler); + listener_socket = nullptr; // initialized later + signal(SIGPIPE, SIG_IGN); h2o_context_init(&ctx, h2o_evloop_create(), &config); @@ -161,8 +163,10 @@ void HttpServer::clear_timeouts(const std::vector & timeouts) { } void HttpServer::stop() { - h2o_socket_read_stop(listener_socket); - h2o_socket_close(listener_socket); + if(listener_socket != nullptr) { + h2o_socket_read_stop(listener_socket); + h2o_socket_close(listener_socket); + } // this will break the event loop exit_loop = true; @@ -209,8 +213,9 @@ std::map HttpServer::parse_query(const std::string& qu } int HttpServer::find_route(const std::vector & path_parts, const std::string & http_method, route_path** found_rpath) { - for(size_t i = 0; i < routes.size(); i++) { - const route_path & rpath = routes[i]; + for (const auto& index_route : routes) { + const route_path & rpath = index_route.second; + if(rpath.path_parts.size() != path_parts.size() || rpath.http_method != http_method) { continue; } @@ -228,7 +233,7 @@ int HttpServer::find_route(const std::vector & path_parts, const st if(found) { *found_rpath = const_cast(&rpath); - return i; + return index_route.first; } } @@ -304,9 +309,9 @@ int HttpServer::catch_all_handler(h2o_handler_t *_self, h2o_req_t *req) { } route_path *rpath = nullptr; - int route_index = self->http_server->find_route(path_parts, http_method, &rpath); + int route_hash = self->http_server->find_route(path_parts, http_method, &rpath); - if(route_index != -1) { + if(route_hash != -1) { bool authenticated = self->http_server->auth_handler(*rpath, auth_key_from_header); if(!authenticated) { return send_401_unauthorized(req); @@ -320,7 +325,7 @@ int HttpServer::catch_all_handler(h2o_handler_t *_self, h2o_req_t *req) { } } - http_req* request = new http_req(req, http_method, route_index, query_map, req_body); + http_req* request = new http_req(req, http_method, route_hash, query_map, req_body); http_res* response = new http_res(); // for writes, we defer to replication_state @@ -391,28 +396,28 @@ void HttpServer::get(const std::string & path, bool (*handler)(http_req &, http_ std::vector path_parts; StringUtils::split(path, path_parts, "/"); route_path rpath = {"GET", path_parts, handler, async}; - routes.push_back(rpath); + routes.emplace(rpath.route_hash(), rpath); } void HttpServer::post(const std::string & path, bool (*handler)(http_req &, http_res &), bool async) { std::vector path_parts; StringUtils::split(path, path_parts, "/"); route_path rpath = {"POST", path_parts, handler, async}; - routes.push_back(rpath); + routes.emplace(rpath.route_hash(), rpath); } void HttpServer::put(const std::string & path, bool (*handler)(http_req &, http_res &), bool async) { std::vector path_parts; StringUtils::split(path, path_parts, "/"); route_path rpath = {"PUT", path_parts, handler, async}; - routes.push_back(rpath); + routes.emplace(rpath.route_hash(), rpath); } void HttpServer::del(const std::string & path, bool (*handler)(http_req &, http_res &), bool async) { std::vector path_parts; StringUtils::split(path, path_parts, "/"); route_path rpath = {"DELETE", path_parts, handler, async}; - routes.push_back(rpath); + routes.emplace(rpath.route_hash(), rpath); } void HttpServer::on(const std::string & message, bool (*handler)(void*)) { @@ -456,7 +461,7 @@ ReplicationState* HttpServer::get_replication_state() const { } void HttpServer::get_route(size_t index, route_path** found_rpath) { - if(index >= 0 && index < routes.size()) { + if(routes.count(index) > 0) { *found_rpath = &routes[index]; } } diff --git a/src/raft_server.cpp b/src/raft_server.cpp index bafaa3f9..68fcf98b 100644 --- a/src/raft_server.cpp +++ b/src/raft_server.cpp @@ -100,7 +100,7 @@ void ReplicationState::write(http_req* request, http_res* response) { LOG(ERROR) << "Rejecting write: could not find a leader."; response->send_500("Could not find a leader."); auto replication_arg = new AsyncIndexArg{request, response, nullptr}; - replication_arg->req->route_index = static_cast(ROUTE_CODES::RETURN_EARLY); + replication_arg->req->route_hash = static_cast(ROUTE_CODES::ALREADY_HANDLED); return message_dispatcher->send_message(REPLICATION_MSG, replication_arg); } @@ -131,7 +131,7 @@ void ReplicationState::write(http_req* request, http_res* response) { } auto replication_arg = new AsyncIndexArg{request, response, nullptr}; - replication_arg->req->route_index = static_cast(ROUTE_CODES::RETURN_EARLY); + replication_arg->req->route_hash = static_cast(ROUTE_CODES::ALREADY_HANDLED); message_dispatcher->send_message(REPLICATION_MSG, replication_arg); });