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