Upgraded websocketpp and moved it and libmicrohttpd into the shared

3rdparty directory.
This commit is contained in:
casey langen 2020-10-05 21:28:46 -07:00
parent 61a0ee78de
commit b51dee258f
148 changed files with 1044 additions and 21137 deletions

View File

@ -0,0 +1,2 @@
init_target("websocketpp")
final_target ()

145
src/3rdparty/include/websocketpp/COPYING vendored Normal file
View File

@ -0,0 +1,145 @@
Main Library:
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.
Bundled Libraries:
****** Base 64 Library (base64/base64.hpp) ******
base64.hpp is a repackaging of the base64.cpp and base64.h files into a
single header suitable for use as a header only library. This conversion was
done by Peter Thorson (webmaster@zaphoyd.com) in 2012. All modifications to
the code are redistributed under the same license as the original, which is
listed below.
base64.cpp and base64.h
Copyright (C) 2004-2008 René Nyffenegger
This source code is provided 'as-is', without any express or implied
warranty. In no event will the author be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this source code must not be misrepresented; you must not
claim that you wrote the original source code. If you use this source code
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original source code.
3. This notice may not be removed or altered from any source distribution.
René Nyffenegger rene.nyffenegger@adp-gmbh.ch
****** SHA1 Library (sha1/sha1.hpp) ******
sha1.hpp is a repackaging of the sha1.cpp and sha1.h files from the shallsha1
library (http://code.google.com/p/smallsha1/) into a single header suitable for
use as a header only library. This conversion was done by Peter Thorson
(webmaster@zaphoyd.com) in 2013. All modifications to the code are redistributed
under the same license as the original, which is listed below.
Copyright (c) 2011, Micael Hildenborg
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 Micael Hildenborg 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 Micael Hildenborg ''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 Micael Hildenborg 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.
****** MD5 Library (common/md5.hpp) ******
md5.hpp is a reformulation of the md5.h and md5.c code from
http://www.opensource.apple.com/source/cups/cups-59/cups/md5.c to allow it to
function as a component of a header only library. This conversion was done by
Peter Thorson (webmaster@zaphoyd.com) in 2012 for the WebSocket++ project. The
changes are released under the same license as the original (listed below)
Copyright (C) 1999, 2002 Aladdin Enterprises. All rights reserved.
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
L. Peter Deutsch
ghost@aladdin.com
****** UTF8 Validation logic (utf8_validation.hpp) ******
utf8_validation.hpp is adapted from code originally written by Bjoern Hoehrmann
<bjoern@hoehrmann.de>. See http://bjoern.hoehrmann.de/utf-8/decoder/dfa/ for
details.
The original license:
Copyright (c) 2008-2009 Bjoern Hoehrmann <bjoern@hoehrmann.de>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@ -142,6 +142,11 @@ namespace status {
/// or reconnect to the same IP upon user action.
static value const try_again_later = 1013;
/// Indicates that the server was acting as a gateway or proxy and received
/// an invalid response from the upstream server. This is similar to 502
/// HTTP Status Code.
static value const bad_gateway = 1014;
/// An endpoint failed to perform a TLS handshake
/**
* Designated for use in applications expecting a status code to indicate
@ -178,7 +183,7 @@ namespace status {
*/
inline bool reserved(value code) {
return ((code >= rsv_start && code <= rsv_end) ||
code == 1004 || code == 1014);
code == 1004);
}
/// First value in range that is always invalid on the wire
@ -248,6 +253,12 @@ namespace status {
return "Extension required";
case internal_endpoint_error:
return "Internal endpoint error";
case service_restart:
return "Service restart";
case try_again_later:
return "Try again later";
case bad_gateway:
return "Bad gateway";
case tls_handshake:
return "TLS handshake failure";
case subprotocol_error:

View File

@ -101,9 +101,19 @@ namespace lib {
bool is_neg(T duration) {
return duration.count() < 0;
}
inline lib::chrono::milliseconds milliseconds(long duration) {
return lib::chrono::milliseconds(duration);
}
// If boost believes it has std::chrono available it will use it
// so we should also use it for things that relate to boost, even
// if the library would otherwise use boost::chrono.
#if defined(BOOST_ASIO_HAS_STD_CHRONO)
inline std::chrono::milliseconds milliseconds(long duration) {
return std::chrono::milliseconds(duration);
}
#else
inline lib::chrono::milliseconds milliseconds(long duration) {
return lib::chrono::milliseconds(duration);
}
#endif
#else
// Using boost::asio <1.49 we pretend a deadline timer is a steady
// timer and wrap the negative detection and duration conversion

View File

@ -65,7 +65,6 @@ namespace lib {
#ifdef _WEBSOCKETPP_CPP11_MEMORY_
using std::shared_ptr;
using std::weak_ptr;
using std::auto_ptr;
using std::enable_shared_from_this;
using std::static_pointer_cast;
using std::make_shared;

View File

@ -51,7 +51,11 @@
#endif
#endif
#ifdef _WEBSOCKETPP_CPP11_THREAD_
#if defined(_WEBSOCKETPP_MINGW_THREAD_)
#include <mingw-threads/mingw.thread.h>
#include <mingw-threads/mingw.mutex.h>
#include <mingw-threads/mingw.condition_variable.h>
#elif defined(_WEBSOCKETPP_CPP11_THREAD_)
#include <thread>
#include <mutex>
#include <condition_variable>
@ -64,7 +68,7 @@
namespace websocketpp {
namespace lib {
#ifdef _WEBSOCKETPP_CPP11_THREAD_
#if defined(_WEBSOCKETPP_CPP11_THREAD_) || defined(_WEBSOCKETPP_MINGW_THREAD_)
using std::mutex;
using std::lock_guard;
using std::thread;

View File

@ -49,6 +49,7 @@
// Loggers
#include <websocketpp/logger/basic.hpp>
#include <websocketpp/logger/levels.hpp>
// RNG
#include <websocketpp/random/none.hpp>
@ -188,7 +189,18 @@ struct core {
static const websocketpp::log::level alog_level =
websocketpp::log::alevel::all ^ websocketpp::log::alevel::devel;
///
/// Size of the per-connection read buffer
/**
* Each connection has an internal buffer of this size. A larger value will
* result in fewer trips through the library and less CPU overhead at the
* expense of increased memory usage per connection.
*
* If your application primarily deals in very large messages you may want
* to try setting this value higher.
*
* If your application has a lot of connections or primarily deals in small
* messages you may want to try setting this smaller.
*/
static const size_t connection_read_buffer_size = 16384;
/// Drop connections immediately on protocol error.

View File

@ -294,8 +294,8 @@ private:
};
public:
explicit connection(bool p_is_server, std::string const & ua, alog_type& alog,
elog_type& elog, rng_type & rng)
explicit connection(bool p_is_server, std::string const & ua, const lib::shared_ptr<alog_type>& alog,
const lib::shared_ptr<elog_type>& elog, rng_type & rng)
: transport_con_type(p_is_server, alog, elog)
, m_handle_read_frame(lib::bind(
&type::handle_read_frame,
@ -329,7 +329,7 @@ public:
, m_http_state(session::http_state::init)
, m_was_clean(false)
{
m_alog.write(log::alevel::devel,"connection constructor");
m_alog->write(log::alevel::devel,"connection constructor");
}
/// Get a shared pointer to this component
@ -1486,7 +1486,7 @@ private:
void log_err(log::level l, char const * msg, error_type const & ec) {
std::stringstream s;
s << msg << " error: " << ec << " (" << ec.message() << ")";
m_elog.write(l, s.str());
m_elog->write(l, s.str());
}
// internal handler functions
@ -1603,8 +1603,8 @@ private:
std::vector<std::string> m_requested_subprotocols;
bool const m_is_server;
alog_type& m_alog;
elog_type& m_elog;
const lib::shared_ptr<alog_type> m_alog;
const lib::shared_ptr<elog_type> m_elog;
rng_type & m_rng;
@ -1633,15 +1633,6 @@ private:
session::http_state::value m_http_state;
bool m_was_clean;
/// Whether or not this endpoint initiated the closing handshake.
bool m_closed_by_me;
/// ???
bool m_failed_by_me;
/// Whether or not this endpoint initiated the drop of the TCP connection
bool m_dropped_by_me;
};
} // namespace websocketpp

View File

@ -89,8 +89,8 @@ public:
//friend connection;
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)
: m_alog(new alog_type(config::alog_level, log::channel_type_hint::access))
, m_elog(new elog_type(config::elog_level, log::channel_type_hint::error))
, m_user_agent(::websocketpp::user_agent)
, m_open_handshake_timeout_dur(config::timeout_open_handshake)
, m_close_handshake_timeout_dur(config::timeout_close_handshake)
@ -99,12 +99,12 @@ public:
, m_max_http_body_size(config::max_http_body_size)
, m_is_server(p_is_server)
{
m_alog.set_channels(config::alog_level);
m_elog.set_channels(config::elog_level);
m_alog->set_channels(config::alog_level);
m_elog->set_channels(config::elog_level);
m_alog.write(log::alevel::devel, "endpoint constructor");
m_alog->write(log::alevel::devel, "endpoint constructor");
transport_type::init_logging(&m_alog, &m_elog);
transport_type::init_logging(m_alog, m_elog);
}
@ -218,7 +218,7 @@ public:
* @param channels The channel value(s) to set
*/
void set_access_channels(log::level channels) {
m_alog.set_channels(channels);
m_alog->set_channels(channels);
}
/// Clear Access logging channels
@ -229,7 +229,7 @@ public:
* @param channels The channel value(s) to clear
*/
void clear_access_channels(log::level channels) {
m_alog.clear_channels(channels);
m_alog->clear_channels(channels);
}
/// Set Error logging channel
@ -240,7 +240,7 @@ public:
* @param channels The channel value(s) to set
*/
void set_error_channels(log::level channels) {
m_elog.set_channels(channels);
m_elog->set_channels(channels);
}
/// Clear Error logging channels
@ -251,7 +251,7 @@ public:
* @param channels The channel value(s) to clear
*/
void clear_error_channels(log::level channels) {
m_elog.clear_channels(channels);
m_elog->clear_channels(channels);
}
/// Get reference to access logger
@ -259,7 +259,7 @@ public:
* @return A reference to the access logger
*/
alog_type & get_alog() {
return m_alog;
return *m_alog;
}
/// Get reference to error logger
@ -267,7 +267,7 @@ public:
* @return A reference to the error logger
*/
elog_type & get_elog() {
return m_elog;
return *m_elog;
}
/*************************/
@ -275,52 +275,52 @@ public:
/*************************/
void set_open_handler(open_handler h) {
m_alog.write(log::alevel::devel,"set_open_handler");
m_alog->write(log::alevel::devel,"set_open_handler");
scoped_lock_type guard(m_mutex);
m_open_handler = h;
}
void set_close_handler(close_handler h) {
m_alog.write(log::alevel::devel,"set_close_handler");
m_alog->write(log::alevel::devel,"set_close_handler");
scoped_lock_type guard(m_mutex);
m_close_handler = h;
}
void set_fail_handler(fail_handler h) {
m_alog.write(log::alevel::devel,"set_fail_handler");
m_alog->write(log::alevel::devel,"set_fail_handler");
scoped_lock_type guard(m_mutex);
m_fail_handler = h;
}
void set_ping_handler(ping_handler h) {
m_alog.write(log::alevel::devel,"set_ping_handler");
m_alog->write(log::alevel::devel,"set_ping_handler");
scoped_lock_type guard(m_mutex);
m_ping_handler = h;
}
void set_pong_handler(pong_handler h) {
m_alog.write(log::alevel::devel,"set_pong_handler");
m_alog->write(log::alevel::devel,"set_pong_handler");
scoped_lock_type guard(m_mutex);
m_pong_handler = h;
}
void set_pong_timeout_handler(pong_timeout_handler h) {
m_alog.write(log::alevel::devel,"set_pong_timeout_handler");
m_alog->write(log::alevel::devel,"set_pong_timeout_handler");
scoped_lock_type guard(m_mutex);
m_pong_timeout_handler = h;
}
void set_interrupt_handler(interrupt_handler h) {
m_alog.write(log::alevel::devel,"set_interrupt_handler");
m_alog->write(log::alevel::devel,"set_interrupt_handler");
scoped_lock_type guard(m_mutex);
m_interrupt_handler = h;
}
void set_http_handler(http_handler h) {
m_alog.write(log::alevel::devel,"set_http_handler");
m_alog->write(log::alevel::devel,"set_http_handler");
scoped_lock_type guard(m_mutex);
m_http_handler = h;
}
void set_validate_handler(validate_handler h) {
m_alog.write(log::alevel::devel,"set_validate_handler");
m_alog->write(log::alevel::devel,"set_validate_handler");
scoped_lock_type guard(m_mutex);
m_validate_handler = h;
}
void set_message_handler(message_handler h) {
m_alog.write(log::alevel::devel,"set_message_handler");
m_alog->write(log::alevel::devel,"set_message_handler");
scoped_lock_type guard(m_mutex);
m_message_handler = h;
}
@ -661,8 +661,8 @@ public:
protected:
connection_ptr create_connection();
alog_type m_alog;
elog_type m_elog;
lib::shared_ptr<alog_type> m_alog;
lib::shared_ptr<elog_type> m_elog;
private:
// dynamic settings
std::string m_user_agent;

View File

@ -29,6 +29,7 @@
#define WEBSOCKETPP_EXTENSION_PERMESSAGE_DEFLATE_DISABLED_HPP
#include <websocketpp/common/cpp11.hpp>
#include <websocketpp/common/stdint.hpp>
#include <websocketpp/common/system_error.hpp>
#include <websocketpp/http/constants.hpp>

View File

@ -32,12 +32,13 @@
#include <websocketpp/common/cpp11.hpp>
#include <websocketpp/common/memory.hpp>
#include <websocketpp/common/platforms.hpp>
#include <websocketpp/common/stdint.hpp>
#include <websocketpp/common/system_error.hpp>
#include <websocketpp/error.hpp>
#include <websocketpp/extensions/extension.hpp>
#include <zlib.h>
#include "zlib.h"
#include <algorithm>
#include <string>
@ -46,7 +47,7 @@
namespace websocketpp {
namespace extensions {
/// Implementation of the draft permessage-deflate WebSocket extension
/// Implementation of RFC 7692, the permessage-deflate WebSocket extension
/**
* ### permessage-deflate interface
*
@ -174,18 +175,30 @@ namespace websocketpp {
namespace extensions {
namespace permessage_deflate {
/// Default value for server_max_window_bits as defined by draft 17
/// Default value for server_max_window_bits as defined by RFC 7692
static uint8_t const default_server_max_window_bits = 15;
/// Minimum value for server_max_window_bits as defined by draft 17
/// Minimum value for server_max_window_bits as defined by RFC 7692
/**
* NOTE: A value of 8 is not actually supported by zlib, the deflate
* library that WebSocket++ uses. To preserve backwards compatibility
* with RFC 7692 and previous versions of the library a value of 8
* is accepted by the library but will always be negotiated as 9.
*/
static uint8_t const min_server_max_window_bits = 8;
/// Maximum value for server_max_window_bits as defined by draft 17
/// Maximum value for server_max_window_bits as defined by RFC 7692
static uint8_t const max_server_max_window_bits = 15;
/// Default value for client_max_window_bits as defined by draft 17
/// Default value for client_max_window_bits as defined by RFC 7692
static uint8_t const default_client_max_window_bits = 15;
/// Minimum value for client_max_window_bits as defined by draft 17
/// Minimum value for client_max_window_bits as defined by RFC 7692
/**
* NOTE: A value of 8 is not actually supported by zlib, the deflate
* library that WebSocket++ uses. To preserve backwards compatibility
* with RFC 7692 and previous versions of the library a value of 8
* is accepted by the library but will always be negotiated as 9.
*/
static uint8_t const min_client_max_window_bits = 8;
/// Maximum value for client_max_window_bits as defined by draft 17
/// Maximum value for client_max_window_bits as defined by RFC 7692
static uint8_t const max_client_max_window_bits = 15;
namespace mode {
@ -213,7 +226,7 @@ public:
, m_server_max_window_bits_mode(mode::accept)
, m_client_max_window_bits_mode(mode::accept)
, m_initialized(false)
, m_compress_buffer_size(16384)
, m_compress_buffer_size(8192)
{
m_dstate.zalloc = Z_NULL;
m_dstate.zfree = Z_NULL;
@ -292,6 +305,7 @@ public:
}
m_compress_buffer.reset(new unsigned char[m_compress_buffer_size]);
m_decompress_buffer.reset(new unsigned char[m_compress_buffer_size]);
if ((m_server_no_context_takeover && is_server) ||
(m_client_no_context_takeover && !is_server))
{
@ -372,7 +386,7 @@ public:
/**
* The bits setting is the base 2 logarithm of the maximum window size that
* the server must use to compress outgoing messages. The permitted range
* is 8 to 15 inclusive. 8 represents a 256 byte window and 15 a 32KiB
* is 9 to 15 inclusive. 9 represents a 512 byte window and 15 a 32KiB
* window. The default setting is 15.
*
* Mode Options:
@ -386,6 +400,14 @@ public:
* adjusted by the server. A server may unilaterally set this value without
* client support.
*
* NOTE: The permessage-deflate spec specifies that a value of 8 is allowed.
* Prior to version 0.8.0 a value of 8 was also allowed by this library.
* zlib, the deflate compression library that WebSocket++ uses has always
* silently adjusted a value of 8 to 9. In recent versions of zlib (1.2.9
* and greater) a value of 8 is now explicitly rejected. WebSocket++ 0.8.0
* continues to perform the 8->9 conversion for backwards compatibility
* purposes but this should be considered deprecated functionality.
*
* @param bits The size to request for the outgoing window size
* @param mode The mode to use for negotiating this parameter
* @return A status code
@ -394,6 +416,12 @@ public:
if (bits < min_server_max_window_bits || bits > max_server_max_window_bits) {
return error::make_error_code(error::invalid_max_window_bits);
}
// See note in doc comment above about what is happening here
if (bits == 8) {
bits = 9;
}
m_server_max_window_bits = bits;
m_server_max_window_bits_mode = mode;
@ -403,8 +431,8 @@ public:
/// Limit client LZ77 sliding window size
/**
* The bits setting is the base 2 logarithm of the window size that the
* client must use to compress outgoing messages. The permitted range is 8
* to 15 inclusive. 8 represents a 256 byte window and 15 a 32KiB window.
* client must use to compress outgoing messages. The permitted range is 9
* to 15 inclusive. 9 represents a 512 byte window and 15 a 32KiB window.
* The default setting is 15.
*
* Mode Options:
@ -417,6 +445,14 @@ public:
* outgoing window size unilaterally. A server may only limit the client's
* window size if the remote client supports that feature.
*
* NOTE: The permessage-deflate spec specifies that a value of 8 is allowed.
* Prior to version 0.8.0 a value of 8 was also allowed by this library.
* zlib, the deflate compression library that WebSocket++ uses has always
* silently adjusted a value of 8 to 9. In recent versions of zlib (1.2.9
* and greater) a value of 8 is now explicitly rejected. WebSocket++ 0.8.0
* continues to perform the 8->9 conversion for backwards compatibility
* purposes but this should be considered deprecated functionality.
*
* @param bits The size to request for the outgoing window size
* @param mode The mode to use for negotiating this parameter
* @return A status code
@ -425,6 +461,12 @@ public:
if (bits < min_client_max_window_bits || bits > max_client_max_window_bits) {
return error::make_error_code(error::invalid_max_window_bits);
}
// See note in doc comment above about what is happening here
if (bits == 8) {
bits = 9;
}
m_client_max_window_bits = bits;
m_client_max_window_bits_mode = mode;
@ -555,7 +597,7 @@ public:
do {
m_istate.avail_out = m_compress_buffer_size;
m_istate.next_out = m_compress_buffer.get();
m_istate.next_out = m_decompress_buffer.get();
ret = inflate(&m_istate, Z_SYNC_FLUSH);
@ -564,7 +606,7 @@ public:
}
out.append(
reinterpret_cast<char *>(m_compress_buffer.get()),
reinterpret_cast<char *>(m_decompress_buffer.get()),
m_compress_buffer_size - m_istate.avail_out
);
} while (m_istate.avail_out == 0);
@ -642,11 +684,17 @@ private:
* client requested that we use.
*
* options:
* - decline (refuse to use the attribute)
* - accept (use whatever the client says)
* - largest (use largest possible value)
* - decline (ignore value, offer our default instead)
* - accept (use the value requested by the client)
* - largest (use largest value acceptable to both)
* - smallest (use smallest possible value)
*
* NOTE: As a value of 8 is no longer explicitly supported by zlib but might
* be requested for negotiation by an older client/server, if the result of
* the negotiation would be to send a value of 8, a value of 9 is offered
* instead. This ensures that WebSocket++ will only ever negotiate connections
* with compression settings explicitly supported by zlib.
*
* @param [in] value The value of the attribute from the offer
* @param [out] ec A reference to the error code to return errors via
*/
@ -678,6 +726,11 @@ private:
ec = make_error_code(error::invalid_mode);
m_server_max_window_bits = default_server_max_window_bits;
}
// See note in doc comment
if (m_server_max_window_bits == 8) {
m_server_max_window_bits = 9;
}
}
/// Negotiate client_max_window_bits attribute
@ -687,11 +740,17 @@ private:
* negotiation mode.
*
* options:
* - decline (refuse to use the attribute)
* - accept (use whatever the client says)
* - largest (use largest possible value)
* - decline (ignore value, offer our default instead)
* - accept (use the value requested by the client)
* - largest (use largest value acceptable to both)
* - smallest (use smallest possible value)
*
* NOTE: As a value of 8 is no longer explicitly supported by zlib but might
* be requested for negotiation by an older client/server, if the result of
* the negotiation would be to send a value of 8, a value of 9 is offered
* instead. This ensures that WebSocket++ will only ever negotiate connections
* with compression settings explicitly supported by zlib.
*
* @param [in] value The value of the attribute from the offer
* @param [out] ec A reference to the error code to return errors via
*/
@ -727,6 +786,11 @@ private:
ec = make_error_code(error::invalid_mode);
m_client_max_window_bits = default_client_max_window_bits;
}
// See note in doc comment
if (m_client_max_window_bits == 8) {
m_client_max_window_bits = 9;
}
}
bool m_enabled;
@ -741,6 +805,7 @@ private:
int m_flush;
size_t m_compress_buffer_size;
lib::unique_ptr_uchar_array m_compress_buffer;
lib::unique_ptr_uchar_array m_decompress_buffer;
z_stream m_dstate;
z_stream m_istate;
};

View File

@ -610,6 +610,9 @@ inline size_t prepare_masking_key(const masking_key_type& key) {
* to zero and less than sizeof(size_t).
*/
inline size_t circshift_prepared_key(size_t prepared_key, size_t offset) {
if (offset == 0) {
return prepared_key;
}
if (lib::net::is_little_endian()) {
size_t temp = prepared_key << (sizeof(size_t)-offset)*8;
return (prepared_key >> offset*8) | temp;

View File

@ -176,6 +176,10 @@ inline void parser::process_header(std::string::iterator begin,
strip_lws(std::string(cursor+sizeof(header_separator)-1,end)));
}
inline header_list const & parser::get_headers() const {
return m_headers;
}
inline std::string parser::raw_headers() const {
std::stringstream raw;

View File

@ -441,6 +441,16 @@ public:
bool get_header_as_plist(std::string const & key, parameter_list & out)
const;
/// Return a list of all HTTP headers
/**
* Return a list of all HTTP headers
*
* @since 0.8.0
*
* @return A list of all HTTP headers
*/
header_list const & get_headers() const;
/// Append a value to an existing HTTP header
/**
* This method will set the value of the HTTP header `key` with the

View File

@ -53,7 +53,7 @@ template <typename config>
void connection<config>::set_termination_handler(
termination_handler new_handler)
{
m_alog.write(log::alevel::devel,
m_alog->write(log::alevel::devel,
"connection set_termination_handler");
//scoped_lock_type lock(m_connection_state_lock);
@ -103,8 +103,8 @@ lib::error_code connection<config>::send(void const * payload, size_t len,
template <typename config>
lib::error_code connection<config>::send(typename config::message_type::ptr msg)
{
if (m_alog.static_test(log::alevel::devel)) {
m_alog.write(log::alevel::devel,"connection send");
if (m_alog->static_test(log::alevel::devel)) {
m_alog->write(log::alevel::devel,"connection send");
}
{
@ -153,8 +153,8 @@ lib::error_code connection<config>::send(typename config::message_type::ptr msg)
template <typename config>
void connection<config>::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_alog->static_test(log::alevel::devel)) {
m_alog->write(log::alevel::devel,"connection ping");
}
{
@ -162,7 +162,7 @@ void connection<config>::ping(std::string const& payload, lib::error_code& ec) {
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());
m_alog->write(log::alevel::devel,ss.str());
ec = error::make_error_code(error::invalid_state);
return;
}
@ -198,7 +198,7 @@ void connection<config>::ping(std::string const& payload, lib::error_code& ec) {
if (!m_ping_timer) {
// Our transport doesn't support timers
m_elog.write(log::elevel::warn,"Warning: a pong_timeout_handler is \
m_elog->write(log::elevel::warn,"Warning: a pong_timeout_handler is \
set but the transport in use does not support timeouts.");
}
}
@ -234,12 +234,12 @@ void connection<config>::handle_pong_timeout(std::string payload,
lib::error_code const & ec)
{
if (ec) {
if (ec.value() == (int) transport::error::operation_aborted) {
if (ec == transport::error::operation_aborted) {
// ignore, this is expected
return;
}
m_elog.write(log::elevel::devel,"pong_timeout error: "+ec.message());
m_elog->write(log::elevel::devel,"pong_timeout error: "+ec.message());
return;
}
@ -250,8 +250,8 @@ void connection<config>::handle_pong_timeout(std::string payload,
template <typename config>
void connection<config>::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_alog->static_test(log::alevel::devel)) {
m_alog->write(log::alevel::devel,"connection pong");
}
{
@ -259,7 +259,7 @@ void connection<config>::pong(std::string const& payload, lib::error_code& ec) {
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());
m_alog->write(log::alevel::devel,ss.str());
ec = error::make_error_code(error::invalid_state);
return;
}
@ -304,8 +304,8 @@ template <typename config>
void connection<config>::close(close::status::value const code,
std::string const & reason, lib::error_code & ec)
{
if (m_alog.static_test(log::alevel::devel)) {
m_alog.write(log::alevel::devel,"connection close");
if (m_alog->static_test(log::alevel::devel)) {
m_alog->write(log::alevel::devel,"connection close");
}
// Truncate reason to maximum size allowable in a close frame.
@ -339,7 +339,7 @@ void connection<config>::close(close::status::value const code,
*/
template <typename config>
lib::error_code connection<config>::interrupt() {
m_alog.write(log::alevel::devel,"connection connection::interrupt");
m_alog->write(log::alevel::devel,"connection connection::interrupt");
return transport_con_type::interrupt(
lib::bind(
&type::handle_interrupt,
@ -358,7 +358,7 @@ void connection<config>::handle_interrupt() {
template <typename config>
lib::error_code connection<config>::pause_reading() {
m_alog.write(log::alevel::devel,"connection connection::pause_reading");
m_alog->write(log::alevel::devel,"connection connection::pause_reading");
return transport_con_type::dispatch(
lib::bind(
&type::handle_pause_reading,
@ -370,13 +370,13 @@ lib::error_code connection<config>::pause_reading() {
/// Pause reading handler. Not safe to call directly
template <typename config>
void connection<config>::handle_pause_reading() {
m_alog.write(log::alevel::devel,"connection connection::handle_pause_reading");
m_alog->write(log::alevel::devel,"connection connection::handle_pause_reading");
m_read_flag = false;
}
template <typename config>
lib::error_code connection<config>::resume_reading() {
m_alog.write(log::alevel::devel,"connection connection::resume_reading");
m_alog->write(log::alevel::devel,"connection connection::resume_reading");
return transport_con_type::dispatch(
lib::bind(
&type::handle_resume_reading,
@ -714,10 +714,10 @@ void connection<config>::send_http_response() {
template <typename config>
void connection<config>::start() {
m_alog.write(log::alevel::devel,"connection start");
m_alog->write(log::alevel::devel,"connection start");
if (m_internal_state != istate::USER_INIT) {
m_alog.write(log::alevel::devel,"Start called in invalid state");
m_alog->write(log::alevel::devel,"Start called in invalid state");
this->terminate(error::make_error_code(error::invalid_state));
return;
}
@ -738,12 +738,12 @@ void connection<config>::start() {
template <typename config>
void connection<config>::handle_transport_init(lib::error_code const & ec) {
m_alog.write(log::alevel::devel,"connection handle_transport_init");
m_alog->write(log::alevel::devel,"connection handle_transport_init");
lib::error_code ecm = ec;
if (m_internal_state != istate::TRANSPORT_INIT) {
m_alog.write(log::alevel::devel,
m_alog->write(log::alevel::devel,
"handle_transport_init must be called from transport init state");
ecm = error::make_error_code(error::invalid_state);
}
@ -751,7 +751,7 @@ void connection<config>::handle_transport_init(lib::error_code const & ec) {
if (ecm) {
std::stringstream s;
s << "handle_transport_init received error: "<< ecm.message();
m_elog.write(log::elevel::rerror,s.str());
m_elog->write(log::elevel::rerror,s.str());
this->terminate(ecm);
return;
@ -772,7 +772,7 @@ void connection<config>::handle_transport_init(lib::error_code const & ec) {
template <typename config>
void connection<config>::read_handshake(size_t num_bytes) {
m_alog.write(log::alevel::devel,"connection read_handshake");
m_alog->write(log::alevel::devel,"connection read_handshake");
if (m_open_handshake_timeout_dur > 0) {
m_handshake_timer = transport_con_type::set_timer(
@ -804,7 +804,7 @@ template <typename config>
void connection<config>::handle_read_handshake(lib::error_code const & ec,
size_t bytes_transferred)
{
m_alog.write(log::alevel::devel,"connection handle_read_handshake");
m_alog->write(log::alevel::devel,"connection handle_read_handshake");
lib::error_code ecm = ec;
@ -819,7 +819,7 @@ void connection<config>::handle_read_handshake(lib::error_code const & ec,
// 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,
m_alog->write(log::alevel::devel,
"handle_read_handshake invoked after connection was closed");
return;
} else {
@ -828,9 +828,9 @@ void connection<config>::handle_read_handshake(lib::error_code const & ec,
}
if (ecm) {
if (ecm.value() == (int) transport::error::eof && m_state == session::state::closed) {
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,
m_alog->write(log::alevel::devel,
"got (expected) eof/state error from closed con");
return;
}
@ -842,7 +842,7 @@ void connection<config>::handle_read_handshake(lib::error_code const & ec,
// Boundaries checking. TODO: How much of this should be done?
if (bytes_transferred > config::connection_read_buffer_size) {
m_elog.write(log::elevel::fatal,"Fatal boundaries checking error.");
m_elog->write(log::elevel::fatal,"Fatal boundaries checking error.");
this->terminate(make_error_code(error::general));
return;
}
@ -861,16 +861,16 @@ void connection<config>::handle_read_handshake(lib::error_code const & ec,
// More paranoid boundaries checking.
// TODO: Is this overkill?
if (bytes_processed > bytes_transferred) {
m_elog.write(log::elevel::fatal,"Fatal boundaries checking error.");
m_elog->write(log::elevel::fatal,"Fatal boundaries checking error.");
this->terminate(make_error_code(error::general));
return;
}
if (m_alog.static_test(log::alevel::devel)) {
if (m_alog->static_test(log::alevel::devel)) {
std::stringstream s;
s << "bytes_transferred: " << bytes_transferred
<< " bytes, bytes processed: " << bytes_processed << " bytes";
m_alog.write(log::alevel::devel,s.str());
m_alog->write(log::alevel::devel,s.str());
}
if (m_request.ready()) {
@ -891,17 +891,17 @@ void connection<config>::handle_read_handshake(lib::error_code const & ec,
bytes_processed += 8;
} else {
// TODO: need more bytes
m_alog.write(log::alevel::devel,"short key3 read");
m_alog->write(log::alevel::devel,"short key3 read");
m_response.set_status(http::status_code::internal_server_error);
this->write_http_response_error(processor::error::make_error_code(processor::error::short_key3));
return;
}
}
if (m_alog.static_test(log::alevel::devel)) {
m_alog.write(log::alevel::devel,m_request.raw());
if (m_alog->static_test(log::alevel::devel)) {
m_alog->write(log::alevel::devel,m_request.raw());
if (!m_request.get_header("Sec-WebSocket-Key3").empty()) {
m_alog.write(log::alevel::devel,
m_alog->write(log::alevel::devel,
utility::to_hex(m_request.get_header("Sec-WebSocket-Key3")));
}
}
@ -948,7 +948,7 @@ void connection<config>::handle_read_handshake(lib::error_code const & ec,
template <typename config>
void connection<config>::write_http_response_error(lib::error_code const & ec) {
if (m_internal_state != istate::READ_HTTP_REQUEST) {
m_alog.write(log::alevel::devel,
m_alog->write(log::alevel::devel,
"write_http_response_error called in invalid state");
this->terminate(error::make_error_code(error::invalid_state));
return;
@ -965,7 +965,7 @@ template <typename config>
void connection<config>::handle_read_frame(lib::error_code const & ec,
size_t bytes_transferred)
{
//m_alog.write(log::alevel::devel,"connection handle_read_frame");
//m_alog->write(log::alevel::devel,"connection handle_read_frame");
lib::error_code ecm = ec;
@ -976,11 +976,11 @@ void connection<config>::handle_read_frame(lib::error_code const & ec,
if (ecm) {
log::level echannel = log::elevel::rerror;
if (ecm.value() == (int) 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
m_alog.write(log::alevel::devel,"got eof from closed con");
m_alog->write(log::alevel::devel,"got eof from closed con");
return;
} else if (m_state == session::state::closing && !m_is_server) {
// If we are a client we expect to get eof in the closing state,
@ -989,29 +989,26 @@ void connection<config>::handle_read_frame(lib::error_code const & ec,
terminate(lib::error_code());
return;
}
} else if (ecm.value() == (int) error::invalid_state) {
} 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,
m_alog->write(log::alevel::devel,
"handle_read_frame: got invalid istate in closed state");
return;
}
} else if (ecm.value() == (int) 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
// read frame path.
terminate(lib::error_code());
return;
}
echannel = log::elevel::rerror;
} else if (ecm.value() == (int) transport::error::action_after_shutdown) {
} else if (ecm == transport::error::action_after_shutdown) {
echannel = log::elevel::info;
} else {
// TODO: more generally should we do something different here in the
// case that m_state is cosed? Are errors after the connection is
// already closed really an rerror?
}
log_err(echannel, "handle_read_frame", ecm);
this->terminate(ecm);
return;
@ -1019,32 +1016,32 @@ void connection<config>::handle_read_frame(lib::error_code const & ec,
// Boundaries checking. TODO: How much of this should be done?
/*if (bytes_transferred > config::connection_read_buffer_size) {
m_elog.write(log::elevel::fatal,"Fatal boundaries checking error");
m_elog->write(log::elevel::fatal,"Fatal boundaries checking error");
this->terminate(make_error_code(error::general));
return;
}*/
size_t p = 0;
if (m_alog.static_test(log::alevel::devel)) {
if (m_alog->static_test(log::alevel::devel)) {
std::stringstream s;
s << "p = " << p << " bytes transferred = " << bytes_transferred;
m_alog.write(log::alevel::devel,s.str());
m_alog->write(log::alevel::devel,s.str());
}
while (p < bytes_transferred) {
if (m_alog.static_test(log::alevel::devel)) {
if (m_alog->static_test(log::alevel::devel)) {
std::stringstream s;
s << "calling consume with " << bytes_transferred-p << " bytes";
m_alog.write(log::alevel::devel,s.str());
m_alog->write(log::alevel::devel,s.str());
}
lib::error_code consume_ec;
if (m_alog.static_test(log::alevel::devel)) {
if (m_alog->static_test(log::alevel::devel)) {
std::stringstream s;
s << "Processing Bytes: " << utility::to_hex(reinterpret_cast<uint8_t*>(m_buf)+p,bytes_transferred-p);
m_alog.write(log::alevel::devel,s.str());
m_alog->write(log::alevel::devel,s.str());
}
p += m_processor->consume(
@ -1053,10 +1050,10 @@ void connection<config>::handle_read_frame(lib::error_code const & ec,
consume_ec
);
if (m_alog.static_test(log::alevel::devel)) {
if (m_alog->static_test(log::alevel::devel)) {
std::stringstream s;
s << "bytes left after consume: " << bytes_transferred-p;
m_alog.write(log::alevel::devel,s.str());
m_alog->write(log::alevel::devel,s.str());
}
if (consume_ec) {
log_err(log::elevel::rerror, "consume", consume_ec);
@ -1082,20 +1079,20 @@ void connection<config>::handle_read_frame(lib::error_code const & ec,
}
if (m_processor->ready()) {
if (m_alog.static_test(log::alevel::devel)) {
if (m_alog->static_test(log::alevel::devel)) {
std::stringstream s;
s << "Complete message received. Dispatching";
m_alog.write(log::alevel::devel,s.str());
m_alog->write(log::alevel::devel,s.str());
}
message_ptr msg = m_processor->get_message();
if (!msg) {
m_alog.write(log::alevel::devel, "null message from m_processor");
m_alog->write(log::alevel::devel, "null message from m_processor");
} else if (!is_control(msg->get_opcode())) {
// data message, dispatch to user
if (m_state != session::state::open) {
m_elog.write(log::elevel::warn, "got non-close frame while closing");
m_elog->write(log::elevel::warn, "got non-close frame while closing");
} else if (m_message_handler) {
m_message_handler(m_connection_hdl, msg);
}
@ -1132,7 +1129,7 @@ void connection<config>::read_frame() {
template <typename config>
lib::error_code connection<config>::initialize_processor() {
m_alog.write(log::alevel::devel,"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)) {
@ -1142,7 +1139,7 @@ lib::error_code connection<config>::initialize_processor() {
int version = processor::get_websocket_version(m_request);
if (version < 0) {
m_alog.write(log::alevel::devel, "BAD REQUEST: can't determine version");
m_alog->write(log::alevel::devel, "BAD REQUEST: can't determine version");
m_response.set_status(http::status_code::bad_request);
return error::make_error_code(error::invalid_version);
}
@ -1156,7 +1153,7 @@ lib::error_code connection<config>::initialize_processor() {
// We don't have a processor for this version. Return bad request
// with Sec-WebSocket-Version header filled with values we do accept
m_alog.write(log::alevel::devel, "BAD REQUEST: no processor for version");
m_alog->write(log::alevel::devel, "BAD REQUEST: no processor for version");
m_response.set_status(http::status_code::bad_request);
std::stringstream ss;
@ -1174,11 +1171,11 @@ lib::error_code connection<config>::initialize_processor() {
template <typename config>
lib::error_code connection<config>::process_handshake_request() {
m_alog.write(log::alevel::devel,"process handshake request");
m_alog->write(log::alevel::devel,"process handshake request");
if (!processor::is_websocket_handshake(m_request)) {
// this is not a websocket handshake. Process as plain HTTP
m_alog.write(log::alevel::devel,"HTTP REQUEST");
m_alog->write(log::alevel::devel,"HTTP REQUEST");
// extract URI from request
m_uri = processor::get_uri_from_host(
@ -1187,7 +1184,7 @@ lib::error_code connection<config>::process_handshake_request() {
);
if (!m_uri->get_valid()) {
m_alog.write(log::alevel::devel, "Bad request: failed to parse uri");
m_alog->write(log::alevel::devel, "Bad request: failed to parse uri");
m_response.set_status(http::status_code::bad_request);
return error::make_error_code(error::invalid_uri);
}
@ -1212,7 +1209,7 @@ lib::error_code connection<config>::process_handshake_request() {
// Validate: make sure all required elements are present.
if (ec){
// Not a valid handshake request
m_alog.write(log::alevel::devel, "Bad request " + ec.message());
m_alog->write(log::alevel::devel, "Bad request " + ec.message());
m_response.set_status(http::status_code::bad_request);
return ec;
}
@ -1222,12 +1219,18 @@ lib::error_code connection<config>::process_handshake_request() {
std::pair<lib::error_code,std::string> neg_results;
neg_results = m_processor->negotiate_extensions(m_request);
if (neg_results.first) {
if (neg_results.first == processor::error::make_error_code(processor::error::extension_parse_error)) {
// There was a fatal error in extension parsing that should result in
// a failed connection attempt.
m_alog.write(log::alevel::devel, "Bad request: " + neg_results.first.message());
m_elog->write(log::elevel::info, "Bad request: " + neg_results.first.message());
m_response.set_status(http::status_code::bad_request);
return neg_results.first;
} else if (neg_results.first) {
// There was a fatal error in extension processing that is probably our
// fault. Consider extension negotiation to have failed and continue as
// if extensions were not supported
m_elog->write(log::elevel::info,
"Extension negotiation failed: " + neg_results.first.message());
} else {
// extension negotiation succeeded, set response header accordingly
// we don't send an empty extensions header because it breaks many
@ -1243,7 +1246,7 @@ lib::error_code connection<config>::process_handshake_request() {
if (!m_uri->get_valid()) {
m_alog.write(log::alevel::devel, "Bad request: failed to parse uri");
m_alog->write(log::alevel::devel, "Bad request: failed to parse uri");
m_response.set_status(http::status_code::bad_request);
return error::make_error_code(error::invalid_uri);
}
@ -1267,14 +1270,14 @@ lib::error_code connection<config>::process_handshake_request() {
if (ec) {
std::stringstream s;
s << "Processing error: " << ec << "(" << ec.message() << ")";
m_alog.write(log::alevel::devel, s.str());
m_alog->write(log::alevel::devel, s.str());
m_response.set_status(http::status_code::internal_server_error);
return ec;
}
} else {
// User application has rejected the handshake
m_alog.write(log::alevel::devel, "USER REJECT");
m_alog->write(log::alevel::devel, "USER REJECT");
// Use Bad Request if the user handler did not provide a more
// specific http response error code.
@ -1291,10 +1294,10 @@ lib::error_code connection<config>::process_handshake_request() {
template <typename config>
void connection<config>::write_http_response(lib::error_code const & ec) {
m_alog.write(log::alevel::devel,"connection write_http_response");
m_alog->write(log::alevel::devel,"connection write_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.");
m_alog->write(log::alevel::http,"An HTTP handler took over the connection.");
return;
}
@ -1324,10 +1327,10 @@ void connection<config>::write_http_response(lib::error_code const & ec) {
m_handshake_buffer = m_response.raw();
}
if (m_alog.static_test(log::alevel::devel)) {
m_alog.write(log::alevel::devel,"Raw Handshake response:\n"+m_handshake_buffer);
if (m_alog->static_test(log::alevel::devel)) {
m_alog->write(log::alevel::devel,"Raw Handshake response:\n"+m_handshake_buffer);
if (!m_response.get_header("Sec-WebSocket-Key3").empty()) {
m_alog.write(log::alevel::devel,
m_alog->write(log::alevel::devel,
utility::to_hex(m_response.get_header("Sec-WebSocket-Key3")));
}
}
@ -1346,7 +1349,7 @@ void connection<config>::write_http_response(lib::error_code const & ec) {
template <typename config>
void connection<config>::handle_write_http_response(lib::error_code const & ec) {
m_alog.write(log::alevel::devel,"handle_write_http_response");
m_alog->write(log::alevel::devel,"handle_write_http_response");
lib::error_code ecm = ec;
@ -1361,7 +1364,7 @@ void connection<config>::handle_write_http_response(lib::error_code const & ec)
// 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,
m_alog->write(log::alevel::devel,
"handle_write_http_response invoked after connection was closed");
return;
} else {
@ -1370,9 +1373,9 @@ void connection<config>::handle_write_http_response(lib::error_code const & ec)
}
if (ecm) {
if (ecm.value() == (int) transport::error::eof && m_state == session::state::closed) {
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,
m_alog->write(log::alevel::devel,
"got (expected) eof/state error from closed con");
return;
}
@ -1397,7 +1400,7 @@ void connection<config>::handle_write_http_response(lib::error_code const & ec)
std::stringstream s;
s << "Handshake ended with HTTP error: "
<< m_response.get_status_code();
m_elog.write(log::elevel::rerror,s.str());
m_elog->write(log::elevel::rerror,s.str());
} else {
// if this was not a websocket connection, we have written
// the expected response and the connection can be closed.
@ -1405,7 +1408,7 @@ void connection<config>::handle_write_http_response(lib::error_code const & ec)
this->log_http_result();
if (m_ec) {
m_alog.write(log::alevel::devel,
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);
@ -1429,7 +1432,7 @@ void connection<config>::handle_write_http_response(lib::error_code const & ec)
template <typename config>
void connection<config>::send_http_request() {
m_alog.write(log::alevel::devel,"connection send_http_request");
m_alog->write(log::alevel::devel,"connection send_http_request");
// TODO: origin header?
@ -1445,7 +1448,7 @@ void connection<config>::send_http_request() {
return;
}
} else {
m_elog.write(log::elevel::fatal,"Internal library error: missing processor");
m_elog->write(log::elevel::fatal,"Internal library error: missing processor");
return;
}
@ -1460,8 +1463,8 @@ void connection<config>::send_http_request() {
m_handshake_buffer = m_request.raw();
if (m_alog.static_test(log::alevel::devel)) {
m_alog.write(log::alevel::devel,"Raw Handshake request:\n"+m_handshake_buffer);
if (m_alog->static_test(log::alevel::devel)) {
m_alog->write(log::alevel::devel,"Raw Handshake request:\n"+m_handshake_buffer);
}
if (m_open_handshake_timeout_dur > 0) {
@ -1488,7 +1491,7 @@ void connection<config>::send_http_request() {
template <typename config>
void connection<config>::handle_send_http_request(lib::error_code const & ec) {
m_alog.write(log::alevel::devel,"handle_send_http_request");
m_alog->write(log::alevel::devel,"handle_send_http_request");
lib::error_code ecm = ec;
@ -1505,7 +1508,7 @@ void connection<config>::handle_send_http_request(lib::error_code const & ec) {
// 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,
m_alog->write(log::alevel::devel,
"handle_send_http_request invoked after connection was closed");
return;
} else {
@ -1514,9 +1517,9 @@ void connection<config>::handle_send_http_request(lib::error_code const & ec) {
}
if (ecm) {
if (ecm.value() == (int) transport::error::eof && m_state == session::state::closed) {
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,
m_alog->write(log::alevel::devel,
"got (expected) eof/state error from closed con");
return;
}
@ -1543,7 +1546,7 @@ template <typename config>
void connection<config>::handle_read_http_response(lib::error_code const & ec,
size_t bytes_transferred)
{
m_alog.write(log::alevel::devel,"handle_read_http_response");
m_alog->write(log::alevel::devel,"handle_read_http_response");
lib::error_code ecm = ec;
@ -1558,7 +1561,7 @@ void connection<config>::handle_read_http_response(lib::error_code const & ec,
// 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,
m_alog->write(log::alevel::devel,
"handle_read_http_response invoked after connection was closed");
return;
} else {
@ -1567,9 +1570,9 @@ void connection<config>::handle_read_http_response(lib::error_code const & ec,
}
if (ecm) {
if (ecm.value() == (int) transport::error::eof && m_state == session::state::closed) {
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,
m_alog->write(log::alevel::devel,
"got (expected) eof/state error from closed con");
return;
}
@ -1584,13 +1587,13 @@ void connection<config>::handle_read_http_response(lib::error_code const & ec,
try {
bytes_processed = m_response.consume(m_buf,bytes_transferred);
} catch (http::exception & e) {
m_elog.write(log::elevel::rerror,
m_elog->write(log::elevel::rerror,
std::string("error in handle_read_http_response: ")+e.what());
this->terminate(make_error_code(error::general));
return;
}
m_alog.write(log::alevel::devel,std::string("Raw response: ")+m_response.raw());
m_alog->write(log::alevel::devel,std::string("Raw response: ")+m_response.raw());
if (m_response.headers_ready()) {
if (m_handshake_timer) {
@ -1621,7 +1624,7 @@ void connection<config>::handle_read_http_response(lib::error_code const & ec,
// doesn't match the options requested by the client. Its possible
// that the best behavior in this cases is to log and continue with
// an unextended connection.
m_alog.write(log::alevel::devel, "Extension negotiation failed: "
m_alog->write(log::alevel::devel, "Extension negotiation failed: "
+ neg_results.first.message());
this->terminate(make_error_code(error::extension_neg_failed));
// TODO: close connection with reason 1010 (and list extensions)
@ -1663,14 +1666,14 @@ template <typename config>
void connection<config>::handle_open_handshake_timeout(
lib::error_code const & ec)
{
if (ec.value() == (int) transport::error::operation_aborted) {
m_alog.write(log::alevel::devel,"open handshake timer cancelled");
if (ec == transport::error::operation_aborted) {
m_alog->write(log::alevel::devel,"open handshake timer cancelled");
} else if (ec) {
m_alog.write(log::alevel::devel,
m_alog->write(log::alevel::devel,
"open handle_open_handshake_timeout error: "+ec.message());
// TODO: ignore or fail here?
} else {
m_alog.write(log::alevel::devel,"open handshake timer expired");
m_alog->write(log::alevel::devel,"open handshake timer expired");
terminate(make_error_code(error::open_handshake_timeout));
}
}
@ -1679,22 +1682,22 @@ template <typename config>
void connection<config>::handle_close_handshake_timeout(
lib::error_code const & ec)
{
if (ec.value() == (int) transport::error::operation_aborted) {
m_alog.write(log::alevel::devel,"asio close handshake timer cancelled");
if (ec == transport::error::operation_aborted) {
m_alog->write(log::alevel::devel,"asio close handshake timer cancelled");
} else if (ec) {
m_alog.write(log::alevel::devel,
m_alog->write(log::alevel::devel,
"asio open handle_close_handshake_timeout error: "+ec.message());
// TODO: ignore or fail here?
} else {
m_alog.write(log::alevel::devel, "asio close handshake timer expired");
m_alog->write(log::alevel::devel, "asio close handshake timer expired");
terminate(make_error_code(error::close_handshake_timeout));
}
}
template <typename config>
void connection<config>::terminate(lib::error_code const & ec) {
if (m_alog.static_test(log::alevel::devel)) {
m_alog.write(log::alevel::devel,"connection terminate");
if (m_alog->static_test(log::alevel::devel)) {
m_alog->write(log::alevel::devel,"connection terminate");
}
// Cancel close handshake timer
@ -1720,14 +1723,14 @@ void connection<config>::terminate(lib::error_code const & ec) {
// Log fail result here before socket is shut down and we can't get
// the remote address, etc anymore
if (m_ec.value() != (int) error::http_connection_ended) {
if (m_ec != error::http_connection_ended) {
log_fail_result();
}
} else if (m_state != session::state::closed) {
m_state = session::state::closed;
tstat = closed;
} else {
m_alog.write(log::alevel::devel,
m_alog->write(log::alevel::devel,
"terminate called on connection that was already terminated");
return;
}
@ -1748,8 +1751,8 @@ template <typename config>
void connection<config>::handle_terminate(terminate_status tstat,
lib::error_code const & ec)
{
if (m_alog.static_test(log::alevel::devel)) {
m_alog.write(log::alevel::devel,"connection handle_terminate");
if (m_alog->static_test(log::alevel::devel)) {
m_alog->write(log::alevel::devel,"connection handle_terminate");
}
if (ec) {
@ -1759,7 +1762,7 @@ void connection<config>::handle_terminate(terminate_status tstat,
// clean shutdown
if (tstat == failed) {
if (m_ec.value() != (int) error::http_connection_ended) {
if (m_ec != error::http_connection_ended) {
if (m_fail_handler) {
m_fail_handler(m_connection_hdl);
}
@ -1770,7 +1773,7 @@ void connection<config>::handle_terminate(terminate_status tstat,
}
log_close_result();
} else {
m_elog.write(log::elevel::rerror,"Unknown terminate_status");
m_elog->write(log::elevel::rerror,"Unknown terminate_status");
}
// call the termination handler if it exists
@ -1780,7 +1783,7 @@ void connection<config>::handle_terminate(terminate_status tstat,
try {
m_termination_handler(type::get_shared());
} catch (std::exception const & e) {
m_elog.write(log::elevel::warn,
m_elog->write(log::elevel::warn,
std::string("termination_handler call failed. Reason was: ")+e.what());
}
}
@ -1788,7 +1791,7 @@ void connection<config>::handle_terminate(terminate_status tstat,
template <typename config>
void connection<config>::write_frame() {
//m_alog.write(log::alevel::devel,"connection write_frame");
//m_alog->write(log::alevel::devel,"connection write_frame");
{
scoped_lock_type lock(m_write_lock);
@ -1834,8 +1837,8 @@ void connection<config>::write_frame() {
}
// Print detailed send stats if those log levels are enabled
if (m_alog.static_test(log::alevel::frame_header)) {
if (m_alog.dynamic_test(log::alevel::frame_header)) {
if (m_alog->static_test(log::alevel::frame_header)) {
if (m_alog->dynamic_test(log::alevel::frame_header)) {
std::stringstream general,header,payload;
general << "Dispatching write containing " << m_current_msgs.size()
@ -1855,8 +1858,8 @@ void connection<config>::write_frame() {
<< m_current_msgs[i]->get_header().size() << ") "
<< utility::to_hex(m_current_msgs[i]->get_header()) << "\n";
if (m_alog.static_test(log::alevel::frame_payload)) {
if (m_alog.dynamic_test(log::alevel::frame_payload)) {
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() << ") ["<<m_current_msgs[i]->get_opcode()<<"] "
<< (m_current_msgs[i]->get_opcode() == frame::opcode::text ?
@ -1870,9 +1873,9 @@ void connection<config>::write_frame() {
general << hbytes << " header bytes and " << pbytes << " payload bytes";
m_alog.write(log::alevel::frame_header,general.str());
m_alog.write(log::alevel::frame_header,header.str());
m_alog.write(log::alevel::frame_payload,payload.str());
m_alog->write(log::alevel::frame_header,general.str());
m_alog->write(log::alevel::frame_header,header.str());
m_alog->write(log::alevel::frame_payload,payload.str());
}
}
@ -1885,8 +1888,8 @@ void connection<config>::write_frame() {
template <typename config>
void connection<config>::handle_write_frame(lib::error_code const & ec)
{
if (m_alog.static_test(log::alevel::devel)) {
m_alog.write(log::alevel::devel,"connection handle_write_frame");
if (m_alog->static_test(log::alevel::devel)) {
m_alog->write(log::alevel::devel,"connection handle_write_frame");
}
bool terminal = m_current_msgs.back()->get_terminal();
@ -1933,21 +1936,21 @@ std::vector<int> const & connection<config>::get_supported_versions() const
template <typename config>
void connection<config>::process_control_frame(typename config::message_type::ptr msg)
{
m_alog.write(log::alevel::devel,"process_control_frame");
m_alog->write(log::alevel::devel,"process_control_frame");
frame::opcode::value op = msg->get_opcode();
lib::error_code ec;
std::stringstream s;
s << "Control frame received with opcode " << op;
m_alog.write(log::alevel::control,s.str());
m_alog->write(log::alevel::control,s.str());
if (m_state == session::state::closed) {
m_elog.write(log::elevel::warn,"got frame in state closed");
m_elog->write(log::elevel::warn,"got frame in state closed");
return;
}
if (op != frame::opcode::CLOSE && m_state != session::state::open) {
m_elog.write(log::elevel::warn,"got non-close frame in state closing");
m_elog->write(log::elevel::warn,"got non-close frame in state closing");
return;
}
@ -1972,7 +1975,7 @@ void connection<config>::process_control_frame(typename config::message_type::pt
m_ping_timer->cancel();
}
} else if (op == frame::opcode::CLOSE) {
m_alog.write(log::alevel::devel,"got close frame");
m_alog->write(log::alevel::devel,"got close frame");
// record close code and reason somewhere
m_remote_close_code = close::extract_code(msg->get_payload(),ec);
@ -1981,12 +1984,12 @@ void connection<config>::process_control_frame(typename config::message_type::pt
if (config::drop_on_protocol_error) {
s << "Received invalid close code " << m_remote_close_code
<< " dropping connection per config.";
m_elog.write(log::elevel::devel,s.str());
m_elog->write(log::elevel::devel,s.str());
this->terminate(ec);
} else {
s << "Received invalid close code " << m_remote_close_code
<< " sending acknowledgement and closing";
m_elog.write(log::elevel::devel,s.str());
m_elog->write(log::elevel::devel,s.str());
ec = send_close_ack(close::status::protocol_error,
"Invalid close code");
if (ec) {
@ -1999,11 +2002,11 @@ void connection<config>::process_control_frame(typename config::message_type::pt
m_remote_close_reason = close::extract_reason(msg->get_payload(),ec);
if (ec) {
if (config::drop_on_protocol_error) {
m_elog.write(log::elevel::devel,
m_elog->write(log::elevel::devel,
"Received invalid close reason. Dropping connection per config");
this->terminate(ec);
} else {
m_elog.write(log::elevel::devel,
m_elog->write(log::elevel::devel,
"Received invalid close reason. Sending acknowledgement and closing");
ec = send_close_ack(close::status::protocol_error,
"Invalid close reason");
@ -2018,7 +2021,7 @@ void connection<config>::process_control_frame(typename config::message_type::pt
s.str("");
s << "Received close frame with code " << m_remote_close_code
<< " and reason " << m_remote_close_reason;
m_alog.write(log::alevel::devel,s.str());
m_alog->write(log::alevel::devel,s.str());
ec = send_close_ack();
if (ec) {
@ -2026,7 +2029,7 @@ void connection<config>::process_control_frame(typename config::message_type::pt
}
} else if (m_state == session::state::closing && !m_was_clean) {
// ack of our close
m_alog.write(log::alevel::devel, "Got acknowledgement of close");
m_alog->write(log::alevel::devel, "Got acknowledgement of close");
m_was_clean = true;
@ -2042,11 +2045,11 @@ void connection<config>::process_control_frame(typename config::message_type::pt
}
} else {
// spurious, ignore
m_elog.write(log::elevel::devel, "Got close frame in wrong state");
m_elog->write(log::elevel::devel, "Got close frame in wrong state");
}
} else {
// got an invalid control opcode
m_elog.write(log::elevel::devel, "Got control frame with invalid opcode");
m_elog->write(log::elevel::devel, "Got control frame with invalid opcode");
// initiate protocol error shutdown
}
}
@ -2062,7 +2065,7 @@ template <typename config>
lib::error_code connection<config>::send_close_frame(close::status::value code,
std::string const & reason, bool ack, bool terminal)
{
m_alog.write(log::alevel::devel,"send_close_frame");
m_alog->write(log::alevel::devel,"send_close_frame");
// check for special codes
@ -2073,24 +2076,24 @@ lib::error_code connection<config>::send_close_frame(close::status::value code,
// send blank info. If it is an ack then echo the close information from
// the remote endpoint.
if (config::silent_close) {
m_alog.write(log::alevel::devel,"closing silently");
m_alog->write(log::alevel::devel,"closing silently");
m_local_close_code = close::status::no_status;
m_local_close_reason.clear();
} else if (code != close::status::blank) {
m_alog.write(log::alevel::devel,"closing with specified codes");
m_alog->write(log::alevel::devel,"closing with specified codes");
m_local_close_code = code;
m_local_close_reason = reason;
} else if (!ack) {
m_alog.write(log::alevel::devel,"closing with no status code");
m_alog->write(log::alevel::devel,"closing with no status code");
m_local_close_code = close::status::no_status;
m_local_close_reason.clear();
} else if (m_remote_close_code == close::status::no_status) {
m_alog.write(log::alevel::devel,
m_alog->write(log::alevel::devel,
"acknowledging a no-status close with normal code");
m_local_close_code = close::status::normal;
m_local_close_reason.clear();
} else {
m_alog.write(log::alevel::devel,"acknowledging with remote codes");
m_alog->write(log::alevel::devel,"acknowledging with remote codes");
m_local_close_code = m_remote_close_code;
m_local_close_reason = m_remote_close_reason;
}
@ -2098,7 +2101,7 @@ lib::error_code connection<config>::send_close_frame(close::status::value code,
std::stringstream s;
s << "Closing with code: " << m_local_close_code << ", and reason: "
<< m_local_close_reason;
m_alog.write(log::alevel::devel,s.str());
m_alog->write(log::alevel::devel,s.str());
message_ptr msg = m_msg_manager->get_message();
if (!msg) {
@ -2213,11 +2216,11 @@ void connection<config>::write_push(typename config::message_type::ptr msg)
m_send_buffer_size += msg->get_payload().size();
m_send_queue.push(msg);
if (m_alog.static_test(log::alevel::devel)) {
if (m_alog->static_test(log::alevel::devel)) {
std::stringstream s;
s << "write_push: message count: " << m_send_queue.size()
<< " buffer size: " << m_send_buffer_size;
m_alog.write(log::alevel::devel,s.str());
m_alog->write(log::alevel::devel,s.str());
}
}
@ -2235,11 +2238,11 @@ typename config::message_type::ptr connection<config>::write_pop()
m_send_buffer_size -= msg->get_payload().size();
m_send_queue.pop();
if (m_alog.static_test(log::alevel::devel)) {
if (m_alog->static_test(log::alevel::devel)) {
std::stringstream s;
s << "write_pop: message count: " << m_send_queue.size()
<< " buffer size: " << m_send_buffer_size;
m_alog.write(log::alevel::devel,s.str());
m_alog->write(log::alevel::devel,s.str());
}
return msg;
}
@ -2282,7 +2285,7 @@ void connection<config>::log_open_result()
// Status code
s << m_response.get_status_code();
m_alog.write(log::alevel::connect,s.str());
m_alog->write(log::alevel::connect,s.str());
}
template <typename config>
@ -2296,7 +2299,7 @@ void connection<config>::log_close_result()
<< "] remote:[" << m_remote_close_code
<< (m_remote_close_reason.empty() ? "" : ","+m_remote_close_reason) << "]";
m_alog.write(log::alevel::disconnect,s.str());
m_alog->write(log::alevel::disconnect,s.str());
}
template <typename config>
@ -2335,7 +2338,7 @@ void connection<config>::log_fail_result()
// WebSocket++ error code & reason
s << " " << m_ec << " " << m_ec.message();
m_alog.write(log::alevel::fail,s.str());
m_alog->write(log::alevel::fail,s.str());
}
template <typename config>
@ -2343,7 +2346,7 @@ void connection<config>::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");
m_alog->write(log::alevel::devel,"Call to log_http_result for WebSocket");
return;
}
@ -2364,7 +2367,7 @@ void connection<config>::log_http_result() {
s << " \"" << utility::string_replace_all(ua,"\"","\\\"") << "\" ";
}
m_alog.write(log::alevel::http,s.str());
m_alog->write(log::alevel::http,s.str());
}
} // namespace websocketpp

View File

@ -35,7 +35,7 @@ namespace websocketpp {
template <typename connection, typename config>
typename endpoint<connection,config>::connection_ptr
endpoint<connection,config>::create_connection() {
m_alog.write(log::alevel::devel,"create_connection");
m_alog->write(log::alevel::devel,"create_connection");
//scoped_lock_type lock(m_state_lock);
/*if (m_state == STOPPING || m_state == STOPPED) {
@ -45,7 +45,7 @@ endpoint<connection,config>::create_connection() {
//scoped_lock_type guard(m_mutex);
// Create a connection on the heap and manage it using a shared pointer
connection_ptr con = lib::make_shared<connection_type>(m_is_server,
m_user_agent, lib::ref(m_alog), lib::ref(m_elog), lib::ref(m_rng));
m_user_agent, m_alog, m_elog, lib::ref(m_rng));
connection_weak_ptr w(con);
@ -85,7 +85,7 @@ endpoint<connection,config>::create_connection() {
ec = transport_type::init(con);
if (ec) {
m_elog.write(log::elevel::fatal,ec.message());
m_elog->write(log::elevel::fatal,ec.message());
return connection_ptr();
}
@ -98,7 +98,7 @@ void endpoint<connection,config>::interrupt(connection_hdl hdl, lib::error_code
connection_ptr con = get_con_from_hdl(hdl,ec);
if (ec) {return;}
m_alog.write(log::alevel::devel,"Interrupting connection");
m_alog->write(log::alevel::devel,"Interrupting connection");
ec = con->interrupt();
}

View File

@ -44,7 +44,7 @@ namespace processor {
namespace constants {
static char const upgrade_token[] = "websocket";
static char const connection_token[] = "upgrade";
static char const connection_token[] = "Upgrade";
static char const handshake_guid[] = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
} // namespace constants

View File

@ -125,38 +125,60 @@ public:
http::parameter_list::const_iterator it;
// look through the list of extension requests to find the first
// one that we can accept.
if (m_permessage_deflate.is_implemented()) {
err_str_pair neg_ret;
for (it = p.begin(); it != p.end(); ++it) {
// look through each extension, if the key is permessage-deflate
if (it->first == "permessage-deflate") {
// if we have already successfully negotiated this extension
// then skip any other requests to negotiate the same one
// with different parameters
if (m_permessage_deflate.is_enabled()) {
continue;
}
neg_ret = m_permessage_deflate.negotiate(it->second);
// not a permessage-deflate extension request, ignore
if (it->first != "permessage-deflate") {
continue;
}
if (neg_ret.first) {
// Figure out if this is an error that should halt all
// extension negotiations or simply cause negotiation of
// this specific extension to fail.
//std::cout << "permessage-compress negotiation failed: "
// << neg_ret.first.message() << std::endl;
} else {
// Note: this list will need commas if WebSocket++ ever
// supports more than one extension
ret.second += neg_ret.second;
m_permessage_deflate.init(base::m_server);
continue;
}
// if we have already successfully negotiated this extension
// then skip any other requests to negotiate the same one
// with different parameters
if (m_permessage_deflate.is_enabled()) {
continue;
}
// attempt to negotiate this offer
neg_ret = m_permessage_deflate.negotiate(it->second);
if (neg_ret.first) {
// negotiation offer failed. Do nothing. We will continue
// searching for a permessage-deflate config that succeeds
continue;
}
// Negotiation tentatively succeeded
// Actually try to initialize the extension before we
// deem negotiation complete
lib::error_code ec = m_permessage_deflate.init(base::m_server);
if (ec) {
// Negotiation succeeded but initialization failed this is
// an error that should stop negotiation of permessage
// deflate. Return the reason for the init failure
ret.first = ec;
break;
} else {
// Successfully initialized, push the negotiated response into
// the reply and stop looking for additional permessage-deflate
// extensions
ret.second += neg_ret.second;
break;
}
}
}
// support for future extensions would go here. Should check the value of
// ret.first before continuing. Might need to consider whether failure of
// negotiation of an earlier extension should stop negotiation of subsequent
// ones
return ret;
}

View File

@ -71,7 +71,7 @@ public:
explicit client() : endpoint_type(false)
{
endpoint_type::m_alog.write(log::alevel::devel, "client constructor");
endpoint_type::m_alog->write(log::alevel::devel, "client constructor");
}
/// Get a new connection
@ -157,10 +157,10 @@ private:
if (ec) {
con->terminate(ec);
endpoint_type::m_elog.write(log::elevel::rerror,
endpoint_type::m_elog->write(log::elevel::rerror,
"handle_connect error: "+ec.message());
} else {
endpoint_type::m_alog.write(log::alevel::connect,
endpoint_type::m_alog->write(log::alevel::connect,
"Successful connection");
con->start();

View File

@ -68,7 +68,7 @@ public:
explicit server() : endpoint_type(true)
{
endpoint_type::m_alog.write(log::alevel::devel, "server constructor");
endpoint_type::m_alog->write(log::alevel::devel, "server constructor");
}
/// Destructor
@ -77,7 +77,7 @@ public:
#ifdef _WEBSOCKETPP_DEFAULT_DELETE_FUNCTIONS_
// no copy constructor because endpoints are not copyable
server<config>(server<config> &) = delete;
// no copy assignment operator because endpoints are not copyable
server<config> & operator=(server<config> const &) = delete;
#endif // _WEBSOCKETPP_DEFAULT_DELETE_FUNCTIONS_
@ -115,7 +115,7 @@ public:
*
* Refer to documentation for the transport policy you are using for
* instructions on how to stop this acceptance loop.
*
*
* @param [out] ec A status code indicating an error, if any.
*/
void start_accept(lib::error_code & ec) {
@ -126,13 +126,18 @@ public:
ec = lib::error_code();
connection_ptr con = get_connection();
if (!con) {
ec = error::make_error_code(error::con_creation_failed);
return;
}
transport_type::async_accept(
lib::static_pointer_cast<transport_con_type>(con),
lib::bind(&type::handle_accept,this,con,lib::placeholders::_1),
ec
);
if (ec && con) {
// If the connection was constructed but the accept failed,
// terminate the connection to prevent memory leaks
@ -162,11 +167,11 @@ public:
if (ec) {
con->terminate(ec);
if (ec.value() == (int) error::operation_canceled) {
endpoint_type::m_elog.write(log::elevel::info,
if (ec == error::operation_canceled) {
endpoint_type::m_elog->write(log::elevel::info,
"handle_accept error: "+ec.message());
} else {
endpoint_type::m_elog.write(log::elevel::rerror,
endpoint_type::m_elog->write(log::elevel::rerror,
"handle_accept error: "+ec.message());
}
} else {
@ -175,11 +180,11 @@ public:
lib::error_code start_ec;
start_accept(start_ec);
if (start_ec.value() == (int) error::async_accept_not_listening) {
endpoint_type::m_elog.write(log::elevel::info,
if (start_ec == error::async_accept_not_listening) {
endpoint_type::m_elog->write(log::elevel::info,
"Stopping acceptance of new connections because the underlying transport is no longer listening.");
} else if (start_ec) {
endpoint_type::m_elog.write(log::elevel::rerror,
endpoint_type::m_elog->write(log::elevel::rerror,
"Restarting async_accept loop failed: "+ec.message());
}
}

View File

@ -98,12 +98,12 @@ public:
friend class endpoint<config>;
// generate and manage our own io_service
explicit connection(bool is_server, alog_type & alog, elog_type & elog)
explicit connection(bool is_server, const lib::shared_ptr<alog_type> & alog, const lib::shared_ptr<elog_type> & elog)
: m_is_server(is_server)
, m_alog(alog)
, m_elog(elog)
{
m_alog.write(log::alevel::devel,"asio con transport constructor");
m_alog->write(log::alevel::devel,"asio con transport constructor");
}
/// Get a shared pointer to this component
@ -120,7 +120,7 @@ public:
* Called by the endpoint as a connection is being established to provide
* the uri being connected to to the transport layer.
*
* This transport policy doesn't use the uri except to forward it to the
* This transport policy doesn't use the uri except to forward it to the
* socket layer.
*
* @since 0.6.0
@ -284,7 +284,7 @@ public:
std::string ret = socket_con_type::get_remote_endpoint(ec);
if (ec) {
m_elog.write(log::elevel::info,ret);
m_elog->write(log::elevel::info,ret);
return "Unknown";
} else {
return ret;
@ -314,7 +314,8 @@ public:
timer_ptr new_timer(
new lib::asio::steady_timer(
*m_io_service,
lib::asio::milliseconds(duration)));
lib::asio::milliseconds(duration))
);
if (config::enable_multithreading) {
new_timer->async_wait(m_strand->wrap(lib::bind(
@ -350,7 +351,7 @@ public:
lib::asio::error_code const & ec)
{
if (ec) {
if (ec.value() == (int) lib::asio::error::operation_aborted) {
if (ec == lib::asio::error::operation_aborted) {
callback(make_error_code(transport::error::operation_aborted));
} else {
log_err(log::elevel::info,"asio handle_timer",ec);
@ -375,14 +376,14 @@ public:
* Primarily used if you are using mismatched asio / system_error
* implementations such as `boost::asio` with `std::system_error`. In these
* cases the transport error type is different than the library error type
* and some WebSocket++ functions that return transport errors via the
* and some WebSocket++ functions that return transport errors via the
* library error code type will be coerced into a catch all `pass_through`
* or `tls_error` error. This method will return the original machine
* or `tls_error` error. This method will return the original machine
* readable transport error in the native type.
*
* @since 0.7.0
*
* @return Error code indicating the reason the connection was closed or
* @return Error code indicating the reason the connection was closed or
* failed
*/
lib::asio::error_code get_transport_ec() const {
@ -408,8 +409,8 @@ public:
*/
protected:
void init(init_handler callback) {
if (m_alog.static_test(log::alevel::devel)) {
m_alog.write(log::alevel::devel,"asio connection init");
if (m_alog->static_test(log::alevel::devel)) {
m_alog->write(log::alevel::devel,"asio connection init");
}
// TODO: pre-init timeout. Right now no implemented socket policies
@ -471,8 +472,8 @@ protected:
}
void handle_pre_init(init_handler callback, lib::error_code const & ec) {
if (m_alog.static_test(log::alevel::devel)) {
m_alog.write(log::alevel::devel,"asio connection handle pre_init");
if (m_alog->static_test(log::alevel::devel)) {
m_alog->write(log::alevel::devel,"asio connection handle pre_init");
}
if (m_tcp_pre_init_handler) {
@ -493,12 +494,12 @@ protected:
}
void post_init(init_handler callback) {
if (m_alog.static_test(log::alevel::devel)) {
m_alog.write(log::alevel::devel,"asio connection post_init");
if (m_alog->static_test(log::alevel::devel)) {
m_alog->write(log::alevel::devel,"asio connection post_init");
}
timer_ptr post_timer;
if (config::timeout_socket_post_init > 0) {
post_timer = set_timer(
config::timeout_socket_post_init,
@ -538,8 +539,8 @@ protected:
lib::error_code ret_ec;
if (ec) {
if (ec.value() == (int) transport::error::operation_aborted) {
m_alog.write(log::alevel::devel,
if (ec == transport::error::operation_aborted) {
m_alog->write(log::alevel::devel,
"asio post init timer cancelled");
return;
}
@ -554,7 +555,7 @@ protected:
}
}
m_alog.write(log::alevel::devel, "Asio transport post-init timed out");
m_alog->write(log::alevel::devel, "Asio transport post-init timed out");
cancel_socket_checked();
callback(ret_ec);
}
@ -571,10 +572,10 @@ protected:
void handle_post_init(timer_ptr post_timer, init_handler callback,
lib::error_code const & ec)
{
if (ec.value() == (int) transport::error::operation_aborted ||
if (ec == transport::error::operation_aborted ||
(post_timer && lib::asio::is_neg(post_timer->expires_from_now())))
{
m_alog.write(log::alevel::devel,"post_init cancelled");
m_alog->write(log::alevel::devel,"post_init cancelled");
return;
}
@ -582,8 +583,8 @@ protected:
post_timer->cancel();
}
if (m_alog.static_test(log::alevel::devel)) {
m_alog.write(log::alevel::devel,"asio connection handle_post_init");
if (m_alog->static_test(log::alevel::devel)) {
m_alog->write(log::alevel::devel,"asio connection handle_post_init");
}
if (m_tcp_post_init_handler) {
@ -594,12 +595,12 @@ protected:
}
void proxy_write(init_handler callback) {
if (m_alog.static_test(log::alevel::devel)) {
m_alog.write(log::alevel::devel,"asio connection proxy_write");
if (m_alog->static_test(log::alevel::devel)) {
m_alog->write(log::alevel::devel,"asio connection proxy_write");
}
if (!m_proxy_data) {
m_elog.write(log::elevel::library,
m_elog->write(log::elevel::library,
"assertion failed: !m_proxy_data in asio::connection::proxy_write");
callback(make_error_code(error::general));
return;
@ -610,7 +611,7 @@ protected:
m_bufs.push_back(lib::asio::buffer(m_proxy_data->write_buf.data(),
m_proxy_data->write_buf.size()));
m_alog.write(log::alevel::devel,m_proxy_data->write_buf);
m_alog->write(log::alevel::devel,m_proxy_data->write_buf);
// Set a timer so we don't wait forever for the proxy to respond
m_proxy_data->timer = this->set_timer(
@ -649,15 +650,15 @@ protected:
void handle_proxy_timeout(init_handler callback, lib::error_code const & ec)
{
if (ec.value() == (int) transport::error::operation_aborted) {
m_alog.write(log::alevel::devel,
if (ec == transport::error::operation_aborted) {
m_alog->write(log::alevel::devel,
"asio handle_proxy_write timer cancelled");
return;
} else if (ec) {
log_err(log::elevel::devel,"asio handle_proxy_write",ec);
callback(ec);
} else {
m_alog.write(log::alevel::devel,
m_alog->write(log::alevel::devel,
"asio handle_proxy_write timer expired");
cancel_socket_checked();
callback(make_error_code(transport::error::timeout));
@ -667,8 +668,8 @@ protected:
void handle_proxy_write(init_handler callback,
lib::asio::error_code const & ec)
{
if (m_alog.static_test(log::alevel::devel)) {
m_alog.write(log::alevel::devel,
if (m_alog->static_test(log::alevel::devel)) {
m_alog->write(log::alevel::devel,
"asio connection handle_proxy_write");
}
@ -677,10 +678,10 @@ protected:
// Timer expired or the operation was aborted for some reason.
// Whatever aborted it will be issuing the callback so we are safe to
// return
if (ec.value() == (int) lib::asio::error::operation_aborted ||
if (ec == lib::asio::error::operation_aborted ||
lib::asio::is_neg(m_proxy_data->timer->expires_from_now()))
{
m_elog.write(log::elevel::devel,"write operation aborted");
m_elog->write(log::elevel::devel,"write operation aborted");
return;
}
@ -695,12 +696,12 @@ protected:
}
void proxy_read(init_handler callback) {
if (m_alog.static_test(log::alevel::devel)) {
m_alog.write(log::alevel::devel,"asio connection proxy_read");
if (m_alog->static_test(log::alevel::devel)) {
m_alog->write(log::alevel::devel,"asio connection proxy_read");
}
if (!m_proxy_data) {
m_elog.write(log::elevel::library,
m_elog->write(log::elevel::library,
"assertion failed: !m_proxy_data in asio::connection::proxy_read");
m_proxy_data->timer->cancel();
callback(make_error_code(error::general));
@ -741,18 +742,18 @@ protected:
void handle_proxy_read(init_handler callback,
lib::asio::error_code const & ec, size_t)
{
if (m_alog.static_test(log::alevel::devel)) {
m_alog.write(log::alevel::devel,
if (m_alog->static_test(log::alevel::devel)) {
m_alog->write(log::alevel::devel,
"asio connection handle_proxy_read");
}
// Timer expired or the operation was aborted for some reason.
// Whatever aborted it will be issuing the callback so we are safe to
// return
if (ec.value() == (int) lib::asio::error::operation_aborted ||
if (ec == lib::asio::error::operation_aborted ||
lib::asio::is_neg(m_proxy_data->timer->expires_from_now()))
{
m_elog.write(log::elevel::devel,"read operation aborted");
m_elog->write(log::elevel::devel,"read operation aborted");
return;
}
@ -760,12 +761,12 @@ protected:
m_proxy_data->timer->cancel();
if (ec) {
m_elog.write(log::elevel::info,
m_elog->write(log::elevel::info,
"asio handle_proxy_read error: "+ec.message());
callback(make_error_code(error::pass_through));
} else {
if (!m_proxy_data) {
m_elog.write(log::elevel::library,
m_elog->write(log::elevel::library,
"assertion failed: !m_proxy_data in asio::connection::handle_proxy_read");
callback(make_error_code(error::general));
return;
@ -782,7 +783,7 @@ protected:
return;
}
m_alog.write(log::alevel::devel,m_proxy_data->res.raw());
m_alog->write(log::alevel::devel,m_proxy_data->res.raw());
if (m_proxy_data->res.get_status_code() != http::status_code::ok) {
// got an error response back
@ -794,7 +795,7 @@ protected:
<< " ("
<< m_proxy_data->res.get_status_msg()
<< ")";
m_elog.write(log::elevel::info,s.str());
m_elog->write(log::elevel::info,s.str());
callback(make_error_code(error::proxy_failed));
return;
}
@ -819,16 +820,16 @@ protected:
void async_read_at_least(size_t num_bytes, char *buf, size_t len,
read_handler handler)
{
if (m_alog.static_test(log::alevel::devel)) {
if (m_alog->static_test(log::alevel::devel)) {
std::stringstream s;
s << "asio async_read_at_least: " << num_bytes;
m_alog.write(log::alevel::devel,s.str());
m_alog->write(log::alevel::devel,s.str());
}
// TODO: safety vs speed ?
// maybe move into an if devel block
/*if (num_bytes > len) {
m_elog.write(log::elevel::devel,
m_elog->write(log::elevel::devel,
"asio async_read_at_least error::invalid_num_bytes");
handler(make_error_code(transport::error::invalid_num_bytes),
size_t(0));
@ -862,19 +863,19 @@ protected:
lib::placeholders::_1, lib::placeholders::_2
)
)
);
);
}
}
void handle_async_read(read_handler handler, lib::asio::error_code const & ec,
size_t bytes_transferred)
{
m_alog.write(log::alevel::devel, "asio con handle_async_read");
m_alog->write(log::alevel::devel, "asio con handle_async_read");
// translate asio error codes into more lib::error_codes
lib::error_code tec;
if (ec.value() == (int) lib::asio::error::eof) {
if (ec == lib::asio::error::eof) {
tec = make_error_code(transport::error::eof);
} else if (ec) {
// We don't know much more about the error at this point. As our
@ -882,8 +883,8 @@ protected:
tec = socket_con_type::translate_ec(ec);
m_tec = ec;
if (tec.value() == (int) transport::error::tls_error ||
tec.value() == (int) transport::error::pass_through)
if (tec == transport::error::tls_error ||
tec == transport::error::pass_through)
{
// These are aggregate/catch all errors. Log some human readable
// information to the info channel to give library users some
@ -896,7 +897,7 @@ protected:
} else {
// This can happen in cases where the connection is terminated while
// the transport is waiting on a read.
m_alog.write(log::alevel::devel,
m_alog->write(log::alevel::devel,
"handle_async_read called with null read handler");
}
}
@ -988,7 +989,7 @@ protected:
} else {
// This can happen in cases where the connection is terminated while
// the transport is waiting on a read.
m_alog.write(log::alevel::devel,
m_alog->write(log::alevel::devel,
"handle_async_write called with null write handler");
}
}
@ -1033,8 +1034,8 @@ protected:
/// close and clean up the underlying socket
void async_shutdown(shutdown_handler callback) {
if (m_alog.static_test(log::alevel::devel)) {
m_alog.write(log::alevel::devel,"asio connection async_shutdown");
if (m_alog->static_test(log::alevel::devel)) {
m_alog->write(log::alevel::devel,"asio connection async_shutdown");
}
timer_ptr shutdown_timer;
@ -1066,14 +1067,14 @@ protected:
* @param callback The function to call back
* @param ec The status code
*/
void handle_async_shutdown_timeout(timer_ptr, init_handler callback,
void handle_async_shutdown_timeout(timer_ptr, init_handler callback,
lib::error_code const & ec)
{
lib::error_code ret_ec;
if (ec) {
if (ec.value() == (int) transport::error::operation_aborted) {
m_alog.write(log::alevel::devel,
if (ec == transport::error::operation_aborted) {
m_alog->write(log::alevel::devel,
"asio socket shutdown timer cancelled");
return;
}
@ -1084,7 +1085,7 @@ protected:
ret_ec = make_error_code(transport::error::timeout);
}
m_alog.write(log::alevel::devel,
m_alog->write(log::alevel::devel,
"Asio transport socket shutdown timed out");
cancel_socket_checked();
callback(ret_ec);
@ -1093,10 +1094,10 @@ protected:
void handle_async_shutdown(timer_ptr shutdown_timer, shutdown_handler
callback, lib::asio::error_code const & ec)
{
if (ec.value() == (int) lib::asio::error::operation_aborted ||
if (ec == lib::asio::error::operation_aborted ||
lib::asio::is_neg(shutdown_timer->expires_from_now()))
{
m_alog.write(log::alevel::devel,"async_shutdown cancelled");
m_alog->write(log::alevel::devel,"async_shutdown cancelled");
return;
}
@ -1104,7 +1105,7 @@ protected:
lib::error_code tec;
if (ec) {
if (ec.value() == (int) lib::asio::error::not_connected) {
if (ec == lib::asio::error::not_connected) {
// The socket was already closed when we tried to close it. This
// happens periodically (usually if a read or write fails
// earlier and if it is a real error will be caught at another
@ -1115,21 +1116,14 @@ protected:
tec = socket_con_type::translate_ec(ec);
m_tec = ec;
if (tec.value() == (int) transport::error::tls_short_read) {
// TLS short read at this point is somewhat expected if both
// sides try and end the connection at the same time or if
// SSLv2 is being used. In general there is nothing that can
// be done here other than a low level development log.
} else {
// all other errors are effectively pass through errors of
// some sort so print some detail on the info channel for
// library users to look up if needed.
log_err(log::elevel::info,"asio async_shutdown",ec);
}
// all other errors are effectively pass through errors of
// some sort so print some detail on the info channel for
// library users to look up if needed.
log_err(log::elevel::info,"asio async_shutdown",ec);
}
} else {
if (m_alog.static_test(log::alevel::devel)) {
m_alog.write(log::alevel::devel,
if (m_alog->static_test(log::alevel::devel)) {
m_alog->write(log::alevel::devel,
"asio con handle_async_shutdown");
}
}
@ -1140,9 +1134,9 @@ protected:
void cancel_socket_checked() {
lib::asio::error_code cec = socket_con_type::cancel_socket();
if (cec) {
if (cec.value() == (int) lib::asio::error::operation_not_supported) {
if (cec == lib::asio::error::operation_not_supported) {
// cancel not supported on this OS, ignore and log at dev level
m_alog.write(log::alevel::devel, "socket cancel not supported");
m_alog->write(log::alevel::devel, "socket cancel not supported");
} else {
log_err(log::elevel::warn, "socket cancel failed", cec);
}
@ -1155,13 +1149,13 @@ private:
void log_err(log::level l, const char * msg, const error_type & ec) {
std::stringstream s;
s << msg << " error: " << ec << " (" << ec.message() << ")";
m_elog.write(l,s.str());
m_elog->write(l,s.str());
}
// static settings
const bool m_is_server;
alog_type& m_alog;
elog_type& m_elog;
lib::shared_ptr<alog_type> m_alog;
lib::shared_ptr<elog_type> m_elog;
struct proxy_data {
proxy_data() : timeout_proxy(config::timeout_proxy) {}

View File

@ -35,6 +35,7 @@
#include <websocketpp/uri.hpp>
#include <websocketpp/logger/levels.hpp>
#include <websocketpp/common/asio.hpp>
#include <websocketpp/common/functional.hpp>
#include <sstream>
@ -87,11 +88,14 @@ public:
/// Type of a shared pointer to an io_service work object
typedef lib::shared_ptr<lib::asio::io_service::work> work_ptr;
/// Type of socket pre-bind handler
typedef lib::function<lib::error_code(acceptor_ptr)> tcp_pre_bind_handler;
// generate and manage our own io_service
explicit endpoint()
: m_io_service(NULL)
, m_external_io_service(false)
, m_listen_backlog(0)
, m_listen_backlog(lib::asio::socket_base::max_connections)
, m_reuse_addr(false)
, m_state(UNINITIALIZED)
{
@ -157,7 +161,7 @@ public:
rhs.m_acceptor = NULL;
rhs.m_listen_backlog = lib::asio::socket_base::max_connections;
rhs.m_state = UNINITIALIZED;
// TODO: this needs to be updated
}
return *this;
@ -221,7 +225,7 @@ public:
* @param ec Set to indicate what error occurred, if any.
*/
void init_asio(lib::error_code & ec) {
// Use a smart pointer until the call is successful and ownership has
// Use a smart pointer until the call is successful and ownership has
// successfully been taken. Use unique_ptr when available.
// TODO: remove the use of auto_ptr when C++98/03 support is no longer
// necessary.
@ -243,7 +247,7 @@ public:
* @see init_asio(io_service_ptr ptr)
*/
void init_asio() {
// Use a smart pointer until the call is successful and ownership has
// Use a smart pointer until the call is successful and ownership has
// successfully been taken. Use unique_ptr when available.
// TODO: remove the use of auto_ptr when C++98/03 support is no longer
// necessary.
@ -258,6 +262,19 @@ public:
m_external_io_service = false;
}
/// Sets the tcp pre bind handler
/**
* The tcp pre bind handler is called after the listen acceptor has
* been created but before the socket bind is performed.
*
* @since 0.8.0
*
* @param h The handler to call on tcp pre bind init.
*/
void set_tcp_pre_bind_handler(tcp_pre_bind_handler h) {
m_tcp_pre_bind_handler = h;
}
/// Sets the tcp pre init handler
/**
* The tcp pre init handler is called after the raw tcp connection has been
@ -313,8 +330,10 @@ public:
*
* New values affect future calls to listen only.
*
* A value of zero will use the operating system default. This is the
* default value.
* The default value is specified as *::asio::socket_base::max_connections
* which uses the operating system defined maximum queue length. Your OS
* may restrict or silently lower this value. A value of zero may cause
* all connections to be rejected.
*
* @since 0.3.0
*
@ -327,10 +346,13 @@ public:
/// 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
* this flag does depends on your operating system. Please consult operating
* system documentation for more details.
* this flag does depends on your operating system.
*
* New values affect future calls to listen only.
* Please consult operating system documentation for more details. There
* may be security consequences to enabling this option.
*
* New values affect future calls to listen only so set this value prior to
* calling listen.
*
* The default is false.
*
@ -356,7 +378,7 @@ public:
lib::asio::io_service & get_io_service() {
return *m_io_service;
}
/// Get local TCP endpoint
/**
* Extracts the local endpoint from the acceptor. This represents the
@ -364,7 +386,7 @@ public:
*
* Sets a bad_descriptor error if the acceptor is not currently listening
* or otherwise unavailable.
*
*
* @since 0.7.0
*
* @param ec Set to indicate what error occurred, if any.
@ -402,27 +424,33 @@ public:
lib::asio::error_code bec;
m_acceptor->open(ep.protocol(),bec);
if (!bec) {
m_acceptor->set_option(lib::asio::socket_base::reuse_address(m_reuse_addr),bec);
}
if (!bec) {
m_acceptor->bind(ep,bec);
}
if (!bec) {
m_acceptor->listen(m_listen_backlog,bec);
}
if (bec) {
if (m_acceptor->is_open()) {
m_acceptor->close();
if (bec) {ec = clean_up_listen_after_error(bec);return;}
m_acceptor->set_option(lib::asio::socket_base::reuse_address(m_reuse_addr),bec);
if (bec) {ec = clean_up_listen_after_error(bec);return;}
// if a TCP pre-bind handler is present, run it
if (m_tcp_pre_bind_handler) {
ec = m_tcp_pre_bind_handler(m_acceptor);
if (ec) {
ec = clean_up_listen_after_error(ec);
return;
}
log_err(log::elevel::info,"asio listen",bec);
ec = make_error_code(error::pass_through);
} else {
m_state = LISTENING;
ec = lib::error_code();
}
m_acceptor->bind(ep,bec);
if (bec) {ec = clean_up_listen_after_error(bec);return;}
m_acceptor->listen(m_listen_backlog,bec);
if (bec) {ec = clean_up_listen_after_error(bec);return;}
// Success
m_state = LISTENING;
ec = lib::error_code();
}
/// Set up endpoint for listening manually
/**
* Bind the internal acceptor using the settings specified by the endpoint e
@ -724,7 +752,7 @@ public:
m_elog->write(log::elevel::info,
"asio handle_timer error: "+ec.message());
log_err(log::elevel::info,"asio handle_timer",ec);
callback(make_error_code(error::pass_through));
callback(socket_con_type::translate_ec(ec));
}
} else {
callback(lib::error_code());
@ -740,7 +768,7 @@ public:
void async_accept(transport_con_ptr tcon, accept_handler callback,
lib::error_code & ec)
{
if (m_state != LISTENING) {
if (m_state != LISTENING || !m_acceptor) {
using websocketpp::error::make_error_code;
ec = make_error_code(websocketpp::error::async_accept_not_listening);
return;
@ -792,12 +820,12 @@ protected:
* haven't been constructed yet, and cannot be used in the transport
* destructor as they will have been destroyed by then.
*/
void init_logging(alog_type* a, elog_type* e) {
void init_logging(const lib::shared_ptr<alog_type>& a, const lib::shared_ptr<elog_type>& e) {
m_alog = a;
m_elog = e;
}
void handle_accept(accept_handler callback, lib::asio::error_code const &
void handle_accept(accept_handler callback, lib::asio::error_code const &
asio_ec)
{
lib::error_code ret_ec;
@ -805,11 +833,11 @@ protected:
m_alog->write(log::alevel::devel, "asio::handle_accept");
if (asio_ec) {
if (asio_ec.value() == (int) lib::asio::errc::operation_canceled) {
if (asio_ec == lib::asio::errc::operation_canceled) {
ret_ec = make_error_code(websocketpp::error::operation_canceled);
} else {
log_err(log::elevel::info,"asio handle_accept",asio_ec);
ret_ec = make_error_code(error::pass_through);
ret_ec = socket_con_type::translate_ec(asio_ec);
}
}
@ -951,7 +979,7 @@ protected:
if (ec) {
log_err(log::elevel::info,"asio async_resolve",ec);
callback(make_error_code(error::pass_through));
callback(socket_con_type::translate_ec(ec));
return;
}
@ -1059,7 +1087,7 @@ protected:
if (ec) {
log_err(log::elevel::info,"asio async_connect",ec);
callback(make_error_code(error::pass_through));
callback(socket_con_type::translate_ec(ec));
return;
}
@ -1108,6 +1136,16 @@ private:
m_elog->write(l,s.str());
}
/// Helper for cleaning up in the listen method after an error
template <typename error_type>
lib::error_code clean_up_listen_after_error(error_type const & ec) {
if (m_acceptor->is_open()) {
m_acceptor->close();
}
log_err(log::elevel::info,"asio listen",ec);
return socket_con_type::translate_ec(ec);
}
enum state {
UNINITIALIZED = 0,
READY = 1,
@ -1115,6 +1153,7 @@ private:
};
// Handlers
tcp_pre_bind_handler m_tcp_pre_bind_handler;
tcp_init_handler m_tcp_pre_init_handler;
tcp_init_handler m_tcp_post_init_handler;
@ -1129,8 +1168,8 @@ private:
int m_listen_backlog;
bool m_reuse_addr;
elog_type* m_elog;
alog_type* m_alog;
lib::shared_ptr<elog_type> m_elog;
lib::shared_ptr<alog_type> m_alog;
// Transport state
state m_state;

View File

@ -170,6 +170,10 @@ protected:
m_socket.reset(new lib::asio::ip::tcp::socket(*service));
if (m_socket_init_handler) {
m_socket_init_handler(m_hdl, *m_socket);
}
m_state = READY;
return lib::error_code();
@ -203,10 +207,6 @@ protected:
return;
}
if (m_socket_init_handler) {
m_socket_init_handler(m_hdl,*m_socket);
}
m_state = READING;
callback(lib::error_code());
@ -260,16 +260,17 @@ protected:
return lib::error_code();
}
public:
/// Translate any security policy specific information about an error code
/**
* Translate_ec takes an Asio error code and attempts to convert its value
* Translate_ec takes an Asio error code and attempts to convert its value
* to an appropriate websocketpp error code. In the case that the Asio and
* Websocketpp error types are the same (such as using boost::asio and
* boost::system_error or using standalone asio and std::system_error the
* code will be passed through natively.
*
* In the case of a mismatch (boost::asio with std::system_error) a
* translated code will be returned. The plain socket policy does not have
* translated code will be returned. The plain socket policy does not have
* any additional information so all such errors will be reported as the
* generic transport pass_through error.
*
@ -279,12 +280,14 @@ protected:
* @return The translated error code
*/
template <typename ErrorCodeType>
static
lib::error_code translate_ec(ErrorCodeType) {
// We don't know any more information about this error so pass through
return make_error_code(transport::error::pass_through);
}
/// Overload of translate_ec to catch cases where lib::error_code is the
static
/// Overload of translate_ec to catch cases where lib::error_code is the
/// same type as lib::asio::error_code
lib::error_code translate_ec(lib::error_code ec) {
// We don't know any more information about this error, but the error is

View File

@ -195,6 +195,10 @@ protected:
}
m_socket.reset(new socket_type(*service, *m_context));
if (m_socket_init_handler) {
m_socket_init_handler(m_hdl, get_socket());
}
m_io_service = service;
m_strand = strand;
m_is_server = is_server;
@ -228,7 +232,7 @@ protected:
* @param callback Handler to call back with completion information
*/
void pre_init(init_handler callback) {
// TODO: is this the best way to check whether this function is
// TODO: is this the best way to check whether this function is
// available in the version of OpenSSL being used?
// TODO: consider case where host is an IP address
#if OPENSSL_VERSION_NUMBER >= 0x90812f
@ -244,10 +248,6 @@ protected:
}
#endif
if (m_socket_init_handler) {
m_socket_init_handler(m_hdl,get_socket());
}
callback(lib::error_code());
}
@ -332,6 +332,7 @@ protected:
}
}
public:
/// Translate any security policy specific information about an error code
/**
* Translate_ec takes an Asio error code and attempts to convert its value
@ -352,15 +353,12 @@ protected:
* @return The translated error code
*/
template <typename ErrorCodeType>
static
lib::error_code translate_ec(ErrorCodeType ec) {
if (ec.category() == lib::asio::error::get_ssl_category()) {
if (ERR_GET_REASON(ec.value()) == SSL_R_SHORT_READ) {
return make_error_code(transport::error::tls_short_read);
} else {
// We know it is a TLS related error, but otherwise don't know
// more. Pass through as TLS generic.
return make_error_code(transport::error::tls_error);
}
// We know it is a TLS related error, but otherwise don't know more.
// Pass through as TLS generic.
return make_error_code(transport::error::tls_error);
} else {
// We don't know any more information about this error so pass
// through
@ -368,17 +366,10 @@ protected:
}
}
static
/// Overload of translate_ec to catch cases where lib::error_code is the
/// same type as lib::asio::error_code
lib::error_code translate_ec(lib::error_code ec) {
// Normalize the tls_short_read error as it is used by the library and
// needs a consistent value. All other errors pass through natively.
// TODO: how to get the SSL category from std::error?
/*if (ec.category() == lib::asio::error::get_ssl_category()) {
if (ERR_GET_REASON(ec.value()) == SSL_R_SHORT_READ) {
return make_error_code(transport::error::tls_short_read);
}
}*/
return ec;
}
private:

View File

@ -59,7 +59,7 @@ namespace websocketpp {
* `connection_hdl` and any error that occurred.
*
* **init_logging**
* `void init_logging(alog_type * a, elog_type * e)`\n
* `void init_logging(const lib::shared_ptr<alog_type>& a, const lib::shared_ptr<elog_type>& e)`\n
* Called once after construction to provide pointers to the endpoint's access
* and error loggers. These may be stored and used to log messages or ignored.
*/

View File

@ -77,7 +77,7 @@ public:
typedef lib::shared_ptr<timer> timer_ptr;
explicit connection(bool is_server, alog_type & alog, elog_type & elog)
explicit connection(bool is_server, const lib::shared_ptr<alog_type> & alog, const lib::shared_ptr<elog_type> & elog)
: m_output_stream(NULL)
, m_reading(false)
, m_is_server(is_server)
@ -86,7 +86,7 @@ public:
, m_elog(elog)
, m_remote_endpoint("iostream transport")
{
m_alog.write(log::alevel::devel,"iostream con transport constructor");
m_alog->write(log::alevel::devel,"iostream con transport constructor");
}
/// Get a shared pointer to this component
@ -408,7 +408,7 @@ protected:
* @param handler The `init_handler` to call when initialization is done
*/
void init(init_handler handler) {
m_alog.write(log::alevel::devel,"iostream connection init");
m_alog->write(log::alevel::devel,"iostream connection init");
handler(lib::error_code());
}
@ -441,7 +441,7 @@ protected:
{
std::stringstream s;
s << "iostream_con async_read_at_least: " << num_bytes;
m_alog.write(log::alevel::devel,s.str());
m_alog->write(log::alevel::devel,s.str());
if (num_bytes > len) {
handler(make_error_code(error::invalid_num_bytes),size_t(0));
@ -487,7 +487,7 @@ protected:
void async_write(char const * buf, size_t len, transport::write_handler
handler)
{
m_alog.write(log::alevel::devel,"iostream_con async_write");
m_alog->write(log::alevel::devel,"iostream_con async_write");
// TODO: lock transport state?
lib::error_code ec;
@ -527,7 +527,7 @@ protected:
void async_write(std::vector<buffer> const & bufs, transport::write_handler
handler)
{
m_alog.write(log::alevel::devel,"iostream_con async_write buffer list");
m_alog->write(log::alevel::devel,"iostream_con async_write buffer list");
// TODO: lock transport state?
lib::error_code ec;
@ -601,18 +601,18 @@ protected:
}
private:
void read(std::istream &in) {
m_alog.write(log::alevel::devel,"iostream_con read");
m_alog->write(log::alevel::devel,"iostream_con read");
while (in.good()) {
if (!m_reading) {
m_elog.write(log::elevel::devel,"write while not reading");
m_elog->write(log::elevel::devel,"write while not reading");
break;
}
in.read(m_buf+m_cursor,static_cast<std::streamsize>(m_len-m_cursor));
if (in.gcount() == 0) {
m_elog.write(log::elevel::devel,"read zero bytes");
m_elog->write(log::elevel::devel,"read zero bytes");
break;
}
@ -632,10 +632,10 @@ private:
}
size_t read_some_impl(char const * buf, size_t len) {
m_alog.write(log::alevel::devel,"iostream_con read_some");
m_alog->write(log::alevel::devel,"iostream_con read_some");
if (!m_reading) {
m_elog.write(log::elevel::devel,"write while not reading");
m_elog->write(log::elevel::devel,"write while not reading");
return 0;
}
@ -694,8 +694,8 @@ private:
bool m_reading;
bool const m_is_server;
bool m_is_secure;
alog_type & m_alog;
elog_type & m_elog;
lib::shared_ptr<alog_type> m_alog;
lib::shared_ptr<elog_type> m_elog;
std::string m_remote_endpoint;
// This lock ensures that only one thread can edit read data for this

View File

@ -168,7 +168,7 @@ protected:
* @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 * a, elog_type * e) {
void init_logging(lib::shared_ptr<alog_type> a, lib::shared_ptr<elog_type> e) {
m_elog = e;
m_alog = a;
}
@ -209,8 +209,8 @@ private:
shutdown_handler m_shutdown_handler;
write_handler m_write_handler;
elog_type * m_elog;
alog_type * m_alog;
lib::shared_ptr<elog_type> m_elog;
lib::shared_ptr<alog_type> m_alog;
bool m_is_secure;
};

View File

@ -72,10 +72,10 @@ public:
typedef lib::shared_ptr<timer> timer_ptr;
explicit connection(bool is_server, alog_type & alog, elog_type & elog)
explicit connection(bool is_server, const lib::shared_ptr<alog_type> & alog, const lib::shared_ptr<elog_type> & elog)
: m_alog(alog), m_elog(elog)
{
m_alog.write(log::alevel::devel,"stub con transport constructor");
m_alog->write(log::alevel::devel,"stub con transport constructor");
}
/// Get a shared pointer to this component
@ -175,7 +175,7 @@ protected:
* @param handler The `init_handler` to call when initialization is done
*/
void init(init_handler handler) {
m_alog.write(log::alevel::devel,"stub connection init");
m_alog->write(log::alevel::devel,"stub connection init");
handler(make_error_code(error::not_implemented));
}
@ -206,7 +206,7 @@ protected:
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");
m_alog->write(log::alevel::devel, "stub_con async_read_at_least");
handler(make_error_code(error::not_implemented), 0);
}
@ -223,7 +223,7 @@ protected:
* @param handler Callback to invoke with operation status.
*/
void async_write(char const * buf, size_t len, write_handler handler) {
m_alog.write(log::alevel::devel,"stub_con async_write");
m_alog->write(log::alevel::devel,"stub_con async_write");
handler(make_error_code(error::not_implemented));
}
@ -239,7 +239,7 @@ protected:
* @param handler Callback to invoke with operation status.
*/
void async_write(std::vector<buffer> const & bufs, write_handler handler) {
m_alog.write(log::alevel::devel,"stub_con async_write buffer list");
m_alog->write(log::alevel::devel,"stub_con async_write buffer list");
handler(make_error_code(error::not_implemented));
}
@ -274,8 +274,8 @@ protected:
}
private:
// member variables!
alog_type & m_alog;
elog_type & m_elog;
lib::shared_ptr<alog_type> m_alog;
lib::shared_ptr<elog_type> m_elog;
};

View File

@ -31,6 +31,7 @@
#include <websocketpp/error.hpp>
#include <websocketpp/common/memory.hpp>
#include <websocketpp/common/stdint.hpp>
#include <algorithm>
#include <sstream>

View File

@ -72,11 +72,9 @@ private:
* Based on code from
* http://stackoverflow.com/questions/3152241/case-insensitive-stdstring-find
*/
struct ci_less : std::binary_function<std::string, std::string, bool> {
struct ci_less {
// case-independent (ci) compare_less binary function
struct nocase_compare
: public std::binary_function<unsigned char,unsigned char,bool>
{
struct nocase_compare {
bool operator() (unsigned char const & c1, unsigned char const & c2) const {
return tolower (c1) < tolower (c2);
}

View File

@ -42,9 +42,9 @@ namespace websocketpp {
/// Library major version number
static int const major_version = 0;
/// Library minor version number
static int const minor_version = 7;
static int const minor_version = 8;
/// Library patch version number
static int const patch_version = 0;
static int const patch_version = 2;
/// Library pre-release flag
/**
* This is a textual flag indicating the type and number for pre-release
@ -54,7 +54,7 @@ static int const patch_version = 0;
static char const prerelease_flag[] = "";
/// Default user agent string
static char const user_agent[] = "WebSocket++/0.7.0";
static char const user_agent[] = "WebSocket++/0.8.2";
} // namespace websocketpp

Some files were not shown because too many files have changed in this diff Show More