Misc changes related to translation of asio transport errors #448
This commit is contained in:
1 parent
f9dbc0fd9d
commit
fb829e0895
10 files changed
+184
-26
No files matched your search
+16
-7
@@ -1,13 +1,22 @@
|
||||
HEAD
|
||||
- Feature: Basic support for the permessage-deflate extension. #344
|
||||
- Improvement: Better automatic std::chrono feature detection for Visual Studio
|
||||
- Improvement: Major refactoring to bundled CMake build system. CMake can now be used to
|
||||
build all of the examples and the test suite. Thank you Thijs Wenker for a significant
|
||||
portion of this code. #378, #435, #449
|
||||
- Bug: Fix memory leak when init_asio produces an error. #454 Thank you Mark Grimes for
|
||||
reporting and fixing.
|
||||
- Bug: Fix crash when processing a specially crafted HTTP header. Thank you Eli Fidler for
|
||||
reporting, test cases, and a patch. #456
|
||||
- Improvement: Major refactoring to bundled CMake build system. CMake can now be
|
||||
used to build all of the examples and the test suite. Thank you Thijs Wenker
|
||||
for a significant portion of this code. #378, #435, #449
|
||||
- Improvement: In build environments where `lib::error_code` and
|
||||
`lib::asio::error_code` match (such as using `boost::asio` with
|
||||
`boost::system_error` or standalone asio with `std::system_error`, transport
|
||||
errors are passed through natively rather than being reported as a translated
|
||||
`pass_through` error type.
|
||||
- Improvement: Add a `get_transport_error` method to Asio transport connections
|
||||
to allow retrieving a machine readable native transport error.
|
||||
- Bug: Fix memory leak when init_asio produces an error. #454 Thank you Mark
|
||||
Grimes for reporting and fixing.
|
||||
- Bug: Fix crash when processing a specially crafted HTTP header. Thank you Eli
|
||||
Fidler for reporting, test cases, and a patch. #456
|
||||
- Bug: Fix an issue where standalone Asio builds that use TLS would not compile
|
||||
due to lingering boost code. #448 Thank you mjsp for reporting
|
||||
|
||||
0.6.0
|
||||
- MINOR BREAKING TRANSPORT POLICY CHANGE: Custom transport policies will now be
|
||||
|
||||
@@ -20,6 +20,16 @@ link_openssl()
|
||||
final_target ()
|
||||
set_target_properties(${TARGET_NAME} PROPERTIES FOLDER "test")
|
||||
|
||||
# Test transport asio security
|
||||
file (GLOB SOURCE asio/security.cpp)
|
||||
|
||||
init_target (test_transport_asio_security)
|
||||
build_executable (${TARGET_NAME} ${SOURCE})
|
||||
link_boost ()
|
||||
link_openssl()
|
||||
final_target ()
|
||||
set_target_properties(${TARGET_NAME} PROPERTIES FOLDER "test")
|
||||
|
||||
endif()
|
||||
|
||||
# Test transport iostream base
|
||||
|
||||
@@ -15,14 +15,18 @@ BOOST_LIBS = boostlibs(['unit_test_framework','system','thread','chrono'],env) +
|
||||
|
||||
objs = env.Object('base_boost.o', ["base.cpp"], LIBS = BOOST_LIBS)
|
||||
objs += env.Object('timers_boost.o', ["timers.cpp"], LIBS = BOOST_LIBS)
|
||||
objs += env.Object('security_boost.o', ["security.cpp"], LIBS = BOOST_LIBS)
|
||||
prgs = env.Program('test_base_boost', ["base_boost.o"], LIBS = BOOST_LIBS)
|
||||
prgs += env.Program('test_timers_boost', ["timers_boost.o"], LIBS = BOOST_LIBS)
|
||||
prgs += env.Program('test_security_boost', ["security_boost.o"], LIBS = BOOST_LIBS)
|
||||
|
||||
if env_cpp11.has_key('WSPP_CPP11_ENABLED'):
|
||||
BOOST_LIBS_CPP11 = boostlibs(['unit_test_framework','system'],env_cpp11) + [platform_libs] + [polyfill_libs] + [tls_libs]
|
||||
objs += env_cpp11.Object('base_stl.o', ["base.cpp"], LIBS = BOOST_LIBS_CPP11)
|
||||
objs += env_cpp11.Object('timers_stl.o', ["timers.cpp"], LIBS = BOOST_LIBS_CPP11)
|
||||
objs += env_cpp11.Object('security_stl.o', ["security.cpp"], LIBS = BOOST_LIBS_CPP11)
|
||||
prgs += env_cpp11.Program('test_base_stl', ["base_stl.o"], LIBS = BOOST_LIBS_CPP11)
|
||||
prgs += env_cpp11.Program('test_timers_stl', ["timers_stl.o"], LIBS = BOOST_LIBS_CPP11)
|
||||
prgs += env_cpp11.Program('test_security_stl', ["security_stl.o"], LIBS = BOOST_LIBS_CPP11)
|
||||
|
||||
Return('prgs')
|
||||
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* Copyright (c) 2015, Peter Thorson. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the WebSocket++ Project nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
//#define BOOST_TEST_DYN_LINK
|
||||
#define BOOST_TEST_MODULE transport_asio_base
|
||||
#include <boost/test/unit_test.hpp>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include <websocketpp/common/type_traits.hpp>
|
||||
|
||||
#include <websocketpp/transport/asio/security/none.hpp>
|
||||
#include <websocketpp/transport/asio/security/tls.hpp>
|
||||
|
||||
template <typename base>
|
||||
struct dummy_con : public base {
|
||||
websocketpp::lib::error_code test() {
|
||||
return this->translate_ec(websocketpp::lib::asio::error_code());
|
||||
}
|
||||
};
|
||||
|
||||
BOOST_AUTO_TEST_CASE( translated_ec_none ) {
|
||||
dummy_con<websocketpp::transport::asio::basic_socket::connection> tscon;
|
||||
|
||||
// If the current configuration settings result in the library error type and the asio
|
||||
// error type being the same, then the code should pass through natively. Otherwise
|
||||
// we should get a generic pass through error.
|
||||
if(websocketpp::lib::is_same<websocketpp::lib::error_code,websocketpp::lib::asio::error_code>::value) {
|
||||
BOOST_CHECK_EQUAL( tscon.test(), websocketpp::lib::error_code() );
|
||||
} else {
|
||||
BOOST_CHECK_EQUAL( tscon.test(), websocketpp::transport::error::make_error_code(websocketpp::transport::error::pass_through) );
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( translated_ec_tls ) {
|
||||
dummy_con<websocketpp::transport::asio::tls_socket::connection> tscon;
|
||||
|
||||
// If the current configuration settings result in the library error type and the asio
|
||||
// error type being the same, then the code should pass through natively. Otherwise
|
||||
// we should get a generic pass through error.
|
||||
if(websocketpp::lib::is_same<websocketpp::lib::error_code,websocketpp::lib::asio::error_code>::value) {
|
||||
BOOST_CHECK_EQUAL( tscon.test(), websocketpp::lib::error_code() );
|
||||
} else {
|
||||
BOOST_CHECK_EQUAL( tscon.test(), websocketpp::transport::error::make_error_code(websocketpp::transport::error::pass_through) );
|
||||
}
|
||||
}
|
||||
@@ -53,8 +53,10 @@ namespace lib {
|
||||
|
||||
#ifdef _WEBSOCKETPP_CPP11_TYPE_TRAITS_
|
||||
using std::aligned_storage;
|
||||
using std::is_same;
|
||||
#else
|
||||
using boost::aligned_storage;
|
||||
using boost::is_same;
|
||||
#endif
|
||||
|
||||
} // namespace lib
|
||||
|
||||
@@ -142,9 +142,6 @@ inline custom_alloc_handler<Handler> make_custom_alloc_handler(
|
||||
template <typename config>
|
||||
class endpoint;
|
||||
|
||||
typedef lib::function<void(lib::asio::error_code const &)>
|
||||
socket_shutdown_handler;
|
||||
|
||||
typedef lib::function<void (lib::asio::error_code const & ec,
|
||||
size_t bytes_transferred)> async_read_handler;
|
||||
|
||||
|
||||
@@ -366,6 +366,29 @@ public:
|
||||
return m_strand;
|
||||
}
|
||||
|
||||
/// Get the internal transport error code for a closed/failed connection
|
||||
/**
|
||||
* Retrieves a machine readable detailed error code indicating the reason
|
||||
* that the connection was closed or failed. Valid only after the close or
|
||||
* fail handler is called.
|
||||
*
|
||||
* Primarily used if you are using mismatched asio / system_error
|
||||
* implementations such as `boost::asio` with `std::system_error`. In these
|
||||
* cases the transport error type is different than the library error type
|
||||
* and some WebSocket++ functions that return transport errors via the
|
||||
* library error code type will be coerced into a catch all `pass_through`
|
||||
* or `tls_error` error. This method will return the original machine
|
||||
* readable transport error in the native type.
|
||||
*
|
||||
* @since 0.7.0
|
||||
*
|
||||
* @return Error code indicating the reason the connection was closed or
|
||||
* failed
|
||||
*/
|
||||
lib::asio::error_code get_transport_ec() const {
|
||||
return m_tec;
|
||||
}
|
||||
|
||||
/// Initialize transport for reading
|
||||
/**
|
||||
* init_asio is called once immediately after construction to initialize
|
||||
@@ -877,6 +900,7 @@ protected:
|
||||
// We don't know much more about the error at this point. As our
|
||||
// socket/security policy if it knows more:
|
||||
tec = socket_con_type::translate_ec(ec);
|
||||
m_tec = ec;
|
||||
|
||||
if (tec == transport::error::tls_error ||
|
||||
tec == transport::error::pass_through)
|
||||
@@ -1100,6 +1124,7 @@ protected:
|
||||
// We don't know anything more about this error, give our
|
||||
// socket/security policy a crack at it.
|
||||
tec = socket_con_type::translate_ec(ec);
|
||||
m_tec = ec;
|
||||
|
||||
if (tec == transport::error::tls_short_read) {
|
||||
// TLS short read at this point is somewhat expected if both
|
||||
@@ -1156,6 +1181,9 @@ private:
|
||||
|
||||
std::vector<lib::asio::const_buffer> m_bufs;
|
||||
|
||||
/// Detailed internal error code
|
||||
lib::asio::error_code m_tec;
|
||||
|
||||
// Handlers
|
||||
tcp_init_handler m_tcp_pre_init_handler;
|
||||
tcp_init_handler m_tcp_post_init_handler;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2014, Peter Thorson. All rights reserved.
|
||||
* Copyright (c) 2015, Peter Thorson. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
@@ -28,6 +28,7 @@
|
||||
#ifndef WEBSOCKETPP_TRANSPORT_ASIO_SOCKET_BASE_HPP
|
||||
#define WEBSOCKETPP_TRANSPORT_ASIO_SOCKET_BASE_HPP
|
||||
|
||||
#include <websocketpp/common/asio.hpp>
|
||||
#include <websocketpp/common/memory.hpp>
|
||||
#include <websocketpp/common/functional.hpp>
|
||||
#include <websocketpp/common/system_error.hpp>
|
||||
@@ -63,6 +64,8 @@ namespace transport {
|
||||
namespace asio {
|
||||
namespace socket {
|
||||
|
||||
typedef lib::function<void(lib::asio::error_code const &)> shutdown_handler;
|
||||
|
||||
/**
|
||||
* The transport::asio::socket::* classes are a set of security/socket related
|
||||
* policies and support code for the ASIO transport types.
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
|
||||
#include <websocketpp/uri.hpp>
|
||||
|
||||
#include <websocketpp/transport/base/connection.hpp>
|
||||
#include <websocketpp/transport/asio/security/base.hpp>
|
||||
|
||||
#include <websocketpp/common/asio.hpp>
|
||||
@@ -240,7 +241,7 @@ protected:
|
||||
m_socket->cancel();
|
||||
}
|
||||
|
||||
void async_shutdown(socket_shutdown_handler h) {
|
||||
void async_shutdown(socket::shutdown_handler h) {
|
||||
lib::asio::error_code ec;
|
||||
m_socket->shutdown(lib::asio::ip::tcp::socket::shutdown_both, ec);
|
||||
h(ec);
|
||||
@@ -252,20 +253,36 @@ protected:
|
||||
|
||||
/// Translate any security policy specific information about an error code
|
||||
/**
|
||||
* Translate_ec takes a boost error code and attempts to convert its value
|
||||
* to an appropriate websocketpp error code. The plain socket policy does
|
||||
* not presently provide any additional information so all errors will be
|
||||
* reported as the generic transport pass_through error.
|
||||
* Translate_ec takes an Asio error code and attempts to convert its value
|
||||
* to an appropriate websocketpp error code. In the case that the Asio and
|
||||
* Websocketpp error types are the same (such as using boost::asio and
|
||||
* boost::system_error or using standalone asio and std::system_error the
|
||||
* code will be passed through natively.
|
||||
*
|
||||
* In the case of a mismatch (boost::asio with std::system_error) a
|
||||
* translated code will be returned. The plain socket policy does not have
|
||||
* any additional information so all such errors will be reported as the
|
||||
* generic transport pass_through error.
|
||||
*
|
||||
* @since 0.3.0
|
||||
*
|
||||
* @param ec The error code to translate_ec
|
||||
* @return The translated error code
|
||||
*/
|
||||
lib::error_code translate_ec(lib::asio::error_code) {
|
||||
template <typename ErrorCodeType>
|
||||
lib::error_code translate_ec(ErrorCodeType) {
|
||||
// We don't know any more information about this error so pass through
|
||||
return make_error_code(transport::error::pass_through);
|
||||
}
|
||||
|
||||
/// Overload of translate_ec to catch cases where lib::error_code is the
|
||||
/// same type as lib::asio::error_code
|
||||
lib::error_code translate_ec(lib::error_code ec) {
|
||||
// We don't know any more information about this error, but the error is
|
||||
// the same type as the one we are translating to, so pass through
|
||||
// untranslated.
|
||||
return ec;
|
||||
}
|
||||
private:
|
||||
enum state {
|
||||
UNINITIALIZED = 0,
|
||||
|
||||
@@ -55,7 +55,7 @@ typedef lib::function<void(connection_hdl,lib::asio::ssl::stream<
|
||||
typedef lib::function<lib::shared_ptr<lib::asio::ssl::context>(connection_hdl)>
|
||||
tls_init_handler;
|
||||
|
||||
/// TLS enabled Boost ASIO connection socket component
|
||||
/// TLS enabled Asio connection socket component
|
||||
/**
|
||||
* transport::asio::tls_socket::connection implements a secure connection socket
|
||||
* component that uses Asio's ssl::stream to wrap an ip::tcp::socket.
|
||||
@@ -315,26 +315,31 @@ protected:
|
||||
get_raw_socket().cancel();
|
||||
}
|
||||
|
||||
void async_shutdown(socket_shutdown_handler callback) {
|
||||
void async_shutdown(socket::shutdown_handler callback) {
|
||||
m_socket->async_shutdown(callback);
|
||||
}
|
||||
|
||||
/// Translate any security policy specific information about an error code
|
||||
/**
|
||||
* Translate_ec takes a boost error code and attempts to convert its value
|
||||
* to an appropriate websocketpp error code. Any error that is determined to
|
||||
* be related to TLS but does not have a more specific websocketpp error
|
||||
* code is returned under the catch all error "tls_error".
|
||||
* Translate_ec takes an Asio error code and attempts to convert its value
|
||||
* to an appropriate websocketpp error code. In the case that the Asio and
|
||||
* Websocketpp error types are the same (such as using boost::asio and
|
||||
* boost::system_error or using standalone asio and std::system_error the
|
||||
* code will be passed through natively.
|
||||
*
|
||||
* Non-TLS related errors are returned as the transport generic pass_through
|
||||
* error.
|
||||
* In the case of a mismatch (boost::asio with std::system_error) a
|
||||
* translated code will be returned. Any error that is determined to be
|
||||
* related to TLS but does not have a more specific websocketpp error code
|
||||
* is returned under the catch all error `tls_error`. Non-TLS related errors
|
||||
* are returned as the transport generic error `pass_through`
|
||||
*
|
||||
* @since 0.3.0
|
||||
*
|
||||
* @param ec The error code to translate_ec
|
||||
* @return The translated error code
|
||||
*/
|
||||
lib::error_code translate_ec(boost::system::error_code ec) {
|
||||
template <typename ErrorCodeType>
|
||||
lib::error_code translate_ec(ErrorCodeType ec) {
|
||||
if (ec.category() == lib::asio::error::get_ssl_category()) {
|
||||
if (ERR_GET_REASON(ec.value()) == SSL_R_SHORT_READ) {
|
||||
return make_error_code(transport::error::tls_short_read);
|
||||
@@ -349,6 +354,20 @@ protected:
|
||||
return make_error_code(transport::error::pass_through);
|
||||
}
|
||||
}
|
||||
|
||||
/// Overload of translate_ec to catch cases where lib::error_code is the
|
||||
/// same type as lib::asio::error_code
|
||||
lib::error_code translate_ec(lib::error_code ec) {
|
||||
// Normalize the tls_short_read error as it is used by the library and
|
||||
// needs a consistent value. All other errors pass through natively.
|
||||
// TODO: how to get the SSL category from std::error?
|
||||
/*if (ec.category() == lib::asio::error::get_ssl_category()) {
|
||||
if (ERR_GET_REASON(ec.value()) == SSL_R_SHORT_READ) {
|
||||
return make_error_code(transport::error::tls_short_read);
|
||||
}
|
||||
}*/
|
||||
return ec;
|
||||
}
|
||||
private:
|
||||
socket_type::handshake_type get_handshake_type() {
|
||||
if (m_is_server) {
|
||||
|
||||
Reference in new issue
Block a user