mirror of
https://github.com/XRPLF/rippled.git
synced 2025-12-06 17:27:55 +00:00
Use websocketpp_02 namespace.
This commit is contained in:
@@ -44,7 +44,7 @@ public:
|
||||
static char const* getCountedObjectName () { return "WSConnection"; }
|
||||
|
||||
protected:
|
||||
typedef websocketpp::message::data::ptr message_ptr;
|
||||
typedef websocketpp_02::message::data::ptr message_ptr;
|
||||
|
||||
WSConnection (HTTP::Port const& port,
|
||||
Resource::Manager& resourceManager, Resource::Consumer usage,
|
||||
@@ -174,7 +174,7 @@ public:
|
||||
connection_ptr ptr = c.lock ();
|
||||
|
||||
if (ptr)
|
||||
ptr->close (websocketpp::close::status::PROTOCOL_ERROR, "overload");
|
||||
ptr->close (websocketpp_02::close::status::PROTOCOL_ERROR, "overload");
|
||||
}
|
||||
|
||||
bool onPingTimer (std::string&)
|
||||
|
||||
@@ -56,7 +56,7 @@ private:
|
||||
Resource::Manager& m_resourceManager;
|
||||
InfoSub::Source& m_source;
|
||||
LockType m_endpointLock;
|
||||
std::shared_ptr<websocketpp::server_autotls> m_endpoint;
|
||||
std::shared_ptr<websocketpp_02::server_autotls> m_endpoint;
|
||||
|
||||
public:
|
||||
WSDoorImp (HTTP::Port const& port, Resource::Manager& resourceManager,
|
||||
@@ -83,14 +83,14 @@ private:
|
||||
port_->ip.to_string() << ":" << std::to_string(port_->port) <<
|
||||
(port_->allow_admin ? "(Admin)" : "");
|
||||
|
||||
websocketpp::server_autotls::handler::ptr handler (
|
||||
new WSServerHandler <websocketpp::server_autotls> (
|
||||
websocketpp_02::server_autotls::handler::ptr handler (
|
||||
new WSServerHandler <websocketpp_02::server_autotls> (
|
||||
port_, m_resourceManager, m_source));
|
||||
|
||||
{
|
||||
ScopedLockType lock (m_endpointLock);
|
||||
|
||||
m_endpoint = std::make_shared<websocketpp::server_autotls> (
|
||||
m_endpoint = std::make_shared<websocketpp_02::server_autotls> (
|
||||
handler);
|
||||
}
|
||||
|
||||
@@ -99,24 +99,24 @@ private:
|
||||
{
|
||||
m_endpoint->listen (port_->ip, port_->port);
|
||||
}
|
||||
catch (websocketpp::exception& e)
|
||||
catch (websocketpp_02::exception& e)
|
||||
{
|
||||
WriteLog (lsWARNING, WSDoor) << "websocketpp exception: "
|
||||
WriteLog (lsWARNING, WSDoor) << "websocketpp_02 exception: "
|
||||
<< e.what ();
|
||||
|
||||
// temporary workaround for websocketpp throwing exceptions on
|
||||
// temporary workaround for websocketpp_02 throwing exceptions on
|
||||
// access/close races
|
||||
for (;;)
|
||||
{
|
||||
// https://github.com/zaphoyd/websocketpp/issues/98
|
||||
// https://github.com/zaphoyd/websocketpp_02/issues/98
|
||||
try
|
||||
{
|
||||
m_endpoint->get_io_service ().run ();
|
||||
break;
|
||||
}
|
||||
catch (websocketpp::exception& e)
|
||||
catch (websocketpp_02::exception& e)
|
||||
{
|
||||
WriteLog (lsWARNING, WSDoor) << "websocketpp exception: "
|
||||
WriteLog (lsWARNING, WSDoor) << "websocketpp_02 exception: "
|
||||
<< e.what ();
|
||||
}
|
||||
}
|
||||
@@ -133,7 +133,7 @@ private:
|
||||
|
||||
void onStop ()
|
||||
{
|
||||
std::shared_ptr<websocketpp::server_autotls> endpoint;
|
||||
std::shared_ptr<websocketpp_02::server_autotls> endpoint;
|
||||
|
||||
{
|
||||
ScopedLockType lock (m_endpointLock);
|
||||
|
||||
@@ -111,7 +111,7 @@ public:
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
cpClient->close (websocketpp::close::status::value (crTooSlow),
|
||||
cpClient->close (websocketpp_02::close::status::value (crTooSlow),
|
||||
std::string ("Client is too slow."));
|
||||
}
|
||||
}
|
||||
@@ -128,7 +128,7 @@ public:
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
cpClient->close (websocketpp::close::status::value (crTooSlow),
|
||||
cpClient->close (websocketpp_02::close::status::value (crTooSlow),
|
||||
std::string ("Client is too slow."));
|
||||
}
|
||||
}
|
||||
@@ -397,7 +397,7 @@ public:
|
||||
{
|
||||
}
|
||||
|
||||
if (mpMessage->get_opcode () != websocketpp::frame::opcode::TEXT)
|
||||
if (mpMessage->get_opcode () != websocketpp_02::frame::opcode::TEXT)
|
||||
{
|
||||
Json::Value jvResult (Json::objectValue);
|
||||
|
||||
|
||||
@@ -22,14 +22,14 @@
|
||||
// VFALCO NOTE this looks like some facility for giving websocket
|
||||
// a way to produce logging output.
|
||||
//
|
||||
namespace websocketpp {
|
||||
namespace websocketpp_02 {
|
||||
namespace log {
|
||||
|
||||
void websocketLog (websocketpp::log::alevel::value v, std::string const& entry)
|
||||
void websocketLog (websocketpp_02::log::alevel::value v, std::string const& entry)
|
||||
{
|
||||
using namespace ripple;
|
||||
|
||||
if ((v == websocketpp::log::alevel::DEVEL) || (v == websocketpp::log::alevel::DEBUG_CLOSE))
|
||||
if ((v == websocketpp_02::log::alevel::DEVEL) || (v == websocketpp_02::log::alevel::DEBUG_CLOSE))
|
||||
{
|
||||
WriteLog(lsTRACE, WebSocket) << entry;
|
||||
}
|
||||
@@ -39,19 +39,19 @@ void websocketLog (websocketpp::log::alevel::value v, std::string const& entry)
|
||||
}
|
||||
}
|
||||
|
||||
void websocketLog (websocketpp::log::elevel::value v, std::string const& entry)
|
||||
void websocketLog (websocketpp_02::log::elevel::value v, std::string const& entry)
|
||||
{
|
||||
using namespace ripple;
|
||||
|
||||
LogSeverity s = lsDEBUG;
|
||||
|
||||
if ((v & websocketpp::log::elevel::INFO) != 0)
|
||||
if ((v & websocketpp_02::log::elevel::INFO) != 0)
|
||||
s = lsINFO;
|
||||
else if ((v & websocketpp::log::elevel::FATAL) != 0)
|
||||
else if ((v & websocketpp_02::log::elevel::FATAL) != 0)
|
||||
s = lsFATAL;
|
||||
else if ((v & websocketpp::log::elevel::RERROR) != 0)
|
||||
else if ((v & websocketpp_02::log::elevel::RERROR) != 0)
|
||||
s = lsERROR;
|
||||
else if ((v & websocketpp::log::elevel::WARN) != 0)
|
||||
else if ((v & websocketpp_02::log::elevel::WARN) != 0)
|
||||
s = lsWARNING;
|
||||
|
||||
WriteLog(s, WebSocket) << entry;
|
||||
|
||||
@@ -11,10 +11,10 @@
|
||||
* * 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
|
||||
*
|
||||
* 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;
|
||||
@@ -22,7 +22,7 @@
|
||||
* 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 WEBSOCKET_CONSTANTS_HPP
|
||||
@@ -52,29 +52,29 @@
|
||||
#include <boost/shared_ptr.hpp>
|
||||
|
||||
// Defaults
|
||||
namespace websocketpp {
|
||||
namespace websocketpp_02 {
|
||||
static const std::string USER_AGENT = "WebSocket++/0.2.1dev";
|
||||
|
||||
|
||||
typedef std::vector<unsigned char> binary_string;
|
||||
typedef boost::shared_ptr<binary_string> binary_string_ptr;
|
||||
|
||||
|
||||
typedef std::string utf8_string;
|
||||
typedef boost::shared_ptr<utf8_string> utf8_string_ptr;
|
||||
|
||||
|
||||
const uint64_t DEFAULT_MAX_MESSAGE_SIZE = 0xFFFFFF; // ~16MB
|
||||
|
||||
|
||||
const size_t DEFAULT_READ_THRESHOLD = 1; // 512 would be a more sane value for this
|
||||
const bool DEFAULT_SILENT_CLOSE = false; // true
|
||||
|
||||
|
||||
const size_t MAX_THREAD_POOL_SIZE = 64;
|
||||
|
||||
|
||||
const uint16_t DEFAULT_PORT = 80;
|
||||
const uint16_t DEFAULT_SECURE_PORT = 443;
|
||||
|
||||
|
||||
inline uint16_t default_port(bool secure) {
|
||||
return (secure ? DEFAULT_SECURE_PORT : DEFAULT_PORT);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace session {
|
||||
namespace state {
|
||||
enum value {
|
||||
@@ -85,7 +85,7 @@ namespace websocketpp {
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
namespace close {
|
||||
namespace status {
|
||||
enum value {
|
||||
@@ -110,24 +110,24 @@ namespace websocketpp {
|
||||
RSV_END = 2999,
|
||||
INVALID_START = 5000
|
||||
};
|
||||
|
||||
|
||||
inline bool reserved(value s) {
|
||||
return ((s >= RSV_START && s <= RSV_END) || s == RSV_ADHOC_1
|
||||
return ((s >= RSV_START && s <= RSV_END) || s == RSV_ADHOC_1
|
||||
|| s == RSV_ADHOC_2 || s == RSV_ADHOC_3 || s == RSV_ADHOC_4);
|
||||
}
|
||||
|
||||
|
||||
// Codes invalid on the wire
|
||||
inline bool invalid(value s) {
|
||||
return ((s <= INVALID_END || s >= INVALID_START) ||
|
||||
s == NO_STATUS ||
|
||||
s == ABNORMAL_CLOSE ||
|
||||
return ((s <= INVALID_END || s >= INVALID_START) ||
|
||||
s == NO_STATUS ||
|
||||
s == ABNORMAL_CLOSE ||
|
||||
s == TLS_HANDSHAKE);
|
||||
}
|
||||
|
||||
|
||||
// TODO functions for application ranges?
|
||||
} // namespace status
|
||||
} // namespace close
|
||||
|
||||
|
||||
namespace fail {
|
||||
namespace status {
|
||||
enum value {
|
||||
@@ -140,7 +140,7 @@ namespace websocketpp {
|
||||
};
|
||||
} // namespace status
|
||||
} // namespace fail
|
||||
|
||||
|
||||
namespace frame {
|
||||
// Opcodes are 4 bits
|
||||
// See spec section 5.2
|
||||
@@ -163,28 +163,28 @@ namespace websocketpp {
|
||||
CONTROL_RSVE = 0xE,
|
||||
CONTROL_RSVF = 0xF
|
||||
};
|
||||
|
||||
|
||||
inline bool reserved(value v) {
|
||||
return (v >= RSV3 && v <= RSV7) ||
|
||||
return (v >= RSV3 && v <= RSV7) ||
|
||||
(v >= CONTROL_RSVB && v <= CONTROL_RSVF);
|
||||
}
|
||||
|
||||
|
||||
inline bool invalid(value v) {
|
||||
return (v > 0xF || v < 0);
|
||||
}
|
||||
|
||||
|
||||
inline bool is_control(value v) {
|
||||
return v >= 0x8;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
namespace limits {
|
||||
static const uint8_t PAYLOAD_SIZE_BASIC = 125;
|
||||
static const uint16_t PAYLOAD_SIZE_EXTENDED = 0xFFFF; // 2^16, 65535
|
||||
static const uint64_t PAYLOAD_SIZE_JUMBO = 0x7FFFFFFFFFFFFFFFLL;//2^63
|
||||
}
|
||||
} // namespace frame
|
||||
|
||||
|
||||
// exception class for errors that should be propogated back to the user.
|
||||
namespace error {
|
||||
enum value {
|
||||
@@ -199,22 +199,22 @@ namespace websocketpp {
|
||||
INVALID_STATE = 7
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
class exception : public std::exception {
|
||||
public:
|
||||
public:
|
||||
exception(const std::string& msg,
|
||||
error::value code = error::GENERIC)
|
||||
error::value code = error::GENERIC)
|
||||
: m_msg(msg),m_code(code) {}
|
||||
~exception() throw() {}
|
||||
|
||||
|
||||
virtual const char* what() const throw() {
|
||||
return m_msg.c_str();
|
||||
}
|
||||
|
||||
|
||||
error::value code() const throw() {
|
||||
return m_code;
|
||||
}
|
||||
|
||||
|
||||
std::string m_msg;
|
||||
error::value m_code;
|
||||
};
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -11,10 +11,10 @@
|
||||
* * 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
|
||||
*
|
||||
* 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;
|
||||
@@ -22,7 +22,7 @@
|
||||
* 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_ENDPOINT_HPP
|
||||
@@ -40,8 +40,8 @@
|
||||
#include <iostream>
|
||||
#include <set>
|
||||
|
||||
namespace websocketpp {
|
||||
|
||||
namespace websocketpp_02 {
|
||||
|
||||
/// endpoint_base provides core functionality that needs to be constructed
|
||||
/// before endpoint policy classes are constructed.
|
||||
class endpoint_base {
|
||||
@@ -57,17 +57,17 @@ protected:
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
boost::asio::io_service m_io_service;
|
||||
};
|
||||
|
||||
/// Describes a configurable WebSocket endpoint.
|
||||
/**
|
||||
* The endpoint class template provides a configurable WebSocket endpoint
|
||||
* capable that manages WebSocket connection lifecycles. endpoint is a host
|
||||
* The endpoint class template provides a configurable WebSocket endpoint
|
||||
* capable that manages WebSocket connection lifecycles. endpoint is a host
|
||||
* class to a series of enriched policy classes that together provide the public
|
||||
* interface for a specific type of WebSocket endpoint.
|
||||
*
|
||||
*
|
||||
* @par Thread Safety
|
||||
* @e Distinct @e objects: Safe.@n
|
||||
* @e Shared @e objects: Will be safe when complete.
|
||||
@@ -76,7 +76,7 @@ template <
|
||||
template <class> class role,
|
||||
template <class> class socket = socket::autotls,
|
||||
template <class> class logger = log::logger>
|
||||
class endpoint
|
||||
class endpoint
|
||||
: public endpoint_base,
|
||||
public role< endpoint<role,socket,logger> >,
|
||||
public socket< endpoint<role,socket,logger> >
|
||||
@@ -84,7 +84,7 @@ class endpoint
|
||||
public:
|
||||
/// Type of the traits class that stores endpoint related types.
|
||||
typedef endpoint_traits< endpoint<role,socket,logger> > traits;
|
||||
|
||||
|
||||
/// The type of the endpoint itself.
|
||||
typedef typename traits::type type;
|
||||
/// The type of a shared pointer to the endpoint.
|
||||
@@ -109,10 +109,10 @@ public:
|
||||
/// A shared pointer to the base class that all handlers for this endpoint
|
||||
/// must derive from.
|
||||
typedef typename traits::handler_ptr handler_ptr;
|
||||
|
||||
// Friend is used here to allow the CRTP base classes to access member
|
||||
// functions in the derived endpoint. This is done to limit the use of
|
||||
// public methods in endpoint and its CRTP bases to only those methods
|
||||
|
||||
// Friend is used here to allow the CRTP base classes to access member
|
||||
// functions in the derived endpoint. This is done to limit the use of
|
||||
// public methods in endpoint and its CRTP bases to only those methods
|
||||
// intended for end-application use.
|
||||
#ifdef _WEBSOCKETPP_CPP11_FRIEND_
|
||||
// Highly simplified and preferred C++11 version:
|
||||
@@ -124,17 +124,17 @@ public:
|
||||
friend class socket< endpoint<role,socket> >;
|
||||
friend class connection<type,role< type >::template connection,socket< type >::template connection>;
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
/// Construct an endpoint.
|
||||
/**
|
||||
* This constructor creates an endpoint and registers the default connection
|
||||
* handler.
|
||||
*
|
||||
*
|
||||
* @param handler A shared_ptr to the handler to use as the default handler
|
||||
* when creating new connections.
|
||||
*/
|
||||
explicit endpoint(handler_ptr handler)
|
||||
explicit endpoint(handler_ptr handler)
|
||||
: role_type(endpoint_base::m_io_service)
|
||||
, socket_type(endpoint_base::m_io_service)
|
||||
, m_handler(handler)
|
||||
@@ -148,36 +148,36 @@ public:
|
||||
{
|
||||
m_pool->set_callback(boost::bind(&type::on_new_message,this));
|
||||
}
|
||||
|
||||
|
||||
/// Destroy an endpoint
|
||||
~endpoint() {
|
||||
m_alog->at(log::alevel::DEVEL) << "Endpoint destructor called" << log::endl;
|
||||
// Tell the memory pool we don't want to be notified about newly freed
|
||||
// messages any more (because we wont be here)
|
||||
m_pool->set_callback(NULL);
|
||||
|
||||
|
||||
// Detach any connections that are still alive at this point
|
||||
boost::lock_guard<boost::recursive_mutex> lock(m_lock);
|
||||
|
||||
|
||||
typename std::set<connection_ptr>::iterator it;
|
||||
|
||||
|
||||
while (!m_connections.empty()) {
|
||||
remove_connection(*m_connections.begin());
|
||||
}
|
||||
m_alog->at(log::alevel::DEVEL) << "Endpoint destructor done" << log::endl;
|
||||
}
|
||||
|
||||
|
||||
// copy/assignment constructors require C++11
|
||||
// boost::noncopyable is being used in the meantime.
|
||||
// endpoint(endpoint const&) = delete;
|
||||
// endpoint& operator=(endpoint const&) = delete
|
||||
|
||||
|
||||
/// Returns a reference to the endpoint's access logger.
|
||||
/**
|
||||
* Visibility: public
|
||||
* State: Any
|
||||
* Concurrency: Callable from anywhere
|
||||
*
|
||||
*
|
||||
* @return A reference to the endpoint's access logger. See @ref logger
|
||||
* for more details about WebSocket++ logging policy classes.
|
||||
*
|
||||
@@ -193,7 +193,7 @@ public:
|
||||
alogger_ptr alog_ptr() {
|
||||
return m_alog;
|
||||
}
|
||||
|
||||
|
||||
/// Returns a reference to the endpoint's error logger.
|
||||
/**
|
||||
* @returns A reference to the endpoint's error logger. See @ref logger
|
||||
@@ -211,162 +211,162 @@ public:
|
||||
elogger_ptr elog_ptr() {
|
||||
return m_elog;
|
||||
}
|
||||
|
||||
|
||||
/// Get default handler
|
||||
/**
|
||||
* Visibility: public
|
||||
* State: valid always
|
||||
* Concurrency: callable from anywhere
|
||||
*
|
||||
*
|
||||
* @return A pointer to the default handler
|
||||
*/
|
||||
handler_ptr get_handler() const {
|
||||
boost::lock_guard<boost::recursive_mutex> lock(m_lock);
|
||||
|
||||
|
||||
return m_handler;
|
||||
}
|
||||
|
||||
|
||||
/// Sets the default handler to be used for future connections
|
||||
/**
|
||||
* Does not affect existing connections.
|
||||
*
|
||||
*
|
||||
* @param new_handler A shared pointer to the new default handler. Must not
|
||||
* be NULL.
|
||||
*/
|
||||
void set_handler(handler_ptr new_handler) {
|
||||
boost::lock_guard<boost::recursive_mutex> lock(m_lock);
|
||||
|
||||
|
||||
if (!new_handler) {
|
||||
elog().at(log::elevel::FATAL)
|
||||
elog().at(log::elevel::FATAL)
|
||||
<< "Tried to switch to a NULL handler." << log::endl;
|
||||
throw websocketpp::exception("TODO: handlers can't be null");
|
||||
throw websocketpp_02::exception("TODO: handlers can't be null");
|
||||
}
|
||||
|
||||
|
||||
m_handler = new_handler;
|
||||
}
|
||||
|
||||
|
||||
/// Set endpoint read threshold
|
||||
/**
|
||||
* Sets the default read threshold value that will be passed to new connections.
|
||||
* Sets the default read threshold value that will be passed to new connections.
|
||||
* Changing this value will only affect new connections, not existing ones. The read
|
||||
* threshold represents the largest block of payload bytes that will be processed in
|
||||
* a single async read. Lower values may experience better callback latency at the
|
||||
* a single async read. Lower values may experience better callback latency at the
|
||||
* expense of additional ASIO context switching overhead. This value also affects the
|
||||
* maximum number of bytes to be buffered before performing utf8 and other streaming
|
||||
* validation.
|
||||
*
|
||||
*
|
||||
* Visibility: public
|
||||
* State: valid always
|
||||
* Concurrency: callable from anywhere
|
||||
*
|
||||
*
|
||||
* @param val Size of the threshold in bytes
|
||||
*/
|
||||
void set_read_threshold(size_t val) {
|
||||
boost::lock_guard<boost::recursive_mutex> lock(m_lock);
|
||||
|
||||
|
||||
m_read_threshold = val;
|
||||
}
|
||||
|
||||
|
||||
/// Get endpoint read threshold
|
||||
/**
|
||||
* Returns the endpoint read threshold. See set_read_threshold for more information
|
||||
* about the read threshold.
|
||||
*
|
||||
*
|
||||
* Visibility: public
|
||||
* State: valid always
|
||||
* Concurrency: callable from anywhere
|
||||
*
|
||||
*
|
||||
* @return Size of the threshold in bytes
|
||||
* @see set_read_threshold()
|
||||
*/
|
||||
size_t get_read_threshold() const {
|
||||
boost::lock_guard<boost::recursive_mutex> lock(m_lock);
|
||||
|
||||
|
||||
return m_read_threshold;
|
||||
}
|
||||
|
||||
|
||||
/// Set connection silent close setting
|
||||
/**
|
||||
* Silent close suppresses the return of detailed connection close information during
|
||||
* the closing handshake. This information is critically useful for debugging but may
|
||||
* be undesirable for security reasons for some production environments. Close reasons
|
||||
* could be used to by an attacker to confirm that the implementation is out of
|
||||
* could be used to by an attacker to confirm that the implementation is out of
|
||||
* resources or be used to identify the WebSocket library in use.
|
||||
*
|
||||
*
|
||||
* Visibility: public
|
||||
* State: valid always
|
||||
* Concurrency: callable from anywhere
|
||||
*
|
||||
*
|
||||
* @param val New silent close value
|
||||
*/
|
||||
void set_silent_close(bool val) {
|
||||
boost::lock_guard<boost::recursive_mutex> lock(m_lock);
|
||||
|
||||
|
||||
m_silent_close = val;
|
||||
}
|
||||
|
||||
|
||||
/// Get connection silent close setting
|
||||
/**
|
||||
* Visibility: public
|
||||
* State: valid always
|
||||
* Concurrency: callable from anywhere
|
||||
*
|
||||
*
|
||||
* @return Current silent close value
|
||||
* @see set_silent_close()
|
||||
*/
|
||||
bool get_silent_close() const {
|
||||
boost::lock_guard<boost::recursive_mutex> lock(m_lock);
|
||||
|
||||
|
||||
return m_silent_close;
|
||||
}
|
||||
|
||||
|
||||
/// Cleanly closes all websocket connections
|
||||
/**
|
||||
* Sends a close signal to every connection with the specified code and
|
||||
* Sends a close signal to every connection with the specified code and
|
||||
* reason. The default code is 1001/Going Away and the default reason is
|
||||
* blank.
|
||||
*
|
||||
* blank.
|
||||
*
|
||||
* @param code The WebSocket close code to send to remote clients as the
|
||||
* reason that the connection is being closed.
|
||||
* @param reason The WebSocket close reason to send to remote clients as the
|
||||
* text reason that the connection is being closed. Must be valid UTF-8.
|
||||
*/
|
||||
void close_all(close::status::value code = close::status::GOING_AWAY,
|
||||
void close_all(close::status::value code = close::status::GOING_AWAY,
|
||||
const std::string& reason = "")
|
||||
{
|
||||
boost::lock_guard<boost::recursive_mutex> lock(m_lock);
|
||||
|
||||
m_alog->at(log::alevel::ENDPOINT)
|
||||
<< "Endpoint received signal to close all connections cleanly with code "
|
||||
|
||||
m_alog->at(log::alevel::ENDPOINT)
|
||||
<< "Endpoint received signal to close all connections cleanly with code "
|
||||
<< code << " and reason " << reason << log::endl;
|
||||
|
||||
// TODO: is there a more elegant way to do this? In some code paths
|
||||
|
||||
// TODO: is there a more elegant way to do this? In some code paths
|
||||
// close can call terminate immediately which removes the connection
|
||||
// from m_connections, invalidating the iterator.
|
||||
typename std::set<connection_ptr>::iterator it;
|
||||
|
||||
|
||||
for (it = m_connections.begin(); it != m_connections.end();) {
|
||||
const connection_ptr con = *it++;
|
||||
con->close(code,reason);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// Stop the endpoint's ASIO loop
|
||||
/**
|
||||
* Signals the endpoint to call the io_service stop member function. If
|
||||
* Signals the endpoint to call the io_service stop member function. If
|
||||
* clean is true the endpoint will be put into an intermediate state where
|
||||
* it signals all connections to close cleanly and only calls stop once that
|
||||
* process is complete. Otherwise stop is called immediately and all
|
||||
* process is complete. Otherwise stop is called immediately and all
|
||||
* io_service operations will be aborted.
|
||||
*
|
||||
* If clean is true stop will use code and reason for the close code and
|
||||
* close reason when it closes open connections. The default code is
|
||||
*
|
||||
* If clean is true stop will use code and reason for the close code and
|
||||
* close reason when it closes open connections. The default code is
|
||||
* 1001/Going Away and the default reason is blank.
|
||||
*
|
||||
*
|
||||
* Visibility: public
|
||||
* State: Valid from RUNNING only
|
||||
* Concurrency: Callable from anywhere
|
||||
*
|
||||
*
|
||||
* @param clean Whether or not to wait until all connections have been
|
||||
* cleanly closed to stop io_service operations.
|
||||
* @param code The WebSocket close code to send to remote clients as the
|
||||
@@ -374,22 +374,22 @@ public:
|
||||
* @param reason The WebSocket close reason to send to remote clients as the
|
||||
* text reason that the connection is being closed. Must be valid UTF-8.
|
||||
*/
|
||||
void stop(bool clean = true,
|
||||
close::status::value code = close::status::GOING_AWAY,
|
||||
void stop(bool clean = true,
|
||||
close::status::value code = close::status::GOING_AWAY,
|
||||
const std::string& reason = "")
|
||||
{
|
||||
{
|
||||
boost::lock_guard<boost::recursive_mutex> lock(m_lock);
|
||||
|
||||
|
||||
if (clean) {
|
||||
m_alog->at(log::alevel::ENDPOINT)
|
||||
m_alog->at(log::alevel::ENDPOINT)
|
||||
<< "Endpoint is stopping cleanly" << log::endl;
|
||||
|
||||
|
||||
m_state = STOPPING;
|
||||
close_all(code,reason);
|
||||
} else {
|
||||
m_alog->at(log::alevel::ENDPOINT)
|
||||
m_alog->at(log::alevel::ENDPOINT)
|
||||
<< "Endpoint is stopping immediately" << log::endl;
|
||||
|
||||
|
||||
endpoint_base::m_io_service.stop();
|
||||
m_state = STOPPED;
|
||||
}
|
||||
@@ -397,15 +397,15 @@ public:
|
||||
protected:
|
||||
/// Creates and returns a new connection
|
||||
/**
|
||||
* This function creates a new connection of the type and passes it a
|
||||
* This function creates a new connection of the type and passes it a
|
||||
* reference to this as well as a shared pointer to the default connection
|
||||
* handler. The newly created connection is added to the endpoint's
|
||||
* management list. The endpoint will retain this pointer until
|
||||
* handler. The newly created connection is added to the endpoint's
|
||||
* management list. The endpoint will retain this pointer until
|
||||
* remove_connection is called to remove it.
|
||||
*
|
||||
* If the endpoint is in a state where it is trying to stop or has already
|
||||
* stopped an empty shared pointer is returned.
|
||||
*
|
||||
*
|
||||
* Visibility: protected
|
||||
* State: Always valid, behavior differs based on state
|
||||
* Concurrency: Callable from anywhere
|
||||
@@ -415,93 +415,93 @@ protected:
|
||||
*/
|
||||
connection_ptr create_connection() {
|
||||
boost::lock_guard<boost::recursive_mutex> lock(m_lock);
|
||||
|
||||
|
||||
if (m_state == STOPPING || m_state == STOPPED) {
|
||||
return connection_ptr();
|
||||
}
|
||||
|
||||
|
||||
connection_ptr new_connection(new connection_type(*this,m_handler));
|
||||
m_connections.insert(new_connection);
|
||||
|
||||
m_alog->at(log::alevel::DEVEL) << "Connection created: count is now: "
|
||||
|
||||
m_alog->at(log::alevel::DEVEL) << "Connection created: count is now: "
|
||||
<< m_connections.size() << log::endl;
|
||||
|
||||
|
||||
return new_connection;
|
||||
}
|
||||
|
||||
|
||||
/// Removes a connection from the list managed by this endpoint.
|
||||
/**
|
||||
* This function erases a connection from the list managed by the endpoint.
|
||||
* After this function returns, endpoint all async events related to this
|
||||
* connection should be canceled and neither ASIO nor this endpoint should
|
||||
* have a pointer to this connection. Unless the end user retains a copy of
|
||||
* the shared pointer the connection will be freed and any state it
|
||||
* the shared pointer the connection will be freed and any state it
|
||||
* contained (close code status, etc) will be lost.
|
||||
*
|
||||
*
|
||||
* Visibility: protected
|
||||
* State: Always valid, behavior differs based on state
|
||||
* Concurrency: Callable from anywhere
|
||||
*
|
||||
*
|
||||
* @param con A shared pointer to a connection created by this endpoint.
|
||||
*/
|
||||
void remove_connection(connection_ptr con) {
|
||||
boost::lock_guard<boost::recursive_mutex> lock(m_lock);
|
||||
|
||||
|
||||
// TODO: is this safe to use?
|
||||
// Detaching signals to the connection that the endpoint is no longer aware of it
|
||||
// and it is no longer safe to assume the endpoint exists.
|
||||
con->detach();
|
||||
|
||||
|
||||
m_connections.erase(con);
|
||||
|
||||
m_alog->at(log::alevel::DEVEL) << "Connection removed: count is now: "
|
||||
|
||||
m_alog->at(log::alevel::DEVEL) << "Connection removed: count is now: "
|
||||
<< m_connections.size() << log::endl;
|
||||
|
||||
|
||||
if (m_state == STOPPING && m_connections.empty()) {
|
||||
// If we are in the process of stopping and have reached zero
|
||||
// connections stop the io_service.
|
||||
m_alog->at(log::alevel::ENDPOINT)
|
||||
<< "Endpoint has reached zero connections in STOPPING state. Stopping io_service now."
|
||||
m_alog->at(log::alevel::ENDPOINT)
|
||||
<< "Endpoint has reached zero connections in STOPPING state. Stopping io_service now."
|
||||
<< log::endl;
|
||||
stop(false);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// Gets a shared pointer to a read/write data message.
|
||||
// TODO: thread safety
|
||||
message::data::ptr get_data_message() {
|
||||
return m_pool->get();
|
||||
}
|
||||
|
||||
|
||||
/// Gets a shared pointer to a read/write control message.
|
||||
// TODO: thread safety
|
||||
message::data::ptr get_control_message() {
|
||||
return m_pool_control->get();
|
||||
}
|
||||
|
||||
|
||||
/// Asks the endpoint to restart this connection's handle_read_frame loop
|
||||
/// when there are avaliable data messages.
|
||||
void wait(connection_ptr con) {
|
||||
boost::lock_guard<boost::recursive_mutex> lock(m_lock);
|
||||
|
||||
|
||||
m_read_waiting.push(con);
|
||||
m_alog->at(log::alevel::DEVEL) << "connection " << con << " is waiting. " << m_read_waiting.size() << log::endl;
|
||||
}
|
||||
|
||||
|
||||
/// Message pool callback indicating that there is a free data message
|
||||
/// avaliable. Causes one waiting connection to get restarted.
|
||||
void on_new_message() {
|
||||
boost::lock_guard<boost::recursive_mutex> lock(m_lock);
|
||||
|
||||
|
||||
if (!m_read_waiting.empty()) {
|
||||
connection_ptr next = m_read_waiting.front();
|
||||
|
||||
|
||||
m_alog->at(log::alevel::DEVEL) << "Waking connection " << next << ". " << m_read_waiting.size()-1 << log::endl;
|
||||
|
||||
|
||||
(*next).handle_read_frame(boost::system::error_code());
|
||||
m_read_waiting.pop();
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
private:
|
||||
@@ -511,29 +511,29 @@ private:
|
||||
STOPPING = 2,
|
||||
STOPPED = 3
|
||||
};
|
||||
|
||||
|
||||
// default settings to pass to connections
|
||||
handler_ptr m_handler;
|
||||
size_t m_read_threshold;
|
||||
bool m_silent_close;
|
||||
|
||||
|
||||
// other stuff
|
||||
state m_state;
|
||||
|
||||
|
||||
std::set<connection_ptr> m_connections;
|
||||
alogger_ptr m_alog;
|
||||
elogger_ptr m_elog;
|
||||
|
||||
|
||||
// resource pools for read/write message buffers
|
||||
message::pool<message::data>::ptr m_pool;
|
||||
message::pool<message::data>::ptr m_pool_control;
|
||||
std::queue<connection_ptr> m_read_waiting;
|
||||
|
||||
|
||||
// concurrency support
|
||||
mutable boost::recursive_mutex m_lock;
|
||||
};
|
||||
|
||||
/// traits class that allows looking up relevant endpoint types by the fully
|
||||
/// traits class that allows looking up relevant endpoint types by the fully
|
||||
/// defined endpoint type.
|
||||
template <
|
||||
template <class> class role,
|
||||
@@ -543,32 +543,32 @@ struct endpoint_traits< endpoint<role, socket, logger> > {
|
||||
/// The type of the endpoint itself.
|
||||
typedef endpoint<role,socket,logger> type;
|
||||
typedef boost::shared_ptr<type> ptr;
|
||||
|
||||
|
||||
/// The type of the role policy.
|
||||
typedef role< type > role_type;
|
||||
/// The type of the socket policy.
|
||||
typedef socket< type > socket_type;
|
||||
|
||||
|
||||
/// The type of the access logger based on the logger policy.
|
||||
typedef logger<log::alevel::value> alogger_type;
|
||||
typedef boost::shared_ptr<alogger_type> alogger_ptr;
|
||||
/// The type of the error logger based on the logger policy.
|
||||
typedef logger<log::elevel::value> elogger_type;
|
||||
typedef boost::shared_ptr<elogger_type> elogger_ptr;
|
||||
|
||||
|
||||
/// The type of the connection that this endpoint creates.
|
||||
typedef connection<type,
|
||||
role< type >::template connection,
|
||||
socket< type >::template connection> connection_type;
|
||||
/// A shared pointer to the type of connection that this endpoint creates.
|
||||
typedef boost::shared_ptr<connection_type> connection_ptr;
|
||||
|
||||
|
||||
class handler;
|
||||
|
||||
|
||||
/// A shared pointer to the base class that all handlers for this endpoint
|
||||
/// must derive from.
|
||||
typedef boost::shared_ptr<handler> handler_ptr;
|
||||
|
||||
|
||||
/// Interface (ABC) that handlers for this type of endpoint may impliment.
|
||||
/// role policy and socket policy both may add methods to this interface
|
||||
class handler : public role_type::handler_interface,
|
||||
@@ -580,9 +580,9 @@ struct endpoint_traits< endpoint<role, socket, logger> > {
|
||||
typedef boost::shared_ptr<handler> ptr;
|
||||
typedef typename connection_type::ptr connection_ptr;
|
||||
typedef typename message::data::ptr message_ptr;
|
||||
|
||||
|
||||
virtual ~handler() {}
|
||||
|
||||
|
||||
/// on_load is the first callback called for a handler after a new
|
||||
/// connection has been transferred to it mid flight.
|
||||
/**
|
||||
@@ -598,9 +598,9 @@ struct endpoint_traits< endpoint<role, socket, logger> > {
|
||||
*/
|
||||
virtual void on_unload(connection_ptr con, handler_ptr new_handler) {}
|
||||
};
|
||||
|
||||
|
||||
};
|
||||
|
||||
} // namespace websocketpp
|
||||
} // namespace websocketpp_02
|
||||
|
||||
#endif // WEBSOCKETPP_ENDPOINT_HPP
|
||||
|
||||
@@ -11,10 +11,10 @@
|
||||
* * 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
|
||||
*
|
||||
* 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;
|
||||
@@ -22,19 +22,19 @@
|
||||
* 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 HTTP_CONSTANTS_HPP
|
||||
#define HTTP_CONSTANTS_HPP
|
||||
|
||||
namespace websocketpp {
|
||||
namespace websocketpp_02 {
|
||||
namespace http {
|
||||
namespace status_code {
|
||||
enum value {
|
||||
CONTINUE = 100,
|
||||
SWITCHING_PROTOCOLS = 101,
|
||||
|
||||
|
||||
OK = 200,
|
||||
CREATED = 201,
|
||||
ACCEPTED = 202,
|
||||
@@ -42,7 +42,7 @@ namespace http {
|
||||
NO_CONTENT = 204,
|
||||
RESET_CONTENT = 205,
|
||||
PARTIAL_CONTENT = 206,
|
||||
|
||||
|
||||
MULTIPLE_CHOICES = 300,
|
||||
MOVED_PERMANENTLY = 301,
|
||||
FOUND = 302,
|
||||
@@ -50,7 +50,7 @@ namespace http {
|
||||
NOT_MODIFIED = 304,
|
||||
USE_PROXY = 305,
|
||||
TEMPORARY_REDIRECT = 307,
|
||||
|
||||
|
||||
BAD_REQUEST = 400,
|
||||
UNAUTHORIZED = 401,
|
||||
PAYMENT_REQUIRED = 402,
|
||||
@@ -74,7 +74,7 @@ namespace http {
|
||||
PRECONDITION_REQUIRED = 428,
|
||||
TOO_MANY_REQUESTS = 429,
|
||||
REQUEST_HEADER_FIELDS_TOO_LARGE = 431,
|
||||
|
||||
|
||||
INTERNAL_SERVER_ERROR = 500,
|
||||
NOT_IMPLIMENTED = 501,
|
||||
BAD_GATEWAY = 502,
|
||||
@@ -84,7 +84,7 @@ namespace http {
|
||||
NOT_EXTENDED = 510,
|
||||
NETWORK_AUTHENTICATION_REQUIRED = 511
|
||||
};
|
||||
|
||||
|
||||
// TODO: should this be inline?
|
||||
inline std::string get_string(value c) {
|
||||
switch (c) {
|
||||
@@ -185,9 +185,9 @@ namespace http {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class exception : public std::exception {
|
||||
public:
|
||||
public:
|
||||
exception(const std::string& log_msg,
|
||||
status_code::value error_code,
|
||||
const std::string& error_msg = "",
|
||||
@@ -197,11 +197,11 @@ namespace http {
|
||||
m_error_msg(error_msg),
|
||||
m_body(body) {}
|
||||
~exception() throw() {}
|
||||
|
||||
|
||||
virtual const char* what() const throw() {
|
||||
return m_msg.c_str();
|
||||
}
|
||||
|
||||
|
||||
std::string m_msg;
|
||||
status_code::value m_error_code;
|
||||
std::string m_error_msg;
|
||||
|
||||
@@ -11,10 +11,10 @@
|
||||
* * 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
|
||||
*
|
||||
* 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;
|
||||
@@ -22,7 +22,7 @@
|
||||
* 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 HTTP_PARSER_HPP
|
||||
@@ -35,7 +35,7 @@
|
||||
|
||||
#include "constants.hpp"
|
||||
|
||||
namespace websocketpp {
|
||||
namespace websocketpp_02 {
|
||||
namespace http {
|
||||
namespace parser {
|
||||
|
||||
@@ -72,16 +72,16 @@ public:
|
||||
bool consume (std::istream&) {
|
||||
throw "Not Implemented";
|
||||
}
|
||||
|
||||
|
||||
void set_version(const std::string& version) {
|
||||
// TODO: validation?
|
||||
m_version = version;
|
||||
}
|
||||
|
||||
|
||||
const std::string& version() const {
|
||||
return m_version;
|
||||
}
|
||||
|
||||
|
||||
std::string header(const std::string& key) const {
|
||||
header_list::const_iterator h = m_headers.find(key);
|
||||
if (h != m_headers.end()) {
|
||||
@@ -89,14 +89,14 @@ public:
|
||||
}
|
||||
|
||||
h = m_headers.find(tolower(key));
|
||||
|
||||
|
||||
if (h == m_headers.end()) {
|
||||
return "";
|
||||
} else {
|
||||
return h->second;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// multiple calls to add header will result in values aggregating.
|
||||
// use replace_header if you do not want this behavior.
|
||||
void add_header(const std::string &key, const std::string &val) {
|
||||
@@ -107,11 +107,11 @@ public:
|
||||
m_headers[key] += ", " + val;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void replace_header(const std::string &key, const std::string &val) {
|
||||
m_headers[key] = val;
|
||||
}
|
||||
|
||||
|
||||
void remove_header(const std::string &key) {
|
||||
m_headers.erase(key);
|
||||
}
|
||||
@@ -119,7 +119,7 @@ protected:
|
||||
bool parse_headers(std::istream& s) {
|
||||
std::string header;
|
||||
std::string::size_type end;
|
||||
|
||||
|
||||
// get headers
|
||||
while (std::getline(s, header) && header != "\r") {
|
||||
if (header[header.size()-1] != '\r') {
|
||||
@@ -127,92 +127,92 @@ protected:
|
||||
} else {
|
||||
header.erase(header.end()-1);
|
||||
}
|
||||
|
||||
|
||||
end = header.find(": ",0);
|
||||
|
||||
if (end != std::string::npos) {
|
||||
|
||||
if (end != std::string::npos) {
|
||||
add_header(header.substr(0,end),header.substr(end+2));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
std::string raw_headers() {
|
||||
std::stringstream raw;
|
||||
|
||||
|
||||
header_list::iterator it;
|
||||
for (it = m_headers.begin(); it != m_headers.end(); it++) {
|
||||
raw << it->first << ": " << it->second << "\r\n";
|
||||
}
|
||||
|
||||
|
||||
return raw.str();
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
std::string m_version;
|
||||
header_list m_headers;
|
||||
};
|
||||
|
||||
class request : public parser {
|
||||
public:
|
||||
public:
|
||||
// parse a complete header (ie \r\n\r\n MUST be in the input stream)
|
||||
bool parse_complete(std::istream& s) {
|
||||
std::string request;
|
||||
|
||||
|
||||
// get status line
|
||||
std::getline(s, request);
|
||||
|
||||
|
||||
if (request[request.size()-1] == '\r') {
|
||||
request.erase(request.end()-1);
|
||||
|
||||
|
||||
std::stringstream ss(request);
|
||||
std::string val;
|
||||
|
||||
|
||||
ss >> val;
|
||||
set_method(val);
|
||||
|
||||
|
||||
ss >> val;
|
||||
set_uri(val);
|
||||
|
||||
|
||||
ss >> val;
|
||||
set_version(val);
|
||||
} else {
|
||||
set_method(request);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
return parse_headers(s);
|
||||
}
|
||||
|
||||
|
||||
// TODO: validation. Make sure all required fields have been set?
|
||||
std::string raw() {
|
||||
std::stringstream raw;
|
||||
|
||||
|
||||
raw << m_method << " " << m_uri << " " << version() << "\r\n";
|
||||
raw << raw_headers() << "\r\n";
|
||||
|
||||
|
||||
return raw.str();
|
||||
}
|
||||
|
||||
|
||||
void set_method(const std::string& method) {
|
||||
// TODO: validation?
|
||||
m_method = method;
|
||||
}
|
||||
|
||||
|
||||
const std::string& method() const {
|
||||
return m_method;
|
||||
}
|
||||
|
||||
|
||||
void set_uri(const std::string& uri) {
|
||||
// TODO: validation?
|
||||
m_uri = uri;
|
||||
}
|
||||
|
||||
|
||||
const std::string& uri() const {
|
||||
return m_uri;
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
std::string m_method;
|
||||
std::string m_uri;
|
||||
@@ -223,72 +223,72 @@ public:
|
||||
// parse a complete header (ie \r\n\r\n MUST be in the input stream)
|
||||
bool parse_complete(std::istream& s) {
|
||||
std::string response;
|
||||
|
||||
|
||||
// get status line
|
||||
std::getline(s, response);
|
||||
|
||||
|
||||
if (response[response.size()-1] == '\r') {
|
||||
response.erase(response.end()-1);
|
||||
|
||||
|
||||
std::stringstream ss(response);
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
// TODO: validation. Make sure all required fields have been set?
|
||||
std::string raw() {
|
||||
std::stringstream raw;
|
||||
|
||||
|
||||
raw << version() << " " << m_status_code << " " << m_status_msg << "\r\n";
|
||||
raw << raw_headers() << "\r\n";
|
||||
|
||||
|
||||
raw << m_body;
|
||||
|
||||
|
||||
return raw.str();
|
||||
}
|
||||
|
||||
|
||||
void set_status(status_code::value code) {
|
||||
// TODO: validation?
|
||||
m_status_code = code;
|
||||
m_status_msg = get_string(code);
|
||||
}
|
||||
|
||||
|
||||
void set_status(status_code::value code, const std::string& msg) {
|
||||
// TODO: validation?
|
||||
m_status_code = code;
|
||||
m_status_msg = msg;
|
||||
}
|
||||
|
||||
|
||||
void set_body(const std::string& value) {
|
||||
if (value.size() == 0) {
|
||||
remove_header("Content-Length");
|
||||
m_body = "";
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
std::stringstream foo;
|
||||
foo << value.size();
|
||||
replace_header("Content-Length", foo.str());
|
||||
m_body = value;
|
||||
}
|
||||
|
||||
|
||||
status_code::value get_status_code() const {
|
||||
return m_status_code;
|
||||
}
|
||||
|
||||
|
||||
const std::string& get_status_msg() const {
|
||||
return m_status_msg;
|
||||
}
|
||||
|
||||
@@ -11,10 +11,10 @@
|
||||
* * 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
|
||||
*
|
||||
* 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;
|
||||
@@ -22,7 +22,7 @@
|
||||
* 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 ZS_LOGGER_HPP
|
||||
@@ -33,15 +33,15 @@
|
||||
|
||||
#include <boost/date_time/posix_time/posix_time.hpp>
|
||||
|
||||
namespace websocketpp {
|
||||
namespace websocketpp_02 {
|
||||
namespace log {
|
||||
|
||||
namespace alevel {
|
||||
typedef uint16_t value;
|
||||
|
||||
|
||||
static const value OFF = 0x0;
|
||||
|
||||
// A single line on connect with connecting ip, websocket version,
|
||||
|
||||
// A single line on connect with connecting ip, websocket version,
|
||||
// request resource, user agent, and the response code.
|
||||
static const value CONNECT = 0x1;
|
||||
// A single line on disconnect with wasClean status and local and remote
|
||||
@@ -58,36 +58,36 @@ namespace alevel {
|
||||
static const value MESSAGE_HEADER = 0x40;
|
||||
// Adds payloads to message logs. Note these can be long!
|
||||
static const value MESSAGE_PAYLOAD = 0x80;
|
||||
|
||||
|
||||
// Notices about internal endpoint operations
|
||||
static const value ENDPOINT = 0x100;
|
||||
|
||||
|
||||
// DEBUG values
|
||||
static const value DEBUG_HANDSHAKE = 0x8000;
|
||||
static const value DEBUG_CLOSE = 0x4000;
|
||||
static const value DEVEL = 0x2000;
|
||||
|
||||
|
||||
static const value ALL = 0xFFFF;
|
||||
}
|
||||
|
||||
namespace elevel {
|
||||
typedef uint32_t value; // make these two values different types DJS
|
||||
|
||||
|
||||
static const value OFF = 0x0;
|
||||
|
||||
|
||||
static const value DEVEL = 0x1; // debugging
|
||||
static const value LIBRARY = 0x2; // library usage exceptions
|
||||
static const value INFO = 0x4; //
|
||||
static const value INFO = 0x4; //
|
||||
static const value WARN = 0x8; //
|
||||
static const value RERROR = 0x10; // recoverable error
|
||||
static const value FATAL = 0x20; // unrecoverable error
|
||||
|
||||
|
||||
static const value ALL = 0xFFFF;
|
||||
}
|
||||
|
||||
extern void websocketLog(alevel::value, const std::string&);
|
||||
extern void websocketLog(elevel::value, const std::string&);
|
||||
|
||||
|
||||
template <typename level_type>
|
||||
class logger {
|
||||
public:
|
||||
@@ -96,32 +96,32 @@ public:
|
||||
m_oss << a; // For now, make this unconditional DJS
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
logger<level_type>& operator<<(logger<level_type>& (*f)(logger<level_type>&)) {
|
||||
return f(*this);
|
||||
}
|
||||
|
||||
|
||||
bool test_level(level_type l) {
|
||||
return (m_level & l) != 0;
|
||||
}
|
||||
|
||||
|
||||
void set_level(level_type l) {
|
||||
m_level |= l;
|
||||
}
|
||||
|
||||
|
||||
void set_levels(level_type l1, level_type l2) {
|
||||
level_type i = l1;
|
||||
|
||||
|
||||
while (i <= l2) {
|
||||
set_level(i);
|
||||
i *= 2;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void unset_level(level_type l) {
|
||||
m_level &= ~l;
|
||||
}
|
||||
|
||||
|
||||
void set_prefix(const std::string& prefix) {
|
||||
if (prefix == "") {
|
||||
m_prefix = prefix;
|
||||
@@ -129,13 +129,13 @@ public:
|
||||
m_prefix = prefix + " ";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
logger<level_type>& print() {
|
||||
websocketLog(m_write_level, m_oss.str()); // Hand to our logger DJS
|
||||
m_oss.str("");
|
||||
#if 0
|
||||
if (test_level(m_write_level)) {
|
||||
std::cout << m_prefix <<
|
||||
std::cout << m_prefix <<
|
||||
boost::posix_time::to_iso_extended_string(
|
||||
boost::posix_time::second_clock::local_time()
|
||||
) << " [" << m_write_level << "] " << m_oss.str() << std::endl;
|
||||
@@ -144,7 +144,7 @@ public:
|
||||
#endif
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
logger<level_type>& at(level_type l) {
|
||||
m_write_level = l;
|
||||
return *this;
|
||||
|
||||
@@ -11,10 +11,10 @@
|
||||
* * 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
|
||||
*
|
||||
* 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;
|
||||
@@ -22,7 +22,7 @@
|
||||
* 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_MD5_WRAPPER_HPP
|
||||
@@ -31,22 +31,22 @@
|
||||
#include "md5.h"
|
||||
#include <string>
|
||||
|
||||
namespace websocketpp {
|
||||
namespace websocketpp_02 {
|
||||
|
||||
// could be compiled separately
|
||||
inline std::string md5_hash_string(const std::string& s) {
|
||||
char digest[16];
|
||||
|
||||
|
||||
md5_state_t state;
|
||||
|
||||
|
||||
md5_init(&state);
|
||||
md5_append(&state, (const md5_byte_t *)s.c_str(), s.size());
|
||||
md5_finish(&state, (md5_byte_t *)digest);
|
||||
|
||||
|
||||
std::string ret;
|
||||
ret.resize(16);
|
||||
std::copy(digest,digest+16,ret.begin());
|
||||
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -55,15 +55,15 @@ const char hexval[16] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a',
|
||||
inline std::string md5_hash_hex(const std::string& input) {
|
||||
std::string hash = md5_hash_string(input);
|
||||
std::string hex;
|
||||
|
||||
|
||||
for (size_t i = 0; i < hash.size(); i++) {
|
||||
hex.push_back(hexval[((hash[i] >> 4) & 0xF)]);
|
||||
hex.push_back(hexval[(hash[i]) & 0x0F]);
|
||||
}
|
||||
|
||||
|
||||
return hex;
|
||||
}
|
||||
|
||||
} // websocketpp
|
||||
} // websocketpp_02
|
||||
|
||||
#endif // WEBSOCKETPP_MD5_WRAPPER_HPP
|
||||
|
||||
@@ -11,10 +11,10 @@
|
||||
* * 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
|
||||
*
|
||||
* 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;
|
||||
@@ -22,7 +22,7 @@
|
||||
* 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 WEBSOCKET_CONTROL_MESSAGE_HPP
|
||||
@@ -36,9 +36,9 @@
|
||||
#include "../utf8_validator/utf8_validator.hpp"
|
||||
#include "../processors/hybi_util.hpp"
|
||||
|
||||
using websocketpp::processor::hybi_util::circshift_prepared_key;
|
||||
using websocketpp_02::processor::hybi_util::circshift_prepared_key;
|
||||
|
||||
namespace websocketpp {
|
||||
namespace websocketpp_02 {
|
||||
namespace message {
|
||||
|
||||
class control {
|
||||
@@ -46,55 +46,55 @@ public:
|
||||
control() {
|
||||
m_payload.reserve(PAYLOAD_SIZE_INIT);
|
||||
}
|
||||
|
||||
|
||||
frame::opcode::value get_opcode() const {
|
||||
return m_opcode;
|
||||
};
|
||||
|
||||
|
||||
const std::string& get_payload() const {
|
||||
return m_payload;
|
||||
}
|
||||
|
||||
|
||||
void process_payload(char *input,uint64_t size) {
|
||||
const size_t new_size = static_cast<size_t>(m_payload.size() + size);
|
||||
|
||||
|
||||
if (new_size > PAYLOAD_SIZE_MAX) {
|
||||
throw processor::exception("Message payload was too large.",processor::error::MESSAGE_TOO_BIG);
|
||||
}
|
||||
|
||||
|
||||
if (m_masked) {
|
||||
// this retrieves ceiling of size / word size
|
||||
size_t n = static_cast<size_t>((size + sizeof(size_t) - 1) / sizeof(size_t));
|
||||
|
||||
|
||||
// reinterpret the input as an array of word sized integers
|
||||
size_t* data = reinterpret_cast<size_t*>(input);
|
||||
|
||||
|
||||
// unmask working buffer
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
data[i] ^= m_prepared_key;
|
||||
}
|
||||
|
||||
|
||||
// circshift working key
|
||||
m_prepared_key = circshift_prepared_key(m_prepared_key, size%4);
|
||||
}
|
||||
|
||||
|
||||
// copy working buffer into
|
||||
m_payload.append(input, static_cast<size_t>(size));
|
||||
}
|
||||
|
||||
|
||||
void complete() {
|
||||
if (m_opcode == frame::opcode::CLOSE) {
|
||||
if (m_payload.size() == 1) {
|
||||
throw processor::exception("Single byte close code",processor::error::PROTOCOL_VIOLATION);
|
||||
} else if (m_payload.size() >= 2) {
|
||||
close::status::value code = close::status::value(get_raw_close_code());
|
||||
|
||||
|
||||
if (close::status::invalid(code)) {
|
||||
throw processor::exception("Close code is not allowed on the wire.",processor::error::PROTOCOL_VIOLATION);
|
||||
} else if (close::status::reserved(code)) {
|
||||
throw processor::exception("Close code is reserved.",processor::error::PROTOCOL_VIOLATION);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
if (m_payload.size() > 2) {
|
||||
if (!m_validator.decode(m_payload.begin()+2,m_payload.end())) {
|
||||
@@ -106,14 +106,14 @@ public:
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void reset(frame::opcode::value opcode, uint32_t masking_key) {
|
||||
m_opcode = opcode;
|
||||
set_masking_key(masking_key);
|
||||
m_payload.resize(0);
|
||||
m_validator.reset();
|
||||
}
|
||||
|
||||
|
||||
close::status::value get_close_code() const {
|
||||
if (m_payload.size() == 0) {
|
||||
return close::status::NO_STATUS;
|
||||
@@ -121,7 +121,7 @@ public:
|
||||
return close::status::value(get_raw_close_code());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
std::string get_close_reason() const {
|
||||
if (m_payload.size() > 2) {
|
||||
return m_payload.substr(2);
|
||||
@@ -129,7 +129,7 @@ public:
|
||||
return std::string();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void set_masking_key(int32_t key) {
|
||||
m_masking_key.i = key;
|
||||
m_prepared_key = processor::hybi_util::prepare_masking_key(m_masking_key);
|
||||
@@ -140,36 +140,36 @@ private:
|
||||
if (m_payload.size() <= 1) {
|
||||
throw processor::exception("get_raw_close_code called with invalid size",processor::error::FATAL_ERROR);
|
||||
}
|
||||
|
||||
|
||||
union {uint16_t i;char c[2];} val;
|
||||
|
||||
|
||||
val.c[0] = m_payload[0];
|
||||
val.c[1] = m_payload[1];
|
||||
|
||||
|
||||
return ntohs(val.i);
|
||||
}
|
||||
|
||||
|
||||
static const uint64_t PAYLOAD_SIZE_INIT = 128; // 128B
|
||||
static const uint64_t PAYLOAD_SIZE_MAX = 128; // 128B
|
||||
|
||||
typedef websocketpp::processor::hybi_util::masking_key_type masking_key_type;
|
||||
|
||||
|
||||
typedef websocketpp_02::processor::hybi_util::masking_key_type masking_key_type;
|
||||
|
||||
union masking_key {
|
||||
int32_t i;
|
||||
char c[4];
|
||||
};
|
||||
|
||||
|
||||
// Message state
|
||||
frame::opcode::value m_opcode;
|
||||
|
||||
|
||||
// UTF8 validation state
|
||||
utf8_validator::validator m_validator;
|
||||
|
||||
|
||||
// Masking state
|
||||
masking_key_type m_masking_key;
|
||||
bool m_masked;
|
||||
size_t m_prepared_key;
|
||||
|
||||
|
||||
// Message payload
|
||||
std::string m_payload;
|
||||
};
|
||||
@@ -177,6 +177,6 @@ private:
|
||||
typedef boost::shared_ptr<control> control_ptr;
|
||||
|
||||
} // namespace message
|
||||
} // namespace websocketpp
|
||||
} // namespace websocketpp_02
|
||||
|
||||
#endif // WEBSOCKET_CONTROL_MESSAGE_HPP
|
||||
|
||||
@@ -11,10 +11,10 @@
|
||||
* * 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
|
||||
*
|
||||
* 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;
|
||||
@@ -22,7 +22,7 @@
|
||||
* 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.
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#include "data.hpp"
|
||||
@@ -34,14 +34,14 @@
|
||||
#undef max
|
||||
#endif // #ifdef max
|
||||
|
||||
using websocketpp::message::data;
|
||||
using websocketpp::processor::hybi_util::circshift_prepared_key;
|
||||
using websocketpp_02::message::data;
|
||||
using websocketpp_02::processor::hybi_util::circshift_prepared_key;
|
||||
|
||||
data::data(data::pool_ptr p, size_t s) : m_prepared(false),m_index(s),m_ref_count(0),m_pool(p),m_live(false) {
|
||||
m_payload.reserve(PAYLOAD_SIZE_INIT);
|
||||
}
|
||||
|
||||
websocketpp::frame::opcode::value data::get_opcode() const {
|
||||
|
||||
websocketpp_02::frame::opcode::value data::get_opcode() const {
|
||||
return m_opcode;
|
||||
}
|
||||
|
||||
@@ -52,61 +52,61 @@ const std::string& data::get_header() const {
|
||||
return m_header;
|
||||
}
|
||||
|
||||
// input must be a buffer with size divisible by the machine word_size and at
|
||||
// input must be a buffer with size divisible by the machine word_size and at
|
||||
// least ceil(size/word_size)*word_size bytes long.
|
||||
void data::process_payload(char *input, size_t size) {
|
||||
//std::cout << "data message processing: " << size << " bytes" << std::endl;
|
||||
|
||||
|
||||
const size_t new_size = m_payload.size() + size;
|
||||
|
||||
|
||||
if (new_size > PAYLOAD_SIZE_MAX) {
|
||||
throw processor::exception("Message too big",processor::error::MESSAGE_TOO_BIG);
|
||||
}
|
||||
|
||||
|
||||
if (new_size > m_payload.capacity()) {
|
||||
m_payload.reserve(std::max(new_size, 2*m_payload.capacity()));
|
||||
}
|
||||
|
||||
|
||||
if (m_masked) {
|
||||
//std::cout << "message is masked" << std::endl;
|
||||
|
||||
|
||||
//std::cout << "before: " << zsutil::to_hex(input, size) << std::endl;
|
||||
|
||||
|
||||
// this retrieves ceiling of size / word size
|
||||
size_t n = (size + sizeof(size_t) - 1) / sizeof(size_t);
|
||||
|
||||
|
||||
// reinterpret the input as an array of word sized integers
|
||||
size_t* data = reinterpret_cast<size_t*>(input);
|
||||
|
||||
|
||||
// unmask working buffer
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
data[i] ^= m_prepared_key;
|
||||
}
|
||||
|
||||
|
||||
//std::cout << "after: " << zsutil::to_hex(input, size) << std::endl;
|
||||
|
||||
|
||||
// circshift working key
|
||||
//std::cout << "circshift by : " << size%4 << " bytes " << zsutil::to_hex(reinterpret_cast<char*>(&m_prepared_key),sizeof(size_t));
|
||||
m_prepared_key = circshift_prepared_key(m_prepared_key, size%4);
|
||||
//std::cout << " to " << zsutil::to_hex(reinterpret_cast<char*>(&m_prepared_key),sizeof(size_t)) << std::endl;
|
||||
}
|
||||
|
||||
|
||||
if (m_opcode == frame::opcode::TEXT) {
|
||||
if (!m_validator.decode(input, input+size)) {
|
||||
throw processor::exception("Invalid UTF8 data",
|
||||
processor::error::PAYLOAD_VIOLATION);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// copy working buffer into
|
||||
//std::cout << "before: " << m_payload.size() << std::endl;
|
||||
|
||||
|
||||
m_payload.append(input, size);
|
||||
|
||||
|
||||
//std::cout << "after: " << m_payload.size() << std::endl;
|
||||
}
|
||||
|
||||
void data::reset(websocketpp::frame::opcode::value opcode) {
|
||||
|
||||
void data::reset(websocketpp_02::frame::opcode::value opcode) {
|
||||
m_opcode = opcode;
|
||||
m_masked = false;
|
||||
m_payload.clear();
|
||||
@@ -128,7 +128,7 @@ void data::validate_payload() {
|
||||
if (!m_validator.decode(m_payload.begin(), m_payload.end())) {
|
||||
throw exception("Invalid UTF8 data",error::PAYLOAD_VIOLATION);
|
||||
}
|
||||
|
||||
|
||||
if (!m_validator.complete()) {
|
||||
throw exception("Invalid UTF8 data",error::PAYLOAD_VIOLATION);
|
||||
}
|
||||
@@ -146,7 +146,7 @@ void data::set_prepared(bool b) {
|
||||
}
|
||||
|
||||
bool data::get_prepared() const {
|
||||
return m_prepared;
|
||||
return m_prepared;
|
||||
}
|
||||
|
||||
// This could be further optimized using methods that write directly into the
|
||||
@@ -162,30 +162,30 @@ void data::append_payload(const std::string& payload) {
|
||||
void data::mask() {
|
||||
if (m_masked && m_payload.size() > 0) {
|
||||
// By default WebSocket++ performs block masking/unmasking in a mannor that makes
|
||||
// some assumptions about the nature of the machine and STL library used. In
|
||||
// some assumptions about the nature of the machine and STL library used. In
|
||||
// particular the assumption is either a 32 or 64 bit word size and an STL with
|
||||
// std::string::data returning a contiguous char array.
|
||||
//
|
||||
// This method improves performance by 3-8x depending on the ratio of small to
|
||||
// This method improves performance by 3-8x depending on the ratio of small to
|
||||
// large messages and the availability of a 64 bit processor.
|
||||
//
|
||||
// To disable this optimization (for use with alternative STL implementations or
|
||||
// processors) define WEBSOCKETPP_STRICT_MASKING when compiling the library. This
|
||||
// will force the library to perform masking in single byte chunks.
|
||||
//#define WEBSOCKETPP_STRICT_MASKING
|
||||
|
||||
|
||||
#ifdef WEBSOCKETPP_STRICT_MASKING
|
||||
size_t len = m_payload.size();
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
m_payload[i] ^= m_masking_key.c[i%4];
|
||||
}
|
||||
#else
|
||||
// This should trigger a write to the string in case the STL
|
||||
// This should trigger a write to the string in case the STL
|
||||
// implimentation is copy-on-write and hasn't been written to yet.
|
||||
// Performing the masking will always require a copy of the string
|
||||
// Performing the masking will always require a copy of the string
|
||||
// in this case to hold the masked version.
|
||||
m_payload[0] = m_payload[0];
|
||||
|
||||
|
||||
size_t size = m_payload.size()/sizeof(size_t);
|
||||
size_t key = m_masking_key.i;
|
||||
size_t wordSize = sizeof(size_t);
|
||||
|
||||
@@ -11,10 +11,10 @@
|
||||
* * 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
|
||||
*
|
||||
* 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;
|
||||
@@ -22,7 +22,7 @@
|
||||
* 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 WEBSOCKET_DATA_MESSAGE_HPP
|
||||
@@ -49,7 +49,7 @@
|
||||
#include <queue>
|
||||
#include <vector>
|
||||
|
||||
namespace websocketpp {
|
||||
namespace websocketpp_02 {
|
||||
namespace message {
|
||||
|
||||
/// message::pool impliments a reference counted pool of elements.
|
||||
@@ -71,32 +71,32 @@ public:
|
||||
typedef boost::weak_ptr<type> weak_ptr;
|
||||
typedef typename element_type::ptr element_ptr;
|
||||
typedef boost::function<void()> callback_type;
|
||||
|
||||
|
||||
pool(size_t max_elements) : m_cur_elements(0),m_max_elements(max_elements) {}
|
||||
~pool() {}
|
||||
|
||||
|
||||
// copy/assignment constructors require C++11
|
||||
// boost::noncopyable is being used in the meantime.
|
||||
// pool(pool const&) = delete;
|
||||
// pool& operator=(pool const&) = delete
|
||||
|
||||
|
||||
/// Requests a pointer to the next free element in the resource pool.
|
||||
/* If there isn't a free element a new one is created. If the maximum number
|
||||
* of elements has been created then it returns an empty/null element
|
||||
* of elements has been created then it returns an empty/null element
|
||||
* pointer.
|
||||
*/
|
||||
element_ptr get() {
|
||||
element_ptr p, q;
|
||||
{
|
||||
boost::lock_guard<boost::recursive_mutex> lock(m_lock);
|
||||
|
||||
/*std::cout << "message requested ("
|
||||
|
||||
/*std::cout << "message requested ("
|
||||
<< m_cur_elements-m_avaliable.size()
|
||||
<< "/"
|
||||
<< m_cur_elements
|
||||
<< ")"
|
||||
<< std::endl;*/
|
||||
|
||||
|
||||
if (!m_avaliable.empty()) {
|
||||
p = m_avaliable.front(); // FIXME can call intrusive_ptr_add_ref (line 215) which can deadlock
|
||||
q = p;
|
||||
@@ -106,59 +106,59 @@ public:
|
||||
if (m_cur_elements == m_max_elements) {
|
||||
return element_ptr();
|
||||
}
|
||||
|
||||
|
||||
p = element_ptr(new element_type(type::shared_from_this(),m_cur_elements));
|
||||
m_cur_elements++;
|
||||
m_used.push_back(p);
|
||||
|
||||
/*std::cout << "Allocated new data message. Count is now "
|
||||
|
||||
/*std::cout << "Allocated new data message. Count is now "
|
||||
<< m_cur_elements
|
||||
<< std::endl;*/
|
||||
}
|
||||
|
||||
|
||||
p->set_live();
|
||||
}
|
||||
return p;
|
||||
}
|
||||
void recycle(element_ptr p) {
|
||||
boost::lock_guard<boost::recursive_mutex> lock(m_lock);
|
||||
|
||||
|
||||
if (p->get_index()+1 > m_used.size() || m_used[p->get_index()] != p) {
|
||||
//std::cout << "error tried to recycle a pointer we don't control" << std::endl;
|
||||
// error tried to recycle a pointer we don't control
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
m_avaliable.push(p);
|
||||
m_used[p->get_index()] = element_ptr();
|
||||
|
||||
/*std::cout << "message recycled ("
|
||||
|
||||
/*std::cout << "message recycled ("
|
||||
<< m_cur_elements-m_avaliable.size()
|
||||
<< "/"
|
||||
<< m_cur_elements
|
||||
<< ")"
|
||||
<< std::endl;*/
|
||||
|
||||
|
||||
if (m_callback && m_avaliable.size() == 1) {
|
||||
m_callback();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// set a function that will be called when new elements are avaliable.
|
||||
void set_callback(callback_type fn) {
|
||||
boost::lock_guard<boost::recursive_mutex> lock(m_lock);
|
||||
m_callback = fn;
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
size_t m_cur_elements;
|
||||
size_t m_max_elements;
|
||||
|
||||
|
||||
std::queue<element_ptr> m_avaliable;
|
||||
std::vector<element_ptr> m_used;
|
||||
|
||||
|
||||
callback_type m_callback;
|
||||
|
||||
|
||||
boost::recursive_mutex m_lock;
|
||||
};
|
||||
|
||||
@@ -167,19 +167,19 @@ public:
|
||||
typedef boost::intrusive_ptr<data> ptr;
|
||||
typedef pool<data>::ptr pool_ptr;
|
||||
typedef pool<data>::weak_ptr pool_weak_ptr;
|
||||
|
||||
|
||||
data(pool_ptr p, size_t s);
|
||||
|
||||
void reset(websocketpp::frame::opcode::value opcode);
|
||||
|
||||
|
||||
void reset(websocketpp_02::frame::opcode::value opcode);
|
||||
|
||||
frame::opcode::value get_opcode() const;
|
||||
const std::string& get_payload() const;
|
||||
const std::string& get_header() const;
|
||||
|
||||
|
||||
// ##reading##
|
||||
// sets the masking key to be used to unmask as bytes are read.
|
||||
void set_masking_key(int32_t key);
|
||||
|
||||
|
||||
// read at most size bytes from a payload stream and perform unmasking/utf8
|
||||
// validation. Returns number of bytes read.
|
||||
// throws a processor::exception if the message is too big, there is a fatal
|
||||
@@ -188,76 +188,76 @@ public:
|
||||
void process_payload(char * input, size_t size);
|
||||
void complete();
|
||||
void validate_payload();
|
||||
|
||||
|
||||
// ##writing##
|
||||
// sets the payload to payload. Performs max size and UTF8 validation
|
||||
// sets the payload to payload. Performs max size and UTF8 validation
|
||||
// immediately and throws processor::exception if it fails
|
||||
void set_payload(const std::string& payload);
|
||||
void append_payload(const std::string& payload);
|
||||
|
||||
|
||||
void set_header(const std::string& header);
|
||||
|
||||
|
||||
// Performs masking and header generation if it has not been done already.
|
||||
void set_prepared(bool b);
|
||||
bool get_prepared() const;
|
||||
void mask();
|
||||
|
||||
|
||||
int32_t get_masking_key() const {
|
||||
return m_masking_key.i;
|
||||
}
|
||||
|
||||
|
||||
// pool management interface
|
||||
void set_live();
|
||||
size_t get_index() const;
|
||||
private:
|
||||
static const uint64_t PAYLOAD_SIZE_INIT = 1000; // 1KB
|
||||
static const uint64_t PAYLOAD_SIZE_MAX = 100000000;// 100MB
|
||||
|
||||
typedef websocketpp::processor::hybi_util::masking_key_type masking_key_type;
|
||||
|
||||
|
||||
typedef websocketpp_02::processor::hybi_util::masking_key_type masking_key_type;
|
||||
|
||||
friend void intrusive_ptr_add_ref(const data * s) {
|
||||
boost::unique_lock<boost::recursive_mutex> lock(s->m_lock);
|
||||
++s->m_ref_count;
|
||||
}
|
||||
|
||||
|
||||
friend void intrusive_ptr_release(const data * s) {
|
||||
boost::unique_lock<boost::recursive_mutex> lock(s->m_lock);
|
||||
|
||||
|
||||
// TODO: thread safety
|
||||
long count = --s->m_ref_count;
|
||||
if (count == 1 && s->m_live) {
|
||||
// recycle if endpoint exists
|
||||
s->m_live = false;
|
||||
|
||||
|
||||
pool_ptr pp = s->m_pool.lock();
|
||||
if (pp) {
|
||||
lock.unlock();
|
||||
pp->recycle(ptr(const_cast<data *>(s)));
|
||||
}
|
||||
|
||||
|
||||
//s->m_pool->recycle(ptr(const_cast<data *>(s)));
|
||||
} else if (count == 0) {
|
||||
lock.unlock();
|
||||
boost::checked_delete(static_cast<data const *>(s));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Message state
|
||||
frame::opcode::value m_opcode;
|
||||
|
||||
|
||||
// UTF8 validation state
|
||||
utf8_validator::validator m_validator;
|
||||
|
||||
|
||||
// Masking state
|
||||
masking_key_type m_masking_key;
|
||||
bool m_masked;
|
||||
size_t m_prepared_key;
|
||||
|
||||
|
||||
std::string m_header;
|
||||
std::string m_payload;
|
||||
|
||||
|
||||
bool m_prepared;
|
||||
|
||||
|
||||
// reference counting
|
||||
size_t m_index;
|
||||
mutable boost::detail::atomic_count m_ref_count;
|
||||
@@ -267,8 +267,8 @@ private:
|
||||
};
|
||||
|
||||
typedef boost::intrusive_ptr<data> data_ptr;
|
||||
|
||||
|
||||
} // namespace message
|
||||
} // namespace websocketpp
|
||||
} // namespace websocketpp_02
|
||||
|
||||
#endif // WEBSOCKET_DATA_MESSAGE_HPP
|
||||
|
||||
@@ -11,10 +11,10 @@
|
||||
* * 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
|
||||
*
|
||||
* 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;
|
||||
@@ -22,7 +22,7 @@
|
||||
* 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 WEBSOCKET_PROCESSOR_HYBI_HPP
|
||||
@@ -44,7 +44,7 @@
|
||||
#undef min
|
||||
#endif // #ifdef min
|
||||
|
||||
namespace websocketpp {
|
||||
namespace websocketpp_02 {
|
||||
namespace processor {
|
||||
|
||||
namespace hybi_state {
|
||||
@@ -91,11 +91,11 @@ std::list< std::pair< std::string,std::string > >
|
||||
/*class hybi_message {
|
||||
public:
|
||||
hybi_message(frame::opcode::value opcode) : m_processed(false) {
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
void reset() {
|
||||
|
||||
|
||||
}
|
||||
private:
|
||||
bool m_processed;
|
||||
@@ -112,37 +112,37 @@ private:
|
||||
template <class connection_type>
|
||||
class hybi : public processor_base {
|
||||
public:
|
||||
hybi(connection_type &connection)
|
||||
hybi(connection_type &connection)
|
||||
: m_connection(connection),
|
||||
m_write_frame(connection)
|
||||
{
|
||||
reset();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void validate_handshake(const http::parser::request& request) const {
|
||||
std::stringstream err;
|
||||
std::string h;
|
||||
|
||||
|
||||
if (request.method() != "GET") {
|
||||
err << "Websocket handshake has invalid method: "
|
||||
err << "Websocket handshake has invalid method: "
|
||||
<< request.method();
|
||||
|
||||
|
||||
throw(http::exception(err.str(),http::status_code::BAD_REQUEST));
|
||||
}
|
||||
|
||||
|
||||
// TODO: allow versions greater than 1.1
|
||||
if (request.version() != "HTTP/1.1") {
|
||||
err << "Websocket handshake has invalid HTTP version: "
|
||||
err << "Websocket handshake has invalid HTTP version: "
|
||||
<< request.method();
|
||||
|
||||
|
||||
throw(http::exception(err.str(),http::status_code::BAD_REQUEST));
|
||||
}
|
||||
|
||||
|
||||
// verify the presence of required headers
|
||||
if (request.header("Host") == "") {
|
||||
throw(http::exception("Required Host header is missing",http::status_code::BAD_REQUEST));
|
||||
}
|
||||
|
||||
|
||||
h = request.header("Upgrade");
|
||||
if (h == "") {
|
||||
throw(http::exception("Required Upgrade header is missing",http::status_code::BAD_REQUEST));
|
||||
@@ -150,26 +150,26 @@ public:
|
||||
err << "Upgrade header \"" << h << "\", does not contain required token \"websocket\"";
|
||||
throw(http::exception(err.str(),http::status_code::BAD_REQUEST));
|
||||
}
|
||||
|
||||
|
||||
h = request.header("Connection");
|
||||
if (h == "") {
|
||||
throw(http::exception("Required Connection header is missing",http::status_code::BAD_REQUEST));
|
||||
} else if (!boost::ifind_first(h,"upgrade")) {
|
||||
err << "Connection header, \"" << h
|
||||
err << "Connection header, \"" << h
|
||||
<< "\", does not contain required token \"upgrade\"";
|
||||
throw(http::exception(err.str(),http::status_code::BAD_REQUEST));
|
||||
}
|
||||
|
||||
|
||||
if (request.header("Sec-WebSocket-Key") == "") {
|
||||
throw(http::exception("Required Sec-WebSocket-Key header is missing",http::status_code::BAD_REQUEST));
|
||||
}
|
||||
|
||||
|
||||
h = request.header("Sec-WebSocket-Version");
|
||||
if (h == "") {
|
||||
throw(http::exception("Required Sec-WebSocket-Version header is missing",http::status_code::BAD_REQUEST));
|
||||
} else {
|
||||
int version = atoi(h.c_str());
|
||||
|
||||
|
||||
if (version != 7 && version != 8 && version != 13) {
|
||||
err << "This processor doesn't support WebSocket protocol version "
|
||||
<< version;
|
||||
@@ -177,11 +177,11 @@ public:
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
std::string get_origin(const http::parser::request& request) const {
|
||||
std::string h = request.header("Sec-WebSocket-Version");
|
||||
int version = atoi(h.c_str());
|
||||
|
||||
|
||||
if (version == 13) {
|
||||
return request.header("Origin");
|
||||
} else if (version == 7 || version == 8) {
|
||||
@@ -190,18 +190,18 @@ public:
|
||||
throw(http::exception("Could not determine origin header. Check Sec-WebSocket-Version header",http::status_code::BAD_REQUEST));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
uri_ptr get_uri(const http::parser::request& request) const {
|
||||
std::string h = request.header("Host");
|
||||
|
||||
|
||||
size_t last_colon = h.rfind(":");
|
||||
size_t last_sbrace = h.rfind("]");
|
||||
|
||||
|
||||
// no : = hostname with no port
|
||||
// last : before ] = ipv6 literal with no port
|
||||
// : with no ] = hostname with port
|
||||
// : after ] = ipv6 literal with port
|
||||
if (last_colon == std::string::npos ||
|
||||
if (last_colon == std::string::npos ||
|
||||
(last_sbrace != std::string::npos && last_sbrace > last_colon))
|
||||
{
|
||||
return uri_ptr(new uri(m_connection.is_secure(),h,request.uri()));
|
||||
@@ -211,46 +211,46 @@ public:
|
||||
h.substr(last_colon+1),
|
||||
request.uri()));
|
||||
}
|
||||
|
||||
|
||||
// TODO: check if get_uri is a full uri
|
||||
}
|
||||
|
||||
|
||||
void handshake_response(const http::parser::request& request,
|
||||
http::parser::response& response)
|
||||
http::parser::response& response)
|
||||
{
|
||||
std::string server_key = request.header("Sec-WebSocket-Key");
|
||||
server_key += "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
|
||||
|
||||
|
||||
SHA1 sha;
|
||||
uint32_t message_digest[5];
|
||||
|
||||
|
||||
sha.Reset();
|
||||
sha << server_key.c_str();
|
||||
|
||||
|
||||
if (sha.Result(message_digest)){
|
||||
// convert sha1 hash bytes to network byte order because this sha1
|
||||
// library works on ints rather than bytes
|
||||
for (int i = 0; i < 5; i++) {
|
||||
message_digest[i] = htonl(message_digest[i]);
|
||||
}
|
||||
|
||||
|
||||
server_key = base64_encode(
|
||||
reinterpret_cast<const unsigned char*>
|
||||
(message_digest),20
|
||||
);
|
||||
|
||||
|
||||
// set handshake accept headers
|
||||
response.replace_header("Sec-WebSocket-Accept",server_key);
|
||||
response.add_header("Upgrade","websocket");
|
||||
response.add_header("Connection","Upgrade");
|
||||
} else {
|
||||
//m_endpoint->elog().at(log::elevel::RERROR)
|
||||
//m_endpoint->elog().at(log::elevel::RERROR)
|
||||
//<< "Error computing handshake sha1 hash" << log::endl;
|
||||
// TODO: make sure this error path works
|
||||
response.set_status(http::status_code::INTERNAL_SERVER_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void consume(std::istream& s) {
|
||||
while (s.good() && m_state != hybi_state::READY) {
|
||||
try {
|
||||
@@ -267,11 +267,11 @@ public:
|
||||
case hybi_state::IGNORE:
|
||||
s.ignore(m_payload_left);
|
||||
m_payload_left -= static_cast<size_t>(s.gcount());
|
||||
|
||||
|
||||
if (m_payload_left == 0) {
|
||||
reset();
|
||||
}
|
||||
|
||||
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@@ -279,8 +279,8 @@ public:
|
||||
} catch (const processor::exception& e) {
|
||||
if (e.code() != processor::error::OUT_OF_MESSAGES) {
|
||||
// The out of messages exception acts as an inturrupt rather
|
||||
// than an error. In that case we don't want to reset
|
||||
// processor state. In all other cases we are aborting
|
||||
// than an error. In that case we don't want to reset
|
||||
// processor state. In all other cases we are aborting
|
||||
// processing of the message in flight and want to reset the
|
||||
// processor for a new message.
|
||||
if (m_header.ready()) {
|
||||
@@ -288,24 +288,24 @@ public:
|
||||
ignore();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Sends the processor an inturrupt signal instructing it to ignore the next
|
||||
// num bytes and then reset itself. This is used to flush a bad frame out of
|
||||
// the read buffer.
|
||||
void ignore() {
|
||||
m_state = hybi_state::IGNORE;
|
||||
}
|
||||
|
||||
|
||||
void process_header(std::istream& s) {
|
||||
m_header.consume(s);
|
||||
|
||||
|
||||
if (m_header.ready()) {
|
||||
// Get a free message from the read queue for the type of the
|
||||
// Get a free message from the read queue for the type of the
|
||||
// current message
|
||||
if (m_header.is_control()) {
|
||||
process_control_header();
|
||||
@@ -314,40 +314,40 @@ public:
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void process_control_header() {
|
||||
m_control_message = m_connection.get_control_message();
|
||||
|
||||
|
||||
if (!m_control_message) {
|
||||
throw processor::exception("Out of control messages",
|
||||
processor::error::OUT_OF_MESSAGES);
|
||||
}
|
||||
|
||||
|
||||
m_control_message->reset(m_header.get_opcode(),m_header.get_masking_key());
|
||||
|
||||
|
||||
m_payload_left = static_cast<size_t>(m_header.get_payload_size());
|
||||
|
||||
|
||||
if (m_payload_left == 0) {
|
||||
process_frame();
|
||||
} else {
|
||||
m_state = hybi_state::READ_PAYLOAD;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void process_data_header() {
|
||||
if (!m_data_message) {
|
||||
// This is a new message. No continuation frames allowed.
|
||||
if (m_header.get_opcode() == frame::opcode::CONTINUATION) {
|
||||
throw processor::exception("Received continuation frame without an outstanding message.",processor::error::PROTOCOL_VIOLATION);
|
||||
}
|
||||
|
||||
|
||||
m_data_message = m_connection.get_data_message();
|
||||
|
||||
|
||||
if (!m_data_message) {
|
||||
throw processor::exception("Out of data messages",
|
||||
processor::error::OUT_OF_MESSAGES);
|
||||
}
|
||||
|
||||
|
||||
m_data_message->reset(m_header.get_opcode());
|
||||
} else {
|
||||
// A message has already been started. Continuation frames only!
|
||||
@@ -355,9 +355,9 @@ public:
|
||||
throw processor::exception("Received new message before the completion of the existing one.",processor::error::PROTOCOL_VIOLATION);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
m_payload_left = static_cast<size_t>(m_header.get_payload_size());
|
||||
|
||||
|
||||
if (m_payload_left == 0) {
|
||||
process_frame();
|
||||
} else {
|
||||
@@ -366,28 +366,28 @@ public:
|
||||
m_state = hybi_state::READ_PAYLOAD;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void process_payload(std::istream& input) {
|
||||
//std::cout << "payload left 1: " << m_payload_left << std::endl;
|
||||
size_t num;
|
||||
|
||||
|
||||
// read bytes into processor buffer. Read the lesser of the buffer size
|
||||
// and the number of bytes left in the payload.
|
||||
|
||||
|
||||
input.read(m_payload_buffer, std::min(m_payload_left, PAYLOAD_BUFFER_SIZE));
|
||||
num = static_cast<size_t>(input.gcount());
|
||||
|
||||
|
||||
if (input.bad()) {
|
||||
throw processor::exception("istream readsome error",
|
||||
processor::error::FATAL_ERROR);
|
||||
}
|
||||
|
||||
|
||||
if (num == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
m_payload_left -= num;
|
||||
|
||||
|
||||
// tell the appropriate message to process the bytes.
|
||||
if (m_header.is_control()) {
|
||||
m_control_message->process_payload(m_payload_buffer,num);
|
||||
@@ -395,13 +395,13 @@ public:
|
||||
//m_connection.alog().at(log::alevel::DEVEL) << "process_payload. Size: " << m_payload_left << log::endl;
|
||||
m_data_message->process_payload(m_payload_buffer,num);
|
||||
}
|
||||
|
||||
|
||||
if (m_payload_left == 0) {
|
||||
process_frame();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
void process_frame() {
|
||||
if (m_header.get_fin()) {
|
||||
if (m_header.is_control()) {
|
||||
@@ -414,34 +414,34 @@ public:
|
||||
reset();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool ready() const {
|
||||
return m_state == hybi_state::READY;
|
||||
}
|
||||
|
||||
|
||||
bool is_control() const {
|
||||
return m_header.is_control();
|
||||
}
|
||||
|
||||
|
||||
// note this can only be called once
|
||||
message::data_ptr get_data_message() {
|
||||
message::data_ptr p = m_data_message;
|
||||
m_data_message.reset();
|
||||
return p;
|
||||
}
|
||||
|
||||
|
||||
// note this can only be called once
|
||||
message::control_ptr get_control_message() {
|
||||
message::control_ptr p = m_control_message;
|
||||
m_control_message.reset();
|
||||
return p;
|
||||
}
|
||||
|
||||
|
||||
void reset() {
|
||||
m_state = hybi_state::READ_HEADER;
|
||||
m_header.reset();
|
||||
}
|
||||
|
||||
|
||||
uint64_t get_bytes_needed() const {
|
||||
switch (m_state) {
|
||||
case hybi_state::READ_HEADER:
|
||||
@@ -455,8 +455,8 @@ public:
|
||||
throw "shouldn't be here";
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: replace all this to remove all lingering dependencies on
|
||||
|
||||
// TODO: replace all this to remove all lingering dependencies on
|
||||
// websocket_frame
|
||||
binary_string_ptr prepare_frame(frame::opcode::value opcode,
|
||||
bool mask,
|
||||
@@ -465,37 +465,37 @@ public:
|
||||
// TODO: hybi_legacy doesn't allow non-text frames.
|
||||
throw;
|
||||
}*/
|
||||
|
||||
|
||||
// TODO: utf8 validation on payload.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
binary_string_ptr response(new binary_string(0));
|
||||
|
||||
|
||||
|
||||
|
||||
m_write_frame.reset();
|
||||
m_write_frame.set_opcode(opcode);
|
||||
m_write_frame.set_masked(mask);
|
||||
|
||||
|
||||
m_write_frame.set_fin(true);
|
||||
m_write_frame.set_payload(payload);
|
||||
|
||||
|
||||
|
||||
|
||||
m_write_frame.process_payload();
|
||||
|
||||
|
||||
// TODO
|
||||
response->resize(m_write_frame.get_header_len()+m_write_frame.get_payload().size());
|
||||
|
||||
|
||||
// copy header
|
||||
std::copy(m_write_frame.get_header(),m_write_frame.get_header()+m_write_frame.get_header_len(),response->begin());
|
||||
|
||||
|
||||
// copy payload
|
||||
std::copy(m_write_frame.get_payload().begin(),m_write_frame.get_payload().end(),response->begin()+m_write_frame.get_header_len());
|
||||
|
||||
|
||||
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
|
||||
binary_string_ptr prepare_frame(frame::opcode::value opcode,
|
||||
bool mask,
|
||||
const binary_string& payload) {
|
||||
@@ -503,86 +503,86 @@ public:
|
||||
// TODO: hybi_legacy doesn't allow non-text frames.
|
||||
throw;
|
||||
}*/
|
||||
|
||||
|
||||
// TODO: utf8 validation on payload.
|
||||
|
||||
|
||||
binary_string_ptr response(new binary_string(0));
|
||||
|
||||
|
||||
m_write_frame.reset();
|
||||
m_write_frame.set_opcode(opcode);
|
||||
m_write_frame.set_masked(mask);
|
||||
m_write_frame.set_fin(true);
|
||||
m_write_frame.set_payload(payload);
|
||||
|
||||
|
||||
m_write_frame.process_payload();
|
||||
|
||||
|
||||
// TODO
|
||||
response->resize(m_write_frame.get_header_len()+m_write_frame.get_payload().size());
|
||||
|
||||
|
||||
// copy header
|
||||
std::copy(m_write_frame.get_header(),m_write_frame.get_header()+m_write_frame.get_header_len(),response->begin());
|
||||
|
||||
|
||||
// copy payload
|
||||
std::copy(m_write_frame.get_payload().begin(),m_write_frame.get_payload().end(),response->begin()+m_write_frame.get_header_len());
|
||||
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
|
||||
/*binary_string_ptr prepare_close_frame(close::status::value code,
|
||||
bool mask,
|
||||
const std::string& reason) {
|
||||
binary_string_ptr response(new binary_string(0));
|
||||
|
||||
|
||||
m_write_frame.reset();
|
||||
m_write_frame.set_opcode(frame::opcode::CLOSE);
|
||||
m_write_frame.set_masked(mask);
|
||||
m_write_frame.set_fin(true);
|
||||
m_write_frame.set_status(code,reason);
|
||||
|
||||
|
||||
m_write_frame.process_payload();
|
||||
|
||||
|
||||
// TODO
|
||||
response->resize(m_write_frame.get_header_len()+m_write_frame.get_payload().size());
|
||||
|
||||
|
||||
// copy header
|
||||
std::copy(m_write_frame.get_header(),m_write_frame.get_header()+m_write_frame.get_header_len(),response->begin());
|
||||
|
||||
|
||||
// copy payload
|
||||
std::copy(m_write_frame.get_payload().begin(),m_write_frame.get_payload().end(),response->begin()+m_write_frame.get_header_len());
|
||||
|
||||
|
||||
return response;
|
||||
}*/
|
||||
|
||||
|
||||
// new prepare frame stuff
|
||||
void prepare_frame(message::data_ptr msg) {
|
||||
assert(msg);
|
||||
if (msg->get_prepared()) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
msg->validate_payload();
|
||||
|
||||
|
||||
bool masked = !m_connection.is_server();
|
||||
int32_t key = m_connection.rand();
|
||||
|
||||
|
||||
m_write_header.reset();
|
||||
m_write_header.set_fin(true);
|
||||
m_write_header.set_opcode(msg->get_opcode());
|
||||
m_write_header.set_masked(masked,key);
|
||||
m_write_header.set_payload_size(msg->get_payload().size());
|
||||
m_write_header.complete();
|
||||
|
||||
|
||||
msg->set_header(m_write_header.get_header_bytes());
|
||||
|
||||
|
||||
if (masked) {
|
||||
msg->set_masking_key(key);
|
||||
msg->mask();
|
||||
}
|
||||
|
||||
|
||||
msg->set_prepared(true);
|
||||
}
|
||||
|
||||
void prepare_close_frame(message::data_ptr msg,
|
||||
|
||||
void prepare_close_frame(message::data_ptr msg,
|
||||
close::status::value code,
|
||||
const std::string& reason)
|
||||
{
|
||||
@@ -590,15 +590,15 @@ public:
|
||||
if (msg->get_prepared()) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// set close payload
|
||||
if (code != close::status::NO_STATUS) {
|
||||
const uint16_t payload = htons(static_cast<u_short>(code));
|
||||
|
||||
|
||||
msg->set_payload(std::string(reinterpret_cast<const char*>(&payload), 2));
|
||||
msg->append_payload(reason);
|
||||
}
|
||||
|
||||
|
||||
// prepare rest of frame
|
||||
prepare_frame(msg);
|
||||
}
|
||||
@@ -606,25 +606,25 @@ private:
|
||||
// must be divisible by 8 (some things are hardcoded for 4 and 8 byte word
|
||||
// sizes
|
||||
static const size_t PAYLOAD_BUFFER_SIZE = 512;
|
||||
|
||||
|
||||
connection_type& m_connection;
|
||||
int m_state;
|
||||
|
||||
|
||||
message::data_ptr m_data_message;
|
||||
message::control_ptr m_control_message;
|
||||
hybi_header m_header;
|
||||
hybi_header m_write_header;
|
||||
size_t m_payload_left;
|
||||
|
||||
|
||||
char m_payload_buffer[PAYLOAD_BUFFER_SIZE];
|
||||
|
||||
|
||||
frame::parser<connection_type> m_write_frame; // TODO: refactor this out
|
||||
};
|
||||
};
|
||||
|
||||
template <class connection_type>
|
||||
const size_t hybi<connection_type>::PAYLOAD_BUFFER_SIZE;
|
||||
|
||||
} // namespace processor
|
||||
} // namespace websocketpp
|
||||
} // namespace websocketpp_02
|
||||
|
||||
#endif // WEBSOCKET_PROCESSOR_HYBI_HPP
|
||||
|
||||
@@ -11,10 +11,10 @@
|
||||
* * 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
|
||||
*
|
||||
* 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;
|
||||
@@ -22,14 +22,14 @@
|
||||
* 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.
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#include "hybi_header.hpp"
|
||||
|
||||
#include <cstring>
|
||||
|
||||
using websocketpp::processor::hybi_header;
|
||||
using websocketpp_02::processor::hybi_header;
|
||||
|
||||
hybi_header::hybi_header() {
|
||||
reset();
|
||||
@@ -46,14 +46,14 @@ void hybi_header::consume(std::istream& input) {
|
||||
case STATE_BASIC_HEADER:
|
||||
input.read(&m_header[BASIC_HEADER_LENGTH-m_bytes_needed],
|
||||
m_bytes_needed);
|
||||
|
||||
|
||||
m_bytes_needed -= input.gcount();
|
||||
|
||||
|
||||
if (m_bytes_needed == 0) {
|
||||
process_basic_header();
|
||||
|
||||
|
||||
validate_basic_header();
|
||||
|
||||
|
||||
if (m_bytes_needed > 0) {
|
||||
m_state = STATE_EXTENDED_HEADER;
|
||||
} else {
|
||||
@@ -65,9 +65,9 @@ void hybi_header::consume(std::istream& input) {
|
||||
case STATE_EXTENDED_HEADER:
|
||||
input.read(&m_header[get_header_len()-m_bytes_needed],
|
||||
m_bytes_needed);
|
||||
|
||||
|
||||
m_bytes_needed -= input.gcount();
|
||||
|
||||
|
||||
if (m_bytes_needed == 0) {
|
||||
process_extended_header();
|
||||
m_state = STATE_READY;
|
||||
@@ -98,7 +98,7 @@ void hybi_header::set_rsv2(bool b) {
|
||||
void hybi_header::set_rsv3(bool b) {
|
||||
set_header_bit(BPB0_RSV3,0,b);
|
||||
}
|
||||
void hybi_header::set_opcode(websocketpp::frame::opcode::value op) {
|
||||
void hybi_header::set_opcode(websocketpp_02::frame::opcode::value op) {
|
||||
m_header[0] &= (0xFF ^ BPB0_OPCODE); // clear op bits
|
||||
m_header[0] |= op; // set op bits
|
||||
}
|
||||
@@ -126,7 +126,7 @@ void hybi_header::set_payload_size(uint64_t size) {
|
||||
}
|
||||
m_payload_size = size;
|
||||
*(reinterpret_cast<uint16_t*>(&m_header[BASIC_HEADER_LENGTH])) = htons(static_cast<uint16_t>(size));
|
||||
|
||||
|
||||
/* uint16_t net_size = htons(static_cast<uint16_t>(size));
|
||||
//memcpy(&m_header[BASIC_HEADER_LENGTH], &net_size, sizeof(uint16_t));
|
||||
std::copy(
|
||||
@@ -148,7 +148,7 @@ void hybi_header::set_payload_size(uint64_t size) {
|
||||
} else {
|
||||
throw processor::exception("set_payload_size called with value that was too large (>2^63)",processor::error::MESSAGE_TOO_BIG);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
void hybi_header::complete() {
|
||||
validate_basic_header();
|
||||
@@ -173,7 +173,7 @@ bool hybi_header::get_rsv2() const {
|
||||
bool hybi_header::get_rsv3() const {
|
||||
return ((m_header[0] & BPB0_RSV3) == BPB0_RSV3);
|
||||
}
|
||||
websocketpp::frame::opcode::value hybi_header::get_opcode() const {
|
||||
websocketpp_02::frame::opcode::value hybi_header::get_opcode() const {
|
||||
return frame::opcode::value(m_header[0] & BPB0_OPCODE);
|
||||
}
|
||||
bool hybi_header::get_masked() const {
|
||||
@@ -196,17 +196,17 @@ bool hybi_header::is_control() const {
|
||||
// private
|
||||
unsigned int hybi_header::get_header_len() const {
|
||||
unsigned int temp = 2;
|
||||
|
||||
|
||||
if (get_masked()) {
|
||||
temp += 4;
|
||||
}
|
||||
|
||||
|
||||
if (get_basic_size() == 126) {
|
||||
temp += 2;
|
||||
} else if (get_basic_size() == 127) {
|
||||
temp += 8;
|
||||
}
|
||||
|
||||
|
||||
return temp;
|
||||
}
|
||||
|
||||
@@ -214,27 +214,27 @@ uint8_t hybi_header::get_basic_size() const {
|
||||
return m_header[1] & BPB1_PAYLOAD;
|
||||
}
|
||||
|
||||
void hybi_header::validate_basic_header() const {
|
||||
void hybi_header::validate_basic_header() const {
|
||||
// check for control frame size
|
||||
if (is_control() && get_basic_size() > frame::limits::PAYLOAD_SIZE_BASIC) {
|
||||
throw processor::exception("Control Frame is too large",processor::error::PROTOCOL_VIOLATION);
|
||||
}
|
||||
|
||||
|
||||
// check for reserved bits
|
||||
if (get_rsv1() || get_rsv2() || get_rsv3()) {
|
||||
throw processor::exception("Reserved bit used",processor::error::PROTOCOL_VIOLATION);
|
||||
}
|
||||
|
||||
|
||||
// check for reserved opcodes
|
||||
if (frame::opcode::reserved(get_opcode())) {
|
||||
throw processor::exception("Reserved opcode used",processor::error::PROTOCOL_VIOLATION);
|
||||
}
|
||||
|
||||
|
||||
// check for invalid opcodes
|
||||
if (frame::opcode::invalid(get_opcode())) {
|
||||
throw processor::exception("Invalid opcode used",processor::error::PROTOCOL_VIOLATION);
|
||||
}
|
||||
|
||||
|
||||
// check for fragmented control message
|
||||
if (is_control() && !get_fin()) {
|
||||
throw processor::exception("Fragmented control message",processor::error::PROTOCOL_VIOLATION);
|
||||
@@ -246,34 +246,34 @@ void hybi_header::process_basic_header() {
|
||||
}
|
||||
void hybi_header::process_extended_header() {
|
||||
uint8_t s = get_basic_size();
|
||||
|
||||
|
||||
if (s <= frame::limits::PAYLOAD_SIZE_BASIC) {
|
||||
m_payload_size = s;
|
||||
} else if (s == BASIC_PAYLOAD_16BIT_CODE) {
|
||||
} else if (s == BASIC_PAYLOAD_16BIT_CODE) {
|
||||
// reinterpret the second two bytes as a 16 bit integer in network
|
||||
// byte order. Convert to host byte order and store locally.
|
||||
m_payload_size = ntohs(*(
|
||||
reinterpret_cast<uint16_t*>(&m_header[BASIC_HEADER_LENGTH])
|
||||
));
|
||||
|
||||
|
||||
if (m_payload_size < s) {
|
||||
std::stringstream err;
|
||||
err << "payload length not minimally encoded. Using 16 bit form for payload size: " << m_payload_size;
|
||||
throw processor::exception(err.str(),processor::error::PROTOCOL_VIOLATION);
|
||||
}
|
||||
|
||||
|
||||
} else if (s == BASIC_PAYLOAD_64BIT_CODE) {
|
||||
// reinterpret the second eight bytes as a 64 bit integer in
|
||||
// reinterpret the second eight bytes as a 64 bit integer in
|
||||
// network byte order. Convert to host byte order and store.
|
||||
m_payload_size = zsutil::ntohll(*(
|
||||
reinterpret_cast<uint64_t*>(&m_header[BASIC_HEADER_LENGTH])
|
||||
));
|
||||
|
||||
|
||||
if (m_payload_size <= frame::limits::PAYLOAD_SIZE_EXTENDED) {
|
||||
throw processor::exception("payload length not minimally encoded",
|
||||
processor::error::PROTOCOL_VIOLATION);
|
||||
}
|
||||
|
||||
|
||||
} else {
|
||||
// TODO: shouldn't be here how to handle?
|
||||
throw processor::exception("invalid get_basic_size in process_extended_header");
|
||||
|
||||
@@ -11,10 +11,10 @@
|
||||
* * 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
|
||||
*
|
||||
* 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;
|
||||
@@ -22,7 +22,7 @@
|
||||
* 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 WEBSOCKET_PROCESSOR_HYBI_HEADER_HPP
|
||||
@@ -30,26 +30,26 @@
|
||||
|
||||
#include "processor.hpp"
|
||||
|
||||
namespace websocketpp {
|
||||
namespace websocketpp_02 {
|
||||
namespace processor {
|
||||
|
||||
/// Describes a processor for reading and writing WebSocket frame headers
|
||||
/**
|
||||
* The hybi_header class provides a processor capable of reading and writing
|
||||
* WebSocket frame headers. It has two writing modes and two reading modes.
|
||||
*
|
||||
*
|
||||
* Writing method 1: call consume() until ready()
|
||||
* Writing method 2: call set_* methods followed by complete()
|
||||
*
|
||||
* Writing methods are valid only when ready() returns false. Use reset() to
|
||||
*
|
||||
* Writing methods are valid only when ready() returns false. Use reset() to
|
||||
* reset the header for writing again. Mixing writing methods between calls to
|
||||
* reset() may behave unpredictably.
|
||||
*
|
||||
*
|
||||
* Reading method 1: call get_header_bytes() to return a string of bytes
|
||||
* Reading method 2: call get_* methods to read individual values
|
||||
*
|
||||
*
|
||||
* Reading methods are valid only when ready() is true.
|
||||
*
|
||||
*
|
||||
* @par Thread Safety
|
||||
* @e Distinct @e objects: Safe.@n
|
||||
* @e Shared @e objects: Unsafe
|
||||
@@ -60,7 +60,7 @@ public:
|
||||
hybi_header();
|
||||
/// Reset a header processor for writing
|
||||
void reset();
|
||||
|
||||
|
||||
// Writing interface (parse a byte stream)
|
||||
// valid only if ready() returns false
|
||||
// Consume will throw a processor::exception in the case that the bytes it
|
||||
@@ -68,7 +68,7 @@ public:
|
||||
void consume(std::istream& input);
|
||||
uint64_t get_bytes_needed() const;
|
||||
bool ready() const;
|
||||
|
||||
|
||||
// Writing interface (set fields directly)
|
||||
// valid only if ready() returns false
|
||||
// set_* may allow invalid values. Call complete() once values are set to
|
||||
@@ -77,17 +77,17 @@ public:
|
||||
void set_rsv1(bool b);
|
||||
void set_rsv2(bool b);
|
||||
void set_rsv3(bool b);
|
||||
void set_opcode(websocketpp::frame::opcode::value op);
|
||||
void set_opcode(websocketpp_02::frame::opcode::value op);
|
||||
void set_masked(bool masked,int32_t key);
|
||||
void set_payload_size(uint64_t size);
|
||||
// Complete will throw a processor::exception in the case that the
|
||||
// Complete will throw a processor::exception in the case that the
|
||||
// combination of values set do not form a valid WebSocket frame header.
|
||||
void complete();
|
||||
|
||||
|
||||
// Reading interface (get string of bytes)
|
||||
// valid only if ready() returns true
|
||||
std::string get_header_bytes() const;
|
||||
|
||||
|
||||
// Reading interface (get fields directly)
|
||||
// valid only if ready() returns true
|
||||
bool get_fin() const;
|
||||
@@ -100,21 +100,21 @@ public:
|
||||
// a masking key of zero is slightly different than no mask at all.
|
||||
int32_t get_masking_key() const;
|
||||
uint64_t get_payload_size() const;
|
||||
|
||||
|
||||
bool is_control() const;
|
||||
private:
|
||||
// general helper functions
|
||||
unsigned int get_header_len() const;
|
||||
uint8_t get_basic_size() const;
|
||||
void validate_basic_header() const;
|
||||
|
||||
|
||||
// helper functions for writing
|
||||
void process_basic_header();
|
||||
void process_extended_header();
|
||||
void set_header_bit(uint8_t bit,int byte,bool value);
|
||||
void set_masking_key(int32_t key);
|
||||
void clear_masking_key();
|
||||
|
||||
|
||||
// basic payload byte flags
|
||||
static const uint8_t BPB0_OPCODE = 0x0F;
|
||||
static const uint8_t BPB0_RSV3 = 0x10;
|
||||
@@ -123,25 +123,25 @@ private:
|
||||
static const uint8_t BPB0_FIN = 0x80;
|
||||
static const uint8_t BPB1_PAYLOAD = 0x7F;
|
||||
static const uint8_t BPB1_MASK = 0x80;
|
||||
|
||||
|
||||
static const uint8_t BASIC_PAYLOAD_16BIT_CODE = 0x7E; // 126
|
||||
static const uint8_t BASIC_PAYLOAD_64BIT_CODE = 0x7F; // 127
|
||||
|
||||
static const unsigned int BASIC_HEADER_LENGTH = 2;
|
||||
|
||||
static const unsigned int BASIC_HEADER_LENGTH = 2;
|
||||
static const unsigned int MAX_HEADER_LENGTH = 14;
|
||||
|
||||
|
||||
static const uint8_t STATE_BASIC_HEADER = 1;
|
||||
static const uint8_t STATE_EXTENDED_HEADER = 2;
|
||||
static const uint8_t STATE_READY = 3;
|
||||
static const uint8_t STATE_WRITE = 4;
|
||||
|
||||
|
||||
uint8_t m_state;
|
||||
std::streamsize m_bytes_needed;
|
||||
uint64_t m_payload_size;
|
||||
char m_header[MAX_HEADER_LENGTH];
|
||||
};
|
||||
|
||||
|
||||
} // namespace processor
|
||||
} // namespace websocketpp
|
||||
} // namespace websocketpp_02
|
||||
|
||||
#endif // WEBSOCKET_PROCESSOR_HYBI_HEADER_HPP
|
||||
|
||||
@@ -11,10 +11,10 @@
|
||||
* * 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
|
||||
*
|
||||
* 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;
|
||||
@@ -22,7 +22,7 @@
|
||||
* 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 WEBSOCKET_PROCESSOR_HYBI_LEGACY_HPP
|
||||
@@ -39,7 +39,7 @@
|
||||
#undef min
|
||||
#endif // #ifdef min
|
||||
|
||||
namespace websocketpp {
|
||||
namespace websocketpp_02 {
|
||||
namespace processor {
|
||||
|
||||
namespace hybi_legacy_state {
|
||||
@@ -53,26 +53,26 @@ namespace hybi_legacy_state {
|
||||
template <class connection_type>
|
||||
class hybi_legacy : public processor_base {
|
||||
public:
|
||||
hybi_legacy(connection_type &connection)
|
||||
hybi_legacy(connection_type &connection)
|
||||
: m_connection(connection),
|
||||
m_state(hybi_legacy_state::INIT)
|
||||
m_state(hybi_legacy_state::INIT)
|
||||
{
|
||||
reset();
|
||||
}
|
||||
|
||||
|
||||
void validate_handshake(const http::parser::request& /*headers*/) const {
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
void handshake_response(const http::parser::request& request,http::parser::response& response) {
|
||||
char key_final[16];
|
||||
|
||||
|
||||
// copy key1 into final key
|
||||
decode_client_key(request.header("Sec-WebSocket-Key1"), &key_final[0]);
|
||||
|
||||
|
||||
// copy key2 into final key
|
||||
decode_client_key(request.header("Sec-WebSocket-Key2"), &key_final[4]);
|
||||
|
||||
|
||||
// copy key3 into final key
|
||||
// key3 should be exactly 8 bytes. If it is more it will be truncated
|
||||
// if it is less the final key will almost certainly be wrong.
|
||||
@@ -82,20 +82,20 @@ public:
|
||||
std::copy(key3.c_str(),
|
||||
key3.c_str()+std::min(static_cast<size_t>(8), key3.size()),
|
||||
&key_final[8]);
|
||||
|
||||
|
||||
m_key3 = md5_hash_string(std::string(key_final,16));
|
||||
|
||||
|
||||
response.add_header("Upgrade","websocket");
|
||||
response.add_header("Connection","Upgrade");
|
||||
|
||||
|
||||
// TODO: require headers that need application specific information?
|
||||
|
||||
|
||||
// Echo back client's origin unless our local application set a
|
||||
// more restrictive one.
|
||||
if (response.header("Sec-WebSocket-Origin") == "") {
|
||||
response.add_header("Sec-WebSocket-Origin",request.header("Origin"));
|
||||
}
|
||||
|
||||
|
||||
// Echo back the client's request host unless our local application
|
||||
// set a different one.
|
||||
if (response.header("Sec-WebSocket-Location") == "") {
|
||||
@@ -104,22 +104,22 @@ public:
|
||||
response.add_header("Sec-WebSocket-Location",uri->str());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
std::string get_origin(const http::parser::request& request) const {
|
||||
return request.header("Origin");
|
||||
}
|
||||
|
||||
|
||||
uri_ptr get_uri(const http::parser::request& request) const {
|
||||
std::string h = request.header("Host");
|
||||
|
||||
|
||||
size_t last_colon = h.rfind(":");
|
||||
size_t last_sbrace = h.rfind("]");
|
||||
|
||||
|
||||
// no : = hostname with no port
|
||||
// last : before ] = ipv6 literal with no port
|
||||
// : with no ] = hostname with port
|
||||
// : after ] = ipv6 literal with port
|
||||
if (last_colon == std::string::npos ||
|
||||
if (last_colon == std::string::npos ||
|
||||
(last_sbrace != std::string::npos && last_sbrace > last_colon))
|
||||
{
|
||||
return uri_ptr(new uri(m_connection.is_secure(),h,request.uri()));
|
||||
@@ -129,10 +129,10 @@ public:
|
||||
h.substr(last_colon+1),
|
||||
request.uri()));
|
||||
}
|
||||
|
||||
|
||||
// TODO: check if get_uri is a full uri
|
||||
}
|
||||
|
||||
|
||||
void consume(std::istream& s) {
|
||||
//unsigned char c;
|
||||
while (s.good() && m_state != hybi_legacy_state::DONE) {
|
||||
@@ -142,91 +142,91 @@ public:
|
||||
//}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool ready() const {
|
||||
return m_state == hybi_legacy_state::DONE;
|
||||
}
|
||||
|
||||
|
||||
// legacy hybi has no control messages.
|
||||
bool is_control() const {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
message::data_ptr get_data_message() {
|
||||
message::data_ptr p = m_data_message;
|
||||
m_data_message.reset();
|
||||
return p;
|
||||
}
|
||||
|
||||
|
||||
message::control_ptr get_control_message() {
|
||||
throw "Hybi legacy has no control messages.";
|
||||
}
|
||||
|
||||
|
||||
void process(std::istream& input) {
|
||||
if (m_state == hybi_legacy_state::INIT) {
|
||||
// we are looking for a 0x00
|
||||
if (input.peek() == 0x00) {
|
||||
// start a message
|
||||
input.ignore();
|
||||
|
||||
|
||||
m_state = hybi_legacy_state::READ;
|
||||
|
||||
|
||||
m_data_message = m_connection.get_data_message();
|
||||
|
||||
|
||||
if (!m_data_message) {
|
||||
throw processor::exception("Out of data messages",processor::error::OUT_OF_MESSAGES);
|
||||
}
|
||||
|
||||
|
||||
m_data_message->reset(frame::opcode::TEXT);
|
||||
} else {
|
||||
input.ignore();
|
||||
// TODO: ignore or error
|
||||
//std::stringstream foo;
|
||||
|
||||
|
||||
//foo << "invalid character read: |" << input.peek() << "|";
|
||||
|
||||
|
||||
std::cout << "invalid character read: |" << input.peek() << "|" << std::endl;
|
||||
|
||||
|
||||
//throw processor::exception(foo.str(),processor::error::PROTOCOL_VIOLATION);
|
||||
}
|
||||
} else if (m_state == hybi_legacy_state::READ) {
|
||||
if (input.peek() == 0xFF) {
|
||||
// end
|
||||
input.ignore();
|
||||
|
||||
|
||||
m_state = hybi_legacy_state::DONE;
|
||||
} else {
|
||||
if (m_data_message) {
|
||||
size_t num;
|
||||
|
||||
|
||||
input.get(m_payload_buffer, PAYLOAD_BUFFER_SIZE, '\xFF');
|
||||
|
||||
|
||||
num = static_cast<size_t>(input.gcount());
|
||||
|
||||
|
||||
if (input.bad()) {
|
||||
throw processor::exception("istream readsome error",
|
||||
processor::error::FATAL_ERROR);
|
||||
}
|
||||
|
||||
|
||||
m_data_message->process_payload(m_payload_buffer,num);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void reset() {
|
||||
m_state = hybi_legacy_state::INIT;
|
||||
m_data_message.reset();
|
||||
}
|
||||
|
||||
|
||||
uint64_t get_bytes_needed() const {
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
std::string get_key3() const {
|
||||
return m_key3;
|
||||
}
|
||||
|
||||
|
||||
// TODO: to factor away
|
||||
binary_string_ptr prepare_frame(frame::opcode::value opcode,
|
||||
bool mask,
|
||||
@@ -235,20 +235,20 @@ public:
|
||||
// TODO: hybi_legacy doesn't allow non-text frames.
|
||||
throw;
|
||||
}
|
||||
|
||||
|
||||
// TODO: mask = ignore?
|
||||
|
||||
|
||||
// TODO: utf8 validation on payload.
|
||||
|
||||
|
||||
binary_string_ptr response(new binary_string(payload.size()+2));
|
||||
|
||||
|
||||
(*response)[0] = 0x00;
|
||||
std::copy(payload.begin(),payload.end(),response->begin()+1);
|
||||
(*response)[response->size()-1] = 0xFF;
|
||||
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
|
||||
binary_string_ptr prepare_frame(frame::opcode::value opcode,
|
||||
bool mask,
|
||||
const utf8_string& payload) {
|
||||
@@ -256,37 +256,37 @@ public:
|
||||
// TODO: hybi_legacy doesn't allow non-text frames.
|
||||
throw;
|
||||
}
|
||||
|
||||
|
||||
// TODO: mask = ignore?
|
||||
|
||||
|
||||
// TODO: utf8 validation on payload.
|
||||
|
||||
|
||||
binary_string_ptr response(new binary_string(payload.size()+2));
|
||||
|
||||
|
||||
(*response)[0] = 0x00;
|
||||
std::copy(payload.begin(),payload.end(),response->begin()+1);
|
||||
(*response)[response->size()-1] = 0xFF;
|
||||
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
|
||||
binary_string_ptr prepare_close_frame(close::status::value code,
|
||||
bool mask,
|
||||
const std::string& reason) {
|
||||
binary_string_ptr response(new binary_string(2));
|
||||
|
||||
|
||||
(*response)[0] = 0xFF;
|
||||
(*response)[1] = 0x00;
|
||||
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
|
||||
void prepare_frame(message::data_ptr msg) {
|
||||
assert(msg);
|
||||
if (msg->get_prepared()) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
msg->set_header(std::string(1,0x00));
|
||||
|
||||
struct Marker
|
||||
@@ -298,7 +298,7 @@ public:
|
||||
char c;
|
||||
unsigned char uc;
|
||||
} v;
|
||||
|
||||
|
||||
v.uc = 0xff;
|
||||
|
||||
value = std::string (1, v.c);
|
||||
@@ -308,10 +308,10 @@ public:
|
||||
};
|
||||
static Marker marker;
|
||||
msg->append_payload(marker.value);
|
||||
|
||||
|
||||
msg->set_prepared(true);
|
||||
}
|
||||
|
||||
|
||||
void prepare_close_frame(message::data_ptr msg,
|
||||
close::status::value /*code*/,
|
||||
const std::string& /*reason*/)
|
||||
@@ -320,9 +320,9 @@ public:
|
||||
if (msg->get_prepared()) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
msg->set_header(std::string());
|
||||
|
||||
|
||||
struct Marker
|
||||
{
|
||||
Marker () { value.uc = 0xff; }
|
||||
@@ -337,16 +337,16 @@ public:
|
||||
val.append(1,marker.value.c);
|
||||
val.append(1,0x00);
|
||||
msg->set_payload(val);
|
||||
|
||||
|
||||
msg->set_prepared(true);
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
void decode_client_key(const std::string& key, char* result) {
|
||||
int spaces = 0;
|
||||
std::string digits = "";
|
||||
uint32_t num;
|
||||
|
||||
|
||||
// key2
|
||||
for (size_t i = 0; i < key.size(); i++) {
|
||||
if (key[i] == ' ') {
|
||||
@@ -355,7 +355,7 @@ private:
|
||||
digits += key[i];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
num = atoi(digits.c_str());
|
||||
if (spaces > 0 && num > 0) {
|
||||
num = htonl(num/spaces);
|
||||
@@ -366,22 +366,22 @@ private:
|
||||
std::fill(result,result+4,0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// must be divisible by 8 (some things are hardcoded for 4 and 8 byte word
|
||||
// sizes
|
||||
static const size_t PAYLOAD_BUFFER_SIZE = 512;
|
||||
|
||||
|
||||
connection_type& m_connection;
|
||||
hybi_legacy_state::value m_state;
|
||||
|
||||
|
||||
message::data_ptr m_data_message;
|
||||
|
||||
|
||||
std::string m_key3;
|
||||
|
||||
|
||||
char m_payload_buffer[PAYLOAD_BUFFER_SIZE];
|
||||
};
|
||||
|
||||
|
||||
} // processor
|
||||
} // websocketpp
|
||||
} // websocketpp_02
|
||||
|
||||
#endif // WEBSOCKET_PROCESSOR_HYBI_LEGACY_HPP
|
||||
|
||||
@@ -11,10 +11,10 @@
|
||||
* * 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
|
||||
*
|
||||
* 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;
|
||||
@@ -22,14 +22,14 @@
|
||||
* 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.
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#include "hybi_util.hpp"
|
||||
|
||||
namespace websocketpp {
|
||||
namespace websocketpp_02 {
|
||||
namespace processor {
|
||||
namespace hybi_util {
|
||||
namespace hybi_util {
|
||||
|
||||
size_t prepare_masking_key(const masking_key_type& key) {
|
||||
size_t prepared_key = key.i;
|
||||
@@ -50,11 +50,11 @@ void word_mask_exact(char* data,size_t length,const masking_key_type& key) {
|
||||
size_t prepared_key = prepare_masking_key(key);
|
||||
size_t n = length/sizeof(size_t);
|
||||
size_t* word_data = reinterpret_cast<size_t*>(data);
|
||||
|
||||
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
word_data[i] ^= prepared_key;
|
||||
}
|
||||
|
||||
|
||||
for (size_t i = n*sizeof(size_t); i < length; i++) {
|
||||
data[i] ^= key.c[i%4];
|
||||
}
|
||||
@@ -62,4 +62,4 @@ void word_mask_exact(char* data,size_t length,const masking_key_type& key) {
|
||||
|
||||
} // namespace hybi_util
|
||||
} // namespace processor
|
||||
} // namespace websocketpp
|
||||
} // namespace websocketpp_02
|
||||
|
||||
@@ -11,10 +11,10 @@
|
||||
* * 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
|
||||
*
|
||||
* 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;
|
||||
@@ -22,7 +22,7 @@
|
||||
* 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 WEBSOCKET_HYBI_UTIL_HPP
|
||||
@@ -30,9 +30,9 @@
|
||||
|
||||
#include "../common.hpp"
|
||||
|
||||
namespace websocketpp {
|
||||
namespace websocketpp_02 {
|
||||
namespace processor {
|
||||
namespace hybi_util {
|
||||
namespace hybi_util {
|
||||
|
||||
// type used to store a masking key
|
||||
union masking_key_type {
|
||||
@@ -65,6 +65,6 @@ void word_mask_exact(char* data,size_t length,const masking_key_type& key);
|
||||
|
||||
} // namespace hybi_util
|
||||
} // namespace processor
|
||||
} // namespace websocketpp
|
||||
} // namespace websocketpp_02
|
||||
|
||||
#endif // WEBSOCKET_HYBI_UTIL_HPP
|
||||
|
||||
@@ -11,10 +11,10 @@
|
||||
* * 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
|
||||
*
|
||||
* 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;
|
||||
@@ -22,7 +22,7 @@
|
||||
* 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 WEBSOCKET_PROCESSOR_HPP
|
||||
@@ -31,9 +31,9 @@
|
||||
#include <exception>
|
||||
#include <string>
|
||||
|
||||
namespace websocketpp {
|
||||
namespace websocketpp_02 {
|
||||
namespace processor {
|
||||
|
||||
|
||||
namespace error {
|
||||
enum value {
|
||||
FATAL_ERROR = 0, // force session end
|
||||
@@ -47,27 +47,27 @@ namespace error {
|
||||
}
|
||||
|
||||
class exception : public std::exception {
|
||||
public:
|
||||
public:
|
||||
exception(const std::string& msg,
|
||||
error::value code = error::FATAL_ERROR)
|
||||
error::value code = error::FATAL_ERROR)
|
||||
: m_msg(msg),m_code(code) {}
|
||||
~exception() throw() {}
|
||||
|
||||
|
||||
virtual const char* what() const throw() {
|
||||
return m_msg.c_str();
|
||||
}
|
||||
|
||||
|
||||
error::value code() const throw() {
|
||||
return m_code;
|
||||
}
|
||||
|
||||
|
||||
std::string m_msg;
|
||||
error::value m_code;
|
||||
};
|
||||
|
||||
} // namespace processor
|
||||
} // namespace websocketpp
|
||||
|
||||
} // namespace websocketpp_02
|
||||
|
||||
#include "../http/parser.hpp"
|
||||
#include "../uri.hpp"
|
||||
#include "../websocket_frame.hpp" // TODO: clean up
|
||||
@@ -79,48 +79,48 @@ public:
|
||||
|
||||
#include <iostream>
|
||||
|
||||
namespace websocketpp {
|
||||
namespace websocketpp_02 {
|
||||
namespace processor {
|
||||
|
||||
|
||||
class processor_base : boost::noncopyable {
|
||||
public:
|
||||
virtual ~processor_base() {}
|
||||
// validate client handshake
|
||||
// validate server handshake
|
||||
|
||||
|
||||
// Given a list of HTTP headers determine if the values are sufficient
|
||||
// to start a websocket session. If so begin constructing a response, if not throw a handshake
|
||||
// to start a websocket session. If so begin constructing a response, if not throw a handshake
|
||||
// exception.
|
||||
// validate handshake request
|
||||
virtual void validate_handshake(const http::parser::request& headers) const = 0;
|
||||
|
||||
|
||||
virtual void handshake_response(const http::parser::request& request,http::parser::response& response) = 0;
|
||||
|
||||
|
||||
// Extracts client origin from a handshake request
|
||||
virtual std::string get_origin(const http::parser::request& request) const = 0;
|
||||
// Extracts client uri from a handshake request
|
||||
virtual uri_ptr get_uri(const http::parser::request& request) const = 0;
|
||||
|
||||
|
||||
// consume bytes, throw on exception
|
||||
virtual void consume(std::istream& s) = 0;
|
||||
|
||||
|
||||
// is there a message ready to be dispatched?
|
||||
virtual bool ready() const = 0;
|
||||
virtual bool is_control() const = 0;
|
||||
virtual message::data_ptr get_data_message() = 0;
|
||||
virtual message::control_ptr get_control_message() = 0;
|
||||
virtual void reset() = 0;
|
||||
|
||||
|
||||
virtual uint64_t get_bytes_needed() const = 0;
|
||||
|
||||
|
||||
// Get information about the message that is ready
|
||||
//virtual frame::opcode::value get_opcode() const = 0;
|
||||
|
||||
|
||||
//virtual utf8_string_ptr get_utf8_payload() const = 0;
|
||||
//virtual binary_string_ptr get_binary_payload() const = 0;
|
||||
//virtual close::status::value get_close_code() const = 0;
|
||||
//virtual utf8_string get_close_reason() const = 0;
|
||||
|
||||
|
||||
// TODO: prepare a frame
|
||||
//virtual binary_string_ptr prepare_frame(frame::opcode::value opcode,
|
||||
// bool mask,
|
||||
@@ -132,17 +132,17 @@ public:
|
||||
//virtual binary_string_ptr prepare_close_frame(close::status::value code,
|
||||
// bool mask,
|
||||
// const std::string& reason) = 0;
|
||||
|
||||
|
||||
virtual void prepare_frame(message::data_ptr msg) = 0;
|
||||
virtual void prepare_close_frame(message::data_ptr msg,
|
||||
close::status::value code,
|
||||
const std::string& reason) = 0;
|
||||
|
||||
|
||||
};
|
||||
|
||||
typedef boost::shared_ptr<processor_base> ptr;
|
||||
|
||||
} // namespace processor
|
||||
} // namespace websocketpp
|
||||
} // namespace websocketpp_02
|
||||
|
||||
#endif // WEBSOCKET_PROCESSOR_HPP
|
||||
|
||||
@@ -11,10 +11,10 @@
|
||||
* * 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
|
||||
*
|
||||
* 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;
|
||||
@@ -22,7 +22,7 @@
|
||||
* 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.
|
||||
*
|
||||
*
|
||||
* This Makefile was derived from a similar one included in the libjson project
|
||||
* It's authors were Jonathan Wallace and Bernhard Fluehmann.
|
||||
*/
|
||||
@@ -32,15 +32,15 @@
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
namespace websocketpp {
|
||||
|
||||
namespace websocketpp_02 {
|
||||
|
||||
class blank_rng {
|
||||
public:
|
||||
int32_t gen() {
|
||||
throw "Random Number generation not supported";
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
#endif // BLANK_RNG_HPP
|
||||
|
||||
@@ -11,10 +11,10 @@
|
||||
* * 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
|
||||
*
|
||||
* 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;
|
||||
@@ -22,16 +22,16 @@
|
||||
* 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.
|
||||
*
|
||||
*
|
||||
* This Makefile was derived from a similar one included in the libjson project
|
||||
* It's authors were Jonathan Wallace and Bernhard Fluehmann.
|
||||
*/
|
||||
|
||||
#include "boost_rng.hpp"
|
||||
|
||||
using websocketpp::boost_rng;
|
||||
using websocketpp_02::boost_rng;
|
||||
|
||||
boost_rng::boost_rng() : m_gen(m_rng,
|
||||
boost_rng::boost_rng() : m_gen(m_rng,
|
||||
boost::random::uniform_int_distribution<>(INT32_MIN,INT32_MAX)) {}
|
||||
|
||||
int32_t boost_rng::gen() {
|
||||
|
||||
@@ -11,10 +11,10 @@
|
||||
* * 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
|
||||
*
|
||||
* 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;
|
||||
@@ -22,7 +22,7 @@
|
||||
* 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.
|
||||
*
|
||||
*
|
||||
* This Makefile was derived from a similar one included in the libjson project
|
||||
* It's authors were Jonathan Wallace and Bernhard Fluehmann.
|
||||
*/
|
||||
@@ -38,7 +38,7 @@
|
||||
#include <boost/random.hpp>
|
||||
#include <boost/random/random_device.hpp>
|
||||
|
||||
namespace websocketpp {
|
||||
namespace websocketpp_02 {
|
||||
class boost_rng {
|
||||
public:
|
||||
boost_rng();
|
||||
|
||||
@@ -11,10 +11,10 @@
|
||||
* * 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
|
||||
*
|
||||
* 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;
|
||||
@@ -22,7 +22,7 @@
|
||||
* 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_ROLE_CLIENT_HPP
|
||||
@@ -50,9 +50,9 @@
|
||||
|
||||
using boost::asio::ip::tcp;
|
||||
|
||||
namespace websocketpp {
|
||||
namespace websocketpp_02 {
|
||||
namespace role {
|
||||
|
||||
|
||||
template <class endpoint>
|
||||
class client {
|
||||
public:
|
||||
@@ -62,19 +62,19 @@ public:
|
||||
public:
|
||||
typedef connection<connection_type> type;
|
||||
typedef endpoint endpoint_type;
|
||||
|
||||
|
||||
// client connections are friends with their respective client endpoint
|
||||
friend class client<endpoint>;
|
||||
|
||||
|
||||
// Valid always
|
||||
int get_version() const {
|
||||
return m_version;
|
||||
}
|
||||
|
||||
|
||||
std::string get_origin() const {
|
||||
return m_origin;
|
||||
}
|
||||
|
||||
|
||||
// not sure when valid
|
||||
std::string get_request_header(const std::string& key) const {
|
||||
return m_request.header(key);
|
||||
@@ -82,7 +82,7 @@ public:
|
||||
std::string get_response_header(const std::string& key) const {
|
||||
return m_response.header(key);
|
||||
}
|
||||
|
||||
|
||||
// Valid before connect is called
|
||||
void add_request_header(const std::string& key, const std::string& value) {
|
||||
m_request.add_header(key,value);
|
||||
@@ -93,15 +93,15 @@ public:
|
||||
void remove_request_header(const std::string& key) {
|
||||
m_request.remove_header(key);
|
||||
}
|
||||
|
||||
|
||||
void add_subprotocol(const std::string& value) {
|
||||
m_requested_subprotocols.push_back(value);
|
||||
}
|
||||
|
||||
|
||||
void set_origin(const std::string& value) {
|
||||
m_origin = value;
|
||||
}
|
||||
|
||||
|
||||
// Information about the requested URI
|
||||
// valid only after URIs are loaded
|
||||
// TODO: check m_uri for NULLness
|
||||
@@ -120,49 +120,49 @@ public:
|
||||
std::string get_uri() const {
|
||||
return m_uri->str();
|
||||
}
|
||||
|
||||
|
||||
int32_t rand() {
|
||||
return m_endpoint.rand();
|
||||
}
|
||||
|
||||
|
||||
bool is_server() const {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// should this exist?
|
||||
boost::asio::io_service& get_io_service() {
|
||||
return m_endpoint.get_io_service();
|
||||
}
|
||||
protected:
|
||||
connection(endpoint& e)
|
||||
connection(endpoint& e)
|
||||
: m_endpoint(e),
|
||||
m_connection(static_cast< connection_type& >(*this)),
|
||||
// TODO: version shouldn't be hardcoded
|
||||
m_version(13) {}
|
||||
|
||||
|
||||
void set_uri(uri_ptr u) {
|
||||
m_uri = u;
|
||||
}
|
||||
|
||||
|
||||
void async_init() {
|
||||
m_connection.m_processor = processor::ptr(new processor::hybi<connection_type>(m_connection));
|
||||
|
||||
|
||||
m_connection.get_handler()->on_handshake_init(m_connection.shared_from_this());
|
||||
|
||||
|
||||
write_request();
|
||||
}
|
||||
|
||||
|
||||
void write_request();
|
||||
void handle_write_request(const boost::system::error_code& error);
|
||||
void read_response();
|
||||
void handle_read_response(const boost::system::error_code& error,
|
||||
std::size_t bytes_transferred);
|
||||
|
||||
|
||||
void log_open_result();
|
||||
private:
|
||||
endpoint& m_endpoint;
|
||||
connection_type& m_connection;
|
||||
|
||||
|
||||
int m_version;
|
||||
uri_ptr m_uri;
|
||||
std::string m_origin;
|
||||
@@ -170,41 +170,41 @@ public:
|
||||
std::vector<std::string> m_requested_extensions;
|
||||
std::string m_subprotocol;
|
||||
std::vector<std::string> m_extensions;
|
||||
|
||||
|
||||
std::string m_handshake_key;
|
||||
http::parser::request m_request;
|
||||
http::parser::response m_response;
|
||||
};
|
||||
|
||||
|
||||
// types
|
||||
typedef client<endpoint> type;
|
||||
typedef endpoint endpoint_type;
|
||||
|
||||
|
||||
typedef typename endpoint_traits<endpoint>::connection_type connection_type;
|
||||
typedef typename endpoint_traits<endpoint>::connection_ptr connection_ptr;
|
||||
typedef typename endpoint_traits<endpoint>::handler_ptr handler_ptr;
|
||||
|
||||
|
||||
// handler interface callback class
|
||||
class handler_interface {
|
||||
public:
|
||||
virtual ~handler_interface() {}
|
||||
|
||||
|
||||
// Required
|
||||
virtual void on_open(connection_ptr con) {}
|
||||
virtual void on_close(connection_ptr con) {}
|
||||
virtual void on_fail(connection_ptr con) {}
|
||||
|
||||
|
||||
virtual void on_message(connection_ptr con,message::data_ptr) {}
|
||||
|
||||
|
||||
// Optional
|
||||
virtual void on_handshake_init(connection_ptr con) {}
|
||||
virtual bool on_ping(connection_ptr con,std::string) {return true;}
|
||||
virtual void on_pong(connection_ptr con,std::string) {}
|
||||
virtual void on_pong_timeout(connection_ptr con,std::string) {}
|
||||
|
||||
|
||||
};
|
||||
|
||||
client (boost::asio::io_service& m)
|
||||
|
||||
client (boost::asio::io_service& m)
|
||||
: m_endpoint(static_cast< endpoint_type& >(*this)),
|
||||
m_io_service(m),
|
||||
m_gen(m_rng,
|
||||
@@ -212,12 +212,12 @@ public:
|
||||
(std::numeric_limits<int32_t>::min)(),
|
||||
(std::numeric_limits<int32_t>::max)()
|
||||
)) {}
|
||||
|
||||
|
||||
connection_ptr get_connection(const std::string& u);
|
||||
|
||||
|
||||
connection_ptr connect(const std::string& u);
|
||||
connection_ptr connect(connection_ptr con);
|
||||
|
||||
|
||||
void run(bool perpetual = false);
|
||||
void end_perpetual();
|
||||
void reset();
|
||||
@@ -226,16 +226,16 @@ protected:
|
||||
int32_t rand() {return m_gen();}
|
||||
private:
|
||||
void handle_connect(connection_ptr con, const boost::system::error_code& error);
|
||||
|
||||
|
||||
endpoint_type& m_endpoint;
|
||||
boost::asio::io_service& m_io_service;
|
||||
|
||||
|
||||
boost::random::random_device m_rng;
|
||||
boost::random::variate_generator<
|
||||
boost::random::random_device&,
|
||||
boost::random::uniform_int_distribution<>
|
||||
> m_gen;
|
||||
|
||||
|
||||
boost::shared_ptr<boost::asio::io_service::work> m_idle_worker;
|
||||
};
|
||||
|
||||
@@ -253,41 +253,41 @@ private:
|
||||
* immediately unless you have already called connect() at least once. To get around
|
||||
* this either queue up all connections you want to make before calling run or call
|
||||
* run with perpetual in another thread.
|
||||
*
|
||||
*
|
||||
* Visibility: public
|
||||
* State: Valid from IDLE, an exception is thrown otherwise
|
||||
* Concurrency: callable from any thread
|
||||
*
|
||||
* @param perpetual whether or not to run the endpoint in perpetual mode
|
||||
* @exception websocketpp::exception with code error::INVALID_STATE if called from a state other than IDLE
|
||||
* @exception websocketpp_02::exception with code error::INVALID_STATE if called from a state other than IDLE
|
||||
*/
|
||||
template <class endpoint>
|
||||
void client<endpoint>::run(bool perpetual) {
|
||||
{
|
||||
boost::lock_guard<boost::recursive_mutex> lock(m_endpoint.m_lock);
|
||||
|
||||
|
||||
if (m_endpoint.m_state != endpoint::IDLE) {
|
||||
throw exception("client::run called from invalid state",error::INVALID_STATE);
|
||||
}
|
||||
|
||||
|
||||
if (perpetual) {
|
||||
m_idle_worker = boost::shared_ptr<boost::asio::io_service::work>(
|
||||
new boost::asio::io_service::work(m_io_service)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
m_endpoint.m_state = endpoint::RUNNING;
|
||||
}
|
||||
|
||||
|
||||
// TODO: preliminary support for multi-threaded clients. Finish external
|
||||
// interface once better tested
|
||||
size_t num_threads = 1;
|
||||
|
||||
|
||||
if (num_threads == 1) {
|
||||
m_io_service.run();
|
||||
} else if (num_threads > 1 && num_threads <= MAX_THREAD_POOL_SIZE) {
|
||||
std::vector< boost::shared_ptr<boost::thread> > threads;
|
||||
|
||||
|
||||
for (std::size_t i = 0; i < num_threads; ++i) {
|
||||
boost::shared_ptr<boost::thread> thread(
|
||||
new boost::thread(boost::bind(
|
||||
@@ -297,24 +297,24 @@ void client<endpoint>::run(bool perpetual) {
|
||||
);
|
||||
threads.push_back(thread);
|
||||
}
|
||||
|
||||
|
||||
for (std::size_t i = 0; i < threads.size(); ++i) {
|
||||
threads[i]->join();
|
||||
}
|
||||
} else {
|
||||
throw exception("listen called with invalid num_threads value");
|
||||
}
|
||||
|
||||
|
||||
m_endpoint.m_state = endpoint::STOPPED;
|
||||
}
|
||||
|
||||
/// End the idle work loop that keeps the io_service active
|
||||
/**
|
||||
* Calling end_perpetual on a client endpoint that was started in perpetual mode (via
|
||||
* run(true), will stop the idle work object that prevents the run method from
|
||||
* run(true), will stop the idle work object that prevents the run method from
|
||||
* returning even when there is no work for it to do. Use if you want to gracefully
|
||||
* stop the endpoint. Use stop() to forcibly stop the endpoint.
|
||||
*
|
||||
*
|
||||
* Visibility: public
|
||||
* State: Valid from RUNNING, ignored otherwise
|
||||
* Concurrency: callable from any thread
|
||||
@@ -332,7 +332,7 @@ void client<endpoint>::end_perpetual() {
|
||||
* running out of work. reset() should not be called while the endpoint is running.
|
||||
* Use stop() and/or end_perpetual() first and then reset once one of those methods
|
||||
* has fully stopped the endpoint.
|
||||
*
|
||||
*
|
||||
* Visibility: public
|
||||
* State: Valid from STOPPED, an exception is thrown otherwise
|
||||
* Concurrency: callable from any thread
|
||||
@@ -340,22 +340,22 @@ void client<endpoint>::end_perpetual() {
|
||||
template <class endpoint>
|
||||
void client<endpoint>::reset() {
|
||||
boost::lock_guard<boost::recursive_mutex> lock(m_endpoint.m_lock);
|
||||
|
||||
|
||||
if (m_endpoint.m_state != endpoint::STOPPED) {
|
||||
throw exception("client::reset called from invalid state",error::INVALID_STATE);
|
||||
}
|
||||
|
||||
|
||||
m_io_service.reset();
|
||||
|
||||
|
||||
m_endpoint.m_state = endpoint::IDLE;
|
||||
}
|
||||
|
||||
/// Returns a new connection
|
||||
/// Returns a new connection
|
||||
/**
|
||||
* Creates and returns a pointer to a new connection to the given URI suitable for passing
|
||||
* to connect(). This method allows applying connection specific settings before
|
||||
* to connect(). This method allows applying connection specific settings before
|
||||
* performing the connection.
|
||||
*
|
||||
*
|
||||
* Visibility: public
|
||||
* State: Valid from IDLE or RUNNING, an exception is thrown otherwise
|
||||
* Concurrency: callable from any thread
|
||||
@@ -368,31 +368,31 @@ typename endpoint_traits<endpoint>::connection_ptr
|
||||
client<endpoint>::get_connection(const std::string& u) {
|
||||
try {
|
||||
uri_ptr location(new uri(u));
|
||||
|
||||
|
||||
if (location->get_secure() && !m_endpoint.is_secure()) {
|
||||
throw websocketpp::exception("Endpoint doesn't support secure connections.",
|
||||
websocketpp::error::ENDPOINT_UNSECURE);
|
||||
throw websocketpp_02::exception("Endpoint doesn't support secure connections.",
|
||||
websocketpp_02::error::ENDPOINT_UNSECURE);
|
||||
}
|
||||
|
||||
|
||||
connection_ptr con = m_endpoint.create_connection();
|
||||
|
||||
|
||||
if (!con) {
|
||||
throw websocketpp::exception("get_connection called from invalid state",
|
||||
websocketpp::error::INVALID_STATE);
|
||||
throw websocketpp_02::exception("get_connection called from invalid state",
|
||||
websocketpp_02::error::INVALID_STATE);
|
||||
}
|
||||
|
||||
|
||||
con->set_uri(location);
|
||||
|
||||
|
||||
return con;
|
||||
} catch (uri_exception& e) {
|
||||
throw websocketpp::exception(e.what(),websocketpp::error::INVALID_URI);
|
||||
throw websocketpp_02::exception(e.what(),websocketpp_02::error::INVALID_URI);
|
||||
}
|
||||
}
|
||||
|
||||
/// Begin the connect process for the given connection.
|
||||
/**
|
||||
* Initiates the async connect request for connection con.
|
||||
*
|
||||
*
|
||||
* Visibility: public
|
||||
* State: Valid from IDLE or RUNNING, an exception is thrown otherwise
|
||||
* Concurrency: callable from any thread
|
||||
@@ -404,13 +404,13 @@ template <class endpoint>
|
||||
typename endpoint_traits<endpoint>::connection_ptr
|
||||
client<endpoint>::connect(connection_ptr con) {
|
||||
tcp::resolver resolver(m_io_service);
|
||||
|
||||
|
||||
std::stringstream p;
|
||||
p << con->get_port();
|
||||
|
||||
|
||||
tcp::resolver::query query(con->get_host(),p.str());
|
||||
tcp::resolver::iterator iterator = resolver.resolve(query);
|
||||
|
||||
|
||||
boost::asio::async_connect(
|
||||
con->get_raw_socket(),
|
||||
iterator,
|
||||
@@ -420,8 +420,8 @@ client<endpoint>::connect(connection_ptr con) {
|
||||
con,
|
||||
boost::asio::placeholders::error
|
||||
)
|
||||
);
|
||||
|
||||
);
|
||||
|
||||
return con;
|
||||
}
|
||||
|
||||
@@ -433,18 +433,18 @@ client<endpoint>::connect(const std::string& u) {
|
||||
}
|
||||
|
||||
template <class endpoint>
|
||||
void client<endpoint>::handle_connect(connection_ptr con,
|
||||
void client<endpoint>::handle_connect(connection_ptr con,
|
||||
const boost::system::error_code& error)
|
||||
{
|
||||
if (!error) {
|
||||
m_endpoint.m_alog->at(log::alevel::CONNECT)
|
||||
<< "Successful connection" << log::endl;
|
||||
|
||||
|
||||
con->start();
|
||||
} else {
|
||||
con->m_fail_code = fail::status::SYSTEM;
|
||||
con->m_fail_system = error;
|
||||
|
||||
|
||||
if (error == boost::system::errc::connection_refused) {
|
||||
con->m_fail_reason = "Connection refused";
|
||||
} else if (error == boost::system::errc::operation_canceled) {
|
||||
@@ -458,11 +458,11 @@ void client<endpoint>::handle_connect(connection_ptr con,
|
||||
} else {
|
||||
con->m_fail_reason = "Unknown";
|
||||
}
|
||||
|
||||
m_endpoint.m_elog->at(log::elevel::RERROR)
|
||||
<< "An error occurred while establishing a connection: "
|
||||
|
||||
m_endpoint.m_elog->at(log::elevel::RERROR)
|
||||
<< "An error occurred while establishing a connection: "
|
||||
<< error << " (" << con->m_fail_reason << ")" << log::endl;
|
||||
|
||||
|
||||
con->terminate(false);
|
||||
}
|
||||
}
|
||||
@@ -474,60 +474,60 @@ template <class connection_type>
|
||||
void client<endpoint>::connection<connection_type>::write_request() {
|
||||
boost::lock_guard<boost::recursive_mutex> lock(m_connection.m_lock);
|
||||
// async write to handle_write
|
||||
|
||||
|
||||
m_request.set_method("GET");
|
||||
m_request.set_uri(m_uri->get_resource());
|
||||
m_request.set_version("HTTP/1.1");
|
||||
|
||||
|
||||
m_request.add_header("Upgrade","websocket");
|
||||
m_request.add_header("Connection","Upgrade");
|
||||
m_request.replace_header("Sec-WebSocket-Version","13");
|
||||
|
||||
|
||||
m_request.replace_header("Host",m_uri->get_host_port());
|
||||
|
||||
|
||||
if (m_origin != "") {
|
||||
m_request.replace_header("Origin",m_origin);
|
||||
}
|
||||
|
||||
|
||||
if (m_requested_subprotocols.size() > 0) {
|
||||
std::string vals;
|
||||
std::string sep = "";
|
||||
|
||||
|
||||
std::vector<std::string>::iterator it;
|
||||
for (it = m_requested_subprotocols.begin(); it != m_requested_subprotocols.end(); ++it) {
|
||||
vals += sep + *it;
|
||||
sep = ",";
|
||||
}
|
||||
|
||||
|
||||
m_request.replace_header("Sec-WebSocket-Protocol",vals);
|
||||
}
|
||||
|
||||
|
||||
// Generate client key
|
||||
int32_t raw_key[4];
|
||||
|
||||
|
||||
for (int i = 0; i < 4; i++) {
|
||||
raw_key[i] = this->rand();
|
||||
}
|
||||
|
||||
|
||||
m_handshake_key = base64_encode(reinterpret_cast<unsigned char const*>(raw_key), 16);
|
||||
|
||||
|
||||
m_request.replace_header("Sec-WebSocket-Key",m_handshake_key);
|
||||
|
||||
|
||||
// Unless the user has overridden the user agent, send generic WS++
|
||||
if (m_request.header("User-Agent") == "") {
|
||||
m_request.replace_header("User-Agent",USER_AGENT);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// TODO: generating this raw request involves way too much copying in cases
|
||||
// without string/vector move semantics.
|
||||
shared_const_buffer buffer(m_request.raw());
|
||||
|
||||
|
||||
//std::string raw = m_request.raw();
|
||||
|
||||
|
||||
//m_endpoint.m_alog->at(log::alevel::DEBUG_HANDSHAKE) << raw << log::endl;
|
||||
|
||||
|
||||
boost::asio::async_write(
|
||||
m_connection.get_socket(),
|
||||
//boost::asio::buffer(raw),
|
||||
@@ -547,14 +547,14 @@ void client<endpoint>::connection<connection_type>::handle_write_request(
|
||||
{
|
||||
if (error) {
|
||||
// TODO: detached state?
|
||||
|
||||
m_endpoint.m_elog->at(log::elevel::RERROR)
|
||||
<< "Error writing WebSocket request. code: "
|
||||
|
||||
m_endpoint.m_elog->at(log::elevel::RERROR)
|
||||
<< "Error writing WebSocket request. code: "
|
||||
<< error << log::endl;
|
||||
m_connection.terminate(false);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
read_response();
|
||||
}
|
||||
|
||||
@@ -580,50 +580,50 @@ void client<endpoint>::connection<connection_type>::handle_read_response (
|
||||
const boost::system::error_code& error, std::size_t bytes_transferred)
|
||||
{
|
||||
boost::lock_guard<boost::recursive_mutex> lock(m_connection.m_lock);
|
||||
|
||||
|
||||
// detached check?
|
||||
|
||||
|
||||
if (error) {
|
||||
m_endpoint.m_elog->at(log::elevel::RERROR)
|
||||
<< "Error reading HTTP request. code: " << error << log::endl;
|
||||
m_connection.terminate(false);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
try {
|
||||
std::istream request(&m_connection.buffer());
|
||||
|
||||
|
||||
if (!m_response.parse_complete(request)) {
|
||||
// not a valid HTTP response
|
||||
// TODO: this should be a client error
|
||||
throw http::exception("Could not parse server response.",
|
||||
http::status_code::BAD_REQUEST);
|
||||
}
|
||||
|
||||
m_endpoint.m_alog->at(log::alevel::DEBUG_HANDSHAKE) << m_response.raw()
|
||||
|
||||
m_endpoint.m_alog->at(log::alevel::DEBUG_HANDSHAKE) << m_response.raw()
|
||||
<< log::endl;
|
||||
|
||||
|
||||
// error checking
|
||||
if (m_response.get_status_code() != http::status_code::SWITCHING_PROTOCOLS) {
|
||||
throw http::exception("Server failed to upgrade connection.",
|
||||
m_response.get_status_code(),
|
||||
m_response.get_status_msg());
|
||||
}
|
||||
|
||||
|
||||
std::string h = m_response.header("Upgrade");
|
||||
if (!boost::ifind_first(h,"websocket")) {
|
||||
throw http::exception("Token `websocket` missing from Upgrade header.",
|
||||
m_response.get_status_code(),
|
||||
m_response.get_status_msg());
|
||||
}
|
||||
|
||||
|
||||
h = m_response.header("Connection");
|
||||
if (!boost::ifind_first(h,"upgrade")) {
|
||||
throw http::exception("Token `upgrade` missing from Connection header.",
|
||||
m_response.get_status_code(),
|
||||
m_response.get_status_msg());
|
||||
}
|
||||
|
||||
|
||||
h = m_response.header("Sec-WebSocket-Accept");
|
||||
if (h == "") {
|
||||
throw http::exception("Required Sec-WebSocket-Accept header is missing.",
|
||||
@@ -632,26 +632,26 @@ void client<endpoint>::connection<connection_type>::handle_read_response (
|
||||
} else {
|
||||
std::string server_key = m_handshake_key;
|
||||
server_key += "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
|
||||
|
||||
|
||||
SHA1 sha;
|
||||
uint32_t message_digest[5];
|
||||
|
||||
|
||||
sha.Reset();
|
||||
sha << server_key.c_str();
|
||||
|
||||
|
||||
if (!sha.Result(message_digest)) {
|
||||
m_endpoint.m_elog->at(log::elevel::RERROR)
|
||||
<< "Error computing handshake sha1 hash." << log::endl;
|
||||
// TODO: close behavior
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// convert sha1 hash bytes to network byte order because this sha1
|
||||
// library works on ints rather than bytes
|
||||
for (int i = 0; i < 5; i++) {
|
||||
message_digest[i] = htonl(message_digest[i]);
|
||||
}
|
||||
|
||||
|
||||
server_key = base64_encode(
|
||||
reinterpret_cast<const unsigned char*>(message_digest),20);
|
||||
if (server_key != h) {
|
||||
@@ -661,13 +661,13 @@ void client<endpoint>::connection<connection_type>::handle_read_response (
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
log_open_result();
|
||||
|
||||
|
||||
m_connection.m_state = session::state::OPEN;
|
||||
|
||||
|
||||
m_connection.get_handler()->on_open(m_connection.shared_from_this());
|
||||
|
||||
|
||||
get_io_service().post(
|
||||
m_connection.m_strand.wrap(boost::bind(
|
||||
&connection_type::handle_read_frame,
|
||||
@@ -675,17 +675,17 @@ void client<endpoint>::connection<connection_type>::handle_read_response (
|
||||
boost::system::error_code()
|
||||
))
|
||||
);
|
||||
|
||||
|
||||
//m_connection.handle_read_frame(boost::system::error_code());
|
||||
} catch (const http::exception& e) {
|
||||
m_endpoint.m_elog->at(log::elevel::RERROR)
|
||||
<< "Error processing server handshake. Server HTTP response: "
|
||||
<< e.m_error_msg << " (" << e.m_error_code
|
||||
m_endpoint.m_elog->at(log::elevel::RERROR)
|
||||
<< "Error processing server handshake. Server HTTP response: "
|
||||
<< e.m_error_msg << " (" << e.m_error_code
|
||||
<< ") Local error: " << e.what() << log::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// start session loop
|
||||
}
|
||||
|
||||
@@ -694,18 +694,18 @@ template <class connection_type>
|
||||
void client<endpoint>::connection<connection_type>::log_open_result() {
|
||||
std::stringstream version;
|
||||
version << "v" << m_version << " ";
|
||||
|
||||
|
||||
m_endpoint.m_alog->at(log::alevel::CONNECT)
|
||||
<< (m_version == -1 ? "HTTP" : "WebSocket") << " Connection "
|
||||
<< m_connection.get_raw_socket().remote_endpoint() << " "
|
||||
<< (m_version == -1 ? "" : version.str())
|
||||
<< (get_request_header("Server") == "" ? "NULL" : get_request_header("Server"))
|
||||
<< " " << m_uri->get_resource() << " " << m_response.get_status_code()
|
||||
<< (get_request_header("Server") == "" ? "NULL" : get_request_header("Server"))
|
||||
<< " " << m_uri->get_resource() << " " << m_response.get_status_code()
|
||||
<< log::endl;
|
||||
}
|
||||
|
||||
|
||||
} // namespace role
|
||||
} // namespace websocketpp
|
||||
} // namespace websocketpp_02
|
||||
|
||||
#ifdef _MSC_VER
|
||||
# pragma warning(pop)
|
||||
|
||||
@@ -11,10 +11,10 @@
|
||||
* * 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
|
||||
*
|
||||
* 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;
|
||||
@@ -22,7 +22,7 @@
|
||||
* 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_ROLE_SERVER_HPP
|
||||
@@ -53,7 +53,7 @@
|
||||
# pragma warning(disable:4355)
|
||||
#endif
|
||||
|
||||
namespace websocketpp {
|
||||
namespace websocketpp_02 {
|
||||
|
||||
typedef boost::asio::buffers_iterator<boost::asio::streambuf::const_buffers_type> bufIterator;
|
||||
|
||||
@@ -96,7 +96,7 @@ static inline std::pair<bufIterator, bool> match_header(boost::shared_ptr<std::s
|
||||
|
||||
// Forward declarations
|
||||
template <typename T> struct endpoint_traits;
|
||||
|
||||
|
||||
namespace role {
|
||||
|
||||
template <class endpoint>
|
||||
@@ -108,7 +108,7 @@ public:
|
||||
public:
|
||||
typedef connection<connection_type> type;
|
||||
typedef endpoint endpoint_type;
|
||||
|
||||
|
||||
// Valid always
|
||||
int get_version() const {
|
||||
return m_version;
|
||||
@@ -119,7 +119,7 @@ public:
|
||||
std::string get_origin() const {
|
||||
return m_origin;
|
||||
}
|
||||
|
||||
|
||||
// Information about the requested URI
|
||||
// valid only after URIs are loaded
|
||||
// TODO: check m_uri for NULLness
|
||||
@@ -135,7 +135,7 @@ public:
|
||||
uint16_t get_port() const {
|
||||
return m_uri->get_port();
|
||||
}
|
||||
|
||||
|
||||
// Valid for CONNECTING state
|
||||
void add_response_header(const std::string& key, const std::string& value) {
|
||||
m_response.add_header(key,value);
|
||||
@@ -146,7 +146,7 @@ public:
|
||||
void remove_response_header(const std::string& key) {
|
||||
m_response.remove_header(key);
|
||||
}
|
||||
|
||||
|
||||
const std::vector<std::string>& get_subprotocols() const {
|
||||
return m_requested_subprotocols;
|
||||
}
|
||||
@@ -155,18 +155,18 @@ public:
|
||||
}
|
||||
void select_subprotocol(const std::string& value);
|
||||
void select_extension(const std::string& value);
|
||||
|
||||
|
||||
// Valid if get_version() returns -1 (ie this is an http connection)
|
||||
void set_body(const std::string& value);
|
||||
|
||||
|
||||
int32_t rand() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
bool is_server() const {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// should this exist?
|
||||
boost::asio::io_service& get_io_service() {
|
||||
return m_endpoint.get_io_service();
|
||||
@@ -177,7 +177,7 @@ public:
|
||||
m_connection(static_cast< connection_type& >(*this)),
|
||||
m_version(-1),
|
||||
m_uri() {}
|
||||
|
||||
|
||||
// initializes the websocket connection
|
||||
void async_init();
|
||||
void handle_read_request(boost::shared_ptr<std::string>, const boost::system::error_code& error,
|
||||
@@ -186,12 +186,12 @@ public:
|
||||
std::size_t bytes_transferred);
|
||||
void write_response();
|
||||
void handle_write_response(const boost::system::error_code& error);
|
||||
|
||||
|
||||
void log_open_result();
|
||||
private:
|
||||
endpoint& m_endpoint;
|
||||
connection_type& m_connection;
|
||||
|
||||
|
||||
int m_version;
|
||||
uri_ptr m_uri;
|
||||
std::string m_origin;
|
||||
@@ -199,33 +199,33 @@ public:
|
||||
std::vector<std::string> m_requested_extensions;
|
||||
std::string m_subprotocol;
|
||||
std::vector<std::string> m_extensions;
|
||||
|
||||
|
||||
http::parser::request m_request;
|
||||
http::parser::response m_response;
|
||||
blank_rng m_rng;
|
||||
};
|
||||
|
||||
|
||||
// types
|
||||
typedef server<endpoint> type;
|
||||
typedef endpoint endpoint_type;
|
||||
|
||||
|
||||
typedef typename endpoint_traits<endpoint>::connection_ptr connection_ptr;
|
||||
typedef typename endpoint_traits<endpoint>::handler_ptr handler_ptr;
|
||||
|
||||
|
||||
// handler interface callback base class
|
||||
class handler_interface {
|
||||
public:
|
||||
virtual ~handler_interface() {}
|
||||
|
||||
|
||||
virtual void on_handshake_init(connection_ptr con) {}
|
||||
|
||||
|
||||
virtual void validate(connection_ptr con) {}
|
||||
virtual void on_open(connection_ptr con) {}
|
||||
virtual void on_close(connection_ptr con) {}
|
||||
virtual void on_fail(connection_ptr con) {}
|
||||
|
||||
|
||||
virtual void on_message(connection_ptr con,message::data_ptr) {}
|
||||
|
||||
|
||||
virtual bool on_ping(connection_ptr con,std::string) {return true;}
|
||||
virtual void on_pong(connection_ptr con,std::string) {}
|
||||
virtual void on_pong_timeout(connection_ptr con,std::string) {}
|
||||
@@ -233,8 +233,8 @@ public:
|
||||
|
||||
virtual void on_send_empty(connection_ptr con) {}
|
||||
};
|
||||
|
||||
server(boost::asio::io_service& m)
|
||||
|
||||
server(boost::asio::io_service& m)
|
||||
: m_endpoint(static_cast< endpoint_type& >(*this)),
|
||||
m_io_service(m),
|
||||
// the only way to set an endpoint address family appears to be using
|
||||
@@ -243,15 +243,15 @@ public:
|
||||
m_acceptor(m),
|
||||
m_state(IDLE),
|
||||
m_timer(m,boost::posix_time::seconds(0)) {}
|
||||
|
||||
|
||||
void start_listen(uint16_t port, size_t num_threads = 1);
|
||||
void start_listen(const boost::asio::ip::tcp::endpoint& e, size_t num_threads = 1);
|
||||
// uses internal resolver
|
||||
void start_listen(const std::string &host, const std::string &service, size_t num_threads = 1);
|
||||
|
||||
template <typename InternetProtocol>
|
||||
|
||||
template <typename InternetProtocol>
|
||||
void start_listen(const InternetProtocol &internet_protocol, uint16_t port, size_t num_threads = 1) {
|
||||
m_endpoint.m_alog->at(log::alevel::DEVEL)
|
||||
m_endpoint.m_alog->at(log::alevel::DEVEL)
|
||||
<< "role::server listening on port " << port << log::endl;
|
||||
boost::asio::ip::tcp::endpoint e(internet_protocol, port);
|
||||
start_listen(e,num_threads);
|
||||
@@ -272,7 +272,7 @@ public:
|
||||
start_listen(host,service,num_threads>1 ? num_threads : 0);
|
||||
if(num_threads > 1) stop_listen(true);
|
||||
}
|
||||
template <typename InternetProtocol>
|
||||
template <typename InternetProtocol>
|
||||
void listen(const InternetProtocol &internet_protocol, uint16_t port, size_t num_threads = 1) {
|
||||
start_listen(internet_protocol,port,num_threads>1 ? num_threads : 0);
|
||||
if(num_threads > 1) stop_listen(true);
|
||||
@@ -289,21 +289,21 @@ private:
|
||||
STOPPING = 2,
|
||||
STOPPED = 3
|
||||
};
|
||||
|
||||
|
||||
// start_accept creates a new connection and begins an async_accept on it
|
||||
void start_accept();
|
||||
|
||||
|
||||
// handle_accept will begin the connection's read/write loop and then reset
|
||||
// the server to accept a new connection. Errors returned by async_accept
|
||||
// are logged and ingored.
|
||||
void handle_accept(connection_ptr con,
|
||||
void handle_accept(connection_ptr con,
|
||||
const boost::system::error_code& error);
|
||||
|
||||
|
||||
endpoint_type& m_endpoint;
|
||||
boost::asio::io_service& m_io_service;
|
||||
boost::asio::ip::tcp::acceptor m_acceptor;
|
||||
state m_state;
|
||||
|
||||
|
||||
boost::asio::deadline_timer m_timer;
|
||||
|
||||
std::vector< boost::shared_ptr<std::thread> > m_listening_threads;
|
||||
@@ -313,20 +313,20 @@ template <class endpoint>
|
||||
void server<endpoint>::start_listen(const boost::asio::ip::tcp::endpoint& e,size_t num_threads) {
|
||||
{
|
||||
boost::unique_lock<boost::recursive_mutex> lock(m_endpoint.m_lock);
|
||||
|
||||
|
||||
if (m_state != IDLE) {
|
||||
throw exception("listen called from invalid state.");
|
||||
}
|
||||
|
||||
|
||||
m_acceptor.open(e.protocol());
|
||||
m_acceptor.set_option(boost::asio::socket_base::reuse_address(true));
|
||||
m_acceptor.bind(e);
|
||||
m_acceptor.listen();
|
||||
|
||||
|
||||
this->start_accept();
|
||||
}
|
||||
|
||||
if (num_threads > MAX_THREAD_POOL_SIZE) {
|
||||
|
||||
if (num_threads > MAX_THREAD_POOL_SIZE) {
|
||||
throw exception("listen called with invalid num_threads value");
|
||||
}
|
||||
|
||||
@@ -360,14 +360,14 @@ template <class endpoint>
|
||||
void server<endpoint>::stop_listen(bool join) {
|
||||
{
|
||||
boost::unique_lock<boost::recursive_mutex> lock(m_endpoint.m_lock);
|
||||
|
||||
|
||||
if (m_state != LISTENING) {
|
||||
throw exception("stop_listen called from invalid state");
|
||||
}
|
||||
|
||||
|
||||
m_acceptor.close();
|
||||
}
|
||||
|
||||
|
||||
if(join) {
|
||||
for (std::size_t i = 0; i < m_listening_threads.size(); ++i) {
|
||||
m_listening_threads[i]->join();
|
||||
@@ -400,17 +400,17 @@ void server<endpoint>::start_listen(const std::string &host, const std::string &
|
||||
template <class endpoint>
|
||||
void server<endpoint>::start_accept() {
|
||||
boost::lock_guard<boost::recursive_mutex> lock(m_endpoint.m_lock);
|
||||
|
||||
|
||||
connection_ptr con = m_endpoint.create_connection();
|
||||
|
||||
|
||||
if (con == connection_ptr()) {
|
||||
// the endpoint is no longer capable of accepting new connections.
|
||||
m_endpoint.m_alog->at(log::alevel::CONNECT)
|
||||
<< "Connection refused because endpoint is out of resources or closing."
|
||||
m_endpoint.m_alog->at(log::alevel::CONNECT)
|
||||
<< "Connection refused because endpoint is out of resources or closing."
|
||||
<< log::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
m_acceptor.async_accept(
|
||||
con->get_native_socket (),
|
||||
boost::bind(
|
||||
@@ -426,7 +426,7 @@ void server<endpoint>::start_accept() {
|
||||
// the server to accept a new connection. Errors returned by async_accept
|
||||
// are logged and ingored.
|
||||
template <class endpoint>
|
||||
void server<endpoint>::handle_accept(connection_ptr con,
|
||||
void server<endpoint>::handle_accept(connection_ptr con,
|
||||
const boost::system::error_code& error)
|
||||
{
|
||||
bool delay = false;
|
||||
@@ -475,7 +475,7 @@ void server<endpoint>::handle_accept(connection_ptr con,
|
||||
else
|
||||
this->start_accept();
|
||||
}
|
||||
|
||||
|
||||
// server<endpoint>::connection<connnection_type> Implimentation
|
||||
|
||||
template <class endpoint>
|
||||
@@ -484,17 +484,17 @@ void server<endpoint>::connection<connection_type>::select_subprotocol(
|
||||
const std::string& value)
|
||||
{
|
||||
// TODO: should this be locked?
|
||||
|
||||
|
||||
std::vector<std::string>::iterator it;
|
||||
|
||||
|
||||
it = std::find(m_requested_subprotocols.begin(),
|
||||
m_requested_subprotocols.end(),
|
||||
value);
|
||||
|
||||
|
||||
if (value != "" && it == m_requested_subprotocols.end()) {
|
||||
throw std::invalid_argument("Attempted to choose a subprotocol not proposed by the client");
|
||||
}
|
||||
|
||||
|
||||
m_subprotocol = value;
|
||||
}
|
||||
|
||||
@@ -504,21 +504,21 @@ void server<endpoint>::connection<connection_type>::select_extension(
|
||||
const std::string& value)
|
||||
{
|
||||
// TODO: should this be locked?
|
||||
|
||||
|
||||
if (value == "") {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
std::vector<std::string>::iterator it;
|
||||
|
||||
|
||||
it = std::find(m_requested_extensions.begin(),
|
||||
m_requested_extensions.end(),
|
||||
value);
|
||||
|
||||
|
||||
if (it == m_requested_extensions.end()) {
|
||||
throw std::invalid_argument("Attempted to choose an extension not proposed by the client");
|
||||
}
|
||||
|
||||
|
||||
m_extensions.push_back(value);
|
||||
}
|
||||
|
||||
@@ -529,15 +529,15 @@ void server<endpoint>::connection<connection_type>::set_body(
|
||||
const std::string& value)
|
||||
{
|
||||
// TODO: should this be locked?
|
||||
|
||||
|
||||
if (m_connection.m_version != -1) {
|
||||
// TODO: throw exception
|
||||
throw std::invalid_argument("set_body called from invalid state");
|
||||
}
|
||||
|
||||
|
||||
m_response.set_body(value);
|
||||
}
|
||||
|
||||
|
||||
/// initiates an async read for an HTTP header
|
||||
/**
|
||||
* Thread Safety: locks connection
|
||||
@@ -546,9 +546,9 @@ template <class endpoint>
|
||||
template <class connection_type>
|
||||
void server<endpoint>::connection<connection_type>::async_init() {
|
||||
boost::lock_guard<boost::recursive_mutex> lock(m_connection.m_lock);
|
||||
|
||||
|
||||
m_connection.get_handler()->on_handshake_init(m_connection.shared_from_this());
|
||||
|
||||
|
||||
// TODO: make this value configurable
|
||||
m_connection.register_timeout(5000,fail::status::TIMEOUT_WS,
|
||||
"Timeout on WebSocket handshake");
|
||||
@@ -583,17 +583,17 @@ void server<endpoint>::connection<connection_type>::handle_read_request(
|
||||
{
|
||||
if (error) {
|
||||
// log error
|
||||
m_endpoint.m_elog->at(log::elevel::RERROR)
|
||||
m_endpoint.m_elog->at(log::elevel::RERROR)
|
||||
<< "Error reading HTTP request. code: " << error << log::endl;
|
||||
m_connection.terminate(false);
|
||||
return;
|
||||
}
|
||||
|
||||
m_connection.buffer().consume(header->size());
|
||||
|
||||
|
||||
try {
|
||||
std::istringstream request(*header);
|
||||
|
||||
|
||||
if (!m_request.parse_complete(request)) {
|
||||
// not a valid HTTP request/response
|
||||
if (m_request.method().find("<policy-file-request/>") != std::string::npos)
|
||||
@@ -620,15 +620,15 @@ void server<endpoint>::connection<connection_type>::handle_read_request(
|
||||
}
|
||||
throw http::exception("Received invalid HTTP Request",http::status_code::BAD_REQUEST);
|
||||
}
|
||||
|
||||
// TODO: is there a way to short circuit this or something?
|
||||
|
||||
// TODO: is there a way to short circuit this or something?
|
||||
// This is often useful but slow to generate.
|
||||
//m_endpoint.m_alog.at(log::alevel::DEBUG_HANDSHAKE) << m_request.raw() << log::endl;
|
||||
|
||||
|
||||
std::string h = m_request.header("Upgrade");
|
||||
if (boost::ifind_first(h,"websocket")) {
|
||||
// Version is stored in the Sec-WebSocket-Version header for all
|
||||
// versions after draft Hybi 00/Hixie 76. The absense of a version
|
||||
// Version is stored in the Sec-WebSocket-Version header for all
|
||||
// versions after draft Hybi 00/Hixie 76. The absense of a version
|
||||
// header is assumed to mean Hybi 00.
|
||||
h = m_request.header("Sec-WebSocket-Version");
|
||||
if (h == "") {
|
||||
@@ -639,45 +639,45 @@ void server<endpoint>::connection<connection_type>::handle_read_request(
|
||||
throw(http::exception("Unable to determine connection version",http::status_code::BAD_REQUEST));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Choose an appropriate websocket processor based on the version
|
||||
if (m_version == 0) {
|
||||
m_connection.m_processor = processor::ptr(
|
||||
new processor::hybi_legacy<connection_type>(m_connection)
|
||||
);
|
||||
|
||||
// Hybi legacy requires some extra out of band bookkeeping that
|
||||
|
||||
// Hybi legacy requires some extra out of band bookkeeping that
|
||||
// future versions wont. We need to pull off an additional eight
|
||||
// bytes after the /r/n/r/n and store them somewhere that the
|
||||
// processor can find them.
|
||||
char foo[8];
|
||||
|
||||
|
||||
request.read(foo,8);
|
||||
|
||||
|
||||
if (request.gcount() != 8) {
|
||||
size_t left = 8 - static_cast<size_t>(request.gcount());
|
||||
// This likely occurs because the full key3 wasn't included
|
||||
// in the asio read. It is likely that the extra bytes are
|
||||
// actually on the wire and another asio read would get them
|
||||
// Fixing this will require a way of restarting the
|
||||
// Fixing this will require a way of restarting the
|
||||
// handshake read and storing the existing bytes until that
|
||||
// comes back. Issue #101
|
||||
|
||||
m_endpoint.m_elog->at(log::elevel::RERROR)
|
||||
<< "Short Key 3: " << zsutil::to_hex(std::string(foo))
|
||||
<< " bytes missing: " << left
|
||||
|
||||
m_endpoint.m_elog->at(log::elevel::RERROR)
|
||||
<< "Short Key 3: " << zsutil::to_hex(std::string(foo))
|
||||
<< " bytes missing: " << left
|
||||
<< " eofbit: " << (request.eof() ? "true" : "false")
|
||||
<< " failbit: " << (request.fail() ? "true" : "false")
|
||||
<< " badbit: " << (request.bad() ? "true" : "false")
|
||||
<< " goodbit: " << (request.good() ? "true" : "false")
|
||||
<< log::endl;
|
||||
|
||||
|
||||
throw http::exception("Full Key3 not found in first chop",
|
||||
http::status_code::INTERNAL_SERVER_ERROR);
|
||||
/*m_request.add_header("Sec-WebSocket-Key3",std::string(foo));
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
boost::asio::async_read(
|
||||
m_connection.get_socket(),
|
||||
m_connection.buffer(),
|
||||
@@ -697,16 +697,16 @@ void server<endpoint>::connection<connection_type>::handle_read_request(
|
||||
new processor::hybi<connection_type>(m_connection)
|
||||
);
|
||||
} else {
|
||||
// version does not match any processor we have avaliable. Send
|
||||
// version does not match any processor we have avaliable. Send
|
||||
// an HTTP error and return the versions we do support in a the
|
||||
// appropriate response header.
|
||||
m_response.add_header("Sec-WebSocket-Version","13, 8, 7");
|
||||
|
||||
|
||||
throw(http::exception("Unsupported WebSocket version",http::status_code::BAD_REQUEST));
|
||||
}
|
||||
|
||||
|
||||
m_connection.m_processor->validate_handshake(m_request);
|
||||
|
||||
|
||||
// Extract subprotocols
|
||||
std::string subprotocols = m_request.header("Sec-WebSocket-Protocol");
|
||||
if(subprotocols.length() > 0) {
|
||||
@@ -720,24 +720,24 @@ void server<endpoint>::connection<connection_type>::handle_read_request(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
m_origin = m_connection.m_processor->get_origin(m_request);
|
||||
m_uri = m_connection.m_processor->get_uri(m_request);
|
||||
|
||||
|
||||
m_endpoint.get_handler()->validate(m_connection.shared_from_this());
|
||||
|
||||
|
||||
m_response.set_status(http::status_code::SWITCHING_PROTOCOLS);
|
||||
} else {
|
||||
// should there be a more encapsulated http processor here?
|
||||
m_origin = m_request.header("Origin");
|
||||
|
||||
|
||||
// Set URI
|
||||
std::string h = m_request.header("Host");
|
||||
|
||||
|
||||
size_t last_colon = h.rfind(":");
|
||||
size_t last_sbrace = h.rfind("]");
|
||||
|
||||
if (last_colon == std::string::npos ||
|
||||
|
||||
if (last_colon == std::string::npos ||
|
||||
(last_sbrace != std::string::npos && last_sbrace > last_colon))
|
||||
{
|
||||
// TODO: this makes the assumption that WS and HTTP
|
||||
@@ -749,7 +749,7 @@ void server<endpoint>::connection<connection_type>::handle_read_request(
|
||||
h.substr(last_colon+1),
|
||||
m_request.uri()));
|
||||
}
|
||||
|
||||
|
||||
// continue as HTTP?
|
||||
if (m_endpoint.get_handler()->http(m_connection.shared_from_this()))
|
||||
m_response.set_status(http::status_code::OK);
|
||||
@@ -765,7 +765,7 @@ void server<endpoint>::connection<connection_type>::handle_read_request(
|
||||
m_endpoint.m_elog->at(log::elevel::RERROR) << e.what() << log::endl;
|
||||
m_response.set_status(http::status_code::BAD_REQUEST);
|
||||
}
|
||||
|
||||
|
||||
write_response();
|
||||
}
|
||||
|
||||
@@ -776,48 +776,48 @@ void server<endpoint>::connection<connection_type>::handle_short_key3 (
|
||||
{
|
||||
if (error) {
|
||||
// log error
|
||||
m_endpoint.m_elog->at(log::elevel::RERROR)
|
||||
m_endpoint.m_elog->at(log::elevel::RERROR)
|
||||
<< "Error reading HTTP request. code: " << error << log::endl;
|
||||
m_connection.terminate(false);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
try {
|
||||
std::istream request(&m_connection.buffer());
|
||||
|
||||
|
||||
std::string foo = m_request.header("Sec-WebSocket-Key3");
|
||||
|
||||
|
||||
size_t left = 8-foo.size();
|
||||
|
||||
|
||||
if (left == 0) {
|
||||
// ?????
|
||||
throw http::exception("handle_short_key3 called without short key",
|
||||
http::status_code::INTERNAL_SERVER_ERROR);
|
||||
}
|
||||
|
||||
|
||||
char foo2[9];
|
||||
|
||||
|
||||
request.get(foo2,left);
|
||||
|
||||
|
||||
if (request.gcount() != left) {
|
||||
// ?????
|
||||
throw http::exception("Full Key3 not found",
|
||||
http::status_code::INTERNAL_SERVER_ERROR);
|
||||
}
|
||||
|
||||
m_endpoint.m_elog->at(log::elevel::RERROR)
|
||||
|
||||
m_endpoint.m_elog->at(log::elevel::RERROR)
|
||||
<< "Recovered from Short Key 3: " << left << log::endl;
|
||||
|
||||
|
||||
foo.append(std::string(foo2));
|
||||
|
||||
|
||||
m_request.replace_header("Sec-WebSocket-Key3",foo2);
|
||||
|
||||
|
||||
m_connection.m_processor->validate_handshake(m_request);
|
||||
m_origin = m_connection.m_processor->get_origin(m_request);
|
||||
m_uri = m_connection.m_processor->get_uri(m_request);
|
||||
|
||||
|
||||
m_endpoint.get_handler()->validate(m_connection.shared_from_this());
|
||||
|
||||
|
||||
m_response.set_status(http::status_code::SWITCHING_PROTOCOLS);
|
||||
} catch (const http::exception& e) {
|
||||
m_endpoint.m_elog->at(log::elevel::RERROR) << e.what() << log::endl;
|
||||
@@ -828,7 +828,7 @@ void server<endpoint>::connection<connection_type>::handle_short_key3 (
|
||||
m_endpoint.m_elog->at(log::elevel::RERROR) << e.what() << log::endl;
|
||||
m_response.set_status(http::status_code::BAD_REQUEST);
|
||||
}
|
||||
|
||||
|
||||
write_response();
|
||||
}
|
||||
|
||||
@@ -836,34 +836,34 @@ template <class endpoint>
|
||||
template <class connection_type>
|
||||
void server<endpoint>::connection<connection_type>::write_response() {
|
||||
bool ws_response = true;
|
||||
|
||||
|
||||
m_response.set_version("HTTP/1.1");
|
||||
|
||||
|
||||
if (m_response.get_status_code() == http::status_code::SWITCHING_PROTOCOLS) {
|
||||
// websocket response
|
||||
m_connection.m_processor->handshake_response(m_request,m_response);
|
||||
|
||||
|
||||
if (m_subprotocol != "") {
|
||||
m_response.replace_header("Sec-WebSocket-Protocol",m_subprotocol);
|
||||
}
|
||||
|
||||
|
||||
// TODO: return negotiated extensions
|
||||
} else {
|
||||
// TODO: HTTP response
|
||||
ws_response = false;
|
||||
}
|
||||
|
||||
|
||||
m_response.replace_header("Server",USER_AGENT);
|
||||
|
||||
|
||||
std::string raw = m_response.raw();
|
||||
|
||||
|
||||
// Hack for legacy HyBi
|
||||
if (ws_response && m_version == 0) {
|
||||
raw += boost::dynamic_pointer_cast<processor::hybi_legacy<connection_type> >(m_connection.m_processor)->get_key3();
|
||||
}
|
||||
|
||||
|
||||
shared_const_buffer buffer(raw);
|
||||
|
||||
|
||||
m_endpoint.m_alog->at(log::alevel::DEBUG_HANDSHAKE) << raw << log::endl;
|
||||
|
||||
boost::asio::async_write(
|
||||
@@ -884,37 +884,37 @@ void server<endpoint>::connection<connection_type>::handle_write_response(
|
||||
const boost::system::error_code& error)
|
||||
{
|
||||
if (error) {
|
||||
m_endpoint.m_elog->at(log::elevel::RERROR)
|
||||
<< "Network error writing handshake respons. code: " << error
|
||||
m_endpoint.m_elog->at(log::elevel::RERROR)
|
||||
<< "Network error writing handshake respons. code: " << error
|
||||
<< log::endl;
|
||||
|
||||
|
||||
m_connection.terminate(false);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (m_response.get_status_code() != http::status_code::SWITCHING_PROTOCOLS) {
|
||||
if (m_version == -1) {
|
||||
// if this was not a websocket connection, we have written
|
||||
// if this was not a websocket connection, we have written
|
||||
// the expected response and the connection can be closed.
|
||||
} else {
|
||||
// this was a websocket connection that ended in an error
|
||||
m_endpoint.m_elog->at(log::elevel::RERROR)
|
||||
<< "Handshake ended with HTTP error: "
|
||||
<< m_response.get_status_code() << " "
|
||||
m_endpoint.m_elog->at(log::elevel::RERROR)
|
||||
<< "Handshake ended with HTTP error: "
|
||||
<< m_response.get_status_code() << " "
|
||||
<< m_response.get_status_msg() << log::endl;
|
||||
}
|
||||
m_connection.terminate(true);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
m_connection.cancel_timeout();
|
||||
|
||||
|
||||
log_open_result();
|
||||
|
||||
|
||||
m_connection.m_state = session::state::OPEN;
|
||||
|
||||
|
||||
m_connection.get_handler()->on_open(m_connection.shared_from_this());
|
||||
|
||||
|
||||
get_io_service().post(
|
||||
m_connection.m_strand.wrap(boost::bind(
|
||||
&connection_type::handle_read_frame,
|
||||
@@ -922,7 +922,7 @@ void server<endpoint>::connection<connection_type>::handle_write_response(
|
||||
boost::system::error_code()
|
||||
))
|
||||
);
|
||||
|
||||
|
||||
//m_connection.handle_read_frame(boost::system::error_code());
|
||||
}
|
||||
|
||||
@@ -931,33 +931,33 @@ template <class connection_type>
|
||||
void server<endpoint>::connection<connection_type>::log_open_result() {
|
||||
std::stringstream version;
|
||||
version << "v" << m_version << " ";
|
||||
|
||||
|
||||
std::string remote;
|
||||
boost::system::error_code ec; // FIXME: proxy
|
||||
boost::asio::ip::tcp::endpoint ep = m_connection.get_native_socket().remote_endpoint(ec);
|
||||
if (ec) {
|
||||
m_endpoint.m_elog->at(log::elevel::WARN)
|
||||
m_endpoint.m_elog->at(log::elevel::WARN)
|
||||
<< "Error getting remote endpoint. code: " << ec << log::endl;
|
||||
}
|
||||
|
||||
m_endpoint.m_alog->at(log::alevel::CONNECT)
|
||||
|
||||
m_endpoint.m_alog->at(log::alevel::CONNECT)
|
||||
<< (m_version == -1 ? "HTTP" : "WebSocket") << " Connection ";
|
||||
|
||||
|
||||
if (ec) {
|
||||
m_endpoint.m_alog->at(log::alevel::CONNECT) << "Unknown";
|
||||
} else {
|
||||
m_endpoint.m_alog->at(log::alevel::CONNECT) << ep;
|
||||
}
|
||||
|
||||
|
||||
m_endpoint.m_alog->at(log::alevel::CONNECT) << " "
|
||||
<< (m_version == -1 ? "" : version.str())
|
||||
<< (get_request_header("User-Agent") == "" ? "NULL" : get_request_header("User-Agent"))
|
||||
<< " " << (m_uri ? m_uri->get_resource() : "uri is NULL") << " "
|
||||
<< (get_request_header("User-Agent") == "" ? "NULL" : get_request_header("User-Agent"))
|
||||
<< " " << (m_uri ? m_uri->get_resource() : "uri is NULL") << " "
|
||||
<< m_response.get_status_code() << log::endl;
|
||||
}
|
||||
|
||||
} // namespace role
|
||||
} // namespace websocketpp
|
||||
|
||||
} // namespace role
|
||||
} // namespace websocketpp_02
|
||||
|
||||
#ifdef _MSC_VER
|
||||
# pragma warning(pop)
|
||||
|
||||
@@ -37,10 +37,10 @@
|
||||
*
|
||||
*/
|
||||
|
||||
namespace websocketpp
|
||||
namespace websocketpp_02
|
||||
{
|
||||
|
||||
/*
|
||||
/*
|
||||
* SHA1
|
||||
*
|
||||
* Description:
|
||||
@@ -60,7 +60,7 @@ SHA1::SHA1()
|
||||
Reset();
|
||||
}
|
||||
|
||||
/*
|
||||
/*
|
||||
* ~SHA1
|
||||
*
|
||||
* Description:
|
||||
@@ -80,7 +80,7 @@ SHA1::~SHA1()
|
||||
// The destructor does nothing
|
||||
}
|
||||
|
||||
/*
|
||||
/*
|
||||
* Reset
|
||||
*
|
||||
* Description:
|
||||
@@ -112,7 +112,7 @@ void SHA1::Reset()
|
||||
Corrupted = false;
|
||||
}
|
||||
|
||||
/*
|
||||
/*
|
||||
* Result
|
||||
*
|
||||
* Description:
|
||||
@@ -153,7 +153,7 @@ bool SHA1::Result(unsigned *message_digest_array)
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
/*
|
||||
* Input
|
||||
*
|
||||
* Description:
|
||||
@@ -210,7 +210,7 @@ void SHA1::Input( const unsigned char *message_array,
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
/*
|
||||
* Input
|
||||
*
|
||||
* Description:
|
||||
@@ -236,7 +236,7 @@ void SHA1::Input( const char *message_array,
|
||||
Input((unsigned char *) message_array, length);
|
||||
}
|
||||
|
||||
/*
|
||||
/*
|
||||
* Input
|
||||
*
|
||||
* Description:
|
||||
@@ -257,7 +257,7 @@ void SHA1::Input(unsigned char message_element)
|
||||
Input(&message_element, 1);
|
||||
}
|
||||
|
||||
/*
|
||||
/*
|
||||
* Input
|
||||
*
|
||||
* Description:
|
||||
@@ -278,7 +278,7 @@ void SHA1::Input(char message_element)
|
||||
Input((unsigned char *) &message_element, 1);
|
||||
}
|
||||
|
||||
/*
|
||||
/*
|
||||
* operator<<
|
||||
*
|
||||
* Description:
|
||||
@@ -309,7 +309,7 @@ SHA1& SHA1::operator<<(const char *message_array)
|
||||
return *this;
|
||||
}
|
||||
|
||||
/*
|
||||
/*
|
||||
* operator<<
|
||||
*
|
||||
* Description:
|
||||
@@ -340,7 +340,7 @@ SHA1& SHA1::operator<<(const unsigned char *message_array)
|
||||
return *this;
|
||||
}
|
||||
|
||||
/*
|
||||
/*
|
||||
* operator<<
|
||||
*
|
||||
* Description:
|
||||
@@ -364,7 +364,7 @@ SHA1& SHA1::operator<<(const char message_element)
|
||||
return *this;
|
||||
}
|
||||
|
||||
/*
|
||||
/*
|
||||
* operator<<
|
||||
*
|
||||
* Description:
|
||||
@@ -388,7 +388,7 @@ SHA1& SHA1::operator<<(const unsigned char message_element)
|
||||
return *this;
|
||||
}
|
||||
|
||||
/*
|
||||
/*
|
||||
* ProcessMessageBlock
|
||||
*
|
||||
* Description:
|
||||
@@ -496,7 +496,7 @@ void SHA1::ProcessMessageBlock()
|
||||
Message_Block_Index = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
/*
|
||||
* PadMessage
|
||||
*
|
||||
* Description:
|
||||
@@ -565,7 +565,7 @@ void SHA1::PadMessage()
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
/*
|
||||
* CircularShift
|
||||
*
|
||||
* Description:
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
#ifndef _SHA1_H_
|
||||
#define _SHA1_H_
|
||||
|
||||
namespace websocketpp {
|
||||
namespace websocketpp_02 {
|
||||
|
||||
class SHA1
|
||||
{
|
||||
@@ -84,9 +84,9 @@ class SHA1
|
||||
|
||||
bool Computed; // Is the digest computed?
|
||||
bool Corrupted; // Is the message digest corruped?
|
||||
|
||||
|
||||
};
|
||||
|
||||
} // namespace websocketpp
|
||||
|
||||
} // namespace websocketpp_02
|
||||
|
||||
#endif // _SHA1_H_
|
||||
|
||||
@@ -11,10 +11,10 @@
|
||||
* * 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
|
||||
*
|
||||
* 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;
|
||||
@@ -22,7 +22,7 @@
|
||||
* 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 SHARED_CONST_BUFFER_HPP
|
||||
@@ -35,7 +35,7 @@
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace websocketpp {
|
||||
namespace websocketpp_02 {
|
||||
|
||||
class shared_const_buffer {
|
||||
public:
|
||||
@@ -51,6 +51,6 @@ private:
|
||||
boost::asio::const_buffer m_buffer;
|
||||
};
|
||||
|
||||
} // namespace websocketpp
|
||||
} // namespace websocketpp_02
|
||||
|
||||
#endif // SHARED_CONST_BUFFER_HPP
|
||||
|
||||
@@ -11,10 +11,10 @@
|
||||
* * 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
|
||||
*
|
||||
* 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;
|
||||
@@ -22,7 +22,7 @@
|
||||
* 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_SOCKET_AUTOTLS_HPP
|
||||
@@ -34,7 +34,7 @@
|
||||
|
||||
// Note that AutoSocket.h must be included before this file
|
||||
|
||||
namespace websocketpp {
|
||||
namespace websocketpp_02 {
|
||||
namespace socket {
|
||||
|
||||
template <typename endpoint_type>
|
||||
@@ -43,7 +43,7 @@ public:
|
||||
typedef autotls<endpoint_type> type;
|
||||
typedef AutoSocket autotls_socket;
|
||||
typedef boost::shared_ptr<autotls_socket> autotls_socket_ptr;
|
||||
|
||||
|
||||
// should be private friended
|
||||
boost::asio::io_service& get_io_service() {
|
||||
return m_io_service;
|
||||
@@ -70,7 +70,7 @@ public:
|
||||
virtual bool plain_only() = 0;
|
||||
virtual bool secure_only() = 0;
|
||||
};
|
||||
|
||||
|
||||
// Connection specific details
|
||||
template <typename connection_type>
|
||||
class connection {
|
||||
@@ -79,11 +79,11 @@ public:
|
||||
autotls_socket::lowest_layer_type& get_raw_socket() {
|
||||
return m_socket_ptr->lowest_layer();
|
||||
}
|
||||
|
||||
|
||||
autotls_socket& get_socket() {
|
||||
return *m_socket_ptr;
|
||||
}
|
||||
|
||||
|
||||
bool is_secure() {
|
||||
return m_socket_ptr->isSecure();
|
||||
}
|
||||
@@ -97,7 +97,7 @@ public:
|
||||
connection(autotls<endpoint_type>& e)
|
||||
: m_endpoint(e)
|
||||
, m_connection(static_cast< connection_type& >(*this)) {}
|
||||
|
||||
|
||||
void init() {
|
||||
boost::asio::ssl::context& ssl_context (
|
||||
m_connection.get_handler()->get_ssl_context());
|
||||
@@ -106,17 +106,17 @@ public:
|
||||
m_endpoint.get_io_service(), ssl_context, m_connection.get_handler()->secure_only(),
|
||||
m_connection.get_handler()->plain_only()));
|
||||
}
|
||||
|
||||
|
||||
void async_init(boost::function<void(const boost::system::error_code&)> callback)
|
||||
{
|
||||
m_connection.get_handler()->on_tcp_init();
|
||||
|
||||
|
||||
// wait for TLS handshake
|
||||
// TODO: configurable value
|
||||
m_connection.register_timeout(5000,
|
||||
fail::status::TIMEOUT_TLS,
|
||||
"Timeout on TLS handshake");
|
||||
|
||||
|
||||
m_socket_ptr->async_handshake(
|
||||
m_endpoint.get_handshake_type(),
|
||||
std::bind(
|
||||
@@ -127,17 +127,17 @@ public:
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
void handle_init(socket_init_callback callback,const boost::system::error_code& error) {
|
||||
m_connection.cancel_timeout();
|
||||
callback(error);
|
||||
}
|
||||
|
||||
// note, this function for some reason shouldn't/doesn't need to be
|
||||
|
||||
// note, this function for some reason shouldn't/doesn't need to be
|
||||
// called for plain HTTP connections. not sure why.
|
||||
bool shutdown() {
|
||||
boost::system::error_code ignored_ec;
|
||||
|
||||
|
||||
m_socket_ptr->async_shutdown( // Don't block on connection shutdown DJS
|
||||
std::bind(
|
||||
&autotls<endpoint_type>::handle_shutdown,
|
||||
@@ -145,7 +145,7 @@ public:
|
||||
beast::asio::placeholders::error
|
||||
)
|
||||
);
|
||||
|
||||
|
||||
if (ignored_ec) {
|
||||
return false;
|
||||
} else {
|
||||
@@ -166,8 +166,8 @@ protected:
|
||||
private:
|
||||
boost::asio::io_service& m_io_service;
|
||||
};
|
||||
|
||||
|
||||
} // namespace socket
|
||||
} // namespace websocketpp
|
||||
} // namespace websocketpp_02
|
||||
|
||||
#endif // WEBSOCKETPP_SOCKET_AUTOTLS_HPP
|
||||
|
||||
@@ -11,10 +11,10 @@
|
||||
* * 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
|
||||
*
|
||||
* 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;
|
||||
@@ -22,7 +22,7 @@
|
||||
* 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.
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#error Use Auto TLS only
|
||||
@@ -43,7 +43,7 @@
|
||||
# pragma warning(disable:4355)
|
||||
#endif
|
||||
|
||||
namespace websocketpp {
|
||||
namespace websocketpp_02 {
|
||||
namespace socket {
|
||||
|
||||
template <typename endpoint_type>
|
||||
@@ -52,19 +52,19 @@ public:
|
||||
boost::asio::io_service& get_io_service() {
|
||||
return m_io_service;
|
||||
}
|
||||
|
||||
|
||||
bool is_secure() {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// hooks that this policy adds to handlers of connections that use it
|
||||
class handler_interface {
|
||||
public:
|
||||
virtual ~handler_interface() {}
|
||||
|
||||
|
||||
virtual void on_tcp_init() {};
|
||||
};
|
||||
|
||||
|
||||
// Connection specific details
|
||||
template <typename connection_type>
|
||||
class connection {
|
||||
@@ -73,11 +73,11 @@ public:
|
||||
boost::asio::ip::tcp::socket& get_raw_socket() {
|
||||
return m_socket;
|
||||
}
|
||||
|
||||
|
||||
boost::asio::ip::tcp::socket& get_socket() {
|
||||
return m_socket;
|
||||
}
|
||||
|
||||
|
||||
bool is_secure() {
|
||||
return false;
|
||||
}
|
||||
@@ -85,25 +85,25 @@ public:
|
||||
connection(plain<endpoint_type>& e)
|
||||
: m_socket(e.get_io_service())
|
||||
, m_connection(static_cast< connection_type& >(*this)) {}
|
||||
|
||||
|
||||
void init() {
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
void async_init(socket_init_callback callback) {
|
||||
m_connection.get_handler()->on_tcp_init();
|
||||
|
||||
|
||||
// TODO: make configuration option for NO_DELAY
|
||||
m_socket.set_option(boost::asio::ip::tcp::no_delay(true));
|
||||
|
||||
|
||||
// TODO: should this use post()?
|
||||
callback(boost::system::error_code());
|
||||
}
|
||||
|
||||
|
||||
bool shutdown() {
|
||||
boost::system::error_code ignored_ec;
|
||||
m_socket.shutdown(boost::asio::ip::tcp::socket::shutdown_both,ignored_ec);
|
||||
|
||||
|
||||
if (ignored_ec) {
|
||||
return false;
|
||||
} else {
|
||||
@@ -120,9 +120,9 @@ private:
|
||||
boost::asio::io_service& m_io_service;
|
||||
};
|
||||
|
||||
|
||||
|
||||
} // namespace socket
|
||||
} // namespace websocketpp
|
||||
} // namespace websocketpp_02
|
||||
|
||||
#ifdef _MSC_VER
|
||||
# pragma warning(pop)
|
||||
|
||||
@@ -11,10 +11,10 @@
|
||||
* * 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
|
||||
*
|
||||
* 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;
|
||||
@@ -22,38 +22,38 @@
|
||||
* 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_SOCKET_BASE_HPP
|
||||
#define WEBSOCKETPP_SOCKET_BASE_HPP
|
||||
|
||||
/*
|
||||
|
||||
websocketpp::socket API
|
||||
|
||||
websocketpp_02::socket API
|
||||
endpoint policy that provides:
|
||||
|
||||
|
||||
|
||||
|
||||
nested connection policy called `connection` that provides:
|
||||
- constructor that takes a reference to the endpoint_policy
|
||||
- async_init
|
||||
- async_read_some
|
||||
- async_write_some
|
||||
- get_raw_socket
|
||||
|
||||
|
||||
*/
|
||||
|
||||
#include <boost/system/error_code.hpp>
|
||||
#include <boost/function.hpp>
|
||||
|
||||
namespace websocketpp {
|
||||
namespace websocketpp_02 {
|
||||
namespace socket {
|
||||
|
||||
typedef boost::function<void(const boost::system::error_code&)> socket_init_callback;
|
||||
|
||||
|
||||
} // namespace socket
|
||||
} // namespace websocketpp
|
||||
} // namespace websocketpp_02
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -11,10 +11,10 @@
|
||||
* * 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
|
||||
*
|
||||
* 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;
|
||||
@@ -22,7 +22,7 @@
|
||||
* 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.
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#error Use auto TLS only
|
||||
@@ -39,7 +39,7 @@
|
||||
|
||||
#include <iostream>
|
||||
|
||||
namespace websocketpp {
|
||||
namespace websocketpp_02 {
|
||||
namespace socket {
|
||||
|
||||
template <typename endpoint_type>
|
||||
@@ -48,7 +48,7 @@ public:
|
||||
typedef tls<endpoint_type> type;
|
||||
typedef boost::asio::ssl::stream<boost::asio::ip::tcp::socket> tls_socket;
|
||||
typedef boost::shared_ptr<tls_socket> tls_socket_ptr;
|
||||
|
||||
|
||||
// should be private friended
|
||||
boost::asio::io_service& get_io_service() {
|
||||
return m_io_service;
|
||||
@@ -65,19 +65,19 @@ public:
|
||||
return boost::asio::ssl::stream_base::client;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool is_secure() {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
class handler_interface {
|
||||
public:
|
||||
virtual ~handler_interface() {}
|
||||
|
||||
|
||||
virtual void on_tcp_init() {};
|
||||
virtual boost::asio::ssl::context& on_tls_init() = 0;
|
||||
};
|
||||
|
||||
|
||||
// Connection specific details
|
||||
template <typename connection_type>
|
||||
class connection {
|
||||
@@ -86,11 +86,11 @@ public:
|
||||
tls_socket::lowest_layer_type& get_raw_socket() {
|
||||
return m_socket_ptr->lowest_layer();
|
||||
}
|
||||
|
||||
|
||||
tls_socket& get_socket() {
|
||||
return *m_socket_ptr;
|
||||
}
|
||||
|
||||
|
||||
bool is_secure() {
|
||||
return true;
|
||||
}
|
||||
@@ -98,26 +98,26 @@ public:
|
||||
connection(tls<endpoint_type>& e)
|
||||
: m_endpoint(e)
|
||||
, m_connection(static_cast< connection_type& >(*this)) {}
|
||||
|
||||
|
||||
void init()
|
||||
{
|
||||
boost::asio::ssl::context& ssl_context (
|
||||
m_connection.get_handler()->get_ssl_context ());
|
||||
|
||||
|
||||
m_socket_ptr = tls_socket_ptr (new tls_socket (
|
||||
m_endpoint.get_io_service(), ssl_context));
|
||||
}
|
||||
|
||||
|
||||
void async_init(boost::function<void(const boost::system::error_code&)> callback)
|
||||
{
|
||||
m_connection.get_handler()->on_tcp_init();
|
||||
|
||||
|
||||
// wait for TLS handshake
|
||||
// TODO: configurable value
|
||||
m_connection.register_timeout(5000,
|
||||
fail::status::TIMEOUT_TLS,
|
||||
"Timeout on TLS handshake");
|
||||
|
||||
|
||||
m_socket_ptr->async_handshake(
|
||||
m_endpoint.get_handshake_type(),
|
||||
boost::bind(
|
||||
@@ -128,17 +128,17 @@ public:
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
void handle_init(socket_init_callback callback,const boost::system::error_code& error) {
|
||||
m_connection.cancel_timeout();
|
||||
callback(error);
|
||||
}
|
||||
|
||||
// note, this function for some reason shouldn't/doesn't need to be
|
||||
|
||||
// note, this function for some reason shouldn't/doesn't need to be
|
||||
// called for plain HTTP connections. not sure why.
|
||||
bool shutdown() {
|
||||
boost::system::error_code ignored_ec;
|
||||
|
||||
|
||||
m_socket_ptr->async_shutdown( // Don't block on connection shutdown DJS
|
||||
boost::bind(
|
||||
&tls<endpoint_type>::handle_shutdown,
|
||||
@@ -146,7 +146,7 @@ public:
|
||||
boost::asio::placeholders::error
|
||||
)
|
||||
);
|
||||
|
||||
|
||||
if (ignored_ec) {
|
||||
return false;
|
||||
} else {
|
||||
@@ -165,8 +165,8 @@ private:
|
||||
boost::asio::io_service& m_io_service;
|
||||
tls_socket::handshake_type m_handshake_type;
|
||||
};
|
||||
|
||||
|
||||
} // namespace socket
|
||||
} // namespace websocketpp
|
||||
} // namespace websocketpp_02
|
||||
|
||||
#endif // WEBSOCKETPP_SOCKET_TLS_HPP
|
||||
|
||||
@@ -11,10 +11,10 @@
|
||||
* * 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
|
||||
*
|
||||
* 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;
|
||||
@@ -22,7 +22,7 @@
|
||||
* 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.
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#include "uri.hpp"
|
||||
@@ -32,7 +32,7 @@
|
||||
|
||||
#include <boost/regex.hpp>
|
||||
|
||||
using websocketpp::uri;
|
||||
using websocketpp_02::uri;
|
||||
|
||||
uri::uri(const std::string& uri) {
|
||||
// temporary testing non-regex implimentation.
|
||||
@@ -45,10 +45,10 @@ uri::uri(const std::string& uri) {
|
||||
READ_PORT = 5,
|
||||
READ_RESOURCE = 6,
|
||||
};
|
||||
|
||||
|
||||
state the_state = BEGIN;
|
||||
std::string temp;
|
||||
|
||||
|
||||
for (std::string::const_iterator it = uri.begin(); it != uri.end(); it++) {
|
||||
switch (the_state) {
|
||||
case BEGIN:
|
||||
@@ -56,9 +56,9 @@ uri::uri(const std::string& uri) {
|
||||
if (temp.size() < 6) {
|
||||
temp.append(1,*it);
|
||||
} else {
|
||||
throw websocketpp::uri_exception("Scheme is too long");
|
||||
throw websocketpp_02::uri_exception("Scheme is too long");
|
||||
}
|
||||
|
||||
|
||||
if (temp == "ws://") {
|
||||
m_secure = false;
|
||||
the_state = HOST_BEGIN;
|
||||
@@ -85,11 +85,11 @@ uri::uri(const std::string& uri) {
|
||||
the_state = BEGIN_PORT;
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
if (m_host.size() > 45) {
|
||||
throw websocketpp::uri_exception("IPv6 literal is too long");
|
||||
throw websocketpp_02::uri_exception("IPv6 literal is too long");
|
||||
}
|
||||
|
||||
|
||||
if (*it == '.' ||
|
||||
*it == ':' ||
|
||||
(*it >= '0' && *it <= '9') ||
|
||||
@@ -106,15 +106,15 @@ uri::uri(const std::string& uri) {
|
||||
the_state = BEGIN_PORT;
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
if (*it == '/') {
|
||||
it--;
|
||||
the_state = BEGIN_PORT;
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
// TODO: max url length?
|
||||
|
||||
|
||||
// TODO: check valid characters?
|
||||
if (1) {
|
||||
m_host.append(1,*it);
|
||||
@@ -128,7 +128,7 @@ uri::uri(const std::string& uri) {
|
||||
*it--;
|
||||
the_state = READ_RESOURCE;
|
||||
} else {
|
||||
throw websocketpp::uri_exception("Error parsing WebSocket URI");
|
||||
throw websocketpp_02::uri_exception("Error parsing WebSocket URI");
|
||||
}
|
||||
break;
|
||||
case READ_PORT:
|
||||
@@ -136,30 +136,30 @@ uri::uri(const std::string& uri) {
|
||||
if (temp.size() < 5) {
|
||||
temp.append(1,*it);
|
||||
} else {
|
||||
throw websocketpp::uri_exception("Port is too long");
|
||||
throw websocketpp_02::uri_exception("Port is too long");
|
||||
}
|
||||
} else if (*it == '/') {
|
||||
m_port = get_port_from_string(temp);
|
||||
temp.clear();
|
||||
*it--;
|
||||
the_state = READ_RESOURCE;
|
||||
|
||||
|
||||
} else {
|
||||
throw websocketpp::uri_exception("Error parsing WebSocket URI");
|
||||
throw websocketpp_02::uri_exception("Error parsing WebSocket URI");
|
||||
}
|
||||
break;
|
||||
case READ_RESOURCE:
|
||||
// max length check?
|
||||
|
||||
|
||||
if (*it == '#') {
|
||||
throw websocketpp::uri_exception("WebSocket URIs cannot have fragments");
|
||||
throw websocketpp_02::uri_exception("WebSocket URIs cannot have fragments");
|
||||
} else {
|
||||
m_resource.append(1,*it);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
switch (the_state) {
|
||||
case READ_PORT:
|
||||
m_port = get_port_from_string(temp);
|
||||
@@ -167,65 +167,65 @@ uri::uri(const std::string& uri) {
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
if (m_resource == "") {
|
||||
m_resource = "/";
|
||||
}*/
|
||||
|
||||
|
||||
|
||||
|
||||
boost::cmatch matches;
|
||||
const boost::regex expression("(ws|wss)://([^/:\\[]+|\\[[0-9a-fA-F:.]+\\])(:\\d{1,5})?(/[^#]*)?");
|
||||
|
||||
|
||||
// TODO: should this split resource into path/query?
|
||||
|
||||
|
||||
if (boost::regex_match(uri.c_str(), matches, expression)) {
|
||||
m_secure = (matches[1] == "wss");
|
||||
m_host = matches[2];
|
||||
|
||||
|
||||
// strip brackets from IPv6 literal URIs
|
||||
if (m_host[0] == '[') {
|
||||
m_host = m_host.substr(1,m_host.size()-2);
|
||||
}
|
||||
|
||||
|
||||
std::string port(matches[3]);
|
||||
|
||||
|
||||
if (port != "") {
|
||||
// strip off the :
|
||||
// this could probably be done with a better regex.
|
||||
port = port.substr(1);
|
||||
}
|
||||
|
||||
|
||||
m_port = get_port_from_string(port);
|
||||
|
||||
|
||||
m_resource = matches[4];
|
||||
|
||||
|
||||
if (m_resource == "") {
|
||||
m_resource = "/";
|
||||
}
|
||||
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
throw websocketpp::uri_exception("Error parsing WebSocket URI");
|
||||
|
||||
|
||||
throw websocketpp_02::uri_exception("Error parsing WebSocket URI");
|
||||
|
||||
}
|
||||
|
||||
uri::uri(bool secure, const std::string& host, uint16_t port, const std::string& resource)
|
||||
uri::uri(bool secure, const std::string& host, uint16_t port, const std::string& resource)
|
||||
: m_secure(secure),
|
||||
m_host(host),
|
||||
m_host(host),
|
||||
m_port(port),
|
||||
m_resource(resource == "" ? "/" : resource) {}
|
||||
|
||||
uri::uri(bool secure, const std::string& host, const std::string& resource)
|
||||
uri::uri(bool secure, const std::string& host, const std::string& resource)
|
||||
: m_secure(secure),
|
||||
m_host(host),
|
||||
m_host(host),
|
||||
m_port(m_secure ? URI_DEFAULT_SECURE_PORT : URI_DEFAULT_PORT),
|
||||
m_resource(resource == "" ? "/" : resource) {}
|
||||
|
||||
uri::uri(bool secure,
|
||||
const std::string& host,
|
||||
const std::string& port,
|
||||
const std::string& resource)
|
||||
uri::uri(bool secure,
|
||||
const std::string& host,
|
||||
const std::string& port,
|
||||
const std::string& resource)
|
||||
: m_secure(secure),
|
||||
m_host(host),
|
||||
m_port(get_port_from_string(port)),
|
||||
@@ -233,24 +233,24 @@ uri::uri(bool secure,
|
||||
|
||||
/* Slightly cleaner C++11 delegated constructor method
|
||||
|
||||
uri::uri(bool secure,
|
||||
const std::string& host,
|
||||
uint16_t port,
|
||||
const std::string& resource)
|
||||
uri::uri(bool secure,
|
||||
const std::string& host,
|
||||
uint16_t port,
|
||||
const std::string& resource)
|
||||
: m_secure(secure),
|
||||
m_host(host),
|
||||
m_host(host),
|
||||
m_port(port),
|
||||
m_resource(resource == "" ? "/" : resource)
|
||||
{
|
||||
if (m_port > 65535) {
|
||||
throw websocketpp::uri_exception("Port must be less than 65535");
|
||||
throw websocketpp_02::uri_exception("Port must be less than 65535");
|
||||
}
|
||||
}
|
||||
|
||||
uri::uri(bool secure,
|
||||
const std::string& host,
|
||||
const std::string& port,
|
||||
const std::string& resource)
|
||||
uri::uri(bool secure,
|
||||
const std::string& host,
|
||||
const std::string& port,
|
||||
const std::string& resource)
|
||||
: uri(secure, host, get_port_from_string(port), resource) {}
|
||||
|
||||
*/
|
||||
@@ -271,7 +271,7 @@ std::string uri::get_host_port() const {
|
||||
p << m_host << ":" << m_port;
|
||||
return p.str();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
uint16_t uri::get_port() const {
|
||||
@@ -290,13 +290,13 @@ std::string uri::get_resource() const {
|
||||
|
||||
std::string uri::str() const {
|
||||
std::stringstream s;
|
||||
|
||||
|
||||
s << "ws" << (m_secure ? "s" : "") << "://" << m_host;
|
||||
|
||||
|
||||
if (m_port != (m_secure ? URI_DEFAULT_SECURE_PORT : URI_DEFAULT_PORT)) {
|
||||
s << ":" << m_port;
|
||||
}
|
||||
|
||||
|
||||
s << m_resource;
|
||||
return s.str();
|
||||
}
|
||||
@@ -305,16 +305,16 @@ uint16_t uri::get_port_from_string(const std::string& port) const {
|
||||
if (port == "") {
|
||||
return (m_secure ? URI_DEFAULT_SECURE_PORT : URI_DEFAULT_PORT);
|
||||
}
|
||||
|
||||
|
||||
unsigned int t_port = atoi(port.c_str());
|
||||
|
||||
|
||||
if (t_port > 65535) {
|
||||
throw websocketpp::uri_exception("Port must be less than 65535");
|
||||
throw websocketpp_02::uri_exception("Port must be less than 65535");
|
||||
}
|
||||
|
||||
|
||||
if (t_port == 0) {
|
||||
throw websocketpp::uri_exception("Error parsing port string: "+port);
|
||||
throw websocketpp_02::uri_exception("Error parsing port string: "+port);
|
||||
}
|
||||
|
||||
|
||||
return static_cast<uint16_t>(t_port);
|
||||
}
|
||||
|
||||
@@ -11,10 +11,10 @@
|
||||
* * 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
|
||||
*
|
||||
* 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;
|
||||
@@ -22,7 +22,7 @@
|
||||
* 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_URI_HPP
|
||||
@@ -32,12 +32,12 @@
|
||||
|
||||
#include <exception>
|
||||
|
||||
namespace websocketpp {
|
||||
namespace websocketpp_02 {
|
||||
|
||||
// WebSocket URI only (not http/etc)
|
||||
// WebSocket URI only (not http/etc)
|
||||
|
||||
class uri_exception : public std::exception {
|
||||
public:
|
||||
public:
|
||||
uri_exception(const std::string& msg) : m_msg(msg) {}
|
||||
~uri_exception() throw() {}
|
||||
|
||||
@@ -58,7 +58,7 @@ public:
|
||||
uri(bool secure, const std::string& host, uint16_t port, const std::string& resource);
|
||||
uri(bool secure, const std::string& host, const std::string& resource);
|
||||
uri(bool secure, const std::string& host, const std::string& port, const std::string& resource);
|
||||
|
||||
|
||||
bool get_secure() const;
|
||||
std::string get_host() const;
|
||||
std::string get_host_port() const;
|
||||
@@ -66,20 +66,20 @@ public:
|
||||
std::string get_port_str() const;
|
||||
std::string get_resource() const;
|
||||
std::string str() const;
|
||||
|
||||
|
||||
// get query?
|
||||
// get fragment
|
||||
|
||||
|
||||
// hi <3
|
||||
|
||||
|
||||
// get the string representation of this URI
|
||||
|
||||
|
||||
//std::string base() const; // is this still needed?
|
||||
|
||||
|
||||
// setter methods set some or all (in the case of parse) based on the input.
|
||||
// These functions throw a uri_exception on failure.
|
||||
/*void set_uri(const std::string& uri);
|
||||
|
||||
|
||||
void set_secure(bool secure);
|
||||
void set_host(const std::string& host);
|
||||
void set_port(uint16_t port);
|
||||
@@ -87,7 +87,7 @@ public:
|
||||
void set_resource(const std::string& resource);*/
|
||||
private:
|
||||
uint16_t get_port_from_string(const std::string& port) const;
|
||||
|
||||
|
||||
bool m_secure;
|
||||
std::string m_host;
|
||||
uint16_t m_port;
|
||||
@@ -96,6 +96,6 @@ private:
|
||||
|
||||
typedef boost::shared_ptr<uri> uri_ptr;
|
||||
|
||||
} // namespace websocketpp
|
||||
} // namespace websocketpp_02
|
||||
|
||||
#endif // WEBSOCKETPP_URI_HPP
|
||||
|
||||
@@ -11,10 +11,10 @@
|
||||
* * 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
|
||||
*
|
||||
* 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;
|
||||
@@ -22,7 +22,7 @@
|
||||
* 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 WEBSOCKET_FRAME_HPP
|
||||
@@ -49,18 +49,18 @@
|
||||
#include <iostream>
|
||||
#include <algorithm>
|
||||
|
||||
namespace websocketpp {
|
||||
namespace websocketpp_02 {
|
||||
namespace frame {
|
||||
|
||||
|
||||
/* policies to abstract out
|
||||
|
||||
|
||||
- random number generation
|
||||
- utf8 validation
|
||||
|
||||
|
||||
rng
|
||||
int32_t gen()
|
||||
|
||||
|
||||
|
||||
|
||||
class boost_random {
|
||||
public:
|
||||
boost_random()
|
||||
@@ -69,9 +69,9 @@ private:
|
||||
boost::random::random_device m_rng;
|
||||
boost::random::variate_generator<boost::random::random_device&,boost::random::uniform_int_distribution<> > m_gen;
|
||||
}
|
||||
|
||||
|
||||
*/
|
||||
|
||||
|
||||
template <class rng_policy>
|
||||
class parser : boost::noncopyable {
|
||||
public:
|
||||
@@ -83,20 +83,20 @@ public:
|
||||
static const uint8_t BPB0_FIN = 0x80;
|
||||
static const uint8_t BPB1_PAYLOAD = 0x7F;
|
||||
static const uint8_t BPB1_MASK = 0x80;
|
||||
|
||||
|
||||
static const uint8_t BASIC_PAYLOAD_16BIT_CODE = 0x7E; // 126
|
||||
static const uint8_t BASIC_PAYLOAD_64BIT_CODE = 0x7F; // 127
|
||||
|
||||
static const unsigned int BASIC_HEADER_LENGTH = 2;
|
||||
|
||||
static const unsigned int BASIC_HEADER_LENGTH = 2;
|
||||
static const unsigned int MAX_HEADER_LENGTH = 14;
|
||||
static const uint8_t extended_header_length = 12;
|
||||
static const uint64_t max_payload_size = 100000000; // 100MB
|
||||
|
||||
|
||||
// create an empty frame for writing into
|
||||
parser(rng_policy& rng) : m_rng(rng) {
|
||||
reset();
|
||||
}
|
||||
|
||||
|
||||
bool ready() const {
|
||||
return (m_state == STATE_READY);
|
||||
}
|
||||
@@ -110,8 +110,8 @@ public:
|
||||
m_payload.clear();
|
||||
std::fill(m_header,m_header+MAX_HEADER_LENGTH,0);
|
||||
}
|
||||
|
||||
// Method invariant: One of the following must always be true even in the case
|
||||
|
||||
// Method invariant: One of the following must always be true even in the case
|
||||
// of exceptions.
|
||||
// - m_bytes_needed > 0
|
||||
// - m-state = STATE_READY
|
||||
@@ -120,23 +120,23 @@ public:
|
||||
switch (m_state) {
|
||||
case STATE_BASIC_HEADER:
|
||||
s.read(&m_header[BASIC_HEADER_LENGTH-m_bytes_needed],m_bytes_needed);
|
||||
|
||||
|
||||
m_bytes_needed -= s.gcount();
|
||||
|
||||
|
||||
if (m_bytes_needed == 0) {
|
||||
process_basic_header();
|
||||
|
||||
|
||||
validate_basic_header();
|
||||
|
||||
|
||||
if (m_bytes_needed > 0) {
|
||||
m_state = STATE_EXTENDED_HEADER;
|
||||
} else {
|
||||
process_extended_header();
|
||||
|
||||
|
||||
if (m_bytes_needed == 0) {
|
||||
m_state = STATE_READY;
|
||||
process_payload();
|
||||
|
||||
|
||||
} else {
|
||||
m_state = STATE_PAYLOAD;
|
||||
}
|
||||
@@ -145,9 +145,9 @@ public:
|
||||
break;
|
||||
case STATE_EXTENDED_HEADER:
|
||||
s.read(&m_header[get_header_len()-m_bytes_needed],m_bytes_needed);
|
||||
|
||||
|
||||
m_bytes_needed -= s.gcount();
|
||||
|
||||
|
||||
if (m_bytes_needed == 0) {
|
||||
process_extended_header();
|
||||
if (m_bytes_needed == 0) {
|
||||
@@ -161,9 +161,9 @@ public:
|
||||
case STATE_PAYLOAD:
|
||||
s.read(reinterpret_cast<char *>(&m_payload[m_payload.size()-m_bytes_needed]),
|
||||
m_bytes_needed);
|
||||
|
||||
|
||||
m_bytes_needed -= s.gcount();
|
||||
|
||||
|
||||
if (m_bytes_needed == 0) {
|
||||
m_state = STATE_READY;
|
||||
process_payload();
|
||||
@@ -174,9 +174,9 @@ public:
|
||||
// of a close frame.
|
||||
do {
|
||||
s.read(reinterpret_cast<char *>(&m_header[0]),1);
|
||||
|
||||
|
||||
//std::cout << std::hex << int(static_cast<unsigned char>(m_header[0])) << " ";
|
||||
|
||||
|
||||
if (int(static_cast<unsigned char>(m_header[0])) == 0x88) {
|
||||
//(BPB0_FIN && CONNECTION_CLOSE)
|
||||
m_bytes_needed--;
|
||||
@@ -184,19 +184,19 @@ public:
|
||||
break;
|
||||
}
|
||||
} while (s.gcount() > 0);
|
||||
|
||||
|
||||
//std::cout << std::endl;
|
||||
|
||||
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
/*if (s.gcount() == 0) {
|
||||
throw frame_error("consume read zero bytes",FERR_FATAL_SESSION_ERROR);
|
||||
}*/
|
||||
} catch (const processor::exception& e) {
|
||||
// After this point all non-close frames must be considered garbage,
|
||||
// After this point all non-close frames must be considered garbage,
|
||||
// including the current one. Reset it and put the reading frame into
|
||||
// a recovery state.
|
||||
if (m_degraded == true) {
|
||||
@@ -205,12 +205,12 @@ public:
|
||||
reset();
|
||||
m_state = STATE_RECOVERY;
|
||||
m_degraded = true;
|
||||
|
||||
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// get pointers to underlying buffers
|
||||
char* get_header() {
|
||||
return m_header;
|
||||
@@ -220,20 +220,20 @@ public:
|
||||
}
|
||||
unsigned int get_header_len() const {
|
||||
unsigned int temp = 2;
|
||||
|
||||
|
||||
if (get_masked()) {
|
||||
temp += 4;
|
||||
}
|
||||
|
||||
|
||||
if (get_basic_size() == 126) {
|
||||
temp += 2;
|
||||
} else if (get_basic_size() == 127) {
|
||||
temp += 8;
|
||||
}
|
||||
|
||||
|
||||
return temp;
|
||||
}
|
||||
|
||||
|
||||
char* get_masking_key() {
|
||||
/*if (m_state != STATE_READY) {
|
||||
std::cout << "throw" << std::endl;
|
||||
@@ -241,7 +241,7 @@ public:
|
||||
}*/
|
||||
return &m_header[get_header_len()-4];
|
||||
}
|
||||
|
||||
|
||||
// get and set header bits
|
||||
bool get_fin() const {
|
||||
return ((m_header[0] & BPB0_FIN) == BPB0_FIN);
|
||||
@@ -253,7 +253,7 @@ public:
|
||||
m_header[0] &= (0xFF ^ BPB0_FIN);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool get_rsv1() const {
|
||||
return ((m_header[0] & BPB0_RSV1) == BPB0_RSV1);
|
||||
}
|
||||
@@ -264,7 +264,7 @@ public:
|
||||
m_header[0] &= (0xFF ^ BPB0_RSV1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool get_rsv2() const {
|
||||
return ((m_header[0] & BPB0_RSV2) == BPB0_RSV2);
|
||||
}
|
||||
@@ -275,7 +275,7 @@ public:
|
||||
m_header[0] &= (0xFF ^ BPB0_RSV2);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool get_rsv3() const {
|
||||
return ((m_header[0] & BPB0_RSV3) == BPB0_RSV3);
|
||||
}
|
||||
@@ -286,7 +286,7 @@ public:
|
||||
m_header[0] &= (0xFF ^ BPB0_RSV3);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
opcode::value get_opcode() const {
|
||||
return frame::opcode::value(m_header[0] & BPB0_OPCODE);
|
||||
}
|
||||
@@ -294,19 +294,19 @@ public:
|
||||
if (opcode::reserved(op)) {
|
||||
throw processor::exception("reserved opcode",processor::error::PROTOCOL_VIOLATION);
|
||||
}
|
||||
|
||||
|
||||
if (opcode::invalid(op)) {
|
||||
throw processor::exception("invalid opcode",processor::error::PROTOCOL_VIOLATION);
|
||||
}
|
||||
|
||||
|
||||
if (is_control() && get_basic_size() > limits::PAYLOAD_SIZE_BASIC) {
|
||||
throw processor::exception("control frames can't have large payloads",processor::error::PROTOCOL_VIOLATION);
|
||||
}
|
||||
|
||||
|
||||
m_header[0] &= (0xFF ^ BPB0_OPCODE); // clear op bits
|
||||
m_header[0] |= op; // set op bits
|
||||
}
|
||||
|
||||
|
||||
bool get_masked() const {
|
||||
return ((m_header[1] & BPB1_MASK) == BPB1_MASK);
|
||||
}
|
||||
@@ -319,7 +319,7 @@ public:
|
||||
clear_masking_key();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
uint8_t get_basic_size() const {
|
||||
return m_header[1] & BPB1_PAYLOAD;
|
||||
}
|
||||
@@ -328,10 +328,10 @@ public:
|
||||
// TODO: how to handle errors like this?
|
||||
throw "attempted to get payload size before reading full header";
|
||||
}
|
||||
|
||||
|
||||
return m_payload.size();
|
||||
}
|
||||
|
||||
|
||||
close::status::value get_close_status() const {
|
||||
if (get_payload_size() == 0) {
|
||||
return close::status::NO_STATUS;
|
||||
@@ -339,9 +339,9 @@ public:
|
||||
char val[2] = { m_payload[0], m_payload[1] };
|
||||
uint16_t code;
|
||||
|
||||
std::copy(val,val+sizeof(code),&code);
|
||||
std::copy(val,val+sizeof(code),&code);
|
||||
code = ntohs(code);
|
||||
|
||||
|
||||
return close::status::value(code);
|
||||
} else {
|
||||
return close::status::PROTOCOL_ERROR;
|
||||
@@ -360,38 +360,38 @@ public:
|
||||
return std::string();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
std::vector<unsigned char> &get_payload() {
|
||||
return m_payload;
|
||||
}
|
||||
|
||||
|
||||
void set_payload(const std::vector<unsigned char>& source) {
|
||||
set_payload_helper(source.size());
|
||||
|
||||
|
||||
std::copy(source.begin(),source.end(),m_payload.begin());
|
||||
}
|
||||
void set_payload(const std::string& source) {
|
||||
set_payload_helper(source.size());
|
||||
|
||||
|
||||
std::copy(source.begin(),source.end(),m_payload.begin());
|
||||
}
|
||||
void set_payload_helper(size_t s) {
|
||||
if (s > max_payload_size) {
|
||||
throw processor::exception("requested payload is over implementation defined limit",processor::error::MESSAGE_TOO_BIG);
|
||||
}
|
||||
|
||||
|
||||
// limits imposed by the websocket spec
|
||||
if (is_control() && s > limits::PAYLOAD_SIZE_BASIC) {
|
||||
throw processor::exception("control frames can't have large payloads",processor::error::PROTOCOL_VIOLATION);
|
||||
}
|
||||
|
||||
|
||||
bool masked = get_masked();
|
||||
|
||||
|
||||
if (s <= limits::PAYLOAD_SIZE_BASIC) {
|
||||
m_header[1] = s;
|
||||
} else if (s <= limits::PAYLOAD_SIZE_EXTENDED) {
|
||||
m_header[1] = BASIC_PAYLOAD_16BIT_CODE;
|
||||
|
||||
|
||||
// this reinterprets the second pair of bytes in m_header as a
|
||||
// 16 bit int and writes the payload size there as an integer
|
||||
// in network byte order
|
||||
@@ -402,14 +402,14 @@ public:
|
||||
} else {
|
||||
throw processor::exception("payload size limit is 63 bits",processor::error::PROTOCOL_VIOLATION);
|
||||
}
|
||||
|
||||
|
||||
if (masked) {
|
||||
m_header[1] |= BPB1_MASK;
|
||||
}
|
||||
|
||||
|
||||
m_payload.resize(s);
|
||||
}
|
||||
|
||||
|
||||
void set_status(close::status::value status,const std::string message = "") {
|
||||
// check for valid statuses
|
||||
if (close::status::invalid(status)) {
|
||||
@@ -417,42 +417,42 @@ public:
|
||||
err << "Status code " << status << " is invalid";
|
||||
throw processor::exception(err.str());
|
||||
}
|
||||
|
||||
|
||||
if (close::status::reserved(status)) {
|
||||
std::stringstream err;
|
||||
err << "Status code " << status << " is reserved";
|
||||
throw processor::exception(err.str());
|
||||
}
|
||||
|
||||
|
||||
m_payload.resize(2+message.size());
|
||||
|
||||
|
||||
char val[2];
|
||||
|
||||
|
||||
*reinterpret_cast<uint16_t*>(&val[0]) = htons(status);
|
||||
|
||||
|
||||
bool masked = get_masked();
|
||||
|
||||
|
||||
m_header[1] = message.size()+2;
|
||||
|
||||
|
||||
if (masked) {
|
||||
m_header[1] |= BPB1_MASK;
|
||||
}
|
||||
|
||||
|
||||
m_payload[0] = val[0];
|
||||
m_payload[1] = val[1];
|
||||
|
||||
|
||||
std::copy(message.begin(),message.end(),m_payload.begin()+2);
|
||||
}
|
||||
|
||||
|
||||
bool is_control() const {
|
||||
return (opcode::is_control(get_opcode()));
|
||||
}
|
||||
|
||||
|
||||
std::string print_frame() const {
|
||||
std::stringstream f;
|
||||
|
||||
|
||||
unsigned int len = get_header_len();
|
||||
|
||||
|
||||
f << "frame: ";
|
||||
// print header
|
||||
for (unsigned int i = 0; i < len; i++) {
|
||||
@@ -469,7 +469,7 @@ public:
|
||||
}
|
||||
return f.str();
|
||||
}
|
||||
|
||||
|
||||
// reads basic header, sets and returns m_header_bits_needed
|
||||
void process_basic_header() {
|
||||
m_bytes_needed = get_header_len() - BASIC_HEADER_LENGTH;
|
||||
@@ -478,43 +478,43 @@ public:
|
||||
uint8_t s = get_basic_size();
|
||||
uint64_t payload_size;
|
||||
int mask_index = BASIC_HEADER_LENGTH;
|
||||
|
||||
|
||||
if (s <= limits::PAYLOAD_SIZE_BASIC) {
|
||||
payload_size = s;
|
||||
} else if (s == BASIC_PAYLOAD_16BIT_CODE) {
|
||||
} else if (s == BASIC_PAYLOAD_16BIT_CODE) {
|
||||
// reinterpret the second two bytes as a 16 bit integer in network
|
||||
// byte order. Convert to host byte order and store locally.
|
||||
payload_size = ntohs(*(
|
||||
reinterpret_cast<uint16_t*>(&m_header[BASIC_HEADER_LENGTH])
|
||||
));
|
||||
|
||||
|
||||
if (payload_size < s) {
|
||||
std::stringstream err;
|
||||
err << "payload length not minimally encoded. Using 16 bit form for payload size: " << payload_size;
|
||||
m_bytes_needed = payload_size;
|
||||
throw processor::exception(err.str(),processor::error::PROTOCOL_VIOLATION);
|
||||
}
|
||||
|
||||
|
||||
mask_index += 2;
|
||||
} else if (s == BASIC_PAYLOAD_64BIT_CODE) {
|
||||
// reinterpret the second eight bytes as a 64 bit integer in
|
||||
// reinterpret the second eight bytes as a 64 bit integer in
|
||||
// network byte order. Convert to host byte order and store.
|
||||
payload_size = zsutil::ntohll(*(
|
||||
reinterpret_cast<uint64_t*>(&m_header[BASIC_HEADER_LENGTH])
|
||||
));
|
||||
|
||||
|
||||
if (payload_size <= limits::PAYLOAD_SIZE_EXTENDED) {
|
||||
m_bytes_needed = payload_size;
|
||||
throw processor::exception("payload length not minimally encoded",
|
||||
processor::error::PROTOCOL_VIOLATION);
|
||||
}
|
||||
|
||||
|
||||
mask_index += 8;
|
||||
} else {
|
||||
// TODO: shouldn't be here how to handle?
|
||||
throw processor::exception("invalid get_basic_size in process_extended_header");
|
||||
}
|
||||
|
||||
|
||||
if (get_masked() == 0) {
|
||||
clear_masking_key();
|
||||
} else {
|
||||
@@ -526,60 +526,60 @@ public:
|
||||
m_masking_key[2] = m_header[mask_index+2];
|
||||
m_masking_key[3] = m_header[mask_index+3];*/
|
||||
}
|
||||
|
||||
|
||||
if (payload_size > max_payload_size) {
|
||||
// TODO: frame/message size limits
|
||||
// TODO: find a way to throw a server error without coupling frame
|
||||
// with server
|
||||
// throw websocketpp::server_error("got frame with payload greater than maximum frame buffer size.");
|
||||
// throw websocketpp_02::server_error("got frame with payload greater than maximum frame buffer size.");
|
||||
throw "Got frame with payload greater than maximum frame buffer size.";
|
||||
}
|
||||
m_payload.resize(payload_size);
|
||||
m_bytes_needed = payload_size;
|
||||
}
|
||||
|
||||
|
||||
void process_payload() {
|
||||
if (get_masked()) {
|
||||
char *masking_key = get_masking_key();
|
||||
|
||||
|
||||
for (uint64_t i = 0; i < m_payload.size(); i++) {
|
||||
m_payload[i] = (m_payload[i] ^ masking_key[i%4]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// experiment with more efficient masking code.
|
||||
void process_payload2() {
|
||||
// unmask payload one byte at a time
|
||||
|
||||
|
||||
//uint64_t key = (*((uint32_t*)m_masking_key;)) << 32;
|
||||
//key += *((uint32_t*)m_masking_key);
|
||||
|
||||
|
||||
// might need to switch byte order
|
||||
/*uint32_t key = *((uint32_t*)m_masking_key);
|
||||
|
||||
|
||||
// 4
|
||||
|
||||
|
||||
uint64_t i = 0;
|
||||
uint64_t s = (m_payload.size() / 4);
|
||||
|
||||
|
||||
std::cout << "s: " << s << std::endl;
|
||||
|
||||
|
||||
// chunks of 4
|
||||
for (i = 0; i < s; i+=4) {
|
||||
((uint32_t*)(&m_payload[0]))[i] = (((uint32_t*)(&m_payload[0]))[i] ^ key);
|
||||
}
|
||||
|
||||
|
||||
// finish the last few
|
||||
for (i = s; i < m_payload.size(); i++) {
|
||||
m_payload[i] = (m_payload[i] ^ m_masking_key[i%4]);
|
||||
}*/
|
||||
}
|
||||
|
||||
|
||||
void validate_utf8(uint32_t* state,uint32_t* codep,size_t offset = 0) const {
|
||||
for (size_t i = offset; i < m_payload.size(); i++) {
|
||||
using utf8_validator::decode;
|
||||
|
||||
|
||||
if (decode(state,codep,m_payload[i]) == utf8_validator::UTF8_REJECT) {
|
||||
throw processor::exception("Invalid UTF-8 Data",processor::error::PAYLOAD_VIOLATION);
|
||||
}
|
||||
@@ -590,23 +590,23 @@ public:
|
||||
if (is_control() && get_basic_size() > limits::PAYLOAD_SIZE_BASIC) {
|
||||
throw processor::exception("Control Frame is too large",processor::error::PROTOCOL_VIOLATION);
|
||||
}
|
||||
|
||||
|
||||
// check for reserved bits
|
||||
if (get_rsv1() || get_rsv2() || get_rsv3()) {
|
||||
throw processor::exception("Reserved bit used",processor::error::PROTOCOL_VIOLATION);
|
||||
}
|
||||
|
||||
|
||||
// check for reserved opcodes
|
||||
if (opcode::reserved(get_opcode())) {
|
||||
throw processor::exception("Reserved opcode used",processor::error::PROTOCOL_VIOLATION);
|
||||
}
|
||||
|
||||
|
||||
// check for fragmented control message
|
||||
if (is_control() && !get_fin()) {
|
||||
throw processor::exception("Fragmented control message",processor::error::PROTOCOL_VIOLATION);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void generate_masking_key() {
|
||||
*(reinterpret_cast<int32_t *>(&m_header[get_header_len()-4])) = m_rng.rand();
|
||||
}
|
||||
@@ -615,21 +615,21 @@ public:
|
||||
// method to not include these byte ranges. Whenever the masking bit is re-
|
||||
// set a new key is generated anyways.
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
static const uint8_t STATE_BASIC_HEADER = 1;
|
||||
static const uint8_t STATE_EXTENDED_HEADER = 2;
|
||||
static const uint8_t STATE_PAYLOAD = 3;
|
||||
static const uint8_t STATE_READY = 4;
|
||||
static const uint8_t STATE_RECOVERY = 5;
|
||||
|
||||
|
||||
uint8_t m_state;
|
||||
uint64_t m_bytes_needed;
|
||||
bool m_degraded;
|
||||
|
||||
|
||||
char m_header[MAX_HEADER_LENGTH];
|
||||
std::vector<unsigned char> m_payload;
|
||||
|
||||
|
||||
rng_policy& m_rng;
|
||||
};
|
||||
|
||||
|
||||
@@ -11,10 +11,10 @@
|
||||
* * 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
|
||||
*
|
||||
* 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;
|
||||
@@ -22,7 +22,7 @@
|
||||
* 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_HPP
|
||||
@@ -31,33 +31,33 @@
|
||||
#include "common.hpp"
|
||||
#include "endpoint.hpp"
|
||||
|
||||
namespace websocketpp {
|
||||
namespace websocketpp_02 {
|
||||
#ifdef WEBSOCKETPP_ROLE_SERVER_HPP
|
||||
#ifdef WEBSOCKETPP_SOCKET_PLAIN_HPP
|
||||
typedef websocketpp::endpoint<websocketpp::role::server,
|
||||
websocketpp::socket::plain> server;
|
||||
typedef websocketpp_02::endpoint<websocketpp_02::role::server,
|
||||
websocketpp_02::socket::plain> server;
|
||||
#endif
|
||||
#ifdef WEBSOCKETPP_SOCKET_TLS_HPP
|
||||
typedef websocketpp::endpoint<websocketpp::role::server,
|
||||
websocketpp::socket::tls> server_tls;
|
||||
typedef websocketpp_02::endpoint<websocketpp_02::role::server,
|
||||
websocketpp_02::socket::tls> server_tls;
|
||||
#endif
|
||||
#ifdef WEBSOCKETPP_SOCKET_AUTOTLS_HPP
|
||||
typedef websocketpp::endpoint<websocketpp::role::server,
|
||||
websocketpp::socket::autotls> server_autotls;
|
||||
typedef websocketpp_02::endpoint<websocketpp_02::role::server,
|
||||
websocketpp_02::socket::autotls> server_autotls;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef WEBSOCKETPP_ROLE_CLIENT_HPP
|
||||
#ifdef WEBSOCKETPP_SOCKET_PLAIN_HPP
|
||||
typedef websocketpp::endpoint<websocketpp::role::client,
|
||||
websocketpp::socket::plain> client;
|
||||
typedef websocketpp_02::endpoint<websocketpp_02::role::client,
|
||||
websocketpp_02::socket::plain> client;
|
||||
#endif
|
||||
#ifdef WEBSOCKETPP_SOCKET_TLS_HPP
|
||||
typedef websocketpp::endpoint<websocketpp::role::client,
|
||||
websocketpp::socket::tls> client_tls;
|
||||
typedef websocketpp_02::endpoint<websocketpp_02::role::client,
|
||||
websocketpp_02::socket::tls> client_tls;
|
||||
#endif
|
||||
#endif
|
||||
} // namespace websocketpp
|
||||
} // namespace websocketpp_02
|
||||
|
||||
#endif // WEBSOCKETPP_HPP
|
||||
|
||||
Reference in New Issue
Block a user