2 // Copyright (c) 2016-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
4 // Distributed under the Boost Software License, Version 1.0. (See accompanying
5 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
7 // Official repository: https://github.com/boostorg/beast
10 //------------------------------------------------------------------------------
12 // Example: HTTP client, coroutine
14 //------------------------------------------------------------------------------
16 #include <boost/beast/core.hpp>
17 #include <boost/beast/http.hpp>
18 #include <boost/beast/version.hpp>
19 #include <boost/asio/connect.hpp>
20 #include <boost/asio/spawn.hpp>
21 #include <boost/asio/ip/tcp.hpp>
27 using tcp
= boost::asio::ip::tcp
; // from <boost/asio/ip/tcp.hpp>
28 namespace http
= boost::beast::http
; // from <boost/beast/http.hpp>
30 //------------------------------------------------------------------------------
34 fail(boost::system::error_code ec
, char const* what
)
36 std::cerr
<< what
<< ": " << ec
.message() << "\n";
39 // Performs an HTTP GET and prints the response
42 std::string
const& host
,
43 std::string
const& port
,
44 std::string
const& target
,
46 boost::asio::io_context
& ioc
,
47 boost::asio::yield_context yield
)
49 boost::system::error_code ec
;
51 // These objects perform our I/O
52 tcp::resolver resolver
{ioc
};
53 tcp::socket socket
{ioc
};
55 // Look up the domain name
56 auto const results
= resolver
.async_resolve(host
, port
, yield
[ec
]);
58 return fail(ec
, "resolve");
60 // Make the connection on the IP address we get from a lookup
61 boost::asio::async_connect(socket
, results
.begin(), results
.end(), yield
[ec
]);
63 return fail(ec
, "connect");
65 // Set up an HTTP GET request message
66 http::request
<http::string_body
> req
{http::verb::get
, target
, version
};
67 req
.set(http::field::host
, host
);
68 req
.set(http::field::user_agent
, BOOST_BEAST_VERSION_STRING
);
70 // Send the HTTP request to the remote host
71 http::async_write(socket
, req
, yield
[ec
]);
73 return fail(ec
, "write");
75 // This buffer is used for reading and must be persisted
76 boost::beast::flat_buffer b
;
78 // Declare a container to hold the response
79 http::response
<http::dynamic_body
> res
;
81 // Receive the HTTP response
82 http::async_read(socket
, b
, res
, yield
[ec
]);
84 return fail(ec
, "read");
86 // Write the message to standard out
87 std::cout
<< res
<< std::endl
;
89 // Gracefully close the socket
90 socket
.shutdown(tcp::socket::shutdown_both
, ec
);
92 // not_connected happens sometimes
93 // so don't bother reporting it.
95 if(ec
&& ec
!= boost::system::errc::not_connected
)
96 return fail(ec
, "shutdown");
98 // If we get here then the connection is closed gracefully
101 //------------------------------------------------------------------------------
103 int main(int argc
, char** argv
)
105 // Check command line arguments.
106 if(argc
!= 4 && argc
!= 5)
109 "Usage: http-client-coro <host> <port> <target> [<HTTP version: 1.0 or 1.1(default)>]\n" <<
111 " http-client-coro www.example.com 80 /\n" <<
112 " http-client-coro www.example.com 80 / 1.0\n";
115 auto const host
= argv
[1];
116 auto const port
= argv
[2];
117 auto const target
= argv
[3];
118 int version
= argc
== 5 && !std::strcmp("1.0", argv
[4]) ? 10 : 11;
120 // The io_context is required for all I/O
121 boost::asio::io_context ioc
;
123 // Launch the asynchronous operation
124 boost::asio::spawn(ioc
, std::bind(
131 std::placeholders::_1
));
133 // Run the I/O service. The call will return when
134 // the get operation is complete.