Crow  1.1
A C++ microframework for the web
 
Loading...
Searching...
No Matches
app.h
Go to the documentation of this file.
1/**
2 * \file crow/app.h
3 * \brief This file includes the definition of the crow::Crow class,
4 * the crow::App and crow::SimpleApp aliases, and some macros.
5 *
6 * In this file are defined:
7 * - crow::Crow
8 * - crow::App
9 * - crow::SimpleApp
10 * - \ref CROW_ROUTE
11 * - \ref CROW_BP_ROUTE
12 * - \ref CROW_WEBSOCKET_ROUTE
13 * - \ref CROW_MIDDLEWARES
14 * - \ref CROW_CATCHALL_ROUTE
15 * - \ref CROW_BP_CATCHALL_ROUTE
16 */
17
18#pragma once
19
20#include <chrono>
21#include <string>
22#include <functional>
23#include <memory>
24#include <future>
25#include <cstdint>
26#include <type_traits>
27#include <thread>
28#include <condition_variable>
29
30#include "crow/version.h"
31#include "crow/settings.h"
32#include "crow/logging.h"
33#include "crow/utility.h"
34#include "crow/routing.h"
35#include "crow/middleware_context.h"
36#include "crow/http_request.h"
37#include "crow/http_server.h"
38#include "crow/task_timer.h"
39#include "crow/websocket.h"
40#ifdef CROW_ENABLE_COMPRESSION
41#include "crow/compression.h"
42#endif // #ifdef CROW_ENABLE_COMPRESSION
43
44
45#ifdef CROW_MSVC_WORKAROUND
46
47#define CROW_ROUTE(app, url) app.route_dynamic(url) // See the documentation in the comment below.
48#define CROW_BP_ROUTE(blueprint, url) blueprint.new_rule_dynamic(url) // See the documentation in the comment below.
49
50#else // #ifdef CROW_MSVC_WORKAROUND
51
52/**
53 * \def CROW_ROUTE(app, url)
54 * \brief Creates a route for app using a rule.
55 *
56 * It use crow::Crow::route_dynamic or crow::Crow::route to define
57 * a rule for your application. It's usage is like this:
58 *
59 * ```cpp
60 * auto app = crow::SimpleApp(); // or crow::App()
61 * CROW_ROUTE(app, "/")
62 * ([](){
63 * return "<h1>Hello, world!</h1>";
64 * });
65 * ```
66 *
67 * This is the recommended way to define routes in a crow application.
68 * \see [Page of guide "Routes"](https://crowcpp.org/master/guides/routes/).
69 */
70#define CROW_ROUTE(app, url) app.template route<crow::black_magic::get_parameter_tag(url)>(url)
71
72/**
73 * \def CROW_STATIC_FILE(app, url, internalPath)
74 * \brief Creates a static route for app for given url to internalPath.
75 *
76 *
77 * ```cpp
78 * auto app = crow::SimpleApp(); // or crow::App()
79 * CROW_STATIC_FILE(app, "/home", "home.html");
80 * CROW_STATIC_FILE(app, "/favicon.ico", "favicon.png");
81 * ```
82 *
83 */
84#define CROW_STATIC_FILE(app, url, internalPath) app.static_file(url, internalPath)
85
86
87/**
88 * \def CROW_BP_ROUTE(blueprint, url)
89 * \brief Creates a route for a blueprint using a rule.
90 *
91 * It may use crow::Blueprint::new_rule_dynamic or
92 * crow::Blueprint::new_rule_tagged to define a new rule for
93 * an given blueprint. It's usage is similar
94 * to CROW_ROUTE macro:
95 *
96 * ```cpp
97 * crow::Blueprint my_bp();
98 * CROW_BP_ROUTE(my_bp, "/")
99 * ([](){
100 * return "<h1>Hello, world!</h1>";
101 * });
102 * ```
103 *
104 * This is the recommended way to define routes in a crow blueprint
105 * because of its compile-time capabilities.
106 *
107 * \see [Page of the guide "Blueprints"](https://crowcpp.org/master/guides/blueprints/).
108 */
109#define CROW_BP_ROUTE(blueprint, url) blueprint.new_rule_tagged<crow::black_magic::get_parameter_tag(url)>(url)
110
111/**
112 * \def CROW_WEBSOCKET_ROUTE(app, url)
113 * \brief Defines WebSocket route for app.
114 *
115 * It binds a WebSocket route to app. Easy solution to implement
116 * WebSockets in your app. The usage syntax of this macro is
117 * like this:
118 *
119 * ```cpp
120 * auto app = crow::SimpleApp(); // or crow::App()
121 * CROW_WEBSOCKET_ROUTE(app, "/ws")
122 * .onopen([&](crow::websocket::connection& conn){
123 * do_something();
124 * })
125 * .onclose([&](crow::websocket::connection& conn, const std::string& reason, uint16_t){
126 * do_something();
127 * })
128 * .onmessage([&](crow::websocket::connection&, const std::string& data, bool is_binary){
129 * if (is_binary)
130 * do_something(data);
131 * else
132 * do_something_else(data);
133 * });
134 * ```
135 *
136 * \see [Page of the guide "WebSockets"](https://crowcpp.org/master/guides/websockets/).
137 */
138#define CROW_WEBSOCKET_ROUTE(app, url) app.route<crow::black_magic::get_parameter_tag(url)>(url).websocket<std::remove_reference<decltype(app)>::type>(&app)
139
140/**
141 * \def CROW_MIDDLEWARES(app, ...)
142 * \brief Enable a Middleware for an specific route in app
143 * or blueprint.
144 *
145 * It defines the usage of a Middleware in one route. And it
146 * can be used in both crow::SimpleApp (and crow::App) instances and
147 * crow::Blueprint. Its usage syntax is like this:
148 *
149 * ```cpp
150 * auto app = crow::SimpleApp(); // or crow::App()
151 * CROW_ROUTE(app, "/with_middleware")
152 * .CROW_MIDDLEWARES(app, LocalMiddleware) // Can be used more than one
153 * ([]() { // middleware.
154 * return "Hello world!";
155 * });
156 * ```
157 *
158 * \see [Page of the guide "Middlewares"](https://crowcpp.org/master/guides/middleware/).
159 */
160#define CROW_MIDDLEWARES(app, ...) template middlewares<typename std::remove_reference<decltype(app)>::type, __VA_ARGS__>()
161
162#endif // #ifdef CROW_MSVC_WORKAROUND
163
164/**
165 * \def CROW_CATCHALL_ROUTE(app)
166 * \brief Defines a custom catchall route for app using a
167 * custom rule.
168 *
169 * It defines a handler when the client make a request for an
170 * undefined route. Instead of just reply with a `404` status
171 * code (default behavior), you can define a custom handler
172 * using this macro.
173 *
174 * \see [Page of the guide "Routes" (Catchall routes)](https://crowcpp.org/master/guides/routes/#catchall-routes).
175 */
176#define CROW_CATCHALL_ROUTE(app) app.catchall_route()
177
178/**
179 * \def CROW_BP_CATCHALL_ROUTE(blueprint)
180 * \brief Defines a custom catchall route for blueprint
181 * using a custom rule.
182 *
183 * It defines a handler when the client make a request for an
184 * undefined route in the blueprint.
185 *
186 * \see [Page of the guide "Blueprint" (Define a custom Catchall route)](https://crowcpp.org/master/guides/blueprints/#define-a-custom-catchall-route).
187 */
188#define CROW_BP_CATCHALL_ROUTE(blueprint) blueprint.catchall_rule()
189
190
191/**
192 * \namespace crow
193 * \brief The main namespace of the library. In this namespace
194 * is defined the most important classes and functions of the
195 * library.
196 *
197 * Within this namespace, the Crow class, Router class, Connection
198 * class, and other are defined.
199 */
200namespace crow
201{
202#ifdef CROW_ENABLE_SSL
203 using ssl_context_t = asio::ssl::context;
204#endif
205 /**
206 * \class Crow
207 * \brief The main server application class.
208 *
209 * Use crow::SimpleApp or crow::App<Middleware1, Middleware2, etc...> instead of
210 * directly instantiate this class.
211 */
212 template<typename... Middlewares>
213 class Crow
214 {
215 public:
216 /// \brief This is the crow application
217 using self_t = Crow;
218
219 /// \brief The HTTP server
220 using server_t = Server<Crow, TCPAcceptor, SocketAdaptor, Middlewares...>;
221 /// \brief An HTTP server that runs on unix domain socket
223#ifdef CROW_ENABLE_SSL
224 /// \brief An HTTP server that runs on SSL with an SSLAdaptor
225 using ssl_server_t = Server<Crow, TCPAcceptor, SSLAdaptor, Middlewares...>;
226#endif
227 /// \brief WebSocket rule type used in this application.
228 ///
229 /// Usefull during WebSocket route definition.
230 /// Usage:
231 ///
232 /// ```cpp
233 /// crow::SimpleApp::WebSocketRule_t& ws = CROW_WEBSOCKET_ROUTE(app, "/ws");
234 ///
235 /// ws.onaccept([](const crow::request& /*conn*/, void** userData) -> bool
236 /// {
237 /// // ...
238 /// return true;
239 /// });
240 /// ws.onopen([](crow::websocket::connection& conn) {
241 /// // ...
242 /// });
243 /// ws.onclose([](crow::websocket::connection& conn, const std::string& /*reason*/, uint16_t){
244 /// // ...
245 /// });
246 /// ws.onmessage([](crow::websocket::connection& conn, const std::string& msgData, bool is_binary) {
247 /// // ...
248 /// });
249 /// ```
250 ///
251 using WebSocketRule_t = WebSocketRule<Crow<Middlewares...>>;
252
253 Crow()
254 {}
255
256 /// \brief Construct Crow with a subset of middleware
257 template<typename... Ts>
258 Crow(Ts&&... ts):
259 middlewares_(make_middleware_tuple(std::forward<Ts>(ts)...))
260 {}
261
262 /// \brief Process an Upgrade request
263 ///
264 /// Currently used to upgrade an HTTP connection to a WebSocket connection
265 template<typename Adaptor>
266 void handle_upgrade(const request& req, response& res, Adaptor&& adaptor)
267 {
268 router_.handle_upgrade(req, res, adaptor);
269 }
270
271 /// \brief Process only the method and URL of a request and provide a route (or an error response)
272 std::unique_ptr<routing_handle_result> handle_initial(request& req, response& res)
273 {
274 return router_.handle_initial(req, res);
275 }
276
277 /// \brief Process the fully parsed request and generate a response for it
278 void handle(request& req, response& res, std::unique_ptr<routing_handle_result>& found)
279 {
280 router_.handle<self_t>(req, res, *found);
281 }
282
283 /// \brief Process a fully parsed request from start to finish (primarily used for debugging)
284 void handle_full(request& req, response& res)
285 {
286 auto found = handle_initial(req, res);
287 if (found->rule_index || found->catch_all)
288 handle(req, res, found);
289 }
290
291 /// \brief Create a dynamic route using a rule (**Use CROW_ROUTE instead**)
292 DynamicRule& route_dynamic(const std::string& rule)
293 {
294 return router_.new_rule_dynamic(rule);
295 }
296
297 /// \brief Create a route using a rule (**Use CROW_ROUTE instead**)
298 template<uint64_t Tag>
299 auto route(const std::string& rule)
300 -> typename std::invoke_result<decltype(&Router::new_rule_tagged<Tag>), Router, const std::string&>::type
301 {
302 return router_.new_rule_tagged<Tag>(rule);
303 }
304
305 /// \brief Create a static route to given url
306 ///
307 /// \param url public URL
308 /// \return The rule
309 ///
310 StaticRule& route_static(const std::string& url)
311 {
312 return router_.new_rule<StaticRule>(url);
313 }
314
315 /// \brief Creates a static route for given url to internalPath.
316 ///
317 /// \param url public URL
318 /// \param internalPath internal path to reach te file
319 /// \return The rule
320 ///
321 StaticRule& static_file(std::string_view url, std::string_view internalPath){
322 StaticRule& rt = route_static(std::string(url));
323
324 // make a copy of given view of internalPath
325 rt([=,localFile=std::string(internalPath)](crow::response& resp) -> void {
326 resp.set_static_file_info(localFile);
327 resp.end();
328 });
329
330 return rt;
331 }
332
333 /// \brief Create a route for any requests without a proper route (**Use CROW_CATCHALL_ROUTE instead**)
335 {
336 return router_.catchall_rule();
337 }
338
339 /// \brief Set the default max payload size for websockets
340 self_t& websocket_max_payload(uint64_t max_payload)
341 {
342 max_payload_ = max_payload;
343 return *this;
344 }
345
346 /// \brief Get the default max payload size for websockets
348 {
349 return max_payload_;
350 }
351
352 self_t& signal_clear()
353 {
354 signals_.clear();
355 return *this;
356 }
357
358 self_t& signal_add(int signal_number)
359 {
360 signals_.push_back(signal_number);
361 return *this;
362 }
363
364 std::vector<int> signals()
365 {
366 return signals_;
367 }
368
369 /// \brief Set the port that Crow will handle requests on
370 self_t& port(std::uint16_t port)
371 {
372 port_ = port;
373 return *this;
374 }
375
376 /// \brief Get the port that Crow will handle requests on
377 std::uint16_t port() const
378 {
379 if (!server_started_)
380 {
381 return port_;
382 }
383#ifdef CROW_ENABLE_SSL
384 if (ssl_used_)
385 {
386 return ssl_server_->port();
387 }
388 else
389#endif
390 {
391 return server_->port();
392 }
393 }
394
395 /// \brief Set status variable to note that the address that Crow will handle requests on is bound
397 is_bound_ = true;
398 }
399
400 /// \brief Get whether address that Crow will handle requests on is bound
401 bool is_bound() const {
402 return is_bound_;
403 }
404
405 /// \brief Set the connection timeout in seconds (default is 5)
406 self_t& timeout(std::uint8_t timeout)
407 {
408 timeout_ = timeout;
409 return *this;
410 }
411
412 /// \brief Set the server name included in the 'Server' HTTP response header. If set to an empty string, the header will be omitted by default.
414 {
415 server_name_ = server_name;
416 return *this;
417 }
418
419 /// \brief The IP address that Crow will handle requests on (default is 0.0.0.0)
421 {
422 bindaddr_ = bindaddr;
423 return *this;
424 }
425
426 /// \brief Get the address that Crow will handle requests on
427 std::string bindaddr()
428 {
429 return bindaddr_;
430 }
431
432 /// \brief Disable tcp/ip and use unix domain socket instead
433 self_t& local_socket_path(std::string path)
434 {
435 bindaddr_ = path;
436 use_unix_ = true;
437 return *this;
438 }
439
440 /// \brief Get the unix domain socket path
441 std::string local_socket_path()
442 {
443 return bindaddr_;
444 }
445
446 /// \brief Run the server on multiple threads using all available threads
448 {
449 return concurrency(std::thread::hardware_concurrency());
450 }
451
452 /// \brief Run the server on multiple threads using a specific number
454 {
455 if (concurrency < 2) // Crow can have a minimum of 2 threads running
456 concurrency = 2;
457 concurrency_ = concurrency;
458 return *this;
459 }
460
461 /// \brief Get the number of threads that server is using
462 std::uint16_t concurrency() const
463 {
464 return concurrency_;
465 }
466
467 /// \brief Set the server's log level
468 ///
469 /// Possible values are:
470 /// - crow::LogLevel::Debug (0)
471 /// - crow::LogLevel::Info (1)
472 /// - crow::LogLevel::Warning (2)
473 /// - crow::LogLevel::Error (3)
474 /// - crow::LogLevel::Critical (4)
475 self_t& loglevel(LogLevel level)
476 {
477 crow::logger::setLogLevel(level);
478 return *this;
479 }
480
481 /// \brief Enable or disable TCP_NODELAY for accepted TCP connections.
482 self_t& tcp_nodelay(bool enabled = true)
483 {
484 tcp_socket_options_.no_delay = enabled;
485 return *this;
486 }
487
488 /// \brief Get the TCP_NODELAY setting for HTTP connections.
490 {
491 return tcp_socket_options_;
492 }
493
494 /// \brief Enable or disable TCP_NODELAY for WebSocket connections.
495 /// We also have to differentiate between socket options for http server socket and websocket server socket.
496 self_t& websocket_tcp_nodelay(bool enabled = true)
497 {
498 websocket_tcp_socket_options_.no_delay = enabled;
499 return *this;
500 }
501
502 /// \brief Get the TCP_NODELAY setting for WebSocket connections.
504 {
505 return websocket_tcp_socket_options_;
506 }
507
508 /// \brief Set the response body size (in bytes) beyond which Crow automatically streams responses (Default is 1MiB)
509 ///
510 /// Any streamed response is unaffected by Crow's timer, and therefore won't timeout before a response is fully sent.
511 self_t& stream_threshold(size_t threshold)
512 {
513 res_stream_threshold_ = threshold;
514 return *this;
515 }
516
517 /// \brief Get the response body size (in bytes) beyond which Crow automatically streams responses
519 {
520 return res_stream_threshold_;
521 }
522
523
524 self_t& register_blueprint(Blueprint& blueprint)
525 {
526 router_.register_blueprint(blueprint);
527 return *this;
528 }
529
530 /// \brief Set the function to call to handle uncaught exceptions generated in routes (Default generates error 500).
531 ///
532 /// The function must have the following signature: void(crow::response&).
533 /// It must set the response passed in argument to the function, which will be sent back to the client.
534 /// See Router::default_exception_handler() for the default implementation.
535 template<typename Func>
537 {
538 router_.exception_handler() = std::forward<Func>(f);
539 return *this;
540 }
541
542 std::function<void(crow::response&)>& exception_handler()
543 {
544 return router_.exception_handler();
545 }
546
547 /// \brief Set a custom duration and function to run on every tick
548 template<typename Duration, typename Func>
549 self_t& tick(Duration d, Func f)
550 {
551 tick_interval_ = std::chrono::duration_cast<std::chrono::milliseconds>(d);
552 tick_function_ = f;
553 return *this;
554 }
555
556#ifdef CROW_ENABLE_COMPRESSION
557
558 self_t& use_compression(compression::algorithm algorithm)
559 {
560 comp_algorithm_ = algorithm;
561 compression_used_ = true;
562 return *this;
563 }
564
565 compression::algorithm compression_algorithm()
566 {
567 return comp_algorithm_;
568 }
569
570 bool compression_used() const
571 {
572 return compression_used_;
573 }
574#endif
575
576 /// \brief Apply blueprints
578 {
579#if defined(__APPLE__) || defined(__MACH__)
580 if (router_.blueprints().empty()) return;
581#endif
582
583 for (Blueprint* bp : router_.blueprints())
584 {
585 if (bp->static_dir().empty()) {
586 CROW_LOG_ERROR << "Blueprint " << bp->prefix() << " and its sub-blueprints ignored due to empty static directory.";
587 continue;
588 }
589 auto static_dir_ = crow::utility::normalize_path(bp->static_dir());
590
591 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) {
592 utility::sanitize_filename(file_path_partial);
593 res.set_static_file_info_unsafe(static_dir_ + file_path_partial);
594 res.end();
595 });
596 }
597
598 router_.validate_bp();
599 }
600
601 /// \brief Go through the rules, upgrade them if possible, and add them to the list of rules
603 {
604 if (are_static_routes_added()) return;
605 auto static_dir_ = crow::utility::normalize_path(CROW_STATIC_DIRECTORY);
606
607 route<crow::black_magic::get_parameter_tag(CROW_STATIC_ENDPOINT)>(CROW_STATIC_ENDPOINT)([static_dir_](crow::response& res, std::string file_path_partial) {
608 utility::sanitize_filename(file_path_partial);
609 res.set_static_file_info_unsafe(static_dir_ + file_path_partial);
610 res.end();
611 });
612 set_static_routes_added();
613 }
614
615 /// \brief A wrapper for `validate()` in the router
616 void validate()
617 {
618 router_.validate();
619 }
620
621 /// \brief Run the server
622 void run()
623 {
624#ifndef CROW_DISABLE_STATIC_DIR
627#endif
628 validate();
629
630#ifdef CROW_ENABLE_SSL
631 if (ssl_used_)
632 {
633
634 error_code ec;
635 asio::ip::address addr = asio::ip::make_address(bindaddr_,ec);
636 if (ec){
637 CROW_LOG_ERROR << ec.message() << " - Can not create valid ip address from string: \"" << bindaddr_ << "\"";
638 return;
639 }
640 tcp::endpoint endpoint(addr, port_);
641 router_.using_ssl = true;
642 ssl_server_ = std::move(std::unique_ptr<ssl_server_t>(new ssl_server_t(this, endpoint, server_name_, &middlewares_, concurrency_, timeout_, &ssl_context_, tcp_socket_options_)));
643 ssl_server_->set_tick_function(tick_interval_, tick_function_);
644 ssl_server_->signal_clear();
645 for (auto snum : signals_)
646 {
647 ssl_server_->signal_add(snum);
648 }
649 notify_server_start();
650 ssl_server_->run();
651 }
652 else
653#endif
654 {
655 if (use_unix_)
656 {
657 UnixSocketAcceptor::endpoint endpoint(bindaddr_);
658 unix_server_ = std::move(std::unique_ptr<unix_server_t>(new unix_server_t(this, endpoint, server_name_, &middlewares_, concurrency_, timeout_, nullptr)));
659 unix_server_->set_tick_function(tick_interval_, tick_function_);
660 for (auto snum : signals_)
661 {
662 unix_server_->signal_add(snum);
663 }
664 notify_server_start();
665 unix_server_->run();
666 }
667 else
668 {
669 error_code ec;
670 asio::ip::address addr = asio::ip::make_address(bindaddr_,ec);
671 if (ec){
672 CROW_LOG_ERROR << ec.message() << " - Can not create valid ip address from string: \"" << bindaddr_ << "\"";
673 return;
674 }
675 TCPAcceptor::endpoint endpoint(addr, port_);
676 server_ = std::move(std::unique_ptr<server_t>(new server_t(this, endpoint, server_name_, &middlewares_, concurrency_, timeout_, nullptr, tcp_socket_options_)));
677 server_->set_tick_function(tick_interval_, tick_function_);
678 for (auto snum : signals_)
679 {
680 server_->signal_add(snum);
681 }
682 notify_server_start();
683 server_->run();
684 }
685 }
686 }
687
688 /// \brief Non-blocking version of \ref run()
689 ///
690 /// The output from this method needs to be saved into a variable!
691 /// Otherwise the call will be made on the same thread.
692 std::future<void> run_async()
693 {
694 return std::async(std::launch::async, [&] {
695 this->run();
696 });
697 }
698
699 /// \brief Stop the server
700 void stop()
701 {
702#ifdef CROW_ENABLE_SSL
703 if (ssl_used_)
704 {
705 if (ssl_server_) { ssl_server_->stop(); }
706 }
707 else
708#endif
709 {
710 close_websockets();
711 if (server_) { server_->stop(); }
712 if (unix_server_) { unix_server_->stop(); }
713 }
714 }
715
716 void close_websockets()
717 {
718 std::lock_guard<std::mutex> lock{websockets_mutex_};
719 for (auto websocket : websockets_)
720 {
721 CROW_LOG_INFO << "Quitting Websocket: " << websocket;
722 websocket->close("Websocket Closed");
723 }
724 }
725
726
727 void add_websocket(std::shared_ptr<websocket::connection> conn)
728 {
729 std::lock_guard<std::mutex> lock{websockets_mutex_};
730 websockets_.push_back(conn);
731 }
732
733 void remove_websocket(std::shared_ptr<websocket::connection> conn)
734 {
735 std::lock_guard<std::mutex> lock{websockets_mutex_};
736 websockets_.erase(std::remove(websockets_.begin(), websockets_.end(), conn), websockets_.end());
737 }
738
739 /// \brief Print the routing paths defined for each HTTP method
741 {
742 CROW_LOG_DEBUG << "Routing:";
743 router_.debug_print();
744 }
745
746
747#ifdef CROW_ENABLE_SSL
748
749 /// \brief Use certificate and key files for SSL
750 self_t& ssl_file(const std::string& crt_filename, const std::string& key_filename)
751 {
752 ssl_used_ = true;
753 ssl_context_.set_verify_mode(asio::ssl::verify_peer);
754 ssl_context_.set_verify_mode(asio::ssl::verify_client_once);
755 ssl_context_.use_certificate_file(crt_filename, ssl_context_t::pem);
756 ssl_context_.use_private_key_file(key_filename, ssl_context_t::pem);
757 ssl_context_.set_options(
758 asio::ssl::context::default_workarounds | asio::ssl::context::no_sslv2 | asio::ssl::context::no_sslv3);
759 return *this;
760 }
761
762 /// \brief Use `.pem` file for SSL
763 self_t& ssl_file(const std::string& pem_filename)
764 {
765 ssl_used_ = true;
766 ssl_context_.set_verify_mode(asio::ssl::verify_peer);
767 ssl_context_.set_verify_mode(asio::ssl::verify_client_once);
768 ssl_context_.load_verify_file(pem_filename);
769 ssl_context_.set_options(
770 asio::ssl::context::default_workarounds | asio::ssl::context::no_sslv2 | asio::ssl::context::no_sslv3);
771 return *this;
772 }
773
774 /// \brief Use certificate chain and key files for SSL
775 self_t& ssl_chainfile(const std::string& crt_filename, const std::string& key_filename)
776 {
777 ssl_used_ = true;
778 ssl_context_.set_verify_mode(asio::ssl::verify_peer);
779 ssl_context_.set_verify_mode(asio::ssl::verify_client_once);
780 ssl_context_.use_certificate_chain_file(crt_filename);
781 ssl_context_.use_private_key_file(key_filename, ssl_context_t::pem);
782 ssl_context_.set_options(
783 asio::ssl::context::default_workarounds | asio::ssl::context::no_sslv2 | asio::ssl::context::no_sslv3);
784 return *this;
785 }
786
787 self_t& ssl(asio::ssl::context&& ctx)
788 {
789 ssl_used_ = true;
790 ssl_context_ = std::move(ctx);
791 return *this;
792 }
793
794 bool ssl_used() const
795 {
796 return ssl_used_;
797 }
798#else
799
800 template<typename T, typename... Remain>
801 self_t& ssl_file(T&&, Remain&&...)
802 {
803 // We can't call .ssl() member function unless CROW_ENABLE_SSL is defined.
804 static_assert(
805 // make static_assert dependent to T; always false
806 std::is_base_of<T, void>::value,
807 "Define CROW_ENABLE_SSL to enable ssl support.");
808 return *this;
809 }
810
811 template<typename T, typename... Remain>
812 self_t& ssl_chainfile(T&&, Remain&&...)
813 {
814 // We can't call .ssl() member function unless CROW_ENABLE_SSL is defined.
815 static_assert(
816 // make static_assert dependent to T; always false
817 std::is_base_of<T, void>::value,
818 "Define CROW_ENABLE_SSL to enable ssl support.");
819 return *this;
820 }
821
822 template<typename T>
823 self_t& ssl(T&&)
824 {
825 // We can't call .ssl() member function unless CROW_ENABLE_SSL is defined.
826 static_assert(
827 // make static_assert dependent to T; always false
828 std::is_base_of<T, void>::value,
829 "Define CROW_ENABLE_SSL to enable ssl support.");
830 return *this;
831 }
832
833 bool ssl_used() const
834 {
835 return false;
836 }
837#endif
838
839 // middleware
840 using context_t = detail::context<Middlewares...>;
841 using mw_container_t = std::tuple<Middlewares...>;
842 template<typename T>
843 typename T::context& get_context(const request& req)
844 {
845 static_assert(black_magic::contains<T, Middlewares...>::value, "App doesn't have the specified middleware type.");
846 auto& ctx = *reinterpret_cast<context_t*>(req.middleware_context);
847 return ctx.template get<T>();
848 }
849
850 template<typename T>
851 T& get_middleware()
852 {
853 return utility::get_element_by_type<T, Middlewares...>(middlewares_);
854 }
855
856 /// \brief Wait until the server has properly started
857 std::cv_status wait_for_server_start(std::chrono::milliseconds wait_timeout = std::chrono::milliseconds(3000))
858 {
859 std::cv_status status = std::cv_status::no_timeout;
860 auto wait_until = std::chrono::steady_clock::now() + wait_timeout;
861 {
862 std::unique_lock<std::mutex> lock(start_mutex_);
863 while (!server_started_ && (status == std::cv_status::no_timeout))
864 {
865 status = cv_started_.wait_until(lock, wait_until);
866 }
867 }
868 if (status == std::cv_status::no_timeout)
869 {
870 if (server_) {
871 status = server_->wait_for_start(wait_until);
872 } else if (unix_server_) {
873 status = unix_server_->wait_for_start(wait_until);
874 }
875#ifdef CROW_ENABLE_SSL
876 else if (ssl_server_)
877 {
878 status = ssl_server_->wait_for_start(wait_until);
879 }
880#endif
881 }
882 return status;
883 }
884
885 private:
886 template<typename... Ts>
887 std::tuple<Middlewares...> make_middleware_tuple(Ts&&... ts)
888 {
889 auto fwd = std::forward_as_tuple((ts)...);
890 return std::make_tuple(
891 std::forward<Middlewares>(
892 black_magic::tuple_extract<Middlewares, decltype(fwd)>(fwd))...);
893 }
894
895 /// \brief Notify anything using \ref wait_for_server_start() to proceed
896 void notify_server_start()
897 {
898 std::unique_lock<std::mutex> lock(start_mutex_);
899 server_started_ = true;
900 cv_started_.notify_all();
901 }
902
903 void set_static_routes_added() {
904 static_routes_added_ = true;
905 }
906
907 bool are_static_routes_added() {
908 return static_routes_added_;
909 }
910
911 private:
912 std::uint8_t timeout_{5};
913 uint16_t port_ = 80;
914 unsigned int concurrency_ = 2;
915 std::atomic_bool is_bound_ = false;
916 uint64_t max_payload_{UINT64_MAX};
917 std::string server_name_ = std::string("Crow/") + VERSION;
918 std::string bindaddr_ = "0.0.0.0";
919 bool use_unix_ = false;
920 detail::socket::tcp_socket_options tcp_socket_options_{};
921 detail::socket::tcp_socket_options websocket_tcp_socket_options_{};
922 size_t res_stream_threshold_ = 1048576;
923 Router router_;
924 bool static_routes_added_{false};
925
926#ifdef CROW_ENABLE_COMPRESSION
927 compression::algorithm comp_algorithm_;
928 bool compression_used_{false};
929#endif
930
931 std::chrono::milliseconds tick_interval_;
932 std::function<void()> tick_function_;
933
934 std::tuple<Middlewares...> middlewares_;
935
936#ifdef CROW_ENABLE_SSL
937 std::unique_ptr<ssl_server_t> ssl_server_;
938 bool ssl_used_{false};
939 ssl_context_t ssl_context_{asio::ssl::context::sslv23};
940#endif
941
942 std::unique_ptr<server_t> server_;
943 std::unique_ptr<unix_server_t> unix_server_;
944
945 std::vector<int> signals_{SIGINT, SIGTERM};
946
947 bool server_started_{false};
948 std::condition_variable cv_started_;
949 std::mutex start_mutex_;
950 std::mutex websockets_mutex_; ///< \brief mutex to protect websockets_
951 std::vector<std::shared_ptr<websocket::connection>> websockets_;
952 };
953
954 /// \brief Alias of Crow<Middlewares...>. Useful if you want
955 /// a instance of an Crow application that require Middlewares
956 template<typename... Middlewares>
957 using App = Crow<Middlewares...>;
958
959 /// \brief Alias of Crow<>. Useful if you want a instance of
960 /// an Crow application that doesn't require of Middlewares
962} // namespace crow
A blueprint can be considered a smaller section of a Crow app, specifically where the router is conce...
Definition routing.h:1150
Definition routing.h:345
The main server application class.
Definition app.h:214
void stop()
Stop the server.
Definition app.h:700
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:511
std::cv_status wait_for_server_start(std::chrono::milliseconds wait_timeout=std::chrono::milliseconds(3000))
Wait until the server has properly started.
Definition app.h:857
void run()
Run the server.
Definition app.h:622
self_t & timeout(std::uint8_t timeout)
Set the connection timeout in seconds (default is 5)
Definition app.h:406
uint64_t websocket_max_payload()
Get the default max payload size for websockets.
Definition app.h:347
void add_static_dir()
Go through the rules, upgrade them if possible, and add them to the list of rules.
Definition app.h:602
Server< Crow, UnixSocketAcceptor, UnixSocketAdaptor, Middlewares... > unix_server_t
An HTTP server that runs on unix domain socket.
Definition app.h:222
StaticRule & route_static(const std::string &url)
Create a static route to given url.
Definition app.h:310
Crow self_t
This is the crow application.
Definition app.h:217
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:775
self_t & server_name(std::string server_name)
Set the server name included in the 'Server' HTTP response header. If set to an empty string,...
Definition app.h:413
self_t & ssl_file(const std::string &crt_filename, const std::string &key_filename)
Use certificate and key files for SSL.
Definition app.h:750
void handle_upgrade(const request &req, response &res, Adaptor &&adaptor)
Process an Upgrade request.
Definition app.h:266
self_t & websocket_tcp_nodelay(bool enabled=true)
Enable or disable TCP_NODELAY for WebSocket connections. We also have to differentiate between socket...
Definition app.h:496
self_t & multithreaded()
Run the server on multiple threads using all available threads.
Definition app.h:447
self_t & tick(Duration d, Func f)
Set a custom duration and function to run on every tick.
Definition app.h:549
self_t & local_socket_path(std::string path)
Disable tcp/ip and use unix domain socket instead.
Definition app.h:433
void debug_print()
Print the routing paths defined for each HTTP method.
Definition app.h:740
self_t & tcp_nodelay(bool enabled=true)
Enable or disable TCP_NODELAY for accepted TCP connections.
Definition app.h:482
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:278
std::string bindaddr()
Get the address that Crow will handle requests on.
Definition app.h:427
self_t & port(std::uint16_t port)
Set the port that Crow will handle requests on.
Definition app.h:370
bool is_bound() const
Get whether address that Crow will handle requests on is bound.
Definition app.h:401
std::uint16_t port() const
Get the port that Crow will handle requests on.
Definition app.h:377
self_t & concurrency(unsigned int concurrency)
Run the server on multiple threads using a specific number.
Definition app.h:453
Server< Crow, TCPAcceptor, SSLAdaptor, Middlewares... > ssl_server_t
An HTTP server that runs on SSL with an SSLAdaptor.
Definition app.h:225
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:536
self_t & bindaddr(std::string bindaddr)
The IP address that Crow will handle requests on (default is 0.0.0.0)
Definition app.h:420
Server< Crow, TCPAcceptor, SocketAdaptor, Middlewares... > server_t
The HTTP server.
Definition app.h:220
void validate()
A wrapper for validate() in the router.
Definition app.h:616
Crow(Ts &&... ts)
Construct Crow with a subset of middleware.
Definition app.h:258
CatchallRule & catchall_route()
Create a route for any requests without a proper route (Use CROW_CATCHALL_ROUTE instead)
Definition app.h:334
self_t & websocket_max_payload(uint64_t max_payload)
Set the default max payload size for websockets.
Definition app.h:340
void handle_full(request &req, response &res)
Process a fully parsed request from start to finish (primarily used for debugging)
Definition app.h:284
StaticRule & static_file(std::string_view url, std::string_view internalPath)
Creates a static route for given url to internalPath.
Definition app.h:321
self_t & ssl_file(const std::string &pem_filename)
Use .pem file for SSL.
Definition app.h:763
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:272
std::string local_socket_path()
Get the unix domain socket path.
Definition app.h:441
DynamicRule & route_dynamic(const std::string &rule)
Create a dynamic route using a rule (Use CROW_ROUTE instead)
Definition app.h:292
self_t & loglevel(LogLevel level)
Set the server's log level.
Definition app.h:475
void add_blueprint()
Apply blueprints.
Definition app.h:577
void address_is_bound()
Set status variable to note that the address that Crow will handle requests on is bound.
Definition app.h:396
auto route(const std::string &rule) -> typename std::invoke_result< decltype(&Router::new_rule_tagged< Tag >), Router, const std::string & >::type
Create a route using a rule (Use CROW_ROUTE instead)
Definition app.h:299
size_t & stream_threshold()
Get the response body size (in bytes) beyond which Crow automatically streams responses.
Definition app.h:518
std::uint16_t concurrency() const
Get the number of threads that server is using.
Definition app.h:462
detail::socket::tcp_socket_options websocket_tcp_socket_options() const
Get the TCP_NODELAY setting for WebSocket connections.
Definition app.h:503
detail::socket::tcp_socket_options tcp_socket_options() const
Get the TCP_NODELAY setting for HTTP connections.
Definition app.h:489
std::future< void > run_async()
Non-blocking version of run()
Definition app.h:692
A rule that can change its parameters during runtime.
Definition routing.h:625
Handles matching requests to existing rules and upgrade requests.
Definition routing.h:1304
Definition http_server.h:47
Default rule created when CROW_ROUTE is called.
Definition routing.h:703
A rule dealing with websockets.
Definition routing.h:425
The main namespace of the library. In this namespace is defined the most important classes and functi...
Definition socket_adaptors.h:184
A wrapper for the asio::ip::tcp::socket and asio::ssl::stream.
Definition socket_adaptors.h:40
Definition socket_acceptors.h:31
Definition socket_acceptors.h:62
Definition socket_adaptors.h:112
Definition tcp_socket_options.h:29
An HTTP request.
Definition http_request.h:47
HTTP response.
Definition http_response.h:40
void set_static_file_info(std::string path, std::string content_type="")
Return a static file as the response body, the content_type may be specified explicitly.
Definition http_response.h:301
void set_static_file_info_unsafe(std::string path, std::string content_type="")
Definition http_response.h:309
void end()
Set the response completion flag and call the handler (to send the response).
Definition http_response.h:250