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