aboutsummaryrefslogtreecommitdiffstats
path: root/include/routing.h
diff options
context:
space:
mode:
authoripknHama <ipknhama@gmail.com>2016-09-21 23:11:06 +0900
committeripknHama <ipknhama@gmail.com>2016-09-21 23:11:06 +0900
commit3081e4e1a82a4efd8feff68850c4cc04af230cd7 (patch)
tree3ad16ef2e940abd2d47c4ac3ca224365387b7f37 /include/routing.h
parent8b04940d2f28290451db439ad29155a0b8771ba3 (diff)
downloadcrow-3081e4e1a82a4efd8feff68850c4cc04af230cd7.tar.gz
crow-3081e4e1a82a4efd8feff68850c4cc04af230cd7.zip
Cleanup include folder into crow subfolder
- only crow.h is exposed now
Diffstat (limited to 'include/routing.h')
-rw-r--r--include/routing.h1056
1 files changed, 0 insertions, 1056 deletions
diff --git a/include/routing.h b/include/routing.h
deleted file mode 100644
index 337d258..0000000
--- a/include/routing.h
+++ /dev/null
@@ -1,1056 +0,0 @@
-#pragma once
-
-#include <cstdint>
-#include <utility>
-#include <tuple>
-#include <unordered_map>
-#include <memory>
-#include <boost/lexical_cast.hpp>
-#include <vector>
-
-#include "common.h"
-#include "http_response.h"
-#include "http_request.h"
-#include "utility.h"
-#include "logging.h"
-#include "websocket.h"
-
-namespace crow
-{
- class BaseRule
- {
- public:
- BaseRule(std::string rule)
- : rule_(std::move(rule))
- {
- }
-
- virtual ~BaseRule()
- {
- }
-
- virtual void validate() = 0;
- std::unique_ptr<BaseRule> upgrade()
- {
- if (rule_to_upgrade_)
- return std::move(rule_to_upgrade_);
- return {};
- }
-
- virtual void handle(const request&, response&, const routing_params&) = 0;
- virtual void handle_upgrade(const request&, response& res, SocketAdaptor&&)
- {
- res = response(404);
- res.end();
- }
-#ifdef CROW_ENABLE_SSL
- virtual void handle_upgrade(const request&, response& res, SSLAdaptor&&)
- {
- res = response(404);
- res.end();
- }
-#endif
-
- uint32_t get_methods()
- {
- return methods_;
- }
-
- protected:
- uint32_t methods_{1<<(int)HTTPMethod::Get};
-
- std::string rule_;
- std::string name_;
-
- std::unique_ptr<BaseRule> rule_to_upgrade_;
-
- friend class Router;
- template <typename T>
- friend struct RuleParameterTraits;
- };
-
-
- namespace detail
- {
- namespace routing_handler_call_helper
- {
- template <typename T, int Pos>
- struct call_pair
- {
- using type = T;
- static const int pos = Pos;
- };
-
- template <typename H1>
- struct call_params
- {
- H1& handler;
- const routing_params& params;
- const request& req;
- response& res;
- };
-
- template <typename F, int NInt, int NUint, int NDouble, int NString, typename S1, typename S2>
- struct call
- {
- };
-
- template <typename F, int NInt, int NUint, int NDouble, int NString, typename ... Args1, typename ... Args2>
- struct call<F, NInt, NUint, NDouble, NString, black_magic::S<int64_t, Args1...>, black_magic::S<Args2...>>
- {
- void operator()(F cparams)
- {
- using pushed = typename black_magic::S<Args2...>::template push_back<call_pair<int64_t, NInt>>;
- call<F, NInt+1, NUint, NDouble, NString,
- black_magic::S<Args1...>, pushed>()(cparams);
- }
- };
-
- template <typename F, int NInt, int NUint, int NDouble, int NString, typename ... Args1, typename ... Args2>
- struct call<F, NInt, NUint, NDouble, NString, black_magic::S<uint64_t, Args1...>, black_magic::S<Args2...>>
- {
- void operator()(F cparams)
- {
- using pushed = typename black_magic::S<Args2...>::template push_back<call_pair<uint64_t, NUint>>;
- call<F, NInt, NUint+1, NDouble, NString,
- black_magic::S<Args1...>, pushed>()(cparams);
- }
- };
-
- template <typename F, int NInt, int NUint, int NDouble, int NString, typename ... Args1, typename ... Args2>
- struct call<F, NInt, NUint, NDouble, NString, black_magic::S<double, Args1...>, black_magic::S<Args2...>>
- {
- void operator()(F cparams)
- {
- using pushed = typename black_magic::S<Args2...>::template push_back<call_pair<double, NDouble>>;
- call<F, NInt, NUint, NDouble+1, NString,
- black_magic::S<Args1...>, pushed>()(cparams);
- }
- };
-
- template <typename F, int NInt, int NUint, int NDouble, int NString, typename ... Args1, typename ... Args2>
- struct call<F, NInt, NUint, NDouble, NString, black_magic::S<std::string, Args1...>, black_magic::S<Args2...>>
- {
- void operator()(F cparams)
- {
- using pushed = typename black_magic::S<Args2...>::template push_back<call_pair<std::string, NString>>;
- call<F, NInt, NUint, NDouble, NString+1,
- black_magic::S<Args1...>, pushed>()(cparams);
- }
- };
-
- template <typename F, int NInt, int NUint, int NDouble, int NString, typename ... Args1>
- struct call<F, NInt, NUint, NDouble, NString, black_magic::S<>, black_magic::S<Args1...>>
- {
- void operator()(F cparams)
- {
- cparams.handler(
- cparams.req,
- cparams.res,
- cparams.params.template get<typename Args1::type>(Args1::pos)...
- );
- }
- };
-
- template <typename Func, typename ... ArgsWrapped>
- struct Wrapped
- {
- template <typename ... Args>
- void set(Func f, typename std::enable_if<
- !std::is_same<typename std::tuple_element<0, std::tuple<Args..., void>>::type, const request&>::value
- , int>::type = 0)
- {
- handler_ = (
-#ifdef CROW_CAN_USE_CPP14
- [f = std::move(f)]
-#else
- [f]
-#endif
- (const request&, response& res, Args... args){
- res = response(f(args...));
- res.end();
- });
- }
-
- template <typename Req, typename ... Args>
- struct req_handler_wrapper
- {
- req_handler_wrapper(Func f)
- : f(std::move(f))
- {
- }
-
- void operator()(const request& req, response& res, Args... args)
- {
- res = response(f(req, args...));
- res.end();
- }
-
- Func f;
- };
-
- template <typename ... Args>
- void set(Func f, typename std::enable_if<
- std::is_same<typename std::tuple_element<0, std::tuple<Args..., void>>::type, const request&>::value &&
- !std::is_same<typename std::tuple_element<1, std::tuple<Args..., void, void>>::type, response&>::value
- , int>::type = 0)
- {
- handler_ = req_handler_wrapper<Args...>(std::move(f));
- /*handler_ = (
- [f = std::move(f)]
- (const request& req, response& res, Args... args){
- res = response(f(req, args...));
- res.end();
- });*/
- }
-
- template <typename ... Args>
- void set(Func f, typename std::enable_if<
- std::is_same<typename std::tuple_element<0, std::tuple<Args..., void>>::type, const request&>::value &&
- std::is_same<typename std::tuple_element<1, std::tuple<Args..., void, void>>::type, response&>::value
- , int>::type = 0)
- {
- handler_ = std::move(f);
- }
-
- template <typename ... Args>
- struct handler_type_helper
- {
- using type = std::function<void(const crow::request&, crow::response&, Args...)>;
- using args_type = black_magic::S<typename black_magic::promote_t<Args>...>;
- };
-
- template <typename ... Args>
- struct handler_type_helper<const request&, Args...>
- {
- using type = std::function<void(const crow::request&, crow::response&, Args...)>;
- using args_type = black_magic::S<typename black_magic::promote_t<Args>...>;
- };
-
- template <typename ... Args>
- struct handler_type_helper<const request&, response&, Args...>
- {
- using type = std::function<void(const crow::request&, crow::response&, Args...)>;
- using args_type = black_magic::S<typename black_magic::promote_t<Args>...>;
- };
-
- typename handler_type_helper<ArgsWrapped...>::type handler_;
-
- void operator()(const request& req, response& res, const routing_params& params)
- {
- detail::routing_handler_call_helper::call<
- detail::routing_handler_call_helper::call_params<
- decltype(handler_)>,
- 0, 0, 0, 0,
- typename handler_type_helper<ArgsWrapped...>::args_type,
- black_magic::S<>
- >()(
- detail::routing_handler_call_helper::call_params<
- decltype(handler_)>
- {handler_, params, req, res}
- );
- }
- };
-
- }
- }
-
- class WebSocketRule : public BaseRule
- {
- using self_t = WebSocketRule;
- public:
- WebSocketRule(std::string rule)
- : BaseRule(std::move(rule))
- {
- }
-
- void validate() override
- {
- }
-
- void handle(const request&, response& res, const routing_params&) override
- {
- res = response(404);
- res.end();
- }
-
- void handle_upgrade(const request& req, response&, SocketAdaptor&& adaptor) override
- {
- new crow::websocket::Connection<SocketAdaptor>(req, std::move(adaptor), open_handler_, message_handler_, close_handler_, error_handler_);
- }
-#ifdef CROW_ENABLE_SSL
- void handle_upgrade(const request& req, response&, SSLAdaptor&& adaptor) override
- {
- new crow::websocket::Connection<SSLAdaptor>(req, std::move(adaptor), open_handler_, message_handler_, close_handler_, error_handler_);
- }
-#endif
-
- template <typename Func>
- self_t& onopen(Func f)
- {
- open_handler_ = f;
- return *this;
- }
-
- template <typename Func>
- self_t& onmessage(Func f)
- {
- message_handler_ = f;
- return *this;
- }
-
- template <typename Func>
- self_t& onclose(Func f)
- {
- close_handler_ = f;
- return *this;
- }
-
- template <typename Func>
- self_t& onerror(Func f)
- {
- error_handler_ = f;
- return *this;
- }
-
- protected:
- std::function<void(crow::websocket::connection&)> open_handler_;
- std::function<void(crow::websocket::connection&, const std::string&, bool)> message_handler_;
- std::function<void(crow::websocket::connection&, const std::string&)> close_handler_;
- std::function<void(crow::websocket::connection&)> error_handler_;
- };
-
- template <typename T>
- struct RuleParameterTraits
- {
- using self_t = T;
- WebSocketRule& websocket()
- {
- auto p =new WebSocketRule(((self_t*)this)->rule_);
- ((self_t*)this)->rule_to_upgrade_.reset(p);
- return *p;
- }
-
- self_t& name(std::string name) noexcept
- {
- ((self_t*)this)->name_ = std::move(name);
- return (self_t&)*this;
- }
-
- self_t& methods(HTTPMethod method)
- {
- ((self_t*)this)->methods_ = 1 << (int)method;
- return (self_t&)*this;
- }
-
- template <typename ... MethodArgs>
- self_t& methods(HTTPMethod method, MethodArgs ... args_method)
- {
- methods(args_method...);
- ((self_t*)this)->methods_ |= 1 << (int)method;
- return (self_t&)*this;
- }
-
- };
-
- class DynamicRule : public BaseRule, public RuleParameterTraits<DynamicRule>
- {
- public:
-
- DynamicRule(std::string rule)
- : BaseRule(std::move(rule))
- {
- }
-
- void validate() override
- {
- if (!erased_handler_)
- {
- throw std::runtime_error(name_ + (!name_.empty() ? ": " : "") + "no handler for url " + rule_);
- }
- }
-
- void handle(const request& req, response& res, const routing_params& params) override
- {
- erased_handler_(req, res, params);
- }
-
- template <typename Func>
- void operator()(Func f)
- {
-#ifdef CROW_MSVC_WORKAROUND
- using function_t = utility::function_traits<decltype(&Func::operator())>;
-#else
- using function_t = utility::function_traits<Func>;
-#endif
- erased_handler_ = wrap(std::move(f), black_magic::gen_seq<function_t::arity>());
- }
-
- // enable_if Arg1 == request && Arg2 == response
- // enable_if Arg1 == request && Arg2 != resposne
- // enable_if Arg1 != request
-#ifdef CROW_MSVC_WORKAROUND
- template <typename Func, size_t ... Indices>
-#else
- template <typename Func, unsigned ... Indices>
-#endif
- std::function<void(const request&, response&, const routing_params&)>
- wrap(Func f, black_magic::seq<Indices...>)
- {
-#ifdef CROW_MSVC_WORKAROUND
- using function_t = utility::function_traits<decltype(&Func::operator())>;
-#else
- using function_t = utility::function_traits<Func>;
-#endif
- if (!black_magic::is_parameter_tag_compatible(
- black_magic::get_parameter_tag_runtime(rule_.c_str()),
- black_magic::compute_parameter_tag_from_args_list<
- typename function_t::template arg<Indices>...>::value))
- {
- throw std::runtime_error("route_dynamic: Handler type is mismatched with URL parameters: " + rule_);
- }
- auto ret = detail::routing_handler_call_helper::Wrapped<Func, typename function_t::template arg<Indices>...>();
- ret.template set<
- typename function_t::template arg<Indices>...
- >(std::move(f));
- return ret;
- }
-
- template <typename Func>
- void operator()(std::string name, Func&& f)
- {
- name_ = std::move(name);
- (*this).template operator()<Func>(std::forward(f));
- }
- private:
- std::function<void(const request&, response&, const routing_params&)> erased_handler_;
-
- };
-
- template <typename ... Args>
- class TaggedRule : public BaseRule, public RuleParameterTraits<TaggedRule<Args...>>
- {
- public:
- using self_t = TaggedRule<Args...>;
-
- TaggedRule(std::string rule)
- : BaseRule(std::move(rule))
- {
- }
-
- void validate() override
- {
- if (!handler_)
- {
- throw std::runtime_error(name_ + (!name_.empty() ? ": " : "") + "no handler for url " + rule_);
- }
- }
-
- template <typename Func>
- typename std::enable_if<black_magic::CallHelper<Func, black_magic::S<Args...>>::value, void>::type
- operator()(Func&& f)
- {
- static_assert(black_magic::CallHelper<Func, black_magic::S<Args...>>::value ||
- black_magic::CallHelper<Func, black_magic::S<crow::request, Args...>>::value ,
- "Handler type is mismatched with URL parameters");
- static_assert(!std::is_same<void, decltype(f(std::declval<Args>()...))>::value,
- "Handler function cannot have void return type; valid return types: string, int, crow::resposne, crow::json::wvalue");
-
- handler_ = [f = std::move(f)](const request&, response& res, Args ... args){
- res = response(f(args...));
- res.end();
- };
- }
-
- template <typename Func>
- typename std::enable_if<
- !black_magic::CallHelper<Func, black_magic::S<Args...>>::value &&
- black_magic::CallHelper<Func, black_magic::S<crow::request, Args...>>::value,
- void>::type
- operator()(Func&& f)
- {
- static_assert(black_magic::CallHelper<Func, black_magic::S<Args...>>::value ||
- black_magic::CallHelper<Func, black_magic::S<crow::request, Args...>>::value,
- "Handler type is mismatched with URL parameters");
- static_assert(!std::is_same<void, decltype(f(std::declval<crow::request>(), std::declval<Args>()...))>::value,
- "Handler function cannot have void return type; valid return types: string, int, crow::resposne, crow::json::wvalue");
-
- handler_ = [f = std::move(f)](const crow::request& req, crow::response& res, Args ... args){
- res = response(f(req, args...));
- res.end();
- };
- }
-
- template <typename Func>
- typename std::enable_if<
- !black_magic::CallHelper<Func, black_magic::S<Args...>>::value &&
- !black_magic::CallHelper<Func, black_magic::S<crow::request, Args...>>::value,
- void>::type
- operator()(Func&& f)
- {
- static_assert(black_magic::CallHelper<Func, black_magic::S<Args...>>::value ||
- black_magic::CallHelper<Func, black_magic::S<crow::request, Args...>>::value ||
- black_magic::CallHelper<Func, black_magic::S<crow::request, crow::response&, Args...>>::value
- ,
- "Handler type is mismatched with URL parameters");
- static_assert(std::is_same<void, decltype(f(std::declval<crow::request>(), std::declval<crow::response&>(), std::declval<Args>()...))>::value,
- "Handler function with response argument should have void return type");
-
- handler_ = std::move(f);
- }
-
- template <typename Func>
- void operator()(std::string name, Func&& f)
- {
- name_ = std::move(name);
- (*this).template operator()<Func>(std::forward(f));
- }
-
- void handle(const request& req, response& res, const routing_params& params) override
- {
- detail::routing_handler_call_helper::call<
- detail::routing_handler_call_helper::call_params<
- decltype(handler_)>,
- 0, 0, 0, 0,
- black_magic::S<Args...>,
- black_magic::S<>
- >()(
- detail::routing_handler_call_helper::call_params<
- decltype(handler_)>
- {handler_, params, req, res}
- );
- }
-
- private:
- std::function<void(const crow::request&, crow::response&, Args...)> handler_;
-
- };
-
- const int RULE_SPECIAL_REDIRECT_SLASH = 1;
-
- class Trie
- {
- public:
- struct Node
- {
- unsigned rule_index{};
- std::array<unsigned, (int)ParamType::MAX> param_childrens{};
- std::unordered_map<std::string, unsigned> children;
-
- bool IsSimpleNode() const
- {
- return
- !rule_index &&
- std::all_of(
- std::begin(param_childrens),
- std::end(param_childrens),
- [](unsigned x){ return !x; });
- }
- };
-
- Trie() : nodes_(1)
- {
- }
-
-private:
- void optimizeNode(Node* node)
- {
- for(auto x : node->param_childrens)
- {
- if (!x)
- continue;
- Node* child = &nodes_[x];
- optimizeNode(child);
- }
- if (node->children.empty())
- return;
- bool mergeWithChild = true;
- for(auto& kv : node->children)
- {
- Node* child = &nodes_[kv.second];
- if (!child->IsSimpleNode())
- {
- mergeWithChild = false;
- break;
- }
- }
- if (mergeWithChild)
- {
- decltype(node->children) merged;
- for(auto& kv : node->children)
- {
- Node* child = &nodes_[kv.second];
- for(auto& child_kv : child->children)
- {
- merged[kv.first + child_kv.first] = child_kv.second;
- }
- }
- node->children = std::move(merged);
- optimizeNode(node);
- }
- else
- {
- for(auto& kv : node->children)
- {
- Node* child = &nodes_[kv.second];
- optimizeNode(child);
- }
- }
- }
-
- void optimize()
- {
- optimizeNode(head());
- }
-
-public:
- void validate()
- {
- if (!head()->IsSimpleNode())
- throw std::runtime_error("Internal error: Trie header should be simple!");
- optimize();
- }
-
- std::pair<unsigned, routing_params> find(const std::string& req_url, const Node* node = nullptr, unsigned pos = 0, routing_params* params = nullptr) const
- {
- routing_params empty;
- if (params == nullptr)
- params = &empty;
-
- unsigned found{};
- routing_params match_params;
-
- if (node == nullptr)
- node = head();
- if (pos == req_url.size())
- return {node->rule_index, *params};
-
- auto update_found = [&found, &match_params](std::pair<unsigned, routing_params>& ret)
- {
- if (ret.first && (!found || found > ret.first))
- {
- found = ret.first;
- match_params = std::move(ret.second);
- }
- };
-
- if (node->param_childrens[(int)ParamType::INT])
- {
- char c = req_url[pos];
- if ((c >= '0' && c <= '9') || c == '+' || c == '-')
- {
- char* eptr;
- errno = 0;
- long long int value = strtoll(req_url.data()+pos, &eptr, 10);
- if (errno != ERANGE && eptr != req_url.data()+pos)
- {
- params->int_params.push_back(value);
- auto ret = find(req_url, &nodes_[node->param_childrens[(int)ParamType::INT]], eptr - req_url.data(), params);
- update_found(ret);
- params->int_params.pop_back();
- }
- }
- }
-
- if (node->param_childrens[(int)ParamType::UINT])
- {
- char c = req_url[pos];
- if ((c >= '0' && c <= '9') || c == '+')
- {
- char* eptr;
- errno = 0;
- unsigned long long int value = strtoull(req_url.data()+pos, &eptr, 10);
- if (errno != ERANGE && eptr != req_url.data()+pos)
- {
- params->uint_params.push_back(value);
- auto ret = find(req_url, &nodes_[node->param_childrens[(int)ParamType::UINT]], eptr - req_url.data(), params);
- update_found(ret);
- params->uint_params.pop_back();
- }
- }
- }
-
- if (node->param_childrens[(int)ParamType::DOUBLE])
- {
- char c = req_url[pos];
- if ((c >= '0' && c <= '9') || c == '+' || c == '-' || c == '.')
- {
- char* eptr;
- errno = 0;
- double value = strtod(req_url.data()+pos, &eptr);
- if (errno != ERANGE && eptr != req_url.data()+pos)
- {
- params->double_params.push_back(value);
- auto ret = find(req_url, &nodes_[node->param_childrens[(int)ParamType::DOUBLE]], eptr - req_url.data(), params);
- update_found(ret);
- params->double_params.pop_back();
- }
- }
- }
-
- if (node->param_childrens[(int)ParamType::STRING])
- {
- size_t epos = pos;
- for(; epos < req_url.size(); epos ++)
- {
- if (req_url[epos] == '/')
- break;
- }
-
- if (epos != pos)
- {
- params->string_params.push_back(req_url.substr(pos, epos-pos));
- auto ret = find(req_url, &nodes_[node->param_childrens[(int)ParamType::STRING]], epos, params);
- update_found(ret);
- params->string_params.pop_back();
- }
- }
-
- if (node->param_childrens[(int)ParamType::PATH])
- {
- size_t epos = req_url.size();
-
- if (epos != pos)
- {
- params->string_params.push_back(req_url.substr(pos, epos-pos));
- auto ret = find(req_url, &nodes_[node->param_childrens[(int)ParamType::PATH]], epos, params);
- update_found(ret);
- params->string_params.pop_back();
- }
- }
-
- for(auto& kv : node->children)
- {
- const std::string& fragment = kv.first;
- const Node* child = &nodes_[kv.second];
-
- if (req_url.compare(pos, fragment.size(), fragment) == 0)
- {
- auto ret = find(req_url, child, pos + fragment.size(), params);
- update_found(ret);
- }
- }
-
- return {found, match_params};
- }
-
- void add(const std::string& url, unsigned rule_index)
- {
- unsigned idx{0};
-
- for(unsigned i = 0; i < url.size(); i ++)
- {
- char c = url[i];
- if (c == '<')
- {
- static struct ParamTraits
- {
- ParamType type;
- std::string name;
- } paramTraits[] =
- {
- { ParamType::INT, "<int>" },
- { ParamType::UINT, "<uint>" },
- { ParamType::DOUBLE, "<float>" },
- { ParamType::DOUBLE, "<double>" },
- { ParamType::STRING, "<str>" },
- { ParamType::STRING, "<string>" },
- { ParamType::PATH, "<path>" },
- };
-
- for(auto& x:paramTraits)
- {
- if (url.compare(i, x.name.size(), x.name) == 0)
- {
- if (!nodes_[idx].param_childrens[(int)x.type])
- {
- auto new_node_idx = new_node();
- nodes_[idx].param_childrens[(int)x.type] = new_node_idx;
- }
- idx = nodes_[idx].param_childrens[(int)x.type];
- i += x.name.size();
- break;
- }
- }
-
- i --;
- }
- else
- {
- std::string piece(&c, 1);
- if (!nodes_[idx].children.count(piece))
- {
- auto new_node_idx = new_node();
- nodes_[idx].children.emplace(piece, new_node_idx);
- }
- idx = nodes_[idx].children[piece];
- }
- }
- if (nodes_[idx].rule_index)
- throw std::runtime_error("handler already exists for " + url);
- nodes_[idx].rule_index = rule_index;
- }
- private:
- void debug_node_print(Node* n, int level)
- {
- for(int i = 0; i < (int)ParamType::MAX; i ++)
- {
- if (n->param_childrens[i])
- {
- CROW_LOG_DEBUG << std::string(2*level, ' ') /*<< "("<<n->param_childrens[i]<<") "*/;
- switch((ParamType)i)
- {
- case ParamType::INT:
- CROW_LOG_DEBUG << "<int>";
- break;
- case ParamType::UINT:
- CROW_LOG_DEBUG << "<uint>";
- break;
- case ParamType::DOUBLE:
- CROW_LOG_DEBUG << "<float>";
- break;
- case ParamType::STRING:
- CROW_LOG_DEBUG << "<str>";
- break;
- case ParamType::PATH:
- CROW_LOG_DEBUG << "<path>";
- break;
- default:
- CROW_LOG_DEBUG << "<ERROR>";
- break;
- }
-
- debug_node_print(&nodes_[n->param_childrens[i]], level+1);
- }
- }
- for(auto& kv : n->children)
- {
- CROW_LOG_DEBUG << std::string(2*level, ' ') /*<< "(" << kv.second << ") "*/ << kv.first;
- debug_node_print(&nodes_[kv.second], level+1);
- }
- }
-
- public:
- void debug_print()
- {
- debug_node_print(head(), 0);
- }
-
- private:
- const Node* head() const
- {
- return &nodes_.front();
- }
-
- Node* head()
- {
- return &nodes_.front();
- }
-
- unsigned new_node()
- {
- nodes_.resize(nodes_.size()+1);
- return nodes_.size() - 1;
- }
-
- std::vector<Node> nodes_;
- };
-
- class Router
- {
- public:
- Router() : rules_(2)
- {
- }
-
- DynamicRule& new_rule_dynamic(const std::string& rule)
- {
- auto ruleObject = new DynamicRule(rule);
-
- internal_add_rule_object(rule, ruleObject);
-
- return *ruleObject;
- }
-
- template <uint64_t N>
- typename black_magic::arguments<N>::type::template rebind<TaggedRule>& new_rule_tagged(const std::string& rule)
- {
- using RuleT = typename black_magic::arguments<N>::type::template rebind<TaggedRule>;
- auto ruleObject = new RuleT(rule);
-
- internal_add_rule_object(rule, ruleObject);
-
- return *ruleObject;
- }
-
- void internal_add_rule_object(const std::string& rule, BaseRule* ruleObject)
- {
- rules_.emplace_back(ruleObject);
- trie_.add(rule, rules_.size() - 1);
-
- // directory case:
- // request to `/about' url matches `/about/' rule
- if (rule.size() > 1 && rule.back() == '/')
- {
- std::string rule_without_trailing_slash = rule;
- rule_without_trailing_slash.pop_back();
- trie_.add(rule_without_trailing_slash, RULE_SPECIAL_REDIRECT_SLASH);
- }
- }
-
- void validate()
- {
- trie_.validate();
- for(auto& rule:rules_)
- {
- if (rule)
- {
- auto upgraded = rule->upgrade();
- if (upgraded)
- rule = std::move(upgraded);
- rule->validate();
- }
- }
- }
-
- template <typename Adaptor>
- void handle_upgrade(const request& req, response& res, Adaptor&& adaptor)
- {
- auto found = trie_.find(req.url);
- unsigned rule_index = found.first;
- if (!rule_index)
- {
- CROW_LOG_DEBUG << "Cannot match rules " << req.url;
- res = response(404);
- res.end();
- return;
- }
-
- if (rule_index >= rules_.size())
- throw std::runtime_error("Trie internal structure corrupted!");
-
- if (rule_index == RULE_SPECIAL_REDIRECT_SLASH)
- {
- CROW_LOG_INFO << "Redirecting to a url with trailing slash: " << req.url;
- res = response(301);
-
- // TODO absolute url building
- if (req.get_header_value("Host").empty())
- {
- res.add_header("Location", req.url + "/");
- }
- else
- {
- res.add_header("Location", "http://" + req.get_header_value("Host") + req.url + "/");
- }
- res.end();
- return;
- }
-
- if ((rules_[rule_index]->get_methods() & (1<<(uint32_t)req.method)) == 0)
- {
- CROW_LOG_DEBUG << "Rule found but method mismatch: " << req.url << " with " << method_name(req.method) << "(" << (uint32_t)req.method << ") / " << rules_[rule_index]->get_methods();
- res = response(404);
- res.end();
- return;
- }
-
- CROW_LOG_DEBUG << "Matched rule (upgrade) '" << rules_[rule_index]->rule_ << "' " << (uint32_t)req.method << " / " << rules_[rule_index]->get_methods();
-
- // any uncaught exceptions become 500s
- try
- {
- rules_[rule_index]->handle_upgrade(req, res, std::move(adaptor));
- }
- catch(std::exception& e)
- {
- CROW_LOG_ERROR << "An uncaught exception occurred: " << e.what();
- res = response(500);
- res.end();
- return;
- }
- catch(...)
- {
- CROW_LOG_ERROR << "An uncaught exception occurred. The type was unknown so no information was available.";
- res = response(500);
- res.end();
- return;
- }
- }
-
- void handle(const request& req, response& res)
- {
- auto found = trie_.find(req.url);
-
- unsigned rule_index = found.first;
-
- if (!rule_index)
- {
- CROW_LOG_DEBUG << "Cannot match rules " << req.url;
- res = response(404);
- res.end();
- return;
- }
-
- if (rule_index >= rules_.size())
- throw std::runtime_error("Trie internal structure corrupted!");
-
- if (rule_index == RULE_SPECIAL_REDIRECT_SLASH)
- {
- CROW_LOG_INFO << "Redirecting to a url with trailing slash: " << req.url;
- res = response(301);
-
- // TODO absolute url building
- if (req.get_header_value("Host").empty())
- {
- res.add_header("Location", req.url + "/");
- }
- else
- {
- res.add_header("Location", "http://" + req.get_header_value("Host") + req.url + "/");
- }
- res.end();
- return;
- }
-
- if ((rules_[rule_index]->get_methods() & (1<<(uint32_t)req.method)) == 0)
- {
- CROW_LOG_DEBUG << "Rule found but method mismatch: " << req.url << " with " << method_name(req.method) << "(" << (uint32_t)req.method << ") / " << rules_[rule_index]->get_methods();
- res = response(404);
- res.end();
- return;
- }
-
- CROW_LOG_DEBUG << "Matched rule '" << rules_[rule_index]->rule_ << "' " << (uint32_t)req.method << " / " << rules_[rule_index]->get_methods();
-
- // any uncaught exceptions become 500s
- try
- {
- rules_[rule_index]->handle(req, res, found.second);
- }
- catch(std::exception& e)
- {
- CROW_LOG_ERROR << "An uncaught exception occurred: " << e.what();
- res = response(500);
- res.end();
- return;
- }
- catch(...)
- {
- CROW_LOG_ERROR << "An uncaught exception occurred. The type was unknown so no information was available.";
- res = response(500);
- res.end();
- return;
- }
- }
-
- void debug_print()
- {
- trie_.debug_print();
- }
-
- private:
- std::vector<std::unique_ptr<BaseRule>> rules_;
- Trie trie_;
- };
-}