RESTinio
Loading...
Searching...
No Matches
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
19namespace restinio
20{
21
22//
23// io_context_shared_ptr_t
24//
25using io_context_shared_ptr_t = std::shared_ptr< asio_ns::io_context >;
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{
38public :
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 */
87external_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*/
171template < typename Traits = default_traits_t >
173{
176 using acceptor_t = impl::acceptor_t< Traits >;
177 using timer_manager_t = typename Traits::timer_manager_t;
178 using timer_manager_handle_t = std::shared_ptr< 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;
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.
201 settings.ensure_valid_connection_state_listener();
202 // The presence of IP-blocker should also be checked.
203 settings.ensure_valid_ip_blocker();
204
205 // Now we can continue preparation of HTTP server.
206
207 using actual_settings_type = basic_server_settings_t<D, Traits>;
208
209 auto timer_factory = settings.timer_factory();
210 m_timer_manager = timer_factory->create( this->io_context() );
211
212 auto conn_settings =
213 std::make_shared< connection_settings_t >(
214 std::forward< actual_settings_type >(settings),
215 impl::create_parser_settings< typename Traits::http_methods_mapper_t >(),
217
218 m_acceptor =
219 std::make_shared< acceptor_t >(
220 settings,
221 this->io_context(),
222 std::make_shared< connection_factory_t >(
223 conn_settings,
224 settings.socket_options_setter() ),
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(
234 std::declval<Configurator>()(
235 std::declval<server_settings_t<Traits>&>() ) ) >
237 io_context_holder_t io_context,
238 Configurator && configurator )
240 io_context,
241 exec_configurator< Traits, Configurator >(
242 std::forward< Configurator >( configurator ) ) }
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.
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(
274 m_acceptor->get_open_close_operations_executor(),
275 [ this,
276 ok_cb = std::move( open_ok_cb ),
277 err_cb = std::move( open_err_cb ) ]{
278 try
279 {
281 call_nothrow_cb( ok_cb );
282 }
283 catch( ... )
284 {
285 call_nothrow_cb( [&err_cb] {
286 err_cb( std::current_exception() );
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 {
300 if( running_state_t::not_running == m_running_state )
301 {
302 m_timer_manager->start();
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(
353 m_acceptor->get_open_close_operations_executor(),
354 [ this,
355 ok_cb = std::move( close_ok_cb ),
356 err_cb = std::move( close_err_cb ) ]{
357 try
358 {
360 call_nothrow_cb( ok_cb );
361 }
362 catch( ... )
363 {
364 call_nothrow_cb( [&err_cb] {
365 err_cb( std::current_exception() );
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 {
379 if( running_state_t::running == m_running_state )
380 {
381 m_timer_manager->stop();
382 m_acceptor->close();
384 m_running_state = running_state_t::not_running;
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.
396 std::shared_ptr< acceptor_t > m_acceptor;
397
398 //! Timer manager object.
400
401 //! State of server.
403 {
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 {
425 cleanup_functor_t fn{ std::move(m_cleanup_functor) };
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 */
Basic container for http_server settings.
Definition settings.hpp:555
Class for http-server.
impl::connection_factory_t< Traits > connection_factory_t
io_context_shared_ptr_t m_io_context
A wrapper for asio io_context where server is running.
Traits traits_t
An alias for Traits type.
impl::connection_settings_t< Traits > connection_settings_t
typename Traits::timer_manager_t timer_manager_t
void call_cleanup_functor() noexcept
Call a cleanup functor if it is defined.
http_server_t(const http_server_t &)=delete
void close_sync()
Stop server.
std::shared_ptr< acceptor_t > m_acceptor
Acceptor for new connections.
void open_async(Server_Open_Ok_CB open_ok_cb, Server_Open_Error_CB open_err_cb)
Starts server in async way.
impl::acceptor_t< Traits > acceptor_t
http_server_t(io_context_holder_t io_context, basic_server_settings_t< D, Traits > &&settings)
void close_async(Server_Close_Ok_CB close_ok_cb, Server_Close_Error_CB close_err_cb)
Closes server in async way.
timer_manager_handle_t m_timer_manager
Timer manager object.
running_state_t
State of server.
http_server_t(http_server_t &&)=delete
http_server_t(io_context_holder_t io_context, Configurator &&configurator)
running_state_t m_running_state
Server state.
std::shared_ptr< timer_manager_t > timer_manager_handle_t
cleanup_functor_t m_cleanup_functor
An optional user's cleanup functor.
virtual ~http_server_t()
It is allowed to inherit from http_server_t.
void open_sync()
Start server.
static void call_nothrow_cb(Callback &&cb) noexcept
Call callback and terminate the application if callback throws.
Helper class for holding shared pointer to io_context.
io_context_shared_ptr_t giveaway_context()
io_context_shared_ptr_t m_context
io_context_holder_t(io_context_shared_ptr_t context)
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...
std::function< void(void) > cleanup_functor_t
Type of holder for user's cleanup function.
Definition settings.hpp:307
io_context_holder_t own_io_context()
Function which tells that http_server should create and use its own instance of io_context.
std::shared_ptr< asio_ns::io_context > io_context_shared_ptr_t
request_handler_type_from_traits_t< Traits > request_handler_t