Merge branch 'master'

This commit is contained in:
The-EDev 2021-07-20 11:00:09 +03:00
commit 27fe952a0c
9 changed files with 291 additions and 229 deletions

View File

@ -75,3 +75,9 @@ endif()
# Install Files
#####################################
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/crow_all.h DESTINATION include)
set(CPACK_GENERATOR "DEB")
set(CPACK_DEBIAN_PACKAGE_MAINTAINER "CrowCpp")
set(CPACK_DEBIAN_PACKAGE_SHLIBDEPS ON)
include(CPack)

View File

@ -1,4 +1,5 @@
Copyright (c) 2014, ipkn
Copyright (c) 2014-2017, ipkn
2020-2021, CrowCpp
All rights reserved.
Redistribution and use in source and binary forms, with or without

View File

@ -10,6 +10,7 @@
#include <thread>
#include <condition_variable>
#include "crow/version.h"
#include "crow/settings.h"
#include "crow/logging.h"
#include "crow/utility.h"
@ -143,7 +144,7 @@ namespace crow
return *this;
}
///Set the server name (default Crow/0.3)
///Set the server name
self_t& server_name(std::string server_name)
{
server_name_ = server_name;
@ -405,7 +406,7 @@ namespace crow
private:
uint16_t port_ = 80;
uint16_t concurrency_ = 1;
std::string server_name_ = "Crow/0.3";
std::string server_name_ = std::string("Crow/") + VERSION;
std::string bindaddr_ = "0.0.0.0";
Router router_;

View File

@ -13,6 +13,7 @@
#include <memory>
#include "crow/version.h"
#include "crow/http_connection.h"
#include "crow/logging.h"
#include "crow/dumb_timer_queue.h"
@ -26,7 +27,7 @@ namespace crow
class Server
{
public:
Server(Handler* handler, std::string bindaddr, uint16_t port, std::string server_name = "Crow/0.3", std::tuple<Middlewares...>* middlewares = nullptr, uint16_t concurrency = 1, typename Adaptor::context* adaptor_ctx = nullptr)
Server(Handler* handler, std::string bindaddr, uint16_t port, std::string server_name = std::string("Crow/") + VERSION, std::tuple<Middlewares...>* middlewares = nullptr, uint16_t concurrency = 1, typename Adaptor::context* adaptor_ctx = nullptr)
: acceptor_(io_service_, tcp::endpoint(boost::asio::ip::address::from_string(bindaddr), port)),
signals_(io_service_, SIGINT, SIGTERM),
tick_timer_(io_service_),
@ -121,7 +122,7 @@ namespace crow
init_count ++;
while(1)
{
try
try
{
if (io_service_pool_[i]->run() == 0)
{
@ -135,7 +136,7 @@ namespace crow
}
}));
if (tick_function_ && tick_interval_.count() > 0)
if (tick_function_ && tick_interval_.count() > 0)
{
tick_timer_.expires_from_now(boost::posix_time::milliseconds(tick_interval_.count()));
tick_timer_.async_wait([this](const boost::system::error_code& ec)

View File

@ -714,100 +714,128 @@ namespace crow
struct Node
{
unsigned rule_index{};
std::array<unsigned, static_cast<int>(ParamType::MAX)> param_childrens{};
std::unordered_map<std::string, unsigned> children;
std::string key;
ParamType param = ParamType::MAX; // MAX = No param.
std::vector<Node*> children;
bool IsSimpleNode() const
{
return
!rule_index &&
std::all_of(
std::begin(param_childrens),
std::end(param_childrens),
[](unsigned x){ return !x; });
children.size() < 2 &&
param == ParamType::MAX &&
std::all_of(std::begin(children), std::end(children), [](Node* x){ return x->param == ParamType::MAX; });
}
};
Trie() : nodes_(1)
Trie()
{
}
///Check whether or not the trie is empty.
bool is_empty()
{
return nodes_.size() > 1;
return head_.children.empty();
}
void optimize()
{
for (auto child: head_.children)
{
optimizeNode(child);
}
}
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)
if (node->IsSimpleNode())
{
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);
Node* child_temp = node->children[0];
node->key = node->key + child_temp->key;
node->rule_index = child_temp->rule_index;
node->children = std::move(child_temp->children);
delete(child_temp);
optimizeNode(node);
}
else
{
for(auto& kv : node->children)
for(auto& child : node->children)
{
Node* child = &nodes_[kv.second];
optimizeNode(child);
}
}
}
void optimize()
void debug_node_print(Node* node, int level)
{
optimizeNode(head());
if (node->param != ParamType::MAX)
{
switch(node->param)
{
case ParamType::INT:
CROW_LOG_DEBUG << std::string(2*level, ' ') << "<int>";
break;
case ParamType::UINT:
CROW_LOG_DEBUG << std::string(2*level, ' ') << "<uint>";
break;
case ParamType::DOUBLE:
CROW_LOG_DEBUG << std::string(2*level, ' ') << "<double>";
break;
case ParamType::STRING:
CROW_LOG_DEBUG << std::string(2*level, ' ') << "<string>";
break;
case ParamType::PATH:
CROW_LOG_DEBUG << std::string(2*level, ' ') << "<path>";
break;
default:
CROW_LOG_DEBUG << std::string(2*level, ' ') << "<ERROR>";
break;
}
}
else
CROW_LOG_DEBUG << std::string(2*level, ' ') << node->key;
for(auto& child : node->children)
{
debug_node_print(child, level+1);
}
}
public:
void debug_print()
{
CROW_LOG_DEBUG << "HEAD";
for (auto& child : head_.children)
debug_node_print(child, 1);
}
public:
void validate()
{
if (!head()->IsSimpleNode())
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
{
//start params as an empty struct
routing_params empty;
if (params == nullptr)
params = &empty;
unsigned found{};
routing_params match_params;
unsigned found{}; //The rule index to be found
routing_params match_params; //supposedly the final matched parameters
//start from the head node
if (node == nullptr)
node = head();
node = &head_;
//if the function was called on a node at the end of the string (the last recursion), return the nodes rule index, and whatever params were passed to the function
if (pos == req_url.size())
return {node->rule_index, *params};
@ -820,109 +848,113 @@ namespace crow
}
};
if (node->param_childrens[static_cast<int>(ParamType::INT)])
for(auto& child : node->children)
{
char c = req_url[pos];
if ((c >= '0' && c <= '9') || c == '+' || c == '-')
if (child->param != ParamType::MAX)
{
char* eptr;
errno = 0;
long long int value = strtoll(req_url.data()+pos, &eptr, 10);
if (errno != ERANGE && eptr != req_url.data()+pos)
if (child->param == ParamType::INT)
{
params->int_params.push_back(value);
auto ret = find(req_url, &nodes_[node->param_childrens[static_cast<int>(ParamType::INT)]], eptr - req_url.data(), params);
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, child, eptr - req_url.data(), params);
update_found(ret);
params->int_params.pop_back();
}
}
}
else if (child->param == 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, child, eptr - req_url.data(), params);
update_found(ret);
params->uint_params.pop_back();
}
}
}
else if (child->param == 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, child, eptr - req_url.data(), params);
update_found(ret);
params->double_params.pop_back();
}
}
}
else if (child->param == 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, child, epos, params);
update_found(ret);
params->string_params.pop_back();
}
}
else if (child->param == 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, child, epos, params);
update_found(ret);
params->string_params.pop_back();
}
}
}
else
{
const std::string& fragment = child->key;
if (req_url.compare(pos, fragment.size(), fragment) == 0)
{
auto ret = find(req_url, child, pos + fragment.size(), params);
update_found(ret);
params->int_params.pop_back();
}
}
}
if (node->param_childrens[static_cast<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[static_cast<int>(ParamType::UINT)]], eptr - req_url.data(), params);
update_found(ret);
params->uint_params.pop_back();
}
}
}
if (node->param_childrens[static_cast<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[static_cast<int>(ParamType::DOUBLE)]], eptr - req_url.data(), params);
update_found(ret);
params->double_params.pop_back();
}
}
}
if (node->param_childrens[static_cast<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[static_cast<int>(ParamType::STRING)]], epos, params);
update_found(ret);
params->string_params.pop_back();
}
}
if (node->param_childrens[static_cast<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[static_cast<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};
return {found, match_params}; //Called after all the recursions have been done
}
void add(const std::string& url, unsigned rule_index)
{
unsigned idx{0};
Node* idx = &head_;
for(unsigned i = 0; i < url.size(); i ++)
{
@ -948,12 +980,23 @@ namespace crow
{
if (url.compare(i, x.name.size(), x.name) == 0)
{
if (!nodes_[idx].param_childrens[static_cast<int>(x.type)])
bool found = false;
for (Node* child : idx->children)
{
auto new_node_idx = new_node();
nodes_[idx].param_childrens[static_cast<int>(x.type)] = new_node_idx;
if (child->param == x.type)
{
idx = child;
i += x.name.size();
found = true;
break;
}
}
idx = nodes_[idx].param_childrens[static_cast<int>(x.type)];
if (found)
break;
auto new_node_idx = new_node(idx);
new_node_idx->param = x.type;
idx = new_node_idx;
i += x.name.size();
break;
}
@ -963,83 +1006,60 @@ namespace crow
}
else
{
std::string piece(&c, 1);
if (!nodes_[idx].children.count(piece))
//This part assumes the tree is unoptimized (every node has a max 1 character key)
bool piece_found = false;
for (auto& child : idx->children)
{
auto new_node_idx = new_node();
nodes_[idx].children.emplace(piece, new_node_idx);
if (child->key[0] == c)
{
idx = child;
piece_found = true;
break;
}
}
if (!piece_found)
{
auto new_node_idx = new_node(idx);
new_node_idx->key = c;
idx = new_node_idx;
}
idx = nodes_[idx].children[piece];
}
}
if (nodes_[idx].rule_index)
//check if the last node already has a value (exact url already in Trie)
if (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 < static_cast<int>(ParamType::MAX); i ++)
{
if (n->param_childrens[i])
{
CROW_LOG_DEBUG << std::string(2*level, ' ') /*<< "("<<n->param_childrens[i]<<") "*/;
switch(static_cast<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);
}
idx->rule_index = rule_index;
}
public:
void debug_print()
size_t get_size()
{
debug_node_print(head(), 0);
return get_size(&head_);
}
size_t get_size(Node* node)
{
unsigned size = 8; //rule_index and param
size += (node->key.size()); //each character in the key is 1 byte
for (auto child: node->children)
{
size += get_size(child);
}
return size;
}
private:
const Node* head() const
Node* new_node(Node* parent)
{
return &nodes_.front();
auto& children = parent->children;
children.resize(children.size()+1);
children[children.size()-1] = new Node();
return children[children.size()-1];
}
Node* head()
{
return &nodes_.front();
}
unsigned new_node()
{
nodes_.resize(nodes_.size()+1);
return nodes_.size() - 1;
}
std::vector<Node> nodes_;
Node head_;
};
/// A blueprint can be considered a smaller section of a Crow app, specifically where the router is conecerned.
@ -1322,7 +1342,7 @@ namespace crow
{
for(int i = 0; i < static_cast<int>(HTTPMethod::InternalMethodCount); i ++)
{
if (per_methods_[i].trie.is_empty())
if (!per_methods_[i].trie.is_empty())
{
allow += method_name(static_cast<HTTPMethod>(i)) + ", ";
}

10
include/crow/version.h Normal file
View File

@ -0,0 +1,10 @@
#pragma once
namespace crow {
#ifdef CROW_MAIN
constexpr char VERSION[] = "master";
#else
extern constexpr char VERSION[];
#endif
}

View File

@ -18,6 +18,8 @@ output_path = sys.argv[2]
middlewares = [x.rsplit(sep, 1)[-1][:-2] for x in glob(pt.join(header_path, ('crow'+sep+'middlewares'+sep+'*.h*')))]
with open(header_path+'/../LICENSE', 'r') as file:
lsc = '/*' + file.read() + '*/'
middlewares_actual = []
if len(sys.argv) > 3:
@ -83,10 +85,10 @@ for x in edges:
assert order.index(x) < order.index(y), 'cyclic include detected'
print(order)
build = []
build = [lsc]
for header in order:
d = open(pt.join(header_path, header)).read()
build.append(re_depends.sub(lambda x: '\n', d))
build.append('\n')
open(output_path, 'w').write('\n'.join(build))
open(output_path, 'w').write('\n'.join(build))

21
scripts/release.py Executable file
View File

@ -0,0 +1,21 @@
#!/bin/env python3
import os
import sys
import shutil
if len(sys.argv) != 2:
print("Usage: {} VERSION".format(sys.argv[0]))
sys.exit(1)
version = str(sys.argv[1])
releasePath = os.path.join(os.path.dirname(__file__), "..", "build_release")
if os.path.exists(releasePath):
shutil.rmtree(releasePath)
os.mkdir(releasePath)
os.chdir(releasePath)
os.system("cmake -DBUILD_EXAMPLES=OFF -DBUILD_TESTING=OFF -DCPACK_PACKAGE_FILE_NAME=\"crow-{}\" .. && make -j5".format(version))
os.system("sed -i 's/constexpr char VERSION\\[\\] = \"master\";/constexpr char VERSION\\[\\] = \"{}\";/g' crow_all.h".format(version))
os.system("cpack")

View File

@ -1,37 +1,37 @@
{
"name": "crow-examples",
"version": "0.3",
"version": "master",
"dependencies": [
{
"name": "boost-array",
"version>=": "1.70.0"
"version>=": "1.70.0"
},
{
"name": "boost-algorithm",
"version>=": "1.70.0"
"version>=": "1.70.0"
},
{
"name": "boost-asio",
"version>=": "1.70.0"
"version>=": "1.70.0"
},
{
"name": "boost-date-time",
"version>=": "1.70.0"
"version>=": "1.70.0"
},
{
"name": "boost-functional",
"version>=": "1.70.0"
"version>=": "1.70.0"
},
{
"name": "boost-lexical-cast",
"version>=": "1.70.0"
"version>=": "1.70.0"
},
{
"name": "boost-optional",
"version>=": "1.70.0"
"version>=": "1.70.0"
},
{
"name": "openssl-windows"
"name": "openssl-windows"
},
{
"name": "zlib"
@ -40,31 +40,31 @@
"overrides": [
{
"name": "boost-array",
"version": "1.70.0"
"version": "1.70.0"
},
{
"name": "boost-algorithm",
"version": "1.70.0"
"version": "1.70.0"
},
{
"name": "boost-asio",
"version-semver": "1.70.0-2"
"version-semver": "1.70.0-2"
},
{
"name": "boost-date-time",
"version": "1.70.0"
"version": "1.70.0"
},
{
"name": "boost-functional",
"version": "1.70.0"
"version": "1.70.0"
},
{
"name": "boost-lexical-cast",
"version": "1.70.0"
"version": "1.70.0"
},
{
"name": "boost-optional",
"version": "1.70.0"
"version": "1.70.0"
}
],
"builtin-baseline": "44d94c2edbd44f0c01d66c2ad95eb6982a9a61bc"