// Read & parse the response beast::flat_buffer buffer; http::response<http::dynamic_body> res; http::read(stream, buffer, res); // Print status code, e.g. 200 cout << res.result_int() << endl;
// Read & parse the response beast::flat_buffer buffer; http::response<http::dynamic_body> res; http::read(stream, buffer, res); // Print status code, e.g. 200 cout << res.result_int() << endl;
// Read & parse the response beast::flat_buffer buffer; http::response<http::dynamic_body> res; http::read(stream, buffer, res); // Iterate response headers for (auto it = res.begin(); it != res.end(); ++it) { std::cout << it->name_string() << ": " << it->value() << "\n"; } // ... or get one specific header cout << res["Content-Length"] << endl;
First include the required header:
#include <openssl/ssl.h>
Once you have initialized the boost::beast::ssl_stream
, add the following code (with host
being a std::string
containing the hostname to connect to such as api.ipify.org
):
if(!SSL_set_tlsext_host_name(stream.native_handle(), host.c_str())) { beast::error_code ec{static_cast<int>(::ERR_get_error()), net::error::get_ssl_category()}; throw beast::system_error{ec}; }
Original source: boost::beast official HTTPS client example
This example uses boost::beast
to make a HTTPS request to ipify.org and parses the response using boost::json
.
#include <iostream> #include <sstream> #include <iomanip> #include <algorithm> #include <boost/beast/core.hpp> #include <boost/beast/ssl.hpp> #include <boost/beast/http.hpp> #include <boost/beast/version.hpp> #include <boost/asio/connect.hpp> #include <boost/asio/ip/tcp.hpp> #include <boost/asio/ssl.hpp> #include <boost/json.hpp> #include <openssl/ssl.h> namespace beast = boost::beast; namespace http = beast::http; namespace net = boost::asio; namespace ip = boost::asio::ip; namespace ssl = boost::asio::ssl; namespace json = boost::json; using tcp = boost::asio::ip::tcp; int main() { std::string host = "api64.ipify.org"; // Initialize IO context net::io_context ioc; ssl::context ctx(ssl::context::tlsv13_client); ctx.set_default_verify_paths(); // Set up an SSL context beast::ssl_stream<beast::tcp_stream> stream(ioc, ctx); stream.set_verify_mode(ssl::verify_none); stream.set_verify_callback([](bool preverified, ssl::verify_context& ctx) { return true; // Accept any certificate }); // Enable SNI if(!SSL_set_tlsext_host_name(stream.native_handle(), host.c_str())) { beast::error_code ec{static_cast<int>(::ERR_get_error()), net::error::get_ssl_category()}; throw beast::system_error{ec}; } // Connect to the HTTPS server ip::tcp::resolver resolver(ioc); get_lowest_layer(stream).connect(resolver.resolve({host, "https"})); get_lowest_layer(stream).expires_after(std::chrono::seconds(30)); // Construct request http::request<http::empty_body> req{http::verb::get, "/?format=json" , 11}; req.set(http::field::host, host); req.set(http::field::user_agent, BOOST_BEAST_VERSION_STRING); // Send the request stream.handshake(ssl::stream_base::client); http::write(stream, req); // Receive the response beast::flat_buffer buffer; http::response<http::dynamic_body> res; http::read(stream, buffer, res); // Parse the JSON response json::error_code err; json::value j = json::parse(buffers_to_string(res.body().data()), err); std::cout << "IP address: " << j.at("ip").as_string() << std::endl; if (err) { std::cerr << "Error parsing JSON: " << err.message() << std::endl; } // Cleanup beast::error_code ec; stream.shutdown(ec); if (ec == net::error::eof) { ec = {}; } if (ec) { throw beast::system_error{ec}; } return 0; }
Compile using
g++ -g -o http-example http-example.cpp -lcrypto -lssl -lboost_json
Example output:
IP address: "2a01:c22:6f8c:ef00:f0bb:a8a8:9c00:ff49"
While running your boost::beast
application, you see the following exception:
terminate called after throwing an instance of 'boost::wrapexcept<boost::system::system_error>' what(): handshake: no protocols available (SSL routines) [asio.ssl:167772351]
You are connecting using a SSL or TLS version the server does not support.
The TLS/SSL version is selected while initializing the boost::asio::ssl::context
:
namespace ssl = boost::asio::ssl; ssl::context ctx(ssl::context::tlsv11_client);
In this case, we’re using the outdated TLSv1.1 protocol.
Change the line to
ssl::context ctx(ssl::context::tlsv13_client);
to use TLSv1.3
instead. Keep in mind that some older TLS/SSL versions are considered to be insecure.
boost::beast
is a header-only library. While boost::beast
heavily depends on boost::asio
as a networking library, asio is also a header-only library.
Therefore, typically, you don’t need to link boost::beast
at all.
The only exception is if you are using SSL/TLS functions for HTTPS connections, in which case you need to link the OpenSSL library which provides the SSL/TLS layer. In that case, link it using
-lcrypto -lssl
This post showcases how to cross-compile boost for OpenWRT. We’ll use the Teltonika RUTX10 SDK which is already pre-configured with the relevant OpenWRT settings for that router.
The prerequisite for this is that you have:
We assume the SDK is located in ~/rutos-ipq40xx-rutx-gpl
.
First, you need to consider that many boost libraries are header-only libraries. For those libraries, you don’t need to compile boost, but it might still be easier to prepare a complete boost folder for installation.
First, download boost and unpack it. Now run
./bootstrap.sh
to compile bjam
.
Now, open project-config.jam
inside the boost folder and add the following line at the top of the file:
using gcc : openwrt : arm-openwrt-linux-muslgnueabi-g++ ;
Now, inside the boost folder, run the following bash script:
export STAGING_DIR=~/rutos-ipq40xx-rutx-gpl/staging_dir export TOOLCHAIN=${STAGING_DIR}/toolchain-arm_cortex-a7+neon-vfpv4_gcc-8.4.0_musl_eabi export CC=${TOOLCHAIN}/bin/arm-openwrt-linux-muslgnueabi-gcc export CPP=${TOOLCHAIN}/bin/arm-openwrt-linux-muslgnueabi-g++ export PATH=$PATH:${TOOLCHAIN}/bin/ # Insert at the top of project-config.jam # using gcc : openwrt : arm-openwrt-linux-muslgnueabi-g++ ; rm -rf ~/boost_rutx10 mkdir -p ~/boost_rutx10/ ./b2 --prefix=$HOME/boost_rutx10 install toolset=gcc-openwrt -sNO_COMPRESSION=1
Now, boost is installed in ~/boost_rutx10
, which has include
and lib
subdirectories.
mitmproxy is a valuable tool to debug HTTPS request made using boost::beast
.
In order to use it, remember that mitmproxy listents to localhost
on port 8080
and forwards requests based on the HTTP Host
header.
First, you need to disable SSL certificate verification:
beast::ssl_stream<beast::tcp_stream> stream(ioc, ctx); stream.set_verify_mode(ssl::verify_none);
Now, instead of connecting to an IP address based on DNS results such as
ip::tcp::resolver resolver(ioc); get_lowest_layer(stream).connect(resolver.resolve({endpoint, "https"}));
directly connect to the 127.0.0.1:8080
endpoint:
boost::asio::ip::tcp::endpoint ep( boost::asio::ip::address::from_string("127.0.0.1"), 8080 ); get_lowest_layer(stream).connect(ep);
Besides that, you can do anything as usual.
This code will initialize a boost::asio::tcp::endpoint
from a IPv4 address string ("127.0.0.1"
as an exmple) and a port number (443
in this example)
boost::asio::ip::tcp::endpoint ep( boost::asio::ip::address::from_string("127.0.0.1"), 443 );
While running your boost::beast
https client you see the following error message:
terminate called after throwing an instance of 'boost::wrapexcept<boost::system::system_error>' what(): uninitialized (SSL routines) [asio.ssl:167772436]
You forgot to handshake before writing the HTTP request:
stream.handshake(ssl::stream_base::client);
You can use a standard for
iteration loon on j.as_array()
in order to iterate all values in the given JSON array:
for (auto& value : json.as_array()) { std::cout << value.as_int64() << std::endl; }
#include <boost/json.hpp> #include <iostream> int main() { const char* json_str = R"([1, 2, 3, 4, 5])"; boost::json::value j = boost::json::parse(json_str); if (j.is_array()) { for (auto& value : j.as_array()) { std::cout << value.as_int64() << std::endl; } } return 0; }
Compile using
g++ -o json json.cpp -lboost_json
This will print
1 2 3 4 5
You can copy a boost::urls::url
by using it copy constructor:
boost::urls::url url1 = boost::urls::url::parse("https://example.com/path1"); boost::urls::url url2(url1); // Copy url1 to url2 using the copy constructor
#include <boost/json.hpp> boost::json::value j = /* ... */; // Access nested value with key "value" j.at("value").as_string();
#include <boost/json.hpp> #include <iostream> int main() { // Hardcoded JSON string const std::string json_str = R"( { "key": "1234", "value": "Hello, world!" } )"; // Parse the JSON string boost::json::value j = boost::json::parse(json_str); // Access the "value" property and print it to stdout std::string value = j.at("value").as_string().c_str(); std::cout << value << std::endl; // Prints "Hello, world!" return 0; }
Compile using
g++ -o json json.cpp -lboost_json
#include <boost/json.hpp> boost::json::value j = boost::json::parse(json_str);
#include <boost/json.hpp> #include <iostream> int main() { // Hardcoded JSON string const std::string json_str = R"( { "key": "1234", "value": "Hello, world!" } )"; // Parse the JSON string boost::json::value j = boost::json::parse(json_str); // Access the "value" property and print it to stdout std::string value = j.at("value").as_string().c_str(); std::cout << value << std::endl; // Prints "Hello, world!" return 0; }
Compile using
g++ -o json json.cpp -lboost_json
#include <iostream> #include <boost/url.hpp> using namespace boost::urls; int main() { std::string username = "myusername"; std::string password = "mypassword"; url_view base_url = "https://example.com/api/login"; url encoded_url(base_url); encoded_url.params().set("user name", username); // With space to test proper encoding encoded_url.params().set("password", password); // Prints "https://example.com/api/login?username=my%20user%20name&password=mypassword" std::cout << "Encoded URL: " << encoded_url << std::endl; return 0; }
Compile using
g++ -o urlhost urlhost.cpp -lboost_url
If you have an URL such as:
std::string myURL = "https://subdomain.example.com/api/test";
you can parse the hostname from it using Boost::URL (you need at least Boost 1.81.0, previous versions of boost don’t have Boost.URL) using
boost::urls::url_view url(myURL); std::string host = url.host(); std::cout << host << std::endl; // Prints "subdomain.example.com"
#include <string> #include <iostream> #include <boost/url.hpp> int main() { std::string myURL = "https://subdomain.example.com/api/test"; boost::urls::url_view url(myURL); std::string host = url.host(); std::cout << host << std::endl; // Prints "subdomain.example.com" }
Compile using
g++ -o urlhost urlhost.cpp -lboost_url
The following example shows how to initialize a boost::asio serial_port
, set its baud rate, parity & stop bits and then read data from it in a loop, printing the data to stdout as-is.
#include <boost/asio.hpp> #include <iostream> #define BUFSIZE 256 int main() { boost::asio::io_service io; // Open serial port boost::asio::serial_port serial(io, "/dev/ttyUSB0"); // Configure basic serial port parameters: 115.2kBaud, 8N1 serial.set_option(boost::asio::serial_port_base::baud_rate(115200)); serial.set_option(boost::asio::serial_port_base::character_size(8 /* data bits */)); serial.set_option(boost::asio::serial_port_base::parity(boost::asio::serial_port_base::parity::none)); serial.set_option(boost::asio::serial_port_base::stop_bits(boost::asio::serial_port_base::stop_bits::one)); // Read data in a loop and copy to stdout while(true) { char data[BUFSIZE]; size_t n = serial.read_some(boost::asio::buffer(data, BUFSIZE)); // Write data to stdout std::cout.write(data, n); } }
For a more complete example that also shows how to open the serial port, see How to open & initialize boost::asio::serial_port
This example shows how to baudrate, parity & stop bits:
// Configure serial port parameters: 115.2kBaud, 8N1 serial.set_option(boost::asio::serial_port_base::baud_rate(115200)); serial.set_option(boost::asio::serial_port_base::character_size(8 /* data bits */)); serial.set_option(boost::asio::serial_port_base::parity(boost::asio::serial_port_base::parity::none)); serial.set_option(boost::asio::serial_port_base::stop_bits(boost::asio::serial_port_base::stop_bits::one));
For a more complete example that also shows how to open the serial port, see How to open & initialize boost::asio::serial_port or our Minimal boost::asio::serial_port read (read_some) example
This example shows how to open a boost serial port and how to set the baudrate, parity & stop bits:
boost::asio::io_service io; // Open serial port boost::asio::serial_port serial(io, "/dev/ttyUSB0"); // Configure basic serial port parameters: 115.2kBaud, 8N1 serial.set_option(boost::asio::serial_port_base::baud_rate(115200)); serial.set_option(boost::asio::serial_port_base::character_size(8 /* data bits */)); serial.set_option(boost::asio::serial_port_base::parity(boost::asio::serial_port_base::parity::none)); serial.set_option(boost::asio::serial_port_base::stop_bits(boost::asio::serial_port_base::stop_bits::one));
Also see our Minimal boost::asio::serial_port read (read_some) example
#include <boost/algorithm/string/split.hpp> // boost::algorithm::split #include <boost/algorithm/string/classification.hpp> // boost::is_any_of #include <string> #include <iostream> #include <vector> int main() { std::string mystr = "foo-bar-x"; // Split by "-" std::vector<std::string> splitResult; boost::algorithm::split(splitResult, mystr, boost::is_any_of("-")); // Print results, one line at a time // Prints: // foo // bar // x for(const std::string& s : splitResult) { std::cout << s << std::endl; } }