From 292801fef7783611d90291d71ba2ff5c8039d31f Mon Sep 17 00:00:00 2001 From: Vinnie Falco Date: Sun, 29 Apr 2018 19:41:26 -0700 Subject: [PATCH] Add ssl_stream to experimental: The ssl_stream wrapper provides C++11 move semantics for ssl::stream, as well as incorporating the flat_stream workaround for a performance problem with ssl::stream writes and buffer sequences having length greater than one. --- CHANGELOG.md | 1 + doc/qbk/02_examples.qbk | 7 - doc/qbk/quickref.xml | 1 + example/advanced/server-flex/CMakeLists.txt | 1 - .../server-flex/advanced_server_flex.cpp | 16 +- .../beast/experimental/core/ssl_stream.hpp | 728 ++++++++++++++++++ test/beast/experimental/CMakeLists.txt | 1 + test/beast/experimental/Jamfile | 1 + .../experimental}/ssl_stream.cpp | 2 +- test/example/common/CMakeLists.txt | 1 - test/example/common/Jamfile | 1 - 11 files changed, 741 insertions(+), 19 deletions(-) create mode 100644 include/boost/beast/experimental/core/ssl_stream.hpp rename test/{example/common => beast/experimental}/ssl_stream.cpp (87%) diff --git a/CHANGELOG.md b/CHANGELOG.md index f86b9fac..3ddbffea 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,7 @@ Version 170: * Add flat_stream to experimental +* Add ssl_stream to experimental -------------------------------------------------------------------------------- diff --git a/doc/qbk/02_examples.qbk b/doc/qbk/02_examples.qbk index 22d0fb14..55363bd9 100644 --- a/doc/qbk/02_examples.qbk +++ b/doc/qbk/02_examples.qbk @@ -234,13 +234,6 @@ listed here along with a description of their use: Authority ("CA") so connecting to an example HTTP server using a browser may generate security warnings. ] -][ - [[source_file example/common/ssl_stream.hpp]] - [ - The `ssl_stream` is a replacement for __ssl_stream__ which - supports construction from a moved-from socket and is also - itself move constructible. - ] ]] [endsect] diff --git a/doc/qbk/quickref.xml b/doc/qbk/quickref.xml index 91c92c1a..66694d44 100644 --- a/doc/qbk/quickref.xml +++ b/doc/qbk/quickref.xml @@ -299,6 +299,7 @@ Classes flat_stream + ssl_stream diff --git a/example/advanced/server-flex/CMakeLists.txt b/example/advanced/server-flex/CMakeLists.txt index 21b5f9cb..981ce6b5 100644 --- a/example/advanced/server-flex/CMakeLists.txt +++ b/example/advanced/server-flex/CMakeLists.txt @@ -16,7 +16,6 @@ if (OPENSSL_FOUND) ${BOOST_BEAST_FILES} ${PROJECT_SOURCE_DIR}/example/common/detect_ssl.hpp ${PROJECT_SOURCE_DIR}/example/common/server_certificate.hpp - ${PROJECT_SOURCE_DIR}/example/common/ssl_stream.hpp Jamfile advanced_server_flex.cpp ) diff --git a/example/advanced/server-flex/advanced_server_flex.cpp b/example/advanced/server-flex/advanced_server_flex.cpp index c9e56a24..75637079 100644 --- a/example/advanced/server-flex/advanced_server_flex.cpp +++ b/example/advanced/server-flex/advanced_server_flex.cpp @@ -15,12 +15,12 @@ #include "example/common/detect_ssl.hpp" #include "example/common/server_certificate.hpp" -#include "example/common/ssl_stream.hpp" #include #include #include #include +#include #include #include #include @@ -545,7 +545,7 @@ class ssl_websocket_session : public websocket_session , public std::enable_shared_from_this { - websocket::stream> ws_; + websocket::stream> ws_; boost::asio::strand< boost::asio::io_context::executor_type> strand_; bool eof_ = false; @@ -553,7 +553,7 @@ class ssl_websocket_session public: // Create the http_session explicit - ssl_websocket_session(ssl_stream stream) + ssl_websocket_session(boost::beast::ssl_stream stream) : websocket_session( stream.get_executor().context()) , ws_(std::move(stream)) @@ -562,7 +562,7 @@ public: } // Called by the base class - websocket::stream>& + websocket::stream>& ws() { return ws_; @@ -640,7 +640,7 @@ make_websocket_session( template void make_websocket_session( - ssl_stream stream, + boost::beast::ssl_stream stream, http::request> req) { std::make_shared( @@ -966,7 +966,7 @@ class ssl_http_session : public http_session , public std::enable_shared_from_this { - ssl_stream stream_; + boost::beast::ssl_stream stream_; boost::asio::strand< boost::asio::io_context::executor_type> strand_; bool eof_ = false; @@ -988,14 +988,14 @@ public: } // Called by the base class - ssl_stream& + boost::beast::ssl_stream& stream() { return stream_; } // Called by the base class - ssl_stream + boost::beast::ssl_stream release_stream() { return std::move(stream_); diff --git a/include/boost/beast/experimental/core/ssl_stream.hpp b/include/boost/beast/experimental/core/ssl_stream.hpp new file mode 100644 index 00000000..bc234c42 --- /dev/null +++ b/include/boost/beast/experimental/core/ssl_stream.hpp @@ -0,0 +1,728 @@ +// +// Copyright (c) 2016-2017 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) +// +// Official repository: https://github.com/boostorg/beast +// + +#ifndef BOOST_BEAST_CORE_SSL_STREAM_HPP +#define BOOST_BEAST_CORE_SSL_STREAM_HPP + +// This include is necessary to work with `ssl::stream` and `boost::beast::websocket::stream` +#include + +#include +#include +#include +#include +#include +#include + +namespace boost { +namespace beast { + +/** Provides stream-oriented functionality using OpenSSL + + The stream class template provides asynchronous and blocking + stream-oriented functionality using SSL. + + @par Thread Safety + @e Distinct @e objects: Safe.@n + @e Shared @e objects: Unsafe. The application must also ensure that all + asynchronous operations are performed within the same implicit or explicit + strand. + + @par Example + To use this template with a `boost::asio::ip::tcp::socket`, you would write: + @code + boost::asio::io_context ioc; + boost::asio::ssl::context ctx{boost::asio::ssl::context::sslv23}; + boost::beast::ssl_stream sock{ioc, ctx}; + @endcode + + In addition to providing an interface identical to `boost::asio::ssl::stream`, + the wrapper has the following additional properties: + + @li Satisfies @b MoveConstructible + + @li Satisfies @b MoveAssignable + + @li Constructible from a moved socket. + + @li Uses @ref flat_stream internally, as a performance work-around for a + limitation of `boost::asio::ssl::stream` when writing buffer sequences + having length greater than one. + + @par Concepts: + @li AsyncReadStream + @li AsyncWriteStream + @li Stream + @li SyncReadStream + @li SyncWriteStream +*/ +template +class ssl_stream + : public boost::asio::ssl::stream_base +{ + using ssl_stream_type = boost::asio::ssl::stream; + using stream_type = boost::beast::flat_stream; + + std::unique_ptr p_; + boost::asio::ssl::context* ctx_; + +public: + /// The native handle type of the SSL stream. + using native_handle_type = + typename ssl_stream_type::native_handle_type; + + /// Structure for use with deprecated impl_type. + using impl_struct = typename ssl_stream_type::impl_struct; + + /// The type of the next layer. + using next_layer_type = typename ssl_stream_type::next_layer_type; + + /// The type of the lowest layer. + using lowest_layer_type = typename ssl_stream_type::lowest_layer_type; + + /// The type of the executor associated with the object. + using executor_type = typename stream_type::executor_type; + + /** Construct a stream. + + This constructor creates a stream and initialises the underlying stream + object. + + @param arg The argument to be passed to initialise the underlying stream. + + @param ctx The SSL context to be used for the stream. + */ + template + ssl_stream( + Arg&& arg, + boost::asio::ssl::context& ctx) + : p_(new stream_type{ + std::forward(arg), ctx}) + , ctx_(&ctx) + { + } + + /// Move Constructor + ssl_stream(ssl_stream&& other) + : p_(std::move(other.p_)) + , ctx_(other.ctx_) + { + } + + /// Move Assignment + ssl_stream& operator=(ssl_stream&& other) + { + p_ = std::move(other.p_); + ctx_ = other.ctx_; + return *this; + } + + /** Get the executor associated with the object. + + This function may be used to obtain the executor object that the stream + uses to dispatch handlers for asynchronous operations. + + @return A copy of the executor that stream will use to dispatch handlers. + */ + executor_type + get_executor() noexcept + { + return p_->get_executor(); + } + + /** Get the underlying implementation in the native type. + + This function may be used to obtain the underlying implementation of the + context. This is intended to allow access to context functionality that is + not otherwise provided. + + @par Example + The native_handle() function returns a pointer of type @c SSL* that is + suitable for passing to functions such as @c SSL_get_verify_result and + @c SSL_get_peer_certificate: + @code + boost::beast::ssl_stream ss{ioc, ctx}; + + // ... establish connection and perform handshake ... + + if (X509* cert = SSL_get_peer_certificate(ss.native_handle())) + { + if (SSL_get_verify_result(ss.native_handle()) == X509_V_OK) + { + // ... + } + } + @endcode + */ + native_handle_type + native_handle() + { + return p_->next_layer().native_handle(); + } + + /** Get a reference to the next layer. + + This function returns a reference to the next layer in a stack of stream + layers. + + @note The next layer is the wrapped stream and not the @ref flat_stream + used in the implementation. + + @return A reference to the next layer in the stack of stream layers. + Ownership is not transferred to the caller. + */ + next_layer_type const& + next_layer() const + { + return p_->next_layer().next_layer(); + } + + /** Get a reference to the next layer. + + This function returns a reference to the next layer in a stack of stream + layers. + + @note The next layer is the wrapped stream and not the @ref flat_stream + used in the implementation. + + @return A reference to the next layer in the stack of stream layers. + Ownership is not transferred to the caller. + */ + next_layer_type& + next_layer() + { + return p_->next_layer().next_layer(); + } + + /** Get a reference to the lowest layer. + + This function returns a reference to the lowest layer in a stack of stream + layers. + + @return A reference to the lowest layer in the stack of stream layers. + Ownership is not transferred to the caller. + */ + lowest_layer_type& + lowest_layer() + { + return p_->lowest_layer(); + } + + /** Get a reference to the lowest layer. + + This function returns a reference to the lowest layer in a stack of stream + layers. + + @return A reference to the lowest layer in the stack of stream layers. + Ownership is not transferred to the caller. + */ + lowest_layer_type const& + lowest_layer() const + { + return p_->lowest_layer(); + } + + /** Set the peer verification mode. + + This function may be used to configure the peer verification mode used by + the stream. The new mode will override the mode inherited from the context. + + @param v A bitmask of peer verification modes. + + @throws boost::system::system_error Thrown on failure. + + @note Calls @c SSL_set_verify. + */ + void + set_verify_mode(boost::asio::ssl::verify_mode v) + { + p_->next_layer().set_verify_mode(v); + } + + /** Set the peer verification mode. + + This function may be used to configure the peer verification mode used by + the stream. The new mode will override the mode inherited from the context. + + @param v A bitmask of peer verification modes. See @ref verify_mode for + available values. + + @param ec Set to indicate what error occurred, if any. + + @note Calls @c SSL_set_verify. + */ + boost::system::error_code + set_verify_mode(boost::asio::ssl::verify_mode v, + boost::system::error_code& ec) + { + return p_->next_layer().set_verify_mode(v, ec); + } + + /** Set the peer verification depth. + + This function may be used to configure the maximum verification depth + allowed by the stream. + + @param depth Maximum depth for the certificate chain verification that + shall be allowed. + + @throws boost::system::system_error Thrown on failure. + + @note Calls @c SSL_set_verify_depth. + */ + void + set_verify_depth(int depth) + { + p_->next_layer().set_verify_depth(depth); + } + + /** Set the peer verification depth. + + This function may be used to configure the maximum verification depth + allowed by the stream. + + @param depth Maximum depth for the certificate chain verification that + shall be allowed. + + @param ec Set to indicate what error occurred, if any. + + @note Calls @c SSL_set_verify_depth. + */ + boost::system::error_code + set_verify_depth( + int depth, boost::system::error_code& ec) + { + return p_->next_layer().set_verify_depth(depth, ec); + } + + /** Set the callback used to verify peer certificates. + + This function is used to specify a callback function that will be called + by the implementation when it needs to verify a peer certificate. + + @param callback The function object to be used for verifying a certificate. + The function signature of the handler must be: + @code bool verify_callback( + bool preverified, // True if the certificate passed pre-verification. + verify_context& ctx // The peer certificate and other context. + ); @endcode + The return value of the callback is true if the certificate has passed + verification, false otherwise. + + @throws boost::system::system_error Thrown on failure. + + @note Calls @c SSL_set_verify. + */ + template + void + set_verify_callback(VerifyCallback callback) + { + p_->next_layer().set_verify_callback(callback); + } + + /** Set the callback used to verify peer certificates. + + This function is used to specify a callback function that will be called + by the implementation when it needs to verify a peer certificate. + + @param callback The function object to be used for verifying a certificate. + The function signature of the handler must be: + @code bool verify_callback( + bool preverified, // True if the certificate passed pre-verification. + boost::asio::verify_context& ctx // The peer certificate and other context. + ); @endcode + The return value of the callback is true if the certificate has passed + verification, false otherwise. + + @param ec Set to indicate what error occurred, if any. + + @note Calls @c SSL_set_verify. + */ + template + boost::system::error_code + set_verify_callback(VerifyCallback callback, + boost::system::error_code& ec) + { + return p_->next_layer().set_verify_callback(callback, ec); + } + + /** Perform SSL handshaking. + + This function is used to perform SSL handshaking on the stream. The + function call will block until handshaking is complete or an error occurs. + + @param type The type of handshaking to be performed, i.e. as a client or as + a server. + + @throws boost::system::system_error Thrown on failure. + */ + void + handshake(handshake_type type) + { + p_->next_layer().handshake(type); + } + + /** Perform SSL handshaking. + + This function is used to perform SSL handshaking on the stream. The + function call will block until handshaking is complete or an error occurs. + + @param type The type of handshaking to be performed, i.e. as a client or as + a server. + + @param ec Set to indicate what error occurred, if any. + */ + boost::system::error_code + handshake(handshake_type type, + boost::system::error_code& ec) + { + return p_->next_layer().handshake(type, ec); + } + + /** Perform SSL handshaking. + + This function is used to perform SSL handshaking on the stream. The + function call will block until handshaking is complete or an error occurs. + + @param type The type of handshaking to be performed, i.e. as a client or as + a server. + + @param buffers The buffered data to be reused for the handshake. + + @throws boost::system::system_error Thrown on failure. + */ + template + void + handshake( + handshake_type type, ConstBufferSequence const& buffers) + { + p_->next_layer().handshake(type, buffers); + } + + /** Perform SSL handshaking. + + This function is used to perform SSL handshaking on the stream. The + function call will block until handshaking is complete or an error occurs. + + @param type The type of handshaking to be performed, i.e. as a client or as + a server. + + @param buffers The buffered data to be reused for the handshake. + + @param ec Set to indicate what error occurred, if any. + */ + template + boost::system::error_code + handshake(handshake_type type, + ConstBufferSequence const& buffers, + boost::system::error_code& ec) + { + return p_->next_layer().handshake(type, buffers, ec); + } + + /** Start an asynchronous SSL handshake. + + This function is used to asynchronously perform an SSL handshake on the + stream. This function call always returns immediately. + + @param type The type of handshaking to be performed, i.e. as a client or as + a server. + + @param handler The handler to be called when the handshake operation + completes. Copies will be made of the handler as required. The equivalent + function signature of the handler must be: + @code void handler( + const boost::system::error_code& error // Result of operation. + ); @endcode + */ + template + BOOST_ASIO_INITFN_RESULT_TYPE(HandshakeHandler, + void(boost::system::error_code)) + async_handshake(handshake_type type, + BOOST_ASIO_MOVE_ARG(HandshakeHandler) handler) + { + return p_->next_layer().async_handshake(type, + BOOST_ASIO_MOVE_CAST(HandshakeHandler)(handler)); + } + + /** Start an asynchronous SSL handshake. + + This function is used to asynchronously perform an SSL handshake on the + stream. This function call always returns immediately. + + @param type The type of handshaking to be performed, i.e. as a client or as + a server. + + @param buffers The buffered data to be reused for the handshake. Although + the buffers object may be copied as necessary, ownership of the underlying + buffers is retained by the caller, which must guarantee that they remain + valid until the handler is called. + + @param handler The handler to be called when the handshake operation + completes. Copies will be made of the handler as required. The equivalent + function signature of the handler must be: + @code void handler( + const boost::system::error_code& error, // Result of operation. + std::size_t bytes_transferred // Amount of buffers used in handshake. + ); @endcode + */ + template + BOOST_ASIO_INITFN_RESULT_TYPE(BufferedHandshakeHandler, + void (boost::system::error_code, std::size_t)) + async_handshake(handshake_type type, ConstBufferSequence const& buffers, + BOOST_ASIO_MOVE_ARG(BufferedHandshakeHandler) handler) + { + return p_->next_layer().async_handshake(type, buffers, + BOOST_ASIO_MOVE_CAST(BufferedHandshakeHandler)(handler)); + } + + /** Shut down SSL on the stream. + + This function is used to shut down SSL on the stream. The function call + will block until SSL has been shut down or an error occurs. + + @throws boost::system::system_error Thrown on failure. + */ + void + shutdown() + { + p_->next_layer().shutdown(); + } + + /** Shut down SSL on the stream. + + This function is used to shut down SSL on the stream. The function call + will block until SSL has been shut down or an error occurs. + + @param ec Set to indicate what error occurred, if any. + */ + boost::system::error_code + shutdown(boost::system::error_code& ec) + { + return p_->next_layer().shutdown(ec); + } + + /** Asynchronously shut down SSL on the stream. + + This function is used to asynchronously shut down SSL on the stream. This + function call always returns immediately. + + @param handler The handler to be called when the handshake operation + completes. Copies will be made of the handler as required. The equivalent + function signature of the handler must be: + @code void handler( + const boost::system::error_code& error // Result of operation. + ); @endcode + */ + template + BOOST_ASIO_INITFN_RESULT_TYPE(ShutdownHandler, + void (boost::system::error_code)) + async_shutdown(BOOST_ASIO_MOVE_ARG(ShutdownHandler) handler) + { + return p_->next_layer().async_shutdown( + BOOST_ASIO_MOVE_CAST(ShutdownHandler)(handler)); + } + + /** Write some data to the stream. + + This function is used to write data on the stream. The function call will + block until one or more bytes of data has been written successfully, or + until an error occurs. + + @param buffers The data to be written. + + @returns The number of bytes written. + + @throws boost::system::system_error Thrown on failure. + + @note The `write_some` operation may not transmit all of the data to the + peer. Consider using the `boost::asio::write` function if you need to + ensure that all data is written before the blocking operation completes. + */ + template + std::size_t + write_some(ConstBufferSequence const& buffers) + { + return p_->write_some(buffers); + } + + /** Write some data to the stream. + + This function is used to write data on the stream. The function call will + block until one or more bytes of data has been written successfully, or + until an error occurs. + + @param buffers The data to be written to the stream. + + @param ec Set to indicate what error occurred, if any. + + @returns The number of bytes written. Returns 0 if an error occurred. + + @note The `write_some` operation may not transmit all of the data to the + peer. Consider using the `boost::asio::write` function if you need to + ensure that all data is written before the blocking operation completes. + */ + template + std::size_t + write_some(ConstBufferSequence const& buffers, + boost::system::error_code& ec) + { + return p_->write_some(buffers, ec); + } + + /** Start an asynchronous write. + + This function is used to asynchronously write one or more bytes of data to + the stream. The function call always returns immediately. + + @param buffers The data to be written to the stream. Although the buffers + object may be copied as necessary, ownership of the underlying buffers is + retained by the caller, which must guarantee that they remain valid until + the handler is called. + + @param handler The handler to be called when the write operation completes. + Copies will be made of the handler as required. The equivalent function + signature of the handler must be: + @code void handler( + const boost::system::error_code& error, // Result of operation. + std::size_t bytes_transferred // Number of bytes written. + ); @endcode + + @note The `async_write_some` operation may not transmit all of the data to + the peer. Consider using the `boost::asio::async_write` function if you + need to ensure that all data is written before the asynchronous operation + completes. + */ + template + BOOST_ASIO_INITFN_RESULT_TYPE(WriteHandler, + void (boost::system::error_code, std::size_t)) + async_write_some(ConstBufferSequence const& buffers, + BOOST_ASIO_MOVE_ARG(WriteHandler) handler) + { + return p_->async_write_some(buffers, + BOOST_ASIO_MOVE_CAST(WriteHandler)(handler)); + } + + /** Read some data from the stream. + + This function is used to read data from the stream. The function call will + block until one or more bytes of data has been read successfully, or until + an error occurs. + + @param buffers The buffers into which the data will be read. + + @returns The number of bytes read. + + @throws boost::system::system_error Thrown on failure. + + @note The `read_some` operation may not read all of the requested number of + bytes. Consider using the `boost::asio::read` function if you need to ensure + that the requested amount of data is read before the blocking operation + completes. + */ + template + std::size_t + read_some(MutableBufferSequence const& buffers) + { + return p_->read_some(buffers); + } + + /** Read some data from the stream. + + This function is used to read data from the stream. The function call will + block until one or more bytes of data has been read successfully, or until + an error occurs. + + @param buffers The buffers into which the data will be read. + + @param ec Set to indicate what error occurred, if any. + + @returns The number of bytes read. Returns 0 if an error occurred. + + @note The `read_some` operation may not read all of the requested number of + bytes. Consider using the `boost::asio::read` function if you need to ensure + that the requested amount of data is read before the blocking operation + completes. + */ + template + std::size_t + read_some(MutableBufferSequence const& buffers, + boost::system::error_code& ec) + { + return p_->read_some(buffers, ec); + } + + /** Start an asynchronous read. + + This function is used to asynchronously read one or more bytes of data from + the stream. The function call always returns immediately. + + @param buffers The buffers into which the data will be read. Although the + buffers object may be copied as necessary, ownership of the underlying + buffers is retained by the caller, which must guarantee that they remain + valid until the handler is called. + + @param handler The handler to be called when the read operation completes. + Copies will be made of the handler as required. The equivalent function + signature of the handler must be: + @code void handler( + const boost::system::error_code& error, // Result of operation. + std::size_t bytes_transferred // Number of bytes read. + ); @endcode + + @note The `async_read_some` operation may not read all of the requested + number of bytes. Consider using the `boost::asio::async_read` function + if you need to ensure that the requested amount of data is read before + the asynchronous operation completes. + */ + template + BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, + void(boost::system::error_code, std::size_t)) + async_read_some(MutableBufferSequence const& buffers, + BOOST_ASIO_MOVE_ARG(ReadHandler) handler) + { + return p_->async_read_some(buffers, + BOOST_ASIO_MOVE_CAST(ReadHandler)(handler)); + } +}; + +// These hooks are used to inform boost::beast::websocket::stream on +// how to tear down the connection as part of the WebSocket +// protocol specifications +#if ! BOOST_BEAST_DOXYGEN +template +void +teardown( + boost::beast::websocket::role_type role, + ssl_stream& stream, + boost::system::error_code& ec) +{ + // Just forward it to the wrapped stream + using boost::beast::websocket::teardown; + teardown(role, stream.next_layer(), ec); +} + +template +void +async_teardown( + boost::beast::websocket::role_type role, + ssl_stream& stream, + TeardownHandler&& handler) +{ + // Just forward it to the wrapped stream + using boost::beast::websocket::async_teardown; + async_teardown(role, + stream.next_layer(), std::forward(handler)); +} +#endif + +} // beast +} // boost + +#endif diff --git a/test/beast/experimental/CMakeLists.txt b/test/beast/experimental/CMakeLists.txt index ff0765aa..8180577a 100644 --- a/test/beast/experimental/CMakeLists.txt +++ b/test/beast/experimental/CMakeLists.txt @@ -18,6 +18,7 @@ add_executable (tests-beast-experimental ${TEST_MAIN} Jamfile flat_stream.cpp + ssl_stream.cpp ) set_property(TARGET tests-beast-experimental PROPERTY FOLDER "tests") diff --git a/test/beast/experimental/Jamfile b/test/beast/experimental/Jamfile index c7ecbd7b..849265f5 100644 --- a/test/beast/experimental/Jamfile +++ b/test/beast/experimental/Jamfile @@ -9,6 +9,7 @@ local SOURCES = flat_stream.cpp + ssl_stream.cpp ; local RUN_TESTS ; diff --git a/test/example/common/ssl_stream.cpp b/test/beast/experimental/ssl_stream.cpp similarity index 87% rename from test/example/common/ssl_stream.cpp rename to test/beast/experimental/ssl_stream.cpp index 75044048..4286539b 100644 --- a/test/example/common/ssl_stream.cpp +++ b/test/beast/experimental/ssl_stream.cpp @@ -10,6 +10,6 @@ #if BOOST_BEAST_USE_OPENSSL // Test that header file is self-contained. -#include "example/common/ssl_stream.hpp" +#include #endif diff --git a/test/example/common/CMakeLists.txt b/test/example/common/CMakeLists.txt index f020d313..7b320f08 100644 --- a/test/example/common/CMakeLists.txt +++ b/test/example/common/CMakeLists.txt @@ -23,7 +23,6 @@ add_executable (tests-example-common root_certificates.cpp server_certificate.cpp session_alloc.cpp - ssl_stream.cpp ) set_property(TARGET tests-example-common PROPERTY FOLDER "tests") \ No newline at end of file diff --git a/test/example/common/Jamfile b/test/example/common/Jamfile index 719deba0..76ba448e 100644 --- a/test/example/common/Jamfile +++ b/test/example/common/Jamfile @@ -12,7 +12,6 @@ local SOURCES = root_certificates.cpp server_certificate.cpp session_alloc.cpp - ssl_stream.cpp ; local RUN_TESTS ;