Electroneum
http_connection.h
Go to the documentation of this file.
1 #pragma once
2 #include <boost/asio.hpp>
3 #include <boost/algorithm/string/predicate.hpp>
4 #include <boost/lexical_cast.hpp>
5 #include <boost/array.hpp>
6 #include <atomic>
7 #include <chrono>
8 #include <vector>
9 
10 #include "http_parser_merged.h"
11 
12 #include "parser.h"
13 #include "http_response.h"
14 #include "logging.h"
15 #include "settings.h"
16 #include "dumb_timer_queue.h"
17 #include "middleware_context.h"
18 #include "socket_adaptors.h"
19 
20 namespace crow
21 {
22  using namespace boost;
23  using tcp = asio::ip::tcp;
24 
25  namespace detail
26  {
27  template <typename MW>
29  {
30  template <typename T,
31  void (T::*)(request&, response&, typename MW::context&) const = &T::before_handle
32  >
33  struct get
34  { };
35  };
36 
37  template <typename MW>
39  {
40  template <typename T,
41  void (T::*)(request&, response&, typename MW::context&) = &T::before_handle
42  >
43  struct get
44  { };
45  };
46 
47  template <typename MW>
49  {
50  template <typename T,
51  void (T::*)(request&, response&, typename MW::context&) const = &T::after_handle
52  >
53  struct get
54  { };
55  };
56 
57  template <typename MW>
59  {
60  template <typename T,
61  void (T::*)(request&, response&, typename MW::context&) = &T::after_handle
62  >
63  struct get
64  { };
65  };
66 
67  template <typename T>
69  {
70  template <typename C>
71  static std::true_type f(typename check_before_handle_arity_3_const<T>::template get<C>*);
72 
73  template <typename C>
74  static std::true_type f(typename check_before_handle_arity_3<T>::template get<C>*);
75 
76  template <typename C>
77  static std::false_type f(...);
78 
79  public:
80  static const bool value = decltype(f<T>(nullptr))::value;
81  };
82 
83  template <typename T>
85  {
86  template <typename C>
87  static std::true_type f(typename check_after_handle_arity_3_const<T>::template get<C>*);
88 
89  template <typename C>
90  static std::true_type f(typename check_after_handle_arity_3<T>::template get<C>*);
91 
92  template <typename C>
93  static std::false_type f(...);
94 
95  public:
96  static const bool value = decltype(f<T>(nullptr))::value;
97  };
98 
99  template <typename MW, typename Context, typename ParentContext>
100  typename std::enable_if<!is_before_handle_arity_3_impl<MW>::value>::type
101  before_handler_call(MW& mw, request& req, response& res, Context& ctx, ParentContext& /*parent_ctx*/)
102  {
103  mw.before_handle(req, res, ctx.template get<MW>(), ctx);
104  }
105 
106  template <typename MW, typename Context, typename ParentContext>
107  typename std::enable_if<is_before_handle_arity_3_impl<MW>::value>::type
108  before_handler_call(MW& mw, request& req, response& res, Context& ctx, ParentContext& /*parent_ctx*/)
109  {
110  mw.before_handle(req, res, ctx.template get<MW>());
111  }
112 
113  template <typename MW, typename Context, typename ParentContext>
114  typename std::enable_if<!is_after_handle_arity_3_impl<MW>::value>::type
115  after_handler_call(MW& mw, request& req, response& res, Context& ctx, ParentContext& /*parent_ctx*/)
116  {
117  mw.after_handle(req, res, ctx.template get<MW>(), ctx);
118  }
119 
120  template <typename MW, typename Context, typename ParentContext>
121  typename std::enable_if<is_after_handle_arity_3_impl<MW>::value>::type
122  after_handler_call(MW& mw, request& req, response& res, Context& ctx, ParentContext& /*parent_ctx*/)
123  {
124  mw.after_handle(req, res, ctx.template get<MW>());
125  }
126 
127  template <int N, typename Context, typename Container, typename CurrentMW, typename ... Middlewares>
128  bool middleware_call_helper(Container& middlewares, request& req, response& res, Context& ctx)
129  {
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));
132 
133  if (res.is_completed())
134  {
135  after_handler_call<CurrentMW, Context, parent_context_t>(std::get<N>(middlewares), req, res, ctx, static_cast<parent_context_t&>(ctx));
136  return true;
137  }
138 
139  if (middleware_call_helper<N+1, Context, Container, Middlewares...>(middlewares, req, res, ctx))
140  {
141  after_handler_call<CurrentMW, Context, parent_context_t>(std::get<N>(middlewares), req, res, ctx, static_cast<parent_context_t&>(ctx));
142  return true;
143  }
144 
145  return false;
146  }
147 
148  template <int N, typename Context, typename Container>
149  bool middleware_call_helper(Container& /*middlewares*/, request& /*req*/, response& /*res*/, Context& /*ctx*/)
150  {
151  return false;
152  }
153 
154  template <int N, typename Context, typename Container>
156  after_handlers_call_helper(Container& /*middlewares*/, Context& /*context*/, request& /*req*/, response& /*res*/)
157  {
158  }
159 
160  template <int N, typename Context, typename Container>
161  typename std::enable_if<(N==0)>::type after_handlers_call_helper(Container& middlewares, Context& ctx, request& req, response& res)
162  {
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));
166  }
167 
168  template <int N, typename Context, typename Container>
169  typename std::enable_if<(N>0)>::type after_handlers_call_helper(Container& middlewares, Context& ctx, request& req, response& res)
170  {
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));
174  after_handlers_call_helper<N-1, Context, Container>(middlewares, ctx, req, res);
175  }
176  }
177 
178 #ifdef CROW_ENABLE_DEBUG
179  static int connectionCount;
180 #endif
181  template <typename Adaptor, typename Handler, typename ... Middlewares>
183  {
184  public:
186  boost::asio::io_service& io_service,
187  Handler* handler,
188  const std::string& server_name,
189  std::tuple<Middlewares...>* middlewares,
190  std::function<std::string()>& get_cached_date_str_f,
191  detail::dumb_timer_queue& timer_queue,
192  typename Adaptor::context* adaptor_ctx_
193  )
194  : adaptor_(io_service, adaptor_ctx_),
195  handler_(handler),
196  parser_(this),
197  server_name_(server_name),
198  middlewares_(middlewares),
199  get_cached_date_str(get_cached_date_str_f),
200  timer_queue(timer_queue)
201  {
202 #ifdef CROW_ENABLE_DEBUG
203  connectionCount ++;
204  CROW_LOG_DEBUG << "Connection open, total " << connectionCount << ", " << this;
205 #endif
206  }
207 
209  {
210  res.complete_request_handler_ = nullptr;
211  cancel_deadline_timer();
212 #ifdef CROW_ENABLE_DEBUG
213  connectionCount --;
214  CROW_LOG_DEBUG << "Connection closed, total " << connectionCount << ", " << this;
215 #endif
216  }
217 
218  decltype(std::declval<Adaptor>().raw_socket())& socket()
219  {
220  return adaptor_.raw_socket();
221  }
222 
223  void start()
224  {
225  adaptor_.start([this](const boost::system::error_code& ec) {
226  if (!ec)
227  {
228  start_deadline();
229 
230  do_read();
231  }
232  else
233  {
234  check_destroy();
235  }
236  });
237  }
238 
240  {
241  // HTTP 1.1 Expect: 100-continue
242  if (parser_.check_version(1, 1) && parser_.headers.count("expect") && get_header_value(parser_.headers, "expect") == "100-continue")
243  {
244  buffers_.clear();
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());
247  do_write();
248  }
249  }
250 
251  void handle()
252  {
253  cancel_deadline_timer();
254  bool is_invalid_request = false;
255  add_keep_alive_ = false;
256 
257  req_ = std::move(parser_.to_request());
258  request& req = req_;
259 
260  if (parser_.check_version(1, 0))
261  {
262  // HTTP/1.0
263  if (req.headers.count("connection"))
264  {
265  if (boost::iequals(req.get_header_value("connection"),"Keep-Alive"))
266  add_keep_alive_ = true;
267  }
268  else
269  close_connection_ = true;
270  }
271  else if (parser_.check_version(1, 1))
272  {
273  // HTTP/1.1
274  if (req.headers.count("connection"))
275  {
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;
280  }
281  if (!req.headers.count("host"))
282  {
283  is_invalid_request = true;
284  res = response(400);
285  }
286  if (parser_.is_upgrade())
287  {
288  if (req.get_header_value("upgrade") == "h2c")
289  {
290  // TODO HTTP/2
291  // currently, ignore upgrade header
292  }
293  else
294  {
295  close_connection_ = true;
296  handler_->handle_upgrade(req, res, std::move(adaptor_));
297  return;
298  }
299  }
300  }
301 
302  CROW_LOG_INFO << "Request: " << boost::lexical_cast<std::string>(adaptor_.remote_endpoint()) << " " << this << " HTTP/" << parser_.http_major << "." << parser_.http_minor << ' '
303  << method_name(req.method) << " " << req.url;
304 
305 
306  need_to_call_after_handlers_ = false;
307  if (!is_invalid_request)
308  {
309  res.complete_request_handler_ = []{};
310  res.is_alive_helper_ = [this]()->bool{ return adaptor_.is_open(); };
311 
312  ctx_ = detail::context<Middlewares...>();
313  req.middleware_context = (void*)&ctx_;
314  req.io_service = &adaptor_.get_io_service();
315  detail::middleware_call_helper<0, decltype(ctx_), decltype(*middlewares_), Middlewares...>(*middlewares_, req, res, ctx_);
316 
317  if (!res.completed_)
318  {
319  res.complete_request_handler_ = [this]{ this->complete_request(); };
320  need_to_call_after_handlers_ = true;
321  handler_->handle(req, res);
322  if (add_keep_alive_)
323  res.set_header("connection", "Keep-Alive");
324  }
325  else
326  {
327  complete_request();
328  }
329  }
330  else
331  {
332  complete_request();
333  }
334  }
335 
337  {
338  CROW_LOG_INFO << "Response: " << this << ' ' << req_.raw_url << ' ' << res.code << ' ' << close_connection_;
339 
340  if (need_to_call_after_handlers_)
341  {
342  need_to_call_after_handlers_ = false;
343 
344  // call all after_handler of middlewares
346  ((int)sizeof...(Middlewares)-1),
347  decltype(ctx_),
348  decltype(*middlewares_)>
349  (*middlewares_, ctx_, req_, res);
350  }
351 
352  //auto self = this->shared_from_this();
353  res.complete_request_handler_ = nullptr;
354 
355  if (!adaptor_.is_open())
356  {
357  //CROW_LOG_DEBUG << this << " delete (socket is closed) " << is_reading << ' ' << is_writing;
358  //delete this;
359  return;
360  }
361 
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"},
367 
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"},
372 
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"},
377 
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"},
382  };
383 
384  static std::string seperator = ": ";
385  static std::string crlf = "\r\n";
386 
387  buffers_.clear();
388  buffers_.reserve(4*(res.headers.size()+5)+3);
389 
390  if (res.body.empty() && res.json_value.t() == json::type::Object)
391  {
392  res.body = json::dump(res.json_value);
393  }
394 
395  if (!statusCodes.count(res.code))
396  res.code = 500;
397  {
398  auto& status = statusCodes.find(res.code)->second;
399  buffers_.emplace_back(status.data(), status.size());
400  }
401 
402  if (res.code >= 400 && res.body.empty())
403  res.body = statusCodes[res.code].substr(9);
404 
405  for(auto& kv : res.headers)
406  {
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());
411 
412  }
413 
414  if (!res.headers.count("content-length"))
415  {
416  content_length_ = std::to_string(res.body.size());
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());
421  }
422  if (!res.headers.count("server"))
423  {
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());
428  }
429  if (!res.headers.count("date"))
430  {
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());
436  }
437  if (add_keep_alive_)
438  {
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());
442  }
443 
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());
447 
448  do_write();
449 
450  if (need_to_start_read_after_complete_)
451  {
452  need_to_start_read_after_complete_ = false;
453  start_deadline();
454  do_read();
455  }
456  }
457 
458  private:
459  void do_read()
460  {
461  //auto self = this->shared_from_this();
462  is_reading = true;
463  adaptor_.socket().async_read_some(boost::asio::buffer(buffer_),
464  [this](const boost::system::error_code& ec, std::size_t bytes_transferred)
465  {
466  bool error_while_reading = true;
467  if (!ec)
468  {
469  bool ret = parser_.feed(buffer_.data(), bytes_transferred);
470  if (ret && adaptor_.is_open() && !close_connection_)
471  {
472  error_while_reading = false;
473  }
474  }
475 
476  if (error_while_reading)
477  {
478  cancel_deadline_timer();
479  parser_.done();
480  adaptor_.close();
481  is_reading = false;
482  CROW_LOG_DEBUG << this << " from read(1)";
483  check_destroy();
484  }
485  else if (!need_to_call_after_handlers_)
486  {
487  start_deadline();
488  do_read();
489  }
490  else
491  {
492  // res will be completed later by user
493  need_to_start_read_after_complete_ = true;
494  }
495  });
496  }
497 
498  void do_write()
499  {
500  //auto self = this->shared_from_this();
501  is_writing = true;
502  boost::asio::async_write(adaptor_.socket(), buffers_,
503  [&](const boost::system::error_code& ec, std::size_t /*bytes_transferred*/)
504  {
505  is_writing = false;
506  res.clear();
507  res_body_copy_.clear();
508  if (!ec)
509  {
510  if (close_connection_)
511  {
512  adaptor_.close();
513  CROW_LOG_DEBUG << this << " from write(1)";
514  check_destroy();
515  }
516  }
517  else
518  {
519  CROW_LOG_DEBUG << this << " from write(2)";
520  check_destroy();
521  }
522  });
523  }
524 
526  {
527  CROW_LOG_DEBUG << this << " is_reading " << is_reading << " is_writing " << is_writing;
528  if (!is_reading && !is_writing)
529  {
530  CROW_LOG_DEBUG << this << " delete (idle) ";
531  delete this;
532  }
533  }
534 
536  {
537  CROW_LOG_DEBUG << this << " timer cancelled: " << timer_cancel_key_.first << ' ' << timer_cancel_key_.second;
538  timer_queue.cancel(timer_cancel_key_);
539  }
540 
541  void start_deadline(/*int timeout = 5*/)
542  {
543  cancel_deadline_timer();
544 
545  timer_cancel_key_ = timer_queue.add([this]
546  {
547  if (!adaptor_.is_open())
548  {
549  return;
550  }
551  adaptor_.close();
552  });
553  CROW_LOG_DEBUG << this << " timer added: " << timer_cancel_key_.first << ' ' << timer_cancel_key_.second;
554  }
555 
556  private:
557  Adaptor adaptor_;
558  Handler* handler_;
559 
560  boost::array<char, 4096> buffer_;
561 
565 
566  bool close_connection_ = false;
567 
568  const std::string& server_name_;
569  std::vector<boost::asio::const_buffer> buffers_;
570 
571  std::string content_length_;
572  std::string date_str_;
573  std::string res_body_copy_;
574 
575  //boost::asio::deadline_timer deadline_;
577 
578  bool is_reading{};
579  bool is_writing{};
580  bool need_to_call_after_handlers_{};
581  bool need_to_start_read_after_complete_{};
582  bool add_keep_alive_{};
583 
584  std::tuple<Middlewares...>* middlewares_;
585  detail::context<Middlewares...> ctx_;
586 
587  std::function<std::string()>& get_cached_date_str;
589  };
590 
591 }
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
Definition: ci_map.h:7
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
Definition: parser.h:15
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