Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add radix tree router and regex router #473

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 52 additions & 2 deletions include/cinatra/coro_http_connection.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -195,8 +195,58 @@ class coro_http_connection
co_await router_.route_coro(coro_handler, request_, response_);
}
else {
// not found
response_.set_status(status_type::not_found);
bool is_exist = false;
std::function<void(coro_http_request & req,
coro_http_response & resp)>
handler;
params_t params = {};
std::string method_str;
method_str.assign(parser_.method().data(), parser_.method().length());
std::string url_path;
url_path.assign(parser_.url().data(), parser_.url().length());

std::tie(is_exist, handler, request_.params_) =
router_.get_router_tree()->get(url_path, method_str);
if (is_exist) {
(handler)(request_, response_);
}
else {
bool is_matched_regex_router = false;
// coro regex router
auto coro_regex_handlers = router_.get_coro_regex_handlers();
if (coro_regex_handlers.size() != 0) {
for (auto &pair : coro_regex_handlers) {
std::string coro_regex_key;
coro_regex_key.assign(key.data(), key.size());

if (std::regex_match(coro_regex_key, request_.matches_,
std::get<0>(pair))) {
auto coro_handler = std::get<1>(pair);
co_await (coro_handler)(request_, response_);
is_matched_regex_router = true;
}
}
}
// regex router
if (!is_matched_regex_router) {
auto regex_handlers = router_.get_regex_handlers();
if (regex_handlers.size() != 0) {
for (auto &pair : regex_handlers) {
std::string regex_key;
regex_key.assign(key.data(), key.size());
if (std::regex_match(regex_key, request_.matches_,
std::get<0>(pair))) {
auto handler = std::get<1>(pair);
(handler)(request_, response_);
is_matched_regex_router = true;
}
}
}
}
// not found
if (!is_matched_regex_router)
response_.set_status(status_type::not_found);
}
}
}

Expand Down
13 changes: 13 additions & 0 deletions include/cinatra/coro_http_request.hpp
Original file line number Diff line number Diff line change
@@ -1,10 +1,20 @@
#pragma once
#include <regex>

#include "async_simple/coro/Lazy.h"
#include "define.h"
#include "http_parser.hpp"
#include "ws_define.h"

namespace cinatra {

typedef std::pair<std::string, std::string> paramters_t;

struct params_t {
std::vector<paramters_t> parameters;
int size;
};

class coro_http_connection;
class coro_http_request {
public:
Expand Down Expand Up @@ -118,6 +128,9 @@ class coro_http_request {
return true;
}

params_t params_;
std::smatch matches_;

private:
http_parser& parser_;
std::string_view body_;
Expand Down
77 changes: 67 additions & 10 deletions include/cinatra/coro_http_router.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@

#include "cinatra/cinatra_log_wrapper.hpp"
#include "cinatra/coro_http_request.hpp"
#include "cinatra/coro_radix_tree.hpp"
#include "cinatra/response_cv.hpp"
#include "cinatra/utils.hpp"
#include "coro_http_response.hpp"
#include "ylt/util/type_traits.h"

Expand All @@ -28,6 +30,7 @@ constexpr inline bool is_lazy_v =

class coro_http_router {
public:
~coro_http_router() { delete router_tree_; }
// eg: "GET hello/" as a key
template <http_method method, typename Func>
void set_http_handler(std::string key, Func handler) {
Expand All @@ -39,20 +42,56 @@ class coro_http_router {
// std::string_view, avoid memcpy when route
using return_type = typename util::function_traits<Func>::return_type;
if constexpr (is_lazy_v<return_type>) {
auto [it, ok] = coro_keys_.emplace(std::move(whole_str));
if (!ok) {
CINATRA_LOG_WARNING << key << " has already registered.";
return;
if (whole_str.find("{") != std::string::npos ||
whole_str.find(")") != std::string::npos) {
std::string pattern = whole_str;
std::unordered_map<std::string, int> params;
params.clear();

if (pattern.find("{}") != std::string::npos) {
replace_all(pattern, "{}", "([^/]+)");
}

coro_regex_handles_.emplace_back(std::regex(pattern),
std::move(handler));
}
else {
auto [it, ok] = coro_keys_.emplace(std::move(whole_str));
if (!ok) {
CINATRA_LOG_WARNING << key << " has already registered.";
return;
}
coro_handles_.emplace(*it, std::move(handler));
}
coro_handles_.emplace(*it, std::move(handler));
}
else {
auto [it, ok] = keys_.emplace(std::move(whole_str));
if (!ok) {
CINATRA_LOG_WARNING << key << " has already registered.";
return;
if (whole_str.find(':') != std::string::npos) {
std::vector<std::string> method_names = {};
std::string method_str;
method_str.append(method_name);
method_names.push_back(method_str);
router_tree_->insert(key, std::move(handler), method_names);
}
else if (whole_str.find("{") != std::string::npos ||
whole_str.find(")") != std::string::npos) {
std::string pattern = whole_str;
std::unordered_map<std::string, int> params;
params.clear();

if (pattern.find("{}") != std::string::npos) {
replace_all(pattern, "{}", "([^/]+)");
}

regex_handles_.emplace_back(std::regex(pattern), std::move(handler));
}
else {
auto [it, ok] = keys_.emplace(std::move(whole_str));
if (!ok) {
CINATRA_LOG_WARNING << key << " has already registered.";
return;
}
map_handles_.emplace(*it, std::move(handler));
}
map_handles_.emplace(*it, std::move(handler));
}
}

Expand Down Expand Up @@ -104,6 +143,12 @@ class coro_http_router {

const auto& get_coro_handlers() const { return coro_handles_; }

radix_tree* get_router_tree() { return router_tree_; }

const auto& get_coro_regex_handlers() { return coro_regex_handles_; }

const auto& get_regex_handlers() { return regex_handles_; }

private:
std::set<std::string> keys_;
std::unordered_map<
Expand All @@ -116,5 +161,17 @@ class coro_http_router {
std::function<async_simple::coro::Lazy<void>(
coro_http_request& req, coro_http_response& resp)>>
coro_handles_;

radix_tree* router_tree_ = new radix_tree();

std::vector<std::tuple<
std::regex,
std::function<void(coro_http_request& req, coro_http_response& resp)>>>
regex_handles_;

std::vector<std::tuple<
std::regex, std::function<async_simple::coro::Lazy<void>(
coro_http_request& req, coro_http_response& resp)>>>
coro_regex_handles_;
};
} // namespace cinatra
Loading
Loading