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. */
| 287 | This example uses fibers (stackful coroutines) and its own I/O context. |
| 288 | */ |
| 289 | std::string |
| 290 | https_get (std::string const& host, std::string const& target, error_code& ec) |
| 291 | { |
| 292 | // It is the responsibility of the algorithm to clear the error first. |
| 293 | ec = {}; |
| 294 | |
| 295 | // We use our own I/O context, to make this function blocking. |
| 296 | net::io_context ioc; |
| 297 | |
| 298 | // This context is used to hold client and server certificates. |
| 299 | // We do not perform certificate verification in this example. |
| 300 | |
| 301 | net::ssl::context ctx(net::ssl::context::tlsv12); |
| 302 | |
| 303 | // This string will hold the body of the HTTP response, if any. |
| 304 | std::string result; |
| 305 | |
| 306 | // Note that Networking TS does not come with spawn. This function |
| 307 | // launches a "fiber" which is a coroutine that has its own separately |
| 308 | // allocated stack. |
| 309 | |
| 310 | boost::asio::spawn(ioc, |
| 311 | [&](boost::asio::yield_context yield) |
| 312 | { |
| 313 | net::ssl::stream<tcp_stream> stream(ioc, ctx); |
| 314 | |
| 315 | // The resolver will be used to look up the IP addresses for the host name |
| 316 | net::ip::tcp::resolver resolver(ioc); |
| 317 | |
| 318 | // First, look up the name. Networking has its own timeout for this. |
| 319 | // The `yield` object is a CompletionToken which specializes the |
| 320 | // `net::async_result` customization point to make the fiber work. |
| 321 | // |
| 322 | // This call will appear to "block" until the operation completes. |
| 323 | // It isn't really blocking. Instead, the fiber implementation saves |
| 324 | // the call stack and suspends the function until the asynchronous |
| 325 | // operation is complete. Then it restores the call stack, and resumes |
| 326 | // the function to the statement following the async_resolve. This |
| 327 | // allows an asynchronous algorithm to be expressed synchronously. |
| 328 | |
| 329 | auto const endpoints = resolver.async_resolve(host, "https", {}, yield[ec]); |
| 330 | if(ec) |
| 331 | return; |
| 332 | |
| 333 | // The function `get_lowest_layer` retrieves the "bottom most" object |
| 334 | // in the stack of stream layers. In this case it will be the tcp_stream. |
| 335 | // This timeout will apply to all subsequent operations collectively. |
| 336 | // That is to say, they must all complete within the same 30 second |
| 337 | // window. |
| 338 | |
| 339 | get_lowest_layer(stream).expires_after(std::chrono::seconds(30)); |
| 340 | |
| 341 | // `tcp_stream` range connect algorithms are member functions, unlike net:: |
| 342 | get_lowest_layer(stream).async_connect(endpoints, yield[ec]); |
| 343 | if(ec) |
| 344 | return; |
| 345 | |
| 346 | // Perform the TLS handshake |
nothing calls this directly
no test coverage detected