Kagome
Polkadot Runtime Engine in C++17
http_session.cpp
Go to the documentation of this file.
1 
7 
8 #include <boost/config.hpp>
9 
10 #include "outcome/outcome.hpp"
11 
12 namespace kagome::api {
13 
15  : strand_(boost::asio::make_strand(context)),
16  config_{config},
17  stream_(boost::asio::ip::tcp::socket(strand_)) {}
18 
20  asyncRead();
21  }
22 
24  boost::system::error_code ec;
25  stream_.socket().shutdown(Socket::shutdown_both, ec);
26  boost::ignore_unused(ec);
27  }
28 
29  auto HttpSession::makeBadResponse(std::string_view message,
30  unsigned version,
31  bool keep_alive) {
32  Response<StringBody> res{boost::beast::http::status::bad_request, version};
33  res.set(boost::beast::http::field::server, kServerName);
34  res.set(boost::beast::http::field::content_type, "text/html");
35  res.keep_alive(keep_alive);
36  res.body() = message;
37  res.prepare_payload();
38  return res;
39  }
40 
41  template <class Body>
42  void HttpSession::handleRequest(boost::beast::http::request<Body> &&req) {
43  // allow only POST method
44  if (req.method() != boost::beast::http::verb::post) {
46  "Unsupported HTTP-method", req.version(), req.keep_alive()));
47  }
48 
49  processRequest(req.body(), shared_from_this());
50  }
51 
53  parser_ = std::make_unique<Parser>();
54  parser_->body_limit(config_.max_request_size);
55  stream_.expires_after(config_.operation_timeout);
56 
57  boost::beast::http::async_read(
58  stream_,
59  buffer_,
60  parser_->get(),
61  [self = shared_from_this()](auto ec, auto count) {
62  auto *s = dynamic_cast<HttpSession *>(self.get());
63  BOOST_ASSERT_MSG(s != nullptr, "cannot cast to HttpSession");
64  s->onRead(ec, count);
65  });
66  }
67 
68  template <class Message>
69  void HttpSession::asyncWrite(Message &&message) {
70  // we need to put message into a shared ptr for async operations
71  using message_type = decltype(message);
72  auto m = std::make_shared<std::decay_t<message_type>>(
73  std::forward<message_type>(message));
74 
75  // write response
76  boost::beast::http::async_write(
77  stream_, *m, [self = shared_from_this(), m](auto ec, auto size) {
78  self->onWrite(ec, size, m->need_eof());
79  });
80  }
81 
82  void HttpSession::respond(std::string_view response) {
83  StringBody::value_type body;
84  body.assign(response);
85 
86  const auto size = body.size();
87 
88  // send response
89  Response<StringBody> res(std::piecewise_construct,
90  std::make_tuple(std::move(body)));
91  res.set(HttpField::server, kServerName);
92  res.set(HttpField::content_type, "text/html");
93  res.content_length(size);
94  res.keep_alive(true);
95 
96  return asyncWrite(std::move(res));
97  }
98 
99  void HttpSession::onRead(boost::system::error_code ec, std::size_t) {
100  if (ec) {
101  if (HttpError::end_of_stream != ec) {
102  reportError(ec, "unknown error occurred");
103  }
104 
105  stop();
106  return;
107  }
108 
109  handleRequest(parser_->release());
110  }
111 
112  void HttpSession::onWrite(boost::system::error_code ec,
113  std::size_t,
114  bool should_stop) {
115  if (ec) {
116  reportError(ec, "failed to write message");
117  return stop();
118  }
119 
120  if (should_stop) {
121  return stop();
122  }
123 
124  // read next request
125  asyncRead();
126  }
127 
128  void HttpSession::reportError(boost::system::error_code ec,
129  std::string_view message) {
130  logger_->error(
131  "error occured: {}, code: {}, message: {}", message, ec, ec.message());
132  }
133 } // namespace kagome::api
void onRead(boost::system::error_code ec, std::size_t size)
read completion callback
void stop()
stops session
Configuration config_
session configuration
static constexpr boost::string_view kServerName
void reportError(boost::system::error_code ec, std::string_view message)
reports error code and message
boost::asio::strand< boost::asio::io_context::executor_type > strand_
Strand to ensure the connection&#39;s handlers are not called concurrently.
auto makeBadResponse(std::string_view message, unsigned version, bool keep_alive)
composes bad request message
void handleRequest(Request< Body > &&request)
process http request, compose and execute response
boost::beast::http::response< Body > Response
string version
Definition: conf.py:16
void onWrite(boost::system::error_code ec, std::size_t, bool close)
write completion callback
boost::beast::tcp_stream stream_
stream
void processRequest(std::string_view request, std::shared_ptr< Session > session)
process request message
Definition: session.hpp:77
void start() override
starts session
HTTP session for api service.
boost::beast::flat_buffer buffer_
read buffer
HttpSession(Context &context, Configuration config)
constructor
void asyncRead()
asynchronously read http message
void asyncWrite(Message &&message)
sends http message
std::unique_ptr< Parser > parser_
http parser
void respond(std::string_view response) override
sends response wrapped by http message