RESTinio
http_server.hpp
Go to the documentation of this file.
1 /*
2  restinio
3 */
4 
5 /*!
6  HTTP-Server.
7 */
8 
9 #pragma once
10 
11 #include <restinio/exception.hpp>
12 #include <restinio/settings.hpp>
13 #include <restinio/request_handler.hpp>
14 #include <restinio/impl/acceptor.hpp>
15 #include <restinio/traits.hpp>
16 
17 #include <memory>
18 
19 namespace restinio
20 {
21 
22 //
23 // io_context_shared_ptr_t
24 //
26 
27 //
28 // io_context_holder_t
29 //
30 /*!
31  * \brief Helper class for holding shared pointer to io_context.
32  *
33  * It intended to be used as argument to http_server_t's constructor.
34  */
36 {
38 public :
39  io_context_holder_t( io_context_shared_ptr_t context )
40  : m_context( std::move(context) )
41  {}
42 
45  {
46  return std::move(m_context);
47  }
48 };
49 
50 //
51 // own_io_context
52 //
53 /*!
54  * \brief Function which tells that http_server should create and use
55  * its own instance of io_context.
56  *
57  * Usage example:
58  * \code
59  * restinio::http_server_t<> server(
60  * restinio::own_io_context(),
61  * restinio::server_settings_t<>()... );
62  * \endcode
63  */
66 {
67  return { std::make_shared< asio_ns::io_context >() };
68 }
69 
70 //
71 // external_io_context
72 //
73 /*!
74  * \brief Function which tells that http_server should use external
75  * instance of io_context and should not controll its lifetime.
76  *
77  * Usage example:
78  * \code
79  * asio::io_context ctx;
80  * ...
81  * restinio::http_server_t<> server(
82  * restinio::external_io_context(ctx),
83  * restinio::server_settings_t<>()...);
84  * \endcode
85  */
87 external_io_context( asio_ns::io_context & ctx )
88 {
89  return { std::shared_ptr< asio_ns::io_context >(
90  std::addressof(ctx),
91  // Empty deleter.
92  []( asio_ns::io_context * ){} )
93  };
94 }
95 
96 //
97 // http_server_t
98 //
99 
100 //! Class for http-server.
101 /*!
102  With the help of this class one can run a server.
103  Server can be started and stopped in sync or async way.
104 
105  Please note that it is responsibility of user to provide a working
106  context for http_server. It means that user must call
107  asio::io_context::run() on some work thread (or on several working
108  threads).
109 
110  Sync way for starting and stopping a http_server can be used only if
111  http_server_t::open_sync() and http_server_t::close_sync() methods
112  are called somewhere inside asio::io_context::run(). For example:
113  \code
114  // Create and initialize object.
115  restinio::http_server_t< my_traits_t > server{
116  restinio::own_io_context(),
117  [&]( auto & settings ){
118  //
119  settings
120  .port( args.port() )
121  // .set_more_params( ... )
122  .request_handler(
123  []( restinio::request_handle_t req ){
124  // Handle request.
125  } );
126  } };
127 
128  // Post initial action to asio event loop.
129  asio::post( server.io_context(),
130  [&] {
131  // Starting the server in a sync way.
132  server.open_sync();
133  } );
134 
135  // Running server.
136  server.io_context().run();
137  \endcode
138 
139  Async way for starting and stopping a http_server can be used if
140  http_server_t::open_async() and http_server_t::close_async() can be
141  called from any other thread. For example:
142  \code
143  asio::io_context io_ctx;
144  restinio::http_server_t< my_traits_t > server{
145  restinio::external_io_context(io_ctx),
146  [&]( auto & settings ) { ... } };
147 
148  // Launch thread on which server will work.
149  std::thread server_thread{ [&] {
150  io_ctx.run();
151  } };
152 
153  // This variable will be used for holding information about
154  // a possible exception in open_async.
155  std::exception_ptr exception_from_open_async;
156 
157  // Start server in async way. Actual start will be performed
158  // on the context of server_thread.
159  server.open_async(
160  // Ok callback. Nothing to do.
161  []() noexcept {},
162  // Error callback. Just store information about an exception.
163  [&]( std::exception_ptr ex_ptr ) noexcept {
164  exception_from_open_async = ex_ptr;
165  } );
166  ...
167  // Wait while server_thread finishes its work.
168  server_thread.join();
169  \endcode
170 */
171 template < typename Traits = default_traits_t >
173 {
177  using timer_manager_t = typename Traits::timer_manager_t;
179 
180  public:
181  /*!
182  * @brief An alias for Traits type.
183  *
184  * @since v.0.5.0
185  */
186  using traits_t = Traits;
187 
188  // This is not Copyable nor Moveable type.
189  http_server_t( const http_server_t & ) = delete;
190  http_server_t( http_server_t && ) = delete;
191 
192  template<typename D>
194  io_context_holder_t io_context,
195  basic_server_settings_t< D, Traits > && settings )
198  {
199  // Since v.0.5.1 the presence of custom connection state
200  // listener should be checked before the start of HTTP server.
202  // The presence of IP-blocker should also be checked.
204 
205  // Now we can continue preparation of HTTP server.
206 
208 
211 
212  auto conn_settings =
216  m_timer_manager );
217 
218  m_acceptor =
220  settings,
221  this->io_context(),
225  *( conn_settings->m_logger ) );
226  }
227 
228  template<
229  typename Configurator,
230  // Use SFINAE.
231  // This constructor must be called only if Configurator
232  // allows to call operator() with server_settings_t& arg.
233  typename = decltype(
235  std::declval<server_settings_t<Traits>&>() ) ) >
237  io_context_holder_t io_context,
238  Configurator && configurator )
239  : http_server_t{
240  io_context,
243  {}
244 
245  //! It is allowed to inherit from http_server_t
246  virtual ~http_server_t()
247  {
248  // Ensure server is closed after destruction of http_server instance.
249  close_sync();
250  }
251 
252  //! Get io_context on which server runs.
253  asio_ns::io_context & io_context() noexcept { return *m_io_context; }
254 
255  //! Starts server in async way.
256  /*!
257  \note It is necessary to be sure that ioservice is running.
258 
259  \attention
260  \a open_ok_cb and \a open_err_cb should be noexcept
261  functions/lambdas. This requirement is not enforced by
262  static_assert in RESTinio's code to avoid problems in
263  cases when `std::function` is used for these callbacks.
264  */
265  template <
266  typename Server_Open_Ok_CB,
267  typename Server_Open_Error_CB >
268  void
270  Server_Open_Ok_CB open_ok_cb,
271  Server_Open_Error_CB open_err_cb )
272  {
273  asio_ns::post(
275  [ this,
276  ok_cb = std::move( open_ok_cb ),
277  err_cb = std::move( open_err_cb ) ]{
278  try
279  {
280  open_sync();
282  }
283  catch( ... )
284  {
285  call_nothrow_cb( [&err_cb] {
287  } );
288  }
289  } );
290  }
291 
292  //! Start server.
293  /*!
294  If server was started successfully then function returns,
295  otherwise it throws.
296  */
297  void
299  {
301  {
303  m_acceptor->open();
305  }
306  }
307 
308  //! Closes server in async way.
309  /*!
310  * Usage example:
311  * \code
312  * restinio::http_server_t< my_traits > server{ ... };
313  *
314  * server.open_async(...);
315  *
316  * // It's time to close the server.
317  * server.close_async(
318  * // OK callback. Will be called if acceptor and other
319  * // stuff is closed without problems.
320  * // Please note that OK callback should not throw exceptions.
321  * [&]() noexcept {
322  * ... // Some actions to perform if everything is OK.
323  * // For example, shutting down worker threads.
324  * },
325  * // Error callback. Will be called if an exception is thrown
326  * // during closing acceptor or other stuff.
327  * // Please note that error callback should not throw exceptions.
328  * []( std::exception_ptr ex ) noexcept {
329  * ... // Some actions. Like storing `ex` somewhere.
330  * } );
331  * \endcode
332  *
333  * \attention
334  * If an error is thrown during closing the acceptor and other stuff,
335  * the \a close_err_cb is called, but the state of the http_server_t
336  * is undefined.
337  *
338  * \attention
339  * \a close_ok_cb and \a close_err_cb should be noexcept
340  * functions/lambdas. This requirement is not enforced by
341  * static_assert in RESTinio's code to avoid problems in
342  * cases when `std::function` is used for these callbacks.
343  */
344  template <
345  typename Server_Close_Ok_CB,
346  typename Server_Close_Error_CB >
347  void
349  Server_Close_Ok_CB close_ok_cb,
350  Server_Close_Error_CB close_err_cb )
351  {
352  asio_ns::post(
354  [ this,
355  ok_cb = std::move( close_ok_cb ),
356  err_cb = std::move( close_err_cb ) ]{
357  try
358  {
359  close_sync();
361  }
362  catch( ... )
363  {
364  call_nothrow_cb( [&err_cb] {
366  } );
367  }
368  } );
369  }
370 
371  //! Stop server.
372  /*!
373  If server was stopped successfully then function returns,
374  otherwise it throws.
375  */
376  void
378  {
380  {
382  m_acceptor->close();
385  }
386  }
387 
388  private:
389  //! A wrapper for asio io_context where server is running.
391 
392  //! An optional user's cleanup functor.
394 
395  //! Acceptor for new connections.
397 
398  //! Timer manager object.
400 
401  //! State of server.
402  enum class running_state_t
403  {
404  not_running,
405  running,
406  };
407 
408  //! Server state.
410 
411  //! Call a cleanup functor if it is defined.
412  /*!
413  * \note
414  * Cleanup functor can be called only once. Next call to
415  * call_cleanup_functor() will do nothing.
416  *
417  * \attention
418  * Cleanup functor can't throw.
419  */
420  void
422  {
423  if( m_cleanup_functor )
424  {
426  fn();
427  }
428  }
429 
430  //! Call callback and terminate the application if callback throws.
431  template< typename Callback >
432  static void call_nothrow_cb( Callback && cb ) noexcept
433  {
434  cb();
435  }
436 };
437 
438 } /* namespace restinio */
Helper class for holding shared pointer to io_context.
Definition: http_server.hpp:35
http_server_t(io_context_holder_t io_context, Configurator &&configurator)
std::shared_ptr< acceptor_t > m_acceptor
Acceptor for new connections.
running_state_t m_running_state
Server state.
cleanup_functor_t m_cleanup_functor
An optional user&#39;s cleanup functor.
timer_manager_handle_t m_timer_manager
Timer manager object.
std::enable_if< std::is_same< Parameter_Container, query_string_params_t >::value||std::is_same< Parameter_Container, router::route_params_t >::value, std::optional< Value_Type > >::type opt_value(const Parameter_Container &params, string_view_t key)
Gets the value of a parameter specified by key wrapped in std::optional<Value_Type> if parameter exis...
Definition: value_or.hpp:64
void open_async(Server_Open_Ok_CB open_ok_cb, Server_Open_Error_CB open_err_cb)
Starts server in async way.
io_context_shared_ptr_t m_context
Definition: http_server.hpp:37
io_context_holder_t own_io_context()
Function which tells that http_server should create and use its own instance of io_context.
Definition: http_server.hpp:65
http_server_t(const http_server_t &)=delete
void close_async(Server_Close_Ok_CB close_ok_cb, Server_Close_Error_CB close_err_cb)
Closes server in async way.
asio_ns::io_context & io_context() noexcept
Get io_context on which server runs.
io_context_shared_ptr_t m_io_context
A wrapper for asio io_context where server is running.
void open_sync()
Start server.
io_context_holder_t external_io_context(asio_ns::io_context &ctx)
Function which tells that http_server should use external instance of io_context and should not contr...
Definition: http_server.hpp:87
running_state_t
State of server.
void close_sync()
Stop server.
io_context_holder_t(io_context_shared_ptr_t context)
Definition: http_server.hpp:39
void call_cleanup_functor() noexcept
Call a cleanup functor if it is defined.
http_server_t(http_server_t &&)=delete
http_server_t(io_context_holder_t io_context, basic_server_settings_t< D, Traits > &&settings)
virtual ~http_server_t()
It is allowed to inherit from http_server_t.
static void call_nothrow_cb(Callback &&cb) noexcept
Call callback and terminate the application if callback throws.
io_context_shared_ptr_t giveaway_context()
Definition: http_server.hpp:44
Class for http-server.