Crow  1.1
A C++ microframework for the web
app.h
1 #pragma once
2 
3 #include <chrono>
4 #include <string>
5 #include <functional>
6 #include <memory>
7 #include <future>
8 #include <cstdint>
9 #include <type_traits>
10 #include <thread>
11 #include <condition_variable>
12 
13 #include "crow/version.h"
14 #include "crow/settings.h"
15 #include "crow/logging.h"
16 #include "crow/utility.h"
17 #include "crow/routing.h"
18 #include "crow/middleware_context.h"
19 #include "crow/http_request.h"
20 #include "crow/http_server.h"
21 #include "crow/task_timer.h"
22 #include "crow/websocket.h"
23 #ifdef CROW_ENABLE_COMPRESSION
24 #include "crow/compression.h"
25 #endif
26 
27 #ifdef CROW_MSVC_WORKAROUND
28 #define CROW_ROUTE(app, url) app.route_dynamic(url)
29 #define CROW_BP_ROUTE(blueprint, url) blueprint.new_rule_dynamic(url)
30 #else
31 #define CROW_ROUTE(app, url) app.template route<crow::black_magic::get_parameter_tag(url)>(url)
32 #define CROW_BP_ROUTE(blueprint, url) blueprint.new_rule_tagged<crow::black_magic::get_parameter_tag(url)>(url)
33 #define CROW_WEBSOCKET_ROUTE(app, url) app.route<crow::black_magic::get_parameter_tag(url)>(url).websocket<std::remove_reference<decltype(app)>::type>(&app)
34 #define CROW_MIDDLEWARES(app, ...) template middlewares<typename std::remove_reference<decltype(app)>::type, __VA_ARGS__>()
35 #endif
36 #define CROW_CATCHALL_ROUTE(app) app.catchall_route()
37 #define CROW_BP_CATCHALL_ROUTE(blueprint) blueprint.catchall_rule()
38 
39 namespace crow
40 {
41 #ifdef CROW_ENABLE_SSL
42  using ssl_context_t = asio::ssl::context;
43 #endif
44  /// The main server application
45 
46  ///
47  /// Use `SimpleApp` or `App<Middleware1, Middleware2, etc...>`
48  template<typename... Middlewares>
49  class Crow
50  {
51  public:
52  /// This crow application
53  using self_t = Crow;
54  /// The HTTP server
55  using server_t = Server<Crow, SocketAdaptor, Middlewares...>;
56 #ifdef CROW_ENABLE_SSL
57  /// An HTTP server that runs on SSL with an SSLAdaptor
58  using ssl_server_t = Server<Crow, SSLAdaptor, Middlewares...>;
59 #endif
60  Crow()
61  {}
62 
63  /// Construct Crow with a subset of middleware
64  template<typename... Ts>
65  Crow(Ts&&... ts):
66  middlewares_(make_middleware_tuple(std::forward<Ts>(ts)...))
67  {}
68 
69  /// Process an Upgrade request
70 
71  ///
72  /// Currently used to upgrade an HTTP connection to a WebSocket connection
73  template<typename Adaptor>
74  void handle_upgrade(const request& req, response& res, Adaptor&& adaptor)
75  {
76  router_.handle_upgrade(req, res, adaptor);
77  }
78 
79  /// Process only the method and URL of a request and provide a route (or an error response)
80  std::unique_ptr<routing_handle_result> handle_initial(request& req, response& res)
81  {
82  return router_.handle_initial(req, res);
83  }
84 
85  /// Process the fully parsed request and generate a response for it
86  void handle(request& req, response& res, std::unique_ptr<routing_handle_result>& found)
87  {
88  router_.handle<self_t>(req, res, *found);
89  }
90 
91  /// Process a fully parsed request from start to finish (primarily used for debugging)
92  void handle_full(request& req, response& res)
93  {
94  auto found = handle_initial(req, res);
95  if (found->rule_index)
96  handle(req, res, found);
97  }
98 
99  /// Create a dynamic route using a rule (**Use CROW_ROUTE instead**)
100  DynamicRule& route_dynamic(const std::string& rule)
101  {
102  return router_.new_rule_dynamic(rule);
103  }
104 
105  /// Create a route using a rule (**Use CROW_ROUTE instead**)
106  template<uint64_t Tag>
107 #ifdef CROW_GCC83_WORKAROUND
108  auto& route(const std::string& rule)
109 #else
110  auto route(const std::string& rule)
111 #endif
112 #if defined CROW_CAN_USE_CPP17 && !defined CROW_GCC83_WORKAROUND
113  -> typename std::invoke_result<decltype(&Router::new_rule_tagged<Tag>), Router, const std::string&>::type
114 #elif !defined CROW_GCC83_WORKAROUND
115  -> typename std::result_of<decltype (&Router::new_rule_tagged<Tag>)(Router, const std::string&)>::type
116 #endif
117  {
118  return router_.new_rule_tagged<Tag>(rule);
119  }
120 
121  /// Create a route for any requests without a proper route (**Use CROW_CATCHALL_ROUTE instead**)
123  {
124  return router_.catchall_rule();
125  }
126 
127  /// Set the default max payload size for websockets
128  self_t& websocket_max_payload(uint64_t max_payload)
129  {
130  max_payload_ = max_payload;
131  return *this;
132  }
133 
134  /// Get the default max payload size for websockets
136  {
137  return max_payload_;
138  }
139 
140  self_t& signal_clear()
141  {
142  signals_.clear();
143  return *this;
144  }
145 
146  self_t& signal_add(int signal_number)
147  {
148  signals_.push_back(signal_number);
149  return *this;
150  }
151 
152  std::vector<int> signals()
153  {
154  return signals_;
155  }
156 
157  /// Set the port that Crow will handle requests on
158  self_t& port(std::uint16_t port)
159  {
160  port_ = port;
161  return *this;
162  }
163 
164  /// Get the port that Crow will handle requests on
165  std::uint16_t port()
166  {
167  return port_;
168  }
169 
170  /// Set the connection timeout in seconds (default is 5)
171  self_t& timeout(std::uint8_t timeout)
172  {
173  timeout_ = timeout;
174  return *this;
175  }
176 
177  /// Set the server name
179  {
180  server_name_ = server_name;
181  return *this;
182  }
183 
184  /// The IP address that Crow will handle requests on (default is 0.0.0.0)
185  self_t& bindaddr(std::string bindaddr)
186  {
187  bindaddr_ = bindaddr;
188  return *this;
189  }
190 
191  /// Get the address that Crow will handle requests on
192  std::string bindaddr()
193  {
194  return bindaddr_;
195  }
196 
197  /// Run the server on multiple threads using all available threads
199  {
200  return concurrency(std::thread::hardware_concurrency());
201  }
202 
203  /// Run the server on multiple threads using a specific number
205  {
206  if (concurrency < 2) // Crow can have a minimum of 2 threads running
207  concurrency = 2;
208  concurrency_ = concurrency;
209  return *this;
210  }
211 
212  /// Get the number of threads that server is using
213  std::uint16_t concurrency()
214  {
215  return concurrency_;
216  }
217 
218  /// Set the server's log level
219 
220  ///
221  /// Possible values are:<br>
222  /// crow::LogLevel::Debug (0)<br>
223  /// crow::LogLevel::Info (1)<br>
224  /// crow::LogLevel::Warning (2)<br>
225  /// crow::LogLevel::Error (3)<br>
226  /// crow::LogLevel::Critical (4)<br>
227  self_t& loglevel(LogLevel level)
228  {
229  crow::logger::setLogLevel(level);
230  return *this;
231  }
232 
233  /// Set the response body size (in bytes) beyond which Crow automatically streams responses (Default is 1MiB)
234 
235  ///
236  /// Any streamed response is unaffected by Crow's timer, and therefore won't timeout before a response is fully sent.
237  self_t& stream_threshold(size_t threshold)
238  {
239  res_stream_threshold_ = threshold;
240  return *this;
241  }
242 
243  /// Get the response body size (in bytes) beyond which Crow automatically streams responses
245  {
246  return res_stream_threshold_;
247  }
248 
249  self_t& register_blueprint(Blueprint& blueprint)
250  {
251  router_.register_blueprint(blueprint);
252  return *this;
253  }
254 
255  /// Set the function to call to handle uncaught exceptions generated in routes (Default generates error 500).
256 
257  ///
258  /// The function must have the following signature: void(crow::response&).
259  /// It must set the response passed in argument to the function, which will be sent back to the client.
260  /// See Router::default_exception_handler() for the default implementation.
261  template<typename Func>
263  {
264  router_.exception_handler() = std::forward<Func>(f);
265  return *this;
266  }
267 
268  std::function<void(crow::response&)>& exception_handler()
269  {
270  return router_.exception_handler();
271  }
272 
273  /// Set a custom duration and function to run on every tick
274  template<typename Duration, typename Func>
275  self_t& tick(Duration d, Func f)
276  {
277  tick_interval_ = std::chrono::duration_cast<std::chrono::milliseconds>(d);
278  tick_function_ = f;
279  return *this;
280  }
281 
282 #ifdef CROW_ENABLE_COMPRESSION
283  self_t& use_compression(compression::algorithm algorithm)
284  {
285  comp_algorithm_ = algorithm;
286  compression_used_ = true;
287  return *this;
288  }
289 
290  compression::algorithm compression_algorithm()
291  {
292  return comp_algorithm_;
293  }
294 
295  bool compression_used() const
296  {
297  return compression_used_;
298  }
299 #endif
300 
301  /// Apply blueprints
303  {
304 #if defined(__APPLE__) || defined(__MACH__)
305  if (router_.blueprints().empty()) return;
306 #endif
307 
308  for (Blueprint* bp : router_.blueprints())
309  {
310  if (bp->static_dir().empty()) continue;
311 
312  auto static_dir_ = crow::utility::normalize_path(bp->static_dir());
313 
314  bp->new_rule_tagged<crow::black_magic::get_parameter_tag(CROW_STATIC_ENDPOINT)>(CROW_STATIC_ENDPOINT)([static_dir_](crow::response& res, std::string file_path_partial) {
315  utility::sanitize_filename(file_path_partial);
316  res.set_static_file_info_unsafe(static_dir_ + file_path_partial);
317  res.end();
318  });
319  }
320 
321  router_.validate_bp();
322  }
323 
324  /// Go through the rules, upgrade them if possible, and add them to the list of rules
326  {
327  if (are_static_routes_added()) return;
328  auto static_dir_ = crow::utility::normalize_path(CROW_STATIC_DIRECTORY);
329 
330  route<crow::black_magic::get_parameter_tag(CROW_STATIC_ENDPOINT)>(CROW_STATIC_ENDPOINT)([static_dir_](crow::response& res, std::string file_path_partial) {
331  utility::sanitize_filename(file_path_partial);
332  res.set_static_file_info_unsafe(static_dir_ + file_path_partial);
333  res.end();
334  });
335  set_static_routes_added();
336  }
337 
338  /// A wrapper for `validate()` in the router
339  void validate()
340  {
341  router_.validate();
342  }
343 
344  /// Run the server
345  void run()
346  {
347 #ifndef CROW_DISABLE_STATIC_DIR
348  add_blueprint();
349  add_static_dir();
350 #endif
351  validate();
352 
353 #ifdef CROW_ENABLE_SSL
354  if (ssl_used_)
355  {
356  ssl_server_ = std::move(std::unique_ptr<ssl_server_t>(new ssl_server_t(this, bindaddr_, port_, server_name_, &middlewares_, concurrency_, timeout_, &ssl_context_)));
357  ssl_server_->set_tick_function(tick_interval_, tick_function_);
358  ssl_server_->signal_clear();
359  for (auto snum : signals_)
360  {
361  ssl_server_->signal_add(snum);
362  }
363  notify_server_start();
364  ssl_server_->run();
365  }
366  else
367 #endif
368  {
369  server_ = std::move(std::unique_ptr<server_t>(new server_t(this, bindaddr_, port_, server_name_, &middlewares_, concurrency_, timeout_, nullptr)));
370  server_->set_tick_function(tick_interval_, tick_function_);
371  for (auto snum : signals_)
372  {
373  server_->signal_add(snum);
374  }
375  notify_server_start();
376  server_->run();
377  }
378  }
379 
380  /// Non-blocking version of \ref run()
381  ///
382  /// The output from this method needs to be saved into a variable!
383  /// Otherwise the call will be made on the same thread.
384  std::future<void> run_async()
385  {
386  return std::async(std::launch::async, [&] {
387  this->run();
388  });
389  }
390 
391  /// Stop the server
392  void stop()
393  {
394 #ifdef CROW_ENABLE_SSL
395  if (ssl_used_)
396  {
397  if (ssl_server_) { ssl_server_->stop(); }
398  }
399  else
400 #endif
401  {
402  // TODO(EDev): Move these 6 lines to a method in http_server.
403  std::vector<crow::websocket::connection*> websockets_to_close = websockets_;
404  for (auto websocket : websockets_to_close)
405  {
406  CROW_LOG_INFO << "Quitting Websocket: " << websocket;
407  websocket->close("Server Application Terminated");
408  }
409  if (server_) { server_->stop(); }
410  }
411  }
412 
413  void add_websocket(crow::websocket::connection* conn)
414  {
415  websockets_.push_back(conn);
416  }
417 
418  void remove_websocket(crow::websocket::connection* conn)
419  {
420  websockets_.erase(std::remove(websockets_.begin(), websockets_.end(), conn), websockets_.end());
421  }
422 
423  /// Print the routing paths defined for each HTTP method
424  void debug_print()
425  {
426  CROW_LOG_DEBUG << "Routing:";
427  router_.debug_print();
428  }
429 
430 
431 #ifdef CROW_ENABLE_SSL
432 
433  /// Use certificate and key files for SSL
434  self_t& ssl_file(const std::string& crt_filename, const std::string& key_filename)
435  {
436  ssl_used_ = true;
437  ssl_context_.set_verify_mode(asio::ssl::verify_peer);
438  ssl_context_.set_verify_mode(asio::ssl::verify_client_once);
439  ssl_context_.use_certificate_file(crt_filename, ssl_context_t::pem);
440  ssl_context_.use_private_key_file(key_filename, ssl_context_t::pem);
441  ssl_context_.set_options(
442  asio::ssl::context::default_workarounds | asio::ssl::context::no_sslv2 | asio::ssl::context::no_sslv3);
443  return *this;
444  }
445 
446  /// Use .pem file for SSL
447  self_t& ssl_file(const std::string& pem_filename)
448  {
449  ssl_used_ = true;
450  ssl_context_.set_verify_mode(asio::ssl::verify_peer);
451  ssl_context_.set_verify_mode(asio::ssl::verify_client_once);
452  ssl_context_.load_verify_file(pem_filename);
453  ssl_context_.set_options(
454  asio::ssl::context::default_workarounds | asio::ssl::context::no_sslv2 | asio::ssl::context::no_sslv3);
455  return *this;
456  }
457 
458  /// Use certificate chain and key files for SSL
459  self_t& ssl_chainfile(const std::string& crt_filename, const std::string& key_filename)
460  {
461  ssl_used_ = true;
462  ssl_context_.set_verify_mode(asio::ssl::verify_peer);
463  ssl_context_.set_verify_mode(asio::ssl::verify_client_once);
464  ssl_context_.use_certificate_chain_file(crt_filename);
465  ssl_context_.use_private_key_file(key_filename, ssl_context_t::pem);
466  ssl_context_.set_options(
467  asio::ssl::context::default_workarounds | asio::ssl::context::no_sslv2 | asio::ssl::context::no_sslv3);
468  return *this;
469  }
470 
471  self_t& ssl(asio::ssl::context&& ctx)
472  {
473  ssl_used_ = true;
474  ssl_context_ = std::move(ctx);
475  return *this;
476  }
477 
478  bool ssl_used() const
479  {
480  return ssl_used_;
481  }
482 #else
483  template<typename T, typename... Remain>
484  self_t& ssl_file(T&&, Remain&&...)
485  {
486  // We can't call .ssl() member function unless CROW_ENABLE_SSL is defined.
487  static_assert(
488  // make static_assert dependent to T; always false
489  std::is_base_of<T, void>::value,
490  "Define CROW_ENABLE_SSL to enable ssl support.");
491  return *this;
492  }
493 
494  template<typename T, typename... Remain>
495  self_t& ssl_chainfile(T&&, Remain&&...)
496  {
497  // We can't call .ssl() member function unless CROW_ENABLE_SSL is defined.
498  static_assert(
499  // make static_assert dependent to T; always false
500  std::is_base_of<T, void>::value,
501  "Define CROW_ENABLE_SSL to enable ssl support.");
502  return *this;
503  }
504 
505  template<typename T>
506  self_t& ssl(T&&)
507  {
508  // We can't call .ssl() member function unless CROW_ENABLE_SSL is defined.
509  static_assert(
510  // make static_assert dependent to T; always false
511  std::is_base_of<T, void>::value,
512  "Define CROW_ENABLE_SSL to enable ssl support.");
513  return *this;
514  }
515 
516  bool ssl_used() const
517  {
518  return false;
519  }
520 #endif
521 
522  // middleware
523  using context_t = detail::context<Middlewares...>;
524  using mw_container_t = std::tuple<Middlewares...>;
525  template<typename T>
526  typename T::context& get_context(const request& req)
527  {
528  static_assert(black_magic::contains<T, Middlewares...>::value, "App doesn't have the specified middleware type.");
529  auto& ctx = *reinterpret_cast<context_t*>(req.middleware_context);
530  return ctx.template get<T>();
531  }
532 
533  template<typename T>
534  T& get_middleware()
535  {
536  return utility::get_element_by_type<T, Middlewares...>(middlewares_);
537  }
538 
539  /// Wait until the server has properly started
541  {
542  {
543  std::unique_lock<std::mutex> lock(start_mutex_);
544  if (!server_started_)
545  cv_started_.wait(lock);
546  }
547  if (server_)
548  server_->wait_for_start();
549 #ifdef CROW_ENABLE_SSL
550  else if (ssl_server_)
551  ssl_server_->wait_for_start();
552 #endif
553  }
554 
555  private:
556  template<typename... Ts>
557  std::tuple<Middlewares...> make_middleware_tuple(Ts&&... ts)
558  {
559  auto fwd = std::forward_as_tuple((ts)...);
560  return std::make_tuple(
561  std::forward<Middlewares>(
562  black_magic::tuple_extract<Middlewares, decltype(fwd)>(fwd))...);
563  }
564 
565  /// Notify anything using `wait_for_server_start()` to proceed
566  void notify_server_start()
567  {
568  std::unique_lock<std::mutex> lock(start_mutex_);
569  server_started_ = true;
570  cv_started_.notify_all();
571  }
572 
573  void set_static_routes_added() {
574  static_routes_added_ = true;
575  }
576 
577  bool are_static_routes_added() {
578  return static_routes_added_;
579  }
580 
581  private:
582  std::uint8_t timeout_{5};
583  uint16_t port_ = 80;
584  uint16_t concurrency_ = 2;
585  uint64_t max_payload_{UINT64_MAX};
586  std::string server_name_ = std::string("Crow/") + VERSION;
587  std::string bindaddr_ = "0.0.0.0";
588  size_t res_stream_threshold_ = 1048576;
589  Router router_;
590  bool static_routes_added_{false};
591 
592 #ifdef CROW_ENABLE_COMPRESSION
593  compression::algorithm comp_algorithm_;
594  bool compression_used_{false};
595 #endif
596 
597  std::chrono::milliseconds tick_interval_;
598  std::function<void()> tick_function_;
599 
600  std::tuple<Middlewares...> middlewares_;
601 
602 #ifdef CROW_ENABLE_SSL
603  std::unique_ptr<ssl_server_t> ssl_server_;
604  bool ssl_used_{false};
605  ssl_context_t ssl_context_{asio::ssl::context::sslv23};
606 #endif
607 
608  std::unique_ptr<server_t> server_;
609 
610  std::vector<int> signals_{SIGINT, SIGTERM};
611 
612  bool server_started_{false};
613  std::condition_variable cv_started_;
614  std::mutex start_mutex_;
615  std::vector<crow::websocket::connection*> websockets_;
616  };
617  template<typename... Middlewares>
618  using App = Crow<Middlewares...>;
619  using SimpleApp = Crow<>;
620 } // namespace crow
A blueprint can be considered a smaller section of a Crow app, specifically where the router is conec...
Definition: routing.h:1104
Definition: routing.h:342
The main server application.
Definition: app.h:50
self_t & multithreaded()
Run the server on multiple threads using all available threads.
Definition: app.h:198
void stop()
Stop the server.
Definition: app.h:392
self_t & tick(Duration d, Func f)
Set a custom duration and function to run on every tick.
Definition: app.h:275
DynamicRule & route_dynamic(const std::string &rule)
Create a dynamic route using a rule (Use CROW_ROUTE instead)
Definition: app.h:100
size_t & stream_threshold()
Get the response body size (in bytes) beyond which Crow automatically streams responses.
Definition: app.h:244
void run()
Run the server.
Definition: app.h:345
self_t & websocket_max_payload(uint64_t max_payload)
Set the default max payload size for websockets.
Definition: app.h:128
self_t & port(std::uint16_t port)
Set the port that Crow will handle requests on.
Definition: app.h:158
uint64_t websocket_max_payload()
Get the default max payload size for websockets.
Definition: app.h:135
void add_static_dir()
Go through the rules, upgrade them if possible, and add them to the list of rules.
Definition: app.h:325
self_t & ssl_file(const std::string &pem_filename)
Use .pem file for SSL.
Definition: app.h:447
self_t & concurrency(std::uint16_t concurrency)
Run the server on multiple threads using a specific number.
Definition: app.h:204
self_t & timeout(std::uint8_t timeout)
Set the connection timeout in seconds (default is 5)
Definition: app.h:171
Crow self_t
This crow application.
Definition: app.h:53
Server< Crow, SocketAdaptor, Middlewares... > server_t
The HTTP server.
Definition: app.h:55
auto route(const std::string &rule) -> typename std::result_of< decltype(&Router::new_rule_tagged< Tag >)(Router, const std::string &)>::type
Create a route using a rule (Use CROW_ROUTE instead)
Definition: app.h:110
void wait_for_server_start()
Wait until the server has properly started.
Definition: app.h:540
void handle_upgrade(const request &req, response &res, Adaptor &&adaptor)
Process an Upgrade request.
Definition: app.h:74
self_t & bindaddr(std::string bindaddr)
The IP address that Crow will handle requests on (default is 0.0.0.0)
Definition: app.h:185
std::unique_ptr< routing_handle_result > handle_initial(request &req, response &res)
Process only the method and URL of a request and provide a route (or an error response)
Definition: app.h:80
self_t & loglevel(LogLevel level)
Set the server's log level.
Definition: app.h:227
void debug_print()
Print the routing paths defined for each HTTP method.
Definition: app.h:424
void handle(request &req, response &res, std::unique_ptr< routing_handle_result > &found)
Process the fully parsed request and generate a response for it.
Definition: app.h:86
self_t & exception_handler(Func &&f)
Set the function to call to handle uncaught exceptions generated in routes (Default generates error 5...
Definition: app.h:262
std::uint16_t port()
Get the port that Crow will handle requests on.
Definition: app.h:165
std::string bindaddr()
Get the address that Crow will handle requests on.
Definition: app.h:192
self_t & ssl_file(const std::string &crt_filename, const std::string &key_filename)
Use certificate and key files for SSL.
Definition: app.h:434
Server< Crow, SSLAdaptor, Middlewares... > ssl_server_t
An HTTP server that runs on SSL with an SSLAdaptor.
Definition: app.h:58
std::future< void > run_async()
Definition: app.h:384
CatchallRule & catchall_route()
Create a route for any requests without a proper route (Use CROW_CATCHALL_ROUTE instead)
Definition: app.h:122
void validate()
A wrapper for validate() in the router.
Definition: app.h:339
Crow(Ts &&... ts)
Construct Crow with a subset of middleware.
Definition: app.h:65
std::uint16_t concurrency()
Get the number of threads that server is using.
Definition: app.h:213
void handle_full(request &req, response &res)
Process a fully parsed request from start to finish (primarily used for debugging)
Definition: app.h:92
self_t & ssl_chainfile(const std::string &crt_filename, const std::string &key_filename)
Use certificate chain and key files for SSL.
Definition: app.h:459
self_t & server_name(std::string server_name)
Set the server name.
Definition: app.h:178
self_t & stream_threshold(size_t threshold)
Set the response body size (in bytes) beyond which Crow automatically streams responses (Default is 1...
Definition: app.h:237
void add_blueprint()
Apply blueprints.
Definition: app.h:302
A rule that can change its parameters during runtime.
Definition: routing.h:575
Handles matching requests to existing rules and upgrade requests.
Definition: routing.h:1254
Definition: http_server.h:28
Definition: socket_adaptors.h:90
A wrapper for the asio::ip::tcp::socket and asio::ssl::stream.
Definition: socket_adaptors.h:22
An HTTP request.
Definition: http_request.h:28
HTTP response.
Definition: http_response.h:34
void end()
Set the response completion flag and call the handler (to send the response).
Definition: http_response.h:237
void set_static_file_info_unsafe(std::string path)
Return a static file as the response body without sanitizing the path (use set_static_file_info inste...
Definition: http_response.h:295
A base class for websocket connection.
Definition: websocket.h:24