| 
									
										
										
										
											2017-08-04 19:55:28 -07:00
										 |  |  | //
 | 
					
						
							| 
									
										
										
										
											2019-02-21 07:00:31 -08:00
										 |  |  | // Copyright (c) 2016-2019 Vinnie Falco (vinnie dot falco at gmail dot com)
 | 
					
						
							| 
									
										
										
										
											2017-08-04 19:55:28 -07:00
										 |  |  | //
 | 
					
						
							|  |  |  | // Distributed under the Boost Software License, Version 1.0. (See accompanying
 | 
					
						
							|  |  |  | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // Official repository: https://github.com/boostorg/beast
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | //------------------------------------------------------------------------------
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // Example: Advanced server, flex (plain + SSL)
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | //------------------------------------------------------------------------------
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "example/common/server_certificate.hpp"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include <boost/beast/core.hpp>
 | 
					
						
							|  |  |  | #include <boost/beast/http.hpp>
 | 
					
						
							| 
									
										
										
										
											2019-02-23 10:46:43 -08:00
										 |  |  | #include <boost/beast/ssl.hpp>
 | 
					
						
							| 
									
										
										
										
											2017-08-04 19:55:28 -07:00
										 |  |  | #include <boost/beast/websocket.hpp>
 | 
					
						
							|  |  |  | #include <boost/beast/version.hpp>
 | 
					
						
							| 
									
										
										
										
											2017-09-07 07:39:52 -07:00
										 |  |  | #include <boost/asio/bind_executor.hpp>
 | 
					
						
							| 
									
										
										
										
											2018-02-21 12:41:54 -08:00
										 |  |  | #include <boost/asio/signal_set.hpp>
 | 
					
						
							| 
									
										
										
										
											2017-08-04 19:55:28 -07:00
										 |  |  | #include <boost/asio/steady_timer.hpp>
 | 
					
						
							| 
									
										
										
										
											2019-02-10 05:48:29 -08:00
										 |  |  | #include <boost/asio/strand.hpp>
 | 
					
						
							| 
									
										
										
										
											2018-01-31 12:19:30 +01:00
										 |  |  | #include <boost/make_unique.hpp>
 | 
					
						
							| 
									
										
										
										
											2019-02-28 10:01:54 -08:00
										 |  |  | #include <boost/optional.hpp>
 | 
					
						
							| 
									
										
										
										
											2017-08-04 19:55:28 -07:00
										 |  |  | #include <algorithm>
 | 
					
						
							|  |  |  | #include <cstdlib>
 | 
					
						
							|  |  |  | #include <functional>
 | 
					
						
							|  |  |  | #include <iostream>
 | 
					
						
							|  |  |  | #include <memory>
 | 
					
						
							|  |  |  | #include <string>
 | 
					
						
							|  |  |  | #include <thread>
 | 
					
						
							|  |  |  | #include <vector>
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-11-30 14:58:38 -08:00
										 |  |  | namespace beast = boost::beast;                 // from <boost/beast.hpp>
 | 
					
						
							|  |  |  | namespace http = beast::http;                   // from <boost/beast/http.hpp>
 | 
					
						
							|  |  |  | namespace websocket = beast::websocket;         // from <boost/beast/websocket.hpp>
 | 
					
						
							|  |  |  | namespace net = boost::asio;                    // from <boost/asio.hpp>
 | 
					
						
							| 
									
										
										
										
											2017-08-04 19:55:28 -07:00
										 |  |  | namespace ssl = boost::asio::ssl;               // from <boost/asio/ssl.hpp>
 | 
					
						
							| 
									
										
										
										
											2018-11-30 14:58:38 -08:00
										 |  |  | using tcp = boost::asio::ip::tcp;               // from <boost/asio/ip/tcp.hpp>
 | 
					
						
							| 
									
										
										
										
											2017-08-04 19:55:28 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | // Return a reasonable mime type based on the extension of a file.
 | 
					
						
							| 
									
										
										
										
											2018-11-30 14:58:38 -08:00
										 |  |  | beast::string_view | 
					
						
							|  |  |  | mime_type(beast::string_view path) | 
					
						
							| 
									
										
										
										
											2017-08-04 19:55:28 -07:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2018-11-30 14:58:38 -08:00
										 |  |  |     using beast::iequals; | 
					
						
							| 
									
										
										
										
											2017-08-04 19:55:28 -07:00
										 |  |  |     auto const ext = [&path] | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         auto const pos = path.rfind("."); | 
					
						
							| 
									
										
										
										
											2018-11-30 14:58:38 -08:00
										 |  |  |         if(pos == beast::string_view::npos) | 
					
						
							|  |  |  |             return beast::string_view{}; | 
					
						
							| 
									
										
										
										
											2017-08-04 19:55:28 -07:00
										 |  |  |         return path.substr(pos); | 
					
						
							|  |  |  |     }(); | 
					
						
							|  |  |  |     if(iequals(ext, ".htm"))  return "text/html"; | 
					
						
							|  |  |  |     if(iequals(ext, ".html")) return "text/html"; | 
					
						
							|  |  |  |     if(iequals(ext, ".php"))  return "text/html"; | 
					
						
							|  |  |  |     if(iequals(ext, ".css"))  return "text/css"; | 
					
						
							|  |  |  |     if(iequals(ext, ".txt"))  return "text/plain"; | 
					
						
							|  |  |  |     if(iequals(ext, ".js"))   return "application/javascript"; | 
					
						
							|  |  |  |     if(iequals(ext, ".json")) return "application/json"; | 
					
						
							|  |  |  |     if(iequals(ext, ".xml"))  return "application/xml"; | 
					
						
							|  |  |  |     if(iequals(ext, ".swf"))  return "application/x-shockwave-flash"; | 
					
						
							|  |  |  |     if(iequals(ext, ".flv"))  return "video/x-flv"; | 
					
						
							|  |  |  |     if(iequals(ext, ".png"))  return "image/png"; | 
					
						
							|  |  |  |     if(iequals(ext, ".jpe"))  return "image/jpeg"; | 
					
						
							|  |  |  |     if(iequals(ext, ".jpeg")) return "image/jpeg"; | 
					
						
							|  |  |  |     if(iequals(ext, ".jpg"))  return "image/jpeg"; | 
					
						
							|  |  |  |     if(iequals(ext, ".gif"))  return "image/gif"; | 
					
						
							|  |  |  |     if(iequals(ext, ".bmp"))  return "image/bmp"; | 
					
						
							|  |  |  |     if(iequals(ext, ".ico"))  return "image/vnd.microsoft.icon"; | 
					
						
							|  |  |  |     if(iequals(ext, ".tiff")) return "image/tiff"; | 
					
						
							|  |  |  |     if(iequals(ext, ".tif"))  return "image/tiff"; | 
					
						
							|  |  |  |     if(iequals(ext, ".svg"))  return "image/svg+xml"; | 
					
						
							|  |  |  |     if(iequals(ext, ".svgz")) return "image/svg+xml"; | 
					
						
							|  |  |  |     return "application/text"; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Append an HTTP rel-path to a local filesystem path.
 | 
					
						
							|  |  |  | // The returned path is normalized for the platform.
 | 
					
						
							|  |  |  | std::string | 
					
						
							|  |  |  | path_cat( | 
					
						
							| 
									
										
										
										
											2018-11-30 14:58:38 -08:00
										 |  |  |     beast::string_view base, | 
					
						
							|  |  |  |     beast::string_view path) | 
					
						
							| 
									
										
										
										
											2017-08-04 19:55:28 -07:00
										 |  |  | { | 
					
						
							|  |  |  |     if(base.empty()) | 
					
						
							| 
									
										
										
										
											2019-02-07 23:47:05 +01:00
										 |  |  |         return std::string(path); | 
					
						
							|  |  |  |     std::string result(base); | 
					
						
							| 
									
										
										
										
											2017-08-04 19:55:28 -07:00
										 |  |  | #if BOOST_MSVC
 | 
					
						
							|  |  |  |     char constexpr path_separator = '\\'; | 
					
						
							|  |  |  |     if(result.back() == path_separator) | 
					
						
							|  |  |  |         result.resize(result.size() - 1); | 
					
						
							|  |  |  |     result.append(path.data(), path.size()); | 
					
						
							|  |  |  |     for(auto& c : result) | 
					
						
							|  |  |  |         if(c == '/') | 
					
						
							|  |  |  |             c = path_separator; | 
					
						
							|  |  |  | #else
 | 
					
						
							|  |  |  |     char constexpr path_separator = '/'; | 
					
						
							|  |  |  |     if(result.back() == path_separator) | 
					
						
							|  |  |  |         result.resize(result.size() - 1); | 
					
						
							|  |  |  |     result.append(path.data(), path.size()); | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  |     return result; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // This function produces an HTTP response for the given
 | 
					
						
							|  |  |  | // request. The type of the response object depends on the
 | 
					
						
							|  |  |  | // contents of the request, so the interface requires the
 | 
					
						
							|  |  |  | // caller to pass a generic lambda for receiving the response.
 | 
					
						
							|  |  |  | template< | 
					
						
							|  |  |  |     class Body, class Allocator, | 
					
						
							|  |  |  |     class Send> | 
					
						
							|  |  |  | void | 
					
						
							|  |  |  | handle_request( | 
					
						
							| 
									
										
										
										
											2018-11-30 14:58:38 -08:00
										 |  |  |     beast::string_view doc_root, | 
					
						
							| 
									
										
										
										
											2017-08-04 19:55:28 -07:00
										 |  |  |     http::request<Body, http::basic_fields<Allocator>>&& req, | 
					
						
							|  |  |  |     Send&& send) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     // Returns a bad request response
 | 
					
						
							|  |  |  |     auto const bad_request = | 
					
						
							| 
									
										
										
										
											2018-11-30 14:58:38 -08:00
										 |  |  |     [&req](beast::string_view why) | 
					
						
							| 
									
										
										
										
											2017-08-04 19:55:28 -07:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2017-09-12 13:49:45 -07:00
										 |  |  |         http::response<http::string_body> res{http::status::bad_request, req.version()}; | 
					
						
							| 
									
										
										
										
											2017-08-04 19:55:28 -07:00
										 |  |  |         res.set(http::field::server, BOOST_BEAST_VERSION_STRING); | 
					
						
							|  |  |  |         res.set(http::field::content_type, "text/html"); | 
					
						
							|  |  |  |         res.keep_alive(req.keep_alive()); | 
					
						
							| 
									
										
										
										
											2019-02-07 23:47:05 +01:00
										 |  |  |         res.body() = std::string(why); | 
					
						
							| 
									
										
										
										
											2017-08-04 19:55:28 -07:00
										 |  |  |         res.prepare_payload(); | 
					
						
							|  |  |  |         return res; | 
					
						
							|  |  |  |     }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // Returns a not found response
 | 
					
						
							|  |  |  |     auto const not_found = | 
					
						
							| 
									
										
										
										
											2018-11-30 14:58:38 -08:00
										 |  |  |     [&req](beast::string_view target) | 
					
						
							| 
									
										
										
										
											2017-08-04 19:55:28 -07:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2017-09-12 13:49:45 -07:00
										 |  |  |         http::response<http::string_body> res{http::status::not_found, req.version()}; | 
					
						
							| 
									
										
										
										
											2017-08-04 19:55:28 -07:00
										 |  |  |         res.set(http::field::server, BOOST_BEAST_VERSION_STRING); | 
					
						
							|  |  |  |         res.set(http::field::content_type, "text/html"); | 
					
						
							|  |  |  |         res.keep_alive(req.keep_alive()); | 
					
						
							| 
									
										
										
										
											2019-02-07 23:47:05 +01:00
										 |  |  |         res.body() = "The resource '" + std::string(target) + "' was not found."; | 
					
						
							| 
									
										
										
										
											2017-08-04 19:55:28 -07:00
										 |  |  |         res.prepare_payload(); | 
					
						
							|  |  |  |         return res; | 
					
						
							|  |  |  |     }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // Returns a server error response
 | 
					
						
							|  |  |  |     auto const server_error = | 
					
						
							| 
									
										
										
										
											2018-11-30 14:58:38 -08:00
										 |  |  |     [&req](beast::string_view what) | 
					
						
							| 
									
										
										
										
											2017-08-04 19:55:28 -07:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2017-09-12 13:49:45 -07:00
										 |  |  |         http::response<http::string_body> res{http::status::internal_server_error, req.version()}; | 
					
						
							| 
									
										
										
										
											2017-08-04 19:55:28 -07:00
										 |  |  |         res.set(http::field::server, BOOST_BEAST_VERSION_STRING); | 
					
						
							|  |  |  |         res.set(http::field::content_type, "text/html"); | 
					
						
							|  |  |  |         res.keep_alive(req.keep_alive()); | 
					
						
							| 
									
										
										
										
											2019-02-07 23:47:05 +01:00
										 |  |  |         res.body() = "An error occurred: '" + std::string(what) + "'"; | 
					
						
							| 
									
										
										
										
											2017-08-04 19:55:28 -07:00
										 |  |  |         res.prepare_payload(); | 
					
						
							|  |  |  |         return res; | 
					
						
							|  |  |  |     }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // Make sure we can handle the method
 | 
					
						
							|  |  |  |     if( req.method() != http::verb::get && | 
					
						
							|  |  |  |         req.method() != http::verb::head) | 
					
						
							|  |  |  |         return send(bad_request("Unknown HTTP-method")); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // Request path must be absolute and not contain "..".
 | 
					
						
							|  |  |  |     if( req.target().empty() || | 
					
						
							|  |  |  |         req.target()[0] != '/' || | 
					
						
							| 
									
										
										
										
											2018-11-30 14:58:38 -08:00
										 |  |  |         req.target().find("..") != beast::string_view::npos) | 
					
						
							| 
									
										
										
										
											2017-08-04 19:55:28 -07:00
										 |  |  |         return send(bad_request("Illegal request-target")); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // Build the path to the requested file
 | 
					
						
							|  |  |  |     std::string path = path_cat(doc_root, req.target()); | 
					
						
							|  |  |  |     if(req.target().back() == '/') | 
					
						
							|  |  |  |         path.append("index.html"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // Attempt to open the file
 | 
					
						
							| 
									
										
										
										
											2018-11-30 14:58:38 -08:00
										 |  |  |     beast::error_code ec; | 
					
						
							| 
									
										
										
										
											2017-08-04 19:55:28 -07:00
										 |  |  |     http::file_body::value_type body; | 
					
						
							| 
									
										
										
										
											2018-11-30 14:58:38 -08:00
										 |  |  |     body.open(path.c_str(), beast::file_mode::scan, ec); | 
					
						
							| 
									
										
										
										
											2017-08-04 19:55:28 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |     // Handle the case where the file doesn't exist
 | 
					
						
							| 
									
										
										
										
											2018-11-30 14:58:38 -08:00
										 |  |  |     if(ec == beast::errc::no_such_file_or_directory) | 
					
						
							| 
									
										
										
										
											2017-08-04 19:55:28 -07:00
										 |  |  |         return send(not_found(req.target())); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // Handle an unknown error
 | 
					
						
							|  |  |  |     if(ec) | 
					
						
							|  |  |  |         return send(server_error(ec.message())); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-01-22 11:57:00 -08:00
										 |  |  |     // Cache the size since we need it after the move
 | 
					
						
							|  |  |  |     auto const size = body.size(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-04 19:55:28 -07:00
										 |  |  |     // Respond to HEAD request
 | 
					
						
							|  |  |  |     if(req.method() == http::verb::head) | 
					
						
							|  |  |  |     { | 
					
						
							| 
									
										
										
										
											2017-09-12 13:49:45 -07:00
										 |  |  |         http::response<http::empty_body> res{http::status::ok, req.version()}; | 
					
						
							| 
									
										
										
										
											2017-08-04 19:55:28 -07:00
										 |  |  |         res.set(http::field::server, BOOST_BEAST_VERSION_STRING); | 
					
						
							|  |  |  |         res.set(http::field::content_type, mime_type(path)); | 
					
						
							| 
									
										
										
										
											2018-01-22 11:57:00 -08:00
										 |  |  |         res.content_length(size); | 
					
						
							| 
									
										
										
										
											2017-08-04 19:55:28 -07:00
										 |  |  |         res.keep_alive(req.keep_alive()); | 
					
						
							|  |  |  |         return send(std::move(res)); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-08 17:38:48 -07:00
										 |  |  |     // Respond to GET request
 | 
					
						
							| 
									
										
										
										
											2017-08-04 19:55:28 -07:00
										 |  |  |     http::response<http::file_body> res{ | 
					
						
							|  |  |  |         std::piecewise_construct, | 
					
						
							|  |  |  |         std::make_tuple(std::move(body)), | 
					
						
							| 
									
										
										
										
											2017-09-12 13:49:45 -07:00
										 |  |  |         std::make_tuple(http::status::ok, req.version())}; | 
					
						
							| 
									
										
										
										
											2017-08-04 19:55:28 -07:00
										 |  |  |     res.set(http::field::server, BOOST_BEAST_VERSION_STRING); | 
					
						
							|  |  |  |     res.set(http::field::content_type, mime_type(path)); | 
					
						
							| 
									
										
										
										
											2018-01-22 11:57:00 -08:00
										 |  |  |     res.content_length(size); | 
					
						
							| 
									
										
										
										
											2017-08-04 19:55:28 -07:00
										 |  |  |     res.keep_alive(req.keep_alive()); | 
					
						
							|  |  |  |     return send(std::move(res)); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | //------------------------------------------------------------------------------
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Report a failure
 | 
					
						
							|  |  |  | void | 
					
						
							| 
									
										
										
										
											2018-11-30 14:58:38 -08:00
										 |  |  | fail(beast::error_code ec, char const* what) | 
					
						
							| 
									
										
										
										
											2017-08-04 19:55:28 -07:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-02-23 06:34:52 -08:00
										 |  |  |     // ssl::error::stream_truncated, also known as an SSL "short read",
 | 
					
						
							|  |  |  |     // indicates the peer closed the connection without performing the
 | 
					
						
							|  |  |  |     // required closing handshake (for example, Google does this to
 | 
					
						
							|  |  |  |     // improve performance). Generally this can be a security issue,
 | 
					
						
							|  |  |  |     // but if your communication protocol is self-terminated (as
 | 
					
						
							|  |  |  |     // it is with both HTTP and WebSocket) then you may simply
 | 
					
						
							|  |  |  |     // ignore the lack of close_notify.
 | 
					
						
							|  |  |  |     //
 | 
					
						
							|  |  |  |     // https://github.com/boostorg/beast/issues/38
 | 
					
						
							|  |  |  |     //
 | 
					
						
							|  |  |  |     // https://security.stackexchange.com/questions/91435/how-to-handle-a-malicious-ssl-tls-shutdown
 | 
					
						
							|  |  |  |     //
 | 
					
						
							|  |  |  |     // When a short read would cut off the end of an HTTP message,
 | 
					
						
							|  |  |  |     // Beast returns the error beast::http::error::partial_message.
 | 
					
						
							|  |  |  |     // Therefore, if we see a short read here, it has occurred
 | 
					
						
							|  |  |  |     // after the message has been completed, so it is safe to ignore it.
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if(ec == net::ssl::error::stream_truncated) | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-04 19:55:28 -07:00
										 |  |  |     std::cerr << what << ": " << ec.message() << "\n"; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | //------------------------------------------------------------------------------
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Echoes back all received WebSocket messages.
 | 
					
						
							|  |  |  | // This uses the Curiously Recurring Template Pattern so that
 | 
					
						
							|  |  |  | // the same code works with both SSL streams and regular sockets.
 | 
					
						
							|  |  |  | template<class Derived> | 
					
						
							|  |  |  | class websocket_session | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     // Access the derived class, this is part of
 | 
					
						
							|  |  |  |     // the Curiously Recurring Template Pattern idiom.
 | 
					
						
							|  |  |  |     Derived& | 
					
						
							|  |  |  |     derived() | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         return static_cast<Derived&>(*this); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-12 17:44:29 -08:00
										 |  |  |     beast::flat_buffer buffer_; | 
					
						
							| 
									
										
										
										
											2017-08-04 19:55:28 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | public: | 
					
						
							|  |  |  |     // Start the asynchronous operation
 | 
					
						
							|  |  |  |     template<class Body, class Allocator> | 
					
						
							|  |  |  |     void | 
					
						
							|  |  |  |     do_accept(http::request<Body, http::basic_fields<Allocator>> req) | 
					
						
							|  |  |  |     { | 
					
						
							| 
									
										
										
										
											2019-02-16 14:01:37 -08:00
										 |  |  |         // Set suggested timeout settings for the websocket
 | 
					
						
							|  |  |  |         derived().ws().set_option( | 
					
						
							| 
									
										
										
										
											2019-02-26 09:42:07 -08:00
										 |  |  |             websocket::stream_base::timeout::suggested( | 
					
						
							| 
									
										
										
										
											2019-02-25 16:00:50 -08:00
										 |  |  |                 beast::role_type::server)); | 
					
						
							| 
									
										
										
										
											2017-08-04 19:55:28 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-17 16:03:09 -08:00
										 |  |  |         // Set a decorator to change the Server of the handshake
 | 
					
						
							|  |  |  |         derived().ws().set_option( | 
					
						
							|  |  |  |             websocket::stream_base::decorator( | 
					
						
							|  |  |  |             [](websocket::response_type& res) | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 res.set(http::field::server, | 
					
						
							|  |  |  |                     std::string(BOOST_BEAST_VERSION_STRING) + | 
					
						
							|  |  |  |                         " advanced-server-flex"); | 
					
						
							|  |  |  |             })); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-04 19:55:28 -07:00
										 |  |  |         // Accept the websocket handshake
 | 
					
						
							|  |  |  |         derived().ws().async_accept( | 
					
						
							|  |  |  |             req, | 
					
						
							| 
									
										
										
										
											2019-02-14 16:20:27 -08:00
										 |  |  |             beast::bind_front_handler( | 
					
						
							| 
									
										
										
										
											2019-02-10 05:48:29 -08:00
										 |  |  |                 &websocket_session::on_accept, | 
					
						
							| 
									
										
										
										
											2019-02-14 16:20:27 -08:00
										 |  |  |                 derived().shared_from_this())); | 
					
						
							| 
									
										
										
										
											2017-08-04 19:55:28 -07:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-11-27 16:44:59 -08:00
										 |  |  |     void | 
					
						
							| 
									
										
										
										
											2018-11-30 14:58:38 -08:00
										 |  |  |     on_accept(beast::error_code ec) | 
					
						
							| 
									
										
										
										
											2017-11-27 16:44:59 -08:00
										 |  |  |     { | 
					
						
							|  |  |  |         if(ec) | 
					
						
							|  |  |  |             return fail(ec, "accept"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // Read a message
 | 
					
						
							|  |  |  |         do_read(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-04 19:55:28 -07:00
										 |  |  |     void | 
					
						
							|  |  |  |     do_read() | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         // Read a message into our buffer
 | 
					
						
							|  |  |  |         derived().ws().async_read( | 
					
						
							|  |  |  |             buffer_, | 
					
						
							| 
									
										
										
										
											2019-02-14 16:20:27 -08:00
										 |  |  |             beast::bind_front_handler( | 
					
						
							| 
									
										
										
										
											2019-02-10 05:48:29 -08:00
										 |  |  |                 &websocket_session::on_read, | 
					
						
							| 
									
										
										
										
											2019-02-14 16:20:27 -08:00
										 |  |  |                 derived().shared_from_this())); | 
					
						
							| 
									
										
										
										
											2017-08-04 19:55:28 -07:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     void | 
					
						
							| 
									
										
										
										
											2017-09-03 06:18:07 -07:00
										 |  |  |     on_read( | 
					
						
							| 
									
										
										
										
											2018-11-30 14:58:38 -08:00
										 |  |  |         beast::error_code ec, | 
					
						
							| 
									
										
										
										
											2017-09-03 06:18:07 -07:00
										 |  |  |         std::size_t bytes_transferred) | 
					
						
							| 
									
										
										
										
											2017-08-04 19:55:28 -07:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2017-09-03 06:18:07 -07:00
										 |  |  |         boost::ignore_unused(bytes_transferred); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-04 19:55:28 -07:00
										 |  |  |         // This indicates that the websocket_session was closed
 | 
					
						
							|  |  |  |         if(ec == websocket::error::closed) | 
					
						
							|  |  |  |             return; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if(ec) | 
					
						
							|  |  |  |             fail(ec, "read"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // Echo the message
 | 
					
						
							|  |  |  |         derived().ws().text(derived().ws().got_text()); | 
					
						
							|  |  |  |         derived().ws().async_write( | 
					
						
							|  |  |  |             buffer_.data(), | 
					
						
							| 
									
										
										
										
											2019-02-14 16:20:27 -08:00
										 |  |  |             beast::bind_front_handler( | 
					
						
							| 
									
										
										
										
											2019-02-10 05:48:29 -08:00
										 |  |  |                 &websocket_session::on_write, | 
					
						
							| 
									
										
										
										
											2019-02-14 16:20:27 -08:00
										 |  |  |                 derived().shared_from_this())); | 
					
						
							| 
									
										
										
										
											2017-08-04 19:55:28 -07:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     void | 
					
						
							| 
									
										
										
										
											2017-09-03 06:18:07 -07:00
										 |  |  |     on_write( | 
					
						
							| 
									
										
										
										
											2018-11-30 14:58:38 -08:00
										 |  |  |         beast::error_code ec, | 
					
						
							| 
									
										
										
										
											2017-09-03 06:18:07 -07:00
										 |  |  |         std::size_t bytes_transferred) | 
					
						
							| 
									
										
										
										
											2017-08-04 19:55:28 -07:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2017-09-03 06:18:07 -07:00
										 |  |  |         boost::ignore_unused(bytes_transferred); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-04 19:55:28 -07:00
										 |  |  |         if(ec) | 
					
						
							|  |  |  |             return fail(ec, "write"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // Clear the buffer
 | 
					
						
							|  |  |  |         buffer_.consume(buffer_.size()); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // Do another read
 | 
					
						
							|  |  |  |         do_read(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-18 12:42:24 -08:00
										 |  |  | //------------------------------------------------------------------------------
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-04 19:55:28 -07:00
										 |  |  | // Handles a plain WebSocket connection
 | 
					
						
							|  |  |  | class plain_websocket_session | 
					
						
							|  |  |  |     : public websocket_session<plain_websocket_session> | 
					
						
							|  |  |  |     , public std::enable_shared_from_this<plain_websocket_session> | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2019-02-18 12:42:24 -08:00
										 |  |  |     websocket::stream<beast::tcp_stream> ws_; | 
					
						
							| 
									
										
										
										
											2017-08-04 19:55:28 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | public: | 
					
						
							|  |  |  |     // Create the session
 | 
					
						
							|  |  |  |     explicit | 
					
						
							| 
									
										
										
										
											2019-02-10 05:48:29 -08:00
										 |  |  |     plain_websocket_session( | 
					
						
							| 
									
										
										
										
											2019-02-18 12:42:24 -08:00
										 |  |  |         beast::tcp_stream&& stream) | 
					
						
							| 
									
										
										
										
											2019-02-16 14:01:37 -08:00
										 |  |  |         : ws_(std::move(stream)) | 
					
						
							| 
									
										
										
										
											2017-08-04 19:55:28 -07:00
										 |  |  |     { | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // Called by the base class
 | 
					
						
							| 
									
										
										
										
											2019-02-18 12:42:24 -08:00
										 |  |  |     websocket::stream<beast::tcp_stream>& | 
					
						
							| 
									
										
										
										
											2017-08-04 19:55:28 -07:00
										 |  |  |     ws() | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         return ws_; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // Start the asynchronous operation
 | 
					
						
							|  |  |  |     template<class Body, class Allocator> | 
					
						
							|  |  |  |     void | 
					
						
							|  |  |  |     run(http::request<Body, http::basic_fields<Allocator>> req) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         // Accept the WebSocket upgrade request
 | 
					
						
							|  |  |  |         do_accept(std::move(req)); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-18 12:42:24 -08:00
										 |  |  | //------------------------------------------------------------------------------
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-04 19:55:28 -07:00
										 |  |  | // Handles an SSL WebSocket connection
 | 
					
						
							|  |  |  | class ssl_websocket_session | 
					
						
							|  |  |  |     : public websocket_session<ssl_websocket_session> | 
					
						
							|  |  |  |     , public std::enable_shared_from_this<ssl_websocket_session> | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2019-02-18 12:42:24 -08:00
										 |  |  |     websocket::stream< | 
					
						
							|  |  |  |         beast::ssl_stream<beast::tcp_stream>> ws_; | 
					
						
							| 
									
										
										
										
											2017-08-04 19:55:28 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | public: | 
					
						
							| 
									
										
										
										
											2019-02-18 12:42:24 -08:00
										 |  |  |     // Create the ssl_websocket_session
 | 
					
						
							| 
									
										
										
										
											2017-08-04 19:55:28 -07:00
										 |  |  |     explicit | 
					
						
							| 
									
										
										
										
											2019-02-18 12:42:24 -08:00
										 |  |  |     ssl_websocket_session( | 
					
						
							|  |  |  |         beast::ssl_stream<beast::tcp_stream>&& stream) | 
					
						
							| 
									
										
										
										
											2019-02-16 14:01:37 -08:00
										 |  |  |         : ws_(std::move(stream)) | 
					
						
							| 
									
										
										
										
											2017-08-04 19:55:28 -07:00
										 |  |  |     { | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-18 12:42:24 -08:00
										 |  |  |     // Start the session
 | 
					
						
							| 
									
										
										
										
											2017-08-04 19:55:28 -07:00
										 |  |  |     template<class Body, class Allocator> | 
					
						
							|  |  |  |     void | 
					
						
							|  |  |  |     run(http::request<Body, http::basic_fields<Allocator>> req) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         // Accept the WebSocket upgrade request
 | 
					
						
							|  |  |  |         do_accept(std::move(req)); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-18 12:42:24 -08:00
										 |  |  |     // Called by the base class
 | 
					
						
							|  |  |  |     websocket::stream< | 
					
						
							|  |  |  |         beast::ssl_stream<beast::tcp_stream>>& | 
					
						
							|  |  |  |     ws() | 
					
						
							| 
									
										
										
										
											2017-08-04 19:55:28 -07:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2019-02-18 12:42:24 -08:00
										 |  |  |         return ws_; | 
					
						
							| 
									
										
										
										
											2017-08-04 19:55:28 -07:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-18 12:42:24 -08:00
										 |  |  | private: | 
					
						
							| 
									
										
										
										
											2017-08-04 19:55:28 -07:00
										 |  |  |     void | 
					
						
							| 
									
										
										
										
											2018-11-30 14:58:38 -08:00
										 |  |  |     on_shutdown(beast::error_code ec) | 
					
						
							| 
									
										
										
										
											2017-08-04 19:55:28 -07:00
										 |  |  |     { | 
					
						
							|  |  |  |         if(ec) | 
					
						
							|  |  |  |             return fail(ec, "shutdown"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // At this point the connection is closed gracefully
 | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-18 12:42:24 -08:00
										 |  |  | //------------------------------------------------------------------------------
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-04 19:55:28 -07:00
										 |  |  | template<class Body, class Allocator> | 
					
						
							|  |  |  | void | 
					
						
							|  |  |  | make_websocket_session( | 
					
						
							| 
									
										
										
										
											2019-02-18 12:42:24 -08:00
										 |  |  |     beast::tcp_stream stream, | 
					
						
							| 
									
										
										
										
											2017-08-04 19:55:28 -07:00
										 |  |  |     http::request<Body, http::basic_fields<Allocator>> req) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     std::make_shared<plain_websocket_session>( | 
					
						
							| 
									
										
										
										
											2019-02-10 05:48:29 -08:00
										 |  |  |         std::move(stream))->run(std::move(req)); | 
					
						
							| 
									
										
										
										
											2017-08-04 19:55:28 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | template<class Body, class Allocator> | 
					
						
							|  |  |  | void | 
					
						
							|  |  |  | make_websocket_session( | 
					
						
							| 
									
										
										
										
											2019-02-18 12:42:24 -08:00
										 |  |  |     beast::ssl_stream<beast::tcp_stream> stream, | 
					
						
							| 
									
										
										
										
											2017-08-04 19:55:28 -07:00
										 |  |  |     http::request<Body, http::basic_fields<Allocator>> req) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     std::make_shared<ssl_websocket_session>( | 
					
						
							|  |  |  |         std::move(stream))->run(std::move(req)); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | //------------------------------------------------------------------------------
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Handles an HTTP server connection.
 | 
					
						
							|  |  |  | // This uses the Curiously Recurring Template Pattern so that
 | 
					
						
							|  |  |  | // the same code works with both SSL streams and regular sockets.
 | 
					
						
							|  |  |  | template<class Derived> | 
					
						
							|  |  |  | class http_session | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     // Access the derived class, this is part of
 | 
					
						
							|  |  |  |     // the Curiously Recurring Template Pattern idiom.
 | 
					
						
							|  |  |  |     Derived& | 
					
						
							|  |  |  |     derived() | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         return static_cast<Derived&>(*this); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // This queue is used for HTTP pipelining.
 | 
					
						
							|  |  |  |     class queue | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         enum | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             // Maximum number of responses we will queue
 | 
					
						
							|  |  |  |             limit = 8 | 
					
						
							|  |  |  |         }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // The type-erased, saved work item
 | 
					
						
							|  |  |  |         struct work | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             virtual ~work() = default; | 
					
						
							|  |  |  |             virtual void operator()() = 0; | 
					
						
							|  |  |  |         }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         http_session& self_; | 
					
						
							|  |  |  |         std::vector<std::unique_ptr<work>> items_; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     public: | 
					
						
							|  |  |  |         explicit | 
					
						
							|  |  |  |         queue(http_session& self) | 
					
						
							|  |  |  |             : self_(self) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             static_assert(limit > 0, "queue limit must be positive"); | 
					
						
							|  |  |  |             items_.reserve(limit); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // Returns `true` if we have reached the queue limit
 | 
					
						
							|  |  |  |         bool | 
					
						
							|  |  |  |         is_full() const | 
					
						
							|  |  |  |         { | 
					
						
							| 
									
										
										
										
											2017-08-08 17:38:48 -07:00
										 |  |  |             return items_.size() >= limit; | 
					
						
							| 
									
										
										
										
											2017-08-04 19:55:28 -07:00
										 |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // Called when a message finishes sending
 | 
					
						
							|  |  |  |         // Returns `true` if the caller should initiate a read
 | 
					
						
							|  |  |  |         bool | 
					
						
							|  |  |  |         on_write() | 
					
						
							|  |  |  |         { | 
					
						
							| 
									
										
										
										
											2017-08-08 17:38:48 -07:00
										 |  |  |             BOOST_ASSERT(! items_.empty()); | 
					
						
							|  |  |  |             auto const was_full = is_full(); | 
					
						
							|  |  |  |             items_.erase(items_.begin()); | 
					
						
							| 
									
										
										
										
											2017-08-04 19:55:28 -07:00
										 |  |  |             if(! items_.empty()) | 
					
						
							| 
									
										
										
										
											2017-08-08 17:38:48 -07:00
										 |  |  |                 (*items_.front())(); | 
					
						
							|  |  |  |             return was_full; | 
					
						
							| 
									
										
										
										
											2017-08-04 19:55:28 -07:00
										 |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // Called by the HTTP handler to send a response.
 | 
					
						
							|  |  |  |         template<bool isRequest, class Body, class Fields> | 
					
						
							|  |  |  |         void | 
					
						
							|  |  |  |         operator()(http::message<isRequest, Body, Fields>&& msg) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             // This holds a work item
 | 
					
						
							|  |  |  |             struct work_impl : work | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 http_session& self_; | 
					
						
							|  |  |  |                 http::message<isRequest, Body, Fields> msg_; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 work_impl( | 
					
						
							|  |  |  |                     http_session& self, | 
					
						
							|  |  |  |                     http::message<isRequest, Body, Fields>&& msg) | 
					
						
							|  |  |  |                     : self_(self) | 
					
						
							|  |  |  |                     , msg_(std::move(msg)) | 
					
						
							|  |  |  |                 { | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 void | 
					
						
							|  |  |  |                 operator()() | 
					
						
							|  |  |  |                 { | 
					
						
							| 
									
										
										
										
											2017-08-08 17:38:48 -07:00
										 |  |  |                     http::async_write( | 
					
						
							| 
									
										
										
										
											2017-08-04 19:55:28 -07:00
										 |  |  |                         self_.derived().stream(), | 
					
						
							| 
									
										
										
										
											2017-08-08 17:38:48 -07:00
										 |  |  |                         msg_, | 
					
						
							| 
									
										
										
										
											2019-02-14 16:20:27 -08:00
										 |  |  |                         beast::bind_front_handler( | 
					
						
							| 
									
										
										
										
											2019-02-10 05:48:29 -08:00
										 |  |  |                             &http_session::on_write, | 
					
						
							|  |  |  |                             self_.derived().shared_from_this(), | 
					
						
							|  |  |  |                             msg_.need_eof())); | 
					
						
							| 
									
										
										
										
											2017-08-04 19:55:28 -07:00
										 |  |  |                 } | 
					
						
							|  |  |  |             }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-08 17:38:48 -07:00
										 |  |  |             // Allocate and store the work
 | 
					
						
							| 
									
										
										
										
											2018-01-31 12:19:30 +01:00
										 |  |  |             items_.push_back( | 
					
						
							|  |  |  |                 boost::make_unique<work_impl>(self_, std::move(msg))); | 
					
						
							| 
									
										
										
										
											2017-08-08 17:38:48 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |             // If there was no previous work, start this one
 | 
					
						
							|  |  |  |             if(items_.size() == 1) | 
					
						
							|  |  |  |                 (*items_.front())(); | 
					
						
							| 
									
										
										
										
											2017-08-04 19:55:28 -07:00
										 |  |  |         } | 
					
						
							|  |  |  |     }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-03 14:18:33 -07:00
										 |  |  |     std::shared_ptr<std::string const> doc_root_; | 
					
						
							| 
									
										
										
										
											2017-08-04 19:55:28 -07:00
										 |  |  |     queue queue_; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-28 10:01:54 -08:00
										 |  |  |     // The parser is stored in an optional container so we can
 | 
					
						
							|  |  |  |     // construct it from scratch it at the beginning of each new message.
 | 
					
						
							|  |  |  |     boost::optional<http::request_parser<http::string_body>> parser_; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-04 19:55:28 -07:00
										 |  |  | protected: | 
					
						
							| 
									
										
										
										
											2018-11-30 14:58:38 -08:00
										 |  |  |     beast::flat_buffer buffer_; | 
					
						
							| 
									
										
										
										
											2017-08-04 19:55:28 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | public: | 
					
						
							|  |  |  |     // Construct the session
 | 
					
						
							|  |  |  |     http_session( | 
					
						
							| 
									
										
										
										
											2018-11-30 14:58:38 -08:00
										 |  |  |         beast::flat_buffer buffer, | 
					
						
							| 
									
										
										
										
											2018-05-03 14:18:33 -07:00
										 |  |  |         std::shared_ptr<std::string const> const& doc_root) | 
					
						
							| 
									
										
										
										
											2017-08-04 19:55:28 -07:00
										 |  |  |         : doc_root_(doc_root) | 
					
						
							|  |  |  |         , queue_(*this) | 
					
						
							|  |  |  |         , buffer_(std::move(buffer)) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     void | 
					
						
							|  |  |  |     do_read() | 
					
						
							|  |  |  |     { | 
					
						
							| 
									
										
										
										
											2019-02-28 10:01:54 -08:00
										 |  |  |         // Construct a new parser for each message
 | 
					
						
							|  |  |  |         parser_.emplace(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // Apply a reasonable limit to the allowed size
 | 
					
						
							|  |  |  |         // of the body in bytes to prevent abuse.
 | 
					
						
							|  |  |  |         parser_->body_limit(10000); | 
					
						
							| 
									
										
										
										
											2018-02-26 20:25:27 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-10 05:48:29 -08:00
										 |  |  |         // Set the timeout.
 | 
					
						
							|  |  |  |         beast::get_lowest_layer( | 
					
						
							|  |  |  |             derived().stream()).expires_after(std::chrono::seconds(30)); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-28 10:01:54 -08:00
										 |  |  |         // Read a request using the parser-oriented interface
 | 
					
						
							| 
									
										
										
										
											2017-08-04 19:55:28 -07:00
										 |  |  |         http::async_read( | 
					
						
							|  |  |  |             derived().stream(), | 
					
						
							|  |  |  |             buffer_, | 
					
						
							| 
									
										
										
										
											2019-02-28 10:01:54 -08:00
										 |  |  |             *parser_, | 
					
						
							| 
									
										
										
										
											2019-02-14 16:20:27 -08:00
										 |  |  |             beast::bind_front_handler( | 
					
						
							| 
									
										
										
										
											2019-02-10 05:48:29 -08:00
										 |  |  |                 &http_session::on_read, | 
					
						
							| 
									
										
										
										
											2019-02-14 16:20:27 -08:00
										 |  |  |                 derived().shared_from_this())); | 
					
						
							| 
									
										
										
										
											2017-08-04 19:55:28 -07:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     void | 
					
						
							| 
									
										
										
										
											2019-02-14 16:20:27 -08:00
										 |  |  |     on_read(beast::error_code ec, std::size_t bytes_transferred) | 
					
						
							| 
									
										
										
										
											2017-08-04 19:55:28 -07:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2019-02-14 16:20:27 -08:00
										 |  |  |         boost::ignore_unused(bytes_transferred); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-04 19:55:28 -07:00
										 |  |  |         // This means they closed the connection
 | 
					
						
							|  |  |  |         if(ec == http::error::end_of_stream) | 
					
						
							|  |  |  |             return derived().do_eof(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if(ec) | 
					
						
							|  |  |  |             return fail(ec, "read"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // See if it is a WebSocket Upgrade
 | 
					
						
							| 
									
										
										
										
											2019-02-28 10:01:54 -08:00
										 |  |  |         if(websocket::is_upgrade(parser_->get())) | 
					
						
							| 
									
										
										
										
											2017-08-04 19:55:28 -07:00
										 |  |  |         { | 
					
						
							| 
									
										
										
										
											2019-02-18 12:42:24 -08:00
										 |  |  |             // Disable the timeout.
 | 
					
						
							|  |  |  |             // The websocket::stream uses its own timeout settings.
 | 
					
						
							|  |  |  |             beast::get_lowest_layer(derived().stream()).expires_never(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-28 10:01:54 -08:00
										 |  |  |             // Create a websocket session, transferring ownership
 | 
					
						
							|  |  |  |             // of both the socket and the HTTP request.
 | 
					
						
							| 
									
										
										
										
											2017-08-04 19:55:28 -07:00
										 |  |  |             return make_websocket_session( | 
					
						
							|  |  |  |                 derived().release_stream(), | 
					
						
							| 
									
										
										
										
											2019-02-28 10:01:54 -08:00
										 |  |  |                 parser_->release()); | 
					
						
							| 
									
										
										
										
											2017-08-04 19:55:28 -07:00
										 |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // Send the response
 | 
					
						
							| 
									
										
										
										
											2019-02-28 10:01:54 -08:00
										 |  |  |         handle_request(*doc_root_, parser_->release(), queue_); | 
					
						
							| 
									
										
										
										
											2017-08-04 19:55:28 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |         // If we aren't at the queue limit, try to pipeline another request
 | 
					
						
							|  |  |  |         if(! queue_.is_full()) | 
					
						
							|  |  |  |             do_read(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     void | 
					
						
							| 
									
										
										
										
											2019-02-14 16:20:27 -08:00
										 |  |  |     on_write(bool close, beast::error_code ec, std::size_t bytes_transferred) | 
					
						
							| 
									
										
										
										
											2017-08-04 19:55:28 -07:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2019-02-14 16:20:27 -08:00
										 |  |  |         boost::ignore_unused(bytes_transferred); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-10-25 18:48:19 -07:00
										 |  |  |         if(ec) | 
					
						
							|  |  |  |             return fail(ec, "write"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if(close) | 
					
						
							| 
									
										
										
										
											2017-08-04 19:55:28 -07:00
										 |  |  |         { | 
					
						
							|  |  |  |             // This means we should close the connection, usually because
 | 
					
						
							|  |  |  |             // the response indicated the "Connection: close" semantic.
 | 
					
						
							|  |  |  |             return derived().do_eof(); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // Inform the queue that a write completed
 | 
					
						
							|  |  |  |         if(queue_.on_write()) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             // Read another request
 | 
					
						
							|  |  |  |             do_read(); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-18 12:42:24 -08:00
										 |  |  | //------------------------------------------------------------------------------
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-04 19:55:28 -07:00
										 |  |  | // Handles a plain HTTP connection
 | 
					
						
							|  |  |  | class plain_http_session | 
					
						
							|  |  |  |     : public http_session<plain_http_session> | 
					
						
							|  |  |  |     , public std::enable_shared_from_this<plain_http_session> | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2019-02-18 12:42:24 -08:00
										 |  |  |     beast::tcp_stream stream_; | 
					
						
							| 
									
										
										
										
											2017-08-04 19:55:28 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | public: | 
					
						
							| 
									
										
										
										
											2019-02-18 12:42:24 -08:00
										 |  |  |     // Create the session
 | 
					
						
							| 
									
										
										
										
											2017-08-04 19:55:28 -07:00
										 |  |  |     plain_http_session( | 
					
						
							| 
									
										
										
										
											2019-02-18 12:42:24 -08:00
										 |  |  |         beast::tcp_stream&& stream, | 
					
						
							| 
									
										
										
										
											2019-02-10 05:48:29 -08:00
										 |  |  |         beast::flat_buffer&& buffer, | 
					
						
							| 
									
										
										
										
											2018-05-03 14:18:33 -07:00
										 |  |  |         std::shared_ptr<std::string const> const& doc_root) | 
					
						
							| 
									
										
										
										
											2017-08-04 19:55:28 -07:00
										 |  |  |         : http_session<plain_http_session>( | 
					
						
							|  |  |  |             std::move(buffer), | 
					
						
							|  |  |  |             doc_root) | 
					
						
							| 
									
										
										
										
											2019-02-10 05:48:29 -08:00
										 |  |  |         , stream_(std::move(stream)) | 
					
						
							| 
									
										
										
										
											2017-08-04 19:55:28 -07:00
										 |  |  |     { | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-18 12:42:24 -08:00
										 |  |  |     // Start the session
 | 
					
						
							|  |  |  |     void | 
					
						
							|  |  |  |     run() | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         this->do_read(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-04 19:55:28 -07:00
										 |  |  |     // Called by the base class
 | 
					
						
							| 
									
										
										
										
											2019-02-18 12:42:24 -08:00
										 |  |  |     beast::tcp_stream& | 
					
						
							| 
									
										
										
										
											2017-08-04 19:55:28 -07:00
										 |  |  |     stream() | 
					
						
							|  |  |  |     { | 
					
						
							| 
									
										
										
										
											2019-02-10 05:48:29 -08:00
										 |  |  |         return stream_; | 
					
						
							| 
									
										
										
										
											2017-08-04 19:55:28 -07:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // Called by the base class
 | 
					
						
							| 
									
										
										
										
											2019-02-18 12:42:24 -08:00
										 |  |  |     beast::tcp_stream | 
					
						
							| 
									
										
										
										
											2017-08-04 19:55:28 -07:00
										 |  |  |     release_stream() | 
					
						
							|  |  |  |     { | 
					
						
							| 
									
										
										
										
											2019-02-10 05:48:29 -08:00
										 |  |  |         return std::move(stream_); | 
					
						
							| 
									
										
										
										
											2017-08-04 19:55:28 -07:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-18 12:42:24 -08:00
										 |  |  |     // Called by the base class
 | 
					
						
							| 
									
										
										
										
											2017-08-04 19:55:28 -07:00
										 |  |  |     void | 
					
						
							|  |  |  |     do_eof() | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         // Send a TCP shutdown
 | 
					
						
							| 
									
										
										
										
											2018-11-30 14:58:38 -08:00
										 |  |  |         beast::error_code ec; | 
					
						
							| 
									
										
										
										
											2019-02-10 05:48:29 -08:00
										 |  |  |         stream_.socket().shutdown(tcp::socket::shutdown_send, ec); | 
					
						
							| 
									
										
										
										
											2017-08-04 19:55:28 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |         // At this point the connection is closed gracefully
 | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-18 12:42:24 -08:00
										 |  |  | //------------------------------------------------------------------------------
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-04 19:55:28 -07:00
										 |  |  | // Handles an SSL HTTP connection
 | 
					
						
							|  |  |  | class ssl_http_session | 
					
						
							|  |  |  |     : public http_session<ssl_http_session> | 
					
						
							|  |  |  |     , public std::enable_shared_from_this<ssl_http_session> | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2019-02-18 12:42:24 -08:00
										 |  |  |     beast::ssl_stream<beast::tcp_stream> stream_; | 
					
						
							| 
									
										
										
										
											2017-08-04 19:55:28 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | public: | 
					
						
							|  |  |  |     // Create the http_session
 | 
					
						
							|  |  |  |     ssl_http_session( | 
					
						
							| 
									
										
										
										
											2019-02-18 12:42:24 -08:00
										 |  |  |         beast::tcp_stream&& stream, | 
					
						
							| 
									
										
										
										
											2017-08-04 19:55:28 -07:00
										 |  |  |         ssl::context& ctx, | 
					
						
							| 
									
										
										
										
											2019-02-10 05:48:29 -08:00
										 |  |  |         beast::flat_buffer&& buffer, | 
					
						
							| 
									
										
										
										
											2018-05-03 14:18:33 -07:00
										 |  |  |         std::shared_ptr<std::string const> const& doc_root) | 
					
						
							| 
									
										
										
										
											2017-08-04 19:55:28 -07:00
										 |  |  |         : http_session<ssl_http_session>( | 
					
						
							|  |  |  |             std::move(buffer), | 
					
						
							|  |  |  |             doc_root) | 
					
						
							| 
									
										
										
										
											2019-02-10 05:48:29 -08:00
										 |  |  |         , stream_(std::move(stream), ctx) | 
					
						
							| 
									
										
										
										
											2017-08-04 19:55:28 -07:00
										 |  |  |     { | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-18 12:42:24 -08:00
										 |  |  |     // Start the session
 | 
					
						
							|  |  |  |     void | 
					
						
							|  |  |  |     run() | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         // Set the timeout.
 | 
					
						
							|  |  |  |         beast::get_lowest_layer(stream_).expires_after(std::chrono::seconds(30)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // Perform the SSL handshake
 | 
					
						
							|  |  |  |         // Note, this is the buffered version of the handshake.
 | 
					
						
							|  |  |  |         stream_.async_handshake( | 
					
						
							|  |  |  |             ssl::stream_base::server, | 
					
						
							|  |  |  |             buffer_.data(), | 
					
						
							|  |  |  |             beast::bind_front_handler( | 
					
						
							|  |  |  |                 &ssl_http_session::on_handshake, | 
					
						
							|  |  |  |                 shared_from_this())); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-04 19:55:28 -07:00
										 |  |  |     // Called by the base class
 | 
					
						
							| 
									
										
										
										
											2019-02-18 12:42:24 -08:00
										 |  |  |     beast::ssl_stream<beast::tcp_stream>& | 
					
						
							| 
									
										
										
										
											2017-08-04 19:55:28 -07:00
										 |  |  |     stream() | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         return stream_; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // Called by the base class
 | 
					
						
							| 
									
										
										
										
											2019-02-18 12:42:24 -08:00
										 |  |  |     beast::ssl_stream<beast::tcp_stream> | 
					
						
							| 
									
										
										
										
											2017-08-04 19:55:28 -07:00
										 |  |  |     release_stream() | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         return std::move(stream_); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-18 12:42:24 -08:00
										 |  |  |     // Called by the base class
 | 
					
						
							| 
									
										
										
										
											2017-08-04 19:55:28 -07:00
										 |  |  |     void | 
					
						
							| 
									
										
										
										
											2019-02-18 12:42:24 -08:00
										 |  |  |     do_eof() | 
					
						
							| 
									
										
										
										
											2017-08-04 19:55:28 -07:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2019-02-10 05:48:29 -08:00
										 |  |  |         // Set the timeout.
 | 
					
						
							|  |  |  |         beast::get_lowest_layer(stream_).expires_after(std::chrono::seconds(30)); | 
					
						
							| 
									
										
										
										
											2017-08-04 19:55:28 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-18 12:42:24 -08:00
										 |  |  |         // Perform the SSL shutdown
 | 
					
						
							|  |  |  |         stream_.async_shutdown( | 
					
						
							| 
									
										
										
										
											2019-02-14 16:20:27 -08:00
										 |  |  |             beast::bind_front_handler( | 
					
						
							| 
									
										
										
										
											2019-02-18 12:42:24 -08:00
										 |  |  |                 &ssl_http_session::on_shutdown, | 
					
						
							| 
									
										
										
										
											2019-02-14 16:20:27 -08:00
										 |  |  |                 shared_from_this())); | 
					
						
							| 
									
										
										
										
											2017-08-04 19:55:28 -07:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2019-02-18 12:42:24 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  | private: | 
					
						
							| 
									
										
										
										
											2017-08-04 19:55:28 -07:00
										 |  |  |     void | 
					
						
							|  |  |  |     on_handshake( | 
					
						
							| 
									
										
										
										
											2018-11-30 14:58:38 -08:00
										 |  |  |         beast::error_code ec, | 
					
						
							| 
									
										
										
										
											2017-08-04 19:55:28 -07:00
										 |  |  |         std::size_t bytes_used) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         if(ec) | 
					
						
							|  |  |  |             return fail(ec, "handshake"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // Consume the portion of the buffer used by the handshake
 | 
					
						
							|  |  |  |         buffer_.consume(bytes_used); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         do_read(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     void | 
					
						
							| 
									
										
										
										
											2018-11-30 14:58:38 -08:00
										 |  |  |     on_shutdown(beast::error_code ec) | 
					
						
							| 
									
										
										
										
											2017-08-04 19:55:28 -07:00
										 |  |  |     { | 
					
						
							|  |  |  |         // Happens when the shutdown times out
 | 
					
						
							| 
									
										
										
										
											2018-11-30 14:58:38 -08:00
										 |  |  |         if(ec == net::error::operation_aborted) | 
					
						
							| 
									
										
										
										
											2017-08-04 19:55:28 -07:00
										 |  |  |             return; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if(ec) | 
					
						
							|  |  |  |             return fail(ec, "shutdown"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // At this point the connection is closed gracefully
 | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | //------------------------------------------------------------------------------
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Detects SSL handshakes
 | 
					
						
							|  |  |  | class detect_session : public std::enable_shared_from_this<detect_session> | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2019-02-18 12:42:24 -08:00
										 |  |  |     beast::tcp_stream stream_; | 
					
						
							| 
									
										
										
										
											2017-08-04 19:55:28 -07:00
										 |  |  |     ssl::context& ctx_; | 
					
						
							| 
									
										
										
										
											2018-05-03 14:18:33 -07:00
										 |  |  |     std::shared_ptr<std::string const> doc_root_; | 
					
						
							| 
									
										
										
										
											2018-11-30 14:58:38 -08:00
										 |  |  |     beast::flat_buffer buffer_; | 
					
						
							| 
									
										
										
										
											2017-08-04 19:55:28 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | public: | 
					
						
							|  |  |  |     explicit | 
					
						
							|  |  |  |     detect_session( | 
					
						
							| 
									
										
										
										
											2019-02-18 12:42:24 -08:00
										 |  |  |         tcp::socket&& socket, | 
					
						
							| 
									
										
										
										
											2017-08-04 19:55:28 -07:00
										 |  |  |         ssl::context& ctx, | 
					
						
							| 
									
										
										
										
											2018-05-03 14:18:33 -07:00
										 |  |  |         std::shared_ptr<std::string const> const& doc_root) | 
					
						
							| 
									
										
										
										
											2019-02-10 05:48:29 -08:00
										 |  |  |         : stream_(std::move(socket)) | 
					
						
							| 
									
										
										
										
											2017-08-04 19:55:28 -07:00
										 |  |  |         , ctx_(ctx) | 
					
						
							|  |  |  |         , doc_root_(doc_root) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // Launch the detector
 | 
					
						
							|  |  |  |     void | 
					
						
							|  |  |  |     run() | 
					
						
							|  |  |  |     { | 
					
						
							| 
									
										
										
										
											2019-02-10 05:48:29 -08:00
										 |  |  |         // Set the timeout.
 | 
					
						
							|  |  |  |         stream_.expires_after(std::chrono::seconds(30)); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-21 18:09:39 -08:00
										 |  |  |         beast::async_detect_ssl( | 
					
						
							| 
									
										
										
										
											2019-02-10 05:48:29 -08:00
										 |  |  |             stream_, | 
					
						
							| 
									
										
										
										
											2017-08-04 19:55:28 -07:00
										 |  |  |             buffer_, | 
					
						
							| 
									
										
										
										
											2019-02-14 16:20:27 -08:00
										 |  |  |             beast::bind_front_handler( | 
					
						
							| 
									
										
										
										
											2019-02-10 05:48:29 -08:00
										 |  |  |                 &detect_session::on_detect, | 
					
						
							| 
									
										
										
										
											2019-02-14 16:20:27 -08:00
										 |  |  |                 this->shared_from_this())); | 
					
						
							| 
									
										
										
										
											2017-08-04 19:55:28 -07:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     void | 
					
						
							| 
									
										
										
										
											2018-11-30 14:58:38 -08:00
										 |  |  |     on_detect(beast::error_code ec, boost::tribool result) | 
					
						
							| 
									
										
										
										
											2017-08-04 19:55:28 -07:00
										 |  |  |     { | 
					
						
							|  |  |  |         if(ec) | 
					
						
							|  |  |  |             return fail(ec, "detect"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if(result) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             // Launch SSL session
 | 
					
						
							|  |  |  |             std::make_shared<ssl_http_session>( | 
					
						
							| 
									
										
										
										
											2019-02-10 05:48:29 -08:00
										 |  |  |                 std::move(stream_), | 
					
						
							| 
									
										
										
										
											2017-08-04 19:55:28 -07:00
										 |  |  |                 ctx_, | 
					
						
							|  |  |  |                 std::move(buffer_), | 
					
						
							|  |  |  |                 doc_root_)->run(); | 
					
						
							|  |  |  |             return; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // Launch plain session
 | 
					
						
							|  |  |  |         std::make_shared<plain_http_session>( | 
					
						
							| 
									
										
										
										
											2019-02-10 05:48:29 -08:00
										 |  |  |             std::move(stream_), | 
					
						
							| 
									
										
										
										
											2017-08-04 19:55:28 -07:00
										 |  |  |             std::move(buffer_), | 
					
						
							|  |  |  |             doc_root_)->run(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Accepts incoming connections and launches the sessions
 | 
					
						
							|  |  |  | class listener : public std::enable_shared_from_this<listener> | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2019-02-18 12:42:24 -08:00
										 |  |  |     net::io_context& ioc_; | 
					
						
							| 
									
										
										
										
											2017-08-04 19:55:28 -07:00
										 |  |  |     ssl::context& ctx_; | 
					
						
							|  |  |  |     tcp::acceptor acceptor_; | 
					
						
							| 
									
										
										
										
											2018-05-03 14:18:33 -07:00
										 |  |  |     std::shared_ptr<std::string const> doc_root_; | 
					
						
							| 
									
										
										
										
											2017-08-04 19:55:28 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | public: | 
					
						
							|  |  |  |     listener( | 
					
						
							| 
									
										
										
										
											2018-11-30 14:58:38 -08:00
										 |  |  |         net::io_context& ioc, | 
					
						
							| 
									
										
										
										
											2017-08-04 19:55:28 -07:00
										 |  |  |         ssl::context& ctx, | 
					
						
							|  |  |  |         tcp::endpoint endpoint, | 
					
						
							| 
									
										
										
										
											2018-05-03 14:18:33 -07:00
										 |  |  |         std::shared_ptr<std::string const> const& doc_root) | 
					
						
							| 
									
										
										
										
											2019-02-18 12:42:24 -08:00
										 |  |  |         : ioc_(ioc) | 
					
						
							|  |  |  |         , ctx_(ctx) | 
					
						
							|  |  |  |         , acceptor_(beast::make_strand(ioc)) | 
					
						
							| 
									
										
										
										
											2017-08-04 19:55:28 -07:00
										 |  |  |         , doc_root_(doc_root) | 
					
						
							|  |  |  |     { | 
					
						
							| 
									
										
										
										
											2018-11-30 14:58:38 -08:00
										 |  |  |         beast::error_code ec; | 
					
						
							| 
									
										
										
										
											2017-08-04 19:55:28 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |         // Open the acceptor
 | 
					
						
							|  |  |  |         acceptor_.open(endpoint.protocol(), ec); | 
					
						
							|  |  |  |         if(ec) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             fail(ec, "open"); | 
					
						
							|  |  |  |             return; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-21 12:35:07 -08:00
										 |  |  |         // Allow address reuse
 | 
					
						
							| 
									
										
										
										
											2018-11-30 14:58:38 -08:00
										 |  |  |         acceptor_.set_option(net::socket_base::reuse_address(true), ec); | 
					
						
							| 
									
										
										
										
											2018-02-21 12:35:07 -08:00
										 |  |  |         if(ec) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             fail(ec, "set_option"); | 
					
						
							|  |  |  |             return; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-04 19:55:28 -07:00
										 |  |  |         // Bind to the server address
 | 
					
						
							|  |  |  |         acceptor_.bind(endpoint, ec); | 
					
						
							|  |  |  |         if(ec) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             fail(ec, "bind"); | 
					
						
							|  |  |  |             return; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // Start listening for connections
 | 
					
						
							|  |  |  |         acceptor_.listen( | 
					
						
							| 
									
										
										
										
											2018-11-30 14:58:38 -08:00
										 |  |  |             net::socket_base::max_listen_connections, ec); | 
					
						
							| 
									
										
										
										
											2017-08-04 19:55:28 -07:00
										 |  |  |         if(ec) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             fail(ec, "listen"); | 
					
						
							|  |  |  |             return; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // Start accepting incoming connections
 | 
					
						
							|  |  |  |     void | 
					
						
							|  |  |  |     run() | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         if(! acceptor_.is_open()) | 
					
						
							|  |  |  |             return; | 
					
						
							|  |  |  |         do_accept(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     void | 
					
						
							|  |  |  |     do_accept() | 
					
						
							|  |  |  |     { | 
					
						
							| 
									
										
										
										
											2019-02-20 07:07:01 -08:00
										 |  |  |         // The new connection gets its own strand
 | 
					
						
							| 
									
										
										
										
											2017-08-04 19:55:28 -07:00
										 |  |  |         acceptor_.async_accept( | 
					
						
							| 
									
										
										
										
											2019-02-20 07:07:01 -08:00
										 |  |  |             beast::make_strand(ioc_), | 
					
						
							| 
									
										
										
										
											2019-02-14 16:20:27 -08:00
										 |  |  |             beast::bind_front_handler( | 
					
						
							| 
									
										
										
										
											2017-08-04 19:55:28 -07:00
										 |  |  |                 &listener::on_accept, | 
					
						
							| 
									
										
										
										
											2019-02-14 16:20:27 -08:00
										 |  |  |                 shared_from_this())); | 
					
						
							| 
									
										
										
										
											2017-08-04 19:55:28 -07:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     void | 
					
						
							| 
									
										
										
										
											2019-02-20 07:07:01 -08:00
										 |  |  |     on_accept(beast::error_code ec, tcp::socket socket) | 
					
						
							| 
									
										
										
										
											2017-08-04 19:55:28 -07:00
										 |  |  |     { | 
					
						
							|  |  |  |         if(ec) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             fail(ec, "accept"); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         else | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             // Create the detector http_session and run it
 | 
					
						
							|  |  |  |             std::make_shared<detect_session>( | 
					
						
							| 
									
										
										
										
											2019-02-20 07:07:01 -08:00
										 |  |  |                 std::move(socket), | 
					
						
							| 
									
										
										
										
											2017-08-04 19:55:28 -07:00
										 |  |  |                 ctx_, | 
					
						
							|  |  |  |                 doc_root_)->run(); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // Accept another connection
 | 
					
						
							|  |  |  |         do_accept(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | //------------------------------------------------------------------------------
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int main(int argc, char* argv[]) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     // Check command line arguments.
 | 
					
						
							|  |  |  |     if (argc != 5) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         std::cerr << | 
					
						
							|  |  |  |             "Usage: advanced-server-flex <address> <port> <doc_root> <threads>\n" << | 
					
						
							|  |  |  |             "Example:\n" << | 
					
						
							|  |  |  |             "    advanced-server-flex 0.0.0.0 8080 . 1\n"; | 
					
						
							|  |  |  |         return EXIT_FAILURE; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2018-11-30 14:58:38 -08:00
										 |  |  |     auto const address = net::ip::make_address(argv[1]); | 
					
						
							| 
									
										
										
										
											2017-08-04 19:55:28 -07:00
										 |  |  |     auto const port = static_cast<unsigned short>(std::atoi(argv[2])); | 
					
						
							| 
									
										
										
										
											2018-05-03 14:18:33 -07:00
										 |  |  |     auto const doc_root = std::make_shared<std::string>(argv[3]); | 
					
						
							| 
									
										
										
										
											2017-09-07 07:39:52 -07:00
										 |  |  |     auto const threads = std::max<int>(1, std::atoi(argv[4])); | 
					
						
							| 
									
										
										
										
											2017-08-04 19:55:28 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-07 07:39:52 -07:00
										 |  |  |     // The io_context is required for all I/O
 | 
					
						
							| 
									
										
										
										
											2018-11-30 14:58:38 -08:00
										 |  |  |     net::io_context ioc{threads}; | 
					
						
							| 
									
										
										
										
											2017-08-04 19:55:28 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |     // The SSL context is required, and holds certificates
 | 
					
						
							|  |  |  |     ssl::context ctx{ssl::context::sslv23}; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // This holds the self-signed certificate used by the server
 | 
					
						
							|  |  |  |     load_server_certificate(ctx); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // Create and launch a listening port
 | 
					
						
							|  |  |  |     std::make_shared<listener>( | 
					
						
							| 
									
										
										
										
											2017-09-07 07:39:52 -07:00
										 |  |  |         ioc, | 
					
						
							| 
									
										
										
										
											2017-08-04 19:55:28 -07:00
										 |  |  |         ctx, | 
					
						
							|  |  |  |         tcp::endpoint{address, port}, | 
					
						
							|  |  |  |         doc_root)->run(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-21 12:41:54 -08:00
										 |  |  |     // Capture SIGINT and SIGTERM to perform a clean shutdown
 | 
					
						
							| 
									
										
										
										
											2018-11-30 14:58:38 -08:00
										 |  |  |     net::signal_set signals(ioc, SIGINT, SIGTERM); | 
					
						
							| 
									
										
										
										
											2018-02-21 12:41:54 -08:00
										 |  |  |     signals.async_wait( | 
					
						
							| 
									
										
										
										
											2018-11-30 14:58:38 -08:00
										 |  |  |         [&](beast::error_code const&, int) | 
					
						
							| 
									
										
										
										
											2018-02-21 12:41:54 -08:00
										 |  |  |         { | 
					
						
							|  |  |  |             // Stop the `io_context`. This will cause `run()`
 | 
					
						
							|  |  |  |             // to return immediately, eventually destroying the
 | 
					
						
							|  |  |  |             // `io_context` and all of the sockets in it.
 | 
					
						
							|  |  |  |             ioc.stop(); | 
					
						
							|  |  |  |         }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-04 19:55:28 -07:00
										 |  |  |     // Run the I/O service on the requested number of threads
 | 
					
						
							|  |  |  |     std::vector<std::thread> v; | 
					
						
							|  |  |  |     v.reserve(threads - 1); | 
					
						
							|  |  |  |     for(auto i = threads - 1; i > 0; --i) | 
					
						
							|  |  |  |         v.emplace_back( | 
					
						
							| 
									
										
										
										
											2017-09-07 07:39:52 -07:00
										 |  |  |         [&ioc] | 
					
						
							| 
									
										
										
										
											2017-08-04 19:55:28 -07:00
										 |  |  |         { | 
					
						
							| 
									
										
										
										
											2017-09-07 07:39:52 -07:00
										 |  |  |             ioc.run(); | 
					
						
							| 
									
										
										
										
											2017-08-04 19:55:28 -07:00
										 |  |  |         }); | 
					
						
							| 
									
										
										
										
											2017-09-07 07:39:52 -07:00
										 |  |  |     ioc.run(); | 
					
						
							| 
									
										
										
										
											2017-08-04 19:55:28 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-21 12:41:54 -08:00
										 |  |  |     // (If we get here, it means we got a SIGINT or SIGTERM)
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // Block until all the threads exit
 | 
					
						
							|  |  |  |     for(auto& t : v) | 
					
						
							|  |  |  |         t.join(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-04 19:55:28 -07:00
										 |  |  |     return EXIT_SUCCESS; | 
					
						
							|  |  |  | } |