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 Crow()
228 {}
229
230 /// \brief Construct Crow with a subset of middleware
231 template<typename... Ts>
232 Crow(Ts&&... ts):
233 middlewares_(make_middleware_tuple(std::forward<Ts>(ts)...))
234 {}
235
236 /// \brief Process an Upgrade request
237 ///
238 /// Currently used to upgrade an HTTP connection to a WebSocket connection
239 template<typename Adaptor>
240 void handle_upgrade(const request& req, response& res, Adaptor&& adaptor)
241 {
242 router_.handle_upgrade(req, res, adaptor);
243 }
244
245 /// \brief Process only the method and URL of a request and provide a route (or an error response)
246 std::unique_ptr<routing_handle_result> handle_initial(request& req, response& res)
247 {
248 return router_.handle_initial(req, res);
249 }
250
251 /// \brief Process the fully parsed request and generate a response for it
252 void handle(request& req, response& res, std::unique_ptr<routing_handle_result>& found)
253 {
254 router_.handle<self_t>(req, res, *found);
255 }
256
257 /// \brief Process a fully parsed request from start to finish (primarily used for debugging)
258 void handle_full(request& req, response& res)
259 {
260 auto found = handle_initial(req, res);
261 if (found->rule_index || found->catch_all)
262 handle(req, res, found);
263 }
264
265 /// \brief Create a dynamic route using a rule (**Use CROW_ROUTE instead**)
266 DynamicRule& route_dynamic(const std::string& rule)
267 {
268 return router_.new_rule_dynamic(rule);
269 }
270
271 /// \brief Create a route using a rule (**Use CROW_ROUTE instead**)
272 template<uint64_t Tag>
273 auto route(const std::string& rule)
274 -> typename std::invoke_result<decltype(&Router::new_rule_tagged<Tag>), Router, const std::string&>::type
275 {
276 return router_.new_rule_tagged<Tag>(rule);
277 }
278
279 /// \brief Create a static route to given url
280 ///
281 /// \param url public URL
282 /// \return The rule
283 ///
284 StaticRule& route_static(const std::string& url)
285 {
286 return router_.new_rule<StaticRule>(url);
287 }
288
289 /// \brief Creates a static route for given url to internalPath.
290 ///
291 /// \param url public URL
292 /// \param internalPath internal path to reach te file
293 /// \return The rule
294 ///
295 StaticRule& static_file(std::string_view url, std::string_view internalPath){
296 StaticRule& rt = route_static(std::string(url));
297
298 // make a copy of given view of internalPath
299 rt([=,localFile=std::string(internalPath)](crow::response& resp) -> void {
300 resp.set_static_file_info(localFile);
301 resp.end();
302 });
303
304 return rt;
305 }
306
307 /// \brief Create a route for any requests without a proper route (**Use CROW_CATCHALL_ROUTE instead**)
309 {
310 return router_.catchall_rule();
311 }
312
313 /// \brief Set the default max payload size for websockets
314 self_t& websocket_max_payload(uint64_t max_payload)
315 {
316 max_payload_ = max_payload;
317 return *this;
318 }
319
320 /// \brief Get the default max payload size for websockets
322 {
323 return max_payload_;
324 }
325
326 self_t& signal_clear()
327 {
328 signals_.clear();
329 return *this;
330 }
331
332 self_t& signal_add(int signal_number)
333 {
334 signals_.push_back(signal_number);
335 return *this;
336 }
337
338 std::vector<int> signals()
339 {
340 return signals_;
341 }
342
343 /// \brief Set the port that Crow will handle requests on
344 self_t& port(std::uint16_t port)
345 {
346 port_ = port;
347 return *this;
348 }
349
350 /// \brief Get the port that Crow will handle requests on
351 std::uint16_t port() const
352 {
353 if (!server_started_)
354 {
355 return port_;
356 }
357#ifdef CROW_ENABLE_SSL
358 if (ssl_used_)
359 {
360 return ssl_server_->port();
361 }
362 else
363#endif
364 {
365 return server_->port();
366 }
367 }
368
369 /// \brief Set status variable to note that the address that Crow will handle requests on is bound
371 is_bound_ = true;
372 }
373
374 /// \brief Get whether address that Crow will handle requests on is bound
375 bool is_bound() const {
376 return is_bound_;
377 }
378
379 /// \brief Set the connection timeout in seconds (default is 5)
380 self_t& timeout(std::uint8_t timeout)
381 {
382 timeout_ = timeout;
383 return *this;
384 }
385
386 /// \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.
388 {
389 server_name_ = server_name;
390 return *this;
391 }
392
393 /// \brief The IP address that Crow will handle requests on (default is 0.0.0.0)
395 {
396 bindaddr_ = bindaddr;
397 return *this;
398 }
399
400 /// \brief Get the address that Crow will handle requests on
401 std::string bindaddr()
402 {
403 return bindaddr_;
404 }
405
406 /// \brief Disable tcp/ip and use unix domain socket instead
407 self_t& local_socket_path(std::string path)
408 {
409 bindaddr_ = path;
410 use_unix_ = true;
411 return *this;
412 }
413
414 /// \brief Get the unix domain socket path
415 std::string local_socket_path()
416 {
417 return bindaddr_;
418 }
419
420 /// \brief Run the server on multiple threads using all available threads
422 {
423 return concurrency(std::thread::hardware_concurrency());
424 }
425
426 /// \brief Run the server on multiple threads using a specific number
428 {
429 if (concurrency < 2) // Crow can have a minimum of 2 threads running
430 concurrency = 2;
431 concurrency_ = concurrency;
432 return *this;
433 }
434
435 /// \brief Get the number of threads that server is using
436 std::uint16_t concurrency() const
437 {
438 return concurrency_;
439 }
440
441 /// \brief Set the server's log level
442 ///
443 /// Possible values are:
444 /// - crow::LogLevel::Debug (0)
445 /// - crow::LogLevel::Info (1)
446 /// - crow::LogLevel::Warning (2)
447 /// - crow::LogLevel::Error (3)
448 /// - crow::LogLevel::Critical (4)
449 self_t& loglevel(LogLevel level)
450 {
451 crow::logger::setLogLevel(level);
452 return *this;
453 }
454
455 /// \brief Set the response body size (in bytes) beyond which Crow automatically streams responses (Default is 1MiB)
456 ///
457 /// Any streamed response is unaffected by Crow's timer, and therefore won't timeout before a response is fully sent.
458 self_t& stream_threshold(size_t threshold)
459 {
460 res_stream_threshold_ = threshold;
461 return *this;
462 }
463
464 /// \brief Get the response body size (in bytes) beyond which Crow automatically streams responses
466 {
467 return res_stream_threshold_;
468 }
469
470
471 self_t& register_blueprint(Blueprint& blueprint)
472 {
473 router_.register_blueprint(blueprint);
474 return *this;
475 }
476
477 /// \brief Set the function to call to handle uncaught exceptions generated in routes (Default generates error 500).
478 ///
479 /// The function must have the following signature: void(crow::response&).
480 /// It must set the response passed in argument to the function, which will be sent back to the client.
481 /// See Router::default_exception_handler() for the default implementation.
482 template<typename Func>
484 {
485 router_.exception_handler() = std::forward<Func>(f);
486 return *this;
487 }
488
489 std::function<void(crow::response&)>& exception_handler()
490 {
491 return router_.exception_handler();
492 }
493
494 /// \brief Set a custom duration and function to run on every tick
495 template<typename Duration, typename Func>
496 self_t& tick(Duration d, Func f)
497 {
498 tick_interval_ = std::chrono::duration_cast<std::chrono::milliseconds>(d);
499 tick_function_ = f;
500 return *this;
501 }
502
503#ifdef CROW_ENABLE_COMPRESSION
504
505 self_t& use_compression(compression::algorithm algorithm)
506 {
507 comp_algorithm_ = algorithm;
508 compression_used_ = true;
509 return *this;
510 }
511
512 compression::algorithm compression_algorithm()
513 {
514 return comp_algorithm_;
515 }
516
517 bool compression_used() const
518 {
519 return compression_used_;
520 }
521#endif
522
523 /// \brief Apply blueprints
525 {
526#if defined(__APPLE__) || defined(__MACH__)
527 if (router_.blueprints().empty()) return;
528#endif
529
530 for (Blueprint* bp : router_.blueprints())
531 {
532 if (bp->static_dir().empty()) {
533 CROW_LOG_ERROR << "Blueprint " << bp->prefix() << " and its sub-blueprints ignored due to empty static directory.";
534 continue;
535 }
536 auto static_dir_ = crow::utility::normalize_path(bp->static_dir());
537
538 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) {
539 utility::sanitize_filename(file_path_partial);
540 res.set_static_file_info_unsafe(static_dir_ + file_path_partial);
541 res.end();
542 });
543 }
544
545 router_.validate_bp();
546 }
547
548 /// \brief Go through the rules, upgrade them if possible, and add them to the list of rules
550 {
551 if (are_static_routes_added()) return;
552 auto static_dir_ = crow::utility::normalize_path(CROW_STATIC_DIRECTORY);
553
554 route<crow::black_magic::get_parameter_tag(CROW_STATIC_ENDPOINT)>(CROW_STATIC_ENDPOINT)([static_dir_](crow::response& res, std::string file_path_partial) {
555 utility::sanitize_filename(file_path_partial);
556 res.set_static_file_info_unsafe(static_dir_ + file_path_partial);
557 res.end();
558 });
559 set_static_routes_added();
560 }
561
562 /// \brief A wrapper for `validate()` in the router
563 void validate()
564 {
565 router_.validate();
566 }
567
568 /// \brief Run the server
569 void run()
570 {
571#ifndef CROW_DISABLE_STATIC_DIR
574#endif
575 validate();
576
577#ifdef CROW_ENABLE_SSL
578 if (ssl_used_)
579 {
580
581 error_code ec;
582 asio::ip::address addr = asio::ip::make_address(bindaddr_,ec);
583 if (ec){
584 CROW_LOG_ERROR << ec.message() << " - Can not create valid ip address from string: \"" << bindaddr_ << "\"";
585 return;
586 }
587 tcp::endpoint endpoint(addr, port_);
588 router_.using_ssl = true;
589 ssl_server_ = std::move(std::unique_ptr<ssl_server_t>(new ssl_server_t(this, endpoint, server_name_, &middlewares_, concurrency_, timeout_, &ssl_context_)));
590 ssl_server_->set_tick_function(tick_interval_, tick_function_);
591 ssl_server_->signal_clear();
592 for (auto snum : signals_)
593 {
594 ssl_server_->signal_add(snum);
595 }
596 notify_server_start();
597 ssl_server_->run();
598 }
599 else
600#endif
601 {
602 if (use_unix_)
603 {
604 UnixSocketAcceptor::endpoint endpoint(bindaddr_);
605 unix_server_ = std::move(std::unique_ptr<unix_server_t>(new unix_server_t(this, endpoint, server_name_, &middlewares_, concurrency_, timeout_, nullptr)));
606 unix_server_->set_tick_function(tick_interval_, tick_function_);
607 for (auto snum : signals_)
608 {
609 unix_server_->signal_add(snum);
610 }
611 notify_server_start();
612 unix_server_->run();
613 }
614 else
615 {
616 error_code ec;
617 asio::ip::address addr = asio::ip::make_address(bindaddr_,ec);
618 if (ec){
619 CROW_LOG_ERROR << ec.message() << " - Can not create valid ip address from string: \"" << bindaddr_ << "\"";
620 return;
621 }
622 TCPAcceptor::endpoint endpoint(addr, port_);
623 server_ = std::move(std::unique_ptr<server_t>(new server_t(this, endpoint, server_name_, &middlewares_, concurrency_, timeout_, nullptr)));
624 server_->set_tick_function(tick_interval_, tick_function_);
625 for (auto snum : signals_)
626 {
627 server_->signal_add(snum);
628 }
629 notify_server_start();
630 server_->run();
631 }
632 }
633 }
634
635 /// \brief Non-blocking version of \ref run()
636 ///
637 /// The output from this method needs to be saved into a variable!
638 /// Otherwise the call will be made on the same thread.
639 std::future<void> run_async()
640 {
641 return std::async(std::launch::async, [&] {
642 this->run();
643 });
644 }
645
646 /// \brief Stop the server
647 void stop()
648 {
649#ifdef CROW_ENABLE_SSL
650 if (ssl_used_)
651 {
652 if (ssl_server_) { ssl_server_->stop(); }
653 }
654 else
655#endif
656 {
657 close_websockets();
658 if (server_) { server_->stop(); }
659 if (unix_server_) { unix_server_->stop(); }
660 }
661 }
662
663 void close_websockets()
664 {
665 std::lock_guard<std::mutex> lock{websockets_mutex_};
666 for (auto websocket : websockets_)
667 {
668 CROW_LOG_INFO << "Quitting Websocket: " << websocket;
669 websocket->close("Websocket Closed");
670 }
671 }
672
673
674 void add_websocket(std::shared_ptr<websocket::connection> conn)
675 {
676 std::lock_guard<std::mutex> lock{websockets_mutex_};
677 websockets_.push_back(conn);
678 }
679
680 void remove_websocket(std::shared_ptr<websocket::connection> conn)
681 {
682 std::lock_guard<std::mutex> lock{websockets_mutex_};
683 websockets_.erase(std::remove(websockets_.begin(), websockets_.end(), conn), websockets_.end());
684 }
685
686 /// \brief Print the routing paths defined for each HTTP method
688 {
689 CROW_LOG_DEBUG << "Routing:";
690 router_.debug_print();
691 }
692
693
694#ifdef CROW_ENABLE_SSL
695
696 /// \brief Use certificate and key files for SSL
697 self_t& ssl_file(const std::string& crt_filename, const std::string& key_filename)
698 {
699 ssl_used_ = true;
700 ssl_context_.set_verify_mode(asio::ssl::verify_peer);
701 ssl_context_.set_verify_mode(asio::ssl::verify_client_once);
702 ssl_context_.use_certificate_file(crt_filename, ssl_context_t::pem);
703 ssl_context_.use_private_key_file(key_filename, ssl_context_t::pem);
704 ssl_context_.set_options(
705 asio::ssl::context::default_workarounds | asio::ssl::context::no_sslv2 | asio::ssl::context::no_sslv3);
706 return *this;
707 }
708
709 /// \brief Use `.pem` file for SSL
710 self_t& ssl_file(const std::string& pem_filename)
711 {
712 ssl_used_ = true;
713 ssl_context_.set_verify_mode(asio::ssl::verify_peer);
714 ssl_context_.set_verify_mode(asio::ssl::verify_client_once);
715 ssl_context_.load_verify_file(pem_filename);
716 ssl_context_.set_options(
717 asio::ssl::context::default_workarounds | asio::ssl::context::no_sslv2 | asio::ssl::context::no_sslv3);
718 return *this;
719 }
720
721 /// \brief Use certificate chain and key files for SSL
722 self_t& ssl_chainfile(const std::string& crt_filename, const std::string& key_filename)
723 {
724 ssl_used_ = true;
725 ssl_context_.set_verify_mode(asio::ssl::verify_peer);
726 ssl_context_.set_verify_mode(asio::ssl::verify_client_once);
727 ssl_context_.use_certificate_chain_file(crt_filename);
728 ssl_context_.use_private_key_file(key_filename, ssl_context_t::pem);
729 ssl_context_.set_options(
730 asio::ssl::context::default_workarounds | asio::ssl::context::no_sslv2 | asio::ssl::context::no_sslv3);
731 return *this;
732 }
733
734 self_t& ssl(asio::ssl::context&& ctx)
735 {
736 ssl_used_ = true;
737 ssl_context_ = std::move(ctx);
738 return *this;
739 }
740
741 bool ssl_used() const
742 {
743 return ssl_used_;
744 }
745#else
746
747 template<typename T, typename... Remain>
748 self_t& ssl_file(T&&, Remain&&...)
749 {
750 // We can't call .ssl() member function unless CROW_ENABLE_SSL is defined.
751 static_assert(
752 // make static_assert dependent to T; always false
753 std::is_base_of<T, void>::value,
754 "Define CROW_ENABLE_SSL to enable ssl support.");
755 return *this;
756 }
757
758 template<typename T, typename... Remain>
759 self_t& ssl_chainfile(T&&, Remain&&...)
760 {
761 // We can't call .ssl() member function unless CROW_ENABLE_SSL is defined.
762 static_assert(
763 // make static_assert dependent to T; always false
764 std::is_base_of<T, void>::value,
765 "Define CROW_ENABLE_SSL to enable ssl support.");
766 return *this;
767 }
768
769 template<typename T>
770 self_t& ssl(T&&)
771 {
772 // We can't call .ssl() member function unless CROW_ENABLE_SSL is defined.
773 static_assert(
774 // make static_assert dependent to T; always false
775 std::is_base_of<T, void>::value,
776 "Define CROW_ENABLE_SSL to enable ssl support.");
777 return *this;
778 }
779
780 bool ssl_used() const
781 {
782 return false;
783 }
784#endif
785
786 // middleware
787 using context_t = detail::context<Middlewares...>;
788 using mw_container_t = std::tuple<Middlewares...>;
789 template<typename T>
790 typename T::context& get_context(const request& req)
791 {
792 static_assert(black_magic::contains<T, Middlewares...>::value, "App doesn't have the specified middleware type.");
793 auto& ctx = *reinterpret_cast<context_t*>(req.middleware_context);
794 return ctx.template get<T>();
795 }
796
797 template<typename T>
798 T& get_middleware()
799 {
800 return utility::get_element_by_type<T, Middlewares...>(middlewares_);
801 }
802
803 /// \brief Wait until the server has properly started
804 std::cv_status wait_for_server_start(std::chrono::milliseconds wait_timeout = std::chrono::milliseconds(3000))
805 {
806 std::cv_status status = std::cv_status::no_timeout;
807 auto wait_until = std::chrono::steady_clock::now() + wait_timeout;
808 {
809 std::unique_lock<std::mutex> lock(start_mutex_);
810 while (!server_started_ && (status == std::cv_status::no_timeout))
811 {
812 status = cv_started_.wait_until(lock, wait_until);
813 }
814 }
815 if (status == std::cv_status::no_timeout)
816 {
817 if (server_) {
818 status = server_->wait_for_start(wait_until);
819 } else if (unix_server_) {
820 status = unix_server_->wait_for_start(wait_until);
821 }
822#ifdef CROW_ENABLE_SSL
823 else if (ssl_server_)
824 {
825 status = ssl_server_->wait_for_start(wait_until);
826 }
827#endif
828 }
829 return status;
830 }
831
832 private:
833 template<typename... Ts>
834 std::tuple<Middlewares...> make_middleware_tuple(Ts&&... ts)
835 {
836 auto fwd = std::forward_as_tuple((ts)...);
837 return std::make_tuple(
838 std::forward<Middlewares>(
839 black_magic::tuple_extract<Middlewares, decltype(fwd)>(fwd))...);
840 }
841
842 /// \brief Notify anything using \ref wait_for_server_start() to proceed
843 void notify_server_start()
844 {
845 std::unique_lock<std::mutex> lock(start_mutex_);
846 server_started_ = true;
847 cv_started_.notify_all();
848 }
849
850 void set_static_routes_added() {
851 static_routes_added_ = true;
852 }
853
854 bool are_static_routes_added() {
855 return static_routes_added_;
856 }
857
858 private:
859 std::uint8_t timeout_{5};
860 uint16_t port_ = 80;
861 unsigned int concurrency_ = 2;
862 std::atomic_bool is_bound_ = false;
863 uint64_t max_payload_{UINT64_MAX};
864 std::string server_name_ = std::string("Crow/") + VERSION;
865 std::string bindaddr_ = "0.0.0.0";
866 bool use_unix_ = false;
867 size_t res_stream_threshold_ = 1048576;
868 Router router_;
869 bool static_routes_added_{false};
870
871#ifdef CROW_ENABLE_COMPRESSION
872 compression::algorithm comp_algorithm_;
873 bool compression_used_{false};
874#endif
875
876 std::chrono::milliseconds tick_interval_;
877 std::function<void()> tick_function_;
878
879 std::tuple<Middlewares...> middlewares_;
880
881#ifdef CROW_ENABLE_SSL
882 std::unique_ptr<ssl_server_t> ssl_server_;
883 bool ssl_used_{false};
884 ssl_context_t ssl_context_{asio::ssl::context::sslv23};
885#endif
886
887 std::unique_ptr<server_t> server_;
888 std::unique_ptr<unix_server_t> unix_server_;
889
890 std::vector<int> signals_{SIGINT, SIGTERM};
891
892 bool server_started_{false};
893 std::condition_variable cv_started_;
894 std::mutex start_mutex_;
895 std::mutex websockets_mutex_; ///< \brief mutex to protect websockets_
896 std::vector<std::shared_ptr<websocket::connection>> websockets_;
897 };
898
899 /// \brief Alias of Crow<Middlewares...>. Useful if you want
900 /// a instance of an Crow application that require Middlewares
901 template<typename... Middlewares>
902 using App = Crow<Middlewares...>;
903
904 /// \brief Alias of Crow<>. Useful if you want a instance of
905 /// an Crow application that doesn't require of Middlewares
907} // namespace crow
A blueprint can be considered a smaller section of a Crow app, specifically where the router is conce...
Definition routing.h:1116
Definition routing.h:345
The main server application class.
Definition app.h:214
void stop()
Stop the server.
Definition app.h:647
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:458
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:804
void run()
Run the server.
Definition app.h:569
self_t & timeout(std::uint8_t timeout)
Set the connection timeout in seconds (default is 5)
Definition app.h:380
uint64_t websocket_max_payload()
Get the default max payload size for websockets.
Definition app.h:321
void add_static_dir()
Go through the rules, upgrade them if possible, and add them to the list of rules.
Definition app.h:549
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:284
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:722
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:387
self_t & ssl_file(const std::string &crt_filename, const std::string &key_filename)
Use certificate and key files for SSL.
Definition app.h:697
void handle_upgrade(const request &req, response &res, Adaptor &&adaptor)
Process an Upgrade request.
Definition app.h:240
self_t & multithreaded()
Run the server on multiple threads using all available threads.
Definition app.h:421
self_t & tick(Duration d, Func f)
Set a custom duration and function to run on every tick.
Definition app.h:496
self_t & local_socket_path(std::string path)
Disable tcp/ip and use unix domain socket instead.
Definition app.h:407
void debug_print()
Print the routing paths defined for each HTTP method.
Definition app.h:687
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:252
std::string bindaddr()
Get the address that Crow will handle requests on.
Definition app.h:401
self_t & port(std::uint16_t port)
Set the port that Crow will handle requests on.
Definition app.h:344
bool is_bound() const
Get whether address that Crow will handle requests on is bound.
Definition app.h:375
std::uint16_t port() const
Get the port that Crow will handle requests on.
Definition app.h:351
self_t & concurrency(unsigned int concurrency)
Run the server on multiple threads using a specific number.
Definition app.h:427
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:483
self_t & bindaddr(std::string bindaddr)
The IP address that Crow will handle requests on (default is 0.0.0.0)
Definition app.h:394
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:563
Crow(Ts &&... ts)
Construct Crow with a subset of middleware.
Definition app.h:232
CatchallRule & catchall_route()
Create a route for any requests without a proper route (Use CROW_CATCHALL_ROUTE instead)
Definition app.h:308
self_t & websocket_max_payload(uint64_t max_payload)
Set the default max payload size for websockets.
Definition app.h:314
void handle_full(request &req, response &res)
Process a fully parsed request from start to finish (primarily used for debugging)
Definition app.h:258
StaticRule & static_file(std::string_view url, std::string_view internalPath)
Creates a static route for given url to internalPath.
Definition app.h:295
self_t & ssl_file(const std::string &pem_filename)
Use .pem file for SSL.
Definition app.h:710
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:246
std::string local_socket_path()
Get the unix domain socket path.
Definition app.h:415
DynamicRule & route_dynamic(const std::string &rule)
Create a dynamic route using a rule (Use CROW_ROUTE instead)
Definition app.h:266
self_t & loglevel(LogLevel level)
Set the server's log level.
Definition app.h:449
void add_blueprint()
Apply blueprints.
Definition app.h:524
void address_is_bound()
Set status variable to note that the address that Crow will handle requests on is bound.
Definition app.h:370
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:273
size_t & stream_threshold()
Get the response body size (in bytes) beyond which Crow automatically streams responses.
Definition app.h:465
std::uint16_t concurrency() const
Get the number of threads that server is using.
Definition app.h:436
std::future< void > run_async()
Non-blocking version of run()
Definition app.h:639
A rule that can change its parameters during runtime.
Definition routing.h:592
Handles matching requests to existing rules and upgrade requests.
Definition routing.h:1270
Definition http_server.h:46
Default rule created when CROW_ROUTE is called.
Definition routing.h:669
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