2 // Copyright (c) 2016-2019 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/ssl.hpp>
21 #include <boost/beast/version.hpp>
22 #include <boost/asio/connect.hpp>
23 #include <boost/asio/ip/tcp.hpp>
24 #include <boost/asio/ssl/error.hpp>
25 #include <boost/asio/ssl/stream.hpp>
30 namespace beast
= boost::beast
; // from <boost/beast.hpp>
31 namespace http
= beast::http
; // from <boost/beast/http.hpp>
32 namespace net
= boost::asio
; // from <boost/asio.hpp>
33 namespace ssl
= net::ssl
; // from <boost/asio/ssl.hpp>
34 using tcp
= net::ip::tcp
; // from <boost/asio/ip/tcp.hpp>
36 // Performs an HTTP GET and prints the response
37 int main(int argc
, char** argv
)
41 // Check command line arguments.
42 if(argc
!= 4 && argc
!= 5)
45 "Usage: http-client-sync-ssl <host> <port> <target> [<HTTP version: 1.0 or 1.1(default)>]\n" <<
47 " http-client-sync-ssl www.example.com 443 /\n" <<
48 " http-client-sync-ssl www.example.com 443 / 1.0\n";
51 auto const host
= argv
[1];
52 auto const port
= argv
[2];
53 auto const target
= argv
[3];
54 int version
= argc
== 5 && !std::strcmp("1.0", argv
[4]) ? 10 : 11;
56 // The io_context is required for all I/O
59 // The SSL context is required, and holds certificates
60 ssl::context
ctx(ssl::context::tlsv12_client
);
62 // This holds the root certificate used for verification
63 load_root_certificates(ctx
);
65 // Verify the remote server's certificate
66 ctx
.set_verify_mode(ssl::verify_peer
);
68 // These objects perform our I/O
69 tcp::resolver
resolver(ioc
);
70 beast::ssl_stream
<beast::tcp_stream
> stream(ioc
, ctx
);
72 // Set SNI Hostname (many hosts need this to handshake successfully)
73 if(! SSL_set_tlsext_host_name(stream
.native_handle(), host
))
75 beast::error_code ec
{static_cast<int>(::ERR_get_error()), net::error::get_ssl_category()};
76 throw beast::system_error
{ec
};
79 // Look up the domain name
80 auto const results
= resolver
.resolve(host
, port
);
82 // Make the connection on the IP address we get from a lookup
83 beast::get_lowest_layer(stream
).connect(results
);
85 // Perform the SSL handshake
86 stream
.handshake(ssl::stream_base::client
);
88 // Set up an HTTP GET request message
89 http::request
<http::string_body
> req
{http::verb::get
, target
, version
};
90 req
.set(http::field::host
, host
);
91 req
.set(http::field::user_agent
, BOOST_BEAST_VERSION_STRING
);
93 // Send the HTTP request to the remote host
94 http::write(stream
, req
);
96 // This buffer is used for reading and must be persisted
97 beast::flat_buffer buffer
;
99 // Declare a container to hold the response
100 http::response
<http::dynamic_body
> res
;
102 // Receive the HTTP response
103 http::read(stream
, buffer
, res
);
105 // Write the message to standard out
106 std::cout
<< res
<< std::endl
;
108 // Gracefully close the stream
109 beast::error_code ec
;
111 if(ec
== net::error::eof
)
114 // http://stackoverflow.com/questions/25587403/boost-asio-ssl-async-shutdown-always-finishes-with-an-error
118 throw beast::system_error
{ec
};
120 // If we get here then the connection is closed gracefully
122 catch(std::exception
const& e
)
124 std::cerr
<< "Error: " << e
.what() << std::endl
;