aboutsummaryrefslogtreecommitdiffstats
path: root/include
diff options
context:
space:
mode:
authorJaeseung Ha <ipknhama@gmail.com>2017-09-18 00:43:42 +0900
committerGitHub <noreply@github.com>2017-09-18 00:43:42 +0900
commit08acc7c0bedc24bf5b8c6cc01f1701b0d45e141e (patch)
tree77aa4aa0f2cbfd139dc3194a3cf113ed2100454f /include
parente40605da59e368be524dee0e9e9d41ef05149473 (diff)
parent194a9ef6812e3d5476419e33be2756ab69fc0696 (diff)
downloadcrow-08acc7c0bedc24bf5b8c6cc01f1701b0d45e141e.tar.gz
crow-08acc7c0bedc24bf5b8c6cc01f1701b0d45e141e.zip
Merge branch 'master' into master
Diffstat (limited to 'include')
-rw-r--r--include/crow/http_connection.h3
-rw-r--r--include/crow/http_server.h24
-rw-r--r--include/crow/json.h41
-rw-r--r--include/crow/query_string.h66
-rw-r--r--include/crow/routing.h40
-rw-r--r--include/crow/websocket.h25
6 files changed, 175 insertions, 24 deletions
diff --git a/include/crow/http_connection.h b/include/crow/http_connection.h
index 96f2d14..1537d17 100644
--- a/include/crow/http_connection.h
+++ b/include/crow/http_connection.h
@@ -176,7 +176,7 @@ namespace crow
}
#ifdef CROW_ENABLE_DEBUG
- static int connectionCount;
+ static std::atomic<int> connectionCount;
#endif
template <typename Adaptor, typename Handler, typename ... Middlewares>
class Connection
@@ -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"},
diff --git a/include/crow/http_server.h b/include/crow/http_server.h
index ab2631b..f190739 100644
--- a/include/crow/http_server.h
+++ b/include/crow/http_server.h
@@ -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();
+ }
}
}));
@@ -141,7 +148,8 @@ namespace crow
});
}
- CROW_LOG_INFO << server_name_ << " server is running at " << bindaddr_ <<":" << port_;
+ CROW_LOG_INFO << server_name_ << " server is running at " << bindaddr_ <<":" << port_
+ << " using " << concurrency_ << " threads";
signals_.async_wait(
[&](const boost::system::error_code& /*error*/, int /*signal_number*/){
@@ -193,6 +201,10 @@ namespace crow
p->start();
});
}
+ else
+ {
+ delete p;
+ }
do_accept();
});
}
diff --git a/include/crow/json.h b/include/crow/json.h
index 891fedf..3d9ed18 100644
--- a/include/crow/json.h
+++ b/include/crow/json.h
@@ -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)
{
@@ -1316,6 +1333,24 @@ namespace crow
return (*o)[str];
}
+ std::vector<std::string> keys() const {
+ std::vector<std::string> result;
+ switch (t_) {
+ case type::Null: return result;
+ case type::False: return result;
+ case type::True: return result;
+ case type::Number: return result;
+ case type::String: return result;
+ case type::List: return result;
+ case type::Object: {
+ for (auto& kv:*o) {
+ result.push_back(kv.first);
+ }
+ return result;
+ }
+ }
+ }
+
size_t estimate_length() const
{
switch(t_)
@@ -1356,7 +1391,6 @@ namespace crow
return 1;
}
-
friend void dump_internal(const wvalue& v, std::string& out);
friend std::string dump(const wvalue& v);
};
@@ -1377,7 +1411,12 @@ namespace crow
case type::Number:
{
char outbuf[128];
+#ifdef _MSC_VER
+ sprintf_s(outbuf, 128, "%g", v.d);
+#else
sprintf(outbuf, "%g", v.d);
+#endif
+
out += outbuf;
}
break;
diff --git a/include/crow/query_string.h b/include/crow/query_string.h
index 3f8bffe..ee61e30 100644
--- a/include/crow/query_string.h
+++ b/include/crow/query_string.h
@@ -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)
{
@@ -222,8 +266,12 @@ inline char * qs_scanvalue(const char * key, const char * qs, char * val, size_t
{
qs++;
i = strcspn(qs, "&=#");
- strncpy(val, qs, (val_len-1)<(i+1) ? (val_len-1) : (i+1));
- qs_decode(val);
+#ifdef _MSC_VER
+ strncpy_s(val, val_len, qs, (val_len - 1)<(i + 1) ? (val_len - 1) : (i + 1));
+#else
+ strncpy(val, qs, (val_len - 1)<(i + 1) ? (val_len - 1) : (i + 1));
+#endif
+ qs_decode(val);
}
else
{
@@ -336,6 +384,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_;
diff --git a/include/crow/routing.h b/include/crow/routing.h
index a8aa233..cdfa480 100644
--- a/include/crow/routing.h
+++ b/include/crow/routing.h
@@ -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>
diff --git a/include/crow/websocket.h b/include/crow/websocket.h
index c3ec331..c0e8c3f 100644
--- a/include/crow/websocket.h
+++ b/include/crow/websocket.h
@@ -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";
@@ -212,11 +226,13 @@ namespace crow
case WebSocketReadState::Len16:
{
remaining_length_ = 0;
- boost::asio::async_read(adaptor_.socket(), boost::asio::buffer(&remaining_length_, 2),
- [this](const boost::system::error_code& ec, std::size_t bytes_transferred)
+ uint16_t remaining_length16_ = 0;
+ boost::asio::async_read(adaptor_.socket(), boost::asio::buffer(&remaining_length16_, 2),
+ [this,&remaining_length16_](const boost::system::error_code& ec, std::size_t bytes_transferred)
{
is_reading = false;
- remaining_length_ = ntohs((uint16_t)remaining_length_);
+ remaining_length16_ = ntohs(remaining_length16_);
+ remaining_length_ = remaining_length16_;
#ifdef CROW_ENABLE_DEBUG
if (!ec && bytes_transferred != 2)
{
@@ -484,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_;
};
}
}