### 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" <<
```