http_client_sync_ssl.cpp 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128
  1. //
  2. // Copyright (c) 2016-2019 Vinnie Falco (vinnie dot falco at gmail dot com)
  3. //
  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)
  6. //
  7. // Official repository: https://github.com/boostorg/beast
  8. //
  9. //------------------------------------------------------------------------------
  10. //
  11. // Example: HTTP SSL client, synchronous
  12. //
  13. //------------------------------------------------------------------------------
  14. #include "example/common/root_certificates.hpp"
  15. #include <boost/beast/core.hpp>
  16. #include <boost/beast/http.hpp>
  17. #include <boost/beast/ssl.hpp>
  18. #include <boost/beast/version.hpp>
  19. #include <boost/asio/connect.hpp>
  20. #include <boost/asio/ip/tcp.hpp>
  21. #include <boost/asio/ssl/error.hpp>
  22. #include <boost/asio/ssl/stream.hpp>
  23. #include <cstdlib>
  24. #include <iostream>
  25. #include <string>
  26. namespace beast = boost::beast; // from <boost/beast.hpp>
  27. namespace http = beast::http; // from <boost/beast/http.hpp>
  28. namespace net = boost::asio; // from <boost/asio.hpp>
  29. namespace ssl = net::ssl; // from <boost/asio/ssl.hpp>
  30. using tcp = net::ip::tcp; // from <boost/asio/ip/tcp.hpp>
  31. // Performs an HTTP GET and prints the response
  32. int main(int argc, char** argv)
  33. {
  34. try
  35. {
  36. // Check command line arguments.
  37. if(argc != 4 && argc != 5)
  38. {
  39. std::cerr <<
  40. "Usage: http-client-sync-ssl <host> <port> <target> [<HTTP version: 1.0 or 1.1(default)>]\n" <<
  41. "Example:\n" <<
  42. " http-client-sync-ssl www.example.com 443 /\n" <<
  43. " http-client-sync-ssl www.example.com 443 / 1.0\n";
  44. return EXIT_FAILURE;
  45. }
  46. auto const host = argv[1];
  47. auto const port = argv[2];
  48. auto const target = argv[3];
  49. int version = argc == 5 && !std::strcmp("1.0", argv[4]) ? 10 : 11;
  50. // The io_context is required for all I/O
  51. net::io_context ioc;
  52. // The SSL context is required, and holds certificates
  53. ssl::context ctx(ssl::context::tlsv12_client);
  54. // This holds the root certificate used for verification
  55. load_root_certificates(ctx);
  56. // Verify the remote server's certificate
  57. ctx.set_verify_mode(ssl::verify_peer);
  58. // These objects perform our I/O
  59. tcp::resolver resolver(ioc);
  60. beast::ssl_stream<beast::tcp_stream> stream(ioc, ctx);
  61. // Set SNI Hostname (many hosts need this to handshake successfully)
  62. if(! SSL_set_tlsext_host_name(stream.native_handle(), host))
  63. {
  64. beast::error_code ec{static_cast<int>(::ERR_get_error()), net::error::get_ssl_category()};
  65. throw beast::system_error{ec};
  66. }
  67. // Look up the domain name
  68. auto const results = resolver.resolve(host, port);
  69. // Make the connection on the IP address we get from a lookup
  70. beast::get_lowest_layer(stream).connect(results);
  71. // Perform the SSL handshake
  72. stream.handshake(ssl::stream_base::client);
  73. // Set up an HTTP GET request message
  74. http::request<http::string_body> req{http::verb::get, target, version};
  75. req.set(http::field::host, host);
  76. req.set(http::field::user_agent, BOOST_BEAST_VERSION_STRING);
  77. // Send the HTTP request to the remote host
  78. http::write(stream, req);
  79. // This buffer is used for reading and must be persisted
  80. beast::flat_buffer buffer;
  81. // Declare a container to hold the response
  82. http::response<http::dynamic_body> res;
  83. // Receive the HTTP response
  84. http::read(stream, buffer, res);
  85. // Write the message to standard out
  86. std::cout << res << std::endl;
  87. // Gracefully close the stream
  88. beast::error_code ec;
  89. stream.shutdown(ec);
  90. if(ec == net::error::eof)
  91. {
  92. // Rationale:
  93. // http://stackoverflow.com/questions/25587403/boost-asio-ssl-async-shutdown-always-finishes-with-an-error
  94. ec = {};
  95. }
  96. if(ec)
  97. throw beast::system_error{ec};
  98. // If we get here then the connection is closed gracefully
  99. }
  100. catch(std::exception const& e)
  101. {
  102. std::cerr << "Error: " << e.what() << std::endl;
  103. return EXIT_FAILURE;
  104. }
  105. return EXIT_SUCCESS;
  106. }