From a2109df5e90c0876ccd8022b4de15cdedd9529ea Mon Sep 17 00:00:00 2001 From: lotodore Date: Sat, 24 Jan 2015 12:30:04 +0100 Subject: [PATCH] Updating websocketpp again to release 0.5.0 (because Windows build fails currently). --- .../websocketpp/websocketpp/close.hpp | 19 + .../websocketpp/websocketpp/common/cpp11.hpp | 5 + .../websocketpp/common/functional.hpp | 26 +- .../websocketpp/websocketpp/common/memory.hpp | 17 +- .../websocketpp/common/network.hpp | 2 +- .../websocketpp/common/platforms.hpp | 5 + .../websocketpp/websocketpp/common/random.hpp | 18 +- .../websocketpp/common/system_error.hpp | 18 +- .../websocketpp/websocketpp/common/thread.hpp | 17 +- .../websocketpp/websocketpp/common/time.hpp | 6 +- .../websocketpp/websocketpp/config/core.hpp | 12 + .../websocketpp/config/core_client.hpp | 12 + .../websocketpp/websocketpp/config/debug.hpp | 12 + .../websocketpp/config/minimal_server.hpp | 18 +- .../websocketpp/websocketpp/connection.hpp | 135 ++-- .../websocketpp/websocketpp/endpoint.hpp | 81 ++- .../websocketpp/websocketpp/error.hpp | 38 +- .../websocketpp/error_container.hpp | 71 --- .../extensions/permessage_deflate/enabled.hpp | 10 +- .../websocketpp/websocketpp/frame.hpp | 1 + .../websocketpp/http/constants.hpp | 5 + .../websocketpp/http/impl/parser.hpp | 59 +- .../websocketpp/http/impl/request.hpp | 84 +-- .../websocketpp/http/impl/response.hpp | 36 +- .../websocketpp/websocketpp/http/parser.hpp | 102 ++- .../websocketpp/websocketpp/http/request.hpp | 22 +- .../websocketpp/websocketpp/http/response.hpp | 32 +- .../websocketpp/impl/connection_impl.hpp | 599 +++++++++++------- .../websocketpp/impl/endpoint_impl.hpp | 3 + .../websocketpp/impl/utilities_impl.hpp | 11 +- .../websocketpp/websocketpp/logger/basic.hpp | 35 +- .../websocketpp/websocketpp/logger/levels.hpp | 11 + .../websocketpp/websocketpp/logger/stub.hpp | 25 +- .../websocketpp/websocketpp/logger/syslog.hpp | 146 +++++ .../websocketpp/message_buffer/message.hpp | 4 +- .../websocketpp/message_buffer/pool.hpp | 4 +- .../websocketpp/processors/base.hpp | 15 +- .../websocketpp/processors/hybi00.hpp | 11 +- .../websocketpp/processors/hybi07.hpp | 3 + .../websocketpp/processors/hybi08.hpp | 5 +- .../websocketpp/processors/hybi13.hpp | 22 +- .../websocketpp/processors/processor.hpp | 8 +- .../websocketpp/roles/client_endpoint.hpp | 6 +- .../websocketpp/roles/server_endpoint.hpp | 4 +- .../websocketpp/transport/asio/connection.hpp | 21 +- .../websocketpp/transport/asio/endpoint.hpp | 19 +- .../transport/asio/security/base.hpp | 6 +- .../transport/asio/security/none.hpp | 4 +- .../transport/asio/security/tls.hpp | 2 + .../websocketpp/transport/base/connection.hpp | 5 +- .../websocketpp/transport/base/endpoint.hpp | 5 - .../websocketpp/transport/debug/base.hpp | 104 +++ .../transport/debug/connection.hpp | 397 ++++++++++++ .../websocketpp/transport/debug/endpoint.hpp | 140 ++++ .../websocketpp/transport/iostream/base.hpp | 10 + .../transport/iostream/connection.hpp | 141 ++++- .../transport/iostream/endpoint.hpp | 57 +- .../websocketpp/transport/stub/base.hpp | 10 +- .../websocketpp/transport/stub/connection.hpp | 24 +- .../websocketpp/transport/stub/endpoint.hpp | 6 +- .../websocketpp/websocketpp/uri.hpp | 4 +- .../websocketpp/utf8_validator.hpp | 2 + .../websocketpp/websocketpp/version.hpp | 4 +- 63 files changed, 2072 insertions(+), 664 deletions(-) delete mode 100644 src/third_party/websocketpp/websocketpp/error_container.hpp create mode 100644 src/third_party/websocketpp/websocketpp/logger/syslog.hpp create mode 100644 src/third_party/websocketpp/websocketpp/transport/debug/base.hpp create mode 100644 src/third_party/websocketpp/websocketpp/transport/debug/connection.hpp create mode 100644 src/third_party/websocketpp/websocketpp/transport/debug/endpoint.hpp diff --git a/src/third_party/websocketpp/websocketpp/close.hpp b/src/third_party/websocketpp/websocketpp/close.hpp index 53ad4f1c..f8e76943 100644 --- a/src/third_party/websocketpp/websocketpp/close.hpp +++ b/src/third_party/websocketpp/websocketpp/close.hpp @@ -150,6 +150,21 @@ namespace status { * illegal on the wire. */ static value const tls_handshake = 1015; + + /// A generic subprotocol error + /** + * Indicates that a subprotocol error occurred. Typically this involves + * receiving a message that is not formatted as a valid message for the + * subprotocol in use. + */ + static value const subprotocol_error = 3000; + + /// A invalid subprotocol data + /** + * Indicates that data was received that violated the specification of the + * subprotocol in use. + */ + static value const invalid_subprotocol_data = 3001; /// First value in range reserved for future protocol use static value const rsv_start = 1016; @@ -235,6 +250,10 @@ namespace status { return "Internal endpoint error"; case tls_handshake: return "TLS handshake failure"; + case subprotocol_error: + return "Generic subprotocol error"; + case invalid_subprotocol_data: + return "Invalid subprotocol data"; default: return "Unknown"; } diff --git a/src/third_party/websocketpp/websocketpp/common/cpp11.hpp b/src/third_party/websocketpp/websocketpp/common/cpp11.hpp index c317e9a4..6c79d644 100644 --- a/src/third_party/websocketpp/websocketpp/common/cpp11.hpp +++ b/src/third_party/websocketpp/websocketpp/common/cpp11.hpp @@ -51,6 +51,11 @@ // C++11 compiler via the __cplusplus macro or the user/build system // supplies one of the two preprocessor defines below: + // This is defined to allow other WebSocket++ common headers to enable + // C++11 features when they are detected by this file rather than + // duplicating the above logic in every common header. + #define _WEBSOCKETPP_CPP11_INTERNAL_ + // _WEBSOCKETPP_CPP11_STRICT_ // // This define reports to WebSocket++ that 100% of the language and library diff --git a/src/third_party/websocketpp/websocketpp/common/functional.hpp b/src/third_party/websocketpp/websocketpp/common/functional.hpp index cc451bfa..d332dd15 100644 --- a/src/third_party/websocketpp/websocketpp/common/functional.hpp +++ b/src/third_party/websocketpp/websocketpp/common/functional.hpp @@ -28,12 +28,27 @@ #ifndef WEBSOCKETPP_COMMON_FUNCTIONAL_HPP #define WEBSOCKETPP_COMMON_FUNCTIONAL_HPP -#if defined _WEBSOCKETPP_CPP11_STL_ && !defined _WEBSOCKETPP_NO_CPP11_FUNCTIONAL_ +#include + +// If we've determined that we're in full C++11 mode and the user hasn't +// explicitly disabled the use of C++11 functional header, then prefer it to +// boost. +#if defined _WEBSOCKETPP_CPP11_INTERNAL_ && !defined _WEBSOCKETPP_NO_CPP11_FUNCTIONAL_ #ifndef _WEBSOCKETPP_CPP11_FUNCTIONAL_ #define _WEBSOCKETPP_CPP11_FUNCTIONAL_ #endif #endif +// If we're on Visual Studio 2010 or higher and haven't explicitly disabled +// the use of C++11 functional header then prefer it to boost. +#if defined(_MSC_VER) && _MSC_VER >= 1600 && !defined _WEBSOCKETPP_NO_CPP11_FUNCTIONAL_ + #ifndef _WEBSOCKETPP_CPP11_FUNCTIONAL_ + #define _WEBSOCKETPP_CPP11_FUNCTIONAL_ + #endif +#endif + + + #ifdef _WEBSOCKETPP_CPP11_FUNCTIONAL_ #include #else @@ -52,14 +67,14 @@ namespace lib { using std::bind; using std::ref; namespace placeholders = std::placeholders; - + // There are some cases where a C++11 compiler balks at using std::ref // but a C++03 compiler using boost function requires boost::ref. As such // lib::ref is not useful in these cases. Instead this macro allows the use // of boost::ref in the case of a boost compile or no reference wrapper at // all in the case of a C++11 compile #define _WEBSOCKETPP_REF(x) x - + template void clear_function(T & x) { x = nullptr; @@ -72,11 +87,12 @@ namespace lib { /// \todo this feels hacky, is there a better way? using ::_1; using ::_2; + using ::_3; } - + // See above definition for more details on what this is and why it exists #define _WEBSOCKETPP_REF(x) boost::ref(x) - + template void clear_function(T & x) { x.clear(); diff --git a/src/third_party/websocketpp/websocketpp/common/memory.hpp b/src/third_party/websocketpp/websocketpp/common/memory.hpp index fba4c607..52cd85b5 100644 --- a/src/third_party/websocketpp/websocketpp/common/memory.hpp +++ b/src/third_party/websocketpp/websocketpp/common/memory.hpp @@ -28,12 +28,27 @@ #ifndef WEBSOCKETPP_COMMON_MEMORY_HPP #define WEBSOCKETPP_COMMON_MEMORY_HPP -#if defined _WEBSOCKETPP_CPP11_STL_ && !defined _WEBSOCKETPP_NO_CPP11_MEMORY_ +#include + +// If we've determined that we're in full C++11 mode and the user hasn't +// explicitly disabled the use of C++11 memory header, then prefer it to +// boost. +#if defined _WEBSOCKETPP_CPP11_INTERNAL_ && !defined _WEBSOCKETPP_NO_CPP11_MEMORY_ #ifndef _WEBSOCKETPP_CPP11_MEMORY_ #define _WEBSOCKETPP_CPP11_MEMORY_ #endif #endif +// If we're on Visual Studio 2010 or higher and haven't explicitly disabled +// the use of C++11 functional header then prefer it to boost. +#if defined(_MSC_VER) && _MSC_VER >= 1600 && !defined _WEBSOCKETPP_NO_CPP11_MEMORY_ + #ifndef _WEBSOCKETPP_CPP11_MEMORY_ + #define _WEBSOCKETPP_CPP11_MEMORY_ + #endif +#endif + + + #ifdef _WEBSOCKETPP_CPP11_MEMORY_ #include #else diff --git a/src/third_party/websocketpp/websocketpp/common/network.hpp b/src/third_party/websocketpp/websocketpp/common/network.hpp index ac906440..3f983966 100644 --- a/src/third_party/websocketpp/websocketpp/common/network.hpp +++ b/src/third_party/websocketpp/websocketpp/common/network.hpp @@ -42,7 +42,7 @@ namespace net { inline bool is_little_endian() { short int val = 0x1; - char *ptr = (char*)&val; + char *ptr = reinterpret_cast(&val); return (ptr[0] == 1); } diff --git a/src/third_party/websocketpp/websocketpp/common/platforms.hpp b/src/third_party/websocketpp/websocketpp/common/platforms.hpp index d934a039..87798577 100644 --- a/src/third_party/websocketpp/websocketpp/common/platforms.hpp +++ b/src/third_party/websocketpp/websocketpp/common/platforms.hpp @@ -38,4 +38,9 @@ #define NOMINMAX #endif +// Bump up the variadic parameter max for Visual Studio 2012 +#if defined(_MSC_VER) && _MSC_VER == 1700 + #define _VARIADIC_MAX 8 +#endif + #endif // WEBSOCKETPP_COMMON_PLATFORMS_HPP diff --git a/src/third_party/websocketpp/websocketpp/common/random.hpp b/src/third_party/websocketpp/websocketpp/common/random.hpp index fd29c42d..ddf99694 100644 --- a/src/third_party/websocketpp/websocketpp/common/random.hpp +++ b/src/third_party/websocketpp/websocketpp/common/random.hpp @@ -28,12 +28,28 @@ #ifndef WEBSOCKETPP_COMMON_RANDOM_DEVICE_HPP #define WEBSOCKETPP_COMMON_RANDOM_DEVICE_HPP -#if defined _WEBSOCKETPP_CPP11_STL_ && !defined _WEBSOCKETPP_NO_CPP11_RANDOM_DEVICE_ +#include + +// If we've determined that we're in full C++11 mode and the user hasn't +// explicitly disabled the use of C++11 random header, then prefer it to +// boost. +#if defined _WEBSOCKETPP_CPP11_INTERNAL_ && !defined _WEBSOCKETPP_NO_CPP11_RANDOM_DEVICE_ #ifndef _WEBSOCKETPP_CPP11_RANDOM_DEVICE_ #define _WEBSOCKETPP_CPP11_RANDOM_DEVICE_ #endif #endif + +// If we're on Visual Studio 2010 or higher and haven't explicitly disabled +// the use of C++11 random header then prefer it to boost. +#if defined(_MSC_VER) && _MSC_VER >= 1600 && !defined _WEBSOCKETPP_NO_CPP11_MEMORY_ + #ifndef _WEBSOCKETPP_CPP11_MEMORY_ + #define _WEBSOCKETPP_CPP11_MEMORY_ + #endif +#endif + + + #ifdef _WEBSOCKETPP_CPP11_RANDOM_DEVICE_ #include #else diff --git a/src/third_party/websocketpp/websocketpp/common/system_error.hpp b/src/third_party/websocketpp/websocketpp/common/system_error.hpp index 4bfa73dc..4abe1732 100644 --- a/src/third_party/websocketpp/websocketpp/common/system_error.hpp +++ b/src/third_party/websocketpp/websocketpp/common/system_error.hpp @@ -28,12 +28,28 @@ #ifndef WEBSOCKETPP_COMMON_SYSTEM_ERROR_HPP #define WEBSOCKETPP_COMMON_SYSTEM_ERROR_HPP -#if defined _WEBSOCKETPP_CPP11_STL_ && !defined _WEBSOCKETPP_NO_CPP11_SYSTEM_ERROR_ + +#include + +// If we've determined that we're in full C++11 mode and the user hasn't +// explicitly disabled the use of C++11 system_error header, then prefer it to +// boost. +#if defined _WEBSOCKETPP_CPP11_INTERNAL_ && !defined _WEBSOCKETPP_NO_CPP11_SYSTEM_ERROR_ #ifndef _WEBSOCKETPP_CPP11_SYSTEM_ERROR_ #define _WEBSOCKETPP_CPP11_SYSTEM_ERROR_ #endif #endif +// If we're on Visual Studio 2010 or higher and haven't explicitly disabled +// the use of C++11 system_error header then prefer it to boost. +#if defined(_MSC_VER) && _MSC_VER >= 1600 && !defined _WEBSOCKETPP_NO_CPP11_SYSTEM_ERROR_ + #ifndef _WEBSOCKETPP_CPP11_SYSTEM_ERROR_ + #define _WEBSOCKETPP_CPP11_SYSTEM_ERROR_ + #endif +#endif + + + #ifdef _WEBSOCKETPP_CPP11_SYSTEM_ERROR_ #include #else diff --git a/src/third_party/websocketpp/websocketpp/common/thread.hpp b/src/third_party/websocketpp/websocketpp/common/thread.hpp index 30fb6a42..fa87396f 100644 --- a/src/third_party/websocketpp/websocketpp/common/thread.hpp +++ b/src/third_party/websocketpp/websocketpp/common/thread.hpp @@ -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,9 +28,18 @@ #ifndef WEBSOCKETPP_COMMON_THREAD_HPP #define WEBSOCKETPP_COMMON_THREAD_HPP -#if defined _WEBSOCKETPP_CPP11_STL_ && !defined _WEBSOCKETPP_NO_CPP11_THREAD_ - #ifndef _WEBSOCKETPP_CPP11_THREAD_ - #define _WEBSOCKETPP_CPP11_THREAD_ +#include + +// If we autodetect C++11 and haven't been explicitly instructed to not use +// C++11 threads, then set the defines that instructs the rest of this header +// to use C++11 and +#if defined _WEBSOCKETPP_CPP11_INTERNAL_ && !defined _WEBSOCKETPP_NO_CPP11_THREAD_ + // MinGW by default does not support C++11 thread/mutex so even if the + // internal check for C++11 passes, ignore it if we are on MinGW + #if (!defined(__MINGW32__) && !defined(__MINGW64__)) + #ifndef _WEBSOCKETPP_CPP11_THREAD_ + #define _WEBSOCKETPP_CPP11_THREAD_ + #endif #endif #endif diff --git a/src/third_party/websocketpp/websocketpp/common/time.hpp b/src/third_party/websocketpp/websocketpp/common/time.hpp index 1f01c311..571688e1 100644 --- a/src/third_party/websocketpp/websocketpp/common/time.hpp +++ b/src/third_party/websocketpp/websocketpp/common/time.hpp @@ -28,7 +28,7 @@ #ifndef WEBSOCKETPP_COMMON_TIME_HPP #define WEBSOCKETPP_COMMON_TIME_HPP -#include +#include namespace websocketpp { namespace lib { @@ -40,7 +40,9 @@ namespace lib { /// Thread safe cross platform localtime inline std::tm localtime(std::time_t const & time) { std::tm tm_snapshot; -#if (defined(WIN32) || defined(_WIN32) || defined(__WIN32__)) +#if (defined(__MINGW32__) || defined(__MINGW64__)) + memcpy(&tm_snapshot, ::localtime(&time), sizeof(std::tm)); +#elif (defined(WIN32) || defined(_WIN32) || defined(__WIN32__)) localtime_s(&tm_snapshot, &time); #else localtime_r(&time, &tm_snapshot); // POSIX diff --git a/src/third_party/websocketpp/websocketpp/config/core.hpp b/src/third_party/websocketpp/websocketpp/config/core.hpp index c35bff76..a95b4021 100644 --- a/src/third_party/websocketpp/websocketpp/config/core.hpp +++ b/src/third_party/websocketpp/websocketpp/config/core.hpp @@ -226,6 +226,18 @@ struct core { * @since 0.3.0 */ static const size_t max_message_size = 32000000; + + /// Default maximum http body size + /** + * Default value for the http parser's maximum body size. Maximum body size + * determines the point at which the library will abort reading an HTTP + * connection with the 413/request entity too large error. + * + * The default is 32MB + * + * @since 0.5.0 + */ + static const size_t max_http_body_size = 32000000; /// Global flag for enabling/disabling extensions static const bool enable_extensions = true; diff --git a/src/third_party/websocketpp/websocketpp/config/core_client.hpp b/src/third_party/websocketpp/websocketpp/config/core_client.hpp index fcbac10a..dadf8a4e 100644 --- a/src/third_party/websocketpp/websocketpp/config/core_client.hpp +++ b/src/third_party/websocketpp/websocketpp/config/core_client.hpp @@ -236,6 +236,18 @@ struct core_client { */ static const size_t max_message_size = 32000000; + /// Default maximum http body size + /** + * Default value for the http parser's maximum body size. Maximum body size + * determines the point at which the library will abort reading an HTTP + * connection with the 413/request entity too large error. + * + * The default is 32MB + * + * @since 0.5.0 + */ + static const size_t max_http_body_size = 32000000; + /// Global flag for enabling/disabling extensions static const bool enable_extensions = true; diff --git a/src/third_party/websocketpp/websocketpp/config/debug.hpp b/src/third_party/websocketpp/websocketpp/config/debug.hpp index 9f90360a..223f72fb 100644 --- a/src/third_party/websocketpp/websocketpp/config/debug.hpp +++ b/src/third_party/websocketpp/websocketpp/config/debug.hpp @@ -228,6 +228,18 @@ struct debug_core { */ static const size_t max_message_size = 32000000; + /// Default maximum http body size + /** + * Default value for the http parser's maximum body size. Maximum body size + * determines the point at which the library will abort reading an HTTP + * connection with the 413/request entity too large error. + * + * The default is 32MB + * + * @since 0.5.0 + */ + static const size_t max_http_body_size = 32000000; + /// Global flag for enabling/disabling extensions static const bool enable_extensions = true; diff --git a/src/third_party/websocketpp/websocketpp/config/minimal_server.hpp b/src/third_party/websocketpp/websocketpp/config/minimal_server.hpp index f689da9e..dd1aedb9 100644 --- a/src/third_party/websocketpp/websocketpp/config/minimal_server.hpp +++ b/src/third_party/websocketpp/websocketpp/config/minimal_server.hpp @@ -112,10 +112,8 @@ struct minimal_server { endpoint_msg_manager_type; /// Logging policies - typedef websocketpp::log::stub elog_type; - typedef websocketpp::log::stub alog_type; + typedef websocketpp::log::stub elog_type; + typedef websocketpp::log::stub alog_type; /// RNG policies typedef websocketpp::random::none::int_generator rng_type; @@ -256,6 +254,18 @@ struct minimal_server { */ static const size_t max_message_size = 32000000; + /// Default maximum http body size + /** + * Default value for the http parser's maximum body size. Maximum body size + * determines the point at which the library will abort reading an HTTP + * connection with the 413/request entity too large error. + * + * The default is 32MB + * + * @since 0.5.0 + */ + static const size_t max_http_body_size = 32000000; + /// Global flag for enabling/disabling extensions static const bool enable_extensions = true; diff --git a/src/third_party/websocketpp/websocketpp/connection.hpp b/src/third_party/websocketpp/websocketpp/connection.hpp index 37880ce1..95468327 100644 --- a/src/third_party/websocketpp/websocketpp/connection.hpp +++ b/src/third_party/websocketpp/websocketpp/connection.hpp @@ -29,18 +29,18 @@ #define WEBSOCKETPP_CONNECTION_HPP #include -#include -#include -#include #include #include -#include + #include #include #include +#include + +#include +#include +#include -#include -#include #include #include #include @@ -119,7 +119,7 @@ typedef lib::function pong_timeout_handler; /** * The validate handler is called after a WebSocket handshake has been received * and processed but before it has been accepted. This gives the application a - * chance to impliment connection details specific policies for accepting + * chance to implement connection details specific policies for accepting * connections and the ability to negotiate extensions and subprotocols. * * The validate handler return value indicates whether or not the connection @@ -311,6 +311,7 @@ public: , m_rng(rng) , m_local_close_code(close::status::abnormal_close) , m_remote_close_code(close::status::abnormal_close) + , m_is_http(false) , m_was_clean(false) { m_alog.write(log::alevel::devel,"connection constructor"); @@ -533,8 +534,8 @@ public: /// Get maximum message size /** - * Get maximum message size. Maximum message size determines the point at which the - * connection will fail a connection with the message_too_big protocol error. + * Get maximum message size. Maximum message size determines the point at + * which the connection will fail with the message_too_big protocol error. * * The default is set by the endpoint that creates the connection. * @@ -546,9 +547,9 @@ public: /// Set maximum message size /** - * Set maximum message size. Maximum message size determines the point at which the - * connection will fail a connection with the message_too_big protocol error. This - * value may be changed during the connection. + * Set maximum message size. Maximum message size determines the point at + * which the connection will fail with the message_too_big protocol error. + * This value may be changed during the connection. * * The default is set by the endpoint that creates the connection. * @@ -562,6 +563,38 @@ public: m_processor->set_max_message_size(new_value); } } + + /// Get maximum HTTP message body size + /** + * Get maximum HTTP message body size. Maximum message body size determines + * the point at which the connection will stop reading an HTTP request whose + * body is too large. + * + * The default is set by the endpoint that creates the connection. + * + * @since 0.5.0 + * + * @return The maximum HTTP message body size + */ + size_t get_max_http_body_size() const { + return m_request.get_max_body_size(); + } + + /// Set maximum HTTP message body size + /** + * Set maximum HTTP message body size. Maximum message body size determines + * the point at which the connection will stop reading an HTTP request whose + * body is too large. + * + * The default is set by the endpoint that creates the connection. + * + * @since 0.5.0 + * + * @param new_value The value to set as the maximum message size. + */ + void set_max_http_body_size(size_t new_value) { + m_request.set_max_body_size(new_value); + } ////////////////////////////////// // Uncategorized public methods // @@ -899,7 +932,18 @@ public: * @param key Name of the header to get * @return The value of the header */ - std::string const & get_request_header(std::string const & key); + std::string const & get_request_header(std::string const & key) const; + + /// Retrieve a request body + /** + * Retrieve the value of the request body. This value is typically used with + * PUT and POST requests to upload files or other data. Only HTTP + * connections will ever have bodies. WebSocket connection's will always + * have blank bodies. + * + * @return The value of the request body. + */ + std::string const & get_request_body() const; /// Retrieve a response header /** @@ -908,7 +952,7 @@ public: * @param key Name of the header to get * @return The value of the header */ - std::string const & get_response_header(std::string const & key); + std::string const & get_response_header(std::string const & key) const; /// Set response status code and message /** @@ -1168,7 +1212,7 @@ public: void read_frame(); /// Get array of WebSocket protocol versions that this connection supports. - const std::vector& get_supported_versions() const; + std::vector const & get_supported_versions() const; /// Sets the handler for a terminating connection. Should only be used /// internally by the endpoint class. @@ -1202,60 +1246,21 @@ protected: void handle_transport_init(lib::error_code const & ec); /// Set m_processor based on information in m_request. Set m_response - /// status and return false on error. - bool initialize_processor(); + /// status and return an error code indicating status. + lib::error_code initialize_processor(); /// Perform WebSocket handshake validation of m_request using m_processor. - /// set m_response and return false on error. - bool process_handshake_request(); - - /// Atomically change the internal connection state. - /** - * @param req The required starting state. If the internal state does not - * match req an exception is thrown. - * - * @param dest The state to change to. - * - * @param msg The message to include in the exception thrown - */ - void atomic_state_change(istate_type req, istate_type dest, - std::string msg); - - /// Atomically change the internal and external connection state. - /** - * @param ireq The required starting internal state. If the internal state - * does not match ireq an exception is thrown. - * - * @param idest The internal state to change to. - * - * @param ereq The required starting external state. If the external state - * does not match ereq an exception is thrown. - * - * @param edest The external state to change to. - * - * @param msg The message to include in the exception thrown - */ - void atomic_state_change(istate_type ireq, istate_type idest, - session::state::value ereq, session::state::value edest, - std::string msg); - - /// Atomically read and compared the internal state. - /** - * @param req The state to test against. If the internal state does not - * match req an exception is thrown. - * - * @param msg The message to include in the exception thrown - */ - void atomic_state_check(istate_type req, std::string msg); + /// set m_response and return an error code indicating status. + lib::error_code process_handshake_request(); private: /// Completes m_response, serializes it, and sends it out on the wire. - void send_http_response(); + void send_http_response(lib::error_code const & ec); /// Sends an opening WebSocket connect request void send_http_request(); /// Alternate path for send_http_response in error conditions - void send_http_response_error(); + void send_http_response_error(lib::error_code const & ec); /// Process control message /** @@ -1352,6 +1357,12 @@ private: * Includes: error code and message for why it was failed */ void log_fail_result(); + + /// Prints information about HTTP connections + /** + * Includes: TODO + */ + void log_http_result(); /// Prints information about an arbitrary error code on the specified channel template @@ -1495,6 +1506,10 @@ private: /// Detailed internal error code lib::error_code m_ec; + + /// A flag that gets set once it is determined that the connection is an + /// HTTP connection and not a WebSocket one. + bool m_is_http; bool m_was_clean; diff --git a/src/third_party/websocketpp/websocketpp/endpoint.hpp b/src/third_party/websocketpp/websocketpp/endpoint.hpp index 3bbe9da1..467f0d82 100644 --- a/src/third_party/websocketpp/websocketpp/endpoint.hpp +++ b/src/third_party/websocketpp/websocketpp/endpoint.hpp @@ -29,10 +29,11 @@ #define WEBSOCKETPP_ENDPOINT_HPP #include + #include #include -#include +#include namespace websocketpp { @@ -84,8 +85,6 @@ public: // TODO: organize these typedef typename connection_type::termination_handler termination_handler; - typedef lib::shared_ptr hdl_type; - explicit endpoint(bool p_is_server) : m_alog(config::alog_level, log::channel_type_hint::access) , m_elog(config::elog_level, log::channel_type_hint::error) @@ -94,6 +93,7 @@ public: , m_close_handshake_timeout_dur(config::timeout_close_handshake) , m_pong_timeout_dur(config::timeout_pong) , m_max_message_size(config::max_message_size) + , m_max_http_body_size(config::max_http_body_size) , m_is_server(p_is_server) { m_alog.set_channels(config::alog_level); @@ -350,9 +350,10 @@ public: /// Get default maximum message size /** - * Get the default maximum message size that will be used for new connections created - * by this endpoint. The maximum message size determines the point at which the - * connection will fail a connection with the message_too_big protocol error. + * Get the default maximum message size that will be used for new + * connections created by this endpoint. The maximum message size determines + * the point at which the connection will fail a connection with the + * message_too_big protocol error. * * The default is set by the max_message_size value from the template config * @@ -364,9 +365,10 @@ public: /// Set default maximum message size /** - * Set the default maximum message size that will be used for new connections created - * by this endpoint. Maximum message size determines the point at which the connection - * will fail a connection with the message_too_big protocol error. + * Set the default maximum message size that will be used for new + * connections created by this endpoint. Maximum message size determines the + * point at which the connection will fail a connection with the + * message_too_big protocol error. * * The default is set by the max_message_size value from the template config * @@ -378,6 +380,40 @@ public: m_max_message_size = new_value; } + /// Get maximum HTTP message body size + /** + * Get maximum HTTP message body size. Maximum message body size determines + * the point at which the connection will stop reading an HTTP request whose + * body is too large. + * + * The default is set by the max_http_body_size value from the template + * config + * + * @since 0.5.0 + * + * @return The maximum HTTP message body size + */ + size_t get_max_http_body_size() const { + return m_max_http_body_size; + } + + /// Set maximum HTTP message body size + /** + * Set maximum HTTP message body size. Maximum message body size determines + * the point at which the connection will stop reading an HTTP request whose + * body is too large. + * + * The default is set by the max_http_body_size value from the template + * config + * + * @since 0.5.0 + * + * @param new_value The value to set as the maximum message size. + */ + void get_max_http_body_size(size_t new_value) { + m_max_http_body_size = new_value; + } + /*************************************/ /* Connection pass through functions */ /*************************************/ @@ -395,21 +431,21 @@ public: /// Pause reading of new data (exception free) /** - * Signals to the connection to halt reading of new data. While reading is paused, - * the connection will stop reading from its associated socket. In turn this will - * result in TCP based flow control kicking in and slowing data flow from the remote - * endpoint. + * Signals to the connection to halt reading of new data. While reading is + * paused, the connection will stop reading from its associated socket. In + * turn this will result in TCP based flow control kicking in and slowing + * data flow from the remote endpoint. * - * This is useful for applications that push new requests to a queue to be processed - * by another thread and need a way to signal when their request queue is full without - * blocking the network processing thread. + * This is useful for applications that push new requests to a queue to be + * processed by another thread and need a way to signal when their request + * queue is full without blocking the network processing thread. * * Use `resume_reading()` to resume. * - * If supported by the transport this is done asynchronously. As such reading may not - * stop until the current read operation completes. Typically you can expect to - * receive no more bytes after initiating a read pause than the size of the read - * buffer. + * If supported by the transport this is done asynchronously. As such + * reading may not stop until the current read operation completes. + * Typically you can expect to receive no more bytes after initiating a read + * pause than the size of the read buffer. * * If reading is paused for this connection already nothing is changed. */ @@ -420,8 +456,8 @@ public: /// Resume reading of new data (exception free) /** - * Signals to the connection to resume reading of new data after it was paused by - * `pause_reading()`. + * Signals to the connection to resume reading of new data after it was + * paused by `pause_reading()`. * * If reading is not paused for this connection already nothing is changed. */ @@ -565,6 +601,7 @@ private: long m_close_handshake_timeout_dur; long m_pong_timeout_dur; size_t m_max_message_size; + size_t m_max_http_body_size; rng_type m_rng; diff --git a/src/third_party/websocketpp/websocketpp/error.hpp b/src/third_party/websocketpp/websocketpp/error.hpp index 6fff5307..81fff873 100644 --- a/src/third_party/websocketpp/websocketpp/error.hpp +++ b/src/third_party/websocketpp/websocketpp/error.hpp @@ -28,7 +28,9 @@ #ifndef WEBSOCKETPP_ERROR_HPP #define WEBSOCKETPP_ERROR_HPP +#include #include +#include #include #include @@ -122,7 +124,23 @@ enum value { async_accept_not_listening, /// The requested operation was canceled - operation_canceled + operation_canceled, + + /// Connection rejected + rejected, + + /// Upgrade Required. This happens if an HTTP request is made to a + /// WebSocket++ server that doesn't implement an http handler + upgrade_required, + + /// Invalid WebSocket protocol version + invalid_version, + + /// Unsupported WebSocket protocol version + unsupported_version, + + /// HTTP parse error + http_parse_error }; // enum value @@ -188,6 +206,16 @@ public: return "Async Accept not listening"; case error::operation_canceled: return "Operation canceled"; + case error::rejected: + return "Connection rejected"; + case error::upgrade_required: + return "Upgrade required"; + case error::invalid_version: + return "Invalid version"; + case error::unsupported_version: + return "Unsupported version"; + case error::http_parse_error: + return "HTTP parse error"; default: return "Unknown"; } @@ -218,7 +246,7 @@ namespace websocketpp { class exception : public std::exception { public: exception(std::string const & msg, lib::error_code ec = make_error_code(error::general)) - : m_msg(msg), m_code(ec) + : m_msg(msg.empty() ? ec.message() : msg), m_code(ec) {} explicit exception(lib::error_code ec) @@ -228,11 +256,7 @@ public: ~exception() throw() {} virtual char const * what() const throw() { - if (m_msg.empty()) { - return m_code.message().c_str(); - } else { - return m_msg.c_str(); - } + return m_msg.c_str(); } lib::error_code code() const throw() { diff --git a/src/third_party/websocketpp/websocketpp/error_container.hpp b/src/third_party/websocketpp/websocketpp/error_container.hpp deleted file mode 100644 index 5a84f7aa..00000000 --- a/src/third_party/websocketpp/websocketpp/error_container.hpp +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright (c) 2014, 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. - * - */ - -#ifndef WEBSOCKETPP_ERROR_MESSAGE_HPP -#define WEBSOCKETPP_ERROR_MESSAGE_HPP - -namespace websocketpp { - -/** - * The transport::security::* classes are a set of security/socket related - * policies and support code for the ASIO transport types. - */ -class error_msg { -public: - const std::string& get_msg() const { - return m_error_msg; - } - - void set_msg(const std::string& msg) { - m_error_msg = msg; - } - - void append_msg(const std::string& msg) { - m_error_msg.append(msg); - } - - template - void set_msg(const T& thing) { - std::stringsteam val; - val << thing; - this->set_msg(val.str()); - } - - template - void append_msg(const T& thing) { - std::stringsteam val; - val << thing; - this->append_msg(val.str()); - } -private: - // error resources - std::string m_error_msg; -}; - -} // namespace websocketpp - -#endif // WEBSOCKETPP_ERROR_MESSAGE_HPP diff --git a/src/third_party/websocketpp/websocketpp/extensions/permessage_deflate/enabled.hpp b/src/third_party/websocketpp/websocketpp/extensions/permessage_deflate/enabled.hpp index 00a255d9..73b9b307 100644 --- a/src/third_party/websocketpp/websocketpp/extensions/permessage_deflate/enabled.hpp +++ b/src/third_party/websocketpp/websocketpp/extensions/permessage_deflate/enabled.hpp @@ -46,13 +46,13 @@ namespace websocketpp { namespace extensions { -/// Implimentation of the draft permessage-deflate WebSocket extension +/// Implementation of the draft permessage-deflate WebSocket extension /** * ### permessage-deflate interface * * **is_implemented**\n * `bool is_implemented()`\n - * Returns whether or not the object impliments the extension or not + * Returns whether or not the object implements the extension or not * * **is_enabled**\n * `bool is_enabled()`\n @@ -287,11 +287,11 @@ public: return lib::error_code(); } - /// Test if this object impliments the permessage-deflate specification + /// Test if this object implements the permessage-deflate specification /** - * Because this object does impliment it, it will always return true. + * Because this object does implieent it, it will always return true. * - * @return Whether or not this object impliments permessage-deflate + * @return Whether or not this object implements permessage-deflate */ bool is_implemented() const { return true; diff --git a/src/third_party/websocketpp/websocketpp/frame.hpp b/src/third_party/websocketpp/websocketpp/frame.hpp index c22d3584..8a173375 100644 --- a/src/third_party/websocketpp/websocketpp/frame.hpp +++ b/src/third_party/websocketpp/websocketpp/frame.hpp @@ -29,6 +29,7 @@ #define WEBSOCKETPP_FRAME_HPP #include +#include #include #include diff --git a/src/third_party/websocketpp/websocketpp/http/constants.hpp b/src/third_party/websocketpp/websocketpp/http/constants.hpp index 22af5f2c..10e726d0 100644 --- a/src/third_party/websocketpp/websocketpp/http/constants.hpp +++ b/src/third_party/websocketpp/websocketpp/http/constants.hpp @@ -28,9 +28,11 @@ #ifndef HTTP_CONSTANTS_HPP #define HTTP_CONSTANTS_HPP +#include #include #include #include +#include namespace websocketpp { /// HTTP handling support @@ -61,6 +63,9 @@ namespace http { /// Maximum size in bytes before rejecting an HTTP header as too big. size_t const max_header_size = 16000; + + /// Default Maximum size in bytes for HTTP message bodies. + size_t const max_body_size = 32000000; /// Number of bytes to use for temporary istream read buffers size_t const istream_buffer = 512; diff --git a/src/third_party/websocketpp/websocketpp/http/impl/parser.hpp b/src/third_party/websocketpp/websocketpp/http/impl/parser.hpp index a8f8d665..92799a40 100644 --- a/src/third_party/websocketpp/websocketpp/http/impl/parser.hpp +++ b/src/third_party/websocketpp/websocketpp/http/impl/parser.hpp @@ -29,6 +29,8 @@ #define HTTP_PARSER_IMPL_HPP #include +#include +#include #include #include @@ -93,6 +95,9 @@ inline void parser::set_body(std::string const & value) { return; } + // TODO: should this method respect the max size? If so how should errors + // be indicated? + std::stringstream len; len << value.size(); replace_header("Content-Length", len.str()); @@ -111,26 +116,46 @@ inline bool parser::parse_parameter_list(std::string const & in, return (it == in.begin()); } -inline bool parser::parse_headers(std::istream & s) { - std::string header; - std::string::size_type end; - - // get headers - while (std::getline(s, header) && header != "\r") { - if (header[header.size()-1] != '\r') { - continue; // ignore malformed header lines? - } else { - header.erase(header.end()-1); - } - - end = header.find(header_separator,0); - - if (end != std::string::npos) { - append_header(header.substr(0,end),header.substr(end+2)); +inline bool parser::prepare_body() { + if (get_header("Content-Length") != "") { + std::string const & cl_header = get_header("Content-Length"); + char * end; + + // TODO: not 100% sure what the compatibility of this method is. Also, + // I believe this will only work up to 32bit sizes. Is there a need for + // > 4GiB HTTP payloads? + m_body_bytes_needed = std::strtoul(cl_header.c_str(),&end,10); + + if (m_body_bytes_needed > m_body_bytes_max) { + throw exception("HTTP message body too large", + status_code::request_entity_too_large); } + + m_body_encoding = body_encoding::plain; + return true; + } else if (get_header("Transfer-Encoding") == "chunked") { + // TODO + //m_body_encoding = body_encoding::chunked; + return false; + } else { + return false; } +} - return true; +inline size_t parser::process_body(char const * buf, size_t len) { + if (m_body_encoding == body_encoding::plain) { + size_t processed = (std::min)(m_body_bytes_needed,len); + m_body.append(buf,processed); + m_body_bytes_needed -= processed; + return processed; + } else if (m_body_encoding == body_encoding::chunked) { + // TODO: + throw exception("Unexpected body encoding", + status_code::internal_server_error); + } else { + throw exception("Unexpected body encoding", + status_code::internal_server_error); + } } inline void parser::process_header(std::string::iterator begin, diff --git a/src/third_party/websocketpp/websocketpp/http/impl/request.hpp b/src/third_party/websocketpp/websocketpp/http/impl/request.hpp index f7cad4f5..58162955 100644 --- a/src/third_party/websocketpp/websocketpp/http/impl/request.hpp +++ b/src/third_party/websocketpp/websocketpp/http/impl/request.hpp @@ -30,6 +30,7 @@ #include #include +#include #include @@ -37,35 +38,18 @@ namespace websocketpp { namespace http { namespace parser { -inline bool request::parse_complete(std::istream& s) { - std::string req; - - // get status line - std::getline(s, req); - - if (req[req.size()-1] == '\r') { - req.erase(req.end()-1); - - std::stringstream ss(req); - std::string val; - - ss >> val; - set_method(val); - - ss >> val; - set_uri(val); - - ss >> val; - set_version(val); - } else { - return false; - } - - return parse_headers(s); -} - -inline size_t request::consume(const char *buf, size_t len) { +inline size_t request::consume(char const * buf, size_t len) { + size_t bytes_processed; + if (m_ready) {return 0;} + + if (m_body_bytes_needed > 0) { + bytes_processed = process_body(buf,len); + if (body_ready()) { + m_ready = true; + } + return bytes_processed; + } if (m_buf->size() + len > max_header_size) { // exceeded max header size @@ -107,9 +91,8 @@ inline size_t request::consume(const char *buf, size_t len) { if (m_method.empty() || get_header("Host") == "") { throw exception("Incomplete Request",status_code::bad_request); } - m_ready = true; - size_t bytes_processed = ( + bytes_processed = ( len - static_cast(m_buf->end()-end) + sizeof(header_delimiter) - 1 ); @@ -117,8 +100,22 @@ inline size_t request::consume(const char *buf, size_t len) { // frees memory used temporarily during request parsing m_buf.reset(); - // return number of bytes processed (starting bytes - bytes left) - return bytes_processed; + // if this was not an upgrade request and has a content length + // continue capturing content-length bytes and expose them as a + // request body. + + if (prepare_body()) { + bytes_processed += process_body(buf+bytes_processed,len-bytes_processed); + if (body_ready()) { + m_ready = true; + } + return bytes_processed; + } else { + m_ready = true; + + // return number of bytes processed (starting bytes - bytes left) + return bytes_processed; + } } else { if (m_method.empty()) { this->process(begin,end); @@ -131,7 +128,7 @@ inline size_t request::consume(const char *buf, size_t len) { } } -inline std::string request::raw() { +inline std::string request::raw() const { // TODO: validation. Make sure all required fields have been set? std::stringstream ret; @@ -141,7 +138,17 @@ inline std::string request::raw() { return ret.str(); } -inline void request::set_method(const std::string& method) { +inline std::string request::raw_head() const { + // TODO: validation. Make sure all required fields have been set? + std::stringstream ret; + + ret << m_method << " " << m_uri << " " << get_version() << "\r\n"; + ret << raw_headers() << "\r\n"; + + return ret.str(); +} + +inline void request::set_method(std::string const & method) { if (std::find_if(method.begin(),method.end(),is_not_token_char) != method.end()) { throw exception("Invalid method token.",status_code::bad_request); } @@ -149,14 +156,7 @@ inline void request::set_method(const std::string& method) { m_method = method; } -/// Set HTTP body -/** - * Sets the body of the HTTP object and fills in the appropriate content length - * header - * - * @param value The value to set the body to. - */ -inline void request::set_uri(const std::string& uri) { +inline void request::set_uri(std::string const & uri) { // TODO: validation? m_uri = uri; } diff --git a/src/third_party/websocketpp/websocketpp/http/impl/response.hpp b/src/third_party/websocketpp/websocketpp/http/impl/response.hpp index 6a99e81c..4bc9de54 100644 --- a/src/third_party/websocketpp/websocketpp/http/impl/response.hpp +++ b/src/third_party/websocketpp/websocketpp/http/impl/response.hpp @@ -29,7 +29,9 @@ #define HTTP_PARSER_RESPONSE_IMPL_HPP #include +#include #include +#include #include @@ -37,7 +39,7 @@ namespace websocketpp { namespace http { namespace parser { -inline size_t response::consume(const char *buf, size_t len) { +inline size_t response::consume(char const * buf, size_t len) { if (m_state == DONE) {return 0;} if (m_state == BODY) { @@ -170,34 +172,6 @@ inline size_t response::consume(std::istream & s) { return total; } -inline bool response::parse_complete(std::istream& s) { - // parse a complete header (ie \r\n\r\n MUST be in the input stream) - std::string line; - - // get status line - std::getline(s, line); - - if (line[line.size()-1] == '\r') { - line.erase(line.end()-1); - - std::stringstream ss(line); - std::string str_val; - int int_val; - char char_val[256]; - - ss >> str_val; - set_version(str_val); - - ss >> int_val; - ss.getline(char_val,256); - set_status(status_code::value(int_val),std::string(char_val)); - } else { - return false; - } - - return parse_headers(s); -} - inline std::string response::raw() const { // TODO: validation. Make sure all required fields have been set? @@ -217,7 +191,7 @@ inline void response::set_status(status_code::value code) { m_status_msg = get_string(code); } -inline void response::set_status(status_code::value code, const std::string& +inline void response::set_status(status_code::value code, std::string const & msg) { // TODO: validation? @@ -255,7 +229,7 @@ inline void response::process(std::string::iterator begin, set_status(status_code::value(code),std::string(cursor_end+1,end)); } -inline size_t response::process_body(const char *buf, size_t len) { +inline size_t response::process_body(char const * buf, size_t len) { // If no content length was set then we read forever and never set m_ready if (m_read == 0) { //m_body.append(buf,len); diff --git a/src/third_party/websocketpp/websocketpp/http/parser.hpp b/src/third_party/websocketpp/websocketpp/http/parser.hpp index cc81f63c..eb7ac144 100644 --- a/src/third_party/websocketpp/websocketpp/http/parser.hpp +++ b/src/third_party/websocketpp/websocketpp/http/parser.hpp @@ -29,8 +29,9 @@ #define HTTP_PARSER_HPP #include -#include #include +#include +#include #include #include @@ -48,6 +49,14 @@ namespace state { }; } +namespace body_encoding { + enum value { + unknown, + plain, + chunked + }; +} + typedef std::map header_list; /// Read and return the next token in the stream @@ -384,6 +393,11 @@ inline std::string strip_lws(std::string const & input) { */ class parser { public: + parser() + : m_body_bytes_needed(0) + , m_body_bytes_max(max_body_size) + , m_body_encoding(body_encoding::unknown) {} + /// Get the HTTP version string /** * @return The version string for this parser @@ -467,12 +481,11 @@ public: */ void remove_header(std::string const & key); - /// Set HTTP body + /// Get HTTP body /** - * Sets the body of the HTTP object and fills in the appropriate content - * length header. + * Gets the body of the HTTP object * - * @param [in] value The value to set the body to. + * @return The body of the HTTP message. */ std::string const & get_body() const { return m_body; @@ -489,6 +502,32 @@ public: */ void set_body(std::string const & value); + /// Get body size limit + /** + * Retrieves the maximum number of bytes to parse & buffer before canceling + * a request. + * + * @since 0.5.0 + * + * @return The maximum length of a message body. + */ + size_t get_max_body_size() const { + return m_body_bytes_max; + } + + /// Set body size limit + /** + * Set the maximum number of bytes to parse and buffer before canceling a + * request. + * + * @since 0.5.0 + * + * @param value The size to set the max body length to. + */ + void set_max_body_size(size_t value) { + m_body_bytes_max = value; + } + /// Extract an HTTP parameter list from a string. /** * @param [in] in The input string. @@ -498,14 +537,6 @@ public: bool parse_parameter_list(std::string const & in, parameter_list & out) const; protected: - /// Parse headers from an istream - /** - * @deprecated Use process_header instead. - * - * @param [in] s The istream to extract headers from. - */ - bool parse_headers(std::istream & s); - /// Process a header line /** * @todo Update this method to be exception free. @@ -515,6 +546,45 @@ protected: */ void process_header(std::string::iterator begin, std::string::iterator end); + /// Prepare the parser to begin parsing body data + /** + * Inspects headers to determine if the message has a body that needs to be + * read. If so, sets up the necessary state, otherwise returns false. If + * this method returns true and loading the message body is desired call + * `process_body` until it returns zero bytes or an error. + * + * Must not be called until after all headers have been processed. + * + * @since 0.5.0 + * + * @return True if more bytes are needed to load the body, false otherwise. + */ + bool prepare_body(); + + /// Process body data + /** + * Parses body data. + * + * @since 0.5.0 + * + * @param [in] begin An iterator to the beginning of the sequence. + * @param [in] end An iterator to the end of the sequence. + * @return The number of bytes processed + */ + size_t process_body(char const * buf, size_t len); + + /// Check if the parser is done parsing the body + /** + * Behavior before a call to `prepare_body` is undefined. + * + * @since 0.5.0 + * + * @return True if the message body has been completed loaded. + */ + bool body_ready() const { + return (m_body_bytes_needed == 0); + } + /// Generate and return the HTTP headers as a string /** * Each headers will be followed by the \r\n sequence including the last one. @@ -526,7 +596,11 @@ protected: std::string m_version; header_list m_headers; - std::string m_body; + + std::string m_body; + size_t m_body_bytes_needed; + size_t m_body_bytes_max; + body_encoding::value m_body_encoding; }; } // namespace parser diff --git a/src/third_party/websocketpp/websocketpp/http/request.hpp b/src/third_party/websocketpp/websocketpp/http/request.hpp index 4a5990ac..3355c99b 100644 --- a/src/third_party/websocketpp/websocketpp/http/request.hpp +++ b/src/third_party/websocketpp/websocketpp/http/request.hpp @@ -28,6 +28,8 @@ #ifndef HTTP_PARSER_REQUEST_HPP #define HTTP_PARSER_REQUEST_HPP +#include + #include #include @@ -54,9 +56,6 @@ public: : m_buf(lib::make_shared()) , m_ready(false) {} - /// DEPRECATED parse a complete header (\r\n\r\n MUST be in the istream) - bool parse_complete(std::istream& s); - /// Process bytes in the input buffer /** * Process up to len bytes from input buffer buf. Returns the number of @@ -77,29 +76,32 @@ public: * @param len Size of byte buffer * @return Number of bytes processed. */ - size_t consume(const char *buf, size_t len); + size_t consume(char const * buf, size_t len); /// Returns whether or not the request is ready for reading. bool ready() const { return m_ready; } - /// Returns the full raw request - std::string raw(); + /// Returns the full raw request (including the body) + std::string raw() const; + + /// Returns the raw request headers only (similar to an HTTP HEAD request) + std::string raw_head() const; /// Set the HTTP method. Must be a valid HTTP token - void set_method(const std::string& method); + void set_method(std::string const & method); /// Return the request method - const std::string& get_method() const { + std::string const & get_method() const { return m_method; } /// Set the HTTP uri. Must be a valid HTTP uri - void set_uri(const std::string& uri); + void set_uri(std::string const & uri); /// Return the requested URI - const std::string& get_uri() const { + std::string const & get_uri() const { return m_uri; } diff --git a/src/third_party/websocketpp/websocketpp/http/response.hpp b/src/third_party/websocketpp/websocketpp/http/response.hpp index 3825a558..e724a3d3 100644 --- a/src/third_party/websocketpp/websocketpp/http/response.hpp +++ b/src/third_party/websocketpp/websocketpp/http/response.hpp @@ -28,6 +28,9 @@ #ifndef HTTP_PARSER_RESPONSE_HPP #define HTTP_PARSER_RESPONSE_HPP +#include +#include + #include namespace websocketpp { @@ -82,8 +85,28 @@ public: * @param len Size of byte buffer * @return Number of bytes processed. */ - size_t consume(const char *buf, size_t len); + size_t consume(char const * buf, size_t len); + /// Process bytes in the input buffer (istream version) + /** + * Process bytes from istream s. Returns the number of bytes processed. + * Bytes left unprocessed means bytes left over after the final header + * delimiters. + * + * Consume is a streaming processor. It may be called multiple times on one + * response and the full headers need not be available before processing can + * begin. If the end of the response was reached during this call to consume + * the ready flag will be set. Further calls to consume once ready will be + * ignored. + * + * Consume will throw an http::exception in the case of an error. Typical + * error reasons include malformed responses, incomplete responses, and max + * header size being reached. + * + * @param buf Pointer to byte buffer + * @param len Size of byte buffer + * @return Number of bytes processed. + */ size_t consume(std::istream & s); /// Returns true if the response is ready. @@ -99,9 +122,6 @@ public: return (m_state == BODY || m_state == DONE); } - /// DEPRECATED parse a complete response from a pre-delimited istream - bool parse_complete(std::istream& s); - /// Returns the full raw response std::string raw() const; @@ -126,7 +146,7 @@ public: * @param code Code to set * @param msg Message to set */ - void set_status(status_code::value code, const std::string& msg); + void set_status(status_code::value code, std::string const & msg); /// Return the response status code status_code::value get_status_code() const { @@ -142,7 +162,7 @@ private: void process(std::string::iterator begin, std::string::iterator end); /// Helper function for processing body bytes - size_t process_body(const char *buf, size_t len); + size_t process_body(char const * buf, size_t len); enum state { RESPONSE_LINE = 0, diff --git a/src/third_party/websocketpp/websocketpp/impl/connection_impl.hpp b/src/third_party/websocketpp/websocketpp/impl/connection_impl.hpp index 1f29f4ef..55832d01 100644 --- a/src/third_party/websocketpp/websocketpp/impl/connection_impl.hpp +++ b/src/third_party/websocketpp/websocketpp/impl/connection_impl.hpp @@ -28,16 +28,23 @@ #ifndef WEBSOCKETPP_CONNECTION_IMPL_HPP #define WEBSOCKETPP_CONNECTION_IMPL_HPP -#include -#include - -#include - #include #include #include #include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include + namespace websocketpp { namespace istate = session::internal_state; @@ -55,7 +62,7 @@ void connection::set_termination_handler( } template -const std::string& connection::get_origin() const { +std::string const & connection::get_origin() const { //scoped_lock_type lock(m_connection_state_lock); return m_processor->get_origin(m_request); } @@ -73,7 +80,7 @@ session::state::value connection::get_state() const { } template -lib::error_code connection::send(const std::string& payload, +lib::error_code connection::send(std::string const & payload, frame::opcode::value op) { message_ptr msg = m_msg_manager->get_message(op,payload.size()); @@ -83,7 +90,7 @@ lib::error_code connection::send(const std::string& payload, } template -lib::error_code connection::send(const void* payload, size_t len, +lib::error_code connection::send(void const * payload, size_t len, frame::opcode::value op) { message_ptr msg = m_msg_manager->get_message(op,len); @@ -98,10 +105,12 @@ lib::error_code connection::send(typename config::message_type::ptr msg) if (m_alog.static_test(log::alevel::devel)) { m_alog.write(log::alevel::devel,"connection send"); } - // TODO: - if (m_state != session::state::open) { - return error::make_error_code(error::invalid_state); + { + scoped_lock_type lock(m_connection_state_lock); + if (m_state != session::state::open) { + return error::make_error_code(error::invalid_state); + } } message_ptr outgoing_msg; @@ -142,14 +151,20 @@ lib::error_code connection::send(typename config::message_type::ptr msg) } template -void connection::ping(const std::string& payload, lib::error_code& ec) { +void connection::ping(std::string const& payload, lib::error_code& ec) { if (m_alog.static_test(log::alevel::devel)) { m_alog.write(log::alevel::devel,"connection ping"); } - if (m_state != session::state::open) { - ec = error::make_error_code(error::invalid_state); - return; + { + scoped_lock_type lock(m_connection_state_lock); + if (m_state != session::state::open) { + std::stringstream ss; + ss << "connection::ping called from invalid state " << m_state; + m_alog.write(log::alevel::devel,ss.str()); + ec = error::make_error_code(error::invalid_state); + return; + } } message_ptr msg = m_msg_manager->get_message(); @@ -233,14 +248,20 @@ void connection::handle_pong_timeout(std::string payload, } template -void connection::pong(const std::string& payload, lib::error_code& ec) { +void connection::pong(std::string const& payload, lib::error_code& ec) { if (m_alog.static_test(log::alevel::devel)) { m_alog.write(log::alevel::devel,"connection pong"); } - if (m_state != session::state::open) { - ec = error::make_error_code(error::invalid_state); - return; + { + scoped_lock_type lock(m_connection_state_lock); + if (m_state != session::state::open) { + std::stringstream ss; + ss << "connection::pong called from invalid state " << m_state; + m_alog.write(log::alevel::devel,ss.str()); + ec = error::make_error_code(error::invalid_state); + return; + } } message_ptr msg = m_msg_manager->get_message(); @@ -286,15 +307,17 @@ void connection::close(close::status::value const code, m_alog.write(log::alevel::devel,"connection close"); } + // Truncate reason to maximum size allowable in a close frame. + std::string tr(reason,0,std::min(reason.size(), + frame::limits::close_reason_size)); + + scoped_lock_type lock(m_connection_state_lock); + if (m_state != session::state::open) { ec = error::make_error_code(error::invalid_state); return; } - // Truncate reason to maximum size allowable in a close frame. - std::string tr(reason,0,std::min(reason.size(), - frame::limits::close_reason_size)); - ec = this->send_close_frame(code,tr,false,close::status::terminal(code)); } @@ -385,13 +408,13 @@ bool connection::get_secure() const { } template -const std::string& connection::get_host() const { +std::string const & connection::get_host() const { //scoped_lock_type lock(m_connection_state_lock); return m_uri->get_host(); } template -const std::string& connection::get_resource() const { +std::string const & connection::get_resource() const { //scoped_lock_type lock(m_connection_state_lock); return m_uri->get_resource(); } @@ -420,12 +443,12 @@ void connection::set_uri(uri_ptr uri) { template -const std::string & connection::get_subprotocol() const { +std::string const & connection::get_subprotocol() const { return m_subprotocol; } template -const std::vector & +std::vector const & connection::get_requested_subprotocols() const { return m_requested_subprotocols; } @@ -499,35 +522,36 @@ void connection::select_subprotocol(std::string const & value) { template -const std::string & -connection::get_request_header(std::string const & key) { +std::string const & +connection::get_request_header(std::string const & key) const { return m_request.get_header(key); } template -const std::string & -connection::get_response_header(std::string const & key) { +std::string const & +connection::get_request_body() const { + return m_request.get_body(); +} + +template +std::string const & +connection::get_response_header(std::string const & key) const { return m_response.get_header(key); } template void connection::set_status(http::status_code::value code) { - //scoped_lock_type lock(m_connection_state_lock); - if (m_internal_state != istate::PROCESS_HTTP_REQUEST) { throw exception("Call to set_status from invalid state", error::make_error_code(error::invalid_state)); } - m_response.set_status(code); } template void connection::set_status(http::status_code::value code, std::string const & msg) { - //scoped_lock_type lock(m_connection_state_lock); - if (m_internal_state != istate::PROCESS_HTTP_REQUEST) { throw exception("Call to set_status from invalid state", error::make_error_code(error::invalid_state)); @@ -537,8 +561,6 @@ void connection::set_status(http::status_code::value code, } template void connection::set_body(std::string const & value) { - //scoped_lock_type lock(m_connection_state_lock); - if (m_internal_state != istate::PROCESS_HTTP_REQUEST) { throw exception("Call to set_status from invalid state", error::make_error_code(error::invalid_state)); @@ -551,8 +573,6 @@ template void connection::append_header(std::string const & key, std::string const & val) { - //scoped_lock_type lock(m_connection_state_lock); - if (m_is_server) { if (m_internal_state == istate::PROCESS_HTTP_REQUEST) { // we are setting response headers for an incoming server connection @@ -575,8 +595,6 @@ template void connection::replace_header(std::string const & key, std::string const & val) { - // scoped_lock_type lock(m_connection_state_lock); - if (m_is_server) { if (m_internal_state == istate::PROCESS_HTTP_REQUEST) { // we are setting response headers for an incoming server connection @@ -598,8 +616,6 @@ void connection::replace_header(std::string const & key, template void connection::remove_header(std::string const & key) { - //scoped_lock_type lock(m_connection_state_lock); - if (m_is_server) { if (m_internal_state == istate::PROCESS_HTTP_REQUEST) { // we are setting response headers for an incoming server connection @@ -630,11 +646,13 @@ template void connection::start() { m_alog.write(log::alevel::devel,"connection start"); - this->atomic_state_change( - istate::USER_INIT, - istate::TRANSPORT_INIT, - "Start must be called from user init state" - ); + if (m_internal_state != istate::USER_INIT) { + m_alog.write(log::alevel::devel,"Start called in invalid state"); + this->terminate(error::make_error_code(error::invalid_state)); + return; + } + + m_internal_state = istate::TRANSPORT_INIT; // Depending on how the transport implements init this function may return // immediately and call handle_transport_init later or call @@ -652,39 +670,31 @@ template void connection::handle_transport_init(lib::error_code const & ec) { m_alog.write(log::alevel::devel,"connection handle_transport_init"); - { - scoped_lock_type lock(m_connection_state_lock); + lib::error_code ecm = ec; - if (m_internal_state != istate::TRANSPORT_INIT) { - throw exception("handle_transport_init must be called from transport init state", - error::make_error_code(error::invalid_state)); - } - - if (!ec) { - // unless there was a transport error, advance internal state. - if (m_is_server) { - m_internal_state = istate::READ_HTTP_REQUEST; - } else { - m_internal_state = istate::WRITE_HTTP_REQUEST; - } - } + if (m_internal_state != istate::TRANSPORT_INIT) { + m_alog.write(log::alevel::devel, + "handle_transport_init must be called from transport init state"); + ecm = error::make_error_code(error::invalid_state); } - if (ec) { + if (ecm) { std::stringstream s; - s << "handle_transport_init received error: "<< ec.message(); - m_elog.write(log::elevel::fatal,s.str()); + s << "handle_transport_init received error: "<< ecm.message(); + m_elog.write(log::elevel::rerror,s.str()); - this->terminate(ec); + this->terminate(ecm); return; } // At this point the transport is ready to read and write bytes. if (m_is_server) { + m_internal_state = istate::READ_HTTP_REQUEST; this->read_handshake(1); } else { // We are a client. Set the processor to the version specified in the // config file and send a handshake request. + m_internal_state = istate::WRITE_HTTP_REQUEST; m_processor = get_processor(config::client_version); this->send_http_request(); } @@ -726,24 +736,37 @@ void connection::handle_read_handshake(lib::error_code const & ec, { m_alog.write(log::alevel::devel,"connection handle_read_handshake"); - this->atomic_state_check( - istate::READ_HTTP_REQUEST, - "handle_read_handshake must be called from READ_HTTP_REQUEST state" - ); + lib::error_code ecm = ec; - if (ec) { - if (ec == transport::error::eof) { - // we expect to get eof if the connection is closed already - if (m_state == session::state::closed) { - m_alog.write(log::alevel::devel,"got eof from closed con"); - return; - } + if (!ecm) { + scoped_lock_type lock(m_connection_state_lock); + + if (m_state == session::state::connecting) { + if (m_internal_state != istate::READ_HTTP_REQUEST) { + ecm = error::make_error_code(error::invalid_state); + } + } else if (m_state == session::state::closed) { + // The connection was canceled while the response was being sent, + // usually by the handshake timer. This is basically expected + // (though hopefully rare) and there is nothing we can do so ignore. + m_alog.write(log::alevel::devel, + "handle_read_handshake invoked after connection was closed"); + return; + } else { + ecm = error::make_error_code(error::invalid_state); } + } - std::stringstream s; - s << "error in handle_read_handshake: "<< ec.message(); - m_elog.write(log::elevel::fatal,s.str()); - this->terminate(ec); + if (ecm) { + if (ecm == transport::error::eof && m_state == session::state::closed) { + // we expect to get eof if the connection is closed already + m_alog.write(log::alevel::devel, + "got (expected) eof/state error from closed con"); + return; + } + + log_err(log::elevel::rerror,"handle_read_handshake",ecm); + this->terminate(ecm); return; } @@ -761,13 +784,13 @@ void connection::handle_read_handshake(lib::error_code const & ec, // All HTTP exceptions will result in this request failing and an error // response being returned. No more bytes will be read in this con. m_response.set_status(e.m_error_code,e.m_error_msg); - this->send_http_response_error(); + this->send_http_response_error(error::make_error_code(error::http_parse_error)); return; } // More paranoid boundaries checking. // TODO: Is this overkill? - if (bytes_processed > config::connection_read_buffer_size) { + if (bytes_processed > bytes_transferred) { m_elog.write(log::elevel::fatal,"Fatal boundaries checking error."); this->terminate(make_error_code(error::general)); return; @@ -781,8 +804,9 @@ void connection::handle_read_handshake(lib::error_code const & ec, } if (m_request.ready()) { - if (!this->initialize_processor()) { - this->send_http_response_error(); + lib::error_code processor_ec = this->initialize_processor(); + if (processor_ec) { + this->send_http_response_error(processor_ec); return; } @@ -799,7 +823,7 @@ void connection::handle_read_handshake(lib::error_code const & ec, // TODO: need more bytes m_alog.write(log::alevel::devel,"short key3 read"); m_response.set_status(http::status_code::internal_server_error); - this->send_http_response_error(); + this->send_http_response_error(processor::error::make_error_code(processor::error::short_key3)); return; } } @@ -818,15 +842,12 @@ void connection::handle_read_handshake(lib::error_code const & ec, std::copy(m_buf+bytes_processed,m_buf+bytes_transferred,m_buf); m_buf_cursor = bytes_transferred-bytes_processed; - this->atomic_state_change( - istate::READ_HTTP_REQUEST, - istate::PROCESS_HTTP_REQUEST, - "send_http_response must be called from READ_HTTP_REQUEST state" - ); + m_internal_state = istate::PROCESS_HTTP_REQUEST; + // We have the complete request. Process it. - this->process_handshake_request(); - this->send_http_response(); + lib::error_code handshake_ec = this->process_handshake_request(); + this->send_http_response(handshake_ec); } else { // read at least 1 more byte transport_con_type::async_read_at_least( @@ -849,13 +870,17 @@ void connection::handle_read_handshake(lib::error_code const & ec, // sure if the hybi00 key3 bytes need to be read). This method sets the correct // state and calls send_http_response template -void connection::send_http_response_error() { - this->atomic_state_change( - istate::READ_HTTP_REQUEST, - istate::PROCESS_HTTP_REQUEST, - "send_http_response must be called from READ_HTTP_REQUEST state" - ); - this->send_http_response(); +void connection::send_http_response_error(lib::error_code const & ec) { + if (m_internal_state != istate::READ_HTTP_REQUEST) { + m_alog.write(log::alevel::devel, + "send_http_response_error called in invalid state"); + this->terminate(error::make_error_code(error::invalid_state)); + return; + } + + m_internal_state = istate::PROCESS_HTTP_REQUEST; + + this->send_http_response(ec); } // All exit paths for this function need to call send_http_response() or submit @@ -866,15 +891,16 @@ void connection::handle_read_frame(lib::error_code const & ec, { //m_alog.write(log::alevel::devel,"connection handle_read_frame"); - this->atomic_state_check( - istate::PROCESS_CONNECTION, - "handle_read_frame must be called from PROCESS_CONNECTION state" - ); + lib::error_code ecm = ec; - if (ec) { - log::level echannel = log::elevel::fatal; + if (!ecm && m_internal_state != istate::PROCESS_CONNECTION) { + ecm = error::make_error_code(error::invalid_state); + } + + if (ecm) { + log::level echannel = log::elevel::rerror; - if (ec == transport::error::eof) { + if (ecm == transport::error::eof) { if (m_state == session::state::closed) { // we expect to get eof if the connection is closed already // just ignore it @@ -887,8 +913,17 @@ void connection::handle_read_frame(lib::error_code const & ec, terminate(lib::error_code()); return; } - } - if (ec == transport::error::tls_short_read) { + } else if (ecm == error::invalid_state) { + // In general, invalid state errors in the closed state are the + // result of handlers that were in the system already when the state + // changed and should be ignored as they pose no problems and there + // is nothing useful that we can do about them. + if (m_state == session::state::closed) { + m_alog.write(log::alevel::devel, + "handle_read_frame: got invalid istate in closed state"); + return; + } + } else if (ecm == transport::error::tls_short_read) { if (m_state == session::state::closed) { // We expect to get a TLS short read if we try to read after the // connection is closed. If this happens ignore and exit the @@ -897,12 +932,12 @@ void connection::handle_read_frame(lib::error_code const & ec, return; } echannel = log::elevel::rerror; - } else if (ec == transport::error::action_after_shutdown) { + } else if (ecm == transport::error::action_after_shutdown) { echannel = log::elevel::info; } - log_err(echannel, "handle_read_frame", ec); - this->terminate(ec); + log_err(echannel, "handle_read_frame", ecm); + this->terminate(ecm); return; } @@ -1014,12 +1049,12 @@ void connection::read_frame() { } template -bool connection::initialize_processor() { +lib::error_code connection::initialize_processor() { m_alog.write(log::alevel::devel,"initialize_processor"); // if it isn't a websocket handshake nothing to do. if (!processor::is_websocket_handshake(m_request)) { - return true; + return lib::error_code(); } int version = processor::get_websocket_version(m_request); @@ -1027,14 +1062,14 @@ bool connection::initialize_processor() { if (version < 0) { m_alog.write(log::alevel::devel, "BAD REQUEST: can't determine version"); m_response.set_status(http::status_code::bad_request); - return false; + return error::make_error_code(error::invalid_version); } m_processor = get_processor(version); // if the processor is not null we are done if (m_processor) { - return true; + return lib::error_code(); } // We don't have a processor for this version. Return bad request @@ -1052,11 +1087,11 @@ bool connection::initialize_processor() { } m_response.replace_header("Sec-WebSocket-Version",ss.str()); - return false; + return error::make_error_code(error::unsupported_version); } template -bool connection::process_handshake_request() { +lib::error_code connection::process_handshake_request() { m_alog.write(log::alevel::devel,"process handshake request"); if (!processor::is_websocket_handshake(m_request)) { @@ -1072,16 +1107,21 @@ bool connection::process_handshake_request() { if (!m_uri->get_valid()) { m_alog.write(log::alevel::devel, "Bad request: failed to parse uri"); m_response.set_status(http::status_code::bad_request); - return false; + return error::make_error_code(error::invalid_uri); } if (m_http_handler) { + m_is_http = true; m_http_handler(m_connection_hdl); + if (m_state == session::state::closed) { + return error::make_error_code(error::http_connection_ended); + } } else { set_status(http::status_code::upgrade_required); + return error::make_error_code(error::upgrade_required); } - return true; + return lib::error_code(); } lib::error_code ec = m_processor->validate_handshake(m_request); @@ -1091,7 +1131,7 @@ bool connection::process_handshake_request() { // Not a valid handshake request m_alog.write(log::alevel::devel, "Bad request " + ec.message()); m_response.set_status(http::status_code::bad_request); - return false; + return ec; } // Read extension parameters and set up values necessary for the end user @@ -1104,7 +1144,7 @@ bool connection::process_handshake_request() { // a failed connection attempt. m_alog.write(log::alevel::devel, "Bad request: " + neg_results.first.message()); m_response.set_status(http::status_code::bad_request); - return false; + return neg_results.first; } else { // extension negotiation succeeded, set response header accordingly // we don't send an empty extensions header because it breaks many @@ -1122,7 +1162,7 @@ bool connection::process_handshake_request() { if (!m_uri->get_valid()) { m_alog.write(log::alevel::devel, "Bad request: failed to parse uri"); m_response.set_status(http::status_code::bad_request); - return false; + return error::make_error_code(error::invalid_uri); } // extract subprotocols @@ -1147,7 +1187,7 @@ bool connection::process_handshake_request() { m_alog.write(log::alevel::devel, s.str()); m_response.set_status(http::status_code::internal_server_error); - return false; + return ec; } } else { // User application has rejected the handshake @@ -1159,19 +1199,27 @@ bool connection::process_handshake_request() { if (m_response.get_status_code() == http::status_code::uninitialized) { m_response.set_status(http::status_code::bad_request); } - - return false; + + return error::make_error_code(error::rejected); } - return true; + return lib::error_code(); } template -void connection::send_http_response() { +void connection::send_http_response(lib::error_code const & ec) { m_alog.write(log::alevel::devel,"connection send_http_response"); + if (ec == error::make_error_code(error::http_connection_ended)) { + m_alog.write(log::alevel::http,"An HTTP handler took over the connection."); + return; + } + if (m_response.get_status_code() == http::status_code::uninitialized) { m_response.set_status(http::status_code::internal_server_error); + m_ec = error::make_error_code(error::general); + } else { + m_ec = ec; } m_response.set_version("HTTP/1.1"); @@ -1217,18 +1265,39 @@ template void connection::handle_send_http_response(lib::error_code const & ec) { m_alog.write(log::alevel::devel,"handle_send_http_response"); - this->atomic_state_check( - istate::PROCESS_HTTP_REQUEST, - "handle_send_http_response must be called from PROCESS_HTTP_REQUEST state" - ); + lib::error_code ecm = ec; - if (ec) { - log_err(log::elevel::rerror,"handle_send_http_response",ec); - this->terminate(ec); - return; + if (!ecm) { + scoped_lock_type lock(m_connection_state_lock); + + if (m_state == session::state::connecting) { + if (m_internal_state != istate::PROCESS_HTTP_REQUEST) { + ecm = error::make_error_code(error::invalid_state); + } + } else if (m_state == session::state::closed) { + // The connection was canceled while the response was being sent, + // usually by the handshake timer. This is basically expected + // (though hopefully rare) and there is nothing we can do so ignore. + m_alog.write(log::alevel::devel, + "handle_send_http_response invoked after connection was closed"); + return; + } else { + ecm = error::make_error_code(error::invalid_state); + } } - this->log_open_result(); + if (ecm) { + if (ecm == transport::error::eof && m_state == session::state::closed) { + // we expect to get eof if the connection is closed already + m_alog.write(log::alevel::devel, + "got (expected) eof/state error from closed con"); + return; + } + + log_err(log::elevel::rerror,"handle_send_http_response",ecm); + this->terminate(ecm); + return; + } if (m_handshake_timer) { m_handshake_timer->cancel(); @@ -1237,8 +1306,11 @@ void connection::handle_send_http_response(lib::error_code const & ec) { if (m_response.get_status_code() != http::status_code::switching_protocols) { - if (m_processor) { - // this was a websocket connection that ended in an error + /*if (m_processor || m_ec == error::http_parse_error || + m_ec == error::invalid_version || m_ec == error::unsupported_version + || m_ec == error::upgrade_required) + {*/ + if (!m_is_http) { std::stringstream s; s << "Handshake ended with HTTP error: " << m_response.get_status_code(); @@ -1246,18 +1318,24 @@ void connection::handle_send_http_response(lib::error_code const & ec) { } else { // if this was not a websocket connection, we have written // the expected response and the connection can be closed. - } - this->terminate(make_error_code(error::http_connection_ended)); + + this->log_http_result(); + + if (m_ec) { + m_alog.write(log::alevel::devel, + "got to writing HTTP results with m_ec set: "+m_ec.message()); + } + m_ec = make_error_code(error::http_connection_ended); + } + + this->terminate(m_ec); return; } - this->atomic_state_change( - istate::PROCESS_HTTP_REQUEST, - istate::PROCESS_CONNECTION, - session::state::connecting, - session::state::open, - "handle_send_http_response must be called from PROCESS_HTTP_REQUEST state" - ); + this->log_open_result(); + + m_internal_state = istate::PROCESS_CONNECTION; + m_state = session::state::open; if (m_open_handler) { m_open_handler(m_connection_hdl); @@ -1329,22 +1407,41 @@ template void connection::handle_send_http_request(lib::error_code const & ec) { m_alog.write(log::alevel::devel,"handle_send_http_request"); - this->atomic_state_check( - istate::WRITE_HTTP_REQUEST, - "handle_send_http_request must be called from WRITE_HTTP_REQUEST state" - ); + lib::error_code ecm = ec; - if (ec) { - log_err(log::elevel::rerror,"handle_send_http_request",ec); - this->terminate(ec); - return; + if (!ecm) { + scoped_lock_type lock(m_connection_state_lock); + + if (m_state == session::state::connecting) { + if (m_internal_state != istate::WRITE_HTTP_REQUEST) { + ecm = error::make_error_code(error::invalid_state); + } else { + m_internal_state = istate::READ_HTTP_RESPONSE; + } + } else if (m_state == session::state::closed) { + // The connection was canceled while the response was being sent, + // usually by the handshake timer. This is basically expected + // (though hopefully rare) and there is nothing we can do so ignore. + m_alog.write(log::alevel::devel, + "handle_send_http_request invoked after connection was closed"); + return; + } else { + ecm = error::make_error_code(error::invalid_state); + } } - this->atomic_state_change( - istate::WRITE_HTTP_REQUEST, - istate::READ_HTTP_RESPONSE, - "handle_send_http_request must be called from WRITE_HTTP_REQUEST state" - ); + if (ecm) { + if (ecm == transport::error::eof && m_state == session::state::closed) { + // we expect to get eof if the connection is closed already + m_alog.write(log::alevel::devel, + "got (expected) eof/state error from closed con"); + return; + } + + log_err(log::elevel::rerror,"handle_send_http_request",ecm); + this->terminate(ecm); + return; + } transport_con_type::async_read_at_least( 1, @@ -1365,16 +1462,40 @@ void connection::handle_read_http_response(lib::error_code const & ec, { m_alog.write(log::alevel::devel,"handle_read_http_response"); - this->atomic_state_check( - istate::READ_HTTP_RESPONSE, - "handle_read_http_response must be called from READ_HTTP_RESPONSE state" - ); + lib::error_code ecm = ec; - if (ec) { - log_err(log::elevel::rerror,"handle_send_http_response",ec); - this->terminate(ec); + if (!ecm) { + scoped_lock_type lock(m_connection_state_lock); + + if (m_state == session::state::connecting) { + if (m_internal_state != istate::READ_HTTP_RESPONSE) { + ecm = error::make_error_code(error::invalid_state); + } + } else if (m_state == session::state::closed) { + // The connection was canceled while the response was being sent, + // usually by the handshake timer. This is basically expected + // (though hopefully rare) and there is nothing we can do so ignore. + m_alog.write(log::alevel::devel, + "handle_read_http_response invoked after connection was closed"); + return; + } else { + ecm = error::make_error_code(error::invalid_state); + } + } + + if (ecm) { + if (ecm == transport::error::eof && m_state == session::state::closed) { + // we expect to get eof if the connection is closed already + m_alog.write(log::alevel::devel, + "got (expected) eof/state error from closed con"); + return; + } + + log_err(log::elevel::rerror,"handle_read_http_response",ecm); + this->terminate(ecm); return; } + size_t bytes_processed = 0; // TODO: refactor this to use error codes rather than exceptions try { @@ -1404,14 +1525,9 @@ void connection::handle_read_http_response(lib::error_code const & ec, return; } - // response is valid, connection can now be assumed to be open - this->atomic_state_change( - istate::READ_HTTP_RESPONSE, - istate::PROCESS_CONNECTION, - session::state::connecting, - session::state::open, - "handle_read_http_response must be called from READ_HTTP_RESPONSE state" - ); + // response is valid, connection can now be assumed to be open + m_internal_state = istate::PROCESS_CONNECTION; + m_state = session::state::open; this->log_open_result(); @@ -1492,9 +1608,16 @@ void connection::terminate(lib::error_code const & ec) { m_local_close_reason = ec.message(); } + // TODO: does this need a mutex? if (m_state == session::state::connecting) { m_state = session::state::closed; tstat = failed; + + // Log fail result here before socket is shut down and we can't get + // the remote address, etc anymore + if (m_ec != error::http_connection_ended) { + log_fail_result(); + } } else if (m_state != session::state::closed) { m_state = session::state::closed; tstat = closed; @@ -1531,10 +1654,11 @@ void connection::handle_terminate(terminate_status tstat, // clean shutdown if (tstat == failed) { - if (m_fail_handler) { - m_fail_handler(m_connection_hdl); + if (m_ec != error::http_connection_ended) { + if (m_fail_handler) { + m_fail_handler(m_connection_hdl); + } } - log_fail_result(); } else if (tstat == closed) { if (m_close_handler) { m_close_handler(m_connection_hdl); @@ -1629,8 +1753,11 @@ void connection::write_frame() { if (m_alog.static_test(log::alevel::frame_payload)) { if (m_alog.dynamic_test(log::alevel::frame_payload)) { payload << "[" << i << "] (" - << m_current_msgs[i]->get_payload().size() << ") " - << utility::to_hex(m_current_msgs[i]->get_payload()) + << m_current_msgs[i]->get_payload().size() << ") ["<get_opcode()<<"] " + << (m_current_msgs[i]->get_opcode() == frame::opcode::text ? + m_current_msgs[i]->get_payload() : + utility::to_hex(m_current_msgs[i]->get_payload()) + ) << "\n"; } } @@ -1693,45 +1820,7 @@ void connection::handle_write_frame(lib::error_code const & ec) } template -void connection::atomic_state_change(istate_type req, istate_type dest, - std::string msg) -{ - scoped_lock_type lock(m_connection_state_lock); - - if (m_internal_state != req) { - throw exception(msg,error::make_error_code(error::invalid_state)); - } - - m_internal_state = dest; -} - -template -void connection::atomic_state_change(istate_type internal_req, - istate_type internal_dest, session::state::value external_req, - session::state::value external_dest, std::string msg) -{ - scoped_lock_type lock(m_connection_state_lock); - - if (m_internal_state != internal_req || m_state != external_req) { - throw exception(msg,error::make_error_code(error::invalid_state)); - } - - m_internal_state = internal_dest; - m_state = external_dest; -} - -template -void connection::atomic_state_check(istate_type req, std::string msg) -{ - scoped_lock_type lock(m_connection_state_lock); - - if (m_internal_state != req) { - throw exception(msg,error::make_error_code(error::invalid_state)); - } -} - -template -const std::vector& connection::get_supported_versions() const +std::vector const & connection::get_supported_versions() const { return versions_supported; } @@ -2108,9 +2197,69 @@ void connection::log_close_result() template void connection::log_fail_result() { - // TODO: include more information about the connection? - // should this be filed under connect rather than disconnect? - m_alog.write(log::alevel::disconnect,"Failed: "+m_ec.message()); + std::stringstream s; + + int version = processor::get_websocket_version(m_request); + + // Connection Type + s << "WebSocket Connection "; + + // Remote endpoint address & WebSocket version + s << transport_con_type::get_remote_endpoint(); + if (version < 0) { + s << " -"; + } else { + s << " v" << version; + } + + // User Agent + std::string ua = m_request.get_header("User-Agent"); + if (ua == "") { + s << " \"\" "; + } else { + // check if there are any quotes in the user agent + s << " \"" << utility::string_replace_all(ua,"\"","\\\"") << "\" "; + } + + // URI + s << (m_uri ? m_uri->get_resource() : "-"); + + // HTTP Status code + s << " " << m_response.get_status_code(); + + // WebSocket++ error code & reason + s << " " << m_ec << " " << m_ec.message(); + + m_alog.write(log::alevel::fail,s.str()); +} + +template +void connection::log_http_result() { + std::stringstream s; + + if (processor::is_websocket_handshake(m_request)) { + m_alog.write(log::alevel::devel,"Call to log_http_result for WebSocket"); + return; + } + + // Connection Type + s << (m_request.get_header("host") == "" ? "-" : m_request.get_header("host")) + << " " << transport_con_type::get_remote_endpoint() + << " \"" << m_request.get_method() + << " " << (m_uri ? m_uri->get_resource() : "-") + << " " << m_request.get_version() << "\" " << m_response.get_status_code() + << " " << m_response.get_body().size(); + + // User Agent + std::string ua = m_request.get_header("User-Agent"); + if (ua == "") { + s << " \"\" "; + } else { + // check if there are any quotes in the user agent + s << " \"" << utility::string_replace_all(ua,"\"","\\\"") << "\" "; + } + + m_alog.write(log::alevel::http,s.str()); } } // namespace websocketpp diff --git a/src/third_party/websocketpp/websocketpp/impl/endpoint_impl.hpp b/src/third_party/websocketpp/websocketpp/impl/endpoint_impl.hpp index ca2a47e9..5895199a 100644 --- a/src/third_party/websocketpp/websocketpp/impl/endpoint_impl.hpp +++ b/src/third_party/websocketpp/websocketpp/impl/endpoint_impl.hpp @@ -28,6 +28,8 @@ #ifndef WEBSOCKETPP_ENDPOINT_IMPL_HPP #define WEBSOCKETPP_ENDPOINT_IMPL_HPP +#include + namespace websocketpp { template @@ -77,6 +79,7 @@ endpoint::create_connection() { if (m_max_message_size != config::max_message_size) { con->set_max_message_size(m_max_message_size); } + con->set_max_http_body_size(m_max_http_body_size); lib::error_code ec; diff --git a/src/third_party/websocketpp/websocketpp/impl/utilities_impl.hpp b/src/third_party/websocketpp/websocketpp/impl/utilities_impl.hpp index 3682a501..6f86e22f 100644 --- a/src/third_party/websocketpp/websocketpp/impl/utilities_impl.hpp +++ b/src/third_party/websocketpp/websocketpp/impl/utilities_impl.hpp @@ -28,6 +28,9 @@ #ifndef WEBSOCKETPP_UTILITIES_IMPL_HPP #define WEBSOCKETPP_UTILITIES_IMPL_HPP +#include +#include + namespace websocketpp { namespace utility { @@ -37,7 +40,7 @@ inline std::string to_lower(std::string const & in) { return out; } -inline std::string to_hex(const std::string& input) { +inline std::string to_hex(std::string const & input) { std::string output; std::string hex = "0123456789ABCDEF"; @@ -50,7 +53,7 @@ inline std::string to_hex(const std::string& input) { return output; } -inline std::string to_hex(const uint8_t* input,size_t length) { +inline std::string to_hex(uint8_t const * input, size_t length) { std::string output; std::string hex = "0123456789ABCDEF"; @@ -67,8 +70,8 @@ inline std::string to_hex(const char* input,size_t length) { return to_hex(reinterpret_cast(input),length); } -inline std::string string_replace_all(std::string subject, const std::string& - search, const std::string& replace) +inline std::string string_replace_all(std::string subject, std::string const & + search, std::string const & replace) { size_t pos = 0; while((pos = subject.find(search, pos)) != std::string::npos) { diff --git a/src/third_party/websocketpp/websocketpp/logger/basic.hpp b/src/third_party/websocketpp/websocketpp/logger/basic.hpp index 1005774c..95099a83 100644 --- a/src/third_party/websocketpp/websocketpp/logger/basic.hpp +++ b/src/third_party/websocketpp/websocketpp/logger/basic.hpp @@ -40,14 +40,16 @@ * */ -#include -#include -#include +#include #include #include #include -#include + +#include +#include +#include +#include namespace websocketpp { namespace log { @@ -56,23 +58,23 @@ namespace log { template class basic { public: - basic(channel_type_hint::value h = + basic(channel_type_hint::value h = channel_type_hint::access) : m_static_channels(0xffffffff) , m_dynamic_channels(0) , m_out(h == channel_type_hint::error ? &std::cerr : &std::cout) {} - + basic(std::ostream * out) : m_static_channels(0xffffffff) , m_dynamic_channels(0) , m_out(out) {} - basic(level c, channel_type_hint::value h = + basic(level c, channel_type_hint::value h = channel_type_hint::access) : m_static_channels(c) , m_dynamic_channels(0) , m_out(h == channel_type_hint::error ? &std::cerr : &std::cout) {} - + basic(level c, std::ostream * out) : m_static_channels(c) , m_dynamic_channels(0) @@ -97,6 +99,11 @@ public: m_dynamic_channels &= ~channels; } + /// Write a string message to the given channel + /** + * @param channel The channel to write to + * @param msg The message to write + */ void write(level channel, std::string const & msg) { scoped_lock_type lock(m_lock); if (!this->dynamic_test(channel)) { return; } @@ -106,6 +113,11 @@ public: m_out->flush(); } + /// Write a cstring message to the given channel + /** + * @param channel The channel to write to + * @param msg The message to write + */ void write(level channel, char const * msg) { scoped_lock_type lock(m_lock); if (!this->dynamic_test(channel)) { return; } @@ -122,10 +134,13 @@ public: bool dynamic_test(level channel) { return ((channel & m_dynamic_channels) != 0); } -private: + +protected: typedef typename concurrency::scoped_lock_type scoped_lock_type; typedef typename concurrency::mutex_type mutex_type; + mutex_type m_lock; +private: // The timestamp does not include the time zone, because on Windows with the // default registry settings, the time zone would be written out in full, // which would be obnoxiously verbose. @@ -143,8 +158,6 @@ private: #endif } - mutex_type m_lock; - level const m_static_channels; level m_dynamic_channels; std::ostream * m_out; diff --git a/src/third_party/websocketpp/websocketpp/logger/levels.hpp b/src/third_party/websocketpp/websocketpp/logger/levels.hpp index a774aadf..cd7ccd69 100644 --- a/src/third_party/websocketpp/websocketpp/logger/levels.hpp +++ b/src/third_party/websocketpp/websocketpp/logger/levels.hpp @@ -141,6 +141,13 @@ struct alevel { static level const devel = 0x400; /// Special channel for application specific logs. Not used by the library. static level const app = 0x800; + /// Access related to HTTP requests + static level const http = 0x1000; + /// One line for each failed WebSocket connection with details + static level const fail = 0x2000; + /// Aggregate package representing the commonly used core access channels + /// Connect, Disconnect, Fail, and HTTP + static level const access_core = 0x00003003; /// Special aggregate value representing "all levels" static level const all = 0xffffffff; @@ -180,6 +187,10 @@ struct alevel { return "devel"; case app: return "application"; + case http: + return "http"; + case fail: + return "fail"; default: return "unknown"; } diff --git a/src/third_party/websocketpp/websocketpp/logger/stub.hpp b/src/third_party/websocketpp/websocketpp/logger/stub.hpp index d9ba6ff9..2db6da7d 100644 --- a/src/third_party/websocketpp/websocketpp/logger/stub.hpp +++ b/src/third_party/websocketpp/websocketpp/logger/stub.hpp @@ -28,10 +28,11 @@ #ifndef WEBSOCKETPP_LOGGER_STUB_HPP #define WEBSOCKETPP_LOGGER_STUB_HPP -#include +#include #include -#include + +#include namespace websocketpp { namespace log { @@ -44,7 +45,7 @@ public: * @param hint A channel type specific hint for how to construct the logger */ explicit stub(channel_type_hint::value) {} - + /// Construct the logger /** * @param default_channels A set of channels to statically enable @@ -55,16 +56,16 @@ public: /// Dynamically enable the given list of channels /** - * All operations on the stub logger are no-ops and all arguments are + * All operations on the stub logger are no-ops and all arguments are * ignored * * @param channels The package of channels to enable */ void set_channels(level) {} - + /// Dynamically disable the given list of channels /** - * All operations on the stub logger are no-ops and all arguments are + * All operations on the stub logger are no-ops and all arguments are * ignored * * @param channels The package of channels to disable @@ -75,23 +76,23 @@ public: /** * Writing on the stub logger is a no-op and all arguments are ignored * - * @param channel The package of channels to write to + * @param channel The channel to write to * @param msg The message to write */ void write(level, std::string const &) {} - + /// Write a cstring message to the given channel /** * Writing on the stub logger is a no-op and all arguments are ignored * - * @param channel The package of channels to write to + * @param channel The channel to write to * @param msg The message to write */ void write(level, char const *) {} /// Test whether a channel is statically enabled /** - * The stub logger has no channels so all arguments are ignored and + * The stub logger has no channels so all arguments are ignored and * `static_test` always returns false. * * @param channel The package of channels to test @@ -99,10 +100,10 @@ public: _WEBSOCKETPP_CONSTEXPR_TOKEN_ bool static_test(level) const { return false; } - + /// Test whether a channel is dynamically enabled /** - * The stub logger has no channels so all arguments are ignored and + * The stub logger has no channels so all arguments are ignored and * `dynamic_test` always returns false. * * @param channel The package of channels to test diff --git a/src/third_party/websocketpp/websocketpp/logger/syslog.hpp b/src/third_party/websocketpp/websocketpp/logger/syslog.hpp new file mode 100644 index 00000000..513abee4 --- /dev/null +++ b/src/third_party/websocketpp/websocketpp/logger/syslog.hpp @@ -0,0 +1,146 @@ +/* + * Copyright (c) 2014, 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. + * + * + * The initial version of this logging policy was contributed to the WebSocket++ + * project by Tom Hughes. + */ + +#ifndef WEBSOCKETPP_LOGGER_SYSLOG_HPP +#define WEBSOCKETPP_LOGGER_SYSLOG_HPP + +#include + +#include + +#include +#include + +namespace websocketpp { +namespace log { + +/// Basic logger that outputs to syslog +template +class syslog : public basic { +public: + typedef basic base; + + /// Construct the logger + /** + * @param hint A channel type specific hint for how to construct the logger + */ + syslog(channel_type_hint::value hint = + channel_type_hint::access) + : basic(hint), m_channel_type_hint(hint) {} + + /// Construct the logger + /** + * @param channels A set of channels to statically enable + * @param hint A channel type specific hint for how to construct the logger + */ + syslog(level channels, channel_type_hint::value hint = + channel_type_hint::access) + : basic(channels, hint), m_channel_type_hint(hint) {} + + /// Write a string message to the given channel + /** + * @param channel The channel to write to + * @param msg The message to write + */ + void write(level channel, std::string const & msg) { + write(channel, msg.c_str()); + } + + /// Write a cstring message to the given channel + /** + * @param channel The channel to write to + * @param msg The message to write + */ + void write(level channel, char const * msg) { + scoped_lock_type lock(base::m_lock); + if (!this->dynamic_test(channel)) { return; } + ::syslog(syslog_priority(channel), "[%s] %s", + names::channel_name(channel), msg); + } +private: + typedef typename base::scoped_lock_type scoped_lock_type; + + /// The default level is used for all access logs and any error logs that + /// don't trivially map to one of the standard syslog levels. + static int const default_level = LOG_INFO; + + /// retrieve the syslog priority code given a WebSocket++ channel + /** + * @param channel The level to look up + * @return The syslog level associated with `channel` + */ + int syslog_priority(level channel) const { + if (m_channel_type_hint == channel_type_hint::access) { + return syslog_priority_access(channel); + } else { + return syslog_priority_error(channel); + } + } + + /// retrieve the syslog priority code given a WebSocket++ error channel + /** + * @param channel The level to look up + * @return The syslog level associated with `channel` + */ + int syslog_priority_error(level channel) const { + switch (channel) { + case elevel::devel: + return LOG_DEBUG; + case elevel::library: + return LOG_DEBUG; + case elevel::info: + return LOG_INFO; + case elevel::warn: + return LOG_WARNING; + case elevel::rerror: + return LOG_ERR; + case elevel::fatal: + return LOG_CRIT; + default: + return default_level; + } + } + + /// retrieve the syslog priority code given a WebSocket++ access channel + /** + * @param channel The level to look up + * @return The syslog level associated with `channel` + */ + _WEBSOCKETPP_CONSTEXPR_TOKEN_ int syslog_priority_access(level) const { + return default_level; + } + + channel_type_hint::value m_channel_type_hint; +}; + +} // log +} // websocketpp + +#endif // WEBSOCKETPP_LOGGER_SYSLOG_HPP diff --git a/src/third_party/websocketpp/websocketpp/message_buffer/message.hpp b/src/third_party/websocketpp/websocketpp/message_buffer/message.hpp index fd70d6bd..b127ee25 100644 --- a/src/third_party/websocketpp/websocketpp/message_buffer/message.hpp +++ b/src/third_party/websocketpp/websocketpp/message_buffer/message.hpp @@ -43,7 +43,7 @@ namespace message_buffer { * * # connection_message_manager: * An object that manages all of the message_buffers associated with a given - * connection. Impliments the get_message_buffer(size) method that returns + * connection. Implements the get_message_buffer(size) method that returns * a message buffer at least size bytes long. * * Message buffers are reference counted with shared ownership semantics. Once @@ -54,7 +54,7 @@ namespace message_buffer { * in the manager. * * # endpoint_message_manager: - * An object that manages connection_message_managers. Impliments the + * An object that manages connection_message_managers. Implements the * get_message_manager() method. This is used once by each connection to * request the message manager that they are supposed to use to manage message * buffers for their own use. diff --git a/src/third_party/websocketpp/websocketpp/message_buffer/pool.hpp b/src/third_party/websocketpp/websocketpp/message_buffer/pool.hpp index 7b82fd21..3af9e02a 100644 --- a/src/third_party/websocketpp/websocketpp/message_buffer/pool.hpp +++ b/src/third_party/websocketpp/websocketpp/message_buffer/pool.hpp @@ -42,7 +42,7 @@ namespace message_buffer { * * # connection_message_manager: * An object that manages all of the message_buffers associated with a given - * connection. Impliments the get_message_buffer(size) method that returns + * connection. Implements the get_message_buffer(size) method that returns * a message buffer at least size bytes long. * * Message buffers are reference counted with shared ownership semantics. Once @@ -53,7 +53,7 @@ namespace message_buffer { * in the manager. * * # endpoint_message_manager: - * An object that manages connection_message_managers. Impliments the + * An object that manages connection_message_managers. Implements the * get_message_manager() method. This is used once by each connection to * request the message manager that they are supposed to use to manage message * buffers for their own use. diff --git a/src/third_party/websocketpp/websocketpp/processors/base.hpp b/src/third_party/websocketpp/websocketpp/processors/base.hpp index 66cfc6aa..ddb8b81a 100644 --- a/src/third_party/websocketpp/websocketpp/processors/base.hpp +++ b/src/third_party/websocketpp/websocketpp/processors/base.hpp @@ -28,14 +28,13 @@ #ifndef WEBSOCKETPP_PROCESSOR_BASE_HPP #define WEBSOCKETPP_PROCESSOR_BASE_HPP -#include -#include - #include #include #include -#include +#include +#include + #include namespace websocketpp { @@ -151,7 +150,11 @@ enum processor_errors { extension_parse_error, /// Extension related operation was ignored because extensions are disabled - extensions_disabled + extensions_disabled, + + /// Short Ke3 read. Hybi00 requires a third key to be read from the 8 bytes + /// after the handshake. Less than 8 bytes were read. + short_key3 }; /// Category for processor errors @@ -223,6 +226,8 @@ public: return "Error parsing extension header"; case error::extensions_disabled: return "Extensions are disabled"; + case error::short_key3: + return "Short Hybi00 Key 3 read"; default: return "Unknown"; } diff --git a/src/third_party/websocketpp/websocketpp/processors/hybi00.hpp b/src/third_party/websocketpp/websocketpp/processors/hybi00.hpp index 704f8266..99181392 100644 --- a/src/third_party/websocketpp/websocketpp/processors/hybi00.hpp +++ b/src/third_party/websocketpp/websocketpp/processors/hybi00.hpp @@ -28,8 +28,6 @@ #ifndef WEBSOCKETPP_PROCESSOR_HYBI00_HPP #define WEBSOCKETPP_PROCESSOR_HYBI00_HPP -#include - #include #include #include @@ -38,6 +36,11 @@ #include +#include +#include +#include +#include + namespace websocketpp { namespace processor { @@ -108,7 +111,7 @@ public: // if it is less the final key will almost certainly be wrong. // TODO: decide if it is best to silently fail here or produce some sort // of warning or exception. - const std::string& key3 = req.get_header("Sec-WebSocket-Key3"); + std::string const & key3 = req.get_header("Sec-WebSocket-Key3"); std::copy(key3.c_str(), key3.c_str()+(std::min)(static_cast(8), key3.size()), &key_final[8]); @@ -364,7 +367,7 @@ public: * @param out The message buffer to prepare the pong in. * @return Status code, zero on success, non-zero on failure */ - lib::error_code prepare_pong(const std::string &, message_ptr) const + lib::error_code prepare_pong(std::string const &, message_ptr) const { return lib::error_code(error::no_protocol_support); } diff --git a/src/third_party/websocketpp/websocketpp/processors/hybi07.hpp b/src/third_party/websocketpp/websocketpp/processors/hybi07.hpp index 59b6f559..14b67c21 100644 --- a/src/third_party/websocketpp/websocketpp/processors/hybi07.hpp +++ b/src/third_party/websocketpp/websocketpp/processors/hybi07.hpp @@ -30,6 +30,9 @@ #include +#include +#include + namespace websocketpp { namespace processor { diff --git a/src/third_party/websocketpp/websocketpp/processors/hybi08.hpp b/src/third_party/websocketpp/websocketpp/processors/hybi08.hpp index 7e9337d8..15f6e658 100644 --- a/src/third_party/websocketpp/websocketpp/processors/hybi08.hpp +++ b/src/third_party/websocketpp/websocketpp/processors/hybi08.hpp @@ -30,6 +30,9 @@ #include +#include +#include + namespace websocketpp { namespace processor { @@ -68,7 +71,7 @@ public: return 8; } - const std::string& get_origin(request_type const & r) const { + std::string const & get_origin(request_type const & r) const { return r.get_header("Sec-WebSocket-Origin"); } private: diff --git a/src/third_party/websocketpp/websocketpp/processors/hybi13.hpp b/src/third_party/websocketpp/websocketpp/processors/hybi13.hpp index cb98286c..51ce3403 100644 --- a/src/third_party/websocketpp/websocketpp/processors/hybi13.hpp +++ b/src/third_party/websocketpp/websocketpp/processors/hybi13.hpp @@ -28,19 +28,20 @@ #ifndef WEBSOCKETPP_PROCESSOR_HYBI13_HPP #define WEBSOCKETPP_PROCESSOR_HYBI13_HPP -#include - -#include -#include -#include -#include -#include - #include +#include +#include + +#include #include #include +#include +#include + +#include +#include #include #include #include @@ -160,8 +161,8 @@ public: * generic struct if other user input parameters to the processed handshake * are found. */ - lib::error_code process_handshake(request_type const & request, const - std::string & subprotocol, response_type& response) const + lib::error_code process_handshake(request_type const & request, + std::string const & subprotocol, response_type & response) const { std::string server_key = request.get_header("Sec-WebSocket-Key"); @@ -588,6 +589,7 @@ public: } out->set_prepared(true); + out->set_opcode(op); return lib::error_code(); } diff --git a/src/third_party/websocketpp/websocketpp/processors/processor.hpp b/src/third_party/websocketpp/websocketpp/processors/processor.hpp index dc174a49..99b64cae 100644 --- a/src/third_party/websocketpp/websocketpp/processors/processor.hpp +++ b/src/third_party/websocketpp/websocketpp/processors/processor.hpp @@ -35,8 +35,10 @@ #include #include -#include +#include #include +#include +#include namespace websocketpp { /// Processors encapsulate the protocol rules specific to each WebSocket version @@ -103,6 +105,10 @@ bool is_websocket_handshake(request_type& r) { */ template int get_websocket_version(request_type& r) { + if (!r.ready()) { + return -2; + } + if (r.get_header("Sec-WebSocket-Version") == "") { return 0; } diff --git a/src/third_party/websocketpp/websocketpp/roles/client_endpoint.hpp b/src/third_party/websocketpp/websocketpp/roles/client_endpoint.hpp index 22c7da10..d5a9f003 100644 --- a/src/third_party/websocketpp/websocketpp/roles/client_endpoint.hpp +++ b/src/third_party/websocketpp/websocketpp/roles/client_endpoint.hpp @@ -29,13 +29,15 @@ #define WEBSOCKETPP_CLIENT_ENDPOINT_HPP #include + #include -#include +#include + +#include namespace websocketpp { - /// Client endpoint role based on the given config /** * diff --git a/src/third_party/websocketpp/websocketpp/roles/server_endpoint.hpp b/src/third_party/websocketpp/websocketpp/roles/server_endpoint.hpp index e92cbf0a..45a4bef9 100644 --- a/src/third_party/websocketpp/websocketpp/roles/server_endpoint.hpp +++ b/src/third_party/websocketpp/websocketpp/roles/server_endpoint.hpp @@ -29,13 +29,13 @@ #define WEBSOCKETPP_SERVER_ENDPOINT_HPP #include + #include -#include +#include namespace websocketpp { - /// Server endpoint role based on the given config /** * diff --git a/src/third_party/websocketpp/websocketpp/transport/asio/connection.hpp b/src/third_party/websocketpp/websocketpp/transport/asio/connection.hpp index f4341019..0be40f6b 100644 --- a/src/third_party/websocketpp/websocketpp/transport/asio/connection.hpp +++ b/src/third_party/websocketpp/websocketpp/transport/asio/connection.hpp @@ -28,22 +28,27 @@ #ifndef WEBSOCKETPP_TRANSPORT_ASIO_CON_HPP #define WEBSOCKETPP_TRANSPORT_ASIO_CON_HPP -#include -#include -#include -#include +#include + +#include + #include #include -#include -#include #include #include +#include +#include +#include +#include + #include #include +#include #include +#include #include namespace websocketpp { @@ -243,7 +248,7 @@ public: if (ec) { throw exception(ec); } } - const std::string & get_proxy() const { + std::string const & get_proxy() const { return m_proxy; } @@ -899,7 +904,7 @@ protected: ); } - void async_write(const std::vector& bufs, write_handler handler) { + void async_write(std::vector const & bufs, write_handler handler) { if (!m_async_write_handler) { m_alog.write(log::alevel::devel, "async_write (vector) called after async_shutdown"); diff --git a/src/third_party/websocketpp/websocketpp/transport/asio/endpoint.hpp b/src/third_party/websocketpp/websocketpp/transport/asio/endpoint.hpp index 9ce58256..ef3b07db 100644 --- a/src/third_party/websocketpp/websocketpp/transport/asio/endpoint.hpp +++ b/src/third_party/websocketpp/websocketpp/transport/asio/endpoint.hpp @@ -28,16 +28,22 @@ #ifndef WEBSOCKETPP_TRANSPORT_ASIO_HPP #define WEBSOCKETPP_TRANSPORT_ASIO_HPP -#include -#include #include #include #include +#include +#include + +#include + #include #include #include +#include +#include + namespace websocketpp { namespace transport { namespace asio { @@ -179,7 +185,7 @@ public: m_external_io_service = true; m_acceptor = lib::make_shared( lib::ref(*m_io_service)); - + m_state = READY; ec = lib::error_code(); } @@ -289,10 +295,10 @@ public: void set_listen_backlog(int backlog) { m_listen_backlog = backlog; } - + /// Sets whether to use the SO_REUSEADDR flag when opening listening sockets /** - * Specifies whether or not to use the SO_REUSEADDR TCP socket option. What + * Specifies whether or not to use the SO_REUSEADDR TCP socket option. What * this flag does depends on your operating system. Please consult operating * system documentation for more details. * @@ -356,6 +362,9 @@ public: m_acceptor->listen(m_listen_backlog,bec); } if (bec) { + if (m_acceptor->is_open()) { + m_acceptor->close(); + } log_err(log::elevel::info,"asio listen",bec); ec = make_error_code(error::pass_through); } else { diff --git a/src/third_party/websocketpp/websocketpp/transport/asio/security/base.hpp b/src/third_party/websocketpp/websocketpp/transport/asio/security/base.hpp index 0b494170..543a3533 100644 --- a/src/third_party/websocketpp/websocketpp/transport/asio/security/base.hpp +++ b/src/third_party/websocketpp/websocketpp/transport/asio/security/base.hpp @@ -97,14 +97,14 @@ namespace error { missing_tls_init_handler, /// TLS Handshake Failed - tls_handshake_failed, + tls_handshake_failed }; } // namespace error /// Error category related to asio transport socket policies class socket_category : public lib::error_category { public: - const char *name() const _WEBSOCKETPP_NOEXCEPT_TOKEN_ { + char const * name() const _WEBSOCKETPP_NOEXCEPT_TOKEN_ { return "websocketpp.transport.asio.socket"; } @@ -132,7 +132,7 @@ public: } }; -inline const lib::error_category& get_socket_category() { +inline lib::error_category const & get_socket_category() { static socket_category instance; return instance; } diff --git a/src/third_party/websocketpp/websocketpp/transport/asio/security/none.hpp b/src/third_party/websocketpp/websocketpp/transport/asio/security/none.hpp index 17ddbf6f..14b6f8b5 100644 --- a/src/third_party/websocketpp/websocketpp/transport/asio/security/none.hpp +++ b/src/third_party/websocketpp/websocketpp/transport/asio/security/none.hpp @@ -28,11 +28,13 @@ #ifndef WEBSOCKETPP_TRANSPORT_SECURITY_NONE_HPP #define WEBSOCKETPP_TRANSPORT_SECURITY_NONE_HPP -#include #include +#include + #include +#include #include namespace websocketpp { diff --git a/src/third_party/websocketpp/websocketpp/transport/asio/security/tls.hpp b/src/third_party/websocketpp/websocketpp/transport/asio/security/tls.hpp index 68f4198e..8434a5c3 100644 --- a/src/third_party/websocketpp/websocketpp/transport/asio/security/tls.hpp +++ b/src/third_party/websocketpp/websocketpp/transport/asio/security/tls.hpp @@ -29,6 +29,7 @@ #define WEBSOCKETPP_TRANSPORT_SECURITY_TLS_HPP #include + #include #include #include @@ -37,6 +38,7 @@ #include #include +#include #include namespace websocketpp { diff --git a/src/third_party/websocketpp/websocketpp/transport/base/connection.hpp b/src/third_party/websocketpp/websocketpp/transport/base/connection.hpp index 774c60d0..f76d4091 100644 --- a/src/third_party/websocketpp/websocketpp/transport/base/connection.hpp +++ b/src/third_party/websocketpp/websocketpp/transport/base/connection.hpp @@ -31,9 +31,10 @@ #include #include #include -#include #include +#include + namespace websocketpp { /// Transport policies provide network connectivity and timers /** @@ -176,7 +177,7 @@ enum value { action_after_shutdown, /// Other TLS error - tls_error, + tls_error }; class category : public lib::error_category { diff --git a/src/third_party/websocketpp/websocketpp/transport/base/endpoint.hpp b/src/third_party/websocketpp/websocketpp/transport/base/endpoint.hpp index 43bbdf46..3b4b0d6d 100644 --- a/src/third_party/websocketpp/websocketpp/transport/base/endpoint.hpp +++ b/src/third_party/websocketpp/websocketpp/transport/base/endpoint.hpp @@ -28,13 +28,8 @@ #ifndef WEBSOCKETPP_TRANSPORT_BASE_HPP #define WEBSOCKETPP_TRANSPORT_BASE_HPP -#include -#include #include #include -#include - -#include namespace websocketpp { /// Transport policies provide network connectivity and timers diff --git a/src/third_party/websocketpp/websocketpp/transport/debug/base.hpp b/src/third_party/websocketpp/websocketpp/transport/debug/base.hpp new file mode 100644 index 00000000..2e477b50 --- /dev/null +++ b/src/third_party/websocketpp/websocketpp/transport/debug/base.hpp @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2014, 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. + * + */ + +#ifndef WEBSOCKETPP_TRANSPORT_DEBUG_BASE_HPP +#define WEBSOCKETPP_TRANSPORT_DEBUG_BASE_HPP + +#include +#include + +#include + +namespace websocketpp { +namespace transport { +/// Debug transport policy that is used for various mocking and stubbing duties +/// in unit tests. +namespace debug { + +/// debug transport errors +namespace error { +enum value { + /// Catch-all error for transport policy errors that don't fit in other + /// categories + general = 1, + + /// not implemented + not_implemented, + + invalid_num_bytes, + + double_read +}; + +/// debug transport error category +class category : public lib::error_category { + public: + category() {} + + char const * name() const _WEBSOCKETPP_NOEXCEPT_TOKEN_ { + return "websocketpp.transport.debug"; + } + + std::string message(int value) const { + switch(value) { + case general: + return "Generic stub transport policy error"; + case not_implemented: + return "feature not implemented"; + case invalid_num_bytes: + return "Invalid number of bytes"; + case double_read: + return "Read while another read was outstanding"; + default: + return "Unknown"; + } + } +}; + +/// Get a reference to a static copy of the debug transport error category +inline lib::error_category const & get_category() { + static category instance; + return instance; +} + +/// Get an error code with the given value and the debug transport category +inline lib::error_code make_error_code(error::value e) { + return lib::error_code(static_cast(e), get_category()); +} + +} // namespace error +} // namespace debug +} // namespace transport +} // namespace websocketpp +_WEBSOCKETPP_ERROR_CODE_ENUM_NS_START_ +template<> struct is_error_code_enum +{ + static bool const value = true; +}; +_WEBSOCKETPP_ERROR_CODE_ENUM_NS_END_ + +#endif // WEBSOCKETPP_TRANSPORT_DEBUG_BASE_HPP diff --git a/src/third_party/websocketpp/websocketpp/transport/debug/connection.hpp b/src/third_party/websocketpp/websocketpp/transport/debug/connection.hpp new file mode 100644 index 00000000..7b8c29cb --- /dev/null +++ b/src/third_party/websocketpp/websocketpp/transport/debug/connection.hpp @@ -0,0 +1,397 @@ +/* + * Copyright (c) 2014, 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. + * + */ + +#ifndef WEBSOCKETPP_TRANSPORT_DEBUG_CON_HPP +#define WEBSOCKETPP_TRANSPORT_DEBUG_CON_HPP + +#include + +#include + +#include + +#include +#include +#include + +#include +#include + +namespace websocketpp { +namespace transport { +namespace debug { + +/// Empty timer class to stub out for timer functionality that stub +/// transport doesn't support +struct timer { + void cancel() {} +}; + +template +class connection : public lib::enable_shared_from_this< connection > { +public: + /// Type of this connection transport component + typedef connection type; + /// Type of a shared pointer to this connection transport component + typedef lib::shared_ptr ptr; + + /// transport concurrency policy + typedef typename config::concurrency_type concurrency_type; + /// Type of this transport's access logging policy + typedef typename config::alog_type alog_type; + /// Type of this transport's error logging policy + typedef typename config::elog_type elog_type; + + // Concurrency policy types + typedef typename concurrency_type::scoped_lock_type scoped_lock_type; + typedef typename concurrency_type::mutex_type mutex_type; + + typedef lib::shared_ptr timer_ptr; + + explicit connection(bool is_server, alog_type & alog, elog_type & elog) + : m_reading(false), m_is_server(is_server), m_alog(alog), m_elog(elog) + { + m_alog.write(log::alevel::devel,"debug con transport constructor"); + } + + /// Get a shared pointer to this component + ptr get_shared() { + return type::shared_from_this(); + } + + /// Set whether or not this connection is secure + /** + * Todo: docs + * + * @since 0.3.0-alpha4 + * + * @param value Whether or not this connection is secure. + */ + void set_secure(bool) {} + + /// Tests whether or not the underlying transport is secure + /** + * TODO: docs + * + * @return Whether or not the underlying transport is secure + */ + bool is_secure() const { + return false; + } + + /// Set human readable remote endpoint address + /** + * Sets the remote endpoint address returned by `get_remote_endpoint`. This + * value should be a human readable string that describes the remote + * endpoint. Typically an IP address or hostname, perhaps with a port. But + * may be something else depending on the nature of the underlying + * transport. + * + * If none is set a default is returned. + * + * @since 0.3.0-alpha4 + * + * @param value The remote endpoint address to set. + */ + void set_remote_endpoint(std::string) {} + + /// Get human readable remote endpoint address + /** + * TODO: docs + * + * This value is used in access and error logs and is available to the end + * application for including in user facing interfaces and messages. + * + * @return A string identifying the address of the remote endpoint + */ + std::string get_remote_endpoint() const { + return "unknown (debug transport)"; + } + + /// Get the connection handle + /** + * @return The handle for this connection. + */ + connection_hdl get_handle() const { + return connection_hdl(); + } + + /// Call back a function after a period of time. + /** + * Timers are not implemented in this transport. The timer pointer will + * always be empty. The handler will never be called. + * + * @param duration Length of time to wait in milliseconds + * @param callback The function to call back when the timer has expired + * @return A handle that can be used to cancel the timer if it is no longer + * needed. + */ + timer_ptr set_timer(long, timer_handler handler) { + m_alog.write(log::alevel::devel,"debug connection set timer"); + m_timer_handler = handler; + return timer_ptr(); + } + + /// Manual input supply (read all) + /** + * Similar to read_some, but continues to read until all bytes in the + * supplied buffer have been read or the connection runs out of read + * requests. + * + * This method still may not read all of the bytes in the input buffer. if + * it doesn't it indicates that the connection was most likely closed or + * is in an error state where it is no longer accepting new input. + * + * @since 0.3.0 + * + * @param buf Char buffer to read into the websocket + * @param len Length of buf + * @return The number of characters from buf actually read. + */ + size_t read_all(char const * buf, size_t len) { + size_t total_read = 0; + size_t temp_read = 0; + + do { + temp_read = this->read_some_impl(buf+total_read,len-total_read); + total_read += temp_read; + } while (temp_read != 0 && total_read < len); + + return total_read; + } + + // debug stuff to invoke the async handlers + void expire_timer(lib::error_code const & ec) { + m_timer_handler(ec); + } + + void fullfil_write() { + m_write_handler(lib::error_code()); + } +protected: + /// Initialize the connection transport + /** + * Initialize the connection's transport component. + * + * @param handler The `init_handler` to call when initialization is done + */ + void init(init_handler handler) { + m_alog.write(log::alevel::devel,"debug connection init"); + handler(lib::error_code()); + } + + /// Initiate an async_read for at least num_bytes bytes into buf + /** + * Initiates an async_read request for at least num_bytes bytes. The input + * will be read into buf. A maximum of len bytes will be input. When the + * operation is complete, handler will be called with the status and number + * of bytes read. + * + * This method may or may not call handler from within the initial call. The + * application should be prepared to accept either. + * + * The application should never call this method a second time before it has + * been called back for the first read. If this is done, the second read + * will be called back immediately with a double_read error. + * + * If num_bytes or len are zero handler will be called back immediately + * indicating success. + * + * @param num_bytes Don't call handler until at least this many bytes have + * been read. + * @param buf The buffer to read bytes into + * @param len The size of buf. At maximum, this many bytes will be read. + * @param handler The callback to invoke when the operation is complete or + * ends in an error + */ + void async_read_at_least(size_t num_bytes, char * buf, size_t len, + read_handler handler) + { + std::stringstream s; + s << "debug_con async_read_at_least: " << num_bytes; + m_alog.write(log::alevel::devel,s.str()); + + if (num_bytes > len) { + handler(make_error_code(error::invalid_num_bytes),size_t(0)); + return; + } + + if (m_reading == true) { + handler(make_error_code(error::double_read),size_t(0)); + return; + } + + if (num_bytes == 0 || len == 0) { + handler(lib::error_code(),size_t(0)); + return; + } + + m_buf = buf; + m_len = len; + m_bytes_needed = num_bytes; + m_read_handler = handler; + m_cursor = 0; + m_reading = true; + } + + /// Asyncronous Transport Write + /** + * Write len bytes in buf to the output stream. Call handler to report + * success or failure. handler may or may not be called during async_write, + * but it must be safe for this to happen. + * + * Will return 0 on success. + * + * @param buf buffer to read bytes from + * @param len number of bytes to write + * @param handler Callback to invoke with operation status. + */ + void async_write(char const *, size_t, write_handler handler) { + m_alog.write(log::alevel::devel,"debug_con async_write"); + m_write_handler = handler; + } + + /// Asyncronous Transport Write (scatter-gather) + /** + * Write a sequence of buffers to the output stream. Call handler to report + * success or failure. handler may or may not be called during async_write, + * but it must be safe for this to happen. + * + * Will return 0 on success. + * + * @param bufs vector of buffers to write + * @param handler Callback to invoke with operation status. + */ + void async_write(std::vector const &, write_handler handler) { + m_alog.write(log::alevel::devel,"debug_con async_write buffer list"); + m_write_handler = handler; + } + + /// Set Connection Handle + /** + * @param hdl The new handle + */ + void set_handle(connection_hdl) {} + + /// Call given handler back within the transport's event system (if present) + /** + * Invoke a callback within the transport's event system if it has one. If + * it doesn't, the handler will be invoked immediately before this function + * returns. + * + * @param handler The callback to invoke + * + * @return Whether or not the transport was able to register the handler for + * callback. + */ + lib::error_code dispatch(dispatch_handler handler) { + handler(); + return lib::error_code(); + } + + /// Perform cleanup on socket shutdown_handler + /** + * @param h The `shutdown_handler` to call back when complete + */ + void async_shutdown(shutdown_handler handler) { + handler(lib::error_code()); + } + + size_t read_some_impl(char const * buf, size_t len) { + m_alog.write(log::alevel::devel,"debug_con read_some"); + + if (!m_reading) { + m_elog.write(log::elevel::devel,"write while not reading"); + return 0; + } + + size_t bytes_to_copy = (std::min)(len,m_len-m_cursor); + + std::copy(buf,buf+bytes_to_copy,m_buf+m_cursor); + + m_cursor += bytes_to_copy; + + if (m_cursor >= m_bytes_needed) { + complete_read(lib::error_code()); + } + + return bytes_to_copy; + } + + /// Signal that a requested read is complete + /** + * Sets the reading flag to false and returns the handler that should be + * called back with the result of the read. The cursor position that is sent + * is whatever the value of m_cursor is. + * + * It MUST NOT be called when m_reading is false. + * it MUST be called while holding the read lock + * + * It is important to use this method rather than directly setting/calling + * m_read_handler back because this function makes sure to delete the + * locally stored handler which contains shared pointers that will otherwise + * cause circular reference based memory leaks. + * + * @param ec The error code to forward to the read handler + */ + void complete_read(lib::error_code const & ec) { + m_reading = false; + + read_handler handler = m_read_handler; + m_read_handler = read_handler(); + + handler(ec,m_cursor); + } +private: + timer_handler m_timer_handler; + + // Read space (Protected by m_read_mutex) + char * m_buf; + size_t m_len; + size_t m_bytes_needed; + read_handler m_read_handler; + size_t m_cursor; + + // transport resources + connection_hdl m_connection_hdl; + write_handler m_write_handler; + shutdown_handler m_shutdown_handler; + + bool m_reading; + bool const m_is_server; + bool m_is_secure; + alog_type & m_alog; + elog_type & m_elog; + std::string m_remote_endpoint; +}; + + +} // namespace debug +} // namespace transport +} // namespace websocketpp + +#endif // WEBSOCKETPP_TRANSPORT_DEBUG_CON_HPP diff --git a/src/third_party/websocketpp/websocketpp/transport/debug/endpoint.hpp b/src/third_party/websocketpp/websocketpp/transport/debug/endpoint.hpp new file mode 100644 index 00000000..1cca70c5 --- /dev/null +++ b/src/third_party/websocketpp/websocketpp/transport/debug/endpoint.hpp @@ -0,0 +1,140 @@ +/* + * Copyright (c) 2014, 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. + * + */ + +#ifndef WEBSOCKETPP_TRANSPORT_DEBUG_HPP +#define WEBSOCKETPP_TRANSPORT_DEBUG_HPP + +#include +#include + +#include +#include + +namespace websocketpp { +namespace transport { +namespace debug { + +template +class endpoint { +public: + /// Type of this endpoint transport component + typedef endpoint type; + /// Type of a pointer to this endpoint transport component + typedef lib::shared_ptr ptr; + + /// Type of this endpoint's concurrency policy + typedef typename config::concurrency_type concurrency_type; + /// Type of this endpoint's error logging policy + typedef typename config::elog_type elog_type; + /// Type of this endpoint's access logging policy + typedef typename config::alog_type alog_type; + + /// Type of this endpoint transport component's associated connection + /// transport component. + typedef debug::connection transport_con_type; + /// Type of a shared pointer to this endpoint transport component's + /// associated connection transport component + typedef typename transport_con_type::ptr transport_con_ptr; + + // generate and manage our own io_service + explicit endpoint() + { + //std::cout << "transport::iostream::endpoint constructor" << std::endl; + } + + /// Set whether or not endpoint can create secure connections + /** + * TODO: docs + * + * Setting this value only indicates whether or not the endpoint is capable + * of producing and managing secure connections. Connections produced by + * this endpoint must also be individually flagged as secure if they are. + * + * @since 0.3.0-alpha4 + * + * @param value Whether or not the endpoint can create secure connections. + */ + void set_secure(bool) {} + + /// Tests whether or not the underlying transport is secure + /** + * TODO: docs + * + * @return Whether or not the underlying transport is secure + */ + bool is_secure() const { + return false; + } +protected: + /// Initialize logging + /** + * The loggers are located in the main endpoint class. As such, the + * transport doesn't have direct access to them. This method is called + * by the endpoint constructor to allow shared logging from the transport + * component. These are raw pointers to member variables of the endpoint. + * In particular, they cannot be used in the transport constructor as they + * haven't been constructed yet, and cannot be used in the transport + * destructor as they will have been destroyed by then. + * + * @param a A pointer to the access logger to use. + * @param e A pointer to the error logger to use. + */ + void init_logging(alog_type *, elog_type *) {} + + /// Initiate a new connection + /** + * @param tcon A pointer to the transport connection component of the + * connection to connect. + * @param u A URI pointer to the URI to connect to. + * @param cb The function to call back with the results when complete. + */ + void async_connect(transport_con_ptr, uri_ptr, connect_handler cb) { + cb(lib::error_code()); + } + + /// Initialize a connection + /** + * Init is called by an endpoint once for each newly created connection. + * It's purpose is to give the transport policy the chance to perform any + * transport specific initialization that couldn't be done via the default + * constructor. + * + * @param tcon A pointer to the transport portion of the connection. + * @return A status code indicating the success or failure of the operation + */ + lib::error_code init(transport_con_ptr) { + return lib::error_code(); + } +private: + +}; + +} // namespace debug +} // namespace transport +} // namespace websocketpp + +#endif // WEBSOCKETPP_TRANSPORT_DEBUG_HPP diff --git a/src/third_party/websocketpp/websocketpp/transport/iostream/base.hpp b/src/third_party/websocketpp/websocketpp/transport/iostream/base.hpp index a80169fe..0103856a 100644 --- a/src/third_party/websocketpp/websocketpp/transport/iostream/base.hpp +++ b/src/third_party/websocketpp/websocketpp/transport/iostream/base.hpp @@ -30,6 +30,8 @@ #include #include +#include +#include #include @@ -38,6 +40,14 @@ namespace transport { /// Transport policy that uses STL iostream for I/O and does not support timers namespace iostream { +/// The type and signature of the callback used by iostream transport to write +typedef lib::function + write_handler; + +/// The type and signature of the callback used by iostream transport to signal +/// a transport shutdown. +typedef lib::function shutdown_handler; + /// iostream transport errors namespace error { enum value { diff --git a/src/third_party/websocketpp/websocketpp/transport/iostream/connection.hpp b/src/third_party/websocketpp/websocketpp/transport/iostream/connection.hpp index cbd802ec..c0d09011 100644 --- a/src/third_party/websocketpp/websocketpp/transport/iostream/connection.hpp +++ b/src/third_party/websocketpp/websocketpp/transport/iostream/connection.hpp @@ -28,15 +28,20 @@ #ifndef WEBSOCKETPP_TRANSPORT_IOSTREAM_CON_HPP #define WEBSOCKETPP_TRANSPORT_IOSTREAM_CON_HPP +#include + +#include + +#include + #include #include #include -#include - -#include -#include +#include +#include #include +#include #include namespace websocketpp { @@ -307,6 +312,44 @@ public: timer_ptr set_timer(long, timer_handler) { return timer_ptr(); } + + /// Sets the write handler + /** + * The write handler is called when the iostream transport receives data + * that needs to be written to the appropriate output location. This handler + * can be used in place of registering an ostream for output. + * + * The signature of the handler is + * `lib::error_code (connection_hdl, char const *, size_t)` The + * code returned will be reported and logged by the core library. + * + * @since 0.5.0 + * + * @param h The handler to call on connection shutdown. + */ + void set_write_handler(write_handler h) { + m_write_handler = h; + } + + /// Sets the shutdown handler + /** + * The shutdown handler is called when the iostream transport receives a + * notification from the core library that it is finished with all read and + * write operations and that the underlying transport can be cleaned up. + * + * If you are using iostream transport with another socket library, this is + * a good time to close/shutdown the socket for this connection. + * + * The signature of the handler is `lib::error_code (connection_hdl)`. The + * code returned will be reported and logged by the core library. + * + * @since 0.5.0 + * + * @param h The handler to call on connection shutdown. + */ + void set_shutdown_handler(shutdown_handler h) { + m_shutdown_handler = h; + } protected: /// Initialize the connection transport /** @@ -375,7 +418,7 @@ protected: /// Asyncronous Transport Write /** - * Write len bytes in buf to the output stream. Call handler to report + * Write len bytes in buf to the output method. Call handler to report * success or failure. handler may or may not be called during async_write, * but it must be safe for this to happen. * @@ -383,31 +426,40 @@ protected: * output_stream_required: No output stream was registered to write to * bad_stream: a ostream pass through error * + * This method will attempt to write to the registered ostream first. If an + * ostream is not registered it will use the write handler. If neither are + * registered then an error is passed up to the connection. + * * @param buf buffer to read bytes from * @param len number of bytes to write * @param handler Callback to invoke with operation status. */ - void async_write(char const * buf, size_t len, write_handler handler) { + void async_write(char const * buf, size_t len, transport::write_handler + handler) + { m_alog.write(log::alevel::devel,"iostream_con async_write"); // TODO: lock transport state? - if (!m_output_stream) { - handler(make_error_code(error::output_stream_required)); - return; - } + lib::error_code ec; - m_output_stream->write(buf,len); - - if (m_output_stream->bad()) { - handler(make_error_code(error::bad_stream)); + if (m_output_stream) { + m_output_stream->write(buf,len); + + if (m_output_stream->bad()) { + ec = make_error_code(error::bad_stream); + } + } else if (m_write_handler) { + ec = m_write_handler(m_connection_hdl, buf, len); } else { - handler(lib::error_code()); + ec = make_error_code(error::output_stream_required); } + + handler(ec); } /// Asyncronous Transport Write (scatter-gather) /** - * Write a sequence of buffers to the output stream. Call handler to report + * Write a sequence of buffers to the output method. Call handler to report * success or failure. handler may or may not be called during async_write, * but it must be safe for this to happen. * @@ -415,28 +467,43 @@ protected: * output_stream_required: No output stream was registered to write to * bad_stream: a ostream pass through error * + * This method will attempt to write to the registered ostream first. If an + * ostream is not registered it will use the write handler. If neither are + * registered then an error is passed up to the connection. + * * @param bufs vector of buffers to write * @param handler Callback to invoke with operation status. */ - void async_write(std::vector const & bufs, write_handler handler) { + void async_write(std::vector const & bufs, transport::write_handler + handler) + { m_alog.write(log::alevel::devel,"iostream_con async_write buffer list"); // TODO: lock transport state? - if (!m_output_stream) { - handler(make_error_code(error::output_stream_required)); - return; - } + lib::error_code ec; - std::vector::const_iterator it; - for (it = bufs.begin(); it != bufs.end(); it++) { - m_output_stream->write((*it).buf,(*it).len); + if (m_output_stream) { + std::vector::const_iterator it; + for (it = bufs.begin(); it != bufs.end(); it++) { + m_output_stream->write((*it).buf,(*it).len); - if (m_output_stream->bad()) { - handler(make_error_code(error::bad_stream)); + if (m_output_stream->bad()) { + ec = make_error_code(error::bad_stream); + break; + } } + } else if (m_write_handler) { + std::vector::const_iterator it; + for (it = bufs.begin(); it != bufs.end(); it++) { + ec = m_write_handler(m_connection_hdl, (*it).buf, (*it).len); + if (ec) {break;} + } + + } else { + ec = make_error_code(error::output_stream_required); } - - handler(lib::error_code()); + + handler(ec); } /// Set Connection Handle @@ -465,10 +532,20 @@ protected: /// Perform cleanup on socket shutdown_handler /** - * @param h The `shutdown_handler` to call back when complete + * If a shutdown handler is set, call it and pass through its return error + * code. Otherwise assume there is nothing to do and pass through a success + * code. + * + * @param handler The `shutdown_handler` to call back when complete */ - void async_shutdown(shutdown_handler handler) { - handler(lib::error_code()); + void async_shutdown(transport::shutdown_handler handler) { + lib::error_code ec; + + if (m_shutdown_handler) { + ec = m_shutdown_handler(m_connection_hdl); + } + + handler(ec); } private: void read(std::istream &in) { @@ -558,6 +635,8 @@ private: // transport resources std::ostream * m_output_stream; connection_hdl m_connection_hdl; + write_handler m_write_handler; + shutdown_handler m_shutdown_handler; bool m_reading; bool const m_is_server; diff --git a/src/third_party/websocketpp/websocketpp/transport/iostream/endpoint.hpp b/src/third_party/websocketpp/websocketpp/transport/iostream/endpoint.hpp index 6a83b3b7..14ec6537 100644 --- a/src/third_party/websocketpp/websocketpp/transport/iostream/endpoint.hpp +++ b/src/third_party/websocketpp/websocketpp/transport/iostream/endpoint.hpp @@ -28,13 +28,15 @@ #ifndef WEBSOCKETPP_TRANSPORT_IOSTREAM_HPP #define WEBSOCKETPP_TRANSPORT_IOSTREAM_HPP -#include -#include - #include #include -#include +#include +#include + +#include + +#include namespace websocketpp { namespace transport { @@ -114,6 +116,44 @@ public: bool is_secure() const { return m_is_secure; } + + /// Sets the write handler + /** + * The write handler is called when the iostream transport receives data + * that needs to be written to the appropriate output location. This handler + * can be used in place of registering an ostream for output. + * + * The signature of the handler is + * `lib::error_code (connection_hdl, char const *, size_t)` The + * code returned will be reported and logged by the core library. + * + * @since 0.5.0 + * + * @param h The handler to call on connection shutdown. + */ + void set_write_handler(write_handler h) { + m_write_handler = h; + } + + /// Sets the shutdown handler + /** + * The shutdown handler is called when the iostream transport receives a + * notification from the core library that it is finished with all read and + * write operations and that the underlying transport can be cleaned up. + * + * If you are using iostream transport with another socket library, this is + * a good time to close/shutdown the socket for this connection. + * + * The signature of the handler is lib::error_code (connection_hdl). The + * code returned will be reported and logged by the core library. + * + * @since 0.5.0 + * + * @param h The handler to call on connection shutdown. + */ + void set_shutdown_handler(shutdown_handler h) { + m_shutdown_handler = h; + } protected: /// Initialize logging /** @@ -156,10 +196,19 @@ protected: */ lib::error_code init(transport_con_ptr tcon) { tcon->register_ostream(m_output_stream); + if (m_shutdown_handler) { + tcon->set_shutdown_handler(m_shutdown_handler); + } + if (m_write_handler) { + tcon->set_write_handler(m_write_handler); + } return lib::error_code(); } private: std::ostream * m_output_stream; + shutdown_handler m_shutdown_handler; + write_handler m_write_handler; + elog_type * m_elog; alog_type * m_alog; bool m_is_secure; diff --git a/src/third_party/websocketpp/websocketpp/transport/stub/base.hpp b/src/third_party/websocketpp/websocketpp/transport/stub/base.hpp index 864372a4..754981e2 100644 --- a/src/third_party/websocketpp/websocketpp/transport/stub/base.hpp +++ b/src/third_party/websocketpp/websocketpp/transport/stub/base.hpp @@ -45,11 +45,11 @@ enum value { /// categories general = 1, - /// not implimented - not_implimented + /// not implemented + not_implemented }; -/// iostream transport error category +/// stub transport error category class category : public lib::error_category { public: category() {} @@ -62,8 +62,8 @@ class category : public lib::error_category { switch(value) { case general: return "Generic stub transport policy error"; - case not_implimented: - return "feature not implimented"; + case not_implemented: + return "feature not implemented"; default: return "Unknown"; } diff --git a/src/third_party/websocketpp/websocketpp/transport/stub/connection.hpp b/src/third_party/websocketpp/websocketpp/transport/stub/connection.hpp index ce3bdccd..3e501a96 100644 --- a/src/third_party/websocketpp/websocketpp/transport/stub/connection.hpp +++ b/src/third_party/websocketpp/websocketpp/transport/stub/connection.hpp @@ -28,13 +28,18 @@ #ifndef WEBSOCKETPP_TRANSPORT_STUB_CON_HPP #define WEBSOCKETPP_TRANSPORT_STUB_CON_HPP +#include + +#include + +#include + #include #include #include -#include -#include -#include +#include +#include namespace websocketpp { namespace transport { @@ -68,6 +73,7 @@ public: typedef lib::shared_ptr timer_ptr; explicit connection(bool is_server, alog_type & alog, elog_type & elog) + : m_alog(alog), m_elog(elog) { m_alog.write(log::alevel::devel,"stub con transport constructor"); } @@ -156,7 +162,7 @@ protected: */ void init(init_handler handler) { m_alog.write(log::alevel::devel,"stub connection init"); - handler(make_error_code(error::not_implimented)); + handler(make_error_code(error::not_implemented)); } /// Initiate an async_read for at least num_bytes bytes into buf @@ -183,11 +189,11 @@ protected: * @param handler The callback to invoke when the operation is complete or * ends in an error */ - void async_read_at_least(size_t num_bytes, char *buf, size_t len, + void async_read_at_least(size_t num_bytes, char * buf, size_t len, read_handler handler) { m_alog.write(log::alevel::devel, "stub_con async_read_at_least"); - handler(make_error_code(error::not_implimented)); + handler(make_error_code(error::not_implemented), 0); } /// Asyncronous Transport Write @@ -204,7 +210,7 @@ protected: */ void async_write(char const * buf, size_t len, write_handler handler) { m_alog.write(log::alevel::devel,"stub_con async_write"); - handler(make_error_code(error::not_implimented)); + handler(make_error_code(error::not_implemented)); } /// Asyncronous Transport Write (scatter-gather) @@ -220,7 +226,7 @@ protected: */ void async_write(std::vector const & bufs, write_handler handler) { m_alog.write(log::alevel::devel,"stub_con async_write buffer list"); - handler(make_error_code(error::not_implimented)); + handler(make_error_code(error::not_implemented)); } /// Set Connection Handle @@ -254,6 +260,8 @@ protected: } private: // member variables! + alog_type & m_alog; + elog_type & m_elog; }; diff --git a/src/third_party/websocketpp/websocketpp/transport/stub/endpoint.hpp b/src/third_party/websocketpp/websocketpp/transport/stub/endpoint.hpp index 7be76d7f..3bbb78f3 100644 --- a/src/third_party/websocketpp/websocketpp/transport/stub/endpoint.hpp +++ b/src/third_party/websocketpp/websocketpp/transport/stub/endpoint.hpp @@ -55,7 +55,7 @@ public: /// Type of this endpoint transport component's associated connection /// transport component. - typedef iostream::connection transport_con_type; + typedef stub::connection transport_con_type; /// Type of a shared pointer to this endpoint transport component's /// associated connection transport component typedef typename transport_con_type::ptr transport_con_ptr; @@ -113,7 +113,7 @@ protected: * @param cb The function to call back with the results when complete. */ void async_connect(transport_con_ptr tcon, uri_ptr u, connect_handler cb) { - cb(make_error_code(error::not_implimented)); + cb(make_error_code(error::not_implemented)); } /// Initialize a connection @@ -127,7 +127,7 @@ protected: * @return A status code indicating the success or failure of the operation */ lib::error_code init(transport_con_ptr tcon) { - cb(make_error_code(error::not_implimented)); + return make_error_code(error::not_implemented); } private: diff --git a/src/third_party/websocketpp/websocketpp/uri.hpp b/src/third_party/websocketpp/websocketpp/uri.hpp index ff8285ba..e2cd8c83 100644 --- a/src/third_party/websocketpp/websocketpp/uri.hpp +++ b/src/third_party/websocketpp/websocketpp/uri.hpp @@ -28,11 +28,11 @@ #ifndef WEBSOCKETPP_URI_HPP #define WEBSOCKETPP_URI_HPP -#include #include +#include + #include -#include #include #include diff --git a/src/third_party/websocketpp/websocketpp/utf8_validator.hpp b/src/third_party/websocketpp/websocketpp/utf8_validator.hpp index 528ede18..c057da62 100644 --- a/src/third_party/websocketpp/websocketpp/utf8_validator.hpp +++ b/src/third_party/websocketpp/websocketpp/utf8_validator.hpp @@ -31,6 +31,8 @@ #include +#include + namespace websocketpp { namespace utf8_validator { diff --git a/src/third_party/websocketpp/websocketpp/version.hpp b/src/third_party/websocketpp/websocketpp/version.hpp index a9a80297..519fa681 100644 --- a/src/third_party/websocketpp/websocketpp/version.hpp +++ b/src/third_party/websocketpp/websocketpp/version.hpp @@ -42,7 +42,7 @@ namespace websocketpp { /// Library major version number static int const major_version = 0; /// Library minor version number -static int const minor_version = 4; +static int const minor_version = 5; /// Library patch version number static int const patch_version = 0; /// Library pre-release flag @@ -53,7 +53,7 @@ static int const patch_version = 0; static char const prerelease_flag[] = ""; /// Default user agent string -static char const user_agent[] = "WebSocket++/0.4.0"; +static char const user_agent[] = "WebSocket++/0.5.0"; } // namespace websocketpp