2014-04-02 16:38:08 +00:00
|
|
|
#pragma once
|
|
|
|
|
|
|
|
#include <cstdint>
|
2014-04-02 20:31:32 +00:00
|
|
|
#include <utility>
|
|
|
|
#include <string>
|
|
|
|
#include <tuple>
|
2014-04-10 16:43:33 +00:00
|
|
|
#include <unordered_map>
|
2014-04-02 16:38:08 +00:00
|
|
|
|
2014-04-09 23:17:08 +00:00
|
|
|
#include "http_response.h"
|
2014-04-02 16:38:08 +00:00
|
|
|
|
2014-04-10 16:43:33 +00:00
|
|
|
//TEST
|
|
|
|
#include <iostream>
|
|
|
|
|
2014-04-02 16:38:08 +00:00
|
|
|
namespace flask
|
|
|
|
{
|
2014-04-09 23:17:08 +00:00
|
|
|
class Rule
|
2014-04-02 16:38:08 +00:00
|
|
|
{
|
2014-04-09 23:17:08 +00:00
|
|
|
public:
|
2014-04-10 16:43:33 +00:00
|
|
|
explicit Rule(std::string rule)
|
2014-04-09 23:17:08 +00:00
|
|
|
: rule_(std::move(rule))
|
2014-04-02 16:38:08 +00:00
|
|
|
{
|
|
|
|
}
|
2014-04-09 23:17:08 +00:00
|
|
|
|
|
|
|
template <typename Func>
|
|
|
|
void operator()(Func&& f)
|
2014-04-02 16:38:08 +00:00
|
|
|
{
|
2014-04-09 23:17:08 +00:00
|
|
|
handler_ = [f = std::move(f)]{
|
|
|
|
return response(f());
|
|
|
|
};
|
2014-04-02 16:38:08 +00:00
|
|
|
}
|
|
|
|
|
2014-04-09 23:17:08 +00:00
|
|
|
template <typename Func>
|
2014-04-10 16:43:33 +00:00
|
|
|
void operator()(std::string name, Func&& f)
|
2014-04-02 20:31:32 +00:00
|
|
|
{
|
2014-04-09 23:17:08 +00:00
|
|
|
name_ = std::move(name);
|
|
|
|
handler_ = [f = std::move(f)]{
|
|
|
|
return response(f());
|
|
|
|
};
|
2014-04-02 20:31:32 +00:00
|
|
|
}
|
|
|
|
|
2014-04-09 23:17:08 +00:00
|
|
|
bool match(const request& req)
|
2014-04-02 16:38:08 +00:00
|
|
|
{
|
2014-04-09 23:17:08 +00:00
|
|
|
// FIXME need url parsing
|
|
|
|
return req.url == rule_;
|
2014-04-02 16:38:08 +00:00
|
|
|
}
|
|
|
|
|
2014-04-10 16:43:33 +00:00
|
|
|
Rule& name(std::string name)
|
2014-04-02 20:31:32 +00:00
|
|
|
{
|
2014-04-10 16:43:33 +00:00
|
|
|
name_ = std::move(name);
|
2014-04-09 23:17:08 +00:00
|
|
|
return *this;
|
2014-04-02 20:31:32 +00:00
|
|
|
}
|
2014-04-10 16:43:33 +00:00
|
|
|
|
2014-04-09 23:17:08 +00:00
|
|
|
void validate()
|
2014-04-02 20:31:32 +00:00
|
|
|
{
|
2014-04-09 23:17:08 +00:00
|
|
|
if (!handler_)
|
2014-04-02 20:31:32 +00:00
|
|
|
{
|
2014-04-10 16:43:33 +00:00
|
|
|
throw std::runtime_error(name_ + (!name_.empty() ? ": " : "") + "no handler for url " + rule_);
|
2014-04-02 20:31:32 +00:00
|
|
|
}
|
2014-04-09 23:17:08 +00:00
|
|
|
}
|
2014-04-02 20:31:32 +00:00
|
|
|
|
2014-04-09 23:17:08 +00:00
|
|
|
response handle(const request&)
|
2014-04-02 20:31:32 +00:00
|
|
|
{
|
2014-04-09 23:17:08 +00:00
|
|
|
return handler_();
|
2014-04-02 20:31:32 +00:00
|
|
|
}
|
|
|
|
|
2014-04-09 23:17:08 +00:00
|
|
|
private:
|
|
|
|
std::string rule_;
|
|
|
|
std::string name_;
|
|
|
|
std::function<response()> handler_;
|
|
|
|
};
|
2014-04-02 16:38:08 +00:00
|
|
|
|
2014-04-10 16:43:33 +00:00
|
|
|
constexpr const size_t INVALID_RULE_INDEX{static_cast<size_t>(-1)};
|
|
|
|
class Trie
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
struct Node
|
|
|
|
{
|
|
|
|
std::unordered_map<std::string, size_t> children;
|
|
|
|
size_t rule_index{INVALID_RULE_INDEX};
|
|
|
|
};
|
|
|
|
|
|
|
|
Trie() : nodes_(1)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
void optimize()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
size_t find(const request& req, const Node* node = nullptr, size_t pos = 0) const
|
|
|
|
{
|
|
|
|
size_t found = INVALID_RULE_INDEX;
|
|
|
|
|
|
|
|
if (node == nullptr)
|
|
|
|
node = head();
|
|
|
|
if (pos == req.url.size())
|
|
|
|
return node->rule_index;
|
|
|
|
|
|
|
|
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)
|
|
|
|
{
|
|
|
|
size_t ret = find(req, child, pos + fragment.size());
|
|
|
|
if (ret != INVALID_RULE_INDEX && (found == INVALID_RULE_INDEX || found > ret))
|
|
|
|
{
|
|
|
|
found = ret;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return found;
|
|
|
|
}
|
|
|
|
|
|
|
|
void add(const std::string& url, size_t rule_index)
|
|
|
|
{
|
|
|
|
size_t idx = 0;
|
|
|
|
for(char c:url)
|
|
|
|
{
|
|
|
|
std::string piece(&c, 1);
|
|
|
|
//std::string piece("/");
|
|
|
|
if (!nodes_[idx].children.count(piece))
|
|
|
|
{
|
|
|
|
nodes_[idx].children.emplace(piece, new_node());
|
|
|
|
}
|
|
|
|
idx = nodes_[idx].children[piece];
|
|
|
|
}
|
|
|
|
if (nodes_[idx].rule_index != INVALID_RULE_INDEX)
|
|
|
|
throw std::runtime_error("handler already exists for " + url);
|
|
|
|
nodes_[idx].rule_index = rule_index;
|
|
|
|
}
|
|
|
|
private:
|
|
|
|
const Node* head() const
|
|
|
|
{
|
|
|
|
return &nodes_.front();
|
|
|
|
}
|
|
|
|
|
|
|
|
Node* head()
|
|
|
|
{
|
|
|
|
return &nodes_.front();
|
|
|
|
}
|
|
|
|
|
|
|
|
size_t new_node()
|
|
|
|
{
|
|
|
|
nodes_.resize(nodes_.size()+1);
|
|
|
|
return nodes_.size() - 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::vector<Node> nodes_;
|
|
|
|
};
|
|
|
|
|
2014-04-02 16:38:08 +00:00
|
|
|
class Router
|
|
|
|
{
|
|
|
|
public:
|
2014-04-10 16:43:33 +00:00
|
|
|
Rule& new_rule(const std::string& rule)
|
2014-04-09 23:17:08 +00:00
|
|
|
{
|
2014-04-10 16:43:33 +00:00
|
|
|
rules_.emplace_back(rule);
|
|
|
|
trie_.add(rule, rules_.size() - 1);
|
2014-04-09 23:17:08 +00:00
|
|
|
return rules_.back();
|
|
|
|
}
|
|
|
|
|
|
|
|
void validate()
|
2014-04-02 20:31:32 +00:00
|
|
|
{
|
2014-04-10 16:43:33 +00:00
|
|
|
trie_.optimize();
|
2014-04-09 23:17:08 +00:00
|
|
|
for(auto& rule:rules_)
|
|
|
|
{
|
|
|
|
rule.validate();
|
|
|
|
}
|
2014-04-02 20:31:32 +00:00
|
|
|
}
|
|
|
|
|
2014-04-09 23:17:08 +00:00
|
|
|
response handle(const request& req)
|
2014-04-02 16:38:08 +00:00
|
|
|
{
|
2014-04-10 16:43:33 +00:00
|
|
|
size_t rule_index = trie_.find(req);
|
|
|
|
|
|
|
|
if (rule_index == INVALID_RULE_INDEX)
|
|
|
|
return response(404);
|
|
|
|
|
|
|
|
if (rule_index >= rules_.size())
|
|
|
|
throw std::runtime_error("Trie internal structure corrupted!");
|
|
|
|
|
|
|
|
return rules_[rule_index].handle(req);
|
2014-04-02 16:38:08 +00:00
|
|
|
}
|
2014-04-02 20:31:32 +00:00
|
|
|
private:
|
2014-04-09 23:17:08 +00:00
|
|
|
std::vector<Rule> rules_;
|
2014-04-10 16:43:33 +00:00
|
|
|
Trie trie_;
|
2014-04-02 16:38:08 +00:00
|
|
|
};
|
|
|
|
}
|