### Main Server Setup and Execution Source: https://www.boost.org/doc/libs/latest/libs/beast/example/http/server/flex/http_server_flex.cpp The `main` function initializes the server, sets up the io_context and SSL context, loads the certificate, creates a listener, and starts the I/O service threads. ```cpp int main(int argc, char* argv[]) { // Check command line arguments. if (argc != 5) { std::cerr << "Usage: http-server-flex
\n" << "Example:\n" << " http-server-flex 0.0.0.0 8080 .\n"; return EXIT_FAILURE; } auto const address = net::ip::make_address(argv[1]); auto const port = static_cast(std::atoi(argv[2])); auto const doc_root = std::make_shared(argv[3]); auto const threads = std::max(1, std::atoi(argv[4])); // The io_context is required for all I/O net::io_context ioc{threads}; // The SSL context is required, and holds certificates ssl::context ctx{ssl::context::tlsv12}; // This holds the self-signed certificate used by the server load_server_certificate(ctx); // Create and launch a listening port std::make_shared( ioc, ctx, tcp::endpoint{address, port}, doc_root)->run(); // Run the I/O service on the requested number of threads std::vector v; v.reserve(threads - 1); for(auto i = threads - 1; i > 0; --i) v.emplace_back( [&ioc] { ioc.run(); }); ioc.run(); return EXIT_SUCCESS; } ``` -------------------------------- ### Main Function Setup Source: https://www.boost.org/doc/libs/latest/libs/beast/example/websocket/server/coro/websocket_server_coro.cpp Parses command-line arguments for address, port, and thread count. Initializes the io_context and spawns the listening coroutine to start the server. Ensures at least one thread is used. ```cpp int main(int argc, char* argv[]) { // Check command line arguments. if (argc != 4) { std::cerr << "Usage: websocket-server-coro
\n" << "Example:\n" << " websocket-server-coro 0.0.0.0 8080 1\n"; return EXIT_FAILURE; } auto const address = net::ip::make_address(argv[1]); auto const port = static_cast(std::atoi(argv[2])); auto const threads = std::max(1, std::atoi(argv[3])); // The io_context is required for all I/O net::io_context ioc(threads); // Spawn a listening port boost::asio::spawn(ioc, std::bind( &do_listen, std::ref(ioc), tcp::endpoint{address, port}, std::placeholders::_1), // on completion, spawn will call this function ``` -------------------------------- ### Main Server Setup and Execution Source: https://www.boost.org/doc/libs/latest/libs/beast/example/http/server/small/http_server_small.cpp Initializes the network context, acceptor, and socket, then starts the HTTP server's accept loop. Handles command-line arguments for address and port, and includes error handling. ```cpp int main(int argc, char* argv[]) { try { // Check command line arguments. if(argc != 3) { std::cerr << "Usage: " << argv[0] << "
\n"; std::cerr << " For IPv4, try:\n"; std::cerr << " receiver 0.0.0.0 80\n"; std::cerr << " For IPv6, try:\n"; std::cerr << " receiver 0::0 80\n"; return EXIT_FAILURE; } auto const address = net::ip::make_address(argv[1]); unsigned short port = static_cast(std::atoi(argv[2])); net::io_context ioc{1}; tcp::acceptor acceptor{ioc, {address, port}}; tcp::socket socket{ioc}; http_server(acceptor, socket); ioc.run(); } catch(std::exception const& e) { std::cerr << "Error: " << e.what() << std::endl; return EXIT_FAILURE; } } ``` -------------------------------- ### Main Function for WebSocket Server Setup Source: https://www.boost.org/doc/libs/latest/libs/beast/example/websocket/server/async-local/websocket_server_async_local.cpp Sets up and runs the asynchronous WebSocket server. It parses command-line arguments for the socket path and number of threads, initializes the io_context, and starts the listener. ```cpp #include "listener.hpp" #include "session.hpp" #include #include #include #include #include #include #include #include #include #include #include #include #include namespace beast = boost::beast; namespace http = beast::http; namespace net = boost::asio; namespace sys = boost::system; using stream_protocol = net::local::stream_protocol; int main(int argc, char* argv[]) { try { // Check command line arguments. if (argc != 3) { std::cerr << "Usage: websocket-server-async-local \n" << "Example:\n" << " websocket-server-async-local /tmp/ws.sock 1\n"; return EXIT_FAILURE; } auto const path = argv[1]; auto const threads = std::max(1, std::atoi(argv[2])); // The io_context is required for all I/O net::io_context ioc{threads}; // Remove previous binding std::remove(path); // Create and launch a listening port std::make_shared(ioc, stream_protocol::endpoint{path})->run(); // Run the I/O service on the requested number of threads std::vector v; v.reserve(threads - 1); for(auto i = threads - 1; i > 0; --i) v.emplace_back( [&ioc] { ioc.run(); }); ioc.run(); return EXIT_SUCCESS; } catch(std::exception const& e) { std::cerr << e.what() << std::endl; return EXIT_FAILURE; } } #else int main(int, char*[]) { std::cerr << "Local sockets not available on this platform" << std::endl; return EXIT_FAILURE; } #endif ``` -------------------------------- ### Main Function Setup for Async SSL HTTP Server Source: https://www.boost.org/doc/libs/latest/libs/beast/example/http/server/async-ssl/http_server_async_ssl.cpp Parses command-line arguments to configure the server's address, port, document root, and thread count. It initializes the network context and starts the listener. ```cpp int main(int argc, char* argv[]) { // Check command line arguments. if (argc != 5) { std::cerr << "Usage: http-server-async-ssl
\n" << "Example:\n" << " http-server-async-ssl 0.0.0.0 8080 . 1\n"; return EXIT_FAILURE; } auto const address = net::ip::make_address(argv[1]); ``` -------------------------------- ### Main Server Setup and Listener Source: https://www.boost.org/doc/libs/latest/libs/beast/example/http/server/sync-ssl/http_server_sync_ssl.cpp Initializes the Boost.Beast HTTP server. It parses command-line arguments for address, port, and document root, sets up the io_context and SSL context, loads the server certificate, and starts listening for incoming connections. ```cpp int main(int argc, char* argv[]) { try { // Check command line arguments. if (argc != 4) { std::cerr << "Usage: http-server-sync-ssl
\n" << "Example:\n" << " http-server-sync-ssl 0.0.0.0 8080 .\n"; return EXIT_FAILURE; } auto const address = net::ip::make_address(argv[1]); auto const port = static_cast(std::atoi(argv[2])); auto const doc_root = std::make_shared(argv[3]); // The io_context is required for all I/O net::io_context ioc{1}; // The SSL context is required, and holds certificates ssl::context ctx{ssl::context::tlsv12}; // This holds the self-signed certificate used by the server load_server_certificate(ctx); // The acceptor receives incoming connections tcp::acceptor acceptor{ioc, {address, port}}; for(;;) { ``` -------------------------------- ### Main Function for WebSocket Server Setup Source: https://www.boost.org/doc/libs/latest/libs/beast/example/websocket/server/awaitable/websocket_server_awaitable.cpp Initializes the Boost.Asio io_context, parses command-line arguments for address, port, and thread count, and starts the listening coroutine. It then runs the io_context on multiple threads to handle concurrent operations. ```cpp int main(int argc, char* argv[]) { // Check command line arguments. if(argc != 4) { std::cerr << "Usage: websocket-server-awaitable
\n" << "Example:\n" << " websocket-server-awaitable 0.0.0.0 8080 1\n"; return EXIT_FAILURE; } auto const address = net::ip::make_address(argv[1]); auto const port = static_cast(std::atoi(argv[2])); auto const threads = std::max(1, std::atoi(argv[3])); // The io_context is required for all I/O net::io_context ioc(threads); // Spawn a listening port net::co_spawn( ioc, do_listen(net::ip::tcp::endpoint{ address, port }), [](std::exception_ptr e) { if(e) { try { std::rethrow_exception(e); } catch(std::exception const& e) { std::cerr << "Error: " << e.what() << std::endl; } } }); // Run the I/O service on the requested number of threads std::vector v; v.reserve(threads - 1); for(auto i = threads - 1; i > 0; --i) v.emplace_back([&ioc] { ioc.run(); }); ioc.run(); return EXIT_SUCCESS; } #else int main(int, char*[]) { std::printf("awaitables require C++20\n"); return EXIT_FAILURE; } #endif ``` -------------------------------- ### WebSocket Server Listener Setup Source: https://www.boost.org/doc/libs/latest/libs/beast/example/websocket/server/stackless-ssl/websocket_server_stackless_ssl.cpp Configures and starts a TCP acceptor to listen for incoming WebSocket connections. It handles socket options, binding, and listening. ```C++ // Accept incoming connections and launches the sessions class listener : public boost::asio::coroutine , public std::enable_shared_from_this { net::io_context& ioc_; ssl::context& ctx_; tcp::acceptor acceptor_; tcp::socket socket_; public: listener( net::io_context& ioc, ssl::context& ctx, tcp::endpoint endpoint) : ioc_(ioc) , ctx_(ctx) , acceptor_(ioc) , socket_(ioc) { beast::error_code ec; // Open the acceptor acceptor_.open(endpoint.protocol(), ec); if(ec) { fail(ec, "open"); return; } // Allow address reuse acceptor_.set_option(net::socket_base::reuse_address(true), ec); if(ec) { fail(ec, "set_option"); return; } // Bind to the server address acceptor_.bind(endpoint, ec); if(ec) { fail(ec, "bind"); return; } // Start listening for connections acceptor_.listen( net::socket_base::max_listen_connections, ec); if(ec) { fail(ec, "listen"); return; } } // Start accepting incoming connections void run() { loop(); } private: #include void loop(beast::error_code ec = {}) { reenter(*this) { for(;;) { yield acceptor_.async_accept( socket_, std::bind( &listener::loop, shared_from_this(), std::placeholders::_1)); if(ec) { fail(ec, "accept"); } else { // Create the session and run it std::make_shared(std::move(socket_), ctx_)->run(); } // Make sure each session gets its own strand socket_ = tcp::socket(net::make_strand(ioc_)); } } } #include }; ``` -------------------------------- ### WebSocket SSL Listener Setup Source: https://www.boost.org/doc/libs/latest/libs/beast/example/websocket/server/coro-ssl/websocket_server_coro_ssl.cpp Sets up the TCP acceptor to listen for incoming connections and launches new sessions for each connection. It configures the acceptor with options like address reuse and starts listening. ```cpp // Accepts incoming connections and launches the sessions void do_listen( net::io_context& ioc, ssl::context& ctx, tcp::endpoint endpoint, net::yield_context yield) { beast::error_code ec; // Open the acceptor tcp::acceptor acceptor(ioc); acceptor.open(endpoint.protocol(), ec); if(ec) return fail(ec, "open"); // Allow address reuse acceptor.set_option(net::socket_base::reuse_address(true), ec); if(ec) return fail(ec, "set_option"); // Bind to the server address acceptor.bind(endpoint, ec); if(ec) return fail(ec, "bind"); // Start listening for connections acceptor.listen(net::socket_base::max_listen_connections, ec); if(ec) return fail(ec, "listen"); for(;;) { tcp::socket socket(ioc); acceptor.async_accept(socket, yield[ec]); if(ec) fail(ec, "accept"); else boost::asio::spawn( acceptor.get_executor(), std::bind( &do_session, websocket::stream>(std::move(socket), ctx), std::placeholders::_1), // we ignore the result of the session, // most errors are handled with error_code boost::asio::detached); } } ``` -------------------------------- ### TCP Listener Setup Source: https://www.boost.org/doc/libs/latest/libs/beast/example/advanced/server-flex/advanced_server_flex.cpp Configures and starts a TCP acceptor to listen for incoming connections on a specified endpoint. It handles socket options and binding to the address. ```cpp class listener : public std::enable_shared_from_this { net::io_context& ioc_; ssl::context& ctx_; tcp::acceptor acceptor_; std::shared_ptr doc_root_; public: listener( net::io_context& ioc, ssl::context& ctx, tcp::endpoint endpoint, std::shared_ptr const& doc_root) : ioc_(ioc) , ctx_(ctx) , acceptor_(net::make_strand(ioc)) , doc_root_(doc_root) { beast::error_code ec; // Open the acceptor acceptor_.open(endpoint.protocol(), ec); if(ec) { fail(ec, "open"); return; } // Allow address reuse acceptor_.set_option(net::socket_base::reuse_address(true), ec); if(ec) { fail(ec, "set_option"); return; } // Bind to the server address acceptor_.bind(endpoint, ec); if(ec) { fail(ec, "bind"); return; } // Start listening for connections acceptor_.listen( net::socket_base::max_listen_connections, ec); if(ec) { fail(ec, "listen"); return; } } // Start accepting incoming connections ``` -------------------------------- ### Serialized HTTP Request Example Source: https://www.boost.org/doc/libs/latest/libs/beast/doc/html/beast/using_http/protocol_primer.html Demonstrates a basic HTTP GET request with a User-Agent header. This format is used by clients to communicate with servers. ```http GET / HTTP/1.1 User-Agent: Beast ``` -------------------------------- ### Synchronous WebSocket SSL Client Example Source: https://www.boost.org/doc/libs/latest/libs/beast/example/websocket/client/sync-ssl/websocket_client_sync_ssl.cpp This C++ code demonstrates how to create a synchronous WebSocket client that connects to a server over SSL. It includes steps for resolving the host, establishing a TCP connection, performing the SSL handshake, the WebSocket handshake, sending a message, receiving a response, and closing the connection gracefully. Ensure you have the necessary Boost libraries installed. ```C++ #include "example/common/root_certificates.hpp" #include #include #include #include #include #include #include #include #include namespace beast = boost::beast; namespace http = beast::http; namespace websocket = beast::websocket; namespace net = boost::asio; namespace ssl = boost::asio::ssl; using tcp = boost::asio::ip::tcp; // Sends a WebSocket message and prints the response int main(int argc, char** argv) { try { // Check command line arguments. if(argc != 4) { std::cerr << "Usage: websocket-client-sync-ssl \n" << "Example:\n" << " websocket-client-sync-ssl echo.websocket.org 443 \"Hello, world!\"\n"; return EXIT_FAILURE; } std::string host = argv[1]; auto const port = argv[2]; auto const text = argv[3]; // The io_context is required for all I/O net::io_context ioc; // The SSL context is required, and holds certificates ssl::context ctx{ssl::context::tlsv12_client}; // Verify the remote server's certificate ctx.set_verify_mode(ssl::verify_peer); // This holds the root certificate used for verification load_root_certificates(ctx); // These objects perform our I/O tcp::resolver resolver{ioc}; websocket::stream> ws{ioc, ctx}; // Look up the domain name auto const results = resolver.resolve(host, port); // Make the connection on the IP address we get from a lookup auto ep = net::connect(beast::get_lowest_layer(ws), results); // Set SNI Hostname (many hosts need this to handshake successfully) if(! SSL_set_tlsext_host_name(ws.next_layer().native_handle(), host.c_str())) { throw beast::system_error( static_cast(::ERR_get_error()), net::error::get_ssl_category()); } // Set the expected hostname in the peer certificate for verification ws.next_layer().set_verify_callback(ssl::host_name_verification(host)); // Update the host_ string. This will provide the value of the // Host HTTP header during the WebSocket handshake. // See https://tools.ietf.org/html/rfc7230#section-5.4 host += ':' + std::to_string(ep.port()); // Perform the SSL handshake ws.next_layer().handshake(ssl::stream_base::client); // Set a decorator to change the User-Agent of the handshake ws.set_option(websocket::stream_base::decorator( [](websocket::request_type& req) { req.set(http::field::user_agent, std::string(BOOST_BEAST_VERSION_STRING) + " websocket-client-coro"); })); // Perform the websocket handshake ws.handshake(host, "/"); // Send the message ws.write(net::buffer(std::string(text))); // This buffer will hold the incoming message beast::flat_buffer buffer; // Read a message into our buffer ws.read(buffer); // Close the WebSocket connection ws.close(websocket::close_code::normal); // If we get here then the connection is closed gracefully // The make_printable() function helps print a ConstBufferSequence std::cout << beast::make_printable(buffer.data()) << std::endl; } catch(std::exception const& e) { std::cerr << "Error: " << e.what() << std::endl; return EXIT_FAILURE; } return EXIT_SUCCESS; } ``` -------------------------------- ### HTTP Client Methods Setup Source: https://www.boost.org/doc/libs/latest/libs/beast/example/http/client/methods/http_client_methods.cpp Includes necessary headers and namespaces for Boost.Beast HTTP client operations. ```cpp #include #include #include #include #include #include #include #include namespace beast = boost::beast; namespace http = beast::http; namespace net = boost::asio; using tcp = net::ip::tcp; ``` -------------------------------- ### WebSocket Server Setup Source: https://www.boost.org/doc/libs/latest/libs/beast/example/websocket/server/fast/websocket_server_fast.cpp Includes necessary headers and namespaces for the WebSocket server. ```cpp #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace beast = boost::beast; namespace http = beast::http; namespace websocket = beast::websocket; namespace net = boost::asio; using tcp = boost::asio::ip::tcp; ``` -------------------------------- ### Main Function for Fast WebSocket Server Source: https://www.boost.org/doc/libs/latest/libs/beast/example/websocket/server/fast/websocket_server_fast.cpp Parses command-line arguments for address, starting port, and thread count. Initializes the io_context and starts listeners for synchronous, asynchronous, and coroutine-based WebSocket connections. Runs the io_context on multiple threads. ```cpp int main(int argc, char* argv[]) { // Check command line arguments. if (argc != 4) { std::cerr << "Usage: websocket-server-fast
\n" "Example:\n" " websocket-server-fast 0.0.0.0 8080 1\n" " Connect to:\n" " starting-port+0 for synchronous,\n" " starting-port+1 for asynchronous,\n" " starting-port+2 for coroutine.\n"; return EXIT_FAILURE; } auto const address = net::ip::make_address(argv[1]); auto const port = static_cast(std::atoi(argv[2])); auto const threads = std::max(1, std::atoi(argv[3])); // The io_context is required for all I/O net::io_context ioc{threads}; // Create sync port std::thread(beast::bind_front_handler( &do_sync_listen, std::ref(ioc), tcp::endpoint{ address, static_cast(port + 0u)} )).detach(); // Create async port std::make_shared( ioc, tcp::endpoint{ address, static_cast(port + 1u)})->run(); // Create coro port boost::asio::spawn(ioc, std::bind( &do_coro_listen, std::ref(ioc), tcp::endpoint{ address, static_cast(port + 2u)}, std::placeholders::_1), boost::asio::detached); // Run the I/O service on the requested number of threads std::vector v; v.reserve(threads - 1); for(auto i = threads - 1; i > 0; --i) v.emplace_back( [&ioc] { ioc.run(); }); ioc.run(); return EXIT_SUCCESS; } ``` -------------------------------- ### Example Initiating Function Signature Source: https://www.boost.org/doc/libs/latest/libs/beast/doc/html/beast/using_io/writing_composed_operations.html Signature for an example initiating function that reads a line from a stream and echoes it back. This function accepts a stream, a dynamic buffer, and a completion token. ```cpp template< class AsyncStream, class DynamicBuffer, class CompletionToken> auto async_echo (AsyncStream& stream, DynamicBuffer& buffer, CompletionToken&& token) ``` -------------------------------- ### Serve Static Files with GET and HEAD Source: https://www.boost.org/doc/libs/latest/libs/beast/example/advanced/server-flex/advanced_server_flex.cpp Handles GET and HEAD requests for static files. It constructs the file path, checks for existence, and serves the file content or headers accordingly. Supports index.html for directory requests. ```cpp // Make sure we can handle the method if( req.method() != http::verb::get && req.method() != http::verb::head) return bad_request("Unknown HTTP-method"); // Request path must be absolute and not contain "..". if( req.target().empty() || req.target()[0] != '/' || req.target().find("..") != beast::string_view::npos) return 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 beast::error_code ec; http::file_body::value_type body; body.open(path.c_str(), beast::file_mode::scan, ec); // Handle the case where the file doesn't exist if(ec == beast::errc::no_such_file_or_directory) return not_found(req.target()); // Handle an unknown error if(ec) return server_error(ec.message()); // Cache the size since we need it after the move auto const size = body.size(); // Respond to HEAD request if(req.method() == http::verb::head) { http::response res{http::status::ok, req.version()}; res.set(http::field::server, BOOST_BEAST_VERSION_STRING); res.set(http::field::content_type, mime_type(path)); res.content_length(size); res.keep_alive(req.keep_alive()); return res; } // Respond to GET request http::response res{ std::piecewise_construct, std::make_tuple(std::move(body)), std::make_tuple(http::status::ok, req.version())}; res.set(http::field::server, BOOST_BEAST_VERSION_STRING); res.set(http::field::content_type, mime_type(path)); res.content_length(size); res.keep_alive(req.keep_alive()); return res; } ``` -------------------------------- ### http::param_list Usage Example Source: https://www.boost.org/doc/libs/latest/libs/beast/doc/html/beast/ref/boost__beast__http__param_list.html This example demonstrates how to construct an http::param_list object from a string and iterate through its parameters using a range-based for loop. Each parameter is a key-value pair, where the value is optional. ```APIDOC ## http::param_list ### Description A list of parameters in an HTTP extension field value. ### Synopsis Defined in header `` ```cpp class param_list ``` ### BNF ``` param-list = *( OWS ";" OWS param ) param = token OWS [ "=" OWS ( token / quoted-string ) ] ``` ### Example ```cpp #include #include int main() { for ( auto const & param : boost::beast::http::param_list{ ";level=9;no_context_takeover;bits=15" }) { std::cout << ";" << param.first; if (! param.second.empty()) std::cout << "=" << param.second; std::cout << "\n" ; } } ``` ``` -------------------------------- ### HTTP Response Serializer Example Source: https://www.boost.org/doc/libs/latest/libs/beast/doc/html/beast/using_http/serializer_stream_operations.html Demonstrates how to create an HTTP response and its corresponding serializer in Boost Beast. ```cpp response res; response_serializer sr{res}; ``` -------------------------------- ### HTTP Request Handling and File Serving Source: https://www.boost.org/doc/libs/latest/libs/beast/example/advanced/server/advanced_server.cpp Handles GET and HEAD requests, validates request targets, and serves static files. Includes logic for constructing file paths, opening files, and preparing responses for both GET and HEAD methods, with error handling for file not found and other I/O errors. ```cpp // Returns a server error response auto const server_error = [&req](beast::string_view what) { http::response res{http::status::internal_server_error, req.version()}; res.set(http::field::server, BOOST_BEAST_VERSION_STRING); res.set(http::field::content_type, "text/html"); res.keep_alive(req.keep_alive()); res.body() = "An error occurred: '" + std::string(what) + "'"; res.prepare_payload(); return res; }; // Make sure we can handle the method if( req.method() != http::verb::get && req.method() != http::verb::head) return bad_request("Unknown HTTP-method"); // Request path must be absolute and not contain "..". if( req.target().empty() || req.target()[0] != '/' || req.target().find(".." ) != beast::string_view::npos) return 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 beast::error_code ec; http::file_body::value_type body; body.open(path.c_str(), beast::file_mode::scan, ec); // Handle the case where the file doesn't exist if(ec == beast::errc::no_such_file_or_directory) return not_found(req.target()); // Handle an unknown error if(ec) return server_error(ec.message()); // Cache the size since we need it after the move auto const size = body.size(); // Respond to HEAD request if(req.method() == http::verb::head) { http::response res{http::status::ok, req.version()}; res.set(http::field::server, BOOST_BEAST_VERSION_STRING); res.set(http::field::content_type, mime_type(path)); res.content_length(size); res.keep_alive(req.keep_alive()); return res; } // Respond to GET request http::response res{ std::piecewise_construct, std::make_tuple(std::move(body)), std::make_tuple(http::status::ok, req.version())}; res.set(http::field::server, BOOST_BEAST_VERSION_STRING); res.set(http::field::content_type, mime_type(path)); res.content_length(size); res.keep_alive(req.keep_alive()); return res; } ``` -------------------------------- ### Main Server Entry Point and Setup Source: https://www.boost.org/doc/libs/latest/libs/beast/example/advanced/server-flex/advanced_server_flex.cpp The `main` function sets up the server, including argument parsing, io_context initialization, SSL context configuration, and launching the listener. It also configures signal handling for graceful shutdown. ```cpp int main(int argc, char* argv[]) { // Check command line arguments. if (argc != 5) { std::cerr << "Usage: advanced-server-flex
\n" << "Example:\n" << " advanced-server-flex 0.0.0.0 8080 . 1\n"; return EXIT_FAILURE; } auto const address = net::ip::make_address(argv[1]); auto const port = static_cast(std::atoi(argv[2])); auto const doc_root = std::make_shared(argv[3]); auto const threads = std::max(1, std::atoi(argv[4])); // The io_context is required for all I/O net::io_context ioc{threads}; // The SSL context is required, and holds certificates ssl::context ctx{ssl::context::tlsv12}; // This holds the self-signed certificate used by the server load_server_certificate(ctx); // Create and launch a listening port std::make_shared( ioc, ctx, tcp::endpoint{address, port}, doc_root)->run(); // Capture SIGINT and SIGTERM to perform a clean shutdown net::signal_set signals(ioc, SIGINT, SIGTERM); signals.async_wait( [&](beast::error_code const&, int) { // 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(); }); // Run the I/O service on the requested number of threads std::vector v; v.reserve(threads - 1); for(auto i = threads - 1; i > 0; --i) v.emplace_back( [&ioc] { ioc.run(); }); ioc.run(); // (If we get here, it means we got a SIGINT or SIGTERM) // Block until all the threads exit for(auto& t : v) t.join(); return EXIT_SUCCESS; } ``` -------------------------------- ### HTTPS GET with Timeout using Fibers Source: https://www.boost.org/doc/libs/latest/libs/beast/doc/html/beast/using_io/timeouts.html This example demonstrates how to perform an HTTPS GET request with a 30-second timeout using fibers (stackful coroutines) and Beast's `tcp_stream`. It establishes an encrypted connection, sends an HTTP request, reads the response, and handles potential timeouts and SSL errors. ```cpp /** Request an HTTP resource from a TLS host and return it as a string, with a timeout. This example uses fibers (stackful coroutines) and its own I/O context. */ std::string https_get (std::string const& host, std::string const& target, error_code& ec) { // It is the responsibility of the algorithm to clear the error first. ec = {}; // We use our own I/O context, to make this function blocking. net::io_context ioc; // This context is used to hold client and server certificates. // We do not perform certificate verification in this example. net::ssl::context ctx(net::ssl::context::tlsv12); // This string will hold the body of the HTTP response, if any. std::string result; // Note that Networking TS does not come with spawn. This function // launches a "fiber" which is a coroutine that has its own separately // allocated stack. boost::asio::spawn(ioc, [&](boost::asio::yield_context yield) { net::ssl::stream stream(ioc, ctx); // The resolver will be used to look up the IP addresses for the host name net::ip::tcp::resolver resolver(ioc); // First, look up the name. Networking has its own timeout for this. // The `yield` object is a CompletionToken which specializes the // `net::async_result` customization point to make the fiber work. // // This call will appear to "block" until the operation completes. // It isn't really blocking. Instead, the fiber implementation saves // the call stack and suspends the function until the asynchronous // operation is complete. Then it restores the call stack, and resumes // the function to the statement following the async_resolve. This // allows an asynchronous algorithm to be expressed synchronously. auto const endpoints = resolver.async_resolve(host, "https", {}, yield[ec]); if(ec) return; // The function `get_lowest_layer` retrieves the "bottom most" object // in the stack of stream layers. In this case it will be the tcp_stream. // This timeout will apply to all subsequent operations collectively. // That is to say, they must all complete within the same 30 second // window. get_lowest_layer(stream).expires_after(std::chrono::seconds(30)); // `tcp_stream` range connect algorithms are member functions, unlike net:: get_lowest_layer(stream).async_connect(endpoints, yield[ec]); if(ec) return; // Perform the TLS handshake stream.async_handshake(net::ssl::stream_base::client, yield[ec]); if(ec) return; // Send an HTTP GET request for the target { http::request req; req.method(http::verb::get); req.target(target); req.version(11); req.set(http::field::host, host); req.set(http::field::user_agent, "Beast"); http::async_write(stream, req, yield[ec]); if(ec) return; } // Now read the response flat_buffer buffer; http::response res; http::async_read(stream, buffer, res, yield[ec]); if(ec) return; // Try to perform the TLS shutdown handshake stream.async_shutdown(yield[ec]); // `net::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 // ``` -------------------------------- ### Main Server Entry Point Source: https://www.boost.org/doc/libs/latest/libs/beast/example/http/server/awaitable/http_server_awaitable.cpp Initializes the server, parses command-line arguments, sets up the I/O context, and starts the listening process. Includes usage instructions. ```cpp int main(int argc, char* argv[]) { // Check command line arguments. if(argc != 5) { std::cerr << "Usage: http-server-awaitable
\n" << "Example:\n" << " http-server-awaitable 0.0.0.0 8080 . 1\n"; return EXIT_FAILURE; } auto const address = net::ip::make_address(argv[1]); auto const port = static_cast(std::atoi(argv[2])); auto const doc_root = std::make_shared(argv[3]); auto const threads = std::max(1, std::atoi(argv[4])); // The io_context is required for all I/O net::io_context ioc{ threads }; // Spawn a listening port net::co_spawn( ioc, do_listen(net::ip::tcp::endpoint{ address, port }, doc_root), [](std::exception_ptr e) { ``` -------------------------------- ### Async HTTP Client Setup and Run Source: https://www.boost.org/doc/libs/latest/libs/beast/example/http/client/async/http_client_async.cpp Sets up the io_context and launches an asynchronous HTTP client session. The I/O service is then run until the operation completes. ```cpp auto const host = argv[1]; auto const port = argv[2]; auto const target = argv[3]; int version = argc == 5 && !std::strcmp("1.0", argv[4]) ? 10 : 11; // The io_context is required for all I/O net::io_context ioc; // Launch the asynchronous operation std::make_shared(ioc)->run(host, port, target, version); // Run the I/O service. The call will return when // the get operation is complete. ioc.run(); return EXIT_SUCCESS; } ``` -------------------------------- ### Main Function Setup for WebSocket Client Source: https://www.boost.org/doc/libs/latest/libs/beast/example/websocket/client/coro-ssl/websocket_client_coro_ssl.cpp Sets up the Boost.Asio io_context and SSL context, then launches the WebSocket session coroutine. Ensure the correct number of command-line arguments are provided. ```cpp #include "example/common/root_certificates.hpp" #include #include #include #include #include #include #include #include #include namespace beast = boost::beast; // from namespace http = beast::http; // from namespace websocket = beast::websocket; // from namespace net = boost::asio; // from namespace ssl = boost::asio::ssl; // from using tcp = boost::asio::ip::tcp; // from //------------------------------------------------------------------------------ // Report a failure void fail(beast::error_code ec, char const* what) { std::cerr << what << ": " << ec.message() << "\n"; } // Sends a WebSocket message and prints the response void do_session( std::string host, std::string const& port, std::string const& text, net::io_context& ioc, ssl::context& ctx, net::yield_context yield) { beast::error_code ec; // These objects perform our I/O tcp::resolver resolver(ioc); websocket::stream> ws(ioc, ctx); // Look up the domain name auto const results = resolver.async_resolve(host, port, yield[ec]); if(ec) return fail(ec, "resolve"); // Set a timeout on the operation beast::get_lowest_layer(ws).expires_after(std::chrono::seconds(30)); // Make the connection on the IP address we get from a lookup auto ep = beast::get_lowest_layer(ws).async_connect(results, yield[ec]); if(ec) return fail(ec, "connect"); // Set SNI Hostname (many hosts need this to handshake successfully) if(! SSL_set_tlsext_host_name(ws.next_layer().native_handle(), host.c_str())) { ec.assign(static_cast(::ERR_get_error()), net::error::get_ssl_category()); return fail(ec, "connect"); } // Set the expected hostname in the peer certificate for verification ws.next_layer().set_verify_callback(ssl::host_name_verification(host)); // Update the host string. This will provide the value of the // Host HTTP header during the WebSocket handshake. // See https://tools.ietf.org/html/rfc7230#section-5.4 host += ':' + std::to_string(ep.port()); // Set a timeout on the operation beast::get_lowest_layer(ws).expires_after(std::chrono::seconds(30)); // Set a decorator to change the User-Agent of the handshake ws.set_option(websocket::stream_base::decorator( [](websocket::request_type& req) { req.set(http::field::user_agent, std::string(BOOST_BEAST_VERSION_STRING) + " websocket-client-coro"); })); // Perform the SSL handshake ws.next_layer().async_handshake(ssl::stream_base::client, yield[ec]); if(ec) return fail(ec, "ssl_handshake"); // Turn off the timeout on the tcp_stream, because // the websocket stream has its own timeout system. beast::get_lowest_layer(ws).expires_never(); // Set suggested timeout settings for the websocket ws.set_option( websocket::stream_base::timeout::suggested( beast::role_type::client)); // Perform the websocket handshake ws.async_handshake(host, "/", yield[ec]); if(ec) return fail(ec, "handshake"); // Send the message ws.async_write(net::buffer(std::string(text)), yield[ec]); if(ec) return fail(ec, "write"); // This buffer will hold the incoming message beast::flat_buffer buffer; // Read a message into our buffer ws.async_read(buffer, yield[ec]); if(ec) return fail(ec, "read"); // Close the WebSocket connection ws.async_close(websocket::close_code::normal, yield[ec]); if(ec) return fail(ec, "close"); // If we get here then the connection is closed gracefully // The make_printable() function helps print a ConstBufferSequence std::cout << beast::make_printable(buffer.data()) << std::endl; } //------------------------------------------------------------------------------ int main(int argc, char** argv) { // Check command line arguments. if(argc != 4) { std::cerr << "Usage: websocket-client-coro-ssl \n" << ```