2 #include <boost/asio.hpp> 3 #include <boost/algorithm/string/predicate.hpp> 4 #include <boost/lexical_cast.hpp> 5 #include <boost/array.hpp> 22 using namespace boost;
27 template <
typename MW>
37 template <
typename MW>
47 template <
typename MW>
57 template <
typename MW>
77 static std::false_type f(...);
80 static const bool value = decltype(f<T>(
nullptr))::value;
93 static std::false_type f(...);
96 static const bool value = decltype(f<T>(
nullptr))::value;
99 template <
typename MW,
typename Context,
typename ParentContext>
100 typename std::enable_if<!is_before_handle_arity_3_impl<MW>::value>
::type 103 mw.before_handle(req, res, ctx.template get<MW>(), ctx);
106 template <
typename MW,
typename Context,
typename ParentContext>
107 typename std::enable_if<is_before_handle_arity_3_impl<MW>::value>
::type 110 mw.before_handle(req, res, ctx.template get<MW>());
113 template <
typename MW,
typename Context,
typename ParentContext>
114 typename std::enable_if<!is_after_handle_arity_3_impl<MW>::value>
::type 117 mw.after_handle(req, res, ctx.template get<MW>(), ctx);
120 template <
typename MW,
typename Context,
typename ParentContext>
121 typename std::enable_if<is_after_handle_arity_3_impl<MW>::value>
::type 124 mw.after_handle(req, res, ctx.template get<MW>());
127 template <
int N,
typename Context,
typename Container,
typename CurrentMW,
typename ... Middlewares>
130 using parent_context_t =
typename Context::template partial<N-1>;
131 before_handler_call<CurrentMW, Context, parent_context_t>(std::get<N>(middlewares), req, res, ctx, static_cast<parent_context_t&>(ctx));
135 after_handler_call<CurrentMW, Context, parent_context_t>(std::get<N>(middlewares), req, res, ctx, static_cast<parent_context_t&>(ctx));
139 if (middleware_call_helper<N+1, Context, Container, Middlewares...>(middlewares, req, res, ctx))
141 after_handler_call<CurrentMW, Context, parent_context_t>(std::get<N>(middlewares), req, res, ctx, static_cast<parent_context_t&>(ctx));
148 template <
int N,
typename Context,
typename Container>
154 template <
int N,
typename Context,
typename Container>
160 template <
int N,
typename Context,
typename Container>
163 using parent_context_t =
typename Context::template partial<N-1>;
165 after_handler_call<CurrentMW, Context, parent_context_t>(std::get<N>(middlewares), req, res, ctx, static_cast<parent_context_t&>(ctx));
168 template <
int N,
typename Context,
typename Container>
171 using parent_context_t =
typename Context::template partial<N-1>;
173 after_handler_call<CurrentMW, Context, parent_context_t>(std::get<N>(middlewares), req, res, ctx, static_cast<parent_context_t&>(ctx));
178 #ifdef CROW_ENABLE_DEBUG 181 template <
typename Adaptor,
typename Handler,
typename ... Middlewares>
186 boost::asio::io_service& io_service,
188 const std::string& server_name,
189 std::tuple<Middlewares...>* middlewares,
190 std::function<std::string()>& get_cached_date_str_f,
194 : adaptor_(io_service, adaptor_ctx_),
197 server_name_(server_name),
198 middlewares_(middlewares),
199 get_cached_date_str(get_cached_date_str_f),
200 timer_queue(timer_queue)
202 #ifdef CROW_ENABLE_DEBUG 210 res.complete_request_handler_ =
nullptr;
211 cancel_deadline_timer();
212 #ifdef CROW_ENABLE_DEBUG 218 decltype(std::declval<Adaptor>().raw_socket())&
socket()
220 return adaptor_.raw_socket();
225 adaptor_.start([
this](
const boost::system::error_code& ec) {
242 if (parser_.check_version(1, 1) && parser_.headers.count(
"expect") &&
get_header_value(parser_.headers,
"expect") ==
"100-continue")
245 static std::string expect_100_continue =
"HTTP/1.1 100 Continue\r\n\r\n";
246 buffers_.emplace_back(expect_100_continue.data(), expect_100_continue.size());
253 cancel_deadline_timer();
254 bool is_invalid_request =
false;
255 add_keep_alive_ =
false;
257 req_ = std::move(parser_.to_request());
260 if (parser_.check_version(1, 0))
263 if (req.headers.count(
"connection"))
265 if (boost::iequals(req.get_header_value(
"connection"),
"Keep-Alive"))
266 add_keep_alive_ =
true;
269 close_connection_ =
true;
271 else if (parser_.check_version(1, 1))
274 if (req.headers.count(
"connection"))
276 if (req.get_header_value(
"connection") ==
"close")
277 close_connection_ =
true;
278 else if (boost::iequals(req.get_header_value(
"connection"),
"Keep-Alive"))
279 add_keep_alive_ =
true;
281 if (!req.headers.count(
"host"))
283 is_invalid_request =
true;
286 if (parser_.is_upgrade())
288 if (req.get_header_value(
"upgrade") ==
"h2c")
295 close_connection_ =
true;
296 handler_->handle_upgrade(req, res, std::move(adaptor_));
302 CROW_LOG_INFO <<
"Request: " << boost::lexical_cast<std::string>(adaptor_.remote_endpoint()) <<
" " <<
this <<
" HTTP/" << parser_.http_major <<
"." << parser_.http_minor <<
' ' 306 need_to_call_after_handlers_ =
false;
307 if (!is_invalid_request)
309 res.complete_request_handler_ = []{};
310 res.is_alive_helper_ = [
this]()->
bool{
return adaptor_.is_open(); };
313 req.middleware_context = (
void*)&ctx_;
314 req.io_service = &adaptor_.get_io_service();
319 res.complete_request_handler_ = [
this]{ this->complete_request(); };
320 need_to_call_after_handlers_ =
true;
321 handler_->handle(req, res);
323 res.set_header(
"connection",
"Keep-Alive");
338 CROW_LOG_INFO <<
"Response: " <<
this <<
' ' << req_.raw_url <<
' ' << res.code <<
' ' << close_connection_;
340 if (need_to_call_after_handlers_)
342 need_to_call_after_handlers_ =
false;
346 ((int)
sizeof...(Middlewares)-1),
348 decltype(*middlewares_)>
349 (*middlewares_, ctx_, req_, res);
353 res.complete_request_handler_ =
nullptr;
355 if (!adaptor_.is_open())
362 static std::unordered_map<int, std::string> statusCodes = {
363 {200,
"HTTP/1.1 200 OK\r\n"},
364 {201,
"HTTP/1.1 201 Created\r\n"},
365 {202,
"HTTP/1.1 202 Accepted\r\n"},
366 {204,
"HTTP/1.1 204 No Content\r\n"},
368 {300,
"HTTP/1.1 300 Multiple Choices\r\n"},
369 {301,
"HTTP/1.1 301 Moved Permanently\r\n"},
370 {302,
"HTTP/1.1 302 Moved Temporarily\r\n"},
371 {304,
"HTTP/1.1 304 Not Modified\r\n"},
373 {400,
"HTTP/1.1 400 Bad Request\r\n"},
374 {401,
"HTTP/1.1 401 Unauthorized\r\n"},
375 {403,
"HTTP/1.1 403 Forbidden\r\n"},
376 {404,
"HTTP/1.1 404 Not Found\r\n"},
378 {500,
"HTTP/1.1 500 Internal Server Error\r\n"},
379 {501,
"HTTP/1.1 501 Not Implemented\r\n"},
380 {502,
"HTTP/1.1 502 Bad Gateway\r\n"},
381 {503,
"HTTP/1.1 503 Service Unavailable\r\n"},
384 static std::string seperator =
": ";
385 static std::string crlf =
"\r\n";
388 buffers_.reserve(4*(res.headers.size()+5)+3);
395 if (!statusCodes.count(res.code))
398 auto& status = statusCodes.find(res.code)->second;
399 buffers_.emplace_back(status.data(), status.size());
402 if (res.code >= 400 && res.body.empty())
403 res.body = statusCodes[res.code].substr(9);
405 for(
auto& kv : res.headers)
407 buffers_.emplace_back(kv.first.data(), kv.first.size());
408 buffers_.emplace_back(seperator.data(), seperator.size());
409 buffers_.emplace_back(kv.second.data(), kv.second.size());
410 buffers_.emplace_back(crlf.data(), crlf.size());
414 if (!res.headers.count(
"content-length"))
417 static std::string content_length_tag =
"Content-Length: ";
418 buffers_.emplace_back(content_length_tag.data(), content_length_tag.size());
419 buffers_.emplace_back(content_length_.data(), content_length_.size());
420 buffers_.emplace_back(crlf.data(), crlf.size());
422 if (!res.headers.count(
"server"))
424 static std::string server_tag =
"Server: ";
425 buffers_.emplace_back(server_tag.data(), server_tag.size());
426 buffers_.emplace_back(server_name_.data(), server_name_.size());
427 buffers_.emplace_back(crlf.data(), crlf.size());
429 if (!res.headers.count(
"date"))
431 static std::string date_tag =
"Date: ";
432 date_str_ = get_cached_date_str();
433 buffers_.emplace_back(date_tag.data(), date_tag.size());
434 buffers_.emplace_back(date_str_.data(), date_str_.size());
435 buffers_.emplace_back(crlf.data(), crlf.size());
439 static std::string keep_alive_tag =
"Connection: Keep-Alive";
440 buffers_.emplace_back(keep_alive_tag.data(), keep_alive_tag.size());
441 buffers_.emplace_back(crlf.data(), crlf.size());
444 buffers_.emplace_back(crlf.data(), crlf.size());
445 res_body_copy_.swap(res.body);
446 buffers_.emplace_back(res_body_copy_.data(), res_body_copy_.size());
450 if (need_to_start_read_after_complete_)
452 need_to_start_read_after_complete_ =
false;
463 adaptor_.socket().async_read_some(boost::asio::buffer(buffer_),
464 [
this](
const boost::system::error_code& ec, std::size_t bytes_transferred)
466 bool error_while_reading =
true;
469 bool ret = parser_.feed(buffer_.data(), bytes_transferred);
470 if (ret && adaptor_.is_open() && !close_connection_)
472 error_while_reading =
false;
476 if (error_while_reading)
478 cancel_deadline_timer();
485 else if (!need_to_call_after_handlers_)
493 need_to_start_read_after_complete_ =
true;
502 boost::asio::async_write(adaptor_.socket(), buffers_,
503 [&](
const boost::system::error_code& ec, std::size_t )
507 res_body_copy_.clear();
510 if (close_connection_)
527 CROW_LOG_DEBUG <<
this <<
" is_reading " << is_reading <<
" is_writing " << is_writing;
528 if (!is_reading && !is_writing)
537 CROW_LOG_DEBUG <<
this <<
" timer cancelled: " << timer_cancel_key_.first <<
' ' << timer_cancel_key_.second;
538 timer_queue.cancel(timer_cancel_key_);
543 cancel_deadline_timer();
545 timer_cancel_key_ = timer_queue.add([
this]
547 if (!adaptor_.is_open())
553 CROW_LOG_DEBUG <<
this <<
" timer added: " << timer_cancel_key_.first <<
' ' << timer_cancel_key_.second;
566 bool close_connection_ =
false;
580 bool need_to_call_after_handlers_{};
581 bool need_to_start_read_after_complete_{};
582 bool add_keep_alive_{};
Definition: http_connection.h:58
Definition: http_response.h:12
std::enable_if<(N< 0)>::type after_handlers_call_helper(Container &, Context &, request &, response &)
Definition: http_connection.h:156
void handle_header()
Definition: http_connection.h:239
std::enable_if< is_before_handle_arity_3_impl< MW >::value >::type before_handler_call(MW &mw, request &req, response &res, Context &ctx, ParentContext &)
Definition: http_connection.h:108
const uint32_t T[512]
Definition: groestl_tables.h:34
void cancel_deadline_timer()
Definition: http_connection.h:535
Definition: unordered_containers_boost_serialization.h:38
const std::string & server_name_
Definition: http_connection.h:568
Definition: http_request.h:23
Definition: http_connection.h:38
HTTPParser< Connection > parser_
Definition: http_connection.h:562
Definition: http_connection.h:28
std::enable_if<(N >0)>::type after_handlers_call_helper(Container &middlewares, Context &ctx, request &req, response &res)
Definition: http_connection.h:169
Definition: dumb_timer_queue.h:16
std::string dump(const wvalue &v)
Definition: json.h:1426
boost::array< char, 4096 > buffer_
Definition: http_connection.h:560
void check_destroy()
Definition: http_connection.h:525
Handler * handler_
Definition: http_connection.h:558
std::string res_body_copy_
Definition: http_connection.h:573
void do_write()
Definition: http_connection.h:498
detail::context< Middlewares... > ctx_
Definition: http_connection.h:585
Adaptor adaptor_
Definition: http_connection.h:557
std::string date_str_
Definition: http_connection.h:572
bool is_completed() const noexcept
Definition: http_response.h:74
response res
Definition: http_connection.h:564
declaration and default definition for the functions used the API
Definition: http_connection.h:182
Definition: http_connection.h:48
const std::string & get_header_value(const T &headers, const std::string &key)
Definition: http_request.h:11
bool middleware_call_helper(Container &, request &, response &, Context &)
Definition: http_connection.h:149
void start()
Definition: http_connection.h:223
type
Definition: json.h:74
void start_deadline()
Definition: http_connection.h:541
std::function< std::string()> & get_cached_date_str
Definition: http_connection.h:587
std::enable_if< is_after_handle_arity_3_impl< MW >::value >::type after_handler_call(MW &mw, request &req, response &res, Context &ctx, ParentContext &)
Definition: http_connection.h:122
Definition: http_connection.h:68
#define CROW_LOG_DEBUG
Definition: logging.h:139
Definition: http_connection.h:84
std::pair< dumb_timer_queue *, int > key
Definition: dumb_timer_queue.h:19
detail::dumb_timer_queue::key timer_cancel_key_
Definition: http_connection.h:576
Definition: middleware_context.h:38
request req_
Definition: http_connection.h:563
asio::ip::tcp tcp
Definition: http_connection.h:23
~Connection()
Definition: http_connection.h:208
decltype(std::declval< Adaptor >().raw_socket()) & socket()
Definition: http_connection.h:218
std::vector< boost::asio::const_buffer > buffers_
Definition: http_connection.h:569
Connection(boost::asio::io_service &io_service, Handler *handler, const std::string &server_name, std::tuple< Middlewares... > *middlewares, std::function< std::string()> &get_cached_date_str_f, detail::dumb_timer_queue &timer_queue, typename Adaptor::context *adaptor_ctx_)
Definition: http_connection.h:185
std::tuple< Middlewares... > * middlewares_
Definition: http_connection.h:584
std::string to_string(t_connection_type type)
Definition: connection_basic.cpp:96
void do_read()
Definition: http_connection.h:459
void complete_request()
Definition: http_connection.h:336
static int connectionCount
Definition: http_connection.h:179
void handle()
Definition: http_connection.h:251
std::string method_name(HTTPMethod method)
Definition: common.h:34
bool middleware_call_helper(Container &middlewares, request &req, response &res, Context &ctx)
Definition: http_connection.h:128
detail::dumb_timer_queue & timer_queue
Definition: http_connection.h:588
#define CROW_LOG_INFO
Definition: logging.h:136
json::wvalue context
Definition: mustache.h:12
std::string content_length_
Definition: http_connection.h:571