diff options
Diffstat (limited to 'include')
-rw-r--r-- | include/crow/http_connection.h | 3 | ||||
-rw-r--r-- | include/crow/http_server.h | 24 | ||||
-rw-r--r-- | include/crow/json.h | 22 | ||||
-rw-r--r-- | include/crow/query_string.h | 66 | ||||
-rw-r--r-- | include/crow/routing.h | 40 | ||||
-rw-r--r-- | include/crow/websocket.h | 25 |
6 files changed, 157 insertions, 23 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 d5abb11..787fdb8 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, local port " << port_; + CROW_LOG_INFO << server_name_ << " server is running on port " << 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 53ed45f..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) { @@ -1394,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 a1e8e8f..d21d7e9 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_; }; } } |