]> git.proxmox.com Git - ceph.git/blobdiff - ceph/src/boost/libs/beast/example/http/client/async-ssl/http_client_async_ssl.cpp
import new upstream nautilus stable release 14.2.8
[ceph.git] / ceph / src / boost / libs / beast / example / http / client / async-ssl / http_client_async_ssl.cpp
index 76b26cb0b6080b938baf7aff0ca76dc337ed0091..6248c33fab0376c9ce40d4435ccf54efb80fb888 100644 (file)
@@ -1,5 +1,5 @@
 //
-// Copyright (c) 2016-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
+// Copyright (c) 2016-2019 Vinnie Falco (vinnie dot falco at gmail dot com)
 //
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
 
 #include <boost/beast/core.hpp>
 #include <boost/beast/http.hpp>
+#include <boost/beast/ssl.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/asio/strand.hpp>
 #include <cstdlib>
 #include <functional>
 #include <iostream>
 #include <memory>
 #include <string>
 
-using tcp = boost::asio::ip::tcp;       // from <boost/asio/ip/tcp.hpp>
+namespace beast = boost::beast;         // from <boost/beast.hpp>
+namespace http = beast::http;           // from <boost/beast/http.hpp>
+namespace net = boost::asio;            // from <boost/asio.hpp>
 namespace ssl = boost::asio::ssl;       // from <boost/asio/ssl.hpp>
-namespace http = boost::beast::http;    // from <boost/beast/http.hpp>
+using tcp = boost::asio::ip::tcp;       // from <boost/asio/ip/tcp.hpp>
 
 //------------------------------------------------------------------------------
 
 // Report a failure
 void
-fail(boost::system::error_code ec, char const* what)
+fail(beast::error_code ec, char const* what)
 {
     std::cerr << what << ": " << ec.message() << "\n";
 }
@@ -45,17 +45,18 @@ fail(boost::system::error_code ec, char const* what)
 class session : public std::enable_shared_from_this<session>
 {
     tcp::resolver resolver_;
-    ssl::stream<tcp::socket> stream_;
-    boost::beast::flat_buffer buffer_; // (Must persist between reads)
+    beast::ssl_stream<beast::tcp_stream> stream_;
+    beast::flat_buffer buffer_; // (Must persist between reads)
     http::request<http::empty_body> req_;
     http::response<http::string_body> res_;
 
 public:
-    // Resolver and stream require an io_context
+    // Objects are constructed with a strand to
+    // ensure that handlers do not execute concurrently.
     explicit
-    session(boost::asio::io_context& ioc, ssl::context& ctx)
-        : resolver_(ioc)
-        , stream_(ioc, ctx)
+    session(net::io_context& ioc, ssl::context& ctx)
+        : resolver_(net::make_strand(ioc))
+        , stream_(net::make_strand(ioc), ctx)
     {
     }
 
@@ -70,7 +71,7 @@ public:
         // Set SNI Hostname (many hosts need this to handshake successfully)
         if(! SSL_set_tlsext_host_name(stream_.native_handle(), host))
         {
-            boost::system::error_code ec{static_cast<int>(::ERR_get_error()), boost::asio::error::get_ssl_category()};
+            beast::error_code ec{static_cast<int>(::ERR_get_error()), net::error::get_ssl_category()};
             std::cerr << ec.message() << "\n";
             return;
         }
@@ -86,34 +87,32 @@ public:
         resolver_.async_resolve(
             host,
             port,
-            std::bind(
+            beast::bind_front_handler(
                 &session::on_resolve,
-                shared_from_this(),
-                std::placeholders::_1,
-                std::placeholders::_2));
+                shared_from_this()));
     }
 
     void
     on_resolve(
-        boost::system::error_code ec,
+        beast::error_code ec,
         tcp::resolver::results_type results)
     {
         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
-        boost::asio::async_connect(
-            stream_.next_layer(),
-            results.begin(),
-            results.end(),
-            std::bind(
+        beast::get_lowest_layer(stream_).async_connect(
+            results,
+            beast::bind_front_handler(
                 &session::on_connect,
-                shared_from_this(),
-                std::placeholders::_1));
+                shared_from_this()));
     }
 
     void
-    on_connect(boost::system::error_code ec)
+    on_connect(beast::error_code ec, tcp::resolver::results_type::endpoint_type)
     {
         if(ec)
             return fail(ec, "connect");
@@ -121,49 +120,47 @@ public:
         // Perform the SSL handshake
         stream_.async_handshake(
             ssl::stream_base::client,
-            std::bind(
+            beast::bind_front_handler(
                 &session::on_handshake,
-                shared_from_this(),
-                std::placeholders::_1));
+                shared_from_this()));
     }
 
     void
-    on_handshake(boost::system::error_code ec)
+    on_handshake(beast::error_code ec)
     {
         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(
+            beast::bind_front_handler(
                 &session::on_write,
-                shared_from_this(),
-                std::placeholders::_1,
-                std::placeholders::_2));
+                shared_from_this()));
     }
 
     void
     on_write(
-        boost::system::error_code ec,
+        beast::error_code ec,
         std::size_t bytes_transferred)
     {
         boost::ignore_unused(bytes_transferred);
 
         if(ec)
             return fail(ec, "write");
-        
+
         // Receive the HTTP response
         http::async_read(stream_, buffer_, res_,
-            std::bind(
+            beast::bind_front_handler(
                 &session::on_read,
-                shared_from_this(),
-                std::placeholders::_1,
-                std::placeholders::_2));
+                shared_from_this()));
     }
 
     void
     on_read(
-        boost::system::error_code ec,
+        beast::error_code ec,
         std::size_t bytes_transferred)
     {
         boost::ignore_unused(bytes_transferred);
@@ -174,22 +171,24 @@ 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(
+            beast::bind_front_handler(
                 &session::on_shutdown,
-                shared_from_this(),
-                std::placeholders::_1));
+                shared_from_this()));
     }
 
     void
-    on_shutdown(boost::system::error_code ec)
+    on_shutdown(beast::error_code ec)
     {
-        if(ec == boost::asio::error::eof)
+        if(ec == net::error::eof)
         {
             // Rationale:
             // http://stackoverflow.com/questions/25587403/boost-asio-ssl-async-shutdown-always-finishes-with-an-error
-            ec.assign(0, ec.category());
+            ec = {};
         }
         if(ec)
             return fail(ec, "shutdown");
@@ -218,14 +217,17 @@ int main(int argc, char** argv)
     int version = argc == 5 && !std::strcmp("1.0", argv[4]) ? 10 : 11;
 
     // The io_context is required for all I/O
-    boost::asio::io_context ioc;
+    net::io_context ioc;
 
     // The SSL context is required, and holds certificates
-    ssl::context ctx{ssl::context::sslv23_client};
+    ssl::context ctx{ssl::context::tlsv12_client};
 
     // This holds the root certificate used for verification
     load_root_certificates(ctx);
 
+    // Verify the remote server's certificate
+    ctx.set_verify_mode(ssl::verify_peer);
+
     // Launch the asynchronous operation
     std::make_shared<session>(ioc, ctx)->run(host, port, target, version);