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 Set the filesystem directory for implicit static file serving.
433 ///
434 /// Defaults to \ref CROW_STATIC_DIRECTORY (`"static/"`). Must be called
435 /// before \ref run() / \ref run_async(). Does not change
436 /// \ref CROW_STATIC_ENDPOINT.
437 self_t& static_directory(std::string path)
438 {
439 static_directory_ = std::move(path);
440 return *this;
441 }
442
443 /// \brief Get the filesystem directory used for implicit static files
444 std::string static_directory() const
445 {
446 return static_directory_;
447 }
448
449 /// \brief Disable tcp/ip and use unix domain socket instead
450 self_t& local_socket_path(std::string path)
451 {
452 bindaddr_ = path;
453 use_unix_ = true;
454 return *this;
455 }
456
457 /// \brief Get the unix domain socket path
458 std::string local_socket_path()
459 {
460 return bindaddr_;
461 }
462
463 /// \brief Run the server on multiple threads using all available threads
465 {
466 return concurrency(std::thread::hardware_concurrency());
467 }
468
469 /// \brief Run the server on multiple threads using a specific number
471 {
472 if (concurrency < 2) // Crow can have a minimum of 2 threads running
473 concurrency = 2;
474 concurrency_ = concurrency;
475 return *this;
476 }
477
478 /// \brief Get the number of threads that server is using
479 std::uint16_t concurrency() const
480 {
481 return concurrency_;
482 }
483
484 /// \brief Set the server's log level
485 ///
486 /// Possible values are:
487 /// - crow::LogLevel::Debug (0)
488 /// - crow::LogLevel::Info (1)
489 /// - crow::LogLevel::Warning (2)
490 /// - crow::LogLevel::Error (3)
491 /// - crow::LogLevel::Critical (4)
492 self_t& loglevel(LogLevel level)
493 {
494 crow::logger::setLogLevel(level);
495 return *this;
496 }
497
498 /// \brief Enable or disable TCP_NODELAY for accepted TCP connections.
499 self_t& tcp_nodelay(bool enabled = true)
500 {
501 tcp_socket_options_.no_delay = enabled;
502 return *this;
503 }
504
505 /// \brief Get the TCP_NODELAY setting for HTTP connections.
507 {
508 return tcp_socket_options_;
509 }
510
511 /// \brief Enable or disable TCP_NODELAY for WebSocket connections.
512 /// We also have to differentiate between socket options for http server socket and websocket server socket.
513 self_t& websocket_tcp_nodelay(bool enabled = true)
514 {
515 websocket_tcp_socket_options_.no_delay = enabled;
516 return *this;
517 }
518
519 /// \brief Get the TCP_NODELAY setting for WebSocket connections.
521 {
522 return websocket_tcp_socket_options_;
523 }
524
525 /// \brief Set the response body size (in bytes) beyond which Crow automatically streams responses (Default is 1MiB)
526 ///
527 /// Any streamed response is unaffected by Crow's timer, and therefore won't timeout before a response is fully sent.
528 self_t& stream_threshold(size_t threshold)
529 {
530 res_stream_threshold_ = threshold;
531 return *this;
532 }
533
534 /// \brief Get the response body size (in bytes) beyond which Crow automatically streams responses
536 {
537 return res_stream_threshold_;
538 }
539
540
541 self_t& register_blueprint(Blueprint& blueprint)
542 {
543 router_.register_blueprint(blueprint);
544 return *this;
545 }
546
547 /// \brief Set the function to call to handle uncaught exceptions generated in routes (Default generates error 500).
548 ///
549 /// The function must have the following signature: void(crow::response&).
550 /// It must set the response passed in argument to the function, which will be sent back to the client.
551 /// See Router::default_exception_handler() for the default implementation.
552 template<typename Func>
554 {
555 router_.exception_handler() = std::forward<Func>(f);
556 return *this;
557 }
558
559 std::function<void(crow::response&)>& exception_handler()
560 {
561 return router_.exception_handler();
562 }
563
564 /// \brief Set a custom duration and function to run on every tick
565 template<typename Duration, typename Func>
566 self_t& tick(Duration d, Func f)
567 {
568 tick_interval_ = std::chrono::duration_cast<std::chrono::milliseconds>(d);
569 tick_function_ = f;
570 return *this;
571 }
572
573#ifdef CROW_ENABLE_COMPRESSION
574
575 self_t& use_compression(compression::algorithm algorithm)
576 {
577 comp_algorithm_ = algorithm;
578 compression_used_ = true;
579 return *this;
580 }
581
582 compression::algorithm compression_algorithm()
583 {
584 return comp_algorithm_;
585 }
586
587 bool compression_used() const
588 {
589 return compression_used_;
590 }
591#endif
592
593 /// \brief Apply blueprints
595 {
596#if defined(__APPLE__) || defined(__MACH__)
597 if (router_.blueprints().empty()) return;
598#endif
599
600 for (Blueprint* bp : router_.blueprints())
601 {
602 if (bp->static_dir().empty()) {
603 CROW_LOG_ERROR << "Blueprint " << bp->prefix() << " and its sub-blueprints ignored due to empty static directory.";
604 continue;
605 }
606 auto static_dir_ = crow::utility::normalize_path(bp->static_dir());
607
608 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) {
609 utility::sanitize_filename(file_path_partial);
610 res.set_static_file_info_unsafe(static_dir_ + file_path_partial);
611 res.end();
612 });
613 }
614
615 router_.validate_bp();
616 }
617
618 /// \brief Go through the rules, upgrade them if possible, and add them to the list of rules
620 {
621 if (are_static_routes_added()) return;
622 auto static_dir_ = crow::utility::normalize_path(static_directory_);
623
624 route<crow::black_magic::get_parameter_tag(CROW_STATIC_ENDPOINT)>(CROW_STATIC_ENDPOINT)([static_dir_](crow::response& res, std::string file_path_partial) {
625 utility::sanitize_filename(file_path_partial);
626 res.set_static_file_info_unsafe(static_dir_ + file_path_partial);
627 res.end();
628 });
629 set_static_routes_added();
630 }
631
632 /// \brief A wrapper for `validate()` in the router
633 void validate()
634 {
635 // Always validate blueprints so routes remain available when
636 // CROW_DISABLE_STATIC_DIR skips add_blueprint()/add_static_dir().
637 router_.validate_bp();
638 router_.validate();
639 }
640
641 /// \brief Run the server
642 void run()
643 {
644#ifndef CROW_DISABLE_STATIC_DIR
647#endif
648 validate();
649
650#ifdef CROW_ENABLE_SSL
651 if (ssl_used_)
652 {
653
654 error_code ec;
655 asio::ip::address addr = asio::ip::make_address(bindaddr_,ec);
656 if (ec){
657 CROW_LOG_ERROR << ec.message() << " - Can not create valid ip address from string: \"" << bindaddr_ << "\"";
658 return;
659 }
660 tcp::endpoint endpoint(addr, port_);
661 router_.using_ssl = true;
662 ssl_server_ = std::make_unique<ssl_server_t>(this, endpoint, server_name_, &middlewares_, concurrency_, timeout_, &ssl_context_, tcp_socket_options_);
663 ssl_server_->set_tick_function(tick_interval_, tick_function_);
664 ssl_server_->signal_clear();
665 for (auto snum : signals_)
666 {
667 ssl_server_->signal_add(snum);
668 }
669 notify_server_start();
670 ssl_server_->run();
671 }
672 else
673#endif
674 {
675 if (use_unix_)
676 {
677 UnixSocketAcceptor::endpoint endpoint(bindaddr_);
678 unix_server_ = std::make_unique<unix_server_t>(this, endpoint, server_name_, &middlewares_, concurrency_, timeout_, nullptr);
679 unix_server_->set_tick_function(tick_interval_, tick_function_);
680 for (auto snum : signals_)
681 {
682 unix_server_->signal_add(snum);
683 }
684 notify_server_start();
685 unix_server_->run();
686 }
687 else
688 {
689 error_code ec;
690 asio::ip::address addr = asio::ip::make_address(bindaddr_,ec);
691 if (ec){
692 CROW_LOG_ERROR << ec.message() << " - Can not create valid ip address from string: \"" << bindaddr_ << "\"";
693 return;
694 }
695 TCPAcceptor::endpoint endpoint(addr, port_);
696 server_ = std::make_unique<server_t>(this, endpoint, server_name_, &middlewares_, concurrency_, timeout_, nullptr, tcp_socket_options_);
697 server_->set_tick_function(tick_interval_, tick_function_);
698 for (auto snum : signals_)
699 {
700 server_->signal_add(snum);
701 }
702 notify_server_start();
703 server_->run();
704 }
705 }
706 }
707
708 /// \brief Non-blocking version of \ref run()
709 ///
710 /// The output from this method needs to be saved into a variable!
711 /// Otherwise the call will be made on the same thread.
712 std::future<void> run_async()
713 {
714 return std::async(std::launch::async, [&] {
715 this->run();
716 });
717 }
718
719 /// \brief Stop the server
720 void stop()
721 {
722#ifdef CROW_ENABLE_SSL
723 if (ssl_used_)
724 {
725 if (ssl_server_) { ssl_server_->stop(); }
726 }
727 else
728#endif
729 {
730 close_websockets();
731 if (server_) { server_->stop(); }
732 if (unix_server_) { unix_server_->stop(); }
733 }
734 }
735
736 void close_websockets()
737 {
738 std::lock_guard<std::mutex> lock{websockets_mutex_};
739 for (auto websocket : websockets_)
740 {
741 CROW_LOG_INFO << "Quitting Websocket: " << websocket;
742 websocket->close("Websocket Closed");
743 }
744 }
745
746
747 void add_websocket(std::shared_ptr<websocket::connection> conn)
748 {
749 std::lock_guard<std::mutex> lock{websockets_mutex_};
750 websockets_.push_back(conn);
751 }
752
753 void remove_websocket(std::shared_ptr<websocket::connection> conn)
754 {
755 std::lock_guard<std::mutex> lock{websockets_mutex_};
756 websockets_.erase(std::remove(websockets_.begin(), websockets_.end(), conn), websockets_.end());
757 }
758
759 /// \brief Print the routing paths defined for each HTTP method
761 {
762 CROW_LOG_DEBUG << "Routing:";
763 router_.debug_print();
764 }
765
766
767#ifdef CROW_ENABLE_SSL
768
769 /// \brief Use certificate and key files for SSL
770 self_t& ssl_file(const std::string& crt_filename, const std::string& key_filename)
771 {
772 ssl_used_ = true;
773 ssl_context_.set_verify_mode(asio::ssl::verify_peer);
774 ssl_context_.set_verify_mode(asio::ssl::verify_client_once);
775 ssl_context_.use_certificate_file(crt_filename, ssl_context_t::pem);
776 ssl_context_.use_private_key_file(key_filename, ssl_context_t::pem);
777 ssl_context_.set_options(
778 asio::ssl::context::default_workarounds | asio::ssl::context::no_sslv2 | asio::ssl::context::no_sslv3);
779 return *this;
780 }
781
782 /// \brief Use `.pem` file for SSL
783 self_t& ssl_file(const std::string& pem_filename)
784 {
785 ssl_used_ = true;
786 ssl_context_.set_verify_mode(asio::ssl::verify_peer);
787 ssl_context_.set_verify_mode(asio::ssl::verify_client_once);
788 ssl_context_.load_verify_file(pem_filename);
789 ssl_context_.set_options(
790 asio::ssl::context::default_workarounds | asio::ssl::context::no_sslv2 | asio::ssl::context::no_sslv3);
791 return *this;
792 }
793
794 /// \brief Use certificate chain and key files for SSL
795 self_t& ssl_chainfile(const std::string& crt_filename, const std::string& key_filename)
796 {
797 ssl_used_ = true;
798 ssl_context_.set_verify_mode(asio::ssl::verify_peer);
799 ssl_context_.set_verify_mode(asio::ssl::verify_client_once);
800 ssl_context_.use_certificate_chain_file(crt_filename);
801 ssl_context_.use_private_key_file(key_filename, ssl_context_t::pem);
802 ssl_context_.set_options(
803 asio::ssl::context::default_workarounds | asio::ssl::context::no_sslv2 | asio::ssl::context::no_sslv3);
804 return *this;
805 }
806
807 self_t& ssl(asio::ssl::context&& ctx)
808 {
809 ssl_used_ = true;
810 ssl_context_ = std::move(ctx);
811 return *this;
812 }
813
814 bool ssl_used() const
815 {
816 return ssl_used_;
817 }
818#else
819
820 template<typename T, typename... Remain>
821 self_t& ssl_file(T&&, Remain&&...)
822 {
823 // We can't call .ssl() member function unless CROW_ENABLE_SSL is defined.
824 static_assert(
825 // make static_assert dependent to T; always false
826 std::is_base_of<T, void>::value,
827 "Define CROW_ENABLE_SSL to enable ssl support.");
828 return *this;
829 }
830
831 template<typename T, typename... Remain>
832 self_t& ssl_chainfile(T&&, Remain&&...)
833 {
834 // We can't call .ssl() member function unless CROW_ENABLE_SSL is defined.
835 static_assert(
836 // make static_assert dependent to T; always false
837 std::is_base_of<T, void>::value,
838 "Define CROW_ENABLE_SSL to enable ssl support.");
839 return *this;
840 }
841
842 template<typename T>
843 self_t& ssl(T&&)
844 {
845 // We can't call .ssl() member function unless CROW_ENABLE_SSL is defined.
846 static_assert(
847 // make static_assert dependent to T; always false
848 std::is_base_of<T, void>::value,
849 "Define CROW_ENABLE_SSL to enable ssl support.");
850 return *this;
851 }
852
853 bool ssl_used() const
854 {
855 return false;
856 }
857#endif
858
859 // middleware
860 using context_t = detail::context<Middlewares...>;
861 using mw_container_t = std::tuple<Middlewares...>;
862 template<typename T>
863 typename T::context& get_context(const request& req)
864 {
865 static_assert(black_magic::contains<T, Middlewares...>::value, "App doesn't have the specified middleware type.");
866 auto& ctx = *reinterpret_cast<context_t*>(req.middleware_context);
867 return ctx.template get<T>();
868 }
869
870 template<typename T>
871 T& get_middleware()
872 {
873 return utility::get_element_by_type<T, Middlewares...>(middlewares_);
874 }
875
876 /// \brief Wait until the server has properly started
877 std::cv_status wait_for_server_start(std::chrono::milliseconds wait_timeout = std::chrono::milliseconds(3000))
878 {
879 std::cv_status status = std::cv_status::no_timeout;
880 auto wait_until = std::chrono::steady_clock::now() + wait_timeout;
881 {
882 std::unique_lock<std::mutex> lock(start_mutex_);
883 while (!server_started_ && (status == std::cv_status::no_timeout))
884 {
885 status = cv_started_.wait_until(lock, wait_until);
886 }
887 }
888 if (status == std::cv_status::no_timeout)
889 {
890 if (server_) {
891 status = server_->wait_for_start(wait_until);
892 } else if (unix_server_) {
893 status = unix_server_->wait_for_start(wait_until);
894 }
895#ifdef CROW_ENABLE_SSL
896 else if (ssl_server_)
897 {
898 status = ssl_server_->wait_for_start(wait_until);
899 }
900#endif
901 }
902 return status;
903 }
904
905 private:
906 template<typename... Ts>
907 std::tuple<Middlewares...> make_middleware_tuple(Ts&&... ts)
908 {
909 auto fwd = std::forward_as_tuple((ts)...);
910 return std::make_tuple(
911 std::forward<Middlewares>(
912 black_magic::tuple_extract<Middlewares, decltype(fwd)>(fwd))...);
913 }
914
915 /// \brief Notify anything using \ref wait_for_server_start() to proceed
916 void notify_server_start()
917 {
918 std::unique_lock<std::mutex> lock(start_mutex_);
919 server_started_ = true;
920 cv_started_.notify_all();
921 }
922
923 void set_static_routes_added() {
924 static_routes_added_ = true;
925 }
926
927 bool are_static_routes_added() {
928 return static_routes_added_;
929 }
930
931 private:
932 std::uint8_t timeout_{5};
933 uint16_t port_ = 80;
934 unsigned int concurrency_ = 2;
935 std::atomic_bool is_bound_ = false;
936 uint64_t max_payload_{UINT64_MAX};
937 std::string server_name_ = std::string("Crow/") + VERSION;
938 std::string bindaddr_ = "0.0.0.0";
939 std::string static_directory_ = CROW_STATIC_DIRECTORY;
940 bool use_unix_ = false;
941 detail::socket::tcp_socket_options tcp_socket_options_{};
942 detail::socket::tcp_socket_options websocket_tcp_socket_options_{};
943 size_t res_stream_threshold_ = 1048576;
944 Router router_;
945 bool static_routes_added_{false};
946
947#ifdef CROW_ENABLE_COMPRESSION
948 compression::algorithm comp_algorithm_;
949 bool compression_used_{false};
950#endif
951
952 std::chrono::milliseconds tick_interval_;
953 std::function<void()> tick_function_;
954
955 std::tuple<Middlewares...> middlewares_;
956
957#ifdef CROW_ENABLE_SSL
958 std::unique_ptr<ssl_server_t> ssl_server_;
959 bool ssl_used_{false};
960 ssl_context_t ssl_context_{asio::ssl::context::sslv23};
961#endif
962
963 std::unique_ptr<server_t> server_;
964 std::unique_ptr<unix_server_t> unix_server_;
965
966 std::vector<int> signals_{SIGINT, SIGTERM};
967
968 bool server_started_{false};
969 std::condition_variable cv_started_;
970 std::mutex start_mutex_;
971 std::mutex websockets_mutex_; ///< \brief mutex to protect websockets_
972 std::vector<std::shared_ptr<websocket::connection>> websockets_;
973 };
974
975 /// \brief Alias of Crow<Middlewares...>. Useful if you want
976 /// a instance of an Crow application that require Middlewares
977 template<typename... Middlewares>
978 using App = Crow<Middlewares...>;
979
980 /// \brief Alias of Crow<>. Useful if you want a instance of
981 /// an Crow application that doesn't require of Middlewares
983} // 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:720
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:528
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:877
std::string static_directory() const
Get the filesystem directory used for implicit static files.
Definition app.h:444
void run()
Run the server.
Definition app.h:642
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:619
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:795
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:770
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:513
self_t & multithreaded()
Run the server on multiple threads using all available threads.
Definition app.h:464
self_t & tick(Duration d, Func f)
Set a custom duration and function to run on every tick.
Definition app.h:566
self_t & local_socket_path(std::string path)
Disable tcp/ip and use unix domain socket instead.
Definition app.h:450
void debug_print()
Print the routing paths defined for each HTTP method.
Definition app.h:760
self_t & tcp_nodelay(bool enabled=true)
Enable or disable TCP_NODELAY for accepted TCP connections.
Definition app.h:499
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:470
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:553
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
void validate()
A wrapper for validate() in the router.
Definition app.h:633
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:783
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:458
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:492
self_t & static_directory(std::string path)
Set the filesystem directory for implicit static file serving.
Definition app.h:437
void add_blueprint()
Apply blueprints.
Definition app.h:594
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:535
std::uint16_t concurrency() const
Get the number of threads that server is using.
Definition app.h:479
detail::socket::tcp_socket_options websocket_tcp_socket_options() const
Get the TCP_NODELAY setting for WebSocket connections.
Definition app.h:520
detail::socket::tcp_socket_options tcp_socket_options() const
Get the TCP_NODELAY setting for HTTP connections.
Definition app.h:506
std::future< void > run_async()
Non-blocking version of run()
Definition app.h:712
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:62
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:198
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:120
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