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 SSL client, synchronous
14 //------------------------------------------------------------------------------
16 #include "example/common/root_certificates.hpp"
18 #include <boost/beast/core.hpp>
19 #include <boost/beast/http.hpp>
20 #include <boost/beast/version.hpp>
21 #include <boost/asio/connect.hpp>
22 #include <boost/asio/ip/tcp.hpp>
23 #include <boost/asio/ssl/error.hpp>
24 #include <boost/asio/ssl/stream.hpp>
29 using tcp
= boost::asio::ip::tcp
; // from <boost/asio/ip/tcp.hpp>
30 namespace ssl
= boost::asio::ssl
; // from <boost/asio/ssl.hpp>
31 namespace http
= boost::beast::http
; // from <boost/beast/http.hpp>
33 // Performs an HTTP GET and prints the response
34 int main(int argc
, char** argv
)
38 // Check command line arguments.
39 if(argc
!= 4 && argc
!= 5)
42 "Usage: http-client-sync-ssl <host> <port> <target> [<HTTP version: 1.0 or 1.1(default)>]\n" <<
44 " http-client-sync-ssl www.example.com 443 /\n" <<
45 " http-client-sync-ssl www.example.com 443 / 1.0\n";
48 auto const host
= argv
[1];
49 auto const port
= argv
[2];
50 auto const target
= argv
[3];
51 int version
= argc
== 5 && !std::strcmp("1.0", argv
[4]) ? 10 : 11;
53 // The io_context is required for all I/O
54 boost::asio::io_context ioc
;
56 // The SSL context is required, and holds certificates
57 ssl::context ctx
{ssl::context::sslv23_client
};
59 // This holds the root certificate used for verification
60 load_root_certificates(ctx
);
62 // These objects perform our I/O
63 tcp::resolver resolver
{ioc
};
64 ssl::stream
<tcp::socket
> stream
{ioc
, ctx
};
66 // Set SNI Hostname (many hosts need this to handshake successfully)
67 if(! SSL_set_tlsext_host_name(stream
.native_handle(), host
))
69 boost::system::error_code ec
{static_cast<int>(::ERR_get_error()), boost::asio::error::get_ssl_category()};
70 throw boost::system::system_error
{ec
};
73 // Look up the domain name
74 auto const results
= resolver
.resolve(host
, port
);
76 // Make the connection on the IP address we get from a lookup
77 boost::asio::connect(stream
.next_layer(), results
.begin(), results
.end());
79 // Perform the SSL handshake
80 stream
.handshake(ssl::stream_base::client
);
82 // Set up an HTTP GET request message
83 http::request
<http::string_body
> req
{http::verb::get
, target
, version
};
84 req
.set(http::field::host
, host
);
85 req
.set(http::field::user_agent
, BOOST_BEAST_VERSION_STRING
);
87 // Send the HTTP request to the remote host
88 http::write(stream
, req
);
90 // This buffer is used for reading and must be persisted
91 boost::beast::flat_buffer buffer
;
93 // Declare a container to hold the response
94 http::response
<http::dynamic_body
> res
;
96 // Receive the HTTP response
97 http::read(stream
, buffer
, res
);
99 // Write the message to standard out
100 std::cout
<< res
<< std::endl
;
102 // Gracefully close the stream
103 boost::system::error_code ec
;
105 if(ec
== boost::asio::error::eof
)
108 // http://stackoverflow.com/questions/25587403/boost-asio-ssl-async-shutdown-always-finishes-with-an-error
109 ec
.assign(0, ec
.category());
112 throw boost::system::system_error
{ec
};
114 // If we get here then the connection is closed gracefully
116 catch(std::exception
const& e
)
118 std::cerr
<< "Error: " << e
.what() << std::endl
;