mirror of
https://github.com/CrowCpp/Crow.git
synced 2024-06-07 21:10:44 +00:00
Merge branch 'master' into master
This commit is contained in:
commit
ef17b8cb9b
3
.gitignore
vendored
3
.gitignore
vendored
@ -33,3 +33,6 @@ build
|
||||
|
||||
.directory
|
||||
crow_all.h
|
||||
|
||||
# conan.io
|
||||
build/
|
||||
|
10
.travis.yml
10
.travis.yml
@ -11,14 +11,22 @@ compiler:
|
||||
env:
|
||||
matrix:
|
||||
- COMPILER=g++-4.8 CCOMPILER=gcc-4.8 PUSH_COVERAGE=ON
|
||||
- COMPILER=g++-4.9 CCOMPILER=gcc-4.9
|
||||
- COMPILER=g++-5 CCOMPILER=gcc-5
|
||||
- COMPILER=clang++-3.6 CCOMPILER=clang-3.6
|
||||
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
- boost-latest
|
||||
- llvm-toolchain-precise
|
||||
- llvm-toolchain-precise-3.6
|
||||
packages:
|
||||
- g++-4.8
|
||||
- g++-4.9
|
||||
- g++-5
|
||||
- clang-3.6
|
||||
- libboost1.55-all-dev
|
||||
- python-pip
|
||||
|
||||
@ -36,4 +44,4 @@ script: make && ctest
|
||||
|
||||
after_success:
|
||||
- cd ..
|
||||
- if [ "PUSH_COVERAGE" == "ON" ]; then coveralls --gcov gcov-4.8 -i include --gcov-options '\-lp'; fi
|
||||
- if [ "$PUSH_COVERAGE" == "ON" ]; then coveralls --gcov gcov-4.8 -i include --gcov-options '\-lp'; fi
|
||||
|
@ -1,5 +1,11 @@
|
||||
cmake_minimum_required(VERSION 2.8)
|
||||
project (crow_all)
|
||||
|
||||
if(EXISTS "${CMAKE_BINARY_DIR}/conanbuildinfo.cmake")
|
||||
include(${CMAKE_BINARY_DIR}/conanbuildinfo.cmake)
|
||||
conan_basic_setup()
|
||||
endif()
|
||||
|
||||
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/")
|
||||
find_package(Tcmalloc)
|
||||
find_package(Threads)
|
||||
|
@ -32,7 +32,7 @@ int main()
|
||||
- You can also use [json11](https://github.com/dropbox/json11) or [rapidjson](https://github.com/miloyip/rapidjson) for better speed or readability
|
||||
- [Mustache](http://mustache.github.io/) based templating library (crow::mustache)
|
||||
- Header only
|
||||
- Provide an amalgamated header file `crow_all.h' with every features
|
||||
- Provide an amalgamated header file `crow_all.h` with every features
|
||||
- Middleware support
|
||||
- Websocket support
|
||||
|
||||
|
10145
amalgamate/crow_all.h
10145
amalgamate/crow_all.h
File diff suppressed because it is too large
Load Diff
28
conanfile.py
Normal file
28
conanfile.py
Normal file
@ -0,0 +1,28 @@
|
||||
from conans import ConanFile, CMake
|
||||
|
||||
|
||||
class CrowConan(ConanFile):
|
||||
name = "Crow"
|
||||
version = "0.1"
|
||||
url = "https://github.com/ipkn/crow"
|
||||
license = "MIT; see https://github.com/ipkn/crow/blob/master/LICENSE"
|
||||
generators = "cmake"
|
||||
settings = "os", "compiler", "build_type", "arch"
|
||||
|
||||
requires = (("Boost/1.60.0@lasote/stable"),
|
||||
("OpenSSL/1.0.2i@lasote/stable"))
|
||||
|
||||
# No exports necessary
|
||||
|
||||
def source(self):
|
||||
# this will create a hello subfolder, take it into account
|
||||
self.run("git clone https://github.com/ipkn/crow.git")
|
||||
|
||||
def build(self):
|
||||
cmake = CMake(self.settings)
|
||||
self.run('cmake %s/crow %s' % (self.conanfile_directory, cmake.command_line))
|
||||
self.run("cmake --build . %s" % cmake.build_config)
|
||||
self.run("make")
|
||||
|
||||
def package(self):
|
||||
self.copy("*.h", dst="include", src="amalgamate")
|
@ -146,6 +146,15 @@ int main()
|
||||
for(const auto& countVal : count) {
|
||||
os << " - " << countVal << '\n';
|
||||
}
|
||||
|
||||
// To get a dictionary from the request
|
||||
// You have to submit something like '/params?mydict[a]=b&mydict[abcd]=42' to have a list of pairs ((a, b) and (abcd, 42))
|
||||
auto mydict = req.url_params.get_dict("mydict");
|
||||
os << "The key 'dict' contains " << mydict.size() << " value(s).\n";
|
||||
for(const auto& mydictVal : mydict) {
|
||||
os << " - " << mydictVal.first << " -> " << mydictVal.second << '\n';
|
||||
}
|
||||
|
||||
return crow::response{os.str()};
|
||||
});
|
||||
|
||||
|
@ -33,8 +33,13 @@ int main()
|
||||
|
||||
CROW_ROUTE(app, "/")
|
||||
([]{
|
||||
char name[256];
|
||||
gethostname(name, 256);
|
||||
crow::mustache::context x;
|
||||
x["servername"] = name;
|
||||
|
||||
auto page = crow::mustache::load("ws.html");
|
||||
return page.render();
|
||||
return page.render(x);
|
||||
});
|
||||
|
||||
app.port(40080)
|
||||
|
@ -11,7 +11,7 @@
|
||||
<textarea id="log" cols=100 rows=50>
|
||||
</textarea>
|
||||
<script>
|
||||
var sock = new WebSocket("ws://i.ipkn.me:40080/ws");
|
||||
var sock = new WebSocket("ws://{{servername}}:40080/ws");
|
||||
sock.onopen = ()=>{
|
||||
console.log('open')
|
||||
}
|
||||
|
@ -374,6 +374,7 @@ namespace crow
|
||||
{401, "HTTP/1.1 401 Unauthorized\r\n"},
|
||||
{403, "HTTP/1.1 403 Forbidden\r\n"},
|
||||
{404, "HTTP/1.1 404 Not Found\r\n"},
|
||||
{422, "HTTP/1.1 422 Unprocessable Entity\r\n"},
|
||||
|
||||
{500, "HTTP/1.1 500 Internal Server Error\r\n"},
|
||||
{501, "HTTP/1.1 501 Not Implemented\r\n"},
|
||||
|
@ -121,12 +121,19 @@ namespace crow
|
||||
timer.async_wait(handler);
|
||||
|
||||
init_count ++;
|
||||
try
|
||||
while(1)
|
||||
{
|
||||
io_service_pool_[i]->run();
|
||||
} catch(std::exception& e)
|
||||
{
|
||||
CROW_LOG_ERROR << "Worker Crash: An uncaught exception occurred: " << e.what();
|
||||
try
|
||||
{
|
||||
if (io_service_pool_[i]->run() == 0)
|
||||
{
|
||||
// when io_service.run returns 0, there are no more works to do.
|
||||
break;
|
||||
}
|
||||
} catch(std::exception& e)
|
||||
{
|
||||
CROW_LOG_ERROR << "Worker Crash: An uncaught exception occurred: " << e.what();
|
||||
}
|
||||
}
|
||||
}));
|
||||
|
||||
@ -193,6 +200,10 @@ namespace crow
|
||||
p->start();
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
delete p;
|
||||
}
|
||||
do_accept();
|
||||
});
|
||||
}
|
||||
|
@ -1264,6 +1264,23 @@ namespace crow
|
||||
return *this;
|
||||
}
|
||||
|
||||
wvalue& operator=(std::vector<wvalue>&& v)
|
||||
{
|
||||
if (t_ != type::List)
|
||||
reset();
|
||||
t_ = type::List;
|
||||
if (!l)
|
||||
l = std::unique_ptr<std::vector<wvalue>>(new std::vector<wvalue>{});
|
||||
l->clear();
|
||||
l->resize(v.size());
|
||||
size_t idx = 0;
|
||||
for(auto& x:v)
|
||||
{
|
||||
(*l)[idx++] = std::move(x);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
wvalue& operator=(const std::vector<T>& v)
|
||||
{
|
||||
|
@ -4,7 +4,9 @@
|
||||
#include <string.h>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <unordered_map>
|
||||
#include <iostream>
|
||||
#include <boost/optional.hpp>
|
||||
|
||||
namespace crow
|
||||
{
|
||||
@ -197,6 +199,48 @@ inline char * qs_k2v(const char * key, char * const * qs_kv, int qs_kv_size, int
|
||||
return NULL;
|
||||
}
|
||||
|
||||
inline boost::optional<std::pair<std::string, std::string>> qs_dict_name2kv(const char * dict_name, char * const * qs_kv, int qs_kv_size, int nth = 0)
|
||||
{
|
||||
int i;
|
||||
size_t name_len, skip_to_eq, skip_to_brace_open, skip_to_brace_close;
|
||||
|
||||
name_len = strlen(dict_name);
|
||||
|
||||
#ifdef _qsSORTING
|
||||
// TODO: binary search for key in the sorted qs_kv
|
||||
#else // _qsSORTING
|
||||
for(i=0; i<qs_kv_size; i++)
|
||||
{
|
||||
if ( strncmp(dict_name, qs_kv[i], name_len) == 0 )
|
||||
{
|
||||
skip_to_eq = strcspn(qs_kv[i], "=");
|
||||
if ( qs_kv[i][skip_to_eq] == '=' )
|
||||
skip_to_eq++;
|
||||
skip_to_brace_open = strcspn(qs_kv[i], "[");
|
||||
if ( qs_kv[i][skip_to_brace_open] == '[' )
|
||||
skip_to_brace_open++;
|
||||
skip_to_brace_close = strcspn(qs_kv[i], "]");
|
||||
|
||||
if ( skip_to_brace_open <= skip_to_brace_close &&
|
||||
skip_to_brace_open > 0 &&
|
||||
skip_to_brace_close > 0 &&
|
||||
nth == 0 )
|
||||
{
|
||||
auto key = std::string(qs_kv[i] + skip_to_brace_open, skip_to_brace_close - skip_to_brace_open);
|
||||
auto value = std::string(qs_kv[i] + skip_to_eq);
|
||||
return boost::make_optional(std::make_pair(key, value));
|
||||
}
|
||||
else
|
||||
{
|
||||
--nth;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif // _qsSORTING
|
||||
|
||||
return boost::none;
|
||||
}
|
||||
|
||||
|
||||
inline char * qs_scanvalue(const char * key, const char * qs, char * val, size_t val_len)
|
||||
{
|
||||
@ -336,6 +380,20 @@ namespace crow
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::unordered_map<std::string, std::string> get_dict (const std::string& name) const
|
||||
{
|
||||
std::unordered_map<std::string, std::string> ret;
|
||||
|
||||
int count = 0;
|
||||
while(1)
|
||||
{
|
||||
if (auto element = qs_dict_name2kv(name.c_str(), key_value_pairs_.data(), key_value_pairs_.size(), count++))
|
||||
ret.insert(*element);
|
||||
else
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
private:
|
||||
std::string url_;
|
||||
|
@ -156,7 +156,7 @@ namespace crow
|
||||
struct Wrapped
|
||||
{
|
||||
template <typename ... Args>
|
||||
void set(Func f, typename std::enable_if<
|
||||
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)
|
||||
{
|
||||
@ -190,7 +190,7 @@ namespace crow
|
||||
};
|
||||
|
||||
template <typename ... Args>
|
||||
void set(Func f, typename std::enable_if<
|
||||
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)
|
||||
@ -205,7 +205,7 @@ namespace crow
|
||||
}
|
||||
|
||||
template <typename ... Args>
|
||||
void set(Func f, typename std::enable_if<
|
||||
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)
|
||||
@ -276,12 +276,12 @@ namespace crow
|
||||
|
||||
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_);
|
||||
new crow::websocket::Connection<SocketAdaptor>(req, std::move(adaptor), open_handler_, message_handler_, close_handler_, error_handler_, accept_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_);
|
||||
new crow::websocket::Connection<SSLAdaptor>(req, std::move(adaptor), open_handler_, message_handler_, close_handler_, error_handler_, accept_handler_);
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -313,11 +313,19 @@ namespace crow
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename Func>
|
||||
self_t& onaccept(Func f)
|
||||
{
|
||||
accept_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_;
|
||||
std::function<bool(const crow::request&)> accept_handler_;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
@ -410,7 +418,7 @@ namespace crow
|
||||
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<
|
||||
ret.template set_<
|
||||
typename function_t::template arg<Indices>...
|
||||
>(std::move(f));
|
||||
return ret;
|
||||
@ -456,10 +464,16 @@ namespace crow
|
||||
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){
|
||||
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 Func>
|
||||
@ -475,10 +489,16 @@ namespace crow
|
||||
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){
|
||||
handler_ = (
|
||||
#ifdef CROW_CAN_USE_CPP14
|
||||
[f = std::move(f)]
|
||||
#else
|
||||
[f]
|
||||
#endif
|
||||
(const crow::request& req, crow::response& res, Args ... args){
|
||||
res = response(f(req, args...));
|
||||
res.end();
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
template <typename Func>
|
||||
|
@ -1,5 +1,6 @@
|
||||
#pragma once
|
||||
#include <boost/algorithm/string/predicate.hpp>
|
||||
#include <boost/array.hpp>
|
||||
#include "crow/socket_adaptors.h"
|
||||
#include "crow/http_request.h"
|
||||
#include "crow/TinySHA1.hpp"
|
||||
@ -39,8 +40,10 @@ namespace crow
|
||||
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)
|
||||
std::function<void(crow::websocket::connection&)> error_handler,
|
||||
std::function<bool(const crow::request&)> accept_handler)
|
||||
: adaptor_(std::move(adaptor)), open_handler_(std::move(open_handler)), message_handler_(std::move(message_handler)), close_handler_(std::move(close_handler)), error_handler_(std::move(error_handler))
|
||||
, accept_handler_(std::move(accept_handler))
|
||||
{
|
||||
if (!boost::iequals(req.get_header_value("upgrade"), "websocket"))
|
||||
{
|
||||
@ -48,6 +51,17 @@ namespace crow
|
||||
delete this;
|
||||
return;
|
||||
}
|
||||
|
||||
if (accept_handler_)
|
||||
{
|
||||
if (!accept_handler_(req))
|
||||
{
|
||||
adaptor.close();
|
||||
delete this;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
|
||||
// Sec-WebSocket-Version: 13
|
||||
std::string magic = req.get_header_value("Sec-WebSocket-Key") + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
|
||||
@ -486,6 +500,7 @@ namespace crow
|
||||
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_;
|
||||
std::function<bool(const crow::request&)> accept_handler_;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user