From 2ad5223d80b628f5fa7e4b96d70c17dd06a77aed Mon Sep 17 00:00:00 2001 From: Vinnie Falco Date: Sun, 2 Oct 2016 16:33:42 -0400 Subject: [PATCH] Add HTTPS example --- CHANGELOG.md | 1 + CMakeLists.txt | 16 +++++++++ Jamroot | 5 +-- doc/Jamfile.v2 | 7 +++- doc/examples.qbk | 7 ++++ examples/{Jamfile => Jamfile.v2} | 3 -- examples/ssl/CMakeLists.txt | 32 +++++++++++++++++ examples/ssl/Jamfile.v2 | 49 ++++++++++++++++++++++++++ examples/ssl/http_ssl_example.cpp | 57 +++++++++++++++++++++++++++++++ 9 files changed, 169 insertions(+), 8 deletions(-) rename examples/{Jamfile => Jamfile.v2} (96%) create mode 100644 examples/ssl/CMakeLists.txt create mode 100644 examples/ssl/Jamfile.v2 create mode 100644 examples/ssl/http_ssl_example.cpp diff --git a/CHANGELOG.md b/CHANGELOG.md index f542a58d..6924273f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,7 @@ 1.0.0-b15 * rfc7230 section 3.3.2 compliance +* Add HTTPS example -------------------------------------------------------------------------------- diff --git a/CMakeLists.txt b/CMakeLists.txt index 0a237cfa..3b390bb0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -23,6 +23,17 @@ else() "${CMAKE_CXX_FLAGS} -std=c++11 -Wall -Wpedantic") endif() +if (APPLE AND NOT DEFINED ENV{OPENSSL_ROOT_DIR}) + find_program(HOMEBREW brew) + if (NOT HOMEBREW STREQUAL "HOMEBREW-NOTFOUND") + execute_process(COMMAND brew --prefix openssl + OUTPUT_VARIABLE OPENSSL_ROOT_DIR + OUTPUT_STRIP_TRAILING_WHITESPACE) + endif() +endif() + +find_package(OpenSSL) + if (MINGW) link_libraries(${Boost_LIBRARIES} ws2_32 mswsock) endif() @@ -82,6 +93,11 @@ file(GLOB_RECURSE EXTRAS_INCLUDES ) add_subdirectory (examples) +if (NOT OPENSSL_FOUND) + message("OpenSSL not found. Not building examples/ssl") +else() + add_subdirectory (examples/ssl) +endif() add_subdirectory (test) add_subdirectory (test/core) add_subdirectory (test/http) diff --git a/Jamroot b/Jamroot index 78951028..fca729e8 100644 --- a/Jamroot +++ b/Jamroot @@ -37,7 +37,7 @@ else if [ os.name ] = HAIKU if [ os.name ] = NT { lib ssl : : ssleay32 ; - lib crypto : : libeay32 ; + lib crypto : : libeay32 ; } else { @@ -87,12 +87,9 @@ project beast /boost/coroutine//boost_coroutine /boost/filesystem//boost_filesystem /boost/program_options//boost_program_options -# ssl -# crypto BOOST_ALL_NO_LIB=1 BOOST_SYSTEM_NO_DEPRECATED=1 multi - static shared on gcc:-std=c++11 diff --git a/doc/Jamfile.v2 b/doc/Jamfile.v2 index b4eddb01..8e78d6cd 100644 --- a/doc/Jamfile.v2 +++ b/doc/Jamfile.v2 @@ -51,7 +51,12 @@ explicit callout ; install examples : - [ glob ../examples/*.* ] + [ glob + ../examples/*.cpp + ../examples/*.hpp + ../examples/ssl/*.cpp + ../examples/ssl/*.hpp + ] : $(here)/html/examples ; diff --git a/doc/examples.qbk b/doc/examples.qbk index d06f40e4..a78fbe3d 100644 --- a/doc/examples.qbk +++ b/doc/examples.qbk @@ -83,6 +83,13 @@ int main() } ``` +[heading HTTPS GET] + +This example demonstrates sending and receiving HTTP messages +over a TLS connection. Requires OpenSSL to build. + +* [@examples/http_ssl_example.cpp] + [heading HTTP Crawl] This example retrieves the page at each of the most popular domains diff --git a/examples/Jamfile b/examples/Jamfile.v2 similarity index 96% rename from examples/Jamfile rename to examples/Jamfile.v2 index f9936fe8..2dd0427b 100644 --- a/examples/Jamfile +++ b/examples/Jamfile.v2 @@ -5,8 +5,6 @@ # file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) # -import os ; - exe http-crawl : http_crawl.cpp urls_large_data.cpp @@ -23,4 +21,3 @@ exe http-example : exe websocket-example : websocket_example.cpp ; - diff --git a/examples/ssl/CMakeLists.txt b/examples/ssl/CMakeLists.txt new file mode 100644 index 00000000..df35e5f3 --- /dev/null +++ b/examples/ssl/CMakeLists.txt @@ -0,0 +1,32 @@ +# Part of Beast + +GroupSources(extras/beast extras) +GroupSources(include/beast beast) + +GroupSources(examples/ssl "/") + +include_directories(${OPENSSL_INCLUDE_DIR}) + +add_executable (http-ssl-example + ${BEAST_INCLUDES} + ${EXTRAS_INCLUDES} + http_ssl_example.cpp +) + +target_link_libraries(http-ssl-example ${OPENSSL_LIBRARIES}) + +if (NOT WIN32) + target_link_libraries(http-ssl-example ${Boost_LIBRARIES} Threads::Threads) +endif() + +add_executable (websocket-ssl-example + ${BEAST_INCLUDES} + ${EXTRAS_INCLUDES} + websocket_ssl_example.cpp +) + +target_link_libraries(websocket-ssl-example ${OPENSSL_LIBRARIES}) + +if (NOT WIN32) + target_link_libraries(websocket-ssl-example ${Boost_LIBRARIES} Threads::Threads) +endif() diff --git a/examples/ssl/Jamfile.v2 b/examples/ssl/Jamfile.v2 new file mode 100644 index 00000000..ecd6eda1 --- /dev/null +++ b/examples/ssl/Jamfile.v2 @@ -0,0 +1,49 @@ +# +# Copyright (c) 2013-2016 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) +# + +import os ; + +if [ os.name ] = SOLARIS +{ + lib socket ; + lib nsl ; +} +else if [ os.name ] = NT +{ + lib ws2_32 ; + lib mswsock ; +} +else if [ os.name ] = HPUX +{ + lib ipv6 ; +} +else if [ os.name ] = HAIKU +{ + lib network ; +} + +if [ os.name ] = NT +{ + lib ssl : : ssleay32 ; + lib crypto : : libeay32 ; +} +else +{ + lib ssl ; + lib crypto ; +} + +project + : requirements + ssl + crypto + ; + +exe http-ssl-example + : + http_ssl_example.cpp + ; diff --git a/examples/ssl/http_ssl_example.cpp b/examples/ssl/http_ssl_example.cpp new file mode 100644 index 00000000..e485a34b --- /dev/null +++ b/examples/ssl/http_ssl_example.cpp @@ -0,0 +1,57 @@ +// +// Copyright (c) 2013-2016 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 +#include +#include +#include +#include + +int main() +{ + using boost::asio::connect; + using socket = boost::asio::ip::tcp::socket; + using resolver = boost::asio::ip::tcp::resolver; + using io_service = boost::asio::io_service; + namespace ssl = boost::asio::ssl; + + // Normal boost::asio setup + std::string const host = "github.com"; + io_service ios; + resolver r{ios}; + socket sock{ios}; + connect(sock, r.resolve(resolver::query{host, "https"})); + + // Perform SSL handshaking + ssl::context ctx{ssl::context::sslv23}; + ssl::stream stream{sock, ctx}; + stream.set_verify_mode(ssl::verify_none); + stream.handshake(ssl::stream_base::client); + + // Send HTTP request over SSL using Beast + beast::http::request_v1 req; + req.method = "GET"; + req.url = "/"; + req.version = 11; + req.headers.insert("Host", host + ":" + + std::to_string(sock.remote_endpoint().port())); + req.headers.insert("User-Agent", "Beast"); + beast::http::prepare(req); + beast::http::write(stream, req); + + // Receive and print HTTP response using Beast + beast::streambuf sb; + beast::http::response_v1 resp; + beast::http::read(stream, sb, resp); + std::cout << resp; + + // Shut down SSL on the stream + boost::system::error_code ec; + stream.shutdown(ec); + if(ec && ec != boost::asio::error::eof) + std::cout << "error: " << ec.message(); +}