HttpSession.hpp
Go to the documentation of this file.
1 // @formatter:off
2 //
3 // Balau core C++ library
4 //
5 // Copyright (C) 2017 Bora Software (contact@borasoftware.com)
6 //
7 // Licensed under the Boost Software License - Version 1.0 - August 17th, 2003.
8 // See the LICENSE file for the full license text.
9 //
10 
11 #ifndef COM_BORA_SOFTWARE__BALAU_NETWORK_HTTP_SERVER__HTTP_SESSION
12 #define COM_BORA_SOFTWARE__BALAU_NETWORK_HTTP_SERVER__HTTP_SESSION
13 
19 
23 #include <Balau/Network/Http/Server/ClientSession.hpp>
24 #include <Balau/Util/DateTime.hpp>
25 
26 // Avoid false positive (due to std::make_shared).
27 #pragma clang diagnostic push
28 #pragma ide diagnostic ignored "OCUnusedGlobalDeclarationInspection"
29 
30 namespace Balau::Network::Http {
31 
32 namespace Impl {
33 
34 class ClientSessions;
35 class HttpSessions;
36 
37 } // namespace Impl
38 
46 class HttpSession final : public std::enable_shared_from_this<HttpSession> {
55  public: HttpSession(Impl::HttpSessions & httpSessions_,
56  Impl::ClientSessions & clientSessions_,
57  std::shared_ptr<HttpServerConfiguration> serverConfiguration_,
58  TCP::socket && socket_);
59 
64  return *serverConfiguration;
65  }
66 
70  public: Address remoteIpAddress() const {
71  return socket.remote_endpoint().address();
72  }
73 
79  public: template <typename BodyT> void sendResponse(Response<BodyT> && response,
80  const std::string & extraLogging = "") {
81  sendResponse(std::move(response), configuration().logger, extraLogging);
82  }
83 
89  public: template <typename BodyT> void sendResponse(Response<BodyT> && response,
90  const BalauLogger & log,
91  const std::string & extraLogging = "") {
92  BalauBalauLogInfo(
93  log
94  , "{} - {} {} {} - {} {} - \"{}\"{} - [{}]"
95  , remoteIpAddress().to_string()
96  , request.method()
97  , response.version() == 11 ? "HTTP/1.1" : "HTTP/1.0"
98  , response.result_int()
99  , response[Field::content_type]
100  , response[Field::content_length]
101  , request.target() // path
102  , extraLogging.empty() ? "" : " - " + extraLogging
103  , request[Field::user_agent]
104  );
105 
106  // Set the session cookie.
107  response.insert(
108  Field::set_cookie, serverConfiguration->sessionCookieName + "=" + clientSession->sessionId + "; HttpOnly"
109  );
110 
111  // Transfer ownership of the response in preparation for the asynchronous call.
112  auto sharedResponse = std::make_shared<Response<BodyT>>(std::move(response));
113  auto sharedVoidResponse = std::shared_ptr<void>(sharedResponse);
114  cachedResponse = sharedVoidResponse;
115 
116  HTTP::async_write(
117  socket
118  , *sharedResponse
119  , boost::asio::bind_executor(
120  strand
121  , std::bind(
122  &HttpSession::onWrite
123  , shared_from_this()
124  , std::placeholders::_1
125  , std::placeholders::_2
126  , sharedResponse->need_eof()
127  )
128  )
129  );
130  }
131 
133 
134  friend class Listener;
135  friend class ::Balau::Network::Http::Impl::HttpSessions;
136 
140  public: void doRead();
141 
145  public: void close();
146 
147  // Callback from context.
148  private: void onRead(boost::system::error_code errorCode, std::size_t bytesTransferred);
149 
150  // Validate the request path.
151  // TODO Add other required validations.
152  private: bool validateRequest(boost::system::error_code errorCode, const StringRequest & request);
153 
154  // Dispatch the request to the appropriate handler method.
155  private: void handleRequest(const StringRequest & request) {
156  try {
157  // The variables generated and consumed during this request.
158  std::map<std::string, std::string> variables;
159 
160  switch (request.method()) {
161  case Method::get: {
162  serverConfiguration->httpHandler->handleGetRequest(*this, request, variables);
163  break;
164  }
165 
166  case Method::head: {
167  serverConfiguration->httpHandler->handleHeadRequest(*this, request, variables);
168  break;
169  }
170 
171  case Method::post: {
172  serverConfiguration->httpHandler->handlePostRequest(*this, request, variables);
173  break;
174  }
175 
176  default: {
177  sendResponse(HttpWebApp::createBadRequestResponse(*this, request, "Unsupported HTTP method."));
178  break;
179  }
180  }
181  } catch (const std::exception & e) {
182  BalauBalauLogError(serverConfiguration->logger, "Exception thrown during request: {}", e);
183  sendResponse(
185  *this, request, "The server experienced an error during the request. A report has been logged."
186  )
187  );
188  } catch (...) {
189  BalauBalauLogError(serverConfiguration->logger, "Unknown exception thrown during request: {}");
190  sendResponse(
192  *this, request, "The server experienced an error during the request. A report has been logged."
193  )
194  );
195  }
196  }
197 
198  private: void onWrite(boost::system::error_code errorCode, std::size_t bytesTransferred, bool close);
199  private: void doClose();
200  private: void parseCookies();
201  private: void setClientSession();
202 
203  private: Impl::HttpSessions & httpSessions;
204  private: Impl::ClientSessions & clientSessions;
205  private: std::shared_ptr<ClientSession> clientSession;
206  private: std::shared_ptr<HttpServerConfiguration> serverConfiguration;
207  private: boost::asio::strand<boost::asio::io_context::executor_type> strand;
208  private: TCP::socket socket;
209  private: Buffer buffer;
210  private: StringRequest request;
211  private: std::string cookieString;
212  private: std::map<std::string_view, std::string_view> cookies;
213  private: std::shared_ptr<void> cachedResponse; // Used to keep the response alive.
214  private: std::allocator<char> allocator;
215 };
216 
217 } // namespace Balau::Network::Http
218 
219 #pragma clang diagnostic pop
220 
221 #endif // COM_BORA_SOFTWARE__BALAU_NETWORK_HTTP_SERVER__HTTP_SESSION
Components and utilities working on HTTP data transmission.
Definition: HttpClient.hpp:26
static StringResponse createBadRequestResponse(HttpSession &session, const StringRequest &request, std::string_view errorMessage)
Create a bad request response.
Manages the handling of HTTP messages and WebSocket upgrade requests in an HTTP connection.
Definition: HttpSession.hpp:46
HttpServerConfiguration & configuration() const
Get the shared state of the http server.
Definition: HttpSession.hpp:63
boost::beast::flat_buffer Buffer
A data buffer used in HTTP code.
Definition: NetworkTypes.hpp:308
Shared state between HTTP sessions.
Definition: HttpServerConfiguration.hpp:44
void sendResponse(Response< BodyT > &&response, const std::string &extraLogging="")
Send the response back to the client.
Definition: HttpSession.hpp:79
Abstract base class of HTTP web application handlers.
boost::asio::ip::address Address
An IP4 or IP6 address.
Definition: NetworkTypes.hpp:225
Request< StringBody > StringRequest
A request with a string body.
Definition: NetworkTypes.hpp:267
void sendResponse(Response< BodyT > &&response, const BalauLogger &log, const std::string &extraLogging="")
Send the response back to the client.
Definition: HttpSession.hpp:89
Manages the handling of WebSocket messages in a WebSocket connection.
boost::beast::http::response< Body, Fields > Response
The response type.
Definition: NetworkTypes.hpp:278
Date and time utilities.
Shared state between HTTP sessions.
static StringResponse createServerErrorResponse(HttpSession &session, const StringRequest &request, std::string_view errorMessage)
Create a server error response.
Address remoteIpAddress() const
Get the requester&#39;s IP address for logging.
Definition: HttpSession.hpp:70