#include "expresscpp/layer.hpp" #include #include "boost/uuid/uuid_generators.hpp" #include "boost/uuid/uuid_io.hpp" #include "expresscpp/console.hpp" #include "expresscpp/impl/utils.hpp" #include "expresscpp/path_to_regexp.hpp" namespace expresscpp { Layer::Layer(const std::string_view registered_path) { path_ = registered_path; Init(); PathToRegExpOptions default_options; regexp_ = pathToRegExpString(path_, keys_, default_options); } Layer::Layer(const std::string_view registered_path, PathToRegExpOptions options, std::string_view parent_path, handler_wn_t handler) : handler_(handler) { path_ = registered_path; Init(); options_ = options; regexp_ = pathToRegExpString(path_, keys_, options, parent_path); } Layer::Layer(const std::string_view registered_path, PathToRegExpOptions options, std::string_view parent_path, handler_t handler) : handler_(handler) { path_ = registered_path; Init(); options_ = options; regexp_ = pathToRegExpString(path_, keys_, options, parent_path); } void Layer::SetParentPath(const std::string_view parent_path) { regexp_ = pathToRegExpString(path_, keys_, options_, parent_path); } void Layer::Init() { uuid_ = boost::uuids::random_generator()(); Console::Debug(fmt::format(R"(Layer created for path: "{}", uuid: "{}")", path_, boostUUIDToString(uuid_))); } std::vector Layer::GetKeys() const { return keys_; } void Layer::SetKeys(const std::vector &keys) { keys_ = keys; } const std::string_view Layer::GetPath() const { return path_; } std::map Layer::ParseQueryString(std::string_view requested_path, size_t key_start_pos) { size_t param_pair_end_pos = 0; size_t equal_sign_pos = 0; std::map result; while (equal_sign_pos != std::string::npos) { equal_sign_pos = requested_path.find("=", equal_sign_pos + 1); param_pair_end_pos = requested_path.find("&", param_pair_end_pos + 1); if (equal_sign_pos < param_pair_end_pos) { auto key = requested_path.substr(key_start_pos + 1, equal_sign_pos - key_start_pos - 1); key_start_pos = requested_path.find("&", key_start_pos + 1); auto value = requested_path.substr(equal_sign_pos + 1, key_start_pos - equal_sign_pos - 1); result.insert({std::string(key), std::string(value)}); } } return result; } bool Layer::Match(std::shared_ptr request) { if (request->getPath().empty()) { return false; } auto requested_path = request->getPath(); const auto query_param_pos = requested_path.find("?"); if (query_param_pos != std::string::npos) { request->SetQueryParams(ParseQueryString(requested_path, query_param_pos)); request->SetQueryString(requested_path.substr(query_param_pos + 1).data()); } std::string current_path; current_path = requested_path.substr(0, query_param_pos); std::smatch smatch; bool match = std::regex_search(current_path, smatch, regexp_); if (smatch.size() > 1) { std::map params; for (const auto &key : keys_) { auto val = smatch[key.index_ + 1].str(); Console::Debug(fmt::format(R"(val, "{}")", val)); params.insert({key.name_, val}); } request->SetParams(params); } return match; } void Layer::HandleRequest(request_t req, response_t res, next_t next) { Console::Debug("Layer handling request"); if (route_ == nullptr) { if (handler_.getWith_next()) { handler_(req, res, next); } else { handler_(req, res); } } else { route_->Dispatch(req, res, next); } } std::shared_ptr Layer::GetRoute() const { return route_; } void Layer::SetRoute(const std::shared_ptr &new_route) { route_ = new_route; } HttpMethod Layer::GetMethod() const { return method_; } void Layer::SetMethod(const HttpMethod &method) { method_ = method; } } // namespace expresscpp