Use timeouts in HTTP client examples

This commit is contained in:
Vinnie Falco
2019-02-09 22:04:01 -08:00
parent 5b97fbb966
commit cab2472ee9
5 changed files with 72 additions and 34 deletions

View File

@ -3,6 +3,7 @@ Version 213:
* Fix posix_file::close handling of EINTR
* basic_stream subsumes stranded_stream:
* Use timeouts in HTTP server examples
* Use timeouts in HTTP client examples
--------------------------------------------------------------------------------

View File

@ -18,10 +18,7 @@
#include <boost/beast/core.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/error.hpp>
#include <boost/asio/ssl/stream.hpp>
#include <boost/beast/_experimental/core/ssl_stream.hpp>
#include <cstdlib>
#include <functional>
#include <iostream>
@ -36,6 +33,10 @@ using tcp = boost::asio::ip::tcp; // from <boost/asio/ip/tcp.hpp>
//------------------------------------------------------------------------------
// The type of stream to use
using stream_type =
beast::ssl_stream<beast::tcp_stream<net::io_context::executor_type>>;
// Report a failure
void
fail(beast::error_code ec, char const* what)
@ -47,7 +48,7 @@ fail(beast::error_code ec, char const* what)
class session : public std::enable_shared_from_this<session>
{
tcp::resolver resolver_;
ssl::stream<tcp::socket> stream_;
stream_type stream_;
beast::flat_buffer buffer_; // (Must persist between reads)
http::request<http::empty_body> req_;
http::response<http::string_body> res_;
@ -103,11 +104,13 @@ public:
if(ec)
return fail(ec, "resolve");
// Set a timeout on the operation
beast::get_lowest_layer(stream_).expires_after(std::chrono::seconds(30));
// Make the connection on the IP address we get from a lookup
net::async_connect(
stream_.next_layer(),
results.begin(),
results.end(),
beast::async_connect(
beast::get_lowest_layer(stream_),
results,
std::bind(
&session::on_connect,
shared_from_this(),
@ -135,6 +138,9 @@ public:
if(ec)
return fail(ec, "handshake");
// Set a timeout on the operation
beast::get_lowest_layer(stream_).expires_after(std::chrono::seconds(30));
// Send the HTTP request to the remote host
http::async_write(stream_, req_,
std::bind(
@ -176,6 +182,9 @@ public:
// Write the message to standard out
std::cout << res_ << std::endl;
// Set a timeout on the operation
beast::get_lowest_layer(stream_).expires_after(std::chrono::seconds(30));
// Gracefully close the stream
stream_.async_shutdown(
std::bind(

View File

@ -16,8 +16,6 @@
#include <boost/beast/core.hpp>
#include <boost/beast/http.hpp>
#include <boost/beast/version.hpp>
#include <boost/asio/connect.hpp>
#include <boost/asio/ip/tcp.hpp>
#include <cstdlib>
#include <functional>
#include <iostream>
@ -31,6 +29,9 @@ using tcp = boost::asio::ip::tcp; // from <boost/asio/ip/tcp.hpp>
//------------------------------------------------------------------------------
// The type of stream to use
using stream_type = beast::tcp_stream<net::io_context::executor_type>;
// Report a failure
void
fail(beast::error_code ec, char const* what)
@ -42,7 +43,7 @@ fail(beast::error_code ec, char const* what)
class session : public std::enable_shared_from_this<session>
{
tcp::resolver resolver_;
tcp::socket socket_;
stream_type stream_;
beast::flat_buffer buffer_; // (Must persist between reads)
http::request<http::empty_body> req_;
http::response<http::string_body> res_;
@ -52,7 +53,7 @@ public:
explicit
session(net::io_context& ioc)
: resolver_(ioc)
, socket_(ioc)
, stream_(ioc)
{
}
@ -90,11 +91,13 @@ public:
if(ec)
return fail(ec, "resolve");
// Set a timeout on the operation
stream_.expires_after(std::chrono::seconds(30));
// Make the connection on the IP address we get from a lookup
net::async_connect(
socket_,
results.begin(),
results.end(),
beast::async_connect(
stream_,
results,
std::bind(
&session::on_connect,
shared_from_this(),
@ -107,8 +110,11 @@ public:
if(ec)
return fail(ec, "connect");
// Set a timeout on the operation
stream_.expires_after(std::chrono::seconds(30));
// Send the HTTP request to the remote host
http::async_write(socket_, req_,
http::async_write(stream_, req_,
std::bind(
&session::on_write,
shared_from_this(),
@ -127,7 +133,7 @@ public:
return fail(ec, "write");
// Receive the HTTP response
http::async_read(socket_, buffer_, res_,
http::async_read(stream_, buffer_, res_,
std::bind(
&session::on_read,
shared_from_this(),
@ -149,7 +155,7 @@ public:
std::cout << res_ << std::endl;
// Gracefully close the socket
socket_.shutdown(tcp::socket::shutdown_both, ec);
stream_.socket().shutdown(tcp::socket::shutdown_both, ec);
// not_connected happens sometimes so don't bother reporting it.
if(ec && ec != beast::errc::not_connected)

View File

@ -18,11 +18,8 @@
#include <boost/beast/core.hpp>
#include <boost/beast/http.hpp>
#include <boost/beast/version.hpp>
#include <boost/asio/connect.hpp>
#include <boost/beast/_experimental/core/ssl_stream.hpp>
#include <boost/asio/spawn.hpp>
#include <boost/asio/ip/tcp.hpp>
#include <boost/asio/ssl/error.hpp>
#include <boost/asio/ssl/stream.hpp>
#include <cstdlib>
#include <functional>
#include <iostream>
@ -36,6 +33,11 @@ using tcp = boost::asio::ip::tcp; // from <boost/asio/ip/tcp.hpp>
//------------------------------------------------------------------------------
// The type of stream to use
// Stackful coroutines are already stranded.
using stream_type =
beast::ssl_stream<beast::tcp_stream<net::io_context::executor_type>>;
// Report a failure
void
fail(beast::error_code ec, char const* what)
@ -57,8 +59,8 @@ do_session(
beast::error_code ec;
// These objects perform our I/O
tcp::resolver resolver{ioc};
ssl::stream<tcp::socket> stream{ioc, ctx};
tcp::resolver resolver(ioc);
stream_type stream(ioc, ctx);
// Set SNI Hostname (many hosts need this to handshake successfully)
if(! SSL_set_tlsext_host_name(stream.native_handle(), host.c_str()))
@ -73,11 +75,17 @@ do_session(
if(ec)
return fail(ec, "resolve");
// Set the timeout.
beast::get_lowest_layer(stream).expires_after(std::chrono::seconds(30));
// Make the connection on the IP address we get from a lookup
net::async_connect(stream.next_layer(), results.begin(), results.end(), yield[ec]);
beast::async_connect(get_lowest_layer(stream), results, yield[ec]);
if(ec)
return fail(ec, "connect");
// Set the timeout.
beast::get_lowest_layer(stream).expires_after(std::chrono::seconds(30));
// Perform the SSL handshake
stream.async_handshake(ssl::stream_base::client, yield[ec]);
if(ec)
@ -88,6 +96,9 @@ do_session(
req.set(http::field::host, host);
req.set(http::field::user_agent, BOOST_BEAST_VERSION_STRING);
// Set the timeout.
beast::get_lowest_layer(stream).expires_after(std::chrono::seconds(30));
// Send the HTTP request to the remote host
http::async_write(stream, req, yield[ec]);
if(ec)
@ -107,6 +118,9 @@ do_session(
// Write the message to standard out
std::cout << res << std::endl;
// Set the timeout.
beast::get_lowest_layer(stream).expires_after(std::chrono::seconds(30));
// Gracefully close the stream
stream.async_shutdown(yield[ec]);
if(ec == net::error::eof)

View File

@ -16,9 +16,7 @@
#include <boost/beast/core.hpp>
#include <boost/beast/http.hpp>
#include <boost/beast/version.hpp>
#include <boost/asio/connect.hpp>
#include <boost/asio/spawn.hpp>
#include <boost/asio/ip/tcp.hpp>
#include <cstdlib>
#include <functional>
#include <iostream>
@ -31,6 +29,10 @@ using tcp = boost::asio::ip::tcp; // from <boost/asio/ip/tcp.hpp>
//------------------------------------------------------------------------------
// The type of stream to use.
// Stackful coroutines are already stranded.
using stream_type = beast::tcp_stream<net::io_context::executor_type>;
// Report a failure
void
fail(beast::error_code ec, char const* what)
@ -52,15 +54,18 @@ do_session(
// These objects perform our I/O
tcp::resolver resolver{ioc};
tcp::socket socket{ioc};
stream_type stream(ioc);
// Look up the domain name
auto const results = resolver.async_resolve(host, port, yield[ec]);
if(ec)
return fail(ec, "resolve");
// Set the timeout.
stream.expires_after(std::chrono::seconds(30));
// Make the connection on the IP address we get from a lookup
net::async_connect(socket, results.begin(), results.end(), yield[ec]);
beast::async_connect(stream, results, yield[ec]);
if(ec)
return fail(ec, "connect");
@ -69,8 +74,11 @@ do_session(
req.set(http::field::host, host);
req.set(http::field::user_agent, BOOST_BEAST_VERSION_STRING);
// Set the timeout.
stream.expires_after(std::chrono::seconds(30));
// Send the HTTP request to the remote host
http::async_write(socket, req, yield[ec]);
http::async_write(stream, req, yield[ec]);
if(ec)
return fail(ec, "write");
@ -81,7 +89,7 @@ do_session(
http::response<http::dynamic_body> res;
// Receive the HTTP response
http::async_read(socket, b, res, yield[ec]);
http::async_read(stream, b, res, yield[ec]);
if(ec)
return fail(ec, "read");
@ -89,7 +97,7 @@ do_session(
std::cout << res << std::endl;
// Gracefully close the socket
socket.shutdown(tcp::socket::shutdown_both, ec);
stream.socket().shutdown(tcp::socket::shutdown_both, ec);
// not_connected happens sometimes
// so don't bother reporting it.