1 parent
16c7200028
commit
19f95f6204
91 files changed
+4561
-2146
No files matched your search
@@ -482,11 +482,11 @@ ServerDBThread::EstablishDBConnection()
|
||||
if (!prepareNick.exec() || !prepareAvatarBlacklist.exec() || !prepareLogin.exec() || !prepareCreateGame.exec()
|
||||
|| !prepareEndGame.exec() || !prepareRelation.exec() || !prepareScore.exec() || !prepareReportAvatar.exec()
|
||||
|| !prepareReportGame.exec() || !prepareAdminPlayer.exec() || !prepareBlockPlayer.exec()) {
|
||||
string tmpError = string(prepareNick.error()) + prepareAvatarBlacklist.error() + prepareLogin.error() + prepareCreateGame.error() +
|
||||
prepareEndGame.error() + prepareRelation.error() + prepareScore.error() + prepareReportAvatar.error() +
|
||||
prepareReportGame.error() + prepareAdminPlayer.error() + prepareBlockPlayer.error();
|
||||
m_connData->conn.disconnect();
|
||||
m_ioService->post(boost::bind(&ServerDBCallback::ConnectFailed, &m_callback,
|
||||
string(prepareNick.error()) + prepareAvatarBlacklist.error() + prepareLogin.error() + prepareCreateGame.error()
|
||||
+ prepareEndGame.error() + prepareRelation.error() + prepareScore.error() + prepareReportAvatar.error()
|
||||
+ prepareReportGame.error() + prepareAdminPlayer.error() + prepareBlockPlayer.error()));
|
||||
m_ioService->post(boost::bind(&ServerDBCallback::ConnectFailed, &m_callback, tmpError));
|
||||
m_permanentError = true;
|
||||
} else {
|
||||
m_ioService->post(boost::bind(&ServerDBCallback::ConnectSuccess, &m_callback));
|
||||
@@ -537,8 +537,9 @@ ServerDBThread::HandleNextQuery()
|
||||
++i;
|
||||
}
|
||||
if (!paramQuery.exec()) {
|
||||
string tmpError = paramQuery.error();
|
||||
m_connData->conn.disconnect();
|
||||
m_ioService->post(boost::bind(&ServerDBCallback::QueryError, &m_callback, paramQuery.error()));
|
||||
m_ioService->post(boost::bind(&ServerDBCallback::QueryError, &m_callback, tmpError));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
|
||||
#ifdef ANDROID
|
||||
#ifndef ANDROID_TEST
|
||||
#include "QtGui/5.2.0/QtGui/qpa/qplatformnativeinterface.h"
|
||||
#include "QtGui/5.7.1/QtGui/qpa/qplatformnativeinterface.h"
|
||||
#include <jni.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -275,6 +275,9 @@ int gameLobbyDialogImpl::exec()
|
||||
registeredUserMode();
|
||||
}
|
||||
|
||||
// Bug #320: https://github.com/pokerth/pokerth/issues/320
|
||||
myChat->refreshIgnoreList();
|
||||
|
||||
#ifdef ANDROID
|
||||
this->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding);
|
||||
#endif
|
||||
|
||||
@@ -69,7 +69,7 @@
|
||||
|
||||
#ifdef ANDROID
|
||||
#ifndef ANDROID_TEST
|
||||
#include "QtGui/5.2.0/QtGui/qpa/qplatformnativeinterface.h"
|
||||
#include "QtGui/5.7.1/QtGui/qpa/qplatformnativeinterface.h"
|
||||
#include <jni.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -156,9 +156,14 @@ void MyAvatarLabel::setPlayerRating(QString playerInfo)
|
||||
std::list<std::string> result;
|
||||
std::string separator="(!#$%)";
|
||||
std::list<std::string>::iterator iterator;
|
||||
|
||||
// Bug #319: https://github.com/pokerth/pokerth/issues/319
|
||||
QString playerName = playerInfoList.at(0);
|
||||
playerName = QUrl::fromPercentEncoding(playerName.toUtf8());
|
||||
|
||||
for(iterator = tipsList.begin(); iterator != tipsList.end(); ++iterator) {
|
||||
tipInfo=QString::fromUtf8(iterator->c_str()).split("(!#$%)", QString::KeepEmptyParts, Qt::CaseSensitive);
|
||||
if(tipInfo.at(0)==playerInfoList.at(0)) {
|
||||
if(tipInfo.at(0)==playerName) {
|
||||
result.push_back(tipInfo.at(0).toUtf8().constData()+separator+tipInfo.at(1).toUtf8().constData()+separator+playerInfoList.at(1).toUtf8().constData()+separator);
|
||||
found=1;
|
||||
} else {
|
||||
@@ -166,7 +171,7 @@ void MyAvatarLabel::setPlayerRating(QString playerInfo)
|
||||
}
|
||||
}
|
||||
if(found==0) {
|
||||
result.push_back(playerInfoList.at(0).toUtf8().constData()+separator+separator+playerInfoList.at(1).toUtf8().constData()+separator);
|
||||
result.push_back(playerName.toUtf8().constData()+separator+separator+playerInfoList.at(1).toUtf8().constData()+separator);
|
||||
}
|
||||
myW->getMyConfig()->writeConfigStringList("PlayerTooltips", result);
|
||||
myW->getMyConfig()->writeBuffer();
|
||||
@@ -224,7 +229,12 @@ void MyAvatarLabel::refreshStars()
|
||||
for(int i=1; i<=5; i++)myW->playerStarsArray[i][seatPlace]->setText("");
|
||||
if(myW->myStartWindow->getSession()->getGameType() == Session::GAME_TYPE_INTERNET && !myW->getSession()->getClientPlayerInfo((*it_c)->getMyUniqueID()).isGuest && (*it_c)->getMyType() != PLAYER_TYPE_COMPUTER) {
|
||||
if((*it_c)->getMyStayOnTableStatus() == true && (*it_c)->getMyName()!="" && seatPlace!=0) {
|
||||
int playerStars=getPlayerRating(QString::fromUtf8((*it_c)->getMyName().c_str()));
|
||||
|
||||
// Bug #319: https://github.com/pokerth/pokerth/issues/319
|
||||
QString playerName = QString::fromUtf8((*it_c)->getMyName().c_str());
|
||||
int playerStars=getPlayerRating(playerName);
|
||||
playerName = QString(QUrl::toPercentEncoding(playerName));
|
||||
|
||||
for(int i=1; i<=5; i++) {
|
||||
myW->playerStarsArray[i][seatPlace]->setText("<a style='color: #"+myW->getMyGameTableStyle()->getRatingStarsColor()+"; "+fontFamily+" font-size: "+fontSize+"px; text-decoration: none;' href='"+QString::fromUtf8((*it_c)->getMyName().c_str())+"\""+QString::number(i)+"'>☆</a>");
|
||||
}
|
||||
|
||||
@@ -61,7 +61,7 @@
|
||||
|
||||
#ifdef ANDROID
|
||||
#ifndef ANDROID_TEST
|
||||
#include "QtGui/5.2.0/QtGui/qpa/qplatformnativeinterface.h"
|
||||
#include "QtGui/5.7.1/QtGui/qpa/qplatformnativeinterface.h"
|
||||
#include <jni.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -312,8 +312,13 @@ void
|
||||
SessionData::CloseWebSocketHandle()
|
||||
{
|
||||
if (m_webData) {
|
||||
#if defined(__GXX_EXPERIMENTAL_CXX0X__) || (__cplusplus >= 201103L) // c++11
|
||||
std::error_code std_ec;
|
||||
m_webData->webSocketServer->close(m_webData->webHandle, websocketpp::close::status::normal, "PokerTH server closed the connection.", std_ec);
|
||||
#else
|
||||
boost::system::error_code ec;
|
||||
m_webData->webSocketServer->close(m_webData->webHandle, websocketpp::close::status::normal, "PokerTH server closed the connection.", ec);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -57,9 +57,14 @@ void
|
||||
WebSendBuffer::AsyncSendNextPacket(boost::shared_ptr<SessionData> session)
|
||||
{
|
||||
if (closeAfterSend) {
|
||||
boost::system::error_code ec;
|
||||
boost::shared_ptr<WebSocketData> webData = session->GetWebData();
|
||||
#if defined(__GXX_EXPERIMENTAL_CXX0X__) || (__cplusplus >= 201103L)
|
||||
std::error_code std_ec;
|
||||
webData->webSocketServer->close(webData->webHandle, websocketpp::close::status::normal, "PokerTH server closed the connection.", std_ec);
|
||||
#else
|
||||
boost::system::error_code ec;
|
||||
webData->webSocketServer->close(webData->webHandle, websocketpp::close::status::normal, "PokerTH server closed the connection.", ec);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -70,10 +75,16 @@ WebSendBuffer::InternalStorePacket(boost::shared_ptr<SessionData> session, boost
|
||||
google::protobuf::uint8 *buf = new google::protobuf::uint8[packetSize];
|
||||
packet->GetMsg()->SerializeWithCachedSizesToArray(buf);
|
||||
|
||||
boost::system::error_code ec;
|
||||
boost::shared_ptr<WebSocketData> webData = session->GetWebData();
|
||||
#if defined(__GXX_EXPERIMENTAL_CXX0X__) || (__cplusplus >= 201103L)
|
||||
std::error_code std_ec;
|
||||
webData->webSocketServer->send(webData->webHandle, string((const char *)buf, packetSize), websocketpp::frame::opcode::BINARY, std_ec);
|
||||
if (std_ec) {
|
||||
#else
|
||||
boost::system::error_code ec;
|
||||
webData->webSocketServer->send(webData->webHandle, string((const char *)buf, packetSize), websocketpp::frame::opcode::BINARY, ec);
|
||||
if (ec) {
|
||||
#endif
|
||||
SetCloseAfterSend();
|
||||
}
|
||||
|
||||
|
||||
@@ -49,9 +49,11 @@ public:
|
||||
virtual void Close();
|
||||
|
||||
protected:
|
||||
|
||||
#if defined(__GXX_EXPERIMENTAL_CXX0X__) || (__cplusplus >= 201103L) // c++11
|
||||
typedef std::map<websocketpp::connection_hdl, boost::weak_ptr<SessionData>, std::owner_less<websocketpp::connection_hdl> > SessionMap;
|
||||
#else
|
||||
typedef std::map<websocketpp::connection_hdl, boost::weak_ptr<SessionData> > SessionMap;
|
||||
|
||||
#endif
|
||||
bool validate(websocketpp::connection_hdl hdl);
|
||||
void on_open(websocketpp::connection_hdl hdl);
|
||||
void on_close(websocketpp::connection_hdl hdl);
|
||||
|
||||
Vendored
+1
-1
@@ -1,6 +1,6 @@
|
||||
Main Library:
|
||||
|
||||
Copyright (c) 2013, Peter Thorson. All rights reserved.
|
||||
Copyright (c) 2014, Peter Thorson. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
+35
-13
@@ -45,6 +45,11 @@ static std::string const base64_chars =
|
||||
"abcdefghijklmnopqrstuvwxyz"
|
||||
"0123456789+/";
|
||||
|
||||
/// Test whether a character is a valid base64 character
|
||||
/**
|
||||
* @param c The character to test
|
||||
* @return true if c is a valid base64 character
|
||||
*/
|
||||
static inline bool is_base64(unsigned char c) {
|
||||
return (c == 43 || // +
|
||||
(c >= 47 && c <= 57) || // /-9
|
||||
@@ -52,17 +57,21 @@ static inline bool is_base64(unsigned char c) {
|
||||
(c >= 97 && c <= 122)); // a-z
|
||||
}
|
||||
|
||||
inline std::string base64_encode(unsigned char const * bytes_to_encode, unsigned
|
||||
int in_len)
|
||||
{
|
||||
/// Encode a char buffer into a base64 string
|
||||
/**
|
||||
* @param input The input data
|
||||
* @param len The length of input in bytes
|
||||
* @return A base64 encoded string representing input
|
||||
*/
|
||||
inline std::string base64_encode(unsigned char const * input, size_t len) {
|
||||
std::string ret;
|
||||
int i = 0;
|
||||
int j = 0;
|
||||
unsigned char char_array_3[3];
|
||||
unsigned char char_array_4[4];
|
||||
|
||||
while (in_len--) {
|
||||
char_array_3[i++] = *(bytes_to_encode++);
|
||||
while (len--) {
|
||||
char_array_3[i++] = *(input++);
|
||||
if (i == 3) {
|
||||
char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
|
||||
char_array_4[1] = ((char_array_3[0] & 0x03) << 4) +
|
||||
@@ -97,25 +106,38 @@ inline std::string base64_encode(unsigned char const * bytes_to_encode, unsigned
|
||||
while((i++ < 3)) {
|
||||
ret += '=';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
return ret;
|
||||
}
|
||||
|
||||
inline std::string base64_encode(std::string const & data) {
|
||||
return base64_encode(reinterpret_cast<const unsigned char *>(data.data()),data.size());
|
||||
/// Encode a string into a base64 string
|
||||
/**
|
||||
* @param input The input data
|
||||
* @return A base64 encoded string representing input
|
||||
*/
|
||||
inline std::string base64_encode(std::string const & input) {
|
||||
return base64_encode(
|
||||
reinterpret_cast<const unsigned char *>(input.data()),
|
||||
input.size()
|
||||
);
|
||||
}
|
||||
|
||||
inline std::string base64_decode(std::string const & encoded_string) {
|
||||
size_t in_len = encoded_string.size();
|
||||
/// Decode a base64 encoded string into a string of raw bytes
|
||||
/**
|
||||
* @param input The base64 encoded input data
|
||||
* @return A string representing the decoded raw bytes
|
||||
*/
|
||||
inline std::string base64_decode(std::string const & input) {
|
||||
size_t in_len = input.size();
|
||||
int i = 0;
|
||||
int j = 0;
|
||||
int in_ = 0;
|
||||
unsigned char char_array_4[4], char_array_3[3];
|
||||
std::string ret;
|
||||
|
||||
while (in_len-- && ( encoded_string[in_] != '=') && is_base64(encoded_string[in_])) {
|
||||
char_array_4[i++] = encoded_string[in_]; in_++;
|
||||
while (in_len-- && ( input[in_] != '=') && is_base64(input[in_])) {
|
||||
char_array_4[i++] = input[in_]; in_++;
|
||||
if (i ==4) {
|
||||
for (i = 0; i <4; i++) {
|
||||
char_array_4[i] = static_cast<unsigned char>(base64_chars.find(char_array_4[i]));
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Peter Thorson. All rights reserved.
|
||||
* Copyright (c) 2014, Peter Thorson. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
|
||||
+61
-2
@@ -1,6 +1,6 @@
|
||||
|
||||
/*
|
||||
* Copyright (c) 2013, Peter Thorson. All rights reserved.
|
||||
* Copyright (c) 2014, Peter Thorson. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
@@ -150,6 +150,21 @@ namespace status {
|
||||
* illegal on the wire.
|
||||
*/
|
||||
static value const tls_handshake = 1015;
|
||||
|
||||
/// A generic subprotocol error
|
||||
/**
|
||||
* Indicates that a subprotocol error occurred. Typically this involves
|
||||
* receiving a message that is not formatted as a valid message for the
|
||||
* subprotocol in use.
|
||||
*/
|
||||
static value const subprotocol_error = 3000;
|
||||
|
||||
/// A invalid subprotocol data
|
||||
/**
|
||||
* Indicates that data was received that violated the specification of the
|
||||
* subprotocol in use.
|
||||
*/
|
||||
static value const invalid_subprotocol_data = 3001;
|
||||
|
||||
/// First value in range reserved for future protocol use
|
||||
static value const rsv_start = 1016;
|
||||
@@ -199,6 +214,50 @@ namespace status {
|
||||
code == policy_violation || code == message_too_big ||
|
||||
code == internal_endpoint_error);
|
||||
}
|
||||
|
||||
/// Return a human readable interpretation of a WebSocket close code
|
||||
/**
|
||||
* See https://tools.ietf.org/html/rfc6455#section-7.4 for more details.
|
||||
*
|
||||
* @since 0.3.0
|
||||
*
|
||||
* @param [in] code The code to look up.
|
||||
* @return A human readable interpretation of the code.
|
||||
*/
|
||||
inline std::string get_string(value code) {
|
||||
switch (code) {
|
||||
case normal:
|
||||
return "Normal close";
|
||||
case going_away:
|
||||
return "Going away";
|
||||
case protocol_error:
|
||||
return "Protocol error";
|
||||
case unsupported_data:
|
||||
return "Unsupported data";
|
||||
case no_status:
|
||||
return "No status set";
|
||||
case abnormal_close:
|
||||
return "Abnormal close";
|
||||
case invalid_payload:
|
||||
return "Invalid payload";
|
||||
case policy_violation:
|
||||
return "Policy violoation";
|
||||
case message_too_big:
|
||||
return "Message too big";
|
||||
case extension_required:
|
||||
return "Extension required";
|
||||
case internal_endpoint_error:
|
||||
return "Internal endpoint error";
|
||||
case tls_handshake:
|
||||
return "TLS handshake failure";
|
||||
case subprotocol_error:
|
||||
return "Generic subprotocol error";
|
||||
case invalid_subprotocol_data:
|
||||
return "Invalid subprotocol data";
|
||||
default:
|
||||
return "Unknown";
|
||||
}
|
||||
}
|
||||
} // namespace status
|
||||
|
||||
/// Type used to convert close statuses between integer and wire representations
|
||||
@@ -263,7 +322,7 @@ inline status::value extract_code(std::string const & payload, lib::error_code
|
||||
inline std::string extract_reason(std::string const & payload, lib::error_code
|
||||
& ec)
|
||||
{
|
||||
std::string reason = "";
|
||||
std::string reason;
|
||||
ec = lib::error_code();
|
||||
|
||||
if (payload.size() > 2) {
|
||||
|
||||
+17
-4
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Peter Thorson. All rights reserved.
|
||||
* Copyright (c) 2015, Peter Thorson. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
@@ -28,7 +28,20 @@
|
||||
#ifndef WEBSOCKETPP_COMMON_CHRONO_HPP
|
||||
#define WEBSOCKETPP_COMMON_CHRONO_HPP
|
||||
|
||||
#if defined _WEBSOCKETPP_CPP11_STL_ && !defined _WEBSOCKETPP_NO_CPP11_CHRONO_
|
||||
#include <websocketpp/common/cpp11.hpp>
|
||||
|
||||
// If we've determined that we're in full C++11 mode and the user hasn't
|
||||
// explicitly disabled the use of C++11 functional header, then prefer it to
|
||||
// boost.
|
||||
#if defined _WEBSOCKETPP_CPP11_INTERNAL_ && !defined _WEBSOCKETPP_NO_CPP11_CHRONO_
|
||||
#ifndef _WEBSOCKETPP_CPP11_CHRONO_
|
||||
#define _WEBSOCKETPP_CPP11_CHRONO_
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// If we're on Visual Studio 2012 or higher and haven't explicitly disabled
|
||||
// the use of C++11 chrono header then prefer it to boost.
|
||||
#if defined(_MSC_VER) && _MSC_VER >= 1700 && !defined _WEBSOCKETPP_NO_CPP11_CHRONO_
|
||||
#ifndef _WEBSOCKETPP_CPP11_CHRONO_
|
||||
#define _WEBSOCKETPP_CPP11_CHRONO_
|
||||
#endif
|
||||
@@ -44,9 +57,9 @@ namespace websocketpp {
|
||||
namespace lib {
|
||||
|
||||
#ifdef _WEBSOCKETPP_CPP11_CHRONO_
|
||||
using std::chrono::system_clock;
|
||||
namespace chrono = std::chrono;
|
||||
#else
|
||||
using boost::chrono::system_clock;
|
||||
namespace chrono = boost::chrono;
|
||||
#endif
|
||||
|
||||
} // namespace lib
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Peter Thorson. All rights reserved.
|
||||
* Copyright (c) 2014, Peter Thorson. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
@@ -34,7 +34,7 @@ namespace websocketpp {
|
||||
|
||||
/// A handle to uniquely identify a connection.
|
||||
/**
|
||||
* This type uniquely identifies a connection. It is implimented as a weak
|
||||
* This type uniquely identifies a connection. It is implemented as a weak
|
||||
* pointer to the connection in question. This provides uniqueness across
|
||||
* multiple endpoints and ensures that IDs never conflict or run out.
|
||||
*
|
||||
|
||||
+71
-4
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Peter Thorson. All rights reserved.
|
||||
* Copyright (c) 2014, Peter Thorson. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
@@ -40,10 +40,34 @@
|
||||
#define __has_extension __has_feature // Compatibility with pre-3.0 compilers.
|
||||
#endif
|
||||
|
||||
// The code below attempts to use information provided by the build system or
|
||||
// user supplied defines to selectively enable C++11 language and library
|
||||
// features. In most cases features that are targeted individually may also be
|
||||
// selectively disabled via an associated _WEBSOCKETPP_NOXXX_ define.
|
||||
|
||||
#ifdef _WEBSOCKETPP_CPP11_STL_
|
||||
// This flag indicates that all of the C++11 language features are available
|
||||
// to us.
|
||||
#if defined(_WEBSOCKETPP_CPP11_STL_) || __cplusplus >= 201103L || defined(_WEBSOCKETPP_CPP11_STRICT_)
|
||||
// This check tests for blanket c++11 coverage. It can be activated in one
|
||||
// of three ways. Either the compiler itself reports that it is a full
|
||||
// C++11 compiler via the __cplusplus macro or the user/build system
|
||||
// supplies one of the two preprocessor defines below:
|
||||
|
||||
// This is defined to allow other WebSocket++ common headers to enable
|
||||
// C++11 features when they are detected by this file rather than
|
||||
// duplicating the above logic in every common header.
|
||||
#define _WEBSOCKETPP_CPP11_INTERNAL_
|
||||
|
||||
// _WEBSOCKETPP_CPP11_STRICT_
|
||||
//
|
||||
// This define reports to WebSocket++ that 100% of the language and library
|
||||
// features of C++11 are available. Using this define on a non-C++11
|
||||
// compiler will result in problems.
|
||||
|
||||
// _WEBSOCKETPP_CPP11_STL_
|
||||
//
|
||||
// This define enables *most* C++11 options that were implemented early on
|
||||
// by compilers. It is typically used for compilers that have many, but not
|
||||
// all C++11 features. It should be safe to use on GCC 4.7-4.8 and perhaps
|
||||
// earlier.
|
||||
#ifndef _WEBSOCKETPP_NOEXCEPT_TOKEN_
|
||||
#define _WEBSOCKETPP_NOEXCEPT_TOKEN_ noexcept
|
||||
#endif
|
||||
@@ -53,7 +77,25 @@
|
||||
#ifndef _WEBSOCKETPP_INITIALIZER_LISTS_
|
||||
#define _WEBSOCKETPP_INITIALIZER_LISTS_
|
||||
#endif
|
||||
#ifndef _WEBSOCKETPP_NULLPTR_TOKEN_
|
||||
#define _WEBSOCKETPP_NULLPTR_TOKEN_ nullptr
|
||||
#endif
|
||||
#ifndef _WEBSOCKETPP_MOVE_SEMANTICS_
|
||||
#define _WEBSOCKETPP_MOVE_SEMANTICS_
|
||||
#endif
|
||||
#ifndef _WEBSOCKETPP_DEFAULT_DELETE_FUNCTIONS_
|
||||
#define _WEBSOCKETPP_DEFAULT_DELETE_FUNCTIONS_
|
||||
#endif
|
||||
|
||||
#ifndef __GNUC__
|
||||
// GCC as of version 4.9 (latest) does not support std::put_time yet.
|
||||
// so ignore it
|
||||
#define _WEBSOCKETPP_PUTTIME_
|
||||
#endif
|
||||
#else
|
||||
// In the absence of a blanket define, try to use compiler versions or
|
||||
// feature testing macros to selectively enable what we can.
|
||||
|
||||
// Test for noexcept
|
||||
#ifndef _WEBSOCKETPP_NOEXCEPT_TOKEN_
|
||||
#ifdef _WEBSOCKETPP_NOEXCEPT_
|
||||
@@ -63,6 +105,9 @@
|
||||
#if __has_feature(cxx_noexcept)
|
||||
// clang feature detect says we have noexcept
|
||||
#define _WEBSOCKETPP_NOEXCEPT_TOKEN_ noexcept
|
||||
#elif defined(_MSC_VER) && _MSC_VER >= 1900
|
||||
// Visual Studio 2015+ has noexcept
|
||||
#define _WEBSOCKETPP_NOEXCEPT_TOKEN_ noexcept
|
||||
#else
|
||||
// assume we don't have noexcept
|
||||
#define _WEBSOCKETPP_NOEXCEPT_TOKEN_
|
||||
@@ -79,6 +124,9 @@
|
||||
#if __has_feature(cxx_constexpr)
|
||||
// clang feature detect says we have constexpr
|
||||
#define _WEBSOCKETPP_CONSTEXPR_TOKEN_ constexpr
|
||||
#elif defined(_MSC_VER) && _MSC_VER >= 1900
|
||||
// Visual Studio 2015+ has constexpr
|
||||
#define _WEBSOCKETPP_CONSTEXPR_TOKEN_ constexpr
|
||||
#else
|
||||
// assume we don't have constexpr
|
||||
#define _WEBSOCKETPP_CONSTEXPR_TOKEN_
|
||||
@@ -90,6 +138,25 @@
|
||||
#if __has_feature(cxx_generalized_initializers) && !defined(_WEBSOCKETPP_INITIALIZER_LISTS_)
|
||||
#define _WEBSOCKETPP_INITIALIZER_LISTS_
|
||||
#endif
|
||||
|
||||
// Test for nullptr
|
||||
#ifndef _WEBSOCKETPP_NULLPTR_TOKEN_
|
||||
#ifdef _WEBSOCKETPP_NULLPTR_
|
||||
// build system says we have nullptr
|
||||
#define _WEBSOCKETPP_NULLPTR_TOKEN_ nullptr
|
||||
#else
|
||||
#if __has_feature(cxx_nullptr)
|
||||
// clang feature detect says we have nullptr
|
||||
#define _WEBSOCKETPP_NULLPTR_TOKEN_ nullptr
|
||||
#elif defined(_MSC_VER) &&_MSC_VER >= 1600
|
||||
// Visual Studio version that has nullptr
|
||||
#define _WEBSOCKETPP_NULLPTR_TOKEN_ nullptr
|
||||
#else
|
||||
// assume we don't have nullptr
|
||||
#define _WEBSOCKETPP_NULLPTR_TOKEN_ 0
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif // WEBSOCKETPP_COMMON_CPP11_HPP
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Peter Thorson. All rights reserved.
|
||||
* Copyright (c) 2014, Peter Thorson. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
@@ -28,19 +28,37 @@
|
||||
#ifndef WEBSOCKETPP_COMMON_FUNCTIONAL_HPP
|
||||
#define WEBSOCKETPP_COMMON_FUNCTIONAL_HPP
|
||||
|
||||
#if defined _WEBSOCKETPP_CPP11_STL_ && !defined _WEBSOCKETPP_NO_CPP11_FUNCTIONAL_
|
||||
#include <websocketpp/common/cpp11.hpp>
|
||||
|
||||
// If we've determined that we're in full C++11 mode and the user hasn't
|
||||
// explicitly disabled the use of C++11 functional header, then prefer it to
|
||||
// boost.
|
||||
#if defined _WEBSOCKETPP_CPP11_INTERNAL_ && !defined _WEBSOCKETPP_NO_CPP11_FUNCTIONAL_
|
||||
#ifndef _WEBSOCKETPP_CPP11_FUNCTIONAL_
|
||||
#define _WEBSOCKETPP_CPP11_FUNCTIONAL_
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// If we're on Visual Studio 2010 or higher and haven't explicitly disabled
|
||||
// the use of C++11 functional header then prefer it to boost.
|
||||
#if defined(_MSC_VER) && _MSC_VER >= 1600 && !defined _WEBSOCKETPP_NO_CPP11_FUNCTIONAL_
|
||||
#ifndef _WEBSOCKETPP_CPP11_FUNCTIONAL_
|
||||
#define _WEBSOCKETPP_CPP11_FUNCTIONAL_
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#ifdef _WEBSOCKETPP_CPP11_FUNCTIONAL_
|
||||
#include <functional>
|
||||
#else
|
||||
#include <boost/bind.hpp>
|
||||
#include <boost/function.hpp>
|
||||
#include <boost/ref.hpp>
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
namespace websocketpp {
|
||||
namespace lib {
|
||||
|
||||
@@ -49,6 +67,18 @@ namespace lib {
|
||||
using std::bind;
|
||||
using std::ref;
|
||||
namespace placeholders = std::placeholders;
|
||||
|
||||
// There are some cases where a C++11 compiler balks at using std::ref
|
||||
// but a C++03 compiler using boost function requires boost::ref. As such
|
||||
// lib::ref is not useful in these cases. Instead this macro allows the use
|
||||
// of boost::ref in the case of a boost compile or no reference wrapper at
|
||||
// all in the case of a C++11 compile
|
||||
#define _WEBSOCKETPP_REF(x) x
|
||||
|
||||
template <typename T>
|
||||
void clear_function(T & x) {
|
||||
x = nullptr;
|
||||
}
|
||||
#else
|
||||
using boost::function;
|
||||
using boost::bind;
|
||||
@@ -57,6 +87,15 @@ namespace lib {
|
||||
/// \todo this feels hacky, is there a better way?
|
||||
using ::_1;
|
||||
using ::_2;
|
||||
using ::_3;
|
||||
}
|
||||
|
||||
// See above definition for more details on what this is and why it exists
|
||||
#define _WEBSOCKETPP_REF(x) boost::ref(x)
|
||||
|
||||
template <typename T>
|
||||
void clear_function(T & x) {
|
||||
x.clear();
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
+70
-70
@@ -34,7 +34,7 @@
|
||||
|
||||
This code implements the MD5 Algorithm defined in RFC 1321, whose
|
||||
text is available at
|
||||
http://www.ietf.org/rfc/rfc1321.txt
|
||||
http://www.ietf.org/rfc/rfc1321.txt
|
||||
The code is derived from the text of the RFC, including the test suite
|
||||
(section A.5) but excluding the rest of Appendix A. It does not include
|
||||
any code or documentation that is identified in the RFC as being
|
||||
@@ -45,12 +45,12 @@
|
||||
that follows (in reverse chronological order):
|
||||
|
||||
2002-04-13 lpd Removed support for non-ANSI compilers; removed
|
||||
references to Ghostscript; clarified derivation from RFC 1321;
|
||||
now handles byte order either statically or dynamically.
|
||||
references to Ghostscript; clarified derivation from RFC 1321;
|
||||
now handles byte order either statically or dynamically.
|
||||
1999-11-04 lpd Edited comments slightly for automatic TOC extraction.
|
||||
1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5);
|
||||
added conditionalization for C++ compilation from Martin
|
||||
Purschke <purschke@bnl.gov>.
|
||||
added conditionalization for C++ compilation from Martin
|
||||
Purschke <purschke@bnl.gov>.
|
||||
1999-05-03 lpd Original version.
|
||||
*/
|
||||
|
||||
@@ -80,9 +80,9 @@ typedef unsigned int md5_word_t; /* 32-bit word */
|
||||
|
||||
/* Define the state of the MD5 Algorithm. */
|
||||
typedef struct md5_state_s {
|
||||
md5_word_t count[2]; /* message length in bits, lsw first */
|
||||
md5_word_t abcd[4]; /* digest buffer */
|
||||
md5_byte_t buf[64]; /* accumulate block */
|
||||
md5_word_t count[2]; /* message length in bits, lsw first */
|
||||
md5_word_t abcd[4]; /* digest buffer */
|
||||
md5_byte_t buf[64]; /* accumulate block */
|
||||
} md5_state_t;
|
||||
|
||||
/* Initialize the algorithm. */
|
||||
@@ -94,7 +94,7 @@ inline void md5_append(md5_state_t *pms, md5_byte_t const * data, size_t nbytes)
|
||||
/* Finish the message and return the digest. */
|
||||
inline void md5_finish(md5_state_t *pms, md5_byte_t digest[16]);
|
||||
|
||||
#undef ZSW_MD5_BYTE_ORDER /* 1 = big-endian, -1 = little-endian, 0 = unknown */
|
||||
#undef ZSW_MD5_BYTE_ORDER /* 1 = big-endian, -1 = little-endian, 0 = unknown */
|
||||
#ifdef ARCH_IS_BIG_ENDIAN
|
||||
# define ZSW_MD5_BYTE_ORDER (ARCH_IS_BIG_ENDIAN ? 1 : -1)
|
||||
#else
|
||||
@@ -169,8 +169,8 @@ inline void md5_finish(md5_state_t *pms, md5_byte_t digest[16]);
|
||||
|
||||
static void md5_process(md5_state_t *pms, md5_byte_t const * data /*[64]*/) {
|
||||
md5_word_t
|
||||
a = pms->abcd[0], b = pms->abcd[1],
|
||||
c = pms->abcd[2], d = pms->abcd[3];
|
||||
a = pms->abcd[0], b = pms->abcd[1],
|
||||
c = pms->abcd[2], d = pms->abcd[3];
|
||||
md5_word_t t;
|
||||
#if ZSW_MD5_BYTE_ORDER > 0
|
||||
/* Define storage only for big-endian CPUs. */
|
||||
@@ -183,51 +183,51 @@ static void md5_process(md5_state_t *pms, md5_byte_t const * data /*[64]*/) {
|
||||
|
||||
{
|
||||
#if ZSW_MD5_BYTE_ORDER == 0
|
||||
/*
|
||||
* Determine dynamically whether this is a big-endian or
|
||||
* little-endian machine, since we can use a more efficient
|
||||
* algorithm on the latter.
|
||||
*/
|
||||
static int const w = 1;
|
||||
/*
|
||||
* Determine dynamically whether this is a big-endian or
|
||||
* little-endian machine, since we can use a more efficient
|
||||
* algorithm on the latter.
|
||||
*/
|
||||
static int const w = 1;
|
||||
|
||||
if (*((md5_byte_t const *)&w)) /* dynamic little-endian */
|
||||
if (*((md5_byte_t const *)&w)) /* dynamic little-endian */
|
||||
#endif
|
||||
#if ZSW_MD5_BYTE_ORDER <= 0 /* little-endian */
|
||||
{
|
||||
/*
|
||||
* On little-endian machines, we can process properly aligned
|
||||
* data without copying it.
|
||||
*/
|
||||
if (!((data - (md5_byte_t const *)0) & 3)) {
|
||||
/* data are properly aligned */
|
||||
X = (md5_word_t const *)data;
|
||||
} else {
|
||||
/* not aligned */
|
||||
std::memcpy(xbuf, data, 64);
|
||||
X = xbuf;
|
||||
}
|
||||
}
|
||||
#if ZSW_MD5_BYTE_ORDER <= 0 /* little-endian */
|
||||
{
|
||||
/*
|
||||
* On little-endian machines, we can process properly aligned
|
||||
* data without copying it.
|
||||
*/
|
||||
if (!((data - (md5_byte_t const *)0) & 3)) {
|
||||
/* data are properly aligned */
|
||||
X = (md5_word_t const *)data;
|
||||
} else {
|
||||
/* not aligned */
|
||||
std::memcpy(xbuf, data, 64);
|
||||
X = xbuf;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#if ZSW_MD5_BYTE_ORDER == 0
|
||||
else /* dynamic big-endian */
|
||||
else /* dynamic big-endian */
|
||||
#endif
|
||||
#if ZSW_MD5_BYTE_ORDER >= 0 /* big-endian */
|
||||
{
|
||||
/*
|
||||
* On big-endian machines, we must arrange the bytes in the
|
||||
* right order.
|
||||
*/
|
||||
const md5_byte_t *xp = data;
|
||||
int i;
|
||||
#if ZSW_MD5_BYTE_ORDER >= 0 /* big-endian */
|
||||
{
|
||||
/*
|
||||
* On big-endian machines, we must arrange the bytes in the
|
||||
* right order.
|
||||
*/
|
||||
const md5_byte_t *xp = data;
|
||||
int i;
|
||||
|
||||
# if ZSW_MD5_BYTE_ORDER == 0
|
||||
X = xbuf; /* (dynamic only) */
|
||||
X = xbuf; /* (dynamic only) */
|
||||
# else
|
||||
# define xbuf X /* (static only) */
|
||||
# define xbuf X /* (static only) */
|
||||
# endif
|
||||
for (i = 0; i < 16; ++i, xp += 4)
|
||||
xbuf[i] = xp[0] + (xp[1] << 8) + (xp[2] << 16) + (xp[3] << 24);
|
||||
}
|
||||
for (i = 0; i < 16; ++i, xp += 4)
|
||||
xbuf[i] = xp[0] + (xp[1] << 8) + (xp[2] << 16) + (xp[3] << 24);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -361,71 +361,71 @@ void md5_append(md5_state_t *pms, md5_byte_t const * data, size_t nbytes) {
|
||||
md5_word_t nbits = (md5_word_t)(nbytes << 3);
|
||||
|
||||
if (nbytes <= 0)
|
||||
return;
|
||||
return;
|
||||
|
||||
/* Update the message length. */
|
||||
pms->count[1] += nbytes >> 29;
|
||||
pms->count[0] += nbits;
|
||||
if (pms->count[0] < nbits)
|
||||
pms->count[1]++;
|
||||
pms->count[1]++;
|
||||
|
||||
/* Process an initial partial block. */
|
||||
if (offset) {
|
||||
int copy = (offset + nbytes > 64 ? 64 - offset : static_cast<int>(nbytes));
|
||||
int copy = (offset + nbytes > 64 ? 64 - offset : static_cast<int>(nbytes));
|
||||
|
||||
std::memcpy(pms->buf + offset, p, copy);
|
||||
if (offset + copy < 64)
|
||||
return;
|
||||
p += copy;
|
||||
left -= copy;
|
||||
md5_process(pms, pms->buf);
|
||||
std::memcpy(pms->buf + offset, p, copy);
|
||||
if (offset + copy < 64)
|
||||
return;
|
||||
p += copy;
|
||||
left -= copy;
|
||||
md5_process(pms, pms->buf);
|
||||
}
|
||||
|
||||
/* Process full blocks. */
|
||||
for (; left >= 64; p += 64, left -= 64)
|
||||
md5_process(pms, p);
|
||||
md5_process(pms, p);
|
||||
|
||||
/* Process a final partial block. */
|
||||
if (left)
|
||||
std::memcpy(pms->buf, p, left);
|
||||
std::memcpy(pms->buf, p, left);
|
||||
}
|
||||
|
||||
void md5_finish(md5_state_t *pms, md5_byte_t digest[16]) {
|
||||
static md5_byte_t const pad[64] = {
|
||||
0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
|
||||
0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
|
||||
};
|
||||
md5_byte_t data[8];
|
||||
int i;
|
||||
|
||||
/* Save the length before padding. */
|
||||
for (i = 0; i < 8; ++i)
|
||||
data[i] = (md5_byte_t)(pms->count[i >> 2] >> ((i & 3) << 3));
|
||||
data[i] = (md5_byte_t)(pms->count[i >> 2] >> ((i & 3) << 3));
|
||||
/* Pad to 56 bytes mod 64. */
|
||||
md5_append(pms, pad, ((55 - (pms->count[0] >> 3)) & 63) + 1);
|
||||
/* Append the length. */
|
||||
md5_append(pms, data, 8);
|
||||
for (i = 0; i < 16; ++i)
|
||||
digest[i] = (md5_byte_t)(pms->abcd[i >> 2] >> ((i & 3) << 3));
|
||||
digest[i] = (md5_byte_t)(pms->abcd[i >> 2] >> ((i & 3) << 3));
|
||||
}
|
||||
|
||||
// some convenience c++ functions
|
||||
inline std::string md5_hash_string(std::string const & s) {
|
||||
char digest[16];
|
||||
char digest[16];
|
||||
|
||||
md5_state_t state;
|
||||
md5_state_t state;
|
||||
|
||||
md5_init(&state);
|
||||
md5_append(&state, (md5_byte_t const *)s.c_str(), s.size());
|
||||
md5_finish(&state, (md5_byte_t *)digest);
|
||||
md5_init(&state);
|
||||
md5_append(&state, (md5_byte_t const *)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;
|
||||
return ret;
|
||||
}
|
||||
|
||||
const char hexval[16] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
|
||||
|
||||
+23
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Peter Thorson. All rights reserved.
|
||||
* Copyright (c) 2014, Peter Thorson. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
@@ -28,16 +28,32 @@
|
||||
#ifndef WEBSOCKETPP_COMMON_MEMORY_HPP
|
||||
#define WEBSOCKETPP_COMMON_MEMORY_HPP
|
||||
|
||||
#if defined _WEBSOCKETPP_CPP11_STL_ && !defined _WEBSOCKETPP_NO_CPP11_MEMORY_
|
||||
#include <websocketpp/common/cpp11.hpp>
|
||||
|
||||
// If we've determined that we're in full C++11 mode and the user hasn't
|
||||
// explicitly disabled the use of C++11 memory header, then prefer it to
|
||||
// boost.
|
||||
#if defined _WEBSOCKETPP_CPP11_INTERNAL_ && !defined _WEBSOCKETPP_NO_CPP11_MEMORY_
|
||||
#ifndef _WEBSOCKETPP_CPP11_MEMORY_
|
||||
#define _WEBSOCKETPP_CPP11_MEMORY_
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// If we're on Visual Studio 2010 or higher and haven't explicitly disabled
|
||||
// the use of C++11 functional header then prefer it to boost.
|
||||
#if defined(_MSC_VER) && _MSC_VER >= 1600 && !defined _WEBSOCKETPP_NO_CPP11_MEMORY_
|
||||
#ifndef _WEBSOCKETPP_CPP11_MEMORY_
|
||||
#define _WEBSOCKETPP_CPP11_MEMORY_
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#ifdef _WEBSOCKETPP_CPP11_MEMORY_
|
||||
#include <memory>
|
||||
#else
|
||||
#include <boost/shared_ptr.hpp>
|
||||
#include <boost/make_shared.hpp>
|
||||
#include <boost/scoped_array.hpp>
|
||||
#include <boost/enable_shared_from_this.hpp>
|
||||
#include <boost/pointer_cast.hpp>
|
||||
@@ -49,15 +65,20 @@ namespace lib {
|
||||
#ifdef _WEBSOCKETPP_CPP11_MEMORY_
|
||||
using std::shared_ptr;
|
||||
using std::weak_ptr;
|
||||
using std::auto_ptr;
|
||||
using std::enable_shared_from_this;
|
||||
using std::static_pointer_cast;
|
||||
using std::make_shared;
|
||||
using std::unique_ptr;
|
||||
|
||||
typedef std::unique_ptr<unsigned char[]> unique_ptr_uchar_array;
|
||||
#else
|
||||
using boost::shared_ptr;
|
||||
using boost::weak_ptr;
|
||||
using std::auto_ptr;
|
||||
using boost::enable_shared_from_this;
|
||||
using boost::static_pointer_cast;
|
||||
using boost::make_shared;
|
||||
|
||||
typedef boost::scoped_array<unsigned char> unique_ptr_uchar_array;
|
||||
#endif
|
||||
|
||||
+30
-6
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Peter Thorson. All rights reserved.
|
||||
* Copyright (c) 2014, Peter Thorson. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
@@ -29,20 +29,22 @@
|
||||
#define WEBSOCKETPP_COMMON_NETWORK_HPP
|
||||
|
||||
// For ntohs and htons
|
||||
#if defined(WIN32)
|
||||
#if defined(_WIN32)
|
||||
#include <winsock2.h>
|
||||
#else
|
||||
//#include <arpa/inet.h>
|
||||
#include <netinet/in.h>
|
||||
#endif
|
||||
|
||||
#include <websocketpp/common/stdint.hpp>
|
||||
|
||||
namespace websocketpp {
|
||||
namespace lib {
|
||||
namespace net {
|
||||
|
||||
inline bool is_little_endian() {
|
||||
short int val = 0x1;
|
||||
char *ptr = (char*)&val;
|
||||
char *ptr = reinterpret_cast<char *>(&val);
|
||||
return (ptr[0] == 1);
|
||||
}
|
||||
|
||||
@@ -50,7 +52,18 @@ inline bool is_little_endian() {
|
||||
#define TYP_SMLE 1
|
||||
#define TYP_BIGE 2
|
||||
|
||||
inline uint64_t htonll(uint64_t src) {
|
||||
/// Convert 64 bit value to network byte order
|
||||
/**
|
||||
* This method is prefixed to avoid conflicts with operating system level
|
||||
* macros for this functionality.
|
||||
*
|
||||
* TODO: figure out if it would be beneficial to use operating system level
|
||||
* macros for this.
|
||||
*
|
||||
* @param src The integer in host byte order
|
||||
* @return src converted to network byte order
|
||||
*/
|
||||
inline uint64_t _htonll(uint64_t src) {
|
||||
static int typ = TYP_INIT;
|
||||
unsigned char c;
|
||||
union {
|
||||
@@ -71,8 +84,19 @@ inline uint64_t htonll(uint64_t src) {
|
||||
return x.ull;
|
||||
}
|
||||
|
||||
inline uint64_t ntohll(uint64_t src) {
|
||||
return htonll(src);
|
||||
/// Convert 64 bit value to host byte order
|
||||
/**
|
||||
* This method is prefixed to avoid conflicts with operating system level
|
||||
* macros for this functionality.
|
||||
*
|
||||
* TODO: figure out if it would be beneficial to use operating system level
|
||||
* macros for this.
|
||||
*
|
||||
* @param src The integer in network byte order
|
||||
* @return src converted to host byte order
|
||||
*/
|
||||
inline uint64_t _ntohll(uint64_t src) {
|
||||
return _htonll(src);
|
||||
}
|
||||
|
||||
} // net
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Peter Thorson. All rights reserved.
|
||||
* Copyright (c) 2014, Peter Thorson. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
@@ -33,9 +33,14 @@
|
||||
* don't fit somewhere else better.
|
||||
*/
|
||||
|
||||
#if defined(WIN32) && !defined(NOMINMAX)
|
||||
#if defined(_WIN32) && !defined(NOMINMAX)
|
||||
// don't define min and max macros that conflict with std::min and std::max
|
||||
#define NOMINMAX
|
||||
#endif
|
||||
|
||||
// Bump up the variadic parameter max for Visual Studio 2012
|
||||
#if defined(_MSC_VER) && _MSC_VER == 1700
|
||||
#define _VARIADIC_MAX 8
|
||||
#endif
|
||||
|
||||
#endif // WEBSOCKETPP_COMMON_PLATFORMS_HPP
|
||||
+18
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Peter Thorson. All rights reserved.
|
||||
* Copyright (c) 2014, Peter Thorson. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
@@ -28,12 +28,28 @@
|
||||
#ifndef WEBSOCKETPP_COMMON_RANDOM_DEVICE_HPP
|
||||
#define WEBSOCKETPP_COMMON_RANDOM_DEVICE_HPP
|
||||
|
||||
#if defined _WEBSOCKETPP_CPP11_STL_ && !defined _WEBSOCKETPP_NO_CPP11_RANDOM_DEVICE_
|
||||
#include <websocketpp/common/cpp11.hpp>
|
||||
|
||||
// If we've determined that we're in full C++11 mode and the user hasn't
|
||||
// explicitly disabled the use of C++11 random header, then prefer it to
|
||||
// boost.
|
||||
#if defined _WEBSOCKETPP_CPP11_INTERNAL_ && !defined _WEBSOCKETPP_NO_CPP11_RANDOM_DEVICE_
|
||||
#ifndef _WEBSOCKETPP_CPP11_RANDOM_DEVICE_
|
||||
#define _WEBSOCKETPP_CPP11_RANDOM_DEVICE_
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
// If we're on Visual Studio 2010 or higher and haven't explicitly disabled
|
||||
// the use of C++11 random header then prefer it to boost.
|
||||
#if defined(_MSC_VER) && _MSC_VER >= 1600 && !defined _WEBSOCKETPP_NO_CPP11_MEMORY_
|
||||
#ifndef _WEBSOCKETPP_CPP11_MEMORY_
|
||||
#define _WEBSOCKETPP_CPP11_MEMORY_
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#ifdef _WEBSOCKETPP_CPP11_RANDOM_DEVICE_
|
||||
#include <random>
|
||||
#else
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Peter Thorson. All rights reserved.
|
||||
* Copyright (c) 2014, Peter Thorson. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Peter Thorson. All rights reserved.
|
||||
* Copyright (c) 2014, Peter Thorson. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
@@ -32,7 +32,7 @@
|
||||
#define __STDC_LIMIT_MACROS 1
|
||||
#endif
|
||||
|
||||
#if WIN32 && (_MSC_VER < 1600)
|
||||
#if defined (_WIN32) && defined (_MSC_VER) && (_MSC_VER < 1600)
|
||||
#include <boost/cstdint.hpp>
|
||||
|
||||
using boost::int8_t;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Peter Thorson. All rights reserved.
|
||||
* Copyright (c) 2014, Peter Thorson. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
@@ -28,12 +28,28 @@
|
||||
#ifndef WEBSOCKETPP_COMMON_SYSTEM_ERROR_HPP
|
||||
#define WEBSOCKETPP_COMMON_SYSTEM_ERROR_HPP
|
||||
|
||||
#if defined _WEBSOCKETPP_CPP11_STL_ && !defined _WEBSOCKETPP_NO_CPP11_SYSTEM_ERROR_
|
||||
|
||||
#include <websocketpp/common/cpp11.hpp>
|
||||
|
||||
// If we've determined that we're in full C++11 mode and the user hasn't
|
||||
// explicitly disabled the use of C++11 system_error header, then prefer it to
|
||||
// boost.
|
||||
#if defined _WEBSOCKETPP_CPP11_INTERNAL_ && !defined _WEBSOCKETPP_NO_CPP11_SYSTEM_ERROR_
|
||||
#ifndef _WEBSOCKETPP_CPP11_SYSTEM_ERROR_
|
||||
#define _WEBSOCKETPP_CPP11_SYSTEM_ERROR_
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// If we're on Visual Studio 2010 or higher and haven't explicitly disabled
|
||||
// the use of C++11 system_error header then prefer it to boost.
|
||||
#if defined(_MSC_VER) && _MSC_VER >= 1600 && !defined _WEBSOCKETPP_NO_CPP11_SYSTEM_ERROR_
|
||||
#ifndef _WEBSOCKETPP_CPP11_SYSTEM_ERROR_
|
||||
#define _WEBSOCKETPP_CPP11_SYSTEM_ERROR_
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#ifdef _WEBSOCKETPP_CPP11_SYSTEM_ERROR_
|
||||
#include <system_error>
|
||||
#else
|
||||
@@ -45,6 +61,7 @@ namespace websocketpp {
|
||||
namespace lib {
|
||||
|
||||
#ifdef _WEBSOCKETPP_CPP11_SYSTEM_ERROR_
|
||||
using std::errc;
|
||||
using std::error_code;
|
||||
using std::error_category;
|
||||
using std::error_condition;
|
||||
@@ -52,6 +69,7 @@ namespace lib {
|
||||
#define _WEBSOCKETPP_ERROR_CODE_ENUM_NS_START_ namespace std {
|
||||
#define _WEBSOCKETPP_ERROR_CODE_ENUM_NS_END_ }
|
||||
#else
|
||||
namespace errc = boost::system::errc;
|
||||
using boost::system::error_code;
|
||||
using boost::system::error_category;
|
||||
using boost::system::error_condition;
|
||||
|
||||
+19
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Peter Thorson. All rights reserved.
|
||||
* Copyright (c) 2015, Peter Thorson. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
@@ -28,7 +28,24 @@
|
||||
#ifndef WEBSOCKETPP_COMMON_THREAD_HPP
|
||||
#define WEBSOCKETPP_COMMON_THREAD_HPP
|
||||
|
||||
#if defined _WEBSOCKETPP_CPP11_STL_ && !defined _WEBSOCKETPP_NO_CPP11_THREAD_
|
||||
#include <websocketpp/common/cpp11.hpp>
|
||||
|
||||
// If we autodetect C++11 and haven't been explicitly instructed to not use
|
||||
// C++11 threads, then set the defines that instructs the rest of this header
|
||||
// to use C++11 <thread> and <mutex>
|
||||
#if defined _WEBSOCKETPP_CPP11_INTERNAL_ && !defined _WEBSOCKETPP_NO_CPP11_THREAD_
|
||||
// MinGW by default does not support C++11 thread/mutex so even if the
|
||||
// internal check for C++11 passes, ignore it if we are on MinGW
|
||||
#if (!defined(__MINGW32__) && !defined(__MINGW64__))
|
||||
#ifndef _WEBSOCKETPP_CPP11_THREAD_
|
||||
#define _WEBSOCKETPP_CPP11_THREAD_
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// If we're on Visual Studio 2013 or higher and haven't explicitly disabled
|
||||
// the use of C++11 thread header then prefer it to boost.
|
||||
#if defined(_MSC_VER) && _MSC_VER >= 1800 && !defined _WEBSOCKETPP_NO_CPP11_THREAD_
|
||||
#ifndef _WEBSOCKETPP_CPP11_THREAD_
|
||||
#define _WEBSOCKETPP_CPP11_THREAD_
|
||||
#endif
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Peter Thorson. All rights reserved.
|
||||
* Copyright (c) 2014, Peter Thorson. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Peter Thorson. All rights reserved.
|
||||
* Copyright (c) 2014, Peter Thorson. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
@@ -29,26 +29,48 @@
|
||||
#define WEBSOCKETPP_CONCURRENCY_NONE_HPP
|
||||
|
||||
namespace websocketpp {
|
||||
|
||||
/// Concurrency handling support
|
||||
namespace concurrency {
|
||||
|
||||
/// Implementation for no-op locking primitives
|
||||
namespace none_impl {
|
||||
/// A fake mutex implementation that does nothing
|
||||
class fake_mutex {
|
||||
public:
|
||||
fake_mutex() {}
|
||||
~fake_mutex() {}
|
||||
};
|
||||
|
||||
/// A fake lock guard implementation that does nothing
|
||||
class fake_lock_guard {
|
||||
public:
|
||||
explicit fake_lock_guard(fake_mutex foo) {}
|
||||
explicit fake_lock_guard(fake_mutex) {}
|
||||
~fake_lock_guard() {}
|
||||
};
|
||||
} // namespace none_impl
|
||||
|
||||
/// Stub Concurrency policy to remove locking in single threaded projects
|
||||
/// Stub concurrency policy that implements the interface using no-ops.
|
||||
/**
|
||||
* This policy documents the concurrency policy interface using no-ops. It can
|
||||
* be used as a reference or base for building a new concurrency policy. It can
|
||||
* also be used as is to disable all locking for endpoints used in purely single
|
||||
* threaded programs.
|
||||
*/
|
||||
class none {
|
||||
public:
|
||||
/// The type of a mutex primitive
|
||||
/**
|
||||
* std::mutex is an example.
|
||||
*/
|
||||
typedef none_impl::fake_mutex mutex_type;
|
||||
|
||||
/// The type of a scoped/RAII lock primitive.
|
||||
/**
|
||||
* The scoped lock constructor should take a mutex_type as a parameter,
|
||||
* acquire that lock, and release it in its destructor. std::lock_guard is
|
||||
* an example.
|
||||
*/
|
||||
typedef none_impl::fake_lock_guard scoped_lock_type;
|
||||
};
|
||||
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Peter Thorson. All rights reserved.
|
||||
* Copyright (c) 2014, Peter Thorson. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Peter Thorson. All rights reserved.
|
||||
* Copyright (c) 2014, Peter Thorson. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Peter Thorson. All rights reserved.
|
||||
* Copyright (c) 2014, Peter Thorson. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Peter Thorson. All rights reserved.
|
||||
* Copyright (c) 2014, Peter Thorson. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Peter Thorson. All rights reserved.
|
||||
* Copyright (c) 2014, Peter Thorson. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
@@ -25,9 +25,9 @@
|
||||
*
|
||||
*/
|
||||
|
||||
// This header defines WebSocket++ macros for C++11 compatibility based on the Boost.Config library.
|
||||
// This will correctly configure most target platforms simply by including this header before
|
||||
// any other WebSocket++ header.
|
||||
// This header defines WebSocket++ macros for C++11 compatibility based on the
|
||||
// Boost.Config library. This will correctly configure most target platforms
|
||||
// simply by including this header before any other WebSocket++ header.
|
||||
|
||||
#ifndef WEBSOCKETPP_CONFIG_BOOST_CONFIG_HPP
|
||||
#define WEBSOCKETPP_CONFIG_BOOST_CONFIG_HPP
|
||||
@@ -41,7 +41,7 @@
|
||||
#define _WEBSOCKETPP_CPP11_FUNCTIONAL_
|
||||
#endif
|
||||
|
||||
#ifndef BOOST_ASIO_HAS_STD_CHRONO
|
||||
#ifdef BOOST_ASIO_HAS_STD_CHRONO
|
||||
#define _WEBSOCKETPP_CPP11_CHRONO_
|
||||
#endif
|
||||
|
||||
@@ -67,5 +67,6 @@
|
||||
|
||||
#define _WEBSOCKETPP_NOEXCEPT_TOKEN_ BOOST_NOEXCEPT
|
||||
#define _WEBSOCKETPP_CONSTEXPR_TOKEN_ BOOST_CONSTEXPR
|
||||
// TODO: nullptr support
|
||||
|
||||
#endif // WEBSOCKETPP_CONFIG_BOOST_CONFIG_HPP
|
||||
+25
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Peter Thorson. All rights reserved.
|
||||
* Copyright (c) 2014, Peter Thorson. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
@@ -215,6 +215,30 @@ struct core {
|
||||
*/
|
||||
static const bool silent_close = false;
|
||||
|
||||
/// Default maximum message size
|
||||
/**
|
||||
* Default value for the processor's maximum message size. Maximum message size
|
||||
* determines the point at which the library will fail a connection with the
|
||||
* message_too_big protocol error.
|
||||
*
|
||||
* The default is 32MB
|
||||
*
|
||||
* @since 0.3.0
|
||||
*/
|
||||
static const size_t max_message_size = 32000000;
|
||||
|
||||
/// Default maximum http body size
|
||||
/**
|
||||
* Default value for the http parser's maximum body size. Maximum body size
|
||||
* determines the point at which the library will abort reading an HTTP
|
||||
* connection with the 413/request entity too large error.
|
||||
*
|
||||
* The default is 32MB
|
||||
*
|
||||
* @since 0.5.0
|
||||
*/
|
||||
static const size_t max_http_body_size = 32000000;
|
||||
|
||||
/// Global flag for enabling/disabling extensions
|
||||
static const bool enable_extensions = true;
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Peter Thorson. All rights reserved.
|
||||
* Copyright (c) 2014, Peter Thorson. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
@@ -34,7 +34,11 @@
|
||||
#include <websocketpp/common/stdint.hpp>
|
||||
|
||||
// Concurrency
|
||||
#ifndef _WEBSOCKETPP_NO_THREADING_
|
||||
#include <websocketpp/concurrency/basic.hpp>
|
||||
#else
|
||||
#include <websocketpp/concurrency/none.hpp>
|
||||
#endif
|
||||
|
||||
// Transport
|
||||
#include <websocketpp/transport/iostream/endpoint.hpp>
|
||||
@@ -68,7 +72,11 @@ struct core_client {
|
||||
typedef core_client type;
|
||||
|
||||
// Concurrency policy
|
||||
#ifndef _WEBSOCKETPP_NO_THREADING_
|
||||
typedef websocketpp::concurrency::basic concurrency_type;
|
||||
#else
|
||||
typedef websocketpp::concurrency::none concurrency_type;
|
||||
#endif
|
||||
|
||||
// HTTP Parser Policies
|
||||
typedef http::parser::request request_type;
|
||||
@@ -216,6 +224,30 @@ struct core_client {
|
||||
*/
|
||||
static const bool silent_close = false;
|
||||
|
||||
/// Default maximum message size
|
||||
/**
|
||||
* Default value for the processor's maximum message size. Maximum message size
|
||||
* determines the point at which the library will fail a connection with the
|
||||
* message_too_big protocol error.
|
||||
*
|
||||
* The default is 32MB
|
||||
*
|
||||
* @since 0.3.0
|
||||
*/
|
||||
static const size_t max_message_size = 32000000;
|
||||
|
||||
/// Default maximum http body size
|
||||
/**
|
||||
* Default value for the http parser's maximum body size. Maximum body size
|
||||
* determines the point at which the library will abort reading an HTTP
|
||||
* connection with the 413/request entity too large error.
|
||||
*
|
||||
* The default is 32MB
|
||||
*
|
||||
* @since 0.5.0
|
||||
*/
|
||||
static const size_t max_http_body_size = 32000000;
|
||||
|
||||
/// Global flag for enabling/disabling extensions
|
||||
static const bool enable_extensions = true;
|
||||
|
||||
|
||||
+25
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Peter Thorson. All rights reserved.
|
||||
* Copyright (c) 2014, Peter Thorson. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
@@ -216,6 +216,30 @@ struct debug_core {
|
||||
*/
|
||||
static const bool silent_close = false;
|
||||
|
||||
/// Default maximum message size
|
||||
/**
|
||||
* Default value for the processor's maximum message size. Maximum message size
|
||||
* determines the point at which the library will fail a connection with the
|
||||
* message_too_big protocol error.
|
||||
*
|
||||
* The default is 32MB
|
||||
*
|
||||
* @since 0.3.0
|
||||
*/
|
||||
static const size_t max_message_size = 32000000;
|
||||
|
||||
/// Default maximum http body size
|
||||
/**
|
||||
* Default value for the http parser's maximum body size. Maximum body size
|
||||
* determines the point at which the library will abort reading an HTTP
|
||||
* connection with the 413/request entity too large error.
|
||||
*
|
||||
* The default is 32MB
|
||||
*
|
||||
* @since 0.5.0
|
||||
*/
|
||||
static const size_t max_http_body_size = 32000000;
|
||||
|
||||
/// Global flag for enabling/disabling extensions
|
||||
static const bool enable_extensions = true;
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Peter Thorson. All rights reserved.
|
||||
* Copyright (c) 2014, Peter Thorson. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Peter Thorson. All rights reserved.
|
||||
* Copyright (c) 2014, Peter Thorson. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
|
||||
+313
-93
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Peter Thorson. All rights reserved.
|
||||
* Copyright (c) 2014, Peter Thorson. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
@@ -29,19 +29,20 @@
|
||||
#define WEBSOCKETPP_CONNECTION_HPP
|
||||
|
||||
#include <websocketpp/close.hpp>
|
||||
#include <websocketpp/common/connection_hdl.hpp>
|
||||
#include <websocketpp/common/cpp11.hpp>
|
||||
#include <websocketpp/common/functional.hpp>
|
||||
#include <websocketpp/error.hpp>
|
||||
#include <websocketpp/frame.hpp>
|
||||
#include <websocketpp/http/constants.hpp>
|
||||
|
||||
#include <websocketpp/logger/levels.hpp>
|
||||
#include <websocketpp/processors/processor.hpp>
|
||||
#include <websocketpp/transport/base/connection.hpp>
|
||||
#include <websocketpp/http/constants.hpp>
|
||||
|
||||
#include <websocketpp/common/connection_hdl.hpp>
|
||||
#include <websocketpp/common/cpp11.hpp>
|
||||
#include <websocketpp/common/functional.hpp>
|
||||
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
#include <queue>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
@@ -118,7 +119,7 @@ typedef lib::function<void(connection_hdl,std::string)> pong_timeout_handler;
|
||||
/**
|
||||
* The validate handler is called after a WebSocket handshake has been received
|
||||
* and processed but before it has been accepted. This gives the application a
|
||||
* chance to impliment connection details specific policies for accepting
|
||||
* chance to implement connection details specific policies for accepting
|
||||
* connections and the ability to negotiate extensions and subprotocols.
|
||||
*
|
||||
* The validate handler return value indicates whether or not the connection
|
||||
@@ -213,6 +214,20 @@ namespace internal_state {
|
||||
PROCESS_CONNECTION = 7
|
||||
};
|
||||
} // namespace internal_state
|
||||
|
||||
|
||||
namespace http_state {
|
||||
// states to keep track of the progress of http connections
|
||||
|
||||
enum value {
|
||||
init = 0,
|
||||
deferred = 1,
|
||||
headers_written = 2,
|
||||
body_written = 3,
|
||||
closed = 4
|
||||
};
|
||||
} // namespace http_state
|
||||
|
||||
} // namespace session
|
||||
|
||||
/// Represents an individual WebSocket connection
|
||||
@@ -279,9 +294,9 @@ private:
|
||||
};
|
||||
public:
|
||||
|
||||
explicit connection(bool is_server, std::string const & ua, alog_type& alog,
|
||||
explicit connection(bool p_is_server, std::string const & ua, alog_type& alog,
|
||||
elog_type& elog, rng_type & rng)
|
||||
: transport_con_type(is_server,alog,elog)
|
||||
: transport_con_type(p_is_server, alog, elog)
|
||||
, m_handle_read_frame(lib::bind(
|
||||
&type::handle_read_frame,
|
||||
this,
|
||||
@@ -297,17 +312,21 @@ public:
|
||||
, m_open_handshake_timeout_dur(config::timeout_open_handshake)
|
||||
, m_close_handshake_timeout_dur(config::timeout_close_handshake)
|
||||
, m_pong_timeout_dur(config::timeout_pong)
|
||||
, m_max_message_size(config::max_message_size)
|
||||
, m_state(session::state::connecting)
|
||||
, m_internal_state(session::internal_state::USER_INIT)
|
||||
, m_msg_manager(new con_msg_manager_type())
|
||||
, m_send_buffer_size(0)
|
||||
, m_write_flag(false)
|
||||
, m_is_server(is_server)
|
||||
, m_read_flag(true)
|
||||
, m_is_server(p_is_server)
|
||||
, m_alog(alog)
|
||||
, m_elog(elog)
|
||||
, m_rng(rng)
|
||||
, m_local_close_code(close::status::abnormal_close)
|
||||
, m_remote_close_code(close::status::abnormal_close)
|
||||
, m_is_http(false)
|
||||
, m_http_state(session::http_state::init)
|
||||
, m_was_clean(false)
|
||||
{
|
||||
m_alog.write(log::alevel::devel,"connection constructor");
|
||||
@@ -455,9 +474,9 @@ public:
|
||||
m_message_handler = h;
|
||||
}
|
||||
|
||||
/////////////////////////
|
||||
// Connection timeouts //
|
||||
/////////////////////////
|
||||
//////////////////////////////////////////
|
||||
// Connection timeouts and other limits //
|
||||
//////////////////////////////////////////
|
||||
|
||||
/// Set open handshake timeout
|
||||
/**
|
||||
@@ -528,6 +547,70 @@ public:
|
||||
m_pong_timeout_dur = dur;
|
||||
}
|
||||
|
||||
/// Get maximum message size
|
||||
/**
|
||||
* Get maximum message size. Maximum message size determines the point at
|
||||
* which the connection will fail with the message_too_big protocol error.
|
||||
*
|
||||
* The default is set by the endpoint that creates the connection.
|
||||
*
|
||||
* @since 0.3.0
|
||||
*/
|
||||
size_t get_max_message_size() const {
|
||||
return m_max_message_size;
|
||||
}
|
||||
|
||||
/// Set maximum message size
|
||||
/**
|
||||
* Set maximum message size. Maximum message size determines the point at
|
||||
* which the connection will fail with the message_too_big protocol error.
|
||||
* This value may be changed during the connection.
|
||||
*
|
||||
* The default is set by the endpoint that creates the connection.
|
||||
*
|
||||
* @since 0.3.0
|
||||
*
|
||||
* @param new_value The value to set as the maximum message size.
|
||||
*/
|
||||
void set_max_message_size(size_t new_value) {
|
||||
m_max_message_size = new_value;
|
||||
if (m_processor) {
|
||||
m_processor->set_max_message_size(new_value);
|
||||
}
|
||||
}
|
||||
|
||||
/// Get maximum HTTP message body size
|
||||
/**
|
||||
* Get maximum HTTP message body size. Maximum message body size determines
|
||||
* the point at which the connection will stop reading an HTTP request whose
|
||||
* body is too large.
|
||||
*
|
||||
* The default is set by the endpoint that creates the connection.
|
||||
*
|
||||
* @since 0.5.0
|
||||
*
|
||||
* @return The maximum HTTP message body size
|
||||
*/
|
||||
size_t get_max_http_body_size() const {
|
||||
return m_request.get_max_body_size();
|
||||
}
|
||||
|
||||
/// Set maximum HTTP message body size
|
||||
/**
|
||||
* Set maximum HTTP message body size. Maximum message body size determines
|
||||
* the point at which the connection will stop reading an HTTP request whose
|
||||
* body is too large.
|
||||
*
|
||||
* The default is set by the endpoint that creates the connection.
|
||||
*
|
||||
* @since 0.5.0
|
||||
*
|
||||
* @param new_value The value to set as the maximum message size.
|
||||
*/
|
||||
void set_max_http_body_size(size_t new_value) {
|
||||
m_request.set_max_body_size(new_value);
|
||||
}
|
||||
|
||||
//////////////////////////////////
|
||||
// Uncategorized public methods //
|
||||
//////////////////////////////////
|
||||
@@ -545,7 +628,10 @@ public:
|
||||
*/
|
||||
size_t get_buffered_amount() const;
|
||||
|
||||
/// DEPRECATED: use get_buffered_amount instead
|
||||
/// Get the size of the outgoing write buffer (in payload bytes)
|
||||
/**
|
||||
* @deprecated use `get_buffered_amount` instead
|
||||
*/
|
||||
size_t buffered_amount() const {
|
||||
return get_buffered_amount();
|
||||
}
|
||||
@@ -615,9 +701,46 @@ public:
|
||||
* @return An error code
|
||||
*/
|
||||
lib::error_code interrupt();
|
||||
|
||||
|
||||
/// Transport inturrupt callback
|
||||
void handle_interrupt();
|
||||
|
||||
/// Pause reading of new data
|
||||
/**
|
||||
* Signals to the connection to halt reading of new data. While reading is paused,
|
||||
* the connection will stop reading from its associated socket. In turn this will
|
||||
* result in TCP based flow control kicking in and slowing data flow from the remote
|
||||
* endpoint.
|
||||
*
|
||||
* This is useful for applications that push new requests to a queue to be processed
|
||||
* by another thread and need a way to signal when their request queue is full without
|
||||
* blocking the network processing thread.
|
||||
*
|
||||
* Use `resume_reading()` to resume.
|
||||
*
|
||||
* If supported by the transport this is done asynchronously. As such reading may not
|
||||
* stop until the current read operation completes. Typically you can expect to
|
||||
* receive no more bytes after initiating a read pause than the size of the read
|
||||
* buffer.
|
||||
*
|
||||
* If reading is paused for this connection already nothing is changed.
|
||||
*/
|
||||
lib::error_code pause_reading();
|
||||
|
||||
/// Pause reading callback
|
||||
void handle_pause_reading();
|
||||
|
||||
/// Resume reading of new data
|
||||
/**
|
||||
* Signals to the connection to resume reading of new data after it was paused by
|
||||
* `pause_reading()`.
|
||||
*
|
||||
* If reading is not paused for this connection already nothing is changed.
|
||||
*/
|
||||
lib::error_code resume_reading();
|
||||
|
||||
/// Resume reading callback
|
||||
void handle_resume_reading();
|
||||
|
||||
/// Send a ping
|
||||
/**
|
||||
@@ -827,7 +950,18 @@ public:
|
||||
* @param key Name of the header to get
|
||||
* @return The value of the header
|
||||
*/
|
||||
std::string const & get_request_header(std::string const & key);
|
||||
std::string const & get_request_header(std::string const & key) const;
|
||||
|
||||
/// Retrieve a request body
|
||||
/**
|
||||
* Retrieve the value of the request body. This value is typically used with
|
||||
* PUT and POST requests to upload files or other data. Only HTTP
|
||||
* connections will ever have bodies. WebSocket connection's will always
|
||||
* have blank bodies.
|
||||
*
|
||||
* @return The value of the request body.
|
||||
*/
|
||||
std::string const & get_request_body() const;
|
||||
|
||||
/// Retrieve a response header
|
||||
/**
|
||||
@@ -836,8 +970,32 @@ public:
|
||||
* @param key Name of the header to get
|
||||
* @return The value of the header
|
||||
*/
|
||||
std::string const & get_response_header(std::string const & key);
|
||||
std::string const & get_response_header(std::string const & key) const;
|
||||
|
||||
/// Get response HTTP status code
|
||||
/**
|
||||
* Gets the response status code
|
||||
*
|
||||
* @since 0.7.0
|
||||
*
|
||||
* @return The response status code sent
|
||||
*/
|
||||
http::status_code::value get_response_code() const {
|
||||
return m_response.get_status_code();
|
||||
}
|
||||
|
||||
/// Get response HTTP status message
|
||||
/**
|
||||
* Gets the response status message
|
||||
*
|
||||
* @since 0.7.0
|
||||
*
|
||||
* @return The response status message sent
|
||||
*/
|
||||
std::string const & get_response_msg() const {
|
||||
return m_response.get_status_msg();
|
||||
}
|
||||
|
||||
/// Set response status code and message
|
||||
/**
|
||||
* Sets the response status code to `code` and looks up the corresponding
|
||||
@@ -944,6 +1102,71 @@ public:
|
||||
request_type const & get_request() const {
|
||||
return m_request;
|
||||
}
|
||||
|
||||
/// Get response object
|
||||
/**
|
||||
* Direct access to the HTTP response sent or received as a part of the
|
||||
* opening handshake. This can be used to call methods of the response
|
||||
* object that are not part of the standard request API that connection
|
||||
* wraps.
|
||||
*
|
||||
* Note use of this method involves using behavior specific to the
|
||||
* configured HTTP policy. Such behavior may not work with alternate HTTP
|
||||
* policies.
|
||||
*
|
||||
* @since 0.7.0
|
||||
*
|
||||
* @return A const reference to the raw response object
|
||||
*/
|
||||
response_type const & get_response() const {
|
||||
return m_response;
|
||||
}
|
||||
|
||||
/// Defer HTTP Response until later (Exception free)
|
||||
/**
|
||||
* Used in the http handler to defer the HTTP response for this connection
|
||||
* until later. Handshake timers will be canceled and the connection will be
|
||||
* left open until `send_http_response` or an equivalent is called.
|
||||
*
|
||||
* Warning: deferred connections won't time out and as a result can tie up
|
||||
* resources.
|
||||
*
|
||||
* @since 0.6.0
|
||||
*
|
||||
* @return A status code, zero on success, non-zero otherwise
|
||||
*/
|
||||
lib::error_code defer_http_response();
|
||||
|
||||
/// Send deferred HTTP Response (exception free)
|
||||
/**
|
||||
* Sends an http response to an HTTP connection that was deferred. This will
|
||||
* send a complete response including all headers, status line, and body
|
||||
* text. The connection will be closed afterwards.
|
||||
*
|
||||
* @since 0.6.0
|
||||
*
|
||||
* @param ec A status code, zero on success, non-zero otherwise
|
||||
*/
|
||||
void send_http_response(lib::error_code & ec);
|
||||
|
||||
/// Send deferred HTTP Response
|
||||
void send_http_response();
|
||||
|
||||
// TODO HTTPNBIO: write_headers
|
||||
// function that processes headers + status so far and writes it to the wire
|
||||
// beginning the HTTP response body state. This method will ignore anything
|
||||
// in the response body.
|
||||
|
||||
// TODO HTTPNBIO: write_body_message
|
||||
// queues the specified message_buffer for async writing
|
||||
|
||||
// TODO HTTPNBIO: finish connection
|
||||
//
|
||||
|
||||
// TODO HTTPNBIO: write_response
|
||||
// Writes the whole response, headers + body and closes the connection
|
||||
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////
|
||||
// Pass-through access to the other connection information //
|
||||
@@ -1032,26 +1255,6 @@ public:
|
||||
return m_ec;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// The remaining public member functions are for internal/policy use //
|
||||
// only. Do not call from application code unless you understand what //
|
||||
// you are doing. //
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// Set Connection Handle
|
||||
/**
|
||||
* The connection handle is a token that can be shared outside the
|
||||
* WebSocket++ core for the purposes of identifying a connection and
|
||||
* sending it messages.
|
||||
*
|
||||
* @param hdl A connection_hdl that the connection will use to refer
|
||||
* to itself.
|
||||
*/
|
||||
void set_handle(connection_hdl hdl) {
|
||||
m_connection_hdl = hdl;
|
||||
transport_con_type::set_handle(hdl);
|
||||
}
|
||||
|
||||
/// Get a message buffer
|
||||
/**
|
||||
* Warning: The API related to directly sending message buffers may change
|
||||
@@ -1077,7 +1280,13 @@ public:
|
||||
return m_msg_manager->get_message(op, size);
|
||||
}
|
||||
|
||||
void start();
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// The remaining public member functions are for internal/policy use //
|
||||
// only. Do not call from application code unless you understand what //
|
||||
// you are doing. //
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
|
||||
void read_handshake(size_t num_bytes);
|
||||
|
||||
@@ -1086,17 +1295,18 @@ public:
|
||||
void handle_read_http_response(lib::error_code const & ec,
|
||||
size_t bytes_transferred);
|
||||
|
||||
void handle_send_http_response(lib::error_code const & ec);
|
||||
|
||||
void handle_write_http_response(lib::error_code const & ec);
|
||||
void handle_send_http_request(lib::error_code const & ec);
|
||||
|
||||
void handle_open_handshake_timeout(lib::error_code const & ec);
|
||||
void handle_close_handshake_timeout(lib::error_code const & ec);
|
||||
|
||||
void handle_read_frame(lib::error_code const & ec,
|
||||
size_t bytes_transferred);
|
||||
void handle_read_frame(lib::error_code const & ec, size_t bytes_transferred);
|
||||
void read_frame();
|
||||
|
||||
/// Get array of WebSocket protocol versions that this connection supports.
|
||||
const std::vector<int>& get_supported_versions() const;
|
||||
std::vector<int> const & get_supported_versions() const;
|
||||
|
||||
/// Sets the handler for a terminating connection. Should only be used
|
||||
/// internally by the endpoint class.
|
||||
@@ -1126,64 +1336,48 @@ public:
|
||||
* non-zero otherwise.
|
||||
*/
|
||||
void handle_write_frame(lib::error_code const & ec);
|
||||
// protected:
|
||||
// This set of methods would really like to be protected, but doing so
|
||||
// requires that the endpoint be able to friend the connection. This is
|
||||
// allowed with C++11, but not prior versions
|
||||
|
||||
/// Start the connection state machine
|
||||
void start();
|
||||
|
||||
/// Set Connection Handle
|
||||
/**
|
||||
* The connection handle is a token that can be shared outside the
|
||||
* WebSocket++ core for the purposes of identifying a connection and
|
||||
* sending it messages.
|
||||
*
|
||||
* @param hdl A connection_hdl that the connection will use to refer
|
||||
* to itself.
|
||||
*/
|
||||
void set_handle(connection_hdl hdl) {
|
||||
m_connection_hdl = hdl;
|
||||
transport_con_type::set_handle(hdl);
|
||||
}
|
||||
protected:
|
||||
void handle_transport_init(lib::error_code const & ec);
|
||||
|
||||
/// Set m_processor based on information in m_request. Set m_response
|
||||
/// status and return false on error.
|
||||
bool initialize_processor();
|
||||
/// status and return an error code indicating status.
|
||||
lib::error_code initialize_processor();
|
||||
|
||||
/// Perform WebSocket handshake validation of m_request using m_processor.
|
||||
/// set m_response and return false on error.
|
||||
bool process_handshake_request();
|
||||
|
||||
/// Atomically change the internal connection state.
|
||||
/**
|
||||
* @param req The required starting state. If the internal state does not
|
||||
* match req an exception is thrown.
|
||||
*
|
||||
* @param dest The state to change to.
|
||||
*
|
||||
* @param msg The message to include in the exception thrown
|
||||
*/
|
||||
void atomic_state_change(istate_type req, istate_type dest,
|
||||
std::string msg);
|
||||
|
||||
/// Atomically change the internal and external connection state.
|
||||
/**
|
||||
* @param ireq The required starting internal state. If the internal state
|
||||
* does not match ireq an exception is thrown.
|
||||
*
|
||||
* @param idest The internal state to change to.
|
||||
*
|
||||
* @param ereq The required starting external state. If the external state
|
||||
* does not match ereq an exception is thrown.
|
||||
*
|
||||
* @param edest The external state to change to.
|
||||
*
|
||||
* @param msg The message to include in the exception thrown
|
||||
*/
|
||||
void atomic_state_change(istate_type ireq, istate_type idest,
|
||||
session::state::value ereq, session::state::value edest,
|
||||
std::string msg);
|
||||
|
||||
/// Atomically read and compared the internal state.
|
||||
/**
|
||||
* @param req The state to test against. If the internal state does not
|
||||
* match req an exception is thrown.
|
||||
*
|
||||
* @param msg The message to include in the exception thrown
|
||||
*/
|
||||
void atomic_state_check(istate_type req, std::string msg);
|
||||
/// set m_response and return an error code indicating status.
|
||||
lib::error_code process_handshake_request();
|
||||
private:
|
||||
|
||||
|
||||
/// Completes m_response, serializes it, and sends it out on the wire.
|
||||
void send_http_response();
|
||||
void write_http_response(lib::error_code const & ec);
|
||||
|
||||
/// Sends an opening WebSocket connect request
|
||||
void send_http_request();
|
||||
|
||||
/// Alternate path for send_http_response in error conditions
|
||||
void send_http_response_error();
|
||||
/// Alternate path for write_http_response in error conditions
|
||||
void write_http_response_error(lib::error_code const & ec);
|
||||
|
||||
/// Process control message
|
||||
/**
|
||||
@@ -1203,7 +1397,7 @@ private:
|
||||
* @return A status code, zero on success, non-zero otherwise
|
||||
*/
|
||||
lib::error_code send_close_ack(close::status::value code =
|
||||
close::status::blank, std::string const & reason = "");
|
||||
close::status::blank, std::string const & reason = std::string());
|
||||
|
||||
/// Send close frame
|
||||
/**
|
||||
@@ -1221,7 +1415,7 @@ private:
|
||||
* @return A status code, zero on success, non-zero otherwise
|
||||
*/
|
||||
lib::error_code send_close_frame(close::status::value code =
|
||||
close::status::blank, std::string const & reason = "", bool ack = false,
|
||||
close::status::blank, std::string const & reason = std::string(), bool ack = false,
|
||||
bool terminal = false);
|
||||
|
||||
/// Get a pointer to a new WebSocket protocol processor for a given version
|
||||
@@ -1280,6 +1474,20 @@ private:
|
||||
* Includes: error code and message for why it was failed
|
||||
*/
|
||||
void log_fail_result();
|
||||
|
||||
/// Prints information about HTTP connections
|
||||
/**
|
||||
* Includes: TODO
|
||||
*/
|
||||
void log_http_result();
|
||||
|
||||
/// Prints information about an arbitrary error code on the specified channel
|
||||
template <typename error_type>
|
||||
void log_err(log::level l, char const * msg, error_type const & ec) {
|
||||
std::stringstream s;
|
||||
s << msg << " error: " << ec << " (" << ec.message() << ")";
|
||||
m_elog.write(l, s.str());
|
||||
}
|
||||
|
||||
// internal handler functions
|
||||
read_handler m_handle_read_frame;
|
||||
@@ -1307,6 +1515,7 @@ private:
|
||||
long m_open_handshake_timeout_dur;
|
||||
long m_close_handshake_timeout_dur;
|
||||
long m_pong_timeout_dur;
|
||||
size_t m_max_message_size;
|
||||
|
||||
/// External connection state
|
||||
/**
|
||||
@@ -1370,9 +1579,9 @@ private:
|
||||
*/
|
||||
std::vector<transport::buffer> m_send_buffer;
|
||||
|
||||
/// a pointer to hold on to the current message being written to keep it
|
||||
/// a list of pointers to hold on to the messages being written to keep them
|
||||
/// from going out of scope before the write is complete.
|
||||
message_ptr m_current_msg;
|
||||
std::vector<message_ptr> m_current_msgs;
|
||||
|
||||
/// True if there is currently an outstanding transport write
|
||||
/**
|
||||
@@ -1380,6 +1589,9 @@ private:
|
||||
*/
|
||||
bool m_write_flag;
|
||||
|
||||
/// True if this connection is presently reading new data
|
||||
bool m_read_flag;
|
||||
|
||||
// connection data
|
||||
request_type m_request;
|
||||
response_type m_response;
|
||||
@@ -1411,6 +1623,14 @@ private:
|
||||
|
||||
/// Detailed internal error code
|
||||
lib::error_code m_ec;
|
||||
|
||||
/// A flag that gets set once it is determined that the connection is an
|
||||
/// HTTP connection and not a WebSocket one.
|
||||
bool m_is_http;
|
||||
|
||||
/// A flag that gets set when the completion of an http connection is
|
||||
/// deferred until later.
|
||||
session::http_state::value m_http_state;
|
||||
|
||||
bool m_was_clean;
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Peter Thorson. All rights reserved.
|
||||
* Copyright (c) 2014, Peter Thorson. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
|
||||
+201
-15
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Peter Thorson. All rights reserved.
|
||||
* Copyright (c) 2014, Peter Thorson. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
@@ -29,11 +29,11 @@
|
||||
#define WEBSOCKETPP_ENDPOINT_HPP
|
||||
|
||||
#include <websocketpp/connection.hpp>
|
||||
|
||||
#include <websocketpp/logger/levels.hpp>
|
||||
#include <websocketpp/version.hpp>
|
||||
|
||||
#include <iostream>
|
||||
#include <set>
|
||||
#include <string>
|
||||
|
||||
namespace websocketpp {
|
||||
|
||||
@@ -85,25 +85,78 @@ public:
|
||||
// TODO: organize these
|
||||
typedef typename connection_type::termination_handler termination_handler;
|
||||
|
||||
typedef lib::shared_ptr<connection_weak_ptr> hdl_type;
|
||||
// This would be ideal. Requires C++11 though
|
||||
//friend connection;
|
||||
|
||||
explicit endpoint(bool is_server)
|
||||
: m_alog(config::alog_level, &std::cout)
|
||||
, m_elog(config::elog_level, &std::cerr)
|
||||
explicit endpoint(bool p_is_server)
|
||||
: m_alog(config::alog_level, log::channel_type_hint::access)
|
||||
, m_elog(config::elog_level, log::channel_type_hint::error)
|
||||
, m_user_agent(::websocketpp::user_agent)
|
||||
, m_open_handshake_timeout_dur(config::timeout_open_handshake)
|
||||
, m_close_handshake_timeout_dur(config::timeout_close_handshake)
|
||||
, m_pong_timeout_dur(config::timeout_pong)
|
||||
, m_is_server(is_server)
|
||||
, m_max_message_size(config::max_message_size)
|
||||
, m_max_http_body_size(config::max_http_body_size)
|
||||
, m_is_server(p_is_server)
|
||||
{
|
||||
m_alog.set_channels(config::alog_level);
|
||||
m_elog.set_channels(config::elog_level);
|
||||
|
||||
m_alog.write(log::alevel::devel,"endpoint constructor");
|
||||
m_alog.write(log::alevel::devel, "endpoint constructor");
|
||||
|
||||
transport_type::init_logging(&m_alog,&m_elog);
|
||||
transport_type::init_logging(&m_alog, &m_elog);
|
||||
}
|
||||
|
||||
|
||||
/// Destructor
|
||||
~endpoint<connection,config>() {}
|
||||
|
||||
#ifdef _WEBSOCKETPP_DEFAULT_DELETE_FUNCTIONS_
|
||||
// no copy constructor because endpoints are not copyable
|
||||
endpoint(endpoint &) = delete;
|
||||
|
||||
// no copy assignment operator because endpoints are not copyable
|
||||
endpoint & operator=(endpoint const &) = delete;
|
||||
#endif // _WEBSOCKETPP_DEFAULT_DELETE_FUNCTIONS_
|
||||
|
||||
#ifdef _WEBSOCKETPP_MOVE_SEMANTICS_
|
||||
/// Move constructor
|
||||
endpoint(endpoint && o)
|
||||
: config::transport_type(std::move(o))
|
||||
, config::endpoint_base(std::move(o))
|
||||
, m_alog(std::move(o.m_alog))
|
||||
, m_elog(std::move(o.m_elog))
|
||||
, m_user_agent(std::move(o.m_user_agent))
|
||||
, m_open_handler(std::move(o.m_open_handler))
|
||||
|
||||
, m_close_handler(std::move(o.m_close_handler))
|
||||
, m_fail_handler(std::move(o.m_fail_handler))
|
||||
, m_ping_handler(std::move(o.m_ping_handler))
|
||||
, m_pong_handler(std::move(o.m_pong_handler))
|
||||
, m_pong_timeout_handler(std::move(o.m_pong_timeout_handler))
|
||||
, m_interrupt_handler(std::move(o.m_interrupt_handler))
|
||||
, m_http_handler(std::move(o.m_http_handler))
|
||||
, m_validate_handler(std::move(o.m_validate_handler))
|
||||
, m_message_handler(std::move(o.m_message_handler))
|
||||
|
||||
, m_open_handshake_timeout_dur(o.m_open_handshake_timeout_dur)
|
||||
, m_close_handshake_timeout_dur(o.m_close_handshake_timeout_dur)
|
||||
, m_pong_timeout_dur(o.m_pong_timeout_dur)
|
||||
, m_max_message_size(o.m_max_message_size)
|
||||
, m_max_http_body_size(o.m_max_http_body_size)
|
||||
|
||||
, m_rng(std::move(o.m_rng))
|
||||
, m_is_server(o.m_is_server)
|
||||
{}
|
||||
|
||||
#ifdef _WEBSOCKETPP_DEFAULT_DELETE_FUNCTIONS_
|
||||
// no move assignment operator because of const member variables
|
||||
endpoint & operator=(endpoint &&) = delete;
|
||||
#endif // _WEBSOCKETPP_DEFAULT_DELETE_FUNCTIONS_
|
||||
|
||||
#endif // _WEBSOCKETPP_MOVE_SEMANTICS_
|
||||
|
||||
|
||||
/// Returns the user agent string that this endpoint will use
|
||||
/**
|
||||
* Returns the user agent string that this endpoint will use when creating
|
||||
@@ -272,9 +325,9 @@ public:
|
||||
m_message_handler = h;
|
||||
}
|
||||
|
||||
/////////////////////////
|
||||
// Connection timeouts //
|
||||
/////////////////////////
|
||||
//////////////////////////////////////////
|
||||
// Connection timeouts and other limits //
|
||||
//////////////////////////////////////////
|
||||
|
||||
/// Set open handshake timeout
|
||||
/**
|
||||
@@ -348,6 +401,72 @@ public:
|
||||
m_pong_timeout_dur = dur;
|
||||
}
|
||||
|
||||
/// Get default maximum message size
|
||||
/**
|
||||
* Get the default maximum message size that will be used for new
|
||||
* connections created by this endpoint. The maximum message size determines
|
||||
* the point at which the connection will fail a connection with the
|
||||
* message_too_big protocol error.
|
||||
*
|
||||
* The default is set by the max_message_size value from the template config
|
||||
*
|
||||
* @since 0.3.0
|
||||
*/
|
||||
size_t get_max_message_size() const {
|
||||
return m_max_message_size;
|
||||
}
|
||||
|
||||
/// Set default maximum message size
|
||||
/**
|
||||
* Set the default maximum message size that will be used for new
|
||||
* connections created by this endpoint. Maximum message size determines the
|
||||
* point at which the connection will fail a connection with the
|
||||
* message_too_big protocol error.
|
||||
*
|
||||
* The default is set by the max_message_size value from the template config
|
||||
*
|
||||
* @since 0.3.0
|
||||
*
|
||||
* @param new_value The value to set as the maximum message size.
|
||||
*/
|
||||
void set_max_message_size(size_t new_value) {
|
||||
m_max_message_size = new_value;
|
||||
}
|
||||
|
||||
/// Get maximum HTTP message body size
|
||||
/**
|
||||
* Get maximum HTTP message body size. Maximum message body size determines
|
||||
* the point at which the connection will stop reading an HTTP request whose
|
||||
* body is too large.
|
||||
*
|
||||
* The default is set by the max_http_body_size value from the template
|
||||
* config
|
||||
*
|
||||
* @since 0.5.0
|
||||
*
|
||||
* @return The maximum HTTP message body size
|
||||
*/
|
||||
size_t get_max_http_body_size() const {
|
||||
return m_max_http_body_size;
|
||||
}
|
||||
|
||||
/// Set maximum HTTP message body size
|
||||
/**
|
||||
* Set maximum HTTP message body size. Maximum message body size determines
|
||||
* the point at which the connection will stop reading an HTTP request whose
|
||||
* body is too large.
|
||||
*
|
||||
* The default is set by the max_http_body_size value from the template
|
||||
* config
|
||||
*
|
||||
* @since 0.5.1
|
||||
*
|
||||
* @param new_value The value to set as the maximum message size.
|
||||
*/
|
||||
void set_max_http_body_size(size_t new_value) {
|
||||
m_max_http_body_size = new_value;
|
||||
}
|
||||
|
||||
/*************************************/
|
||||
/* Connection pass through functions */
|
||||
/*************************************/
|
||||
@@ -363,6 +482,72 @@ public:
|
||||
void interrupt(connection_hdl hdl, lib::error_code & ec);
|
||||
void interrupt(connection_hdl hdl);
|
||||
|
||||
/// Pause reading of new data (exception free)
|
||||
/**
|
||||
* Signals to the connection to halt reading of new data. While reading is
|
||||
* paused, the connection will stop reading from its associated socket. In
|
||||
* turn this will result in TCP based flow control kicking in and slowing
|
||||
* data flow from the remote endpoint.
|
||||
*
|
||||
* This is useful for applications that push new requests to a queue to be
|
||||
* processed by another thread and need a way to signal when their request
|
||||
* queue is full without blocking the network processing thread.
|
||||
*
|
||||
* Use `resume_reading()` to resume.
|
||||
*
|
||||
* If supported by the transport this is done asynchronously. As such
|
||||
* reading may not stop until the current read operation completes.
|
||||
* Typically you can expect to receive no more bytes after initiating a read
|
||||
* pause than the size of the read buffer.
|
||||
*
|
||||
* If reading is paused for this connection already nothing is changed.
|
||||
*/
|
||||
void pause_reading(connection_hdl hdl, lib::error_code & ec);
|
||||
|
||||
/// Pause reading of new data
|
||||
void pause_reading(connection_hdl hdl);
|
||||
|
||||
/// Resume reading of new data (exception free)
|
||||
/**
|
||||
* Signals to the connection to resume reading of new data after it was
|
||||
* paused by `pause_reading()`.
|
||||
*
|
||||
* If reading is not paused for this connection already nothing is changed.
|
||||
*/
|
||||
void resume_reading(connection_hdl hdl, lib::error_code & ec);
|
||||
|
||||
/// Resume reading of new data
|
||||
void resume_reading(connection_hdl hdl);
|
||||
|
||||
/// Send deferred HTTP Response
|
||||
/**
|
||||
* Sends an http response to an HTTP connection that was deferred. This will
|
||||
* send a complete response including all headers, status line, and body
|
||||
* text. The connection will be closed afterwards.
|
||||
*
|
||||
* Exception free variant
|
||||
*
|
||||
* @since 0.6.0
|
||||
*
|
||||
* @param hdl The connection to send the response on
|
||||
* @param ec A status code, zero on success, non-zero otherwise
|
||||
*/
|
||||
void send_http_response(connection_hdl hdl, lib::error_code & ec);
|
||||
|
||||
/// Send deferred HTTP Response (exception free)
|
||||
/**
|
||||
* Sends an http response to an HTTP connection that was deferred. This will
|
||||
* send a complete response including all headers, status line, and body
|
||||
* text. The connection will be closed afterwards.
|
||||
*
|
||||
* Exception variant
|
||||
*
|
||||
* @since 0.6.0
|
||||
*
|
||||
* @param hdl The connection to send the response on
|
||||
*/
|
||||
void send_http_response(connection_hdl hdl);
|
||||
|
||||
/// Create a message and add it to the outgoing send queue (exception free)
|
||||
/**
|
||||
* Convenience method to send a message given a payload string and an opcode
|
||||
@@ -456,7 +641,6 @@ public:
|
||||
* @return the connection_ptr. May be NULL if the handle was invalid.
|
||||
*/
|
||||
connection_ptr get_con_from_hdl(connection_hdl hdl, lib::error_code & ec) {
|
||||
scoped_lock_type lock(m_mutex);
|
||||
connection_ptr con = lib::static_pointer_cast<connection_type>(
|
||||
hdl.lock());
|
||||
if (!con) {
|
||||
@@ -470,7 +654,7 @@ public:
|
||||
lib::error_code ec;
|
||||
connection_ptr con = this->get_con_from_hdl(hdl,ec);
|
||||
if (ec) {
|
||||
throw ec;
|
||||
throw exception(ec);
|
||||
}
|
||||
return con;
|
||||
}
|
||||
@@ -497,6 +681,8 @@ private:
|
||||
long m_open_handshake_timeout_dur;
|
||||
long m_close_handshake_timeout_dur;
|
||||
long m_pong_timeout_dur;
|
||||
size_t m_max_message_size;
|
||||
size_t m_max_http_body_size;
|
||||
|
||||
rng_type m_rng;
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Peter Thorson. All rights reserved.
|
||||
* Copyright (c) 2014, Peter Thorson. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
|
||||
+60
-10
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Peter Thorson. All rights reserved.
|
||||
* Copyright (c) 2014, Peter Thorson. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
@@ -28,7 +28,9 @@
|
||||
#ifndef WEBSOCKETPP_ERROR_HPP
|
||||
#define WEBSOCKETPP_ERROR_HPP
|
||||
|
||||
#include <exception>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
#include <websocketpp/common/cpp11.hpp>
|
||||
#include <websocketpp/common/system_error.hpp>
|
||||
@@ -38,7 +40,7 @@ namespace websocketpp {
|
||||
/// Combination error code / string type for returning two values
|
||||
typedef std::pair<lib::error_code,std::string> err_str_pair;
|
||||
|
||||
// setup for errors that should be propogated back to the user.
|
||||
/// Library level error codes
|
||||
namespace error {
|
||||
enum value {
|
||||
/// Catch-all library error
|
||||
@@ -86,7 +88,8 @@ enum value {
|
||||
/// Invalid subprotocol
|
||||
invalid_subprotocol,
|
||||
|
||||
/// Bad or unknown connection
|
||||
/// An operation was attempted on a connection that did not exist or was
|
||||
/// already deleted.
|
||||
bad_connection,
|
||||
|
||||
/// Unit testing utility error code
|
||||
@@ -114,7 +117,33 @@ enum value {
|
||||
close_handshake_timeout,
|
||||
|
||||
/// Invalid port in URI
|
||||
invalid_port
|
||||
invalid_port,
|
||||
|
||||
/// An async accept operation failed because the underlying transport has been
|
||||
/// requested to not listen for new connections anymore.
|
||||
async_accept_not_listening,
|
||||
|
||||
/// The requested operation was canceled
|
||||
operation_canceled,
|
||||
|
||||
/// Connection rejected
|
||||
rejected,
|
||||
|
||||
/// Upgrade Required. This happens if an HTTP request is made to a
|
||||
/// WebSocket++ server that doesn't implement an http handler
|
||||
upgrade_required,
|
||||
|
||||
/// Invalid WebSocket protocol version
|
||||
invalid_version,
|
||||
|
||||
/// Unsupported WebSocket protocol version
|
||||
unsupported_version,
|
||||
|
||||
/// HTTP parse error
|
||||
http_parse_error,
|
||||
|
||||
/// Extension negotiation failed
|
||||
extension_neg_failed
|
||||
}; // enum value
|
||||
|
||||
|
||||
@@ -176,6 +205,22 @@ public:
|
||||
return "The closing handshake timed out";
|
||||
case error::invalid_port:
|
||||
return "Invalid URI port";
|
||||
case error::async_accept_not_listening:
|
||||
return "Async Accept not listening";
|
||||
case error::operation_canceled:
|
||||
return "Operation canceled";
|
||||
case error::rejected:
|
||||
return "Connection rejected";
|
||||
case error::upgrade_required:
|
||||
return "Upgrade required";
|
||||
case error::invalid_version:
|
||||
return "Invalid version";
|
||||
case error::unsupported_version:
|
||||
return "Unsupported version";
|
||||
case error::http_parse_error:
|
||||
return "HTTP parse error";
|
||||
case error::extension_neg_failed:
|
||||
return "Extension negotiation failed";
|
||||
default:
|
||||
return "Unknown";
|
||||
}
|
||||
@@ -205,21 +250,26 @@ namespace websocketpp {
|
||||
|
||||
class exception : public std::exception {
|
||||
public:
|
||||
exception(std::string const & msg,
|
||||
error::value code = error::general)
|
||||
: m_msg(msg),m_code(code) {}
|
||||
exception(std::string const & msg, lib::error_code ec = make_error_code(error::general))
|
||||
: m_msg(msg.empty() ? ec.message() : msg), m_code(ec)
|
||||
{}
|
||||
|
||||
explicit exception(lib::error_code ec)
|
||||
: m_msg(ec.message()), m_code(ec)
|
||||
{}
|
||||
|
||||
~exception() throw() {}
|
||||
|
||||
virtual char const * what() const throw() {
|
||||
return m_msg.c_str();
|
||||
}
|
||||
|
||||
error::value code() const throw() {
|
||||
lib::error_code code() const throw() {
|
||||
return m_code;
|
||||
}
|
||||
|
||||
std::string m_msg;
|
||||
error::value m_code;
|
||||
const std::string m_msg;
|
||||
lib::error_code m_code;
|
||||
};
|
||||
|
||||
} // namespace websocketpp
|
||||
|
||||
@@ -1,71 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2012, Peter Thorson. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the WebSocket++ Project nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef WEBSOCKETPP_ERROR_MESSAGE_HPP
|
||||
#define WEBSOCKETPP_ERROR_MESSAGE_HPP
|
||||
|
||||
namespace websocketpp {
|
||||
|
||||
/**
|
||||
* The transport::security::* classes are a set of security/socket related
|
||||
* policies and support code for the ASIO transport types.
|
||||
*/
|
||||
class error_msg {
|
||||
public:
|
||||
const std::string& get_msg() const {
|
||||
return m_error_msg;
|
||||
}
|
||||
|
||||
void set_msg(const std::string& msg) {
|
||||
m_error_msg = msg;
|
||||
}
|
||||
|
||||
void append_msg(const std::string& msg) {
|
||||
m_error_msg.append(msg);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void set_msg(const T& thing) {
|
||||
std::stringsteam val;
|
||||
val << thing;
|
||||
this->set_msg(val.str());
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void append_msg(const T& thing) {
|
||||
std::stringsteam val;
|
||||
val << thing;
|
||||
this->append_msg(val.str());
|
||||
}
|
||||
private:
|
||||
// error resources
|
||||
std::string m_error_msg;
|
||||
};
|
||||
|
||||
} // namespace websocketpp
|
||||
|
||||
#endif // WEBSOCKETPP_ERROR_MESSAGE_HPP
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Peter Thorson. All rights reserved.
|
||||
* Copyright (c) 2014, Peter Thorson. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
@@ -78,7 +78,7 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
inline const lib::error_category& get_category() {
|
||||
inline lib::error_category const & get_category() {
|
||||
static category instance;
|
||||
return instance;
|
||||
}
|
||||
|
||||
+47
-10
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Peter Thorson. All rights reserved.
|
||||
* Copyright (c) 2014, Peter Thorson. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
@@ -53,10 +53,29 @@ class disabled {
|
||||
typedef std::pair<lib::error_code,std::string> err_str_pair;
|
||||
|
||||
public:
|
||||
err_str_pair negotiate(http::attribute_list const & attributes) {
|
||||
/// Negotiate extension
|
||||
/**
|
||||
* The disabled extension always fails the negotiation with a disabled
|
||||
* error.
|
||||
*
|
||||
* @param offer Attribute from client's offer
|
||||
* @return Status code and value to return to remote endpoint
|
||||
*/
|
||||
err_str_pair negotiate(http::attribute_list const &) {
|
||||
return make_pair(make_error_code(error::disabled),std::string());
|
||||
}
|
||||
|
||||
/// Initialize state
|
||||
/**
|
||||
* For the disabled extension state initialization is a no-op.
|
||||
*
|
||||
* @param is_server True to initialize as a server, false for a client.
|
||||
* @return A code representing the error that occurred, if any
|
||||
*/
|
||||
lib::error_code init(bool) {
|
||||
return lib::error_code();
|
||||
}
|
||||
|
||||
/// Returns true if the extension is capable of providing
|
||||
/// permessage_deflate functionality
|
||||
bool is_implemented() const {
|
||||
@@ -69,17 +88,35 @@ public:
|
||||
return false;
|
||||
}
|
||||
|
||||
lib::error_code compress(std::string const & in, std::string & out) {
|
||||
/// Generate extension offer
|
||||
/**
|
||||
* Creates an offer string to include in the Sec-WebSocket-Extensions
|
||||
* header of outgoing client requests.
|
||||
*
|
||||
* @return A WebSocket extension offer string for this extension
|
||||
*/
|
||||
std::string generate_offer() const {
|
||||
return "";
|
||||
}
|
||||
|
||||
/// Compress bytes
|
||||
/**
|
||||
* @param [in] in String to compress
|
||||
* @param [out] out String to append compressed bytes to
|
||||
* @return Error or status code
|
||||
*/
|
||||
lib::error_code compress(std::string const &, std::string &) {
|
||||
return make_error_code(error::disabled);
|
||||
}
|
||||
|
||||
lib::error_code decompress(uint8_t const * buf, size_t len,
|
||||
std::string & out)
|
||||
{
|
||||
return make_error_code(error::disabled);
|
||||
}
|
||||
|
||||
lib::error_code decompress(std::string const & in, std::string & out) {
|
||||
/// Decompress bytes
|
||||
/**
|
||||
* @param buf Byte buffer to decompress
|
||||
* @param len Length of buf
|
||||
* @param out String to append decompressed bytes to
|
||||
* @return Error or status code
|
||||
*/
|
||||
lib::error_code decompress(uint8_t const *, size_t, std::string &) {
|
||||
return make_error_code(error::disabled);
|
||||
}
|
||||
};
|
||||
|
||||
+136
-108
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Peter Thorson. All rights reserved.
|
||||
* Copyright (c) 2015, Peter Thorson. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
@@ -28,8 +28,10 @@
|
||||
#ifndef WEBSOCKETPP_PROCESSOR_EXTENSION_PERMESSAGEDEFLATE_HPP
|
||||
#define WEBSOCKETPP_PROCESSOR_EXTENSION_PERMESSAGEDEFLATE_HPP
|
||||
|
||||
|
||||
#include <websocketpp/common/cpp11.hpp>
|
||||
#include <websocketpp/common/memory.hpp>
|
||||
#include <websocketpp/common/platforms.hpp>
|
||||
#include <websocketpp/common/system_error.hpp>
|
||||
#include <websocketpp/error.hpp>
|
||||
|
||||
@@ -44,10 +46,14 @@
|
||||
namespace websocketpp {
|
||||
namespace extensions {
|
||||
|
||||
/// Implimentation of the draft permessage-deflate WebSocket extension
|
||||
/// Implementation of the draft permessage-deflate WebSocket extension
|
||||
/**
|
||||
* ### permessage-deflate interface
|
||||
*
|
||||
* **init**\n
|
||||
* `lib::error_code init(bool is_server)`\n
|
||||
* Performs initialization
|
||||
*
|
||||
* **is_implimented**\n
|
||||
* `bool is_implimented()`\n
|
||||
* Returns whether or not the object impliments the extension or not
|
||||
@@ -134,7 +140,7 @@ public:
|
||||
case zlib_error:
|
||||
return "A zlib function returned an error";
|
||||
case uninitialized:
|
||||
return "Object must be initialized before use";
|
||||
return "Deflate extension must be initialized before use";
|
||||
default:
|
||||
return "Unknown permessage-compress error";
|
||||
}
|
||||
@@ -142,13 +148,13 @@ public:
|
||||
};
|
||||
|
||||
/// Get a reference to a static copy of the permessage-deflate error category
|
||||
lib::error_category const & get_category() {
|
||||
inline lib::error_category const & get_category() {
|
||||
static category instance;
|
||||
return instance;
|
||||
}
|
||||
|
||||
/// Create an error code in the permessage-deflate category
|
||||
lib::error_code make_error_code(error::value e) {
|
||||
inline lib::error_code make_error_code(error::value e) {
|
||||
return lib::error_code(static_cast<int>(e), get_category());
|
||||
}
|
||||
|
||||
@@ -168,19 +174,19 @@ namespace websocketpp {
|
||||
namespace extensions {
|
||||
namespace permessage_deflate {
|
||||
|
||||
/// Default value for s2c_max_window_bits as defined by RFC6455
|
||||
static uint8_t const default_s2c_max_window_bits = 15;
|
||||
/// Minimum value for s2c_max_window_bits as defined by RFC6455
|
||||
static uint8_t const min_s2c_max_window_bits = 8;
|
||||
/// Maximum value for s2c_max_window_bits as defined by RFC6455
|
||||
static uint8_t const max_s2c_max_window_bits = 15;
|
||||
/// Default value for server_max_window_bits as defined by draft 17
|
||||
static uint8_t const default_server_max_window_bits = 15;
|
||||
/// Minimum value for server_max_window_bits as defined by draft 17
|
||||
static uint8_t const min_server_max_window_bits = 8;
|
||||
/// Maximum value for server_max_window_bits as defined by draft 17
|
||||
static uint8_t const max_server_max_window_bits = 15;
|
||||
|
||||
/// Default value for c2s_max_window_bits as defined by RFC6455
|
||||
static uint8_t const default_c2s_max_window_bits = 15;
|
||||
/// Minimum value for c2s_max_window_bits as defined by RFC6455
|
||||
static uint8_t const min_c2s_max_window_bits = 8;
|
||||
/// Maximum value for c2s_max_window_bits as defined by RFC6455
|
||||
static uint8_t const max_c2s_max_window_bits = 15;
|
||||
/// Default value for client_max_window_bits as defined by draft 17
|
||||
static uint8_t const default_client_max_window_bits = 15;
|
||||
/// Minimum value for client_max_window_bits as defined by draft 17
|
||||
static uint8_t const min_client_max_window_bits = 8;
|
||||
/// Maximum value for client_max_window_bits as defined by draft 17
|
||||
static uint8_t const max_client_max_window_bits = 15;
|
||||
|
||||
namespace mode {
|
||||
enum value {
|
||||
@@ -200,12 +206,12 @@ class enabled {
|
||||
public:
|
||||
enabled()
|
||||
: m_enabled(false)
|
||||
, m_s2c_no_context_takeover(false)
|
||||
, m_c2s_no_context_takeover(false)
|
||||
, m_s2c_max_window_bits(15)
|
||||
, m_c2s_max_window_bits(15)
|
||||
, m_s2c_max_window_bits_mode(mode::accept)
|
||||
, m_c2s_max_window_bits_mode(mode::accept)
|
||||
, m_server_no_context_takeover(false)
|
||||
, m_client_no_context_takeover(false)
|
||||
, m_server_max_window_bits(15)
|
||||
, m_client_max_window_bits(15)
|
||||
, m_server_max_window_bits_mode(mode::accept)
|
||||
, m_client_max_window_bits_mode(mode::accept)
|
||||
, m_initialized(false)
|
||||
, m_compress_buffer_size(16384)
|
||||
{
|
||||
@@ -242,20 +248,25 @@ public:
|
||||
|
||||
/// Initialize zlib state
|
||||
/**
|
||||
* Note: this should be called *after* the negotiation methods. It will use
|
||||
* information from the negotiation to determine how to initialize the zlib
|
||||
* data structures.
|
||||
*
|
||||
* @todo memory level, strategy, etc are hardcoded
|
||||
* @todo server detection is hardcoded
|
||||
*
|
||||
* @param is_server True to initialize as a server, false for a client.
|
||||
* @return A code representing the error that occurred, if any
|
||||
*/
|
||||
lib::error_code init() {
|
||||
lib::error_code init(bool is_server) {
|
||||
uint8_t deflate_bits;
|
||||
uint8_t inflate_bits;
|
||||
|
||||
if (true /*is_server*/) {
|
||||
deflate_bits = m_s2c_max_window_bits;
|
||||
inflate_bits = m_c2s_max_window_bits;
|
||||
if (is_server) {
|
||||
deflate_bits = m_server_max_window_bits;
|
||||
inflate_bits = m_client_max_window_bits;
|
||||
} else {
|
||||
deflate_bits = m_c2s_max_window_bits;
|
||||
inflate_bits = m_s2c_max_window_bits;
|
||||
deflate_bits = m_client_max_window_bits;
|
||||
inflate_bits = m_server_max_window_bits;
|
||||
}
|
||||
|
||||
int ret = deflateInit2(
|
||||
@@ -263,8 +274,8 @@ public:
|
||||
Z_DEFAULT_COMPRESSION,
|
||||
Z_DEFLATED,
|
||||
-1*deflate_bits,
|
||||
8, // memory level 1-9
|
||||
/*Z_DEFAULT_STRATEGY*/Z_FIXED
|
||||
4, // memory level 1-9
|
||||
Z_DEFAULT_STRATEGY
|
||||
);
|
||||
|
||||
if (ret != Z_OK) {
|
||||
@@ -281,15 +292,22 @@ public:
|
||||
}
|
||||
|
||||
m_compress_buffer.reset(new unsigned char[m_compress_buffer_size]);
|
||||
if ((m_server_no_context_takeover && is_server) ||
|
||||
(m_client_no_context_takeover && !is_server))
|
||||
{
|
||||
m_flush = Z_FULL_FLUSH;
|
||||
} else {
|
||||
m_flush = Z_SYNC_FLUSH;
|
||||
}
|
||||
m_initialized = true;
|
||||
return lib::error_code();
|
||||
}
|
||||
|
||||
/// Test if this object impliments the permessage-deflate specification
|
||||
/// Test if this object implements the permessage-deflate specification
|
||||
/**
|
||||
* Because this object does impliment it, it will always return true.
|
||||
* Because this object does implieent it, it will always return true.
|
||||
*
|
||||
* @return Whether or not this object impliments permessage-deflate
|
||||
* @return Whether or not this object implements permessage-deflate
|
||||
*/
|
||||
bool is_implemented() const {
|
||||
return true;
|
||||
@@ -327,8 +345,8 @@ public:
|
||||
* the option will be in use so they can optimize resource usage if they
|
||||
* are able.
|
||||
*/
|
||||
void enable_s2c_no_context_takeover() {
|
||||
m_s2c_no_context_takeover = true;
|
||||
void enable_server_no_context_takeover() {
|
||||
m_server_no_context_takeover = true;
|
||||
}
|
||||
|
||||
/// Reset client's outgoing LZ77 sliding window for each new message
|
||||
@@ -346,8 +364,8 @@ public:
|
||||
* This option is supported by all compliant clients and servers. Enabling
|
||||
* it via either endpoint should be sufficient to ensure it is used.
|
||||
*/
|
||||
void enable_c2s_no_context_takeover() {
|
||||
m_c2s_no_context_takeover = true;
|
||||
void enable_client_no_context_takeover() {
|
||||
m_client_no_context_takeover = true;
|
||||
}
|
||||
|
||||
/// Limit server LZ77 sliding window size
|
||||
@@ -372,12 +390,12 @@ public:
|
||||
* @param mode The mode to use for negotiating this parameter
|
||||
* @return A status code
|
||||
*/
|
||||
lib::error_code set_s2c_max_window_bits(uint8_t bits, mode::value mode) {
|
||||
if (bits < min_s2c_max_window_bits || bits > max_s2c_max_window_bits) {
|
||||
lib::error_code set_server_max_window_bits(uint8_t bits, mode::value mode) {
|
||||
if (bits < min_server_max_window_bits || bits > max_server_max_window_bits) {
|
||||
return error::make_error_code(error::invalid_max_window_bits);
|
||||
}
|
||||
m_s2c_max_window_bits = bits;
|
||||
m_s2c_max_window_bits_mode = mode;
|
||||
m_server_max_window_bits = bits;
|
||||
m_server_max_window_bits_mode = mode;
|
||||
|
||||
return lib::error_code();
|
||||
}
|
||||
@@ -403,12 +421,12 @@ public:
|
||||
* @param mode The mode to use for negotiating this parameter
|
||||
* @return A status code
|
||||
*/
|
||||
lib::error_code set_c2s_max_window_bits(uint8_t bits, mode::value mode) {
|
||||
if (bits < min_c2s_max_window_bits || bits > max_c2s_max_window_bits) {
|
||||
lib::error_code set_client_max_window_bits(uint8_t bits, mode::value mode) {
|
||||
if (bits < min_client_max_window_bits || bits > max_client_max_window_bits) {
|
||||
return error::make_error_code(error::invalid_max_window_bits);
|
||||
}
|
||||
m_c2s_max_window_bits = bits;
|
||||
m_c2s_max_window_bits_mode = mode;
|
||||
m_client_max_window_bits = bits;
|
||||
m_client_max_window_bits_mode = mode;
|
||||
|
||||
return lib::error_code();
|
||||
}
|
||||
@@ -421,7 +439,8 @@ public:
|
||||
* @return A WebSocket extension offer string for this extension
|
||||
*/
|
||||
std::string generate_offer() const {
|
||||
return "";
|
||||
// TODO: this should be dynamically generated based on user settings
|
||||
return "permessage-deflate; client_no_context_takeover; client_max_window_bits";
|
||||
}
|
||||
|
||||
/// Validate extension response
|
||||
@@ -432,8 +451,8 @@ public:
|
||||
* @param response The server response attribute list to validate
|
||||
* @return Validation error or 0 on success
|
||||
*/
|
||||
lib::error_code validate_offer(http::attribute_list const & response) {
|
||||
|
||||
lib::error_code validate_offer(http::attribute_list const &) {
|
||||
return lib::error_code();
|
||||
}
|
||||
|
||||
/// Negotiate extension
|
||||
@@ -450,14 +469,14 @@ public:
|
||||
|
||||
http::attribute_list::const_iterator it;
|
||||
for (it = offer.begin(); it != offer.end(); ++it) {
|
||||
if (it->first == "s2c_no_context_takeover") {
|
||||
negotiate_s2c_no_context_takeover(it->second,ret.first);
|
||||
} else if (it->first == "c2s_no_context_takeover") {
|
||||
negotiate_c2s_no_context_takeover(it->second,ret.first);
|
||||
} else if (it->first == "s2c_max_window_bits") {
|
||||
negotiate_s2c_max_window_bits(it->second,ret.first);
|
||||
} else if (it->first == "c2s_max_window_bits") {
|
||||
negotiate_c2s_max_window_bits(it->second,ret.first);
|
||||
if (it->first == "server_no_context_takeover") {
|
||||
negotiate_server_no_context_takeover(it->second,ret.first);
|
||||
} else if (it->first == "client_no_context_takeover") {
|
||||
negotiate_client_no_context_takeover(it->second,ret.first);
|
||||
} else if (it->first == "server_max_window_bits") {
|
||||
negotiate_server_max_window_bits(it->second,ret.first);
|
||||
} else if (it->first == "client_max_window_bits") {
|
||||
negotiate_client_max_window_bits(it->second,ret.first);
|
||||
} else {
|
||||
ret.first = make_error_code(error::invalid_attributes);
|
||||
}
|
||||
@@ -477,6 +496,9 @@ public:
|
||||
|
||||
/// Compress bytes
|
||||
/**
|
||||
* @todo: avail_in/out is 32 bit, need to fix for cases of >32 bit frames
|
||||
* on 64 bit machines.
|
||||
*
|
||||
* @param [in] in String to compress
|
||||
* @param [out] out String to append compressed bytes to
|
||||
* @return Error or status code
|
||||
@@ -487,9 +509,14 @@ public:
|
||||
}
|
||||
|
||||
size_t output;
|
||||
int ret;
|
||||
|
||||
m_dstate.avail_out = m_compress_buffer_size;
|
||||
if (in.empty()) {
|
||||
uint8_t buf[6] = {0x02, 0x00, 0x00, 0x00, 0xff, 0xff};
|
||||
out.append((char *)(buf),6);
|
||||
return lib::error_code();
|
||||
}
|
||||
|
||||
m_dstate.avail_in = in.size();
|
||||
m_dstate.next_in = (unsigned char *)(const_cast<char *>(in.data()));
|
||||
|
||||
do {
|
||||
@@ -497,7 +524,7 @@ public:
|
||||
m_dstate.avail_out = m_compress_buffer_size;
|
||||
m_dstate.next_out = m_compress_buffer.get();
|
||||
|
||||
ret = deflate(&m_dstate, Z_SYNC_FLUSH);
|
||||
deflate(&m_dstate, m_flush);
|
||||
|
||||
output = m_compress_buffer_size - m_dstate.avail_out;
|
||||
|
||||
@@ -552,35 +579,35 @@ private:
|
||||
std::string generate_response() {
|
||||
std::string ret = "permessage-deflate";
|
||||
|
||||
if (m_s2c_no_context_takeover) {
|
||||
ret += "; s2c_no_context_takeover";
|
||||
if (m_server_no_context_takeover) {
|
||||
ret += "; server_no_context_takeover";
|
||||
}
|
||||
|
||||
if (m_c2s_no_context_takeover) {
|
||||
ret += "; c2s_no_context_takeover";
|
||||
if (m_client_no_context_takeover) {
|
||||
ret += "; client_no_context_takeover";
|
||||
}
|
||||
|
||||
if (m_s2c_max_window_bits < default_s2c_max_window_bits) {
|
||||
if (m_server_max_window_bits < default_server_max_window_bits) {
|
||||
std::stringstream s;
|
||||
s << int(m_s2c_max_window_bits);
|
||||
ret += "; s2c_max_window_bits="+s.str();
|
||||
s << int(m_server_max_window_bits);
|
||||
ret += "; server_max_window_bits="+s.str();
|
||||
}
|
||||
|
||||
if (m_c2s_max_window_bits < default_c2s_max_window_bits) {
|
||||
if (m_client_max_window_bits < default_client_max_window_bits) {
|
||||
std::stringstream s;
|
||||
s << int(m_c2s_max_window_bits);
|
||||
ret += "; c2s_max_window_bits="+s.str();
|
||||
s << int(m_client_max_window_bits);
|
||||
ret += "; client_max_window_bits="+s.str();
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/// Negotiate s2c_no_context_takeover attribute
|
||||
/// Negotiate server_no_context_takeover attribute
|
||||
/**
|
||||
* @param [in] value The value of the attribute from the offer
|
||||
* @param [out] ec A reference to the error code to return errors via
|
||||
*/
|
||||
void negotiate_s2c_no_context_takeover(std::string const & value,
|
||||
void negotiate_server_no_context_takeover(std::string const & value,
|
||||
lib::error_code & ec)
|
||||
{
|
||||
if (!value.empty()) {
|
||||
@@ -588,15 +615,15 @@ private:
|
||||
return;
|
||||
}
|
||||
|
||||
m_s2c_no_context_takeover = true;
|
||||
m_server_no_context_takeover = true;
|
||||
}
|
||||
|
||||
/// Negotiate c2s_no_context_takeover attribute
|
||||
/// Negotiate client_no_context_takeover attribute
|
||||
/**
|
||||
* @param [in] value The value of the attribute from the offer
|
||||
* @param [out] ec A reference to the error code to return errors via
|
||||
*/
|
||||
void negotiate_c2s_no_context_takeover(std::string const & value,
|
||||
void negotiate_client_no_context_takeover(std::string const & value,
|
||||
lib::error_code & ec)
|
||||
{
|
||||
if (!value.empty()) {
|
||||
@@ -604,13 +631,13 @@ private:
|
||||
return;
|
||||
}
|
||||
|
||||
m_c2s_no_context_takeover = true;
|
||||
m_client_no_context_takeover = true;
|
||||
}
|
||||
|
||||
/// Negotiate s2c_max_window_bits attribute
|
||||
/// Negotiate server_max_window_bits attribute
|
||||
/**
|
||||
* When this method starts, m_s2c_max_window_bits will contain the server's
|
||||
* preferred value and m_s2c_max_window_bits_mode will contain the mode the
|
||||
* When this method starts, m_server_max_window_bits will contain the server's
|
||||
* preferred value and m_server_max_window_bits_mode will contain the mode the
|
||||
* server wants to use to for negotiation. `value` contains the value the
|
||||
* client requested that we use.
|
||||
*
|
||||
@@ -623,39 +650,39 @@ private:
|
||||
* @param [in] value The value of the attribute from the offer
|
||||
* @param [out] ec A reference to the error code to return errors via
|
||||
*/
|
||||
void negotiate_s2c_max_window_bits(std::string const & value,
|
||||
void negotiate_server_max_window_bits(std::string const & value,
|
||||
lib::error_code & ec)
|
||||
{
|
||||
uint8_t bits = uint8_t(atoi(value.c_str()));
|
||||
|
||||
if (bits < min_s2c_max_window_bits || bits > max_s2c_max_window_bits) {
|
||||
if (bits < min_server_max_window_bits || bits > max_server_max_window_bits) {
|
||||
ec = make_error_code(error::invalid_attribute_value);
|
||||
m_s2c_max_window_bits = default_s2c_max_window_bits;
|
||||
m_server_max_window_bits = default_server_max_window_bits;
|
||||
return;
|
||||
}
|
||||
|
||||
switch (m_s2c_max_window_bits_mode) {
|
||||
switch (m_server_max_window_bits_mode) {
|
||||
case mode::decline:
|
||||
m_s2c_max_window_bits = default_s2c_max_window_bits;
|
||||
m_server_max_window_bits = default_server_max_window_bits;
|
||||
break;
|
||||
case mode::accept:
|
||||
m_s2c_max_window_bits = bits;
|
||||
m_server_max_window_bits = bits;
|
||||
break;
|
||||
case mode::largest:
|
||||
m_s2c_max_window_bits = std::min(bits,m_s2c_max_window_bits);
|
||||
m_server_max_window_bits = std::min(bits,m_server_max_window_bits);
|
||||
break;
|
||||
case mode::smallest:
|
||||
m_s2c_max_window_bits = min_s2c_max_window_bits;
|
||||
m_server_max_window_bits = min_server_max_window_bits;
|
||||
break;
|
||||
default:
|
||||
ec = make_error_code(error::invalid_mode);
|
||||
m_s2c_max_window_bits = default_s2c_max_window_bits;
|
||||
m_server_max_window_bits = default_server_max_window_bits;
|
||||
}
|
||||
}
|
||||
|
||||
/// Negotiate c2s_max_window_bits attribute
|
||||
/// Negotiate client_max_window_bits attribute
|
||||
/**
|
||||
* When this method starts, m_c2s_max_window_bits and m_c2s_max_window_mode
|
||||
* When this method starts, m_client_max_window_bits and m_c2s_max_window_mode
|
||||
* will contain the server's preferred values for window size and
|
||||
* negotiation mode.
|
||||
*
|
||||
@@ -668,49 +695,50 @@ private:
|
||||
* @param [in] value The value of the attribute from the offer
|
||||
* @param [out] ec A reference to the error code to return errors via
|
||||
*/
|
||||
void negotiate_c2s_max_window_bits(std::string const & value,
|
||||
void negotiate_client_max_window_bits(std::string const & value,
|
||||
lib::error_code & ec)
|
||||
{
|
||||
uint8_t bits = uint8_t(atoi(value.c_str()));
|
||||
|
||||
if (value.empty()) {
|
||||
bits = default_c2s_max_window_bits;
|
||||
} else if (bits < min_c2s_max_window_bits ||
|
||||
bits > max_c2s_max_window_bits)
|
||||
bits = default_client_max_window_bits;
|
||||
} else if (bits < min_client_max_window_bits ||
|
||||
bits > max_client_max_window_bits)
|
||||
{
|
||||
ec = make_error_code(error::invalid_attribute_value);
|
||||
m_c2s_max_window_bits = default_c2s_max_window_bits;
|
||||
m_client_max_window_bits = default_client_max_window_bits;
|
||||
return;
|
||||
}
|
||||
|
||||
switch (m_c2s_max_window_bits_mode) {
|
||||
switch (m_client_max_window_bits_mode) {
|
||||
case mode::decline:
|
||||
m_c2s_max_window_bits = default_c2s_max_window_bits;
|
||||
m_client_max_window_bits = default_client_max_window_bits;
|
||||
break;
|
||||
case mode::accept:
|
||||
m_c2s_max_window_bits = bits;
|
||||
m_client_max_window_bits = bits;
|
||||
break;
|
||||
case mode::largest:
|
||||
m_c2s_max_window_bits = std::min(bits,m_c2s_max_window_bits);
|
||||
m_client_max_window_bits = std::min(bits,m_client_max_window_bits);
|
||||
break;
|
||||
case mode::smallest:
|
||||
m_c2s_max_window_bits = min_c2s_max_window_bits;
|
||||
m_client_max_window_bits = min_client_max_window_bits;
|
||||
break;
|
||||
default:
|
||||
ec = make_error_code(error::invalid_mode);
|
||||
m_c2s_max_window_bits = default_c2s_max_window_bits;
|
||||
m_client_max_window_bits = default_client_max_window_bits;
|
||||
}
|
||||
}
|
||||
|
||||
bool m_enabled;
|
||||
bool m_s2c_no_context_takeover;
|
||||
bool m_c2s_no_context_takeover;
|
||||
uint8_t m_s2c_max_window_bits;
|
||||
uint8_t m_c2s_max_window_bits;
|
||||
mode::value m_s2c_max_window_bits_mode;
|
||||
mode::value m_c2s_max_window_bits_mode;
|
||||
bool m_server_no_context_takeover;
|
||||
bool m_client_no_context_takeover;
|
||||
uint8_t m_server_max_window_bits;
|
||||
uint8_t m_client_max_window_bits;
|
||||
mode::value m_server_max_window_bits_mode;
|
||||
mode::value m_client_max_window_bits_mode;
|
||||
|
||||
bool m_initialized;
|
||||
int m_flush;
|
||||
size_t m_compress_buffer_size;
|
||||
lib::unique_ptr_uchar_array m_compress_buffer;
|
||||
z_stream m_dstate;
|
||||
|
||||
+4
-32
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Peter Thorson. All rights reserved.
|
||||
* Copyright (c) 2014, Peter Thorson. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
@@ -29,6 +29,7 @@
|
||||
#define WEBSOCKETPP_FRAME_HPP
|
||||
|
||||
#include <algorithm>
|
||||
#include <string>
|
||||
|
||||
#include <websocketpp/common/system_error.hpp>
|
||||
#include <websocketpp/common/network.hpp>
|
||||
@@ -266,7 +267,7 @@ private:
|
||||
}
|
||||
|
||||
uint64_converter temp64;
|
||||
temp64.i = lib::net::htonll(payload_size);
|
||||
temp64.i = lib::net::_htonll(payload_size);
|
||||
std::copy(temp64.c+payload_offset,temp64.c+8,bytes);
|
||||
|
||||
return 8-payload_offset;
|
||||
@@ -456,35 +457,6 @@ inline size_t get_header_len(basic_header const & h) {
|
||||
return size;
|
||||
}
|
||||
|
||||
/// Set the frame's size
|
||||
/**
|
||||
* @param [out] h The basic header to set.
|
||||
* @param [out] eh The extended header to set.
|
||||
* @param [in] The size to set.
|
||||
* @return What error occurred, if any.
|
||||
*/
|
||||
inline lib::error_code set_size(basic_header & h, extended_header & eh, uint64_t
|
||||
size)
|
||||
{
|
||||
// make sure value isn't too big
|
||||
uint8_t basic_value;
|
||||
|
||||
if (size <= limits::payload_size_basic) {
|
||||
basic_value = static_cast<uint8_t>(size);
|
||||
} else if (size <= limits::payload_size_extended) {
|
||||
basic_value = payload_size_code_16bit;
|
||||
} else if (size <= limits::payload_size_jumbo) {
|
||||
basic_value = payload_size_code_64bit;
|
||||
} else {
|
||||
// error
|
||||
return lib::error_code();
|
||||
}
|
||||
|
||||
h.b1 = (basic_value & BHB1_PAYLOAD) | (h.b1 & BHB1_MASK);
|
||||
|
||||
return lib::error_code();
|
||||
}
|
||||
|
||||
/// Calculate the offset location of the masking key within the extended header
|
||||
/**
|
||||
* Calculate the offset location of the masking key within the extended header
|
||||
@@ -583,7 +555,7 @@ inline uint16_t get_extended_size(const extended_header &e) {
|
||||
inline uint64_t get_jumbo_size(const extended_header &e) {
|
||||
uint64_converter temp64;
|
||||
std::copy(e.bytes,e.bytes+8,temp64.c);
|
||||
return lib::net::ntohll(temp64.i);
|
||||
return lib::net::_ntohll(temp64.i);
|
||||
}
|
||||
|
||||
/// Extract the full payload size field from a WebSocket header
|
||||
|
||||
+11
-5
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Peter Thorson. All rights reserved.
|
||||
* Copyright (c) 2014, Peter Thorson. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
@@ -28,11 +28,14 @@
|
||||
#ifndef HTTP_CONSTANTS_HPP
|
||||
#define HTTP_CONSTANTS_HPP
|
||||
|
||||
#include <exception>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <utility>
|
||||
|
||||
namespace websocketpp {
|
||||
/// HTTP handling support
|
||||
namespace http {
|
||||
/// The type of an HTTP attribute list
|
||||
/**
|
||||
@@ -56,10 +59,13 @@ namespace http {
|
||||
static char const header_separator[] = ":";
|
||||
|
||||
/// Literal value of an empty header
|
||||
static std::string const empty_header = "";
|
||||
static std::string const empty_header;
|
||||
|
||||
/// Maximum size in bytes before rejecting an HTTP header as too big.
|
||||
size_t const max_header_size = 16000;
|
||||
|
||||
/// Default Maximum size in bytes for HTTP message bodies.
|
||||
size_t const max_body_size = 32000000;
|
||||
|
||||
/// Number of bytes to use for temporary istream read buffers
|
||||
size_t const istream_buffer = 512;
|
||||
@@ -255,7 +261,7 @@ namespace http {
|
||||
case internal_server_error:
|
||||
return "Internal Server Error";
|
||||
case not_implemented:
|
||||
return "Not Implimented";
|
||||
return "Not Implemented";
|
||||
case bad_gateway:
|
||||
return "Bad Gateway";
|
||||
case service_unavailable:
|
||||
@@ -278,8 +284,8 @@ namespace http {
|
||||
public:
|
||||
exception(const std::string& log_msg,
|
||||
status_code::value error_code,
|
||||
const std::string& error_msg = "",
|
||||
const std::string& body = "")
|
||||
const std::string& error_msg = std::string(),
|
||||
const std::string& body = std::string())
|
||||
: m_msg(log_msg)
|
||||
, m_error_msg(error_msg)
|
||||
, m_body(body)
|
||||
|
||||
+45
-20
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Peter Thorson. All rights reserved.
|
||||
* Copyright (c) 2014, Peter Thorson. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
@@ -29,6 +29,8 @@
|
||||
#define HTTP_PARSER_IMPL_HPP
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstdlib>
|
||||
#include <istream>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
|
||||
@@ -69,7 +71,7 @@ inline void parser::append_header(std::string const & key, std::string const &
|
||||
throw exception("Invalid header name",status_code::bad_request);
|
||||
}
|
||||
|
||||
if (this->get_header(key) == "") {
|
||||
if (this->get_header(key).empty()) {
|
||||
m_headers[key] = val;
|
||||
} else {
|
||||
m_headers[key] += ", " + val;
|
||||
@@ -89,10 +91,13 @@ inline void parser::remove_header(std::string const & key) {
|
||||
inline void parser::set_body(std::string const & value) {
|
||||
if (value.size() == 0) {
|
||||
remove_header("Content-Length");
|
||||
m_body = "";
|
||||
m_body.clear();
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: should this method respect the max size? If so how should errors
|
||||
// be indicated?
|
||||
|
||||
std::stringstream len;
|
||||
len << value.size();
|
||||
replace_header("Content-Length", len.str());
|
||||
@@ -111,26 +116,46 @@ inline bool parser::parse_parameter_list(std::string const & in,
|
||||
return (it == in.begin());
|
||||
}
|
||||
|
||||
inline bool parser::parse_headers(std::istream & s) {
|
||||
std::string header;
|
||||
std::string::size_type end;
|
||||
|
||||
// get headers
|
||||
while (std::getline(s, header) && header != "\r") {
|
||||
if (header[header.size()-1] != '\r') {
|
||||
continue; // ignore malformed header lines?
|
||||
} else {
|
||||
header.erase(header.end()-1);
|
||||
}
|
||||
|
||||
end = header.find(header_separator,0);
|
||||
|
||||
if (end != std::string::npos) {
|
||||
append_header(header.substr(0,end),header.substr(end+2));
|
||||
inline bool parser::prepare_body() {
|
||||
if (!get_header("Content-Length").empty()) {
|
||||
std::string const & cl_header = get_header("Content-Length");
|
||||
char * end;
|
||||
|
||||
// TODO: not 100% sure what the compatibility of this method is. Also,
|
||||
// I believe this will only work up to 32bit sizes. Is there a need for
|
||||
// > 4GiB HTTP payloads?
|
||||
m_body_bytes_needed = std::strtoul(cl_header.c_str(),&end,10);
|
||||
|
||||
if (m_body_bytes_needed > m_body_bytes_max) {
|
||||
throw exception("HTTP message body too large",
|
||||
status_code::request_entity_too_large);
|
||||
}
|
||||
|
||||
m_body_encoding = body_encoding::plain;
|
||||
return true;
|
||||
} else if (get_header("Transfer-Encoding") == "chunked") {
|
||||
// TODO
|
||||
//m_body_encoding = body_encoding::chunked;
|
||||
return false;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
inline size_t parser::process_body(char const * buf, size_t len) {
|
||||
if (m_body_encoding == body_encoding::plain) {
|
||||
size_t processed = (std::min)(m_body_bytes_needed,len);
|
||||
m_body.append(buf,processed);
|
||||
m_body_bytes_needed -= processed;
|
||||
return processed;
|
||||
} else if (m_body_encoding == body_encoding::chunked) {
|
||||
// TODO:
|
||||
throw exception("Unexpected body encoding",
|
||||
status_code::internal_server_error);
|
||||
} else {
|
||||
throw exception("Unexpected body encoding",
|
||||
status_code::internal_server_error);
|
||||
}
|
||||
}
|
||||
|
||||
inline void parser::process_header(std::string::iterator begin,
|
||||
|
||||
+57
-57
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Peter Thorson. All rights reserved.
|
||||
* Copyright (c) 2014, Peter Thorson. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
@@ -30,6 +30,7 @@
|
||||
|
||||
#include <algorithm>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
|
||||
#include <websocketpp/http/parser.hpp>
|
||||
|
||||
@@ -37,40 +38,17 @@ namespace websocketpp {
|
||||
namespace http {
|
||||
namespace parser {
|
||||
|
||||
inline bool request::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 {
|
||||
return false;
|
||||
}
|
||||
|
||||
return parse_headers(s);
|
||||
}
|
||||
|
||||
inline size_t request::consume(const char *buf, size_t len) {
|
||||
inline size_t request::consume(char const * buf, size_t len) {
|
||||
size_t bytes_processed;
|
||||
|
||||
if (m_ready) {return 0;}
|
||||
|
||||
if (m_buf->size() + len > max_header_size) {
|
||||
// exceeded max header size
|
||||
throw exception("Maximum header size exceeded.",
|
||||
status_code::request_header_fields_too_large);
|
||||
|
||||
if (m_body_bytes_needed > 0) {
|
||||
bytes_processed = process_body(buf,len);
|
||||
if (body_ready()) {
|
||||
m_ready = true;
|
||||
}
|
||||
return bytes_processed;
|
||||
}
|
||||
|
||||
// copy new header bytes into buffer
|
||||
@@ -88,15 +66,21 @@ inline size_t request::consume(const char *buf, size_t len) {
|
||||
header_delimiter,
|
||||
header_delimiter+sizeof(header_delimiter)-1
|
||||
);
|
||||
|
||||
//std::cout << "mark5: " << end-begin << std::endl;
|
||||
//std::cout << "mark6: " << sizeof(header_delimiter) << std::endl;
|
||||
|
||||
m_header_bytes += (end-begin+sizeof(header_delimiter));
|
||||
|
||||
if (m_header_bytes > max_header_size) {
|
||||
// exceeded max header size
|
||||
throw exception("Maximum header size exceeded.",
|
||||
status_code::request_header_fields_too_large);
|
||||
}
|
||||
|
||||
if (end == m_buf->end()) {
|
||||
// we are out of bytes. Discard the processed bytes and copy the
|
||||
// remaining unprecessed bytes to the beginning of the buffer
|
||||
std::copy(begin,end,m_buf->begin());
|
||||
m_buf->resize(static_cast<std::string::size_type>(end-begin));
|
||||
m_header_bytes -= m_buf->size();
|
||||
|
||||
return len;
|
||||
}
|
||||
@@ -104,12 +88,11 @@ inline size_t request::consume(const char *buf, size_t len) {
|
||||
//the range [begin,end) now represents a line to be processed.
|
||||
if (end-begin == 0) {
|
||||
// we got a blank line
|
||||
if (m_method.empty() || get_header("Host") == "") {
|
||||
if (m_method.empty() || get_header("Host").empty()) {
|
||||
throw exception("Incomplete Request",status_code::bad_request);
|
||||
}
|
||||
m_ready = true;
|
||||
|
||||
size_t bytes_processed = (
|
||||
bytes_processed = (
|
||||
len - static_cast<std::string::size_type>(m_buf->end()-end)
|
||||
+ sizeof(header_delimiter) - 1
|
||||
);
|
||||
@@ -117,8 +100,22 @@ inline size_t request::consume(const char *buf, size_t len) {
|
||||
// frees memory used temporarily during request parsing
|
||||
m_buf.reset();
|
||||
|
||||
// return number of bytes processed (starting bytes - bytes left)
|
||||
return bytes_processed;
|
||||
// if this was not an upgrade request and has a content length
|
||||
// continue capturing content-length bytes and expose them as a
|
||||
// request body.
|
||||
|
||||
if (prepare_body()) {
|
||||
bytes_processed += process_body(buf+bytes_processed,len-bytes_processed);
|
||||
if (body_ready()) {
|
||||
m_ready = true;
|
||||
}
|
||||
return bytes_processed;
|
||||
} else {
|
||||
m_ready = true;
|
||||
|
||||
// return number of bytes processed (starting bytes - bytes left)
|
||||
return bytes_processed;
|
||||
}
|
||||
} else {
|
||||
if (m_method.empty()) {
|
||||
this->process(begin,end);
|
||||
@@ -127,21 +124,31 @@ inline size_t request::consume(const char *buf, size_t len) {
|
||||
}
|
||||
}
|
||||
|
||||
begin = end+sizeof(header_delimiter)-1;
|
||||
begin = end+(sizeof(header_delimiter)-1);
|
||||
}
|
||||
}
|
||||
|
||||
inline std::string request::raw() {
|
||||
inline std::string request::raw() const {
|
||||
// TODO: validation. Make sure all required fields have been set?
|
||||
std::stringstream raw;
|
||||
std::stringstream ret;
|
||||
|
||||
raw << m_method << " " << m_uri << " " << get_version() << "\r\n";
|
||||
raw << raw_headers() << "\r\n" << m_body;
|
||||
ret << m_method << " " << m_uri << " " << get_version() << "\r\n";
|
||||
ret << raw_headers() << "\r\n" << m_body;
|
||||
|
||||
return raw.str();
|
||||
return ret.str();
|
||||
}
|
||||
|
||||
inline void request::set_method(const std::string& method) {
|
||||
inline std::string request::raw_head() const {
|
||||
// TODO: validation. Make sure all required fields have been set?
|
||||
std::stringstream ret;
|
||||
|
||||
ret << m_method << " " << m_uri << " " << get_version() << "\r\n";
|
||||
ret << raw_headers() << "\r\n";
|
||||
|
||||
return ret.str();
|
||||
}
|
||||
|
||||
inline void request::set_method(std::string const & method) {
|
||||
if (std::find_if(method.begin(),method.end(),is_not_token_char) != method.end()) {
|
||||
throw exception("Invalid method token.",status_code::bad_request);
|
||||
}
|
||||
@@ -149,14 +156,7 @@ inline void request::set_method(const std::string& method) {
|
||||
m_method = method;
|
||||
}
|
||||
|
||||
/// Set HTTP body
|
||||
/**
|
||||
* Sets the body of the HTTP object and fills in the appropriate content length
|
||||
* header
|
||||
*
|
||||
* @param value The value to set the body to.
|
||||
*/
|
||||
inline void request::set_uri(const std::string& uri) {
|
||||
inline void request::set_uri(std::string const & uri) {
|
||||
// TODO: validation?
|
||||
m_uri = uri;
|
||||
}
|
||||
|
||||
+22
-45
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Peter Thorson. All rights reserved.
|
||||
* Copyright (c) 2014, Peter Thorson. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
@@ -29,7 +29,9 @@
|
||||
#define HTTP_PARSER_RESPONSE_IMPL_HPP
|
||||
|
||||
#include <algorithm>
|
||||
#include <istream>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
|
||||
#include <websocketpp/http/parser.hpp>
|
||||
|
||||
@@ -37,19 +39,13 @@ namespace websocketpp {
|
||||
namespace http {
|
||||
namespace parser {
|
||||
|
||||
inline size_t response::consume(const char *buf, size_t len) {
|
||||
inline size_t response::consume(char const * buf, size_t len) {
|
||||
if (m_state == DONE) {return 0;}
|
||||
|
||||
if (m_state == BODY) {
|
||||
return this->process_body(buf,len);
|
||||
}
|
||||
|
||||
if (m_read + len > max_header_size) {
|
||||
// exceeded max header size
|
||||
throw exception("Maximum header size exceeded.",
|
||||
status_code::request_header_fields_too_large);
|
||||
}
|
||||
|
||||
// copy new header bytes into buffer
|
||||
m_buf->append(buf,len);
|
||||
|
||||
@@ -67,13 +63,22 @@ inline size_t response::consume(const char *buf, size_t len) {
|
||||
header_delimiter + sizeof(header_delimiter) - 1
|
||||
);
|
||||
|
||||
m_header_bytes += (end-begin+sizeof(header_delimiter));
|
||||
|
||||
if (m_header_bytes > max_header_size) {
|
||||
// exceeded max header size
|
||||
throw exception("Maximum header size exceeded.",
|
||||
status_code::request_header_fields_too_large);
|
||||
}
|
||||
|
||||
if (end == m_buf->end()) {
|
||||
// we are out of bytes. Discard the processed bytes and copy the
|
||||
// remaining unprecessed bytes to the beginning of the buffer
|
||||
std::copy(begin,end,m_buf->begin());
|
||||
m_buf->resize(static_cast<std::string::size_type>(end-begin));
|
||||
|
||||
m_read +=len;
|
||||
m_read += len;
|
||||
m_header_bytes -= m_buf->size();
|
||||
|
||||
return len;
|
||||
}
|
||||
@@ -89,7 +94,7 @@ inline size_t response::consume(const char *buf, size_t len) {
|
||||
// TODO: grab content-length
|
||||
std::string length = get_header("Content-Length");
|
||||
|
||||
if (length == "") {
|
||||
if (length.empty()) {
|
||||
// no content length found, read indefinitely
|
||||
m_read = 0;
|
||||
} else {
|
||||
@@ -170,45 +175,17 @@ inline size_t response::consume(std::istream & s) {
|
||||
return total;
|
||||
}
|
||||
|
||||
inline bool response::parse_complete(std::istream& s) {
|
||||
// parse a complete header (ie \r\n\r\n MUST be in the input stream)
|
||||
std::string 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);
|
||||
}
|
||||
|
||||
inline std::string response::raw() const {
|
||||
// TODO: validation. Make sure all required fields have been set?
|
||||
|
||||
std::stringstream raw;
|
||||
std::stringstream ret;
|
||||
|
||||
raw << get_version() << " " << m_status_code << " " << m_status_msg;
|
||||
raw << "\r\n" << raw_headers() << "\r\n";
|
||||
ret << get_version() << " " << m_status_code << " " << m_status_msg;
|
||||
ret << "\r\n" << raw_headers() << "\r\n";
|
||||
|
||||
raw << m_body;
|
||||
ret << m_body;
|
||||
|
||||
return raw.str();
|
||||
return ret.str();
|
||||
}
|
||||
|
||||
inline void response::set_status(status_code::value code) {
|
||||
@@ -217,7 +194,7 @@ inline void response::set_status(status_code::value code) {
|
||||
m_status_msg = get_string(code);
|
||||
}
|
||||
|
||||
inline void response::set_status(status_code::value code, const std::string&
|
||||
inline void response::set_status(status_code::value code, std::string const &
|
||||
msg)
|
||||
{
|
||||
// TODO: validation?
|
||||
@@ -255,7 +232,7 @@ inline void response::process(std::string::iterator begin,
|
||||
set_status(status_code::value(code),std::string(cursor_end+1,end));
|
||||
}
|
||||
|
||||
inline size_t response::process_body(const char *buf, size_t len) {
|
||||
inline size_t response::process_body(char const * buf, size_t len) {
|
||||
// If no content length was set then we read forever and never set m_ready
|
||||
if (m_read == 0) {
|
||||
//m_body.append(buf,len);
|
||||
|
||||
+105
-21
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Peter Thorson. All rights reserved.
|
||||
* Copyright (c) 2014, Peter Thorson. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
@@ -29,8 +29,9 @@
|
||||
#define HTTP_PARSER_HPP
|
||||
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
#include <websocketpp/utilities.hpp>
|
||||
#include <websocketpp/http/constants.hpp>
|
||||
@@ -48,6 +49,14 @@ namespace state {
|
||||
};
|
||||
}
|
||||
|
||||
namespace body_encoding {
|
||||
enum value {
|
||||
unknown,
|
||||
plain,
|
||||
chunked
|
||||
};
|
||||
}
|
||||
|
||||
typedef std::map<std::string, std::string, utility::ci_less > header_list;
|
||||
|
||||
/// Read and return the next token in the stream
|
||||
@@ -221,7 +230,7 @@ InputIterator extract_attributes(InputIterator begin, InputIterator end,
|
||||
cursor = http::parser::extract_all_lws(cursor,end);
|
||||
ret = http::parser::extract_token(cursor,end);
|
||||
|
||||
if (ret.first == "") {
|
||||
if (ret.first.empty()) {
|
||||
// error: expected a token
|
||||
return begin;
|
||||
} else {
|
||||
@@ -233,7 +242,7 @@ InputIterator extract_attributes(InputIterator begin, InputIterator end,
|
||||
if (cursor == end || *cursor != '=') {
|
||||
// if there is an equals sign, read the attribute value. Otherwise
|
||||
// record a blank value and continue
|
||||
attributes[name] = "";
|
||||
attributes[name].clear();
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -254,7 +263,7 @@ InputIterator extract_attributes(InputIterator begin, InputIterator end,
|
||||
}
|
||||
|
||||
ret = http::parser::extract_token(cursor,end);
|
||||
if (ret.first == "") {
|
||||
if (ret.first.empty()) {
|
||||
// error : expected token or quoted string
|
||||
return begin;
|
||||
} else {
|
||||
@@ -312,7 +321,7 @@ InputIterator extract_parameters(InputIterator begin, InputIterator end,
|
||||
|
||||
ret = http::parser::extract_token(cursor,end);
|
||||
|
||||
if (ret.first == "") {
|
||||
if (ret.first.empty()) {
|
||||
// error: expected a token
|
||||
return begin;
|
||||
} else {
|
||||
@@ -369,9 +378,16 @@ InputIterator extract_parameters(InputIterator begin, InputIterator end,
|
||||
|
||||
inline std::string strip_lws(std::string const & input) {
|
||||
std::string::const_iterator begin = extract_all_lws(input.begin(),input.end());
|
||||
std::string::const_reverse_iterator end = extract_all_lws(input.rbegin(),input.rend());
|
||||
if (begin == input.end()) {
|
||||
return std::string();
|
||||
}
|
||||
|
||||
return std::string(begin,end.base());
|
||||
std::string::const_reverse_iterator rbegin = extract_all_lws(input.rbegin(),input.rend());
|
||||
if (rbegin == input.rend()) {
|
||||
return std::string();
|
||||
}
|
||||
|
||||
return std::string(begin,rbegin.base());
|
||||
}
|
||||
|
||||
/// Base HTTP parser
|
||||
@@ -381,6 +397,12 @@ inline std::string strip_lws(std::string const & input) {
|
||||
*/
|
||||
class parser {
|
||||
public:
|
||||
parser()
|
||||
: m_header_bytes(0)
|
||||
, m_body_bytes_needed(0)
|
||||
, m_body_bytes_max(max_body_size)
|
||||
, m_body_encoding(body_encoding::unknown) {}
|
||||
|
||||
/// Get the HTTP version string
|
||||
/**
|
||||
* @return The version string for this parser
|
||||
@@ -464,12 +486,11 @@ public:
|
||||
*/
|
||||
void remove_header(std::string const & key);
|
||||
|
||||
/// Set HTTP body
|
||||
/// Get HTTP body
|
||||
/**
|
||||
* Sets the body of the HTTP object and fills in the appropriate content
|
||||
* length header.
|
||||
* Gets the body of the HTTP object
|
||||
*
|
||||
* @param [in] value The value to set the body to.
|
||||
* @return The body of the HTTP message.
|
||||
*/
|
||||
std::string const & get_body() const {
|
||||
return m_body;
|
||||
@@ -486,6 +507,32 @@ public:
|
||||
*/
|
||||
void set_body(std::string const & value);
|
||||
|
||||
/// Get body size limit
|
||||
/**
|
||||
* Retrieves the maximum number of bytes to parse & buffer before canceling
|
||||
* a request.
|
||||
*
|
||||
* @since 0.5.0
|
||||
*
|
||||
* @return The maximum length of a message body.
|
||||
*/
|
||||
size_t get_max_body_size() const {
|
||||
return m_body_bytes_max;
|
||||
}
|
||||
|
||||
/// Set body size limit
|
||||
/**
|
||||
* Set the maximum number of bytes to parse and buffer before canceling a
|
||||
* request.
|
||||
*
|
||||
* @since 0.5.0
|
||||
*
|
||||
* @param value The size to set the max body length to.
|
||||
*/
|
||||
void set_max_body_size(size_t value) {
|
||||
m_body_bytes_max = value;
|
||||
}
|
||||
|
||||
/// Extract an HTTP parameter list from a string.
|
||||
/**
|
||||
* @param [in] in The input string.
|
||||
@@ -495,14 +542,6 @@ public:
|
||||
bool parse_parameter_list(std::string const & in, parameter_list & out)
|
||||
const;
|
||||
protected:
|
||||
/// Parse headers from an istream
|
||||
/**
|
||||
* @deprecated Use process_header instead.
|
||||
*
|
||||
* @param [in] s The istream to extract headers from.
|
||||
*/
|
||||
bool parse_headers(std::istream & s);
|
||||
|
||||
/// Process a header line
|
||||
/**
|
||||
* @todo Update this method to be exception free.
|
||||
@@ -512,6 +551,45 @@ protected:
|
||||
*/
|
||||
void process_header(std::string::iterator begin, std::string::iterator end);
|
||||
|
||||
/// Prepare the parser to begin parsing body data
|
||||
/**
|
||||
* Inspects headers to determine if the message has a body that needs to be
|
||||
* read. If so, sets up the necessary state, otherwise returns false. If
|
||||
* this method returns true and loading the message body is desired call
|
||||
* `process_body` until it returns zero bytes or an error.
|
||||
*
|
||||
* Must not be called until after all headers have been processed.
|
||||
*
|
||||
* @since 0.5.0
|
||||
*
|
||||
* @return True if more bytes are needed to load the body, false otherwise.
|
||||
*/
|
||||
bool prepare_body();
|
||||
|
||||
/// Process body data
|
||||
/**
|
||||
* Parses body data.
|
||||
*
|
||||
* @since 0.5.0
|
||||
*
|
||||
* @param [in] begin An iterator to the beginning of the sequence.
|
||||
* @param [in] end An iterator to the end of the sequence.
|
||||
* @return The number of bytes processed
|
||||
*/
|
||||
size_t process_body(char const * buf, size_t len);
|
||||
|
||||
/// Check if the parser is done parsing the body
|
||||
/**
|
||||
* Behavior before a call to `prepare_body` is undefined.
|
||||
*
|
||||
* @since 0.5.0
|
||||
*
|
||||
* @return True if the message body has been completed loaded.
|
||||
*/
|
||||
bool body_ready() const {
|
||||
return (m_body_bytes_needed == 0);
|
||||
}
|
||||
|
||||
/// Generate and return the HTTP headers as a string
|
||||
/**
|
||||
* Each headers will be followed by the \r\n sequence including the last one.
|
||||
@@ -523,7 +601,13 @@ protected:
|
||||
|
||||
std::string m_version;
|
||||
header_list m_headers;
|
||||
std::string m_body;
|
||||
|
||||
size_t m_header_bytes;
|
||||
|
||||
std::string m_body;
|
||||
size_t m_body_bytes_needed;
|
||||
size_t m_body_bytes_max;
|
||||
body_encoding::value m_body_encoding;
|
||||
};
|
||||
|
||||
} // namespace parser
|
||||
|
||||
+14
-12
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Peter Thorson. All rights reserved.
|
||||
* Copyright (c) 2014, Peter Thorson. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
@@ -28,6 +28,8 @@
|
||||
#ifndef HTTP_PARSER_REQUEST_HPP
|
||||
#define HTTP_PARSER_REQUEST_HPP
|
||||
|
||||
#include <string>
|
||||
|
||||
#include <websocketpp/common/memory.hpp>
|
||||
#include <websocketpp/http/parser.hpp>
|
||||
|
||||
@@ -51,12 +53,9 @@ public:
|
||||
typedef lib::shared_ptr<type> ptr;
|
||||
|
||||
request()
|
||||
: m_buf(new std::string())
|
||||
: m_buf(lib::make_shared<std::string>())
|
||||
, m_ready(false) {}
|
||||
|
||||
/// DEPRECATED parse a complete header (\r\n\r\n MUST be in the istream)
|
||||
bool parse_complete(std::istream& s);
|
||||
|
||||
/// Process bytes in the input buffer
|
||||
/**
|
||||
* Process up to len bytes from input buffer buf. Returns the number of
|
||||
@@ -77,29 +76,32 @@ public:
|
||||
* @param len Size of byte buffer
|
||||
* @return Number of bytes processed.
|
||||
*/
|
||||
size_t consume(const char *buf, size_t len);
|
||||
size_t consume(char const * buf, size_t len);
|
||||
|
||||
/// Returns whether or not the request is ready for reading.
|
||||
bool ready() const {
|
||||
return m_ready;
|
||||
}
|
||||
|
||||
/// Returns the full raw request
|
||||
std::string raw();
|
||||
/// Returns the full raw request (including the body)
|
||||
std::string raw() const;
|
||||
|
||||
/// Returns the raw request headers only (similar to an HTTP HEAD request)
|
||||
std::string raw_head() const;
|
||||
|
||||
/// Set the HTTP method. Must be a valid HTTP token
|
||||
void set_method(const std::string& method);
|
||||
void set_method(std::string const & method);
|
||||
|
||||
/// Return the request method
|
||||
const std::string& get_method() const {
|
||||
std::string const & get_method() const {
|
||||
return m_method;
|
||||
}
|
||||
|
||||
/// Set the HTTP uri. Must be a valid HTTP uri
|
||||
void set_uri(const std::string& uri);
|
||||
void set_uri(std::string const & uri);
|
||||
|
||||
/// Return the requested URI
|
||||
const std::string& get_uri() const {
|
||||
std::string const & get_uri() const {
|
||||
return m_uri;
|
||||
}
|
||||
|
||||
|
||||
+28
-8
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Peter Thorson. All rights reserved.
|
||||
* Copyright (c) 2014, Peter Thorson. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
@@ -28,6 +28,9 @@
|
||||
#ifndef HTTP_PARSER_RESPONSE_HPP
|
||||
#define HTTP_PARSER_RESPONSE_HPP
|
||||
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
#include <websocketpp/http/parser.hpp>
|
||||
|
||||
namespace websocketpp {
|
||||
@@ -58,7 +61,7 @@ public:
|
||||
|
||||
response()
|
||||
: m_read(0)
|
||||
, m_buf(new std::string())
|
||||
, m_buf(lib::make_shared<std::string>())
|
||||
, m_status_code(status_code::uninitialized)
|
||||
, m_state(RESPONSE_LINE) {}
|
||||
|
||||
@@ -82,8 +85,28 @@ public:
|
||||
* @param len Size of byte buffer
|
||||
* @return Number of bytes processed.
|
||||
*/
|
||||
size_t consume(const char *buf, size_t len);
|
||||
size_t consume(char const * buf, size_t len);
|
||||
|
||||
/// Process bytes in the input buffer (istream version)
|
||||
/**
|
||||
* Process bytes from istream s. Returns the number of bytes processed.
|
||||
* Bytes left unprocessed means bytes left over after the final header
|
||||
* delimiters.
|
||||
*
|
||||
* Consume is a streaming processor. It may be called multiple times on one
|
||||
* response and the full headers need not be available before processing can
|
||||
* begin. If the end of the response was reached during this call to consume
|
||||
* the ready flag will be set. Further calls to consume once ready will be
|
||||
* ignored.
|
||||
*
|
||||
* Consume will throw an http::exception in the case of an error. Typical
|
||||
* error reasons include malformed responses, incomplete responses, and max
|
||||
* header size being reached.
|
||||
*
|
||||
* @param buf Pointer to byte buffer
|
||||
* @param len Size of byte buffer
|
||||
* @return Number of bytes processed.
|
||||
*/
|
||||
size_t consume(std::istream & s);
|
||||
|
||||
/// Returns true if the response is ready.
|
||||
@@ -99,9 +122,6 @@ public:
|
||||
return (m_state == BODY || m_state == DONE);
|
||||
}
|
||||
|
||||
/// DEPRECATED parse a complete response from a pre-delimited istream
|
||||
bool parse_complete(std::istream& s);
|
||||
|
||||
/// Returns the full raw response
|
||||
std::string raw() const;
|
||||
|
||||
@@ -126,7 +146,7 @@ public:
|
||||
* @param code Code to set
|
||||
* @param msg Message to set
|
||||
*/
|
||||
void set_status(status_code::value code, const std::string& msg);
|
||||
void set_status(status_code::value code, std::string const & msg);
|
||||
|
||||
/// Return the response status code
|
||||
status_code::value get_status_code() const {
|
||||
@@ -142,7 +162,7 @@ private:
|
||||
void process(std::string::iterator begin, std::string::iterator end);
|
||||
|
||||
/// Helper function for processing body bytes
|
||||
size_t process_body(const char *buf, size_t len);
|
||||
size_t process_body(char const * buf, size_t len);
|
||||
|
||||
enum state {
|
||||
RESPONSE_LINE = 0,
|
||||
|
||||
+768
-452
File diff suppressed because it is too large.
Load diff
+77
-26
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Peter Thorson. All rights reserved.
|
||||
* Copyright (c) 2014, Peter Thorson. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
@@ -28,6 +28,8 @@
|
||||
#ifndef WEBSOCKETPP_ENDPOINT_IMPL_HPP
|
||||
#define WEBSOCKETPP_ENDPOINT_IMPL_HPP
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace websocketpp {
|
||||
|
||||
template <typename connection, typename config>
|
||||
@@ -42,8 +44,8 @@ endpoint<connection,config>::create_connection() {
|
||||
|
||||
//scoped_lock_type guard(m_mutex);
|
||||
// Create a connection on the heap and manage it using a shared pointer
|
||||
connection_ptr con(new connection_type(m_is_server,m_user_agent,m_alog,
|
||||
m_elog, m_rng));
|
||||
connection_ptr con = lib::make_shared<connection_type>(m_is_server,
|
||||
m_user_agent, lib::ref(m_alog), lib::ref(m_elog), lib::ref(m_rng));
|
||||
|
||||
connection_weak_ptr w(con);
|
||||
|
||||
@@ -64,16 +66,20 @@ endpoint<connection,config>::create_connection() {
|
||||
con->set_http_handler(m_http_handler);
|
||||
con->set_validate_handler(m_validate_handler);
|
||||
con->set_message_handler(m_message_handler);
|
||||
|
||||
if (m_open_handshake_timeout_dur == config::timeout_open_handshake) {
|
||||
|
||||
if (m_open_handshake_timeout_dur != config::timeout_open_handshake) {
|
||||
con->set_open_handshake_timeout(m_open_handshake_timeout_dur);
|
||||
}
|
||||
if (m_close_handshake_timeout_dur == config::timeout_close_handshake) {
|
||||
if (m_close_handshake_timeout_dur != config::timeout_close_handshake) {
|
||||
con->set_close_handshake_timeout(m_close_handshake_timeout_dur);
|
||||
}
|
||||
if (m_pong_timeout_dur == config::timeout_pong) {
|
||||
if (m_pong_timeout_dur != config::timeout_pong) {
|
||||
con->set_pong_timeout(m_pong_timeout_dur);
|
||||
}
|
||||
if (m_max_message_size != config::max_message_size) {
|
||||
con->set_max_message_size(m_max_message_size);
|
||||
}
|
||||
con->set_max_http_body_size(m_max_http_body_size);
|
||||
|
||||
lib::error_code ec;
|
||||
|
||||
@@ -87,8 +93,7 @@ endpoint<connection,config>::create_connection() {
|
||||
}
|
||||
|
||||
template <typename connection, typename config>
|
||||
void endpoint<connection,config>::interrupt(connection_hdl hdl,
|
||||
lib::error_code & ec)
|
||||
void endpoint<connection,config>::interrupt(connection_hdl hdl, lib::error_code & ec)
|
||||
{
|
||||
connection_ptr con = get_con_from_hdl(hdl,ec);
|
||||
if (ec) {return;}
|
||||
@@ -102,12 +107,60 @@ template <typename connection, typename config>
|
||||
void endpoint<connection,config>::interrupt(connection_hdl hdl) {
|
||||
lib::error_code ec;
|
||||
interrupt(hdl,ec);
|
||||
if (ec) { throw ec; }
|
||||
if (ec) { throw exception(ec); }
|
||||
}
|
||||
|
||||
template <typename connection, typename config>
|
||||
void endpoint<connection,config>::send(connection_hdl hdl, std::string const &
|
||||
payload, frame::opcode::value op, lib::error_code & ec)
|
||||
void endpoint<connection,config>::pause_reading(connection_hdl hdl, lib::error_code & ec)
|
||||
{
|
||||
connection_ptr con = get_con_from_hdl(hdl,ec);
|
||||
if (ec) {return;}
|
||||
|
||||
ec = con->pause_reading();
|
||||
}
|
||||
|
||||
template <typename connection, typename config>
|
||||
void endpoint<connection,config>::pause_reading(connection_hdl hdl) {
|
||||
lib::error_code ec;
|
||||
pause_reading(hdl,ec);
|
||||
if (ec) { throw exception(ec); }
|
||||
}
|
||||
|
||||
template <typename connection, typename config>
|
||||
void endpoint<connection,config>::resume_reading(connection_hdl hdl, lib::error_code & ec)
|
||||
{
|
||||
connection_ptr con = get_con_from_hdl(hdl,ec);
|
||||
if (ec) {return;}
|
||||
|
||||
ec = con->resume_reading();
|
||||
}
|
||||
|
||||
template <typename connection, typename config>
|
||||
void endpoint<connection,config>::resume_reading(connection_hdl hdl) {
|
||||
lib::error_code ec;
|
||||
resume_reading(hdl,ec);
|
||||
if (ec) { throw exception(ec); }
|
||||
}
|
||||
|
||||
template <typename connection, typename config>
|
||||
void endpoint<connection,config>::send_http_response(connection_hdl hdl,
|
||||
lib::error_code & ec)
|
||||
{
|
||||
connection_ptr con = get_con_from_hdl(hdl,ec);
|
||||
if (ec) {return;}
|
||||
con->send_http_response(ec);
|
||||
}
|
||||
|
||||
template <typename connection, typename config>
|
||||
void endpoint<connection,config>::send_http_response(connection_hdl hdl) {
|
||||
lib::error_code ec;
|
||||
send_http_response(hdl,ec);
|
||||
if (ec) { throw exception(ec); }
|
||||
}
|
||||
|
||||
template <typename connection, typename config>
|
||||
void endpoint<connection,config>::send(connection_hdl hdl, std::string const & payload,
|
||||
frame::opcode::value op, lib::error_code & ec)
|
||||
{
|
||||
connection_ptr con = get_con_from_hdl(hdl,ec);
|
||||
if (ec) {return;}
|
||||
@@ -116,12 +169,12 @@ void endpoint<connection,config>::send(connection_hdl hdl, std::string const &
|
||||
}
|
||||
|
||||
template <typename connection, typename config>
|
||||
void endpoint<connection,config>::send(connection_hdl hdl, std::string const &
|
||||
payload, frame::opcode::value op)
|
||||
void endpoint<connection,config>::send(connection_hdl hdl, std::string const & payload,
|
||||
frame::opcode::value op)
|
||||
{
|
||||
lib::error_code ec;
|
||||
send(hdl,payload,op,ec);
|
||||
if (ec) { throw ec; }
|
||||
if (ec) { throw exception(ec); }
|
||||
}
|
||||
|
||||
template <typename connection, typename config>
|
||||
@@ -139,7 +192,7 @@ void endpoint<connection,config>::send(connection_hdl hdl, void const * payload,
|
||||
{
|
||||
lib::error_code ec;
|
||||
send(hdl,payload,len,op,ec);
|
||||
if (ec) { throw ec; }
|
||||
if (ec) { throw exception(ec); }
|
||||
}
|
||||
|
||||
template <typename connection, typename config>
|
||||
@@ -155,7 +208,7 @@ template <typename connection, typename config>
|
||||
void endpoint<connection,config>::send(connection_hdl hdl, message_ptr msg) {
|
||||
lib::error_code ec;
|
||||
send(hdl,msg,ec);
|
||||
if (ec) { throw ec; }
|
||||
if (ec) { throw exception(ec); }
|
||||
}
|
||||
|
||||
template <typename connection, typename config>
|
||||
@@ -174,7 +227,7 @@ void endpoint<connection,config>::close(connection_hdl hdl, close::status::value
|
||||
{
|
||||
lib::error_code ec;
|
||||
close(hdl,code,reason,ec);
|
||||
if (ec) { throw ec; }
|
||||
if (ec) { throw exception(ec); }
|
||||
}
|
||||
|
||||
template <typename connection, typename config>
|
||||
@@ -187,17 +240,16 @@ void endpoint<connection,config>::ping(connection_hdl hdl, std::string const &
|
||||
}
|
||||
|
||||
template <typename connection, typename config>
|
||||
void endpoint<connection,config>::ping(connection_hdl hdl, std::string const &
|
||||
payload)
|
||||
void endpoint<connection,config>::ping(connection_hdl hdl, std::string const & payload)
|
||||
{
|
||||
lib::error_code ec;
|
||||
ping(hdl,payload,ec);
|
||||
if (ec) { throw ec; }
|
||||
if (ec) { throw exception(ec); }
|
||||
}
|
||||
|
||||
template <typename connection, typename config>
|
||||
void endpoint<connection,config>::pong(connection_hdl hdl, std::string const &
|
||||
payload, lib::error_code & ec)
|
||||
void endpoint<connection,config>::pong(connection_hdl hdl, std::string const & payload,
|
||||
lib::error_code & ec)
|
||||
{
|
||||
connection_ptr con = get_con_from_hdl(hdl,ec);
|
||||
if (ec) {return;}
|
||||
@@ -205,12 +257,11 @@ void endpoint<connection,config>::pong(connection_hdl hdl, std::string const &
|
||||
}
|
||||
|
||||
template <typename connection, typename config>
|
||||
void endpoint<connection,config>::pong(connection_hdl hdl, std::string const &
|
||||
payload)
|
||||
void endpoint<connection,config>::pong(connection_hdl hdl, std::string const & payload)
|
||||
{
|
||||
lib::error_code ec;
|
||||
pong(hdl,payload,ec);
|
||||
if (ec) { throw ec; }
|
||||
if (ec) { throw exception(ec); }
|
||||
}
|
||||
|
||||
} // namespace websocketpp
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Peter Thorson. All rights reserved.
|
||||
* Copyright (c) 2014, Peter Thorson. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
@@ -28,6 +28,9 @@
|
||||
#ifndef WEBSOCKETPP_UTILITIES_IMPL_HPP
|
||||
#define WEBSOCKETPP_UTILITIES_IMPL_HPP
|
||||
|
||||
#include <algorithm>
|
||||
#include <string>
|
||||
|
||||
namespace websocketpp {
|
||||
namespace utility {
|
||||
|
||||
@@ -37,7 +40,7 @@ inline std::string to_lower(std::string const & in) {
|
||||
return out;
|
||||
}
|
||||
|
||||
inline std::string to_hex(const std::string& input) {
|
||||
inline std::string to_hex(std::string const & input) {
|
||||
std::string output;
|
||||
std::string hex = "0123456789ABCDEF";
|
||||
|
||||
@@ -50,7 +53,7 @@ inline std::string to_hex(const std::string& input) {
|
||||
return output;
|
||||
}
|
||||
|
||||
inline std::string to_hex(const uint8_t* input,size_t length) {
|
||||
inline std::string to_hex(uint8_t const * input, size_t length) {
|
||||
std::string output;
|
||||
std::string hex = "0123456789ABCDEF";
|
||||
|
||||
@@ -67,8 +70,8 @@ inline std::string to_hex(const char* input,size_t length) {
|
||||
return to_hex(reinterpret_cast<const uint8_t*>(input),length);
|
||||
}
|
||||
|
||||
inline std::string string_replace_all(std::string subject, const std::string&
|
||||
search, const std::string& replace)
|
||||
inline std::string string_replace_all(std::string subject, std::string const &
|
||||
search, std::string const & replace)
|
||||
{
|
||||
size_t pos = 0;
|
||||
while((pos = subject.find(search, pos)) != std::string::npos) {
|
||||
|
||||
+71
-15
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Peter Thorson. All rights reserved.
|
||||
* Copyright (c) 2014, Peter Thorson. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
@@ -40,13 +40,16 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <ctime>
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include <websocketpp/logger/levels.hpp>
|
||||
|
||||
#include <websocketpp/common/cpp11.hpp>
|
||||
#include <websocketpp/common/stdint.hpp>
|
||||
#include <websocketpp/logger/levels.hpp>
|
||||
#include <websocketpp/common/time.hpp>
|
||||
|
||||
#include <ctime>
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include <string>
|
||||
|
||||
namespace websocketpp {
|
||||
namespace log {
|
||||
@@ -55,16 +58,58 @@ namespace log {
|
||||
template <typename concurrency, typename names>
|
||||
class basic {
|
||||
public:
|
||||
basic<concurrency,names>(std::ostream * out = &std::cout)
|
||||
basic<concurrency,names>(channel_type_hint::value h =
|
||||
channel_type_hint::access)
|
||||
: m_static_channels(0xffffffff)
|
||||
, m_dynamic_channels(0)
|
||||
, m_out(h == channel_type_hint::error ? &std::cerr : &std::cout) {}
|
||||
|
||||
basic<concurrency,names>(std::ostream * out)
|
||||
: m_static_channels(0xffffffff)
|
||||
, m_dynamic_channels(0)
|
||||
, m_out(out) {}
|
||||
|
||||
basic<concurrency,names>(level c, std::ostream * out = &std::cout)
|
||||
basic<concurrency,names>(level c, channel_type_hint::value h =
|
||||
channel_type_hint::access)
|
||||
: m_static_channels(c)
|
||||
, m_dynamic_channels(0)
|
||||
, m_out(h == channel_type_hint::error ? &std::cerr : &std::cout) {}
|
||||
|
||||
basic<concurrency,names>(level c, std::ostream * out)
|
||||
: m_static_channels(c)
|
||||
, m_dynamic_channels(0)
|
||||
, m_out(out) {}
|
||||
|
||||
/// Destructor
|
||||
~basic<concurrency,names>() {}
|
||||
|
||||
/// Copy constructor
|
||||
basic<concurrency,names>(basic<concurrency,names> const & other)
|
||||
: m_static_channels(other.m_static_channels)
|
||||
, m_dynamic_channels(other.m_dynamic_channels)
|
||||
, m_out(other.m_out)
|
||||
{}
|
||||
|
||||
#ifdef _WEBSOCKETPP_DEFAULT_DELETE_FUNCTIONS_
|
||||
// no copy assignment operator because of const member variables
|
||||
basic<concurrency,names> & operator=(basic<concurrency,names> const &) = delete;
|
||||
#endif // _WEBSOCKETPP_DEFAULT_DELETE_FUNCTIONS_
|
||||
|
||||
#ifdef _WEBSOCKETPP_MOVE_SEMANTICS_
|
||||
/// Move constructor
|
||||
basic<concurrency,names>(basic<concurrency,names> && other)
|
||||
: m_static_channels(other.m_static_channels)
|
||||
, m_dynamic_channels(other.m_dynamic_channels)
|
||||
, m_out(other.m_out)
|
||||
{}
|
||||
|
||||
#ifdef _WEBSOCKETPP_DEFAULT_DELETE_FUNCTIONS_
|
||||
// no move assignment operator because of const member variables
|
||||
basic<concurrency,names> & operator=(basic<concurrency,names> &&) = delete;
|
||||
#endif // _WEBSOCKETPP_DEFAULT_DELETE_FUNCTIONS_
|
||||
|
||||
#endif // _WEBSOCKETPP_MOVE_SEMANTICS_
|
||||
|
||||
void set_ostream(std::ostream * out = &std::cout) {
|
||||
m_out = out;
|
||||
}
|
||||
@@ -84,6 +129,11 @@ public:
|
||||
m_dynamic_channels &= ~channels;
|
||||
}
|
||||
|
||||
/// Write a string message to the given channel
|
||||
/**
|
||||
* @param channel The channel to write to
|
||||
* @param msg The message to write
|
||||
*/
|
||||
void write(level channel, std::string const & msg) {
|
||||
scoped_lock_type lock(m_lock);
|
||||
if (!this->dynamic_test(channel)) { return; }
|
||||
@@ -93,6 +143,11 @@ public:
|
||||
m_out->flush();
|
||||
}
|
||||
|
||||
/// Write a cstring message to the given channel
|
||||
/**
|
||||
* @param channel The channel to write to
|
||||
* @param msg The message to write
|
||||
*/
|
||||
void write(level channel, char const * msg) {
|
||||
scoped_lock_type lock(m_lock);
|
||||
if (!this->dynamic_test(channel)) { return; }
|
||||
@@ -109,10 +164,13 @@ public:
|
||||
bool dynamic_test(level channel) {
|
||||
return ((channel & m_dynamic_channels) != 0);
|
||||
}
|
||||
private:
|
||||
|
||||
protected:
|
||||
typedef typename concurrency::scoped_lock_type scoped_lock_type;
|
||||
typedef typename concurrency::mutex_type mutex_type;
|
||||
mutex_type m_lock;
|
||||
|
||||
private:
|
||||
// The timestamp does not include the time zone, because on Windows with the
|
||||
// default registry settings, the time zone would be written out in full,
|
||||
// which would be obnoxiously verbose.
|
||||
@@ -120,18 +178,16 @@ private:
|
||||
// TODO: find a workaround for this or make this format user settable
|
||||
static std::ostream & timestamp(std::ostream & os) {
|
||||
std::time_t t = std::time(NULL);
|
||||
std::tm* lt = std::localtime(&t);
|
||||
#ifdef _WEBSOCKETPP_CPP11_CHRONO_
|
||||
return os << std::put_time(lt,"%Y-%m-%d %H:%M:%S");
|
||||
std::tm lt = lib::localtime(t);
|
||||
#ifdef _WEBSOCKETPP_PUTTIME_
|
||||
return os << std::put_time(<,"%Y-%m-%d %H:%M:%S");
|
||||
#else // Falls back to strftime, which requires a temporary copy of the string.
|
||||
char buffer[20];
|
||||
std::strftime(buffer,sizeof(buffer),"%Y-%m-%d %H:%M:%S",lt);
|
||||
return os << buffer;
|
||||
size_t result = std::strftime(buffer,sizeof(buffer),"%Y-%m-%d %H:%M:%S",<);
|
||||
return os << (result == 0 ? "Unknown" : buffer);
|
||||
#endif
|
||||
}
|
||||
|
||||
mutex_type m_lock;
|
||||
|
||||
level const m_static_channels;
|
||||
level m_dynamic_channels;
|
||||
std::ostream * m_out;
|
||||
|
||||
+31
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Peter Thorson. All rights reserved.
|
||||
* Copyright (c) 2014, Peter Thorson. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
@@ -36,6 +36,25 @@ namespace log {
|
||||
/// Type of a channel package
|
||||
typedef uint32_t level;
|
||||
|
||||
/// Package of values for hinting at the nature of a given logger.
|
||||
/**
|
||||
* Used by the library to signal to the logging class a hint that it can use to
|
||||
* set itself up. For example, the `access` hint indicates that it is an access
|
||||
* log that might be suitable for being printed to an access log file or to cout
|
||||
* whereas `error` might be suitable for an error log file or cerr.
|
||||
*/
|
||||
struct channel_type_hint {
|
||||
/// Type of a channel type hint value
|
||||
typedef uint32_t value;
|
||||
|
||||
/// No information
|
||||
static value const none = 0;
|
||||
/// Access log
|
||||
static value const access = 1;
|
||||
/// Error log
|
||||
static value const error = 2;
|
||||
};
|
||||
|
||||
/// Package of log levels for logging errors
|
||||
struct elevel {
|
||||
/// Special aggregate value representing "no levels"
|
||||
@@ -122,6 +141,13 @@ struct alevel {
|
||||
static level const devel = 0x400;
|
||||
/// Special channel for application specific logs. Not used by the library.
|
||||
static level const app = 0x800;
|
||||
/// Access related to HTTP requests
|
||||
static level const http = 0x1000;
|
||||
/// One line for each failed WebSocket connection with details
|
||||
static level const fail = 0x2000;
|
||||
/// Aggregate package representing the commonly used core access channels
|
||||
/// Connect, Disconnect, Fail, and HTTP
|
||||
static level const access_core = 0x00003003;
|
||||
/// Special aggregate value representing "all levels"
|
||||
static level const all = 0xffffffff;
|
||||
|
||||
@@ -161,6 +187,10 @@ struct alevel {
|
||||
return "devel";
|
||||
case app:
|
||||
return "application";
|
||||
case http:
|
||||
return "http";
|
||||
case fail:
|
||||
return "fail";
|
||||
default:
|
||||
return "unknown";
|
||||
}
|
||||
|
||||
+67
-11
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Peter Thorson. All rights reserved.
|
||||
* Copyright (c) 2014, Peter Thorson. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
@@ -28,10 +28,11 @@
|
||||
#ifndef WEBSOCKETPP_LOGGER_STUB_HPP
|
||||
#define WEBSOCKETPP_LOGGER_STUB_HPP
|
||||
|
||||
#include <iostream>
|
||||
#include <websocketpp/logger/levels.hpp>
|
||||
|
||||
#include <websocketpp/common/cpp11.hpp>
|
||||
#include <websocketpp/logger/levels.hpp>
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace websocketpp {
|
||||
namespace log {
|
||||
@@ -39,20 +40,75 @@ namespace log {
|
||||
/// Stub logger that ignores all input
|
||||
class stub {
|
||||
public:
|
||||
explicit stub(std::ostream * out) {}
|
||||
stub(level c, std::ostream * out) {}
|
||||
/// Construct the logger
|
||||
/**
|
||||
* @param hint A channel type specific hint for how to construct the logger
|
||||
*/
|
||||
explicit stub(channel_type_hint::value) {}
|
||||
|
||||
/// Construct the logger
|
||||
/**
|
||||
* @param default_channels A set of channels to statically enable
|
||||
* @param hint A channel type specific hint for how to construct the logger
|
||||
*/
|
||||
stub(level, channel_type_hint::value) {}
|
||||
_WEBSOCKETPP_CONSTEXPR_TOKEN_ stub() {}
|
||||
|
||||
void set_channels(level channels) {}
|
||||
void clear_channels(level channels) {}
|
||||
/// Dynamically enable the given list of channels
|
||||
/**
|
||||
* All operations on the stub logger are no-ops and all arguments are
|
||||
* ignored
|
||||
*
|
||||
* @param channels The package of channels to enable
|
||||
*/
|
||||
void set_channels(level) {}
|
||||
|
||||
void write(level channel, std::string const & msg) {}
|
||||
void write(level channel, char const * msg) {}
|
||||
/// Dynamically disable the given list of channels
|
||||
/**
|
||||
* All operations on the stub logger are no-ops and all arguments are
|
||||
* ignored
|
||||
*
|
||||
* @param channels The package of channels to disable
|
||||
*/
|
||||
void clear_channels(level) {}
|
||||
|
||||
_WEBSOCKETPP_CONSTEXPR_TOKEN_ bool static_test(level channel) const {
|
||||
/// Write a string message to the given channel
|
||||
/**
|
||||
* Writing on the stub logger is a no-op and all arguments are ignored
|
||||
*
|
||||
* @param channel The channel to write to
|
||||
* @param msg The message to write
|
||||
*/
|
||||
void write(level, std::string const &) {}
|
||||
|
||||
/// Write a cstring message to the given channel
|
||||
/**
|
||||
* Writing on the stub logger is a no-op and all arguments are ignored
|
||||
*
|
||||
* @param channel The channel to write to
|
||||
* @param msg The message to write
|
||||
*/
|
||||
void write(level, char const *) {}
|
||||
|
||||
/// Test whether a channel is statically enabled
|
||||
/**
|
||||
* The stub logger has no channels so all arguments are ignored and
|
||||
* `static_test` always returns false.
|
||||
*
|
||||
* @param channel The package of channels to test
|
||||
*/
|
||||
_WEBSOCKETPP_CONSTEXPR_TOKEN_ bool static_test(level) const {
|
||||
return false;
|
||||
}
|
||||
bool dynamic_test(level channel) {
|
||||
|
||||
/// Test whether a channel is dynamically enabled
|
||||
/**
|
||||
* The stub logger has no channels so all arguments are ignored and
|
||||
* `dynamic_test` always returns false.
|
||||
*
|
||||
* @param channel The package of channels to test
|
||||
*/
|
||||
bool dynamic_test(level) {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Peter Thorson. All rights reserved.
|
||||
* Copyright (c) 2014, Peter Thorson. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
@@ -53,7 +53,7 @@ public:
|
||||
* @return A shared pointer to an empty new message
|
||||
*/
|
||||
message_ptr get_message() {
|
||||
return message_ptr(new message(type::shared_from_this()));
|
||||
return message_ptr(lib::make_shared<message>(type::shared_from_this()));
|
||||
}
|
||||
|
||||
/// Get a message buffer with specified size and opcode
|
||||
@@ -64,7 +64,7 @@ public:
|
||||
* @return A shared pointer to a new message with specified size.
|
||||
*/
|
||||
message_ptr get_message(frame::opcode::value op,size_t size) {
|
||||
return message_ptr(new message(type::shared_from_this(),op,size));
|
||||
return message_ptr(lib::make_shared<message>(type::shared_from_this(),op,size));
|
||||
}
|
||||
|
||||
/// Recycle a message
|
||||
@@ -77,7 +77,7 @@ public:
|
||||
*
|
||||
* @return true if the message was successfully recycled, false otherwse.
|
||||
*/
|
||||
bool recycle(message * msg) {
|
||||
bool recycle(message *) {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
@@ -94,7 +94,7 @@ public:
|
||||
* @return A pointer to the requested connection message manager.
|
||||
*/
|
||||
con_msg_man_ptr get_manager() const {
|
||||
return con_msg_man_ptr(new con_msg_manager());
|
||||
return con_msg_man_ptr(lib::make_shared<con_msg_manager>());
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Peter Thorson. All rights reserved.
|
||||
* Copyright (c) 2014, Peter Thorson. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
@@ -43,7 +43,7 @@ namespace message_buffer {
|
||||
*
|
||||
* # connection_message_manager:
|
||||
* An object that manages all of the message_buffers associated with a given
|
||||
* connection. Impliments the get_message_buffer(size) method that returns
|
||||
* connection. Implements the get_message_buffer(size) method that returns
|
||||
* a message buffer at least size bytes long.
|
||||
*
|
||||
* Message buffers are reference counted with shared ownership semantics. Once
|
||||
@@ -54,7 +54,7 @@ namespace message_buffer {
|
||||
* in the manager.
|
||||
*
|
||||
* # endpoint_message_manager:
|
||||
* An object that manages connection_message_managers. Impliments the
|
||||
* An object that manages connection_message_managers. Implements the
|
||||
* get_message_manager() method. This is used once by each connection to
|
||||
* request the message manager that they are supposed to use to manage message
|
||||
* buffers for their own use.
|
||||
@@ -146,10 +146,10 @@ public:
|
||||
|
||||
/// Set or clear the compression flag
|
||||
/**
|
||||
* The compression flag is used to indicate whether or not the message is
|
||||
* or should be compressed. Compression is not guaranteed. Both endpoints
|
||||
* must support a compression extension and the connection must have had
|
||||
* that extension negotiated in its handshake.
|
||||
* Setting the compression flag indicates that the data in this message
|
||||
* would benefit from compression. If both endpoints negotiate a compression
|
||||
* extension WebSocket++ will attempt to compress messages with this flag.
|
||||
* Setting this flag does not guarantee that the message will be compressed.
|
||||
*
|
||||
* @param value The value to set the compressed flag to
|
||||
*/
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Peter Thorson. All rights reserved.
|
||||
* Copyright (c) 2014, Peter Thorson. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
@@ -42,7 +42,7 @@ namespace message_buffer {
|
||||
*
|
||||
* # connection_message_manager:
|
||||
* An object that manages all of the message_buffers associated with a given
|
||||
* connection. Impliments the get_message_buffer(size) method that returns
|
||||
* connection. Implements the get_message_buffer(size) method that returns
|
||||
* a message buffer at least size bytes long.
|
||||
*
|
||||
* Message buffers are reference counted with shared ownership semantics. Once
|
||||
@@ -53,7 +53,7 @@ namespace message_buffer {
|
||||
* in the manager.
|
||||
*
|
||||
* # endpoint_message_manager:
|
||||
* An object that manages connection_message_managers. Impliments the
|
||||
* An object that manages connection_message_managers. Implements the
|
||||
* get_message_manager() method. This is used once by each connection to
|
||||
* request the message manager that they are supposed to use to manage message
|
||||
* buffers for their own use.
|
||||
@@ -171,7 +171,7 @@ public:
|
||||
* @return A shared pointer to a new message with specified size.
|
||||
*/
|
||||
message_ptr get_message(size_t size) const {
|
||||
return message_ptr(new message(size));
|
||||
return lib::make_shared<message>(size);
|
||||
}
|
||||
|
||||
/// Recycle a message
|
||||
@@ -201,7 +201,7 @@ public:
|
||||
* @return A pointer to the requested connection message manager.
|
||||
*/
|
||||
con_msg_man_ptr get_manager() const {
|
||||
return con_msg_man_ptr(new con_msg_manager());
|
||||
return lib::make_shared<con_msg_manager>();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
+11
-6
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Peter Thorson. All rights reserved.
|
||||
* Copyright (c) 2014, Peter Thorson. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
@@ -28,14 +28,13 @@
|
||||
#ifndef WEBSOCKETPP_PROCESSOR_BASE_HPP
|
||||
#define WEBSOCKETPP_PROCESSOR_BASE_HPP
|
||||
|
||||
#include <websocketpp/common/cpp11.hpp>
|
||||
#include <websocketpp/common/system_error.hpp>
|
||||
|
||||
#include <websocketpp/close.hpp>
|
||||
#include <websocketpp/utilities.hpp>
|
||||
#include <websocketpp/uri.hpp>
|
||||
|
||||
#include <map>
|
||||
#include <websocketpp/common/cpp11.hpp>
|
||||
#include <websocketpp/common/system_error.hpp>
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace websocketpp {
|
||||
@@ -151,7 +150,11 @@ enum processor_errors {
|
||||
extension_parse_error,
|
||||
|
||||
/// Extension related operation was ignored because extensions are disabled
|
||||
extensions_disabled
|
||||
extensions_disabled,
|
||||
|
||||
/// Short Ke3 read. Hybi00 requires a third key to be read from the 8 bytes
|
||||
/// after the handshake. Less than 8 bytes were read.
|
||||
short_key3
|
||||
};
|
||||
|
||||
/// Category for processor errors
|
||||
@@ -223,6 +226,8 @@ public:
|
||||
return "Error parsing extension header";
|
||||
case error::extensions_disabled:
|
||||
return "Extensions are disabled";
|
||||
case error::short_key3:
|
||||
return "Short Hybi00 Key 3 read";
|
||||
default:
|
||||
return "Unknown";
|
||||
}
|
||||
|
||||
+97
-27
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Peter Thorson. All rights reserved.
|
||||
* Copyright (c) 2014, Peter Thorson. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
@@ -28,15 +28,21 @@
|
||||
#ifndef WEBSOCKETPP_PROCESSOR_HYBI00_HPP
|
||||
#define WEBSOCKETPP_PROCESSOR_HYBI00_HPP
|
||||
|
||||
#include <cstdlib>
|
||||
|
||||
#include <websocketpp/frame.hpp>
|
||||
#include <websocketpp/http/constants.hpp>
|
||||
|
||||
#include <websocketpp/utf8_validator.hpp>
|
||||
#include <websocketpp/common/network.hpp>
|
||||
#include <websocketpp/common/md5.hpp>
|
||||
#include <websocketpp/common/platforms.hpp>
|
||||
|
||||
#include <websocketpp/processors/processor.hpp>
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstdlib>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace websocketpp {
|
||||
namespace processor {
|
||||
|
||||
@@ -57,8 +63,8 @@ public:
|
||||
|
||||
typedef typename config::con_msg_manager_type::ptr msg_manager_ptr;
|
||||
|
||||
explicit hybi00(bool secure, bool server, msg_manager_ptr manager)
|
||||
: processor<config>(secure, server)
|
||||
explicit hybi00(bool secure, bool p_is_server, msg_manager_ptr manager)
|
||||
: processor<config>(secure, p_is_server)
|
||||
, msg_hdr(0x00)
|
||||
, msg_ftr(0xff)
|
||||
, m_state(HEADER)
|
||||
@@ -81,9 +87,9 @@ public:
|
||||
// Host is required by HTTP/1.1
|
||||
// Connection is required by is_websocket_handshake
|
||||
// Upgrade is required by is_websocket_handshake
|
||||
if (r.get_header("Sec-WebSocket-Key1") == "" ||
|
||||
r.get_header("Sec-WebSocket-Key2") == "" ||
|
||||
r.get_header("Sec-WebSocket-Key3") == "")
|
||||
if (r.get_header("Sec-WebSocket-Key1").empty() ||
|
||||
r.get_header("Sec-WebSocket-Key2").empty() ||
|
||||
r.get_header("Sec-WebSocket-Key3").empty())
|
||||
{
|
||||
return make_error_code(error::missing_required_header);
|
||||
}
|
||||
@@ -107,9 +113,9 @@ public:
|
||||
// if it is less the final key will almost certainly be wrong.
|
||||
// TODO: decide if it is best to silently fail here or produce some sort
|
||||
// of warning or exception.
|
||||
const std::string& key3 = req.get_header("Sec-WebSocket-Key3");
|
||||
std::string const & key3 = req.get_header("Sec-WebSocket-Key3");
|
||||
std::copy(key3.c_str(),
|
||||
key3.c_str()+std::min(static_cast<size_t>(8), key3.size()),
|
||||
key3.c_str()+(std::min)(static_cast<size_t>(8), key3.size()),
|
||||
&key_final[8]);
|
||||
|
||||
res.append_header(
|
||||
@@ -122,33 +128,50 @@ public:
|
||||
|
||||
// Echo back client's origin unless our local application set a
|
||||
// more restrictive one.
|
||||
if (res.get_header("Sec-WebSocket-Origin") == "") {
|
||||
if (res.get_header("Sec-WebSocket-Origin").empty()) {
|
||||
res.append_header("Sec-WebSocket-Origin",req.get_header("Origin"));
|
||||
}
|
||||
|
||||
// Echo back the client's request host unless our local application
|
||||
// set a different one.
|
||||
if (res.get_header("Sec-WebSocket-Location") == "") {
|
||||
if (res.get_header("Sec-WebSocket-Location").empty()) {
|
||||
uri_ptr uri = get_uri(req);
|
||||
res.append_header("Sec-WebSocket-Location",uri->str());
|
||||
}
|
||||
|
||||
if (subprotocol != "") {
|
||||
if (!subprotocol.empty()) {
|
||||
res.replace_header("Sec-WebSocket-Protocol",subprotocol);
|
||||
}
|
||||
|
||||
return lib::error_code();
|
||||
}
|
||||
|
||||
// outgoing client connection processing is not supported for this version
|
||||
lib::error_code client_handshake_request(request_type& req, uri_ptr uri,
|
||||
std::vector<std::string> const & subprotocols) const
|
||||
/// Fill in a set of request headers for a client connection request
|
||||
/**
|
||||
* The Hybi 00 processor only implements incoming connections so this will
|
||||
* always return an error.
|
||||
*
|
||||
* @param [out] req Set of headers to fill in
|
||||
* @param [in] uri The uri being connected to
|
||||
* @param [in] subprotocols The list of subprotocols to request
|
||||
*/
|
||||
lib::error_code client_handshake_request(request_type &, uri_ptr,
|
||||
std::vector<std::string> const &) const
|
||||
{
|
||||
return error::make_error_code(error::no_protocol_support);
|
||||
}
|
||||
|
||||
lib::error_code validate_server_handshake_response(request_type const & req,
|
||||
response_type & res) const
|
||||
/// Validate the server's response to an outgoing handshake request
|
||||
/**
|
||||
* The Hybi 00 processor only implements incoming connections so this will
|
||||
* always return an error.
|
||||
*
|
||||
* @param req The original request sent
|
||||
* @param res The reponse to generate
|
||||
* @return An error code, 0 on success, non-zero for other errors
|
||||
*/
|
||||
lib::error_code validate_server_handshake_response(request_type const &,
|
||||
response_type &) const
|
||||
{
|
||||
return error::make_error_code(error::no_protocol_support);
|
||||
}
|
||||
@@ -163,10 +186,31 @@ public:
|
||||
return r.get_header("Origin");
|
||||
}
|
||||
|
||||
// hybi00 doesn't support subprotocols so there never will be any requested
|
||||
/// Extracts requested subprotocols from a handshake request
|
||||
/**
|
||||
* hybi00 does support subprotocols
|
||||
* https://tools.ietf.org/html/draft-ietf-hybi-thewebsocketprotocol-00#section-1.9
|
||||
*
|
||||
* @param [in] req The request to extract from
|
||||
* @param [out] subprotocol_list A reference to a vector of strings to store
|
||||
* the results in.
|
||||
*/
|
||||
lib::error_code extract_subprotocols(request_type const & req,
|
||||
std::vector<std::string> & subprotocol_list)
|
||||
{
|
||||
if (!req.get_header("Sec-WebSocket-Protocol").empty()) {
|
||||
http::parameter_list p;
|
||||
|
||||
if (!req.get_header_as_plist("Sec-WebSocket-Protocol",p)) {
|
||||
http::parameter_list::const_iterator it;
|
||||
|
||||
for (it = p.begin(); it != p.end(); ++it) {
|
||||
subprotocol_list.push_back(it->first);
|
||||
}
|
||||
} else {
|
||||
return error::make_error_code(error::subprotocol_parse_error);
|
||||
}
|
||||
}
|
||||
return lib::error_code();
|
||||
}
|
||||
|
||||
@@ -184,12 +228,12 @@ public:
|
||||
if (last_colon == std::string::npos ||
|
||||
(last_sbrace != std::string::npos && last_sbrace > last_colon))
|
||||
{
|
||||
return uri_ptr(new uri(base::m_secure, h, request.get_uri()));
|
||||
return lib::make_shared<uri>(base::m_secure, h, request.get_uri());
|
||||
} else {
|
||||
return uri_ptr(new uri(base::m_secure,
|
||||
return lib::make_shared<uri>(base::m_secure,
|
||||
h.substr(0,last_colon),
|
||||
h.substr(last_colon+1),
|
||||
request.get_uri()));
|
||||
request.get_uri());
|
||||
}
|
||||
|
||||
// TODO: check if get_uri is a full uri
|
||||
@@ -318,18 +362,44 @@ public:
|
||||
return lib::error_code();
|
||||
}
|
||||
|
||||
lib::error_code prepare_ping(std::string const & in, message_ptr out) const
|
||||
/// Prepare a ping frame
|
||||
/**
|
||||
* Hybi 00 doesn't support pings so this will always return an error
|
||||
*
|
||||
* @param in The string to use for the ping payload
|
||||
* @param out The message buffer to prepare the ping in.
|
||||
* @return Status code, zero on success, non-zero on failure
|
||||
*/
|
||||
lib::error_code prepare_ping(std::string const &, message_ptr) const
|
||||
{
|
||||
return lib::error_code(error::no_protocol_support);
|
||||
}
|
||||
|
||||
lib::error_code prepare_pong(const std::string & in, message_ptr out) const
|
||||
/// Prepare a pong frame
|
||||
/**
|
||||
* Hybi 00 doesn't support pongs so this will always return an error
|
||||
*
|
||||
* @param in The string to use for the pong payload
|
||||
* @param out The message buffer to prepare the pong in.
|
||||
* @return Status code, zero on success, non-zero on failure
|
||||
*/
|
||||
lib::error_code prepare_pong(std::string const &, message_ptr) const
|
||||
{
|
||||
return lib::error_code(error::no_protocol_support);
|
||||
}
|
||||
|
||||
lib::error_code prepare_close(close::status::value code,
|
||||
std::string const & reason, message_ptr out) const
|
||||
/// Prepare a close frame
|
||||
/**
|
||||
* Hybi 00 doesn't support the close code or reason so these parameters are
|
||||
* ignored.
|
||||
*
|
||||
* @param code The close code to send
|
||||
* @param reason The reason string to send
|
||||
* @param out The message buffer to prepare the fame in
|
||||
* @return Status code, zero on success, non-zero on failure
|
||||
*/
|
||||
lib::error_code prepare_close(close::status::value, std::string const &,
|
||||
message_ptr out) const
|
||||
{
|
||||
if (!out) {
|
||||
return lib::error_code(error::invalid_arguments);
|
||||
@@ -346,7 +416,7 @@ public:
|
||||
private:
|
||||
void decode_client_key(std::string const & key, char * result) const {
|
||||
unsigned int spaces = 0;
|
||||
std::string digits = "";
|
||||
std::string digits;
|
||||
uint32_t num;
|
||||
|
||||
// key2
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Peter Thorson. All rights reserved.
|
||||
* Copyright (c) 2014, Peter Thorson. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
@@ -30,6 +30,9 @@
|
||||
|
||||
#include <websocketpp/processors/hybi08.hpp>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace websocketpp {
|
||||
namespace processor {
|
||||
|
||||
@@ -45,13 +48,20 @@ public:
|
||||
typedef typename config::con_msg_manager_type::ptr msg_manager_ptr;
|
||||
typedef typename config::rng_type rng_type;
|
||||
|
||||
explicit hybi07(bool secure, bool server, msg_manager_ptr manager,
|
||||
rng_type& rng)
|
||||
: hybi08<config>(secure, server, manager, rng) {}
|
||||
explicit hybi07(bool secure, bool p_is_server, msg_manager_ptr manager, rng_type& rng)
|
||||
: hybi08<config>(secure, p_is_server, manager, rng) {}
|
||||
|
||||
// outgoing client connection processing is not supported for this version
|
||||
lib::error_code client_handshake_request(request_type & req, uri_ptr uri,
|
||||
std::vector<std::string> const & subprotocols) const
|
||||
/// Fill in a set of request headers for a client connection request
|
||||
/**
|
||||
* The Hybi 07 processor only implements incoming connections so this will
|
||||
* always return an error.
|
||||
*
|
||||
* @param [out] req Set of headers to fill in
|
||||
* @param [in] uri The uri being connected to
|
||||
* @param [in] subprotocols The list of subprotocols to request
|
||||
*/
|
||||
lib::error_code client_handshake_request(request_type &, uri_ptr,
|
||||
std::vector<std::string> const &) const
|
||||
{
|
||||
return error::make_error_code(error::no_protocol_support);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Peter Thorson. All rights reserved.
|
||||
* Copyright (c) 2014, Peter Thorson. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
@@ -30,6 +30,9 @@
|
||||
|
||||
#include <websocketpp/processors/hybi13.hpp>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace websocketpp {
|
||||
namespace processor {
|
||||
|
||||
@@ -46,13 +49,20 @@ public:
|
||||
typedef typename config::con_msg_manager_type::ptr msg_manager_ptr;
|
||||
typedef typename config::rng_type rng_type;
|
||||
|
||||
explicit hybi08(bool secure, bool server, msg_manager_ptr manager,
|
||||
rng_type& rng)
|
||||
: hybi13<config>(secure, server, manager, rng) {}
|
||||
explicit hybi08(bool secure, bool p_is_server, msg_manager_ptr manager, rng_type& rng)
|
||||
: hybi13<config>(secure, p_is_server, manager, rng) {}
|
||||
|
||||
// outgoing client connection processing is not supported for this version
|
||||
lib::error_code client_handshake_request(request_type& req, uri_ptr uri,
|
||||
std::vector<std::string> const & subprotocols) const
|
||||
/// Fill in a set of request headers for a client connection request
|
||||
/**
|
||||
* The Hybi 08 processor only implements incoming connections so this will
|
||||
* always return an error.
|
||||
*
|
||||
* @param [out] req Set of headers to fill in
|
||||
* @param [in] uri The uri being connected to
|
||||
* @param [in] subprotocols The list of subprotocols to request
|
||||
*/
|
||||
lib::error_code client_handshake_request(request_type &, uri_ptr,
|
||||
std::vector<std::string> const &) const
|
||||
{
|
||||
return error::make_error_code(error::no_protocol_support);
|
||||
}
|
||||
@@ -61,7 +71,7 @@ public:
|
||||
return 8;
|
||||
}
|
||||
|
||||
const std::string& get_origin(request_type const & r) const {
|
||||
std::string const & get_origin(request_type const & r) const {
|
||||
return r.get_header("Sec-WebSocket-Origin");
|
||||
}
|
||||
private:
|
||||
|
||||
+160
-80
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Peter Thorson. All rights reserved.
|
||||
* Copyright (c) 2015, Peter Thorson. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
@@ -28,18 +28,20 @@
|
||||
#ifndef WEBSOCKETPP_PROCESSOR_HYBI13_HPP
|
||||
#define WEBSOCKETPP_PROCESSOR_HYBI13_HPP
|
||||
|
||||
#include <cassert>
|
||||
|
||||
#include <websocketpp/frame.hpp>
|
||||
#include <websocketpp/utf8_validator.hpp>
|
||||
#include <websocketpp/common/network.hpp>
|
||||
#include <websocketpp/http/constants.hpp>
|
||||
|
||||
#include <websocketpp/processors/processor.hpp>
|
||||
|
||||
#include <websocketpp/frame.hpp>
|
||||
#include <websocketpp/http/constants.hpp>
|
||||
|
||||
#include <websocketpp/utf8_validator.hpp>
|
||||
#include <websocketpp/sha1/sha1.hpp>
|
||||
#include <websocketpp/base64/base64.hpp>
|
||||
|
||||
#include <websocketpp/common/network.hpp>
|
||||
#include <websocketpp/common/platforms.hpp>
|
||||
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <utility>
|
||||
@@ -67,9 +69,8 @@ public:
|
||||
|
||||
typedef std::pair<lib::error_code,std::string> err_str_pair;
|
||||
|
||||
explicit hybi13(bool secure, bool server, msg_manager_ptr manager,
|
||||
rng_type& rng)
|
||||
: processor<config>(secure,server)
|
||||
explicit hybi13(bool secure, bool p_is_server, msg_manager_ptr manager, rng_type& rng)
|
||||
: processor<config>(secure, p_is_server)
|
||||
, m_msg_manager(manager)
|
||||
, m_rng(rng)
|
||||
{
|
||||
@@ -84,7 +85,21 @@ public:
|
||||
return m_permessage_deflate.is_implemented();
|
||||
}
|
||||
|
||||
err_str_pair negotiate_extensions(request_type const & req) {
|
||||
err_str_pair negotiate_extensions(request_type const & request) {
|
||||
return negotiate_extensions_helper(request);
|
||||
}
|
||||
|
||||
err_str_pair negotiate_extensions(response_type const & response) {
|
||||
return negotiate_extensions_helper(response);
|
||||
}
|
||||
|
||||
/// Extension negotiation helper function
|
||||
/**
|
||||
* This exists mostly because the code for requests and responses is
|
||||
* identical and I can't have virtual template methods.
|
||||
*/
|
||||
template <typename header_type>
|
||||
err_str_pair negotiate_extensions_helper(header_type const & header) {
|
||||
err_str_pair ret;
|
||||
|
||||
// Respect blanket disabling of all extensions and don't even parse
|
||||
@@ -96,7 +111,7 @@ public:
|
||||
|
||||
http::parameter_list p;
|
||||
|
||||
bool error = req.get_header_as_plist("Sec-WebSocket-Extensions",p);
|
||||
bool error = header.get_header_as_plist("Sec-WebSocket-Extensions",p);
|
||||
|
||||
if (error) {
|
||||
ret.first = make_error_code(error::extension_parse_error);
|
||||
@@ -115,18 +130,27 @@ public:
|
||||
for (it = p.begin(); it != p.end(); ++it) {
|
||||
// look through each extension, if the key is permessage-deflate
|
||||
if (it->first == "permessage-deflate") {
|
||||
// if we have already successfully negotiated this extension
|
||||
// then skip any other requests to negotiate the same one
|
||||
// with different parameters
|
||||
if (m_permessage_deflate.is_enabled()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
neg_ret = m_permessage_deflate.negotiate(it->second);
|
||||
|
||||
if (neg_ret.first) {
|
||||
// Figure out if this is an error that should halt all
|
||||
// extension negotiations or simply cause negotiation of
|
||||
// this specific extension to fail.
|
||||
std::cout << "permessage-compress negotiation failed: "
|
||||
<< neg_ret.first.message() << std::endl;
|
||||
//std::cout << "permessage-compress negotiation failed: "
|
||||
// << neg_ret.first.message() << std::endl;
|
||||
} else {
|
||||
// Note: this list will need commas if WebSocket++ ever
|
||||
// supports more than one extension
|
||||
ret.second += neg_ret.second;
|
||||
m_permessage_deflate.init(base::m_server);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
@@ -149,7 +173,7 @@ public:
|
||||
// Host is required by HTTP/1.1
|
||||
// Connection is required by is_websocket_handshake
|
||||
// Upgrade is required by is_websocket_handshake
|
||||
if (r.get_header("Sec-WebSocket-Key") == "") {
|
||||
if (r.get_header("Sec-WebSocket-Key").empty()) {
|
||||
return make_error_code(error::missing_required_header);
|
||||
}
|
||||
|
||||
@@ -160,8 +184,8 @@ public:
|
||||
* generic struct if other user input parameters to the processed handshake
|
||||
* are found.
|
||||
*/
|
||||
lib::error_code process_handshake(request_type const & request, const
|
||||
std::string & subprotocol, response_type& response) const
|
||||
lib::error_code process_handshake(request_type const & request,
|
||||
std::string const & subprotocol, response_type & response) const
|
||||
{
|
||||
std::string server_key = request.get_header("Sec-WebSocket-Key");
|
||||
|
||||
@@ -182,7 +206,13 @@ public:
|
||||
return lib::error_code();
|
||||
}
|
||||
|
||||
lib::error_code client_handshake_request(request_type& req, uri_ptr
|
||||
/// Fill in a set of request headers for a client connection request
|
||||
/**
|
||||
* @param [out] req Set of headers to fill in
|
||||
* @param [in] uri The uri being connected to
|
||||
* @param [in] subprotocols The list of subprotocols to request
|
||||
*/
|
||||
lib::error_code client_handshake_request(request_type & req, uri_ptr
|
||||
uri, std::vector<std::string> const & subprotocols) const
|
||||
{
|
||||
req.set_method("GET");
|
||||
@@ -216,9 +246,22 @@ public:
|
||||
|
||||
req.replace_header("Sec-WebSocket-Key",base64_encode(raw_key, 16));
|
||||
|
||||
if (m_permessage_deflate.is_implemented()) {
|
||||
std::string offer = m_permessage_deflate.generate_offer();
|
||||
if (!offer.empty()) {
|
||||
req.replace_header("Sec-WebSocket-Extensions",offer);
|
||||
}
|
||||
}
|
||||
|
||||
return lib::error_code();
|
||||
}
|
||||
|
||||
/// Validate the server's response to an outgoing handshake request
|
||||
/**
|
||||
* @param req The original request sent
|
||||
* @param res The reponse to generate
|
||||
* @return An error code, 0 on success, non-zero for other errors
|
||||
*/
|
||||
lib::error_code validate_server_handshake_response(request_type const & req,
|
||||
response_type& res) const
|
||||
{
|
||||
@@ -251,6 +294,8 @@ public:
|
||||
return error::make_error_code(error::missing_required_header);
|
||||
}
|
||||
|
||||
// check extensions
|
||||
|
||||
return lib::error_code();
|
||||
}
|
||||
|
||||
@@ -369,11 +414,29 @@ public:
|
||||
m_current_msg = &m_control_msg;
|
||||
} else {
|
||||
if (!m_data_msg.msg_ptr) {
|
||||
if (m_bytes_needed > base::m_max_message_size) {
|
||||
ec = make_error_code(error::message_too_big);
|
||||
break;
|
||||
}
|
||||
|
||||
m_data_msg = msg_metadata(
|
||||
m_msg_manager->get_message(op,m_bytes_needed),
|
||||
frame::get_masking_key(m_basic_header,m_extended_header)
|
||||
);
|
||||
|
||||
if (m_permessage_deflate.is_enabled()) {
|
||||
m_data_msg.msg_ptr->set_compressed(frame::get_rsv1(m_basic_header));
|
||||
}
|
||||
} else {
|
||||
// Fetch the underlying payload buffer from the data message we
|
||||
// are writing into.
|
||||
std::string & out = m_data_msg.msg_ptr->get_raw_payload();
|
||||
|
||||
if (out.size() + m_bytes_needed > base::m_max_message_size) {
|
||||
ec = make_error_code(error::message_too_big);
|
||||
break;
|
||||
}
|
||||
|
||||
// Each frame starts a new masking key. All other state
|
||||
// remains between frames.
|
||||
m_data_msg.prepared_key = prepare_masking_key(
|
||||
@@ -382,14 +445,15 @@ public:
|
||||
m_extended_header
|
||||
)
|
||||
);
|
||||
// TODO: reserve space in the existing message for the new bytes
|
||||
|
||||
out.reserve(out.size() + m_bytes_needed);
|
||||
}
|
||||
m_current_msg = &m_data_msg;
|
||||
}
|
||||
} else if (m_state == EXTENSION) {
|
||||
m_state = APPLICATION;
|
||||
} else if (m_state == APPLICATION) {
|
||||
size_t bytes_to_process = std::min(m_bytes_needed,len-p);
|
||||
size_t bytes_to_process = (std::min)(m_bytes_needed,len-p);
|
||||
|
||||
if (bytes_to_process > 0) {
|
||||
p += this->process_payload_bytes(buf+p,bytes_to_process,ec);
|
||||
@@ -404,15 +468,10 @@ public:
|
||||
// If this was the last frame in the message set the ready flag.
|
||||
// Otherwise, reset processor state to read additional frames.
|
||||
if (frame::get_fin(m_basic_header)) {
|
||||
// ensure that text messages end on a valid UTF8 code point
|
||||
if (frame::get_opcode(m_basic_header) == frame::opcode::TEXT) {
|
||||
if (!m_current_msg->validator.complete()) {
|
||||
ec = make_error_code(error::invalid_utf8);
|
||||
break;
|
||||
}
|
||||
ec = finalize_message();
|
||||
if (ec) {
|
||||
break;
|
||||
}
|
||||
|
||||
m_state = READY;
|
||||
} else {
|
||||
this->reset_headers();
|
||||
}
|
||||
@@ -426,6 +485,44 @@ public:
|
||||
return p;
|
||||
}
|
||||
|
||||
/// Perform any finalization actions on an incoming message
|
||||
/**
|
||||
* Called after the full message is received. Provides the opportunity for
|
||||
* extensions to complete any data post processing as well as final UTF8
|
||||
* validation checks for text messages.
|
||||
*
|
||||
* @return A code indicating errors, if any
|
||||
*/
|
||||
lib::error_code finalize_message() {
|
||||
std::string & out = m_current_msg->msg_ptr->get_raw_payload();
|
||||
|
||||
// if the frame is compressed, append the compression
|
||||
// trailer and flush the compression buffer.
|
||||
if (m_permessage_deflate.is_enabled()
|
||||
&& m_current_msg->msg_ptr->get_compressed())
|
||||
{
|
||||
uint8_t trailer[4] = {0x00, 0x00, 0xff, 0xff};
|
||||
|
||||
// Decompress current buffer into the message buffer
|
||||
lib::error_code ec;
|
||||
ec = m_permessage_deflate.decompress(trailer,4,out);
|
||||
if (ec) {
|
||||
return ec;
|
||||
}
|
||||
}
|
||||
|
||||
// ensure that text messages end on a valid UTF8 code point
|
||||
if (frame::get_opcode(m_basic_header) == frame::opcode::TEXT) {
|
||||
if (!m_current_msg->validator.complete()) {
|
||||
return make_error_code(error::invalid_utf8);
|
||||
}
|
||||
}
|
||||
|
||||
m_state = READY;
|
||||
|
||||
return lib::error_code();
|
||||
}
|
||||
|
||||
void reset_headers() {
|
||||
m_state = HEADER_BASIC;
|
||||
m_bytes_needed = frame::BASIC_HEADER_LENGTH;
|
||||
@@ -477,19 +574,6 @@ public:
|
||||
* Performs validation, masking, compression, etc. will return an error if
|
||||
* there was an error, otherwise msg will be ready to be written
|
||||
*
|
||||
* By default WebSocket++ performs block masking/unmasking in a manner that
|
||||
* makes 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 masking 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.
|
||||
*
|
||||
* TODO: tests
|
||||
*
|
||||
* @param in An unprepared message to prepare
|
||||
@@ -523,18 +607,11 @@ public:
|
||||
&& in->get_compressed();
|
||||
bool fin = in->get_fin();
|
||||
|
||||
// generate header
|
||||
frame::basic_header h(op,i.size(),fin,masked,compressed);
|
||||
|
||||
if (masked) {
|
||||
// Generate masking key.
|
||||
key.i = m_rng();
|
||||
|
||||
frame::extended_header e(i.size(),key.i);
|
||||
out->set_header(frame::prepare_header(h,e));
|
||||
} else {
|
||||
frame::extended_header e(i.size());
|
||||
out->set_header(frame::prepare_header(h,e));
|
||||
key.i = 0;
|
||||
}
|
||||
|
||||
// prepare payload
|
||||
@@ -542,6 +619,14 @@ public:
|
||||
// compress and store in o after header.
|
||||
m_permessage_deflate.compress(i,o);
|
||||
|
||||
if (o.size() < 4) {
|
||||
return make_error_code(error::general);
|
||||
}
|
||||
|
||||
// Strip trailing 4 0x00 0x00 0xff 0xff bytes before writing to the
|
||||
// wire
|
||||
o.resize(o.size()-4);
|
||||
|
||||
// mask in place if necessary
|
||||
if (masked) {
|
||||
this->masked_copy(o,o,key);
|
||||
@@ -560,7 +645,19 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
// generate header
|
||||
frame::basic_header h(op,o.size(),fin,masked,compressed);
|
||||
|
||||
if (masked) {
|
||||
frame::extended_header e(o.size(),key.i);
|
||||
out->set_header(frame::prepare_header(h,e));
|
||||
} else {
|
||||
frame::extended_header e(o.size());
|
||||
out->set_header(frame::prepare_header(h,e));
|
||||
}
|
||||
|
||||
out->set_prepared(true);
|
||||
out->set_opcode(op);
|
||||
|
||||
return lib::error_code();
|
||||
}
|
||||
@@ -655,7 +752,7 @@ protected:
|
||||
|
||||
/// Reads bytes from buf into m_extended_header
|
||||
size_t copy_extended_header_bytes(uint8_t const * buf, size_t len) {
|
||||
size_t bytes_to_read = std::min(m_bytes_needed,len);
|
||||
size_t bytes_to_read = (std::min)(m_bytes_needed,len);
|
||||
|
||||
std::copy(buf,buf+bytes_to_read,m_extended_header.bytes+m_cursor);
|
||||
m_cursor += bytes_to_read;
|
||||
@@ -681,19 +778,9 @@ protected:
|
||||
{
|
||||
// unmask if masked
|
||||
if (frame::get_masked(m_basic_header)) {
|
||||
#ifdef WEBSOCKETPP_STRICT_MASKING
|
||||
m_current_msg->prepared_key = frame::byte_mask_circ(
|
||||
buf,
|
||||
len,
|
||||
m_current_msg->prepared_key
|
||||
);
|
||||
#else
|
||||
m_current_msg->prepared_key = frame::word_mask_circ(
|
||||
buf,
|
||||
len,
|
||||
m_current_msg->prepared_key
|
||||
);
|
||||
#endif
|
||||
m_current_msg->prepared_key = frame::byte_mask_circ(
|
||||
buf, len, m_current_msg->prepared_key);
|
||||
// TODO: SIMD masking
|
||||
}
|
||||
|
||||
std::string & out = m_current_msg->msg_ptr->get_raw_payload();
|
||||
@@ -701,13 +788,13 @@ protected:
|
||||
|
||||
// decompress message if needed.
|
||||
if (m_permessage_deflate.is_enabled()
|
||||
&& frame::get_rsv1(m_basic_header))
|
||||
&& m_current_msg->msg_ptr->get_compressed())
|
||||
{
|
||||
// Decompress current buffer into the message buffer
|
||||
m_permessage_deflate.decompress(buf,len,out);
|
||||
|
||||
// get the length of the newly uncompressed output
|
||||
offset = out.size() - offset;
|
||||
ec = m_permessage_deflate.decompress(buf,len,out);
|
||||
if (ec) {
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
// No compression, straight copy
|
||||
out.append(reinterpret_cast<char *>(buf),len);
|
||||
@@ -852,16 +939,8 @@ protected:
|
||||
void masked_copy (std::string const & i, std::string & o,
|
||||
frame::masking_key_type key) const
|
||||
{
|
||||
#ifdef WEBSOCKETPP_STRICT_MASKING
|
||||
frame::byte_mask(i.begin(),i.end(),o.begin(),key);
|
||||
#else
|
||||
websocketpp::frame::word_mask_exact(
|
||||
reinterpret_cast<uint8_t *>(const_cast<char *>(i.data())),
|
||||
reinterpret_cast<uint8_t *>(const_cast<char *>(o.data())),
|
||||
i.size(),
|
||||
key
|
||||
);
|
||||
#endif
|
||||
frame::byte_mask(i.begin(),i.end(),o.begin(),key);
|
||||
// TODO: SIMD masking
|
||||
}
|
||||
|
||||
/// Generic prepare control frame with opcode and payload.
|
||||
@@ -908,7 +987,8 @@ protected:
|
||||
out->set_header(frame::prepare_header(h,e));
|
||||
std::copy(payload.begin(),payload.end(),o.begin());
|
||||
}
|
||||
|
||||
|
||||
out->set_opcode(op);
|
||||
out->set_prepared(true);
|
||||
|
||||
return lib::error_code();
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Peter Thorson. All rights reserved.
|
||||
* Copyright (c) 2015, Peter Thorson. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
@@ -35,8 +35,10 @@
|
||||
#include <websocketpp/utilities.hpp>
|
||||
#include <websocketpp/uri.hpp>
|
||||
|
||||
#include <map>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
namespace websocketpp {
|
||||
/// Processors encapsulate the protocol rules specific to each WebSocket version
|
||||
@@ -103,7 +105,11 @@ bool is_websocket_handshake(request_type& r) {
|
||||
*/
|
||||
template <typename request_type>
|
||||
int get_websocket_version(request_type& r) {
|
||||
if (r.get_header("Sec-WebSocket-Version") == "") {
|
||||
if (!r.ready()) {
|
||||
return -2;
|
||||
}
|
||||
|
||||
if (r.get_header("Sec-WebSocket-Version").empty()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -140,12 +146,12 @@ uri_ptr get_uri_from_host(request_type & request, std::string scheme) {
|
||||
if (last_colon == std::string::npos ||
|
||||
(last_sbrace != std::string::npos && last_sbrace > last_colon))
|
||||
{
|
||||
return uri_ptr(new uri(scheme, h, request.get_uri()));
|
||||
return lib::make_shared<uri>(scheme, h, request.get_uri());
|
||||
} else {
|
||||
return uri_ptr(new uri(scheme,
|
||||
return lib::make_shared<uri>(scheme,
|
||||
h.substr(0,last_colon),
|
||||
h.substr(last_colon+1),
|
||||
request.get_uri()));
|
||||
request.get_uri());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -159,15 +165,45 @@ public:
|
||||
typedef typename config::message_type::ptr message_ptr;
|
||||
typedef std::pair<lib::error_code,std::string> err_str_pair;
|
||||
|
||||
explicit processor(bool secure, bool server)
|
||||
explicit processor(bool secure, bool p_is_server)
|
||||
: m_secure(secure)
|
||||
, m_server(server) {}
|
||||
, m_server(p_is_server)
|
||||
, m_max_message_size(config::max_message_size)
|
||||
{}
|
||||
|
||||
virtual ~processor() {}
|
||||
|
||||
/// Get the protocol version of this processor
|
||||
virtual int get_version() const = 0;
|
||||
|
||||
/// Get maximum message size
|
||||
/**
|
||||
* Get maximum message size. Maximum message size determines the point at which the
|
||||
* processor will fail a connection with the message_too_big protocol error.
|
||||
*
|
||||
* The default is retrieved from the max_message_size value from the template config
|
||||
*
|
||||
* @since 0.3.0
|
||||
*/
|
||||
size_t get_max_message_size() const {
|
||||
return m_max_message_size;
|
||||
}
|
||||
|
||||
/// Set maximum message size
|
||||
/**
|
||||
* Set maximum message size. Maximum message size determines the point at which the
|
||||
* processor will fail a connection with the message_too_big protocol error.
|
||||
*
|
||||
* The default is retrieved from the max_message_size value from the template config
|
||||
*
|
||||
* @since 0.3.0
|
||||
*
|
||||
* @param new_value The value to set as the maximum message size.
|
||||
*/
|
||||
void set_max_message_size(size_t new_value) {
|
||||
m_max_message_size = new_value;
|
||||
}
|
||||
|
||||
/// Returns whether or not the permessage_compress extension is implemented
|
||||
/**
|
||||
* Compile time flag that indicates whether this processor has implemented
|
||||
@@ -181,9 +217,26 @@ public:
|
||||
/**
|
||||
* Reads the Sec-WebSocket-Extensions header and determines if any of the
|
||||
* requested extensions are supported by this processor. If they are their
|
||||
* settings data is initialized.
|
||||
* settings data is initialized and an extension string to send to the
|
||||
* is returned.
|
||||
*
|
||||
* @param request The request or response headers to look at.
|
||||
*/
|
||||
virtual err_str_pair negotiate_extensions(request_type const & request) {
|
||||
virtual err_str_pair negotiate_extensions(request_type const &) {
|
||||
return err_str_pair();
|
||||
}
|
||||
|
||||
/// Initializes extensions based on the Sec-WebSocket-Extensions header
|
||||
/**
|
||||
* Reads the Sec-WebSocket-Extensions header and determines if any of the
|
||||
* requested extensions were accepted by the server. If they are their
|
||||
* settings data is initialized. If they are not a list of required
|
||||
* extensions (if any) is returned. This list may be sent back to the server
|
||||
* as a part of the 1010/Extension required close code.
|
||||
*
|
||||
* @param response The request or response headers to look at.
|
||||
*/
|
||||
virtual err_str_pair negotiate_extensions(response_type const &) {
|
||||
return err_str_pair();
|
||||
}
|
||||
|
||||
@@ -196,8 +249,7 @@ public:
|
||||
* @return A status code, 0 on success, non-zero for specific sorts of
|
||||
* failure
|
||||
*/
|
||||
virtual lib::error_code validate_handshake(request_type const & request)
|
||||
const = 0;
|
||||
virtual lib::error_code validate_handshake(request_type const & request) const = 0;
|
||||
|
||||
/// Calculate the appropriate response for this websocket request
|
||||
/**
|
||||
@@ -224,9 +276,7 @@ public:
|
||||
/// Validate the server's response to an outgoing handshake request
|
||||
/**
|
||||
* @param req The original request sent
|
||||
*
|
||||
* @param res The reponse to generate
|
||||
*
|
||||
* @return An error code, 0 on success, non-zero for other errors
|
||||
*/
|
||||
virtual lib::error_code validate_server_handshake_response(request_type
|
||||
@@ -236,18 +286,16 @@ public:
|
||||
virtual std::string get_raw(response_type const & request) const = 0;
|
||||
|
||||
/// Return the value of the header containing the CORS origin.
|
||||
virtual std::string const & get_origin(request_type const & request)
|
||||
const = 0;
|
||||
virtual std::string const & get_origin(request_type const & request) const = 0;
|
||||
|
||||
/// Extracts requested subprotocols from a handshake request
|
||||
/**
|
||||
* Extracts a list of all subprotocols that the client has requested in the
|
||||
* given opening handshake request.
|
||||
*
|
||||
* @param req The request to extract from
|
||||
*
|
||||
* @param subprotocol_list A reference to a vector of strings to store the
|
||||
* results in.
|
||||
* @param [in] req The request to extract from
|
||||
* @param [out] subprotocol_list A reference to a vector of strings to store
|
||||
* the results in.
|
||||
*/
|
||||
virtual lib::error_code extract_subprotocols(const request_type & req,
|
||||
std::vector<std::string> & subprotocol_list) = 0;
|
||||
@@ -261,11 +309,8 @@ public:
|
||||
* interpreted by a protocol processor into discrete frames.
|
||||
*
|
||||
* @param buf Buffer from which bytes should be read.
|
||||
*
|
||||
* @param len Length of buffer
|
||||
*
|
||||
* @param ec Reference to an error code to return any errors in
|
||||
*
|
||||
* @return Number of bytes processed
|
||||
*/
|
||||
virtual size_t consume(uint8_t *buf, size_t len, lib::error_code & ec) = 0;
|
||||
@@ -310,8 +355,7 @@ public:
|
||||
* Performs validation, masking, compression, etc. will return an error if
|
||||
* there was an error, otherwise msg will be ready to be written
|
||||
*/
|
||||
virtual lib::error_code prepare_data_frame(message_ptr in, message_ptr out)
|
||||
= 0;
|
||||
virtual lib::error_code prepare_data_frame(message_ptr in, message_ptr out) = 0;
|
||||
|
||||
/// Prepare a ping frame
|
||||
/**
|
||||
@@ -319,13 +363,11 @@ public:
|
||||
* other than length. Payload need not be UTF-8.
|
||||
*
|
||||
* @param in The string to use for the ping payload
|
||||
*
|
||||
* @param out The message buffer to prepare the ping in.
|
||||
*
|
||||
* @return Status code, zero on success, non-zero on failure
|
||||
*/
|
||||
virtual lib::error_code prepare_ping(std::string const & in,
|
||||
message_ptr out) const = 0;
|
||||
virtual lib::error_code prepare_ping(std::string const & in, message_ptr out) const
|
||||
= 0;
|
||||
|
||||
/// Prepare a pong frame
|
||||
/**
|
||||
@@ -333,13 +375,11 @@ public:
|
||||
* other than length. Payload need not be UTF-8.
|
||||
*
|
||||
* @param in The string to use for the pong payload
|
||||
*
|
||||
* @param out The message buffer to prepare the pong in.
|
||||
*
|
||||
* @return Status code, zero on success, non-zero on failure
|
||||
*/
|
||||
virtual lib::error_code prepare_pong(std::string const & in,
|
||||
message_ptr out) const = 0;
|
||||
virtual lib::error_code prepare_pong(std::string const & in, message_ptr out) const
|
||||
= 0;
|
||||
|
||||
/// Prepare a close frame
|
||||
/**
|
||||
@@ -349,11 +389,8 @@ public:
|
||||
* indicate no code. If no code is supplied a reason may not be specified.
|
||||
*
|
||||
* @param code The close code to send
|
||||
*
|
||||
* @param reason The reason string to send
|
||||
*
|
||||
* @param out The message buffer to prepare the fame in
|
||||
*
|
||||
* @return Status code, zero on success, non-zero on failure
|
||||
*/
|
||||
virtual lib::error_code prepare_close(close::status::value code,
|
||||
@@ -361,6 +398,7 @@ public:
|
||||
protected:
|
||||
bool const m_secure;
|
||||
bool const m_server;
|
||||
size_t m_max_message_size;
|
||||
};
|
||||
|
||||
} // namespace processor
|
||||
|
||||
+2
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Peter Thorson. All rights reserved.
|
||||
* Copyright (c) 2014, Peter Thorson. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
@@ -29,6 +29,7 @@
|
||||
#define WEBSOCKETPP_RANDOM_NONE_HPP
|
||||
|
||||
namespace websocketpp {
|
||||
/// Random number generation policies
|
||||
namespace random {
|
||||
/// Stub RNG policy that always returns 0
|
||||
namespace none {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Peter Thorson. All rights reserved.
|
||||
* Copyright (c) 2014, Peter Thorson. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Peter Thorson. All rights reserved.
|
||||
* Copyright (c) 2014, Peter Thorson. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
@@ -29,13 +29,16 @@
|
||||
#define WEBSOCKETPP_CLIENT_ENDPOINT_HPP
|
||||
|
||||
#include <websocketpp/endpoint.hpp>
|
||||
#include <websocketpp/uri.hpp>
|
||||
|
||||
#include <websocketpp/logger/levels.hpp>
|
||||
|
||||
#include <iostream>
|
||||
#include <websocketpp/common/system_error.hpp>
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace websocketpp {
|
||||
|
||||
|
||||
/// Client endpoint role based on the given config
|
||||
/**
|
||||
*
|
||||
@@ -64,6 +67,8 @@ public:
|
||||
/// Type of the endpoint component of this server
|
||||
typedef endpoint<connection_type,config> endpoint_type;
|
||||
|
||||
friend class connection<config>;
|
||||
|
||||
explicit client() : endpoint_type(false)
|
||||
{
|
||||
endpoint_type::m_alog.write(log::alevel::devel, "client constructor");
|
||||
@@ -112,7 +117,7 @@ public:
|
||||
* @return A connection_ptr to the new connection
|
||||
*/
|
||||
connection_ptr get_connection(std::string const & u, lib::error_code & ec) {
|
||||
uri_ptr location(new uri(u));
|
||||
uri_ptr location = lib::make_shared<uri>(u);
|
||||
|
||||
if (!location->get_valid()) {
|
||||
ec = error::make_error_code(error::invalid_uri);
|
||||
|
||||
+100
-27
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Peter Thorson. All rights reserved.
|
||||
* Copyright (c) 2014, Peter Thorson. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
@@ -29,13 +29,13 @@
|
||||
#define WEBSOCKETPP_SERVER_ENDPOINT_HPP
|
||||
|
||||
#include <websocketpp/endpoint.hpp>
|
||||
|
||||
#include <websocketpp/logger/levels.hpp>
|
||||
|
||||
#include <iostream>
|
||||
#include <websocketpp/common/system_error.hpp>
|
||||
|
||||
namespace websocketpp {
|
||||
|
||||
|
||||
/// Server endpoint role based on the given config
|
||||
/**
|
||||
*
|
||||
@@ -64,52 +64,125 @@ public:
|
||||
/// Type of the endpoint component of this server
|
||||
typedef endpoint<connection_type,config> endpoint_type;
|
||||
|
||||
|
||||
// TODO: clean up these types
|
||||
friend class connection<config>;
|
||||
|
||||
explicit server() : endpoint_type(true)
|
||||
{
|
||||
endpoint_type::m_alog.write(log::alevel::devel,
|
||||
"server constructor");
|
||||
endpoint_type::m_alog.write(log::alevel::devel, "server constructor");
|
||||
}
|
||||
|
||||
// return an initialized connection_ptr. Call start() on this object to
|
||||
// begin the processing loop.
|
||||
/// Destructor
|
||||
~server<config>() {}
|
||||
|
||||
#ifdef _WEBSOCKETPP_DEFAULT_DELETE_FUNCTIONS_
|
||||
// no copy constructor because endpoints are not copyable
|
||||
server<config>(server<config> &) = delete;
|
||||
|
||||
// no copy assignment operator because endpoints are not copyable
|
||||
server<config> & operator=(server<config> const &) = delete;
|
||||
#endif // _WEBSOCKETPP_DEFAULT_DELETE_FUNCTIONS_
|
||||
|
||||
#ifdef _WEBSOCKETPP_MOVE_SEMANTICS_
|
||||
/// Move constructor
|
||||
server<config>(server<config> && o) : endpoint<connection<config>,config>(std::move(o)) {}
|
||||
|
||||
#ifdef _WEBSOCKETPP_DEFAULT_DELETE_FUNCTIONS_
|
||||
// no move assignment operator because of const member variables
|
||||
server<config> & operator=(server<config> &&) = delete;
|
||||
#endif // _WEBSOCKETPP_DEFAULT_DELETE_FUNCTIONS_
|
||||
|
||||
#endif // _WEBSOCKETPP_MOVE_SEMANTICS_
|
||||
|
||||
/// Create and initialize a new connection
|
||||
/**
|
||||
* The connection will be initialized and ready to begin. Call its start()
|
||||
* method to begin the processing loop.
|
||||
*
|
||||
* Note: The connection must either be started or terminated using
|
||||
* connection::terminate in order to avoid memory leaks.
|
||||
*
|
||||
* @return A pointer to the new connection.
|
||||
*/
|
||||
connection_ptr get_connection() {
|
||||
connection_ptr con = endpoint_type::create_connection();
|
||||
|
||||
return con;
|
||||
return endpoint_type::create_connection();
|
||||
}
|
||||
|
||||
// Starts the server's async connection acceptance loop.
|
||||
void start_accept() {
|
||||
/// Starts the server's async connection acceptance loop (exception free)
|
||||
/**
|
||||
* Initiates the server connection acceptance loop. Must be called after
|
||||
* listen. This method will have no effect until the underlying io_service
|
||||
* starts running. It may be called after the io_service is already running.
|
||||
*
|
||||
* Refer to documentation for the transport policy you are using for
|
||||
* instructions on how to stop this acceptance loop.
|
||||
*
|
||||
* @param [out] ec A status code indicating an error, if any.
|
||||
*/
|
||||
void start_accept(lib::error_code & ec) {
|
||||
if (!transport_type::is_listening()) {
|
||||
ec = error::make_error_code(error::async_accept_not_listening);
|
||||
return;
|
||||
}
|
||||
|
||||
ec = lib::error_code();
|
||||
connection_ptr con = get_connection();
|
||||
|
||||
|
||||
transport_type::async_accept(
|
||||
lib::static_pointer_cast<transport_con_type>(con),
|
||||
lib::bind(
|
||||
&type::handle_accept,
|
||||
this,
|
||||
con,
|
||||
lib::placeholders::_1
|
||||
)
|
||||
lib::bind(&type::handle_accept,this,con,lib::placeholders::_1),
|
||||
ec
|
||||
);
|
||||
|
||||
if (ec && con) {
|
||||
// If the connection was constructed but the accept failed,
|
||||
// terminate the connection to prevent memory leaks
|
||||
con->terminate(lib::error_code());
|
||||
}
|
||||
}
|
||||
|
||||
void handle_accept(connection_ptr con, const lib::error_code& ec) {
|
||||
/// Starts the server's async connection acceptance loop
|
||||
/**
|
||||
* Initiates the server connection acceptance loop. Must be called after
|
||||
* listen. This method will have no effect until the underlying io_service
|
||||
* starts running. It may be called after the io_service is already running.
|
||||
*
|
||||
* Refer to documentation for the transport policy you are using for
|
||||
* instructions on how to stop this acceptance loop.
|
||||
*/
|
||||
void start_accept() {
|
||||
lib::error_code ec;
|
||||
start_accept(ec);
|
||||
if (ec) {
|
||||
throw exception(ec);
|
||||
}
|
||||
}
|
||||
|
||||
/// Handler callback for start_accept
|
||||
void handle_accept(connection_ptr con, lib::error_code const & ec) {
|
||||
if (ec) {
|
||||
con->terminate(ec);
|
||||
|
||||
endpoint_type::m_elog.write(log::elevel::rerror,
|
||||
"handle_accept error: "+ec.message());
|
||||
if (ec == error::operation_canceled) {
|
||||
endpoint_type::m_elog.write(log::elevel::info,
|
||||
"handle_accept error: "+ec.message());
|
||||
} else {
|
||||
endpoint_type::m_elog.write(log::elevel::rerror,
|
||||
"handle_accept error: "+ec.message());
|
||||
}
|
||||
} else {
|
||||
con->start();
|
||||
}
|
||||
|
||||
// TODO: are there cases where we should terminate this loop?
|
||||
start_accept();
|
||||
lib::error_code start_ec;
|
||||
start_accept(start_ec);
|
||||
if (start_ec == error::async_accept_not_listening) {
|
||||
endpoint_type::m_elog.write(log::elevel::info,
|
||||
"Stopping acceptance of new connections because the underlying transport is no longer listening.");
|
||||
} else if (start_ec) {
|
||||
endpoint_type::m_elog.write(log::elevel::rerror,
|
||||
"Restarting async_accept loop failed: "+ec.message());
|
||||
}
|
||||
}
|
||||
private:
|
||||
};
|
||||
|
||||
} // namespace websocketpp
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Peter Thorson. All rights reserved.
|
||||
* Copyright (c) 2014, Peter Thorson. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
|
||||
+189
-184
@@ -1,184 +1,189 @@
|
||||
/*
|
||||
*****
|
||||
sha1.hpp is a repackaging of the sha1.cpp and sha1.h files from the shallsha1
|
||||
library (http://code.google.com/p/smallsha1/) into a single header suitable for
|
||||
use as a header only library. This conversion was done by Peter Thorson
|
||||
(webmaster@zaphoyd.com) in 2013. All modifications to the code are redistributed
|
||||
under the same license as the original, which is listed below.
|
||||
*****
|
||||
|
||||
Copyright (c) 2011, Micael Hildenborg
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of Micael Hildenborg nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY Micael Hildenborg ''AS IS'' AND ANY
|
||||
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL Micael Hildenborg BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef SHA1_DEFINED
|
||||
#define SHA1_DEFINED
|
||||
|
||||
namespace websocketpp {
|
||||
namespace sha1 {
|
||||
|
||||
namespace // local
|
||||
{
|
||||
// Rotate an integer value to left.
|
||||
inline const unsigned int rol(const unsigned int value,
|
||||
const unsigned int steps)
|
||||
{
|
||||
return ((value << steps) | (value >> (32 - steps)));
|
||||
}
|
||||
|
||||
// Sets the first 16 integers in the buffert to zero.
|
||||
// Used for clearing the W buffert.
|
||||
inline void clearWBuffert(unsigned int* buffert)
|
||||
{
|
||||
for (int pos = 16; --pos >= 0;)
|
||||
{
|
||||
buffert[pos] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
inline void innerHash(unsigned int* result, unsigned int* w)
|
||||
{
|
||||
unsigned int a = result[0];
|
||||
unsigned int b = result[1];
|
||||
unsigned int c = result[2];
|
||||
unsigned int d = result[3];
|
||||
unsigned int e = result[4];
|
||||
|
||||
int round = 0;
|
||||
|
||||
#define sha1macro(func,val) \
|
||||
{ \
|
||||
const unsigned int t = rol(a, 5) + (func) + e + val + w[round]; \
|
||||
e = d; \
|
||||
d = c; \
|
||||
c = rol(b, 30); \
|
||||
b = a; \
|
||||
a = t; \
|
||||
}
|
||||
|
||||
while (round < 16)
|
||||
{
|
||||
sha1macro((b & c) | (~b & d), 0x5a827999)
|
||||
++round;
|
||||
}
|
||||
while (round < 20)
|
||||
{
|
||||
w[round] = rol((w[round - 3] ^ w[round - 8] ^ w[round - 14] ^ w[round - 16]), 1);
|
||||
sha1macro((b & c) | (~b & d), 0x5a827999)
|
||||
++round;
|
||||
}
|
||||
while (round < 40)
|
||||
{
|
||||
w[round] = rol((w[round - 3] ^ w[round - 8] ^ w[round - 14] ^ w[round - 16]), 1);
|
||||
sha1macro(b ^ c ^ d, 0x6ed9eba1)
|
||||
++round;
|
||||
}
|
||||
while (round < 60)
|
||||
{
|
||||
w[round] = rol((w[round - 3] ^ w[round - 8] ^ w[round - 14] ^ w[round - 16]), 1);
|
||||
sha1macro((b & c) | (b & d) | (c & d), 0x8f1bbcdc)
|
||||
++round;
|
||||
}
|
||||
while (round < 80)
|
||||
{
|
||||
w[round] = rol((w[round - 3] ^ w[round - 8] ^ w[round - 14] ^ w[round - 16]), 1);
|
||||
sha1macro(b ^ c ^ d, 0xca62c1d6)
|
||||
++round;
|
||||
}
|
||||
|
||||
#undef sha1macro
|
||||
|
||||
result[0] += a;
|
||||
result[1] += b;
|
||||
result[2] += c;
|
||||
result[3] += d;
|
||||
result[4] += e;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
/**
|
||||
@param src points to any kind of data to be hashed.
|
||||
@param bytelength the number of bytes to hash from the src pointer.
|
||||
@param hash should point to a buffer of at least 20 bytes of size for storing the sha1 result in.
|
||||
*/
|
||||
inline void calc(const void* src, const int bytelength, unsigned char* hash) {
|
||||
// Init the result array.
|
||||
unsigned int result[5] = { 0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476, 0xc3d2e1f0 };
|
||||
|
||||
// Cast the void src pointer to be the byte array we can work with.
|
||||
const unsigned char* sarray = (const unsigned char*) src;
|
||||
|
||||
// The reusable round buffer
|
||||
unsigned int w[80];
|
||||
|
||||
// Loop through all complete 64byte blocks.
|
||||
const int endOfFullBlocks = bytelength - 64;
|
||||
int endCurrentBlock;
|
||||
int currentBlock = 0;
|
||||
|
||||
while (currentBlock <= endOfFullBlocks)
|
||||
{
|
||||
endCurrentBlock = currentBlock + 64;
|
||||
|
||||
// Init the round buffer with the 64 byte block data.
|
||||
for (int roundPos = 0; currentBlock < endCurrentBlock; currentBlock += 4)
|
||||
{
|
||||
// This line will swap endian on big endian and keep endian on little endian.
|
||||
w[roundPos++] = (unsigned int) sarray[currentBlock + 3]
|
||||
| (((unsigned int) sarray[currentBlock + 2]) << 8)
|
||||
| (((unsigned int) sarray[currentBlock + 1]) << 16)
|
||||
| (((unsigned int) sarray[currentBlock]) << 24);
|
||||
}
|
||||
innerHash(result, w);
|
||||
}
|
||||
|
||||
// Handle the last and not full 64 byte block if existing.
|
||||
endCurrentBlock = bytelength - currentBlock;
|
||||
clearWBuffert(w);
|
||||
int lastBlockBytes = 0;
|
||||
for (;lastBlockBytes < endCurrentBlock; ++lastBlockBytes)
|
||||
{
|
||||
w[lastBlockBytes >> 2] |= (unsigned int) sarray[lastBlockBytes + currentBlock] << ((3 - (lastBlockBytes & 3)) << 3);
|
||||
}
|
||||
w[lastBlockBytes >> 2] |= 0x80 << ((3 - (lastBlockBytes & 3)) << 3);
|
||||
if (endCurrentBlock >= 56)
|
||||
{
|
||||
innerHash(result, w);
|
||||
clearWBuffert(w);
|
||||
}
|
||||
w[15] = bytelength << 3;
|
||||
innerHash(result, w);
|
||||
|
||||
// Store hash in result pointer, and make sure we get in in the correct order on both endian models.
|
||||
for (int hashByte = 20; --hashByte >= 0;)
|
||||
{
|
||||
hash[hashByte] = (result[hashByte >> 2] >> (((3 - hashByte) & 0x3) << 3)) & 0xff;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace sha1
|
||||
} // namespace websocketpp
|
||||
|
||||
#endif // SHA1_DEFINED
|
||||
/*
|
||||
*****
|
||||
sha1.hpp is a repackaging of the sha1.cpp and sha1.h files from the smallsha1
|
||||
library (http://code.google.com/p/smallsha1/) into a single header suitable for
|
||||
use as a header only library. This conversion was done by Peter Thorson
|
||||
(webmaster@zaphoyd.com) in 2013. All modifications to the code are redistributed
|
||||
under the same license as the original, which is listed below.
|
||||
*****
|
||||
|
||||
Copyright (c) 2011, Micael Hildenborg
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of Micael Hildenborg nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY Micael Hildenborg ''AS IS'' AND ANY
|
||||
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL Micael Hildenborg BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef SHA1_DEFINED
|
||||
#define SHA1_DEFINED
|
||||
|
||||
namespace websocketpp {
|
||||
namespace sha1 {
|
||||
|
||||
namespace { // local
|
||||
|
||||
// Rotate an integer value to left.
|
||||
inline unsigned int rol(unsigned int value, unsigned int steps) {
|
||||
return ((value << steps) | (value >> (32 - steps)));
|
||||
}
|
||||
|
||||
// Sets the first 16 integers in the buffert to zero.
|
||||
// Used for clearing the W buffert.
|
||||
inline void clearWBuffert(unsigned int * buffert)
|
||||
{
|
||||
for (int pos = 16; --pos >= 0;)
|
||||
{
|
||||
buffert[pos] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
inline void innerHash(unsigned int * result, unsigned int * w)
|
||||
{
|
||||
unsigned int a = result[0];
|
||||
unsigned int b = result[1];
|
||||
unsigned int c = result[2];
|
||||
unsigned int d = result[3];
|
||||
unsigned int e = result[4];
|
||||
|
||||
int round = 0;
|
||||
|
||||
#define sha1macro(func,val) \
|
||||
{ \
|
||||
const unsigned int t = rol(a, 5) + (func) + e + val + w[round]; \
|
||||
e = d; \
|
||||
d = c; \
|
||||
c = rol(b, 30); \
|
||||
b = a; \
|
||||
a = t; \
|
||||
}
|
||||
|
||||
while (round < 16)
|
||||
{
|
||||
sha1macro((b & c) | (~b & d), 0x5a827999)
|
||||
++round;
|
||||
}
|
||||
while (round < 20)
|
||||
{
|
||||
w[round] = rol((w[round - 3] ^ w[round - 8] ^ w[round - 14] ^ w[round - 16]), 1);
|
||||
sha1macro((b & c) | (~b & d), 0x5a827999)
|
||||
++round;
|
||||
}
|
||||
while (round < 40)
|
||||
{
|
||||
w[round] = rol((w[round - 3] ^ w[round - 8] ^ w[round - 14] ^ w[round - 16]), 1);
|
||||
sha1macro(b ^ c ^ d, 0x6ed9eba1)
|
||||
++round;
|
||||
}
|
||||
while (round < 60)
|
||||
{
|
||||
w[round] = rol((w[round - 3] ^ w[round - 8] ^ w[round - 14] ^ w[round - 16]), 1);
|
||||
sha1macro((b & c) | (b & d) | (c & d), 0x8f1bbcdc)
|
||||
++round;
|
||||
}
|
||||
while (round < 80)
|
||||
{
|
||||
w[round] = rol((w[round - 3] ^ w[round - 8] ^ w[round - 14] ^ w[round - 16]), 1);
|
||||
sha1macro(b ^ c ^ d, 0xca62c1d6)
|
||||
++round;
|
||||
}
|
||||
|
||||
#undef sha1macro
|
||||
|
||||
result[0] += a;
|
||||
result[1] += b;
|
||||
result[2] += c;
|
||||
result[3] += d;
|
||||
result[4] += e;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
/// Calculate a SHA1 hash
|
||||
/**
|
||||
* @param src points to any kind of data to be hashed.
|
||||
* @param bytelength the number of bytes to hash from the src pointer.
|
||||
* @param hash should point to a buffer of at least 20 bytes of size for storing
|
||||
* the sha1 result in.
|
||||
*/
|
||||
inline void calc(void const * src, size_t bytelength, unsigned char * hash) {
|
||||
// Init the result array.
|
||||
unsigned int result[5] = { 0x67452301, 0xefcdab89, 0x98badcfe,
|
||||
0x10325476, 0xc3d2e1f0 };
|
||||
|
||||
// Cast the void src pointer to be the byte array we can work with.
|
||||
unsigned char const * sarray = (unsigned char const *) src;
|
||||
|
||||
// The reusable round buffer
|
||||
unsigned int w[80];
|
||||
|
||||
// Loop through all complete 64byte blocks.
|
||||
|
||||
size_t endCurrentBlock;
|
||||
size_t currentBlock = 0;
|
||||
|
||||
if (bytelength >= 64) {
|
||||
size_t const endOfFullBlocks = bytelength - 64;
|
||||
|
||||
while (currentBlock <= endOfFullBlocks) {
|
||||
endCurrentBlock = currentBlock + 64;
|
||||
|
||||
// Init the round buffer with the 64 byte block data.
|
||||
for (int roundPos = 0; currentBlock < endCurrentBlock; currentBlock += 4)
|
||||
{
|
||||
// This line will swap endian on big endian and keep endian on
|
||||
// little endian.
|
||||
w[roundPos++] = (unsigned int) sarray[currentBlock + 3]
|
||||
| (((unsigned int) sarray[currentBlock + 2]) << 8)
|
||||
| (((unsigned int) sarray[currentBlock + 1]) << 16)
|
||||
| (((unsigned int) sarray[currentBlock]) << 24);
|
||||
}
|
||||
innerHash(result, w);
|
||||
}
|
||||
}
|
||||
|
||||
// Handle the last and not full 64 byte block if existing.
|
||||
endCurrentBlock = bytelength - currentBlock;
|
||||
clearWBuffert(w);
|
||||
size_t lastBlockBytes = 0;
|
||||
for (;lastBlockBytes < endCurrentBlock; ++lastBlockBytes) {
|
||||
w[lastBlockBytes >> 2] |= (unsigned int) sarray[lastBlockBytes + currentBlock] << ((3 - (lastBlockBytes & 3)) << 3);
|
||||
}
|
||||
|
||||
w[lastBlockBytes >> 2] |= 0x80 << ((3 - (lastBlockBytes & 3)) << 3);
|
||||
if (endCurrentBlock >= 56) {
|
||||
innerHash(result, w);
|
||||
clearWBuffert(w);
|
||||
}
|
||||
w[15] = bytelength << 3;
|
||||
innerHash(result, w);
|
||||
|
||||
// Store hash in result pointer, and make sure we get in in the correct
|
||||
// order on both endian models.
|
||||
for (int hashByte = 20; --hashByte >= 0;) {
|
||||
hash[hashByte] = (result[hashByte >> 2] >> (((3 - hashByte) & 0x3) << 3)) & 0xff;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace sha1
|
||||
} // namespace websocketpp
|
||||
|
||||
#endif // SHA1_DEFINED
|
||||
+60
-79
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Peter Thorson. All rights reserved.
|
||||
* Copyright (c) 2015, Peter Thorson. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
@@ -28,123 +28,107 @@
|
||||
#ifndef WEBSOCKETPP_TRANSPORT_ASIO_BASE_HPP
|
||||
#define WEBSOCKETPP_TRANSPORT_ASIO_BASE_HPP
|
||||
|
||||
#include <websocketpp/common/asio.hpp>
|
||||
#include <websocketpp/common/cpp11.hpp>
|
||||
#include <websocketpp/common/functional.hpp>
|
||||
#include <websocketpp/common/system_error.hpp>
|
||||
|
||||
#include <boost/system/error_code.hpp>
|
||||
|
||||
#include <boost/aligned_storage.hpp>
|
||||
#include <boost/noncopyable.hpp>
|
||||
#include <boost/array.hpp>
|
||||
#include <websocketpp/common/type_traits.hpp>
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace websocketpp {
|
||||
namespace transport {
|
||||
/// Transport policy that uses boost::asio
|
||||
/// Transport policy that uses asio
|
||||
/**
|
||||
* This policy uses a single boost::asio io_service to provide transport
|
||||
* This policy uses a single asio io_service to provide transport
|
||||
* services to a WebSocket++ endpoint.
|
||||
*/
|
||||
namespace asio {
|
||||
|
||||
//
|
||||
|
||||
// Class to manage the memory to be used for handler-based custom allocation.
|
||||
// It contains a single block of memory which may be returned for allocation
|
||||
// requests. If the memory is in use when an allocation request is made, the
|
||||
// allocator delegates allocation to the global heap.
|
||||
class handler_allocator
|
||||
: private boost::noncopyable
|
||||
{
|
||||
class handler_allocator {
|
||||
public:
|
||||
handler_allocator()
|
||||
: in_use_(false)
|
||||
{
|
||||
}
|
||||
static const size_t size = 1024;
|
||||
|
||||
handler_allocator() : m_in_use(false) {}
|
||||
|
||||
void* allocate(std::size_t size)
|
||||
{
|
||||
if (!in_use_ && size < storage_.size)
|
||||
{
|
||||
in_use_ = true;
|
||||
return storage_.address();
|
||||
}
|
||||
else
|
||||
{
|
||||
return ::operator new(size);
|
||||
}
|
||||
}
|
||||
#ifdef _WEBSOCKETPP_DEFAULT_DELETE_FUNCTIONS_
|
||||
handler_allocator(handler_allocator const & cpy) = delete;
|
||||
handler_allocator & operator =(handler_allocator const &) = delete;
|
||||
#endif
|
||||
|
||||
void deallocate(void* pointer)
|
||||
{
|
||||
if (pointer == storage_.address())
|
||||
{
|
||||
in_use_ = false;
|
||||
void * allocate(std::size_t memsize) {
|
||||
if (!m_in_use && memsize < size) {
|
||||
m_in_use = true;
|
||||
return static_cast<void*>(&m_storage);
|
||||
} else {
|
||||
return ::operator new(memsize);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
::operator delete(pointer);
|
||||
|
||||
void deallocate(void * pointer) {
|
||||
if (pointer == &m_storage) {
|
||||
m_in_use = false;
|
||||
} else {
|
||||
::operator delete(pointer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
// Storage space used for handler-based custom memory allocation.
|
||||
boost::aligned_storage<1024> storage_;
|
||||
// Storage space used for handler-based custom memory allocation.
|
||||
lib::aligned_storage<size>::type m_storage;
|
||||
|
||||
// Whether the handler-based custom allocation storage has been used.
|
||||
bool in_use_;
|
||||
// Whether the handler-based custom allocation storage has been used.
|
||||
bool m_in_use;
|
||||
};
|
||||
|
||||
// Wrapper class template for handler objects to allow handler memory
|
||||
// allocation to be customised. Calls to operator() are forwarded to the
|
||||
// encapsulated handler.
|
||||
template <typename Handler>
|
||||
class custom_alloc_handler
|
||||
{
|
||||
class custom_alloc_handler {
|
||||
public:
|
||||
custom_alloc_handler(handler_allocator& a, Handler h)
|
||||
: allocator_(a),
|
||||
handler_(h)
|
||||
{
|
||||
}
|
||||
custom_alloc_handler(handler_allocator& a, Handler h)
|
||||
: allocator_(a),
|
||||
handler_(h)
|
||||
{}
|
||||
|
||||
template <typename Arg1>
|
||||
void operator()(Arg1 arg1)
|
||||
{
|
||||
handler_(arg1);
|
||||
}
|
||||
template <typename Arg1>
|
||||
void operator()(Arg1 arg1) {
|
||||
handler_(arg1);
|
||||
}
|
||||
|
||||
template <typename Arg1, typename Arg2>
|
||||
void operator()(Arg1 arg1, Arg2 arg2)
|
||||
{
|
||||
handler_(arg1, arg2);
|
||||
}
|
||||
template <typename Arg1, typename Arg2>
|
||||
void operator()(Arg1 arg1, Arg2 arg2) {
|
||||
handler_(arg1, arg2);
|
||||
}
|
||||
|
||||
friend void* asio_handler_allocate(std::size_t size,
|
||||
custom_alloc_handler<Handler>* this_handler)
|
||||
{
|
||||
return this_handler->allocator_.allocate(size);
|
||||
}
|
||||
friend void* asio_handler_allocate(std::size_t size,
|
||||
custom_alloc_handler<Handler> * this_handler)
|
||||
{
|
||||
return this_handler->allocator_.allocate(size);
|
||||
}
|
||||
|
||||
friend void asio_handler_deallocate(void* pointer, std::size_t /*size*/,
|
||||
custom_alloc_handler<Handler>* this_handler)
|
||||
{
|
||||
this_handler->allocator_.deallocate(pointer);
|
||||
}
|
||||
friend void asio_handler_deallocate(void* pointer, std::size_t /*size*/,
|
||||
custom_alloc_handler<Handler> * this_handler)
|
||||
{
|
||||
this_handler->allocator_.deallocate(pointer);
|
||||
}
|
||||
|
||||
private:
|
||||
handler_allocator& allocator_;
|
||||
Handler handler_;
|
||||
handler_allocator & allocator_;
|
||||
Handler handler_;
|
||||
};
|
||||
|
||||
// Helper function to wrap a handler object to add custom allocation.
|
||||
template <typename Handler>
|
||||
inline custom_alloc_handler<Handler> make_custom_alloc_handler(
|
||||
handler_allocator& a, Handler h)
|
||||
handler_allocator & a, Handler h)
|
||||
{
|
||||
return custom_alloc_handler<Handler>(a, h);
|
||||
return custom_alloc_handler<Handler>(a, h);
|
||||
}
|
||||
|
||||
|
||||
@@ -158,13 +142,10 @@ inline custom_alloc_handler<Handler> make_custom_alloc_handler(
|
||||
template <typename config>
|
||||
class endpoint;
|
||||
|
||||
typedef lib::function<void(boost::system::error_code const &)>
|
||||
socket_shutdown_handler;
|
||||
|
||||
typedef lib::function<void (boost::system::error_code const & ec,
|
||||
typedef lib::function<void (lib::asio::error_code const & ec,
|
||||
size_t bytes_transferred)> async_read_handler;
|
||||
|
||||
typedef lib::function<void (boost::system::error_code const & ec,
|
||||
typedef lib::function<void (lib::asio::error_code const & ec,
|
||||
size_t bytes_transferred)> async_write_handler;
|
||||
|
||||
typedef lib::function<void (lib::error_code const & ec)> pre_init_handler;
|
||||
|
||||
+347
-218
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Peter Thorson. All rights reserved.
|
||||
* Copyright (c) 2015, Peter Thorson. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
@@ -28,21 +28,27 @@
|
||||
#ifndef WEBSOCKETPP_TRANSPORT_ASIO_CON_HPP
|
||||
#define WEBSOCKETPP_TRANSPORT_ASIO_CON_HPP
|
||||
|
||||
#include <websocketpp/common/memory.hpp>
|
||||
#include <websocketpp/common/functional.hpp>
|
||||
#include <websocketpp/common/connection_hdl.hpp>
|
||||
#include <websocketpp/transport/asio/base.hpp>
|
||||
|
||||
#include <websocketpp/transport/base/connection.hpp>
|
||||
|
||||
#include <websocketpp/logger/levels.hpp>
|
||||
#include <websocketpp/http/constants.hpp>
|
||||
#include <websocketpp/transport/asio/base.hpp>
|
||||
#include <websocketpp/transport/base/connection.hpp>
|
||||
|
||||
#include <websocketpp/base64/base64.hpp>
|
||||
#include <websocketpp/error.hpp>
|
||||
#include <websocketpp/uri.hpp>
|
||||
|
||||
#include <boost/asio.hpp>
|
||||
#include <boost/system/error_code.hpp>
|
||||
#include <websocketpp/common/asio.hpp>
|
||||
#include <websocketpp/common/chrono.hpp>
|
||||
#include <websocketpp/common/cpp11.hpp>
|
||||
#include <websocketpp/common/memory.hpp>
|
||||
#include <websocketpp/common/functional.hpp>
|
||||
#include <websocketpp/common/connection_hdl.hpp>
|
||||
|
||||
#include <istream>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace websocketpp {
|
||||
@@ -51,10 +57,10 @@ namespace asio {
|
||||
|
||||
typedef lib::function<void(connection_hdl)> tcp_init_handler;
|
||||
|
||||
/// Boost Asio based connection transport component
|
||||
/// Asio based connection transport component
|
||||
/**
|
||||
* transport::asio::connection implements a connection transport component using
|
||||
* Boost ASIO that works with the transport::asio::endpoint endpoint transport
|
||||
* Asio that works with the transport::asio::endpoint endpoint transport
|
||||
* component.
|
||||
*/
|
||||
template <typename config>
|
||||
@@ -79,12 +85,12 @@ public:
|
||||
typedef typename config::response_type response_type;
|
||||
typedef typename response_type::ptr response_ptr;
|
||||
|
||||
/// Type of a pointer to the ASIO io_service being used
|
||||
typedef boost::asio::io_service* io_service_ptr;
|
||||
/// Type of a pointer to the ASIO io_service::strand being used
|
||||
typedef lib::shared_ptr<boost::asio::io_service::strand> strand_ptr;
|
||||
/// Type of a pointer to the ASIO timer class
|
||||
typedef lib::shared_ptr<boost::asio::deadline_timer> timer_ptr;
|
||||
/// Type of a pointer to the Asio io_service being used
|
||||
typedef lib::asio::io_service * io_service_ptr;
|
||||
/// Type of a pointer to the Asio io_service::strand being used
|
||||
typedef lib::shared_ptr<lib::asio::io_service::strand> strand_ptr;
|
||||
/// Type of a pointer to the Asio timer class
|
||||
typedef lib::shared_ptr<lib::asio::steady_timer> timer_ptr;
|
||||
|
||||
// connection is friends with its associated endpoint to allow the endpoint
|
||||
// to call private/protected utility methods that we don't want to expose
|
||||
@@ -92,7 +98,7 @@ public:
|
||||
friend class endpoint<config>;
|
||||
|
||||
// generate and manage our own io_service
|
||||
explicit connection(bool is_server, alog_type& alog, elog_type& elog)
|
||||
explicit connection(bool is_server, alog_type & alog, elog_type & elog)
|
||||
: m_is_server(is_server)
|
||||
, m_alog(alog)
|
||||
, m_elog(elog)
|
||||
@@ -109,13 +115,29 @@ public:
|
||||
return socket_con_type::is_secure();
|
||||
}
|
||||
|
||||
/// Set uri hook
|
||||
/**
|
||||
* Called by the endpoint as a connection is being established to provide
|
||||
* the uri being connected to to the transport layer.
|
||||
*
|
||||
* This transport policy doesn't use the uri except to forward it to the
|
||||
* socket layer.
|
||||
*
|
||||
* @since 0.6.0
|
||||
*
|
||||
* @param u The uri to set
|
||||
*/
|
||||
void set_uri(uri_ptr u) {
|
||||
socket_con_type::set_uri(u);
|
||||
}
|
||||
|
||||
/// Sets the tcp pre init handler
|
||||
/**
|
||||
* The tcp pre init handler is called after the raw tcp connection has been
|
||||
* established but before any additional wrappers (proxy connects, TLS
|
||||
* handshakes, etc) have been performed.
|
||||
*
|
||||
* @since 0.4.0-alpha1
|
||||
* @since 0.3.0
|
||||
*
|
||||
* @param h The handler to call on tcp pre init.
|
||||
*/
|
||||
@@ -144,7 +166,7 @@ public:
|
||||
* etc have been performed. This is fired before any bytes are read or any
|
||||
* WebSocket specific handshake logic has been performed.
|
||||
*
|
||||
* @since 0.4.0-alpha1
|
||||
* @since 0.3.0
|
||||
*
|
||||
* @param h The handler to call on tcp post init.
|
||||
*/
|
||||
@@ -164,19 +186,19 @@ public:
|
||||
*
|
||||
* @param ec A status value
|
||||
*/
|
||||
void set_proxy(const std::string & uri, lib::error_code & ec) {
|
||||
void set_proxy(std::string const & uri, lib::error_code & ec) {
|
||||
// TODO: return errors for illegal URIs here?
|
||||
// TODO: should https urls be illegal for the moment?
|
||||
m_proxy = uri;
|
||||
m_proxy_data.reset(new proxy_data());
|
||||
m_proxy_data = lib::make_shared<proxy_data>();
|
||||
ec = lib::error_code();
|
||||
}
|
||||
|
||||
/// Set the proxy to connect through (exception)
|
||||
void set_proxy(const std::string & uri) {
|
||||
void set_proxy(std::string const & uri) {
|
||||
lib::error_code ec;
|
||||
set_proxy(uri,ec);
|
||||
if (ec) { throw ec; }
|
||||
if (ec) { throw exception(ec); }
|
||||
}
|
||||
|
||||
/// Set the basic auth credentials to use (exception free)
|
||||
@@ -192,8 +214,8 @@ public:
|
||||
*
|
||||
* @param ec A status value
|
||||
*/
|
||||
void set_proxy_basic_auth(const std::string & username, const
|
||||
std::string & password, lib::error_code & ec)
|
||||
void set_proxy_basic_auth(std::string const & username, std::string const &
|
||||
password, lib::error_code & ec)
|
||||
{
|
||||
if (!m_proxy_data) {
|
||||
ec = make_error_code(websocketpp::error::invalid_state);
|
||||
@@ -207,12 +229,12 @@ public:
|
||||
}
|
||||
|
||||
/// Set the basic auth credentials to use (exception)
|
||||
void set_proxy_basic_auth(const std::string & username, const
|
||||
std::string & password)
|
||||
void set_proxy_basic_auth(std::string const & username, std::string const &
|
||||
password)
|
||||
{
|
||||
lib::error_code ec;
|
||||
set_proxy_basic_auth(username,password,ec);
|
||||
if (ec) { throw ec; }
|
||||
if (ec) { throw exception(ec); }
|
||||
}
|
||||
|
||||
/// Set the proxy timeout duration (exception free)
|
||||
@@ -239,10 +261,10 @@ public:
|
||||
void set_proxy_timeout(long duration) {
|
||||
lib::error_code ec;
|
||||
set_proxy_timeout(duration,ec);
|
||||
if (ec) { throw ec; }
|
||||
if (ec) { throw exception(ec); }
|
||||
}
|
||||
|
||||
const std::string & get_proxy() const {
|
||||
std::string const & get_proxy() const {
|
||||
return m_proxy;
|
||||
}
|
||||
|
||||
@@ -289,11 +311,9 @@ public:
|
||||
* needed.
|
||||
*/
|
||||
timer_ptr set_timer(long duration, timer_handler callback) {
|
||||
timer_ptr new_timer(
|
||||
new boost::asio::deadline_timer(
|
||||
*m_io_service,
|
||||
boost::posix_time::milliseconds(duration)
|
||||
)
|
||||
timer_ptr new_timer = lib::make_shared<lib::asio::steady_timer>(
|
||||
lib::ref(*m_io_service),
|
||||
lib::asio::milliseconds(duration)
|
||||
);
|
||||
|
||||
if (config::enable_multithreading) {
|
||||
@@ -322,15 +342,15 @@ public:
|
||||
*
|
||||
* TODO: candidate for protected status
|
||||
*
|
||||
* @param t Pointer to the timer in question
|
||||
* @param post_timer Pointer to the timer in question
|
||||
* @param callback The function to call back
|
||||
* @param ec The status code
|
||||
*/
|
||||
void handle_timer(timer_ptr t, timer_handler callback,
|
||||
boost::system::error_code const & ec)
|
||||
void handle_timer(timer_ptr, timer_handler callback,
|
||||
lib::asio::error_code const & ec)
|
||||
{
|
||||
if (ec) {
|
||||
if (ec == boost::asio::error::operation_aborted) {
|
||||
if (ec == lib::asio::error::operation_aborted) {
|
||||
callback(make_error_code(transport::error::operation_aborted));
|
||||
} else {
|
||||
log_err(log::elevel::info,"asio handle_timer",ec);
|
||||
@@ -340,16 +360,39 @@ public:
|
||||
callback(lib::error_code());
|
||||
}
|
||||
}
|
||||
protected:
|
||||
|
||||
/// Get a pointer to this connection's strand
|
||||
strand_ptr get_strand() {
|
||||
return m_strand;
|
||||
}
|
||||
|
||||
/// Get the internal transport error code for a closed/failed connection
|
||||
/**
|
||||
* Retrieves a machine readable detailed error code indicating the reason
|
||||
* that the connection was closed or failed. Valid only after the close or
|
||||
* fail handler is called.
|
||||
*
|
||||
* Primarily used if you are using mismatched asio / system_error
|
||||
* implementations such as `boost::asio` with `std::system_error`. In these
|
||||
* cases the transport error type is different than the library error type
|
||||
* and some WebSocket++ functions that return transport errors via the
|
||||
* library error code type will be coerced into a catch all `pass_through`
|
||||
* or `tls_error` error. This method will return the original machine
|
||||
* readable transport error in the native type.
|
||||
*
|
||||
* @since 0.7.0
|
||||
*
|
||||
* @return Error code indicating the reason the connection was closed or
|
||||
* failed
|
||||
*/
|
||||
lib::asio::error_code get_transport_ec() const {
|
||||
return m_tec;
|
||||
}
|
||||
|
||||
/// Initialize transport for reading
|
||||
/**
|
||||
* init_asio is called once immediately after construction to initialize
|
||||
* boost::asio components to the io_service
|
||||
* Asio components to the io_service
|
||||
*
|
||||
* The transport initialization sequence consists of the following steps:
|
||||
* - Pre-init: the underlying socket is initialized to the point where
|
||||
@@ -363,6 +406,7 @@ protected:
|
||||
* read or write the WebSocket handshakes. At this point the original
|
||||
* callback function is called.
|
||||
*/
|
||||
protected:
|
||||
void init(init_handler callback) {
|
||||
if (m_alog.static_test(log::alevel::devel)) {
|
||||
m_alog.write(log::alevel::devel,"asio connection init");
|
||||
@@ -371,12 +415,11 @@ protected:
|
||||
// TODO: pre-init timeout. Right now no implemented socket policies
|
||||
// actually have an asyncronous pre-init
|
||||
|
||||
m_init_handler = callback;
|
||||
|
||||
socket_con_type::pre_init(
|
||||
lib::bind(
|
||||
&type::handle_pre_init,
|
||||
get_shared(),
|
||||
callback,
|
||||
lib::placeholders::_1
|
||||
)
|
||||
);
|
||||
@@ -407,7 +450,7 @@ protected:
|
||||
/// Finish constructing the transport
|
||||
/**
|
||||
* init_asio is called once immediately after construction to initialize
|
||||
* boost::asio components to the io_service
|
||||
* Asio components to the io_service.
|
||||
*
|
||||
* @param io_service A pointer to the io_service to register with this
|
||||
* connection
|
||||
@@ -415,38 +458,20 @@ protected:
|
||||
* @return Status code for the success or failure of the initialization
|
||||
*/
|
||||
lib::error_code init_asio (io_service_ptr io_service) {
|
||||
// do we need to store or use the io_service at this level?
|
||||
m_io_service = io_service;
|
||||
|
||||
if (config::enable_multithreading) {
|
||||
m_strand.reset(new boost::asio::strand(*io_service));
|
||||
|
||||
m_async_read_handler = m_strand->wrap(lib::bind(
|
||||
&type::handle_async_read, get_shared(),
|
||||
lib::placeholders::_1, lib::placeholders::_2
|
||||
));
|
||||
|
||||
m_async_write_handler = m_strand->wrap(lib::bind(
|
||||
&type::handle_async_write, get_shared(),
|
||||
lib::placeholders::_1, lib::placeholders::_2
|
||||
));
|
||||
} else {
|
||||
// TODO: goal: not have this line here
|
||||
//m_strand.reset(new boost::asio::strand(*io_service));
|
||||
|
||||
m_async_read_handler = lib::bind(
|
||||
&type::handle_async_read, get_shared(),
|
||||
lib::placeholders::_1, lib::placeholders::_2
|
||||
);
|
||||
|
||||
m_async_write_handler = lib::bind(&type::handle_async_write,
|
||||
get_shared(), lib::placeholders::_1, lib::placeholders::_2);
|
||||
m_strand = lib::make_shared<lib::asio::io_service::strand>(
|
||||
lib::ref(*io_service));
|
||||
}
|
||||
|
||||
return socket_con_type::init_asio(io_service, m_strand, m_is_server);
|
||||
lib::error_code ec = socket_con_type::init_asio(io_service, m_strand,
|
||||
m_is_server);
|
||||
|
||||
return ec;
|
||||
}
|
||||
|
||||
void handle_pre_init(lib::error_code const & ec) {
|
||||
void handle_pre_init(init_handler callback, lib::error_code const & ec) {
|
||||
if (m_alog.static_test(log::alevel::devel)) {
|
||||
m_alog.write(log::alevel::devel,"asio connection handle pre_init");
|
||||
}
|
||||
@@ -456,48 +481,60 @@ protected:
|
||||
}
|
||||
|
||||
if (ec) {
|
||||
m_init_handler(ec);
|
||||
callback(ec);
|
||||
}
|
||||
|
||||
// If we have a proxy set issue a proxy connect, otherwise skip to
|
||||
// post_init
|
||||
if (!m_proxy.empty()) {
|
||||
proxy_write();
|
||||
proxy_write(callback);
|
||||
} else {
|
||||
post_init();
|
||||
post_init(callback);
|
||||
}
|
||||
}
|
||||
|
||||
void post_init() {
|
||||
void post_init(init_handler callback) {
|
||||
if (m_alog.static_test(log::alevel::devel)) {
|
||||
m_alog.write(log::alevel::devel,"asio connection post_init");
|
||||
}
|
||||
|
||||
timer_ptr post_timer;
|
||||
post_timer = set_timer(
|
||||
config::timeout_socket_post_init,
|
||||
lib::bind(
|
||||
&type::handle_post_init_timeout,
|
||||
get_shared(),
|
||||
post_timer,
|
||||
m_init_handler,
|
||||
lib::placeholders::_1
|
||||
)
|
||||
);
|
||||
|
||||
if (config::timeout_socket_post_init > 0) {
|
||||
post_timer = set_timer(
|
||||
config::timeout_socket_post_init,
|
||||
lib::bind(
|
||||
&type::handle_post_init_timeout,
|
||||
get_shared(),
|
||||
post_timer,
|
||||
callback,
|
||||
lib::placeholders::_1
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
socket_con_type::post_init(
|
||||
lib::bind(
|
||||
&type::handle_post_init,
|
||||
get_shared(),
|
||||
post_timer,
|
||||
m_init_handler,
|
||||
callback,
|
||||
lib::placeholders::_1
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
void handle_post_init_timeout(timer_ptr post_timer, init_handler callback,
|
||||
const lib::error_code& ec)
|
||||
/// Post init timeout callback
|
||||
/**
|
||||
* The timer pointer is included to ensure the timer isn't destroyed until
|
||||
* after it has expired.
|
||||
*
|
||||
* @param post_timer Pointer to the timer in question
|
||||
* @param callback The function to call back
|
||||
* @param ec The status code
|
||||
*/
|
||||
void handle_post_init_timeout(timer_ptr, init_handler callback,
|
||||
lib::error_code const & ec)
|
||||
{
|
||||
lib::error_code ret_ec;
|
||||
|
||||
@@ -518,35 +555,46 @@ protected:
|
||||
}
|
||||
}
|
||||
|
||||
m_alog.write(log::alevel::devel,"Asio transport post-init timed out");
|
||||
socket_con_type::cancel_socket();
|
||||
m_alog.write(log::alevel::devel, "Asio transport post-init timed out");
|
||||
cancel_socket_checked();
|
||||
callback(ret_ec);
|
||||
}
|
||||
|
||||
void handle_post_init(timer_ptr post_timer, init_handler callback, const
|
||||
lib::error_code& ec)
|
||||
/// Post init timeout callback
|
||||
/**
|
||||
* The timer pointer is included to ensure the timer isn't destroyed until
|
||||
* after it has expired.
|
||||
*
|
||||
* @param post_timer Pointer to the timer in question
|
||||
* @param callback The function to call back
|
||||
* @param ec The status code
|
||||
*/
|
||||
void handle_post_init(timer_ptr post_timer, init_handler callback,
|
||||
lib::error_code const & ec)
|
||||
{
|
||||
if (ec == transport::error::operation_aborted ||
|
||||
post_timer->expires_from_now().is_negative())
|
||||
(post_timer && lib::asio::is_neg(post_timer->expires_from_now())))
|
||||
{
|
||||
m_alog.write(log::alevel::devel,"post_init cancelled");
|
||||
return;
|
||||
}
|
||||
|
||||
post_timer->cancel();
|
||||
if (post_timer) {
|
||||
post_timer->cancel();
|
||||
}
|
||||
|
||||
if (m_alog.static_test(log::alevel::devel)) {
|
||||
m_alog.write(log::alevel::devel,"asio connection handle_post_init");
|
||||
}
|
||||
|
||||
if (m_tcp_post_init_handler) {
|
||||
if (m_tcp_post_init_handler) {
|
||||
m_tcp_post_init_handler(m_connection_hdl);
|
||||
}
|
||||
|
||||
callback(ec);
|
||||
}
|
||||
|
||||
void proxy_write() {
|
||||
void proxy_write(init_handler callback) {
|
||||
if (m_alog.static_test(log::alevel::devel)) {
|
||||
m_alog.write(log::alevel::devel,"asio connection proxy_write");
|
||||
}
|
||||
@@ -554,14 +602,14 @@ protected:
|
||||
if (!m_proxy_data) {
|
||||
m_elog.write(log::elevel::library,
|
||||
"assertion failed: !m_proxy_data in asio::connection::proxy_write");
|
||||
m_init_handler(make_error_code(error::general));
|
||||
callback(make_error_code(error::general));
|
||||
return;
|
||||
}
|
||||
|
||||
m_proxy_data->write_buf = m_proxy_data->req.raw();
|
||||
|
||||
m_bufs.push_back(boost::asio::buffer(m_proxy_data->write_buf.data(),
|
||||
m_proxy_data->write_buf.size()));
|
||||
m_bufs.push_back(lib::asio::buffer(m_proxy_data->write_buf.data(),
|
||||
m_proxy_data->write_buf.size()));
|
||||
|
||||
m_alog.write(log::alevel::devel,m_proxy_data->write_buf);
|
||||
|
||||
@@ -571,29 +619,29 @@ protected:
|
||||
lib::bind(
|
||||
&type::handle_proxy_timeout,
|
||||
get_shared(),
|
||||
m_init_handler,
|
||||
callback,
|
||||
lib::placeholders::_1
|
||||
)
|
||||
);
|
||||
|
||||
// Send proxy request
|
||||
if (config::enable_multithreading) {
|
||||
boost::asio::async_write(
|
||||
lib::asio::async_write(
|
||||
socket_con_type::get_next_layer(),
|
||||
m_bufs,
|
||||
m_strand->wrap(lib::bind(
|
||||
&type::handle_proxy_write, get_shared(),
|
||||
m_init_handler,
|
||||
callback,
|
||||
lib::placeholders::_1
|
||||
))
|
||||
);
|
||||
} else {
|
||||
boost::asio::async_write(
|
||||
lib::asio::async_write(
|
||||
socket_con_type::get_next_layer(),
|
||||
m_bufs,
|
||||
lib::bind(
|
||||
&type::handle_proxy_write, get_shared(),
|
||||
m_init_handler,
|
||||
callback,
|
||||
lib::placeholders::_1
|
||||
)
|
||||
);
|
||||
@@ -612,13 +660,13 @@ protected:
|
||||
} else {
|
||||
m_alog.write(log::alevel::devel,
|
||||
"asio handle_proxy_write timer expired");
|
||||
socket_con_type::cancel_socket();
|
||||
cancel_socket_checked();
|
||||
callback(make_error_code(transport::error::timeout));
|
||||
}
|
||||
}
|
||||
|
||||
void handle_proxy_write(init_handler callback,
|
||||
boost::system::error_code const & ec)
|
||||
lib::asio::error_code const & ec)
|
||||
{
|
||||
if (m_alog.static_test(log::alevel::devel)) {
|
||||
m_alog.write(log::alevel::devel,
|
||||
@@ -630,8 +678,8 @@ protected:
|
||||
// Timer expired or the operation was aborted for some reason.
|
||||
// Whatever aborted it will be issuing the callback so we are safe to
|
||||
// return
|
||||
if (ec == boost::asio::error::operation_aborted ||
|
||||
m_proxy_data->timer->expires_from_now().is_negative())
|
||||
if (ec == lib::asio::error::operation_aborted ||
|
||||
lib::asio::is_neg(m_proxy_data->timer->expires_from_now()))
|
||||
{
|
||||
m_elog.write(log::elevel::devel,"write operation aborted");
|
||||
return;
|
||||
@@ -661,7 +709,7 @@ protected:
|
||||
}
|
||||
|
||||
if (config::enable_multithreading) {
|
||||
boost::asio::async_read_until(
|
||||
lib::asio::async_read_until(
|
||||
socket_con_type::get_next_layer(),
|
||||
m_proxy_data->read_buf,
|
||||
"\r\n\r\n",
|
||||
@@ -672,7 +720,7 @@ protected:
|
||||
))
|
||||
);
|
||||
} else {
|
||||
boost::asio::async_read_until(
|
||||
lib::asio::async_read_until(
|
||||
socket_con_type::get_next_layer(),
|
||||
m_proxy_data->read_buf,
|
||||
"\r\n\r\n",
|
||||
@@ -685,8 +733,14 @@ protected:
|
||||
}
|
||||
}
|
||||
|
||||
/// Proxy read callback
|
||||
/**
|
||||
* @param init_handler The function to call back
|
||||
* @param ec The status code
|
||||
* @param bytes_transferred The number of bytes read
|
||||
*/
|
||||
void handle_proxy_read(init_handler callback,
|
||||
boost::system::error_code const & ec, size_t bytes_transferred)
|
||||
lib::asio::error_code const & ec, size_t)
|
||||
{
|
||||
if (m_alog.static_test(log::alevel::devel)) {
|
||||
m_alog.write(log::alevel::devel,
|
||||
@@ -696,8 +750,8 @@ protected:
|
||||
// Timer expired or the operation was aborted for some reason.
|
||||
// Whatever aborted it will be issuing the callback so we are safe to
|
||||
// return
|
||||
if (ec == boost::asio::error::operation_aborted ||
|
||||
m_proxy_data->timer->expires_from_now().is_negative())
|
||||
if (ec == lib::asio::error::operation_aborted ||
|
||||
lib::asio::is_neg(m_proxy_data->timer->expires_from_now()))
|
||||
{
|
||||
m_elog.write(log::elevel::devel,"read operation aborted");
|
||||
return;
|
||||
@@ -758,15 +812,11 @@ protected:
|
||||
m_proxy_data.reset();
|
||||
|
||||
// Continue with post proxy initialization
|
||||
post_init();
|
||||
post_init(callback);
|
||||
}
|
||||
}
|
||||
|
||||
/// read at least num_bytes bytes into buf and then call handler.
|
||||
/**
|
||||
*
|
||||
*
|
||||
*/
|
||||
void async_read_at_least(size_t num_bytes, char *buf, size_t len,
|
||||
read_handler handler)
|
||||
{
|
||||
@@ -776,13 +826,6 @@ protected:
|
||||
m_alog.write(log::alevel::devel,s.str());
|
||||
}
|
||||
|
||||
if (!m_async_read_handler) {
|
||||
m_alog.write(log::alevel::devel,
|
||||
"async_read_at_least called after async_shutdown");
|
||||
handler(make_error_code(transport::error::action_after_shutdown), 0);
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: safety vs speed ?
|
||||
// maybe move into an if devel block
|
||||
/*if (num_bytes > len) {
|
||||
@@ -793,97 +836,161 @@ protected:
|
||||
return;
|
||||
}*/
|
||||
|
||||
m_read_handler = handler;
|
||||
|
||||
boost::asio::async_read(
|
||||
socket_con_type::get_socket(),
|
||||
boost::asio::buffer(buf,len),
|
||||
boost::asio::transfer_at_least(num_bytes),
|
||||
make_custom_alloc_handler(
|
||||
m_read_handler_allocator,
|
||||
m_async_read_handler
|
||||
)
|
||||
);
|
||||
if (config::enable_multithreading) {
|
||||
lib::asio::async_read(
|
||||
socket_con_type::get_socket(),
|
||||
lib::asio::buffer(buf,len),
|
||||
lib::asio::transfer_at_least(num_bytes),
|
||||
m_strand->wrap(make_custom_alloc_handler(
|
||||
m_read_handler_allocator,
|
||||
lib::bind(
|
||||
&type::handle_async_read, get_shared(),
|
||||
handler,
|
||||
lib::placeholders::_1, lib::placeholders::_2
|
||||
)
|
||||
))
|
||||
);
|
||||
} else {
|
||||
lib::asio::async_read(
|
||||
socket_con_type::get_socket(),
|
||||
lib::asio::buffer(buf,len),
|
||||
lib::asio::transfer_at_least(num_bytes),
|
||||
make_custom_alloc_handler(
|
||||
m_read_handler_allocator,
|
||||
lib::bind(
|
||||
&type::handle_async_read, get_shared(),
|
||||
handler,
|
||||
lib::placeholders::_1, lib::placeholders::_2
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void handle_async_read(const boost::system::error_code& ec,
|
||||
void handle_async_read(read_handler handler, lib::asio::error_code const & ec,
|
||||
size_t bytes_transferred)
|
||||
{
|
||||
if (!ec) {
|
||||
m_read_handler(lib::error_code(), bytes_transferred);
|
||||
return;
|
||||
}
|
||||
m_alog.write(log::alevel::devel, "asio con handle_async_read");
|
||||
|
||||
// translate boost error codes into more lib::error_codes
|
||||
if (ec == boost::asio::error::eof) {
|
||||
m_read_handler(make_error_code(transport::error::eof),
|
||||
bytes_transferred);
|
||||
} else if (ec.value() == 335544539) {
|
||||
m_read_handler(make_error_code(transport::error::tls_short_read),
|
||||
bytes_transferred);
|
||||
// translate asio error codes into more lib::error_codes
|
||||
lib::error_code tec;
|
||||
if (ec == lib::asio::error::eof) {
|
||||
tec = make_error_code(transport::error::eof);
|
||||
} else if (ec) {
|
||||
// We don't know much more about the error at this point. As our
|
||||
// socket/security policy if it knows more:
|
||||
tec = socket_con_type::translate_ec(ec);
|
||||
m_tec = ec;
|
||||
|
||||
if (tec == transport::error::tls_error ||
|
||||
tec == transport::error::pass_through)
|
||||
{
|
||||
// These are aggregate/catch all errors. Log some human readable
|
||||
// information to the info channel to give library users some
|
||||
// more details about why the upstream method may have failed.
|
||||
log_err(log::elevel::info,"asio async_read_at_least",ec);
|
||||
}
|
||||
}
|
||||
if (handler) {
|
||||
handler(tec,bytes_transferred);
|
||||
} else {
|
||||
log_err(log::elevel::info,"asio async_read_at_least",ec);
|
||||
m_read_handler(make_error_code(transport::error::pass_through),
|
||||
bytes_transferred);
|
||||
// This can happen in cases where the connection is terminated while
|
||||
// the transport is waiting on a read.
|
||||
m_alog.write(log::alevel::devel,
|
||||
"handle_async_read called with null read handler");
|
||||
}
|
||||
}
|
||||
|
||||
/// Initiate a potentially asyncronous write of the given buffer
|
||||
void async_write(const char* buf, size_t len, write_handler handler) {
|
||||
if (!m_async_write_handler) {
|
||||
m_alog.write(log::alevel::devel,
|
||||
"async_write (single) called after async_shutdown");
|
||||
handler(make_error_code(transport::error::action_after_shutdown));
|
||||
return;
|
||||
m_bufs.push_back(lib::asio::buffer(buf,len));
|
||||
|
||||
if (config::enable_multithreading) {
|
||||
lib::asio::async_write(
|
||||
socket_con_type::get_socket(),
|
||||
m_bufs,
|
||||
m_strand->wrap(make_custom_alloc_handler(
|
||||
m_write_handler_allocator,
|
||||
lib::bind(
|
||||
&type::handle_async_write, get_shared(),
|
||||
handler,
|
||||
lib::placeholders::_1, lib::placeholders::_2
|
||||
)
|
||||
))
|
||||
);
|
||||
} else {
|
||||
lib::asio::async_write(
|
||||
socket_con_type::get_socket(),
|
||||
m_bufs,
|
||||
make_custom_alloc_handler(
|
||||
m_write_handler_allocator,
|
||||
lib::bind(
|
||||
&type::handle_async_write, get_shared(),
|
||||
handler,
|
||||
lib::placeholders::_1, lib::placeholders::_2
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
m_bufs.push_back(boost::asio::buffer(buf,len));
|
||||
|
||||
m_write_handler = handler;
|
||||
|
||||
boost::asio::async_write(
|
||||
socket_con_type::get_socket(),
|
||||
m_bufs,
|
||||
make_custom_alloc_handler(
|
||||
m_write_handler_allocator,
|
||||
m_async_write_handler
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
void async_write(const std::vector<buffer>& bufs, write_handler handler) {
|
||||
if (!m_async_write_handler) {
|
||||
m_alog.write(log::alevel::devel,
|
||||
"async_write (vector) called after async_shutdown");
|
||||
handler(make_error_code(transport::error::action_after_shutdown));
|
||||
return;
|
||||
}
|
||||
/// Initiate a potentially asyncronous write of the given buffers
|
||||
void async_write(std::vector<buffer> const & bufs, write_handler handler) {
|
||||
std::vector<buffer>::const_iterator it;
|
||||
|
||||
for (it = bufs.begin(); it != bufs.end(); ++it) {
|
||||
m_bufs.push_back(boost::asio::buffer((*it).buf,(*it).len));
|
||||
m_bufs.push_back(lib::asio::buffer((*it).buf,(*it).len));
|
||||
}
|
||||
|
||||
m_write_handler = handler;
|
||||
|
||||
boost::asio::async_write(
|
||||
socket_con_type::get_socket(),
|
||||
m_bufs,
|
||||
make_custom_alloc_handler(
|
||||
m_write_handler_allocator,
|
||||
m_async_write_handler
|
||||
)
|
||||
);
|
||||
if (config::enable_multithreading) {
|
||||
lib::asio::async_write(
|
||||
socket_con_type::get_socket(),
|
||||
m_bufs,
|
||||
m_strand->wrap(make_custom_alloc_handler(
|
||||
m_write_handler_allocator,
|
||||
lib::bind(
|
||||
&type::handle_async_write, get_shared(),
|
||||
handler,
|
||||
lib::placeholders::_1, lib::placeholders::_2
|
||||
)
|
||||
))
|
||||
);
|
||||
} else {
|
||||
lib::asio::async_write(
|
||||
socket_con_type::get_socket(),
|
||||
m_bufs,
|
||||
make_custom_alloc_handler(
|
||||
m_write_handler_allocator,
|
||||
lib::bind(
|
||||
&type::handle_async_write, get_shared(),
|
||||
handler,
|
||||
lib::placeholders::_1, lib::placeholders::_2
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
void handle_async_write(boost::system::error_code const & ec,
|
||||
size_t bytes_transferred)
|
||||
{
|
||||
/// Async write callback
|
||||
/**
|
||||
* @param ec The status code
|
||||
* @param bytes_transferred The number of bytes read
|
||||
*/
|
||||
void handle_async_write(write_handler handler, lib::asio::error_code const & ec, size_t) {
|
||||
m_bufs.clear();
|
||||
lib::error_code tec;
|
||||
if (ec) {
|
||||
log_err(log::elevel::info,"asio async_write",ec);
|
||||
m_write_handler(make_error_code(transport::error::pass_through));
|
||||
tec = make_error_code(transport::error::pass_through);
|
||||
}
|
||||
if (handler) {
|
||||
handler(tec);
|
||||
} else {
|
||||
m_write_handler(lib::error_code());
|
||||
// This can happen in cases where the connection is terminated while
|
||||
// the transport is waiting on a read.
|
||||
m_alog.write(log::alevel::devel,
|
||||
"handle_async_write called with null write handler");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -931,13 +1038,6 @@ protected:
|
||||
m_alog.write(log::alevel::devel,"asio connection async_shutdown");
|
||||
}
|
||||
|
||||
// Reset cached handlers now that we won't be reading or writing anymore
|
||||
// These cached handlers store shared pointers to this connection and will leak
|
||||
// the connection if not destroyed.
|
||||
m_async_read_handler = 0;
|
||||
m_async_write_handler = 0;
|
||||
m_init_handler = 0;
|
||||
|
||||
timer_ptr shutdown_timer;
|
||||
shutdown_timer = set_timer(
|
||||
config::timeout_socket_shutdown,
|
||||
@@ -961,8 +1061,14 @@ protected:
|
||||
);
|
||||
}
|
||||
|
||||
void handle_async_shutdown_timeout(timer_ptr shutdown_timer, init_handler
|
||||
callback, const lib::error_code& ec)
|
||||
/// Async shutdown timeout handler
|
||||
/**
|
||||
* @param shutdown_timer A pointer to the timer to keep it in scope
|
||||
* @param callback The function to call back
|
||||
* @param ec The status code
|
||||
*/
|
||||
void handle_async_shutdown_timeout(timer_ptr, init_handler callback,
|
||||
lib::error_code const & ec)
|
||||
{
|
||||
lib::error_code ret_ec;
|
||||
|
||||
@@ -973,7 +1079,7 @@ protected:
|
||||
return;
|
||||
}
|
||||
|
||||
log_err(log::elevel::devel,"asio handle_async_socket_shutdown",ec);
|
||||
log_err(log::elevel::devel,"asio handle_async_shutdown_timeout",ec);
|
||||
ret_ec = ec;
|
||||
} else {
|
||||
ret_ec = make_error_code(transport::error::timeout);
|
||||
@@ -981,15 +1087,15 @@ protected:
|
||||
|
||||
m_alog.write(log::alevel::devel,
|
||||
"Asio transport socket shutdown timed out");
|
||||
socket_con_type::cancel_socket();
|
||||
cancel_socket_checked();
|
||||
callback(ret_ec);
|
||||
}
|
||||
|
||||
void handle_async_shutdown(timer_ptr shutdown_timer, shutdown_handler
|
||||
callback, const boost::system::error_code & ec)
|
||||
callback, lib::asio::error_code const & ec)
|
||||
{
|
||||
if (ec == boost::asio::error::operation_aborted ||
|
||||
shutdown_timer->expires_from_now().is_negative())
|
||||
if (ec == lib::asio::error::operation_aborted ||
|
||||
lib::asio::is_neg(shutdown_timer->expires_from_now()))
|
||||
{
|
||||
m_alog.write(log::alevel::devel,"async_shutdown cancelled");
|
||||
return;
|
||||
@@ -997,26 +1103,53 @@ protected:
|
||||
|
||||
shutdown_timer->cancel();
|
||||
|
||||
lib::error_code tec;
|
||||
if (ec) {
|
||||
log_err(log::elevel::info,"asio async_shutdown",ec);
|
||||
if (ec == boost::asio::error::not_connected) {
|
||||
if (ec == lib::asio::error::not_connected) {
|
||||
// The socket was already closed when we tried to close it. This
|
||||
// happens periodically (usually if a read or write fails
|
||||
// earlier and if it is a real error will be caught at another
|
||||
// level of the stack.
|
||||
callback(lib::error_code());
|
||||
} else {
|
||||
callback(make_error_code(transport::error::pass_through));
|
||||
// We don't know anything more about this error, give our
|
||||
// socket/security policy a crack at it.
|
||||
tec = socket_con_type::translate_ec(ec);
|
||||
m_tec = ec;
|
||||
|
||||
if (tec == transport::error::tls_short_read) {
|
||||
// TLS short read at this point is somewhat expected if both
|
||||
// sides try and end the connection at the same time or if
|
||||
// SSLv2 is being used. In general there is nothing that can
|
||||
// be done here other than a low level development log.
|
||||
} else {
|
||||
// all other errors are effectively pass through errors of
|
||||
// some sort so print some detail on the info channel for
|
||||
// library users to look up if needed.
|
||||
log_err(log::elevel::info,"asio async_shutdown",ec);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (m_alog.static_test(log::alevel::devel)) {
|
||||
m_alog.write(log::alevel::devel,
|
||||
"asio con handle_async_shutdown");
|
||||
}
|
||||
}
|
||||
callback(tec);
|
||||
}
|
||||
|
||||
callback(lib::error_code());
|
||||
/// Cancel the underlying socket and log any errors
|
||||
void cancel_socket_checked() {
|
||||
lib::asio::error_code cec = socket_con_type::cancel_socket();
|
||||
if (cec) {
|
||||
if (cec == lib::asio::error::operation_not_supported) {
|
||||
// cancel not supported on this OS, ignore and log at dev level
|
||||
m_alog.write(log::alevel::devel, "socket cancel not supported");
|
||||
} else {
|
||||
log_err(log::elevel::warn, "socket cancel failed", cec);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
/// Convenience method for logging the code and message for an error_code
|
||||
template <typename error_type>
|
||||
@@ -1037,7 +1170,7 @@ private:
|
||||
request_type req;
|
||||
response_type res;
|
||||
std::string write_buf;
|
||||
boost::asio::streambuf read_buf;
|
||||
lib::asio::streambuf read_buf;
|
||||
long timeout_proxy;
|
||||
timer_ptr timer;
|
||||
};
|
||||
@@ -1050,7 +1183,10 @@ private:
|
||||
strand_ptr m_strand;
|
||||
connection_hdl m_connection_hdl;
|
||||
|
||||
std::vector<boost::asio::const_buffer> m_bufs;
|
||||
std::vector<lib::asio::const_buffer> m_bufs;
|
||||
|
||||
/// Detailed internal error code
|
||||
lib::asio::error_code m_tec;
|
||||
|
||||
// Handlers
|
||||
tcp_init_handler m_tcp_pre_init_handler;
|
||||
@@ -1058,13 +1194,6 @@ private:
|
||||
|
||||
handler_allocator m_read_handler_allocator;
|
||||
handler_allocator m_write_handler_allocator;
|
||||
|
||||
read_handler m_read_handler;
|
||||
write_handler m_write_handler;
|
||||
init_handler m_init_handler;
|
||||
|
||||
async_read_handler m_async_read_handler;
|
||||
async_write_handler m_async_write_handler;
|
||||
};
|
||||
|
||||
|
||||
|
||||
+222
-112
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Peter Thorson. All rights reserved.
|
||||
* Copyright (c) 2015, Peter Thorson. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
@@ -28,26 +28,26 @@
|
||||
#ifndef WEBSOCKETPP_TRANSPORT_ASIO_HPP
|
||||
#define WEBSOCKETPP_TRANSPORT_ASIO_HPP
|
||||
|
||||
#include <websocketpp/common/functional.hpp>
|
||||
#include <websocketpp/logger/levels.hpp>
|
||||
#include <websocketpp/transport/base/endpoint.hpp>
|
||||
#include <websocketpp/transport/asio/connection.hpp>
|
||||
#include <websocketpp/transport/asio/security/none.hpp>
|
||||
|
||||
#include <boost/asio.hpp>
|
||||
#include <boost/bind.hpp>
|
||||
#include <boost/system/error_code.hpp>
|
||||
#include <websocketpp/uri.hpp>
|
||||
#include <websocketpp/logger/levels.hpp>
|
||||
|
||||
#include <iostream>
|
||||
#include <websocketpp/common/functional.hpp>
|
||||
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
|
||||
namespace websocketpp {
|
||||
namespace transport {
|
||||
namespace asio {
|
||||
|
||||
/// Boost Asio based endpoint transport component
|
||||
/// Asio based endpoint transport component
|
||||
/**
|
||||
* transport::asio::endpoint implements an endpoint transport component using
|
||||
* Boost ASIO.
|
||||
* Asio.
|
||||
*/
|
||||
template <typename config>
|
||||
class endpoint : public config::socket_type {
|
||||
@@ -77,20 +77,22 @@ public:
|
||||
typedef typename transport_con_type::ptr transport_con_ptr;
|
||||
|
||||
/// Type of a pointer to the ASIO io_service being used
|
||||
typedef boost::asio::io_service* io_service_ptr;
|
||||
typedef lib::asio::io_service * io_service_ptr;
|
||||
/// Type of a shared pointer to the acceptor being used
|
||||
typedef lib::shared_ptr<boost::asio::ip::tcp::acceptor> acceptor_ptr;
|
||||
typedef lib::shared_ptr<lib::asio::ip::tcp::acceptor> acceptor_ptr;
|
||||
/// Type of a shared pointer to the resolver being used
|
||||
typedef lib::shared_ptr<boost::asio::ip::tcp::resolver> resolver_ptr;
|
||||
typedef lib::shared_ptr<lib::asio::ip::tcp::resolver> resolver_ptr;
|
||||
/// Type of timer handle
|
||||
typedef lib::shared_ptr<boost::asio::deadline_timer> timer_ptr;
|
||||
typedef lib::shared_ptr<lib::asio::steady_timer> timer_ptr;
|
||||
/// Type of a shared pointer to an io_service work object
|
||||
typedef lib::shared_ptr<boost::asio::io_service::work> work_ptr;
|
||||
typedef lib::shared_ptr<lib::asio::io_service::work> work_ptr;
|
||||
|
||||
// generate and manage our own io_service
|
||||
explicit endpoint()
|
||||
: m_external_io_service(false)
|
||||
: m_io_service(NULL)
|
||||
, m_external_io_service(false)
|
||||
, m_listen_backlog(0)
|
||||
, m_reuse_addr(false)
|
||||
, m_state(UNINITIALIZED)
|
||||
{
|
||||
//std::cout << "transport::asio::endpoint constructor" << std::endl;
|
||||
@@ -98,7 +100,11 @@ public:
|
||||
|
||||
~endpoint() {
|
||||
// clean up our io_service if we were initialized with an internal one.
|
||||
|
||||
// Explicitly destroy local objects
|
||||
m_acceptor.reset();
|
||||
m_resolver.reset();
|
||||
m_work.reset();
|
||||
if (m_state != UNINITIALIZED && !m_external_io_service) {
|
||||
delete m_io_service;
|
||||
}
|
||||
@@ -107,22 +113,28 @@ public:
|
||||
/// transport::asio objects are moveable but not copyable or assignable.
|
||||
/// The following code sets this situation up based on whether or not we
|
||||
/// have C++11 support or not
|
||||
#ifdef _WEBSOCKETPP_DELETED_FUNCTIONS_
|
||||
endpoint(const endpoint& src) = delete;
|
||||
#ifdef _WEBSOCKETPP_DEFAULT_DELETE_FUNCTIONS_
|
||||
endpoint(const endpoint & src) = delete;
|
||||
endpoint& operator= (const endpoint & rhs) = delete;
|
||||
#else
|
||||
private:
|
||||
endpoint(const endpoint& src);
|
||||
endpoint& operator= (const endpoint & rhs);
|
||||
endpoint(const endpoint & src);
|
||||
endpoint & operator= (const endpoint & rhs);
|
||||
public:
|
||||
#endif
|
||||
#endif // _WEBSOCKETPP_DEFAULT_DELETE_FUNCTIONS_
|
||||
|
||||
#ifdef _WEBSOCKETPP_RVALUE_REFERENCES_
|
||||
endpoint (endpoint&& src)
|
||||
: m_io_service(src.m_io_service)
|
||||
#ifdef _WEBSOCKETPP_MOVE_SEMANTICS_
|
||||
endpoint (endpoint && src)
|
||||
: config::socket_type(std::move(src))
|
||||
, m_tcp_pre_init_handler(src.m_tcp_pre_init_handler)
|
||||
, m_tcp_post_init_handler(src.m_tcp_post_init_handler)
|
||||
, m_io_service(src.m_io_service)
|
||||
, m_external_io_service(src.m_external_io_service)
|
||||
, m_acceptor(src.m_acceptor)
|
||||
, m_listen_backlog(0)
|
||||
, m_listen_backlog(lib::asio::socket_base::max_connections)
|
||||
, m_reuse_addr(src.m_reuse_addr)
|
||||
, m_elog(src.m_elog)
|
||||
, m_alog(src.m_alog)
|
||||
, m_state(src.m_state)
|
||||
{
|
||||
src.m_io_service = NULL;
|
||||
@@ -131,23 +143,27 @@ public:
|
||||
src.m_state = UNINITIALIZED;
|
||||
}
|
||||
|
||||
endpoint& operator= (const endpoint && rhs) {
|
||||
/*endpoint & operator= (const endpoint && rhs) {
|
||||
if (this != &rhs) {
|
||||
m_io_service = rhs.m_io_service;
|
||||
m_external_io_service = rhs.m_external_io_service;
|
||||
m_acceptor = rhs.m_acceptor;
|
||||
m_listen_backlog = rhs.m_listen_backlog
|
||||
m_listen_backlog = rhs.m_listen_backlog;
|
||||
m_reuse_addr = rhs.m_reuse_addr;
|
||||
m_state = rhs.m_state;
|
||||
|
||||
rhs.m_io_service = NULL;
|
||||
rhs.m_external_io_service = false;
|
||||
rhs.m_acceptor = NULL;
|
||||
rhs.m_listen_backlog = 0;
|
||||
rhs.m_listen_backlog = lib::asio::socket_base::max_connections;
|
||||
rhs.m_state = UNINITIALIZED;
|
||||
|
||||
// TODO: this needs to be updated
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
#endif
|
||||
}*/
|
||||
#endif // _WEBSOCKETPP_MOVE_SEMANTICS_
|
||||
|
||||
/// Return whether or not the endpoint produces secure connections.
|
||||
bool is_secure() const {
|
||||
return socket_type::is_secure();
|
||||
@@ -175,7 +191,9 @@ public:
|
||||
|
||||
m_io_service = ptr;
|
||||
m_external_io_service = true;
|
||||
m_acceptor.reset(new boost::asio::ip::tcp::acceptor(*m_io_service));
|
||||
m_acceptor = lib::make_shared<lib::asio::ip::tcp::acceptor>(
|
||||
lib::ref(*m_io_service));
|
||||
|
||||
m_state = READY;
|
||||
ec = lib::error_code();
|
||||
}
|
||||
@@ -191,9 +209,7 @@ public:
|
||||
void init_asio(io_service_ptr ptr) {
|
||||
lib::error_code ec;
|
||||
init_asio(ptr,ec);
|
||||
if (ec) {
|
||||
throw ec;
|
||||
}
|
||||
if (ec) { throw exception(ec); }
|
||||
}
|
||||
|
||||
/// Initialize asio transport with internal io_service (exception free)
|
||||
@@ -206,7 +222,17 @@ public:
|
||||
* @param ec Set to indicate what error occurred, if any.
|
||||
*/
|
||||
void init_asio(lib::error_code & ec) {
|
||||
init_asio(new boost::asio::io_service(),ec);
|
||||
// Use a smart pointer until the call is successful and ownership has
|
||||
// successfully been taken. Use unique_ptr when available.
|
||||
// TODO: remove the use of auto_ptr when C++98/03 support is no longer
|
||||
// necessary.
|
||||
#ifdef _WEBSOCKETPP_CPP11_MEMORY_
|
||||
lib::unique_ptr<lib::asio::io_service> service(new lib::asio::io_service());
|
||||
#else
|
||||
lib::auto_ptr<lib::asio::io_service> service(new lib::asio::io_service());
|
||||
#endif
|
||||
init_asio(service.get(), ec);
|
||||
if( !ec ) service.release(); // Call was successful, transfer ownership
|
||||
m_external_io_service = false;
|
||||
}
|
||||
|
||||
@@ -218,7 +244,18 @@ public:
|
||||
* @see init_asio(io_service_ptr ptr)
|
||||
*/
|
||||
void init_asio() {
|
||||
init_asio(new boost::asio::io_service());
|
||||
// Use a smart pointer until the call is successful and ownership has
|
||||
// successfully been taken. Use unique_ptr when available.
|
||||
// TODO: remove the use of auto_ptr when C++98/03 support is no longer
|
||||
// necessary.
|
||||
#ifdef _WEBSOCKETPP_CPP11_MEMORY_
|
||||
lib::unique_ptr<lib::asio::io_service> service(new lib::asio::io_service());
|
||||
#else
|
||||
lib::auto_ptr<lib::asio::io_service> service(new lib::asio::io_service());
|
||||
#endif
|
||||
init_asio( service.get() );
|
||||
// If control got this far without an exception, then ownership has successfully been taken
|
||||
service.release();
|
||||
m_external_io_service = false;
|
||||
}
|
||||
|
||||
@@ -228,7 +265,7 @@ public:
|
||||
* established but before any additional wrappers (proxy connects, TLS
|
||||
* handshakes, etc) have been performed.
|
||||
*
|
||||
* @since 0.4.0-alpha1
|
||||
* @since 0.3.0
|
||||
*
|
||||
* @param h The handler to call on tcp pre init.
|
||||
*/
|
||||
@@ -257,7 +294,7 @@ public:
|
||||
* etc have been performed. This is fired before any bytes are read or any
|
||||
* WebSocket specific handshake logic has been performed.
|
||||
*
|
||||
* @since 0.4.0-alpha1
|
||||
* @since 0.3.0
|
||||
*
|
||||
* @param h The handler to call on tcp post init.
|
||||
*/
|
||||
@@ -280,7 +317,7 @@ public:
|
||||
* A value of zero will use the operating system default. This is the
|
||||
* default value.
|
||||
*
|
||||
* @since 0.4.0-alpha1
|
||||
* @since 0.3.0
|
||||
*
|
||||
* @param backlog The maximum length of the queue of pending connections
|
||||
*/
|
||||
@@ -288,6 +325,24 @@ public:
|
||||
m_listen_backlog = backlog;
|
||||
}
|
||||
|
||||
/// Sets whether to use the SO_REUSEADDR flag when opening listening sockets
|
||||
/**
|
||||
* Specifies whether or not to use the SO_REUSEADDR TCP socket option. What
|
||||
* this flag does depends on your operating system. Please consult operating
|
||||
* system documentation for more details.
|
||||
*
|
||||
* New values affect future calls to listen only.
|
||||
*
|
||||
* The default is false.
|
||||
*
|
||||
* @since 0.3.0
|
||||
*
|
||||
* @param value Whether or not to use the SO_REUSEADDR option
|
||||
*/
|
||||
void set_reuse_addr(bool value) {
|
||||
m_reuse_addr = value;
|
||||
}
|
||||
|
||||
/// Retrieve a reference to the endpoint's io_service
|
||||
/**
|
||||
* The io_service may be an internal or external one. This may be used to
|
||||
@@ -299,9 +354,31 @@ public:
|
||||
*
|
||||
* @return A reference to the endpoint's io_service
|
||||
*/
|
||||
boost::asio::io_service & get_io_service() {
|
||||
lib::asio::io_service & get_io_service() {
|
||||
return *m_io_service;
|
||||
}
|
||||
|
||||
/// Get local TCP endpoint
|
||||
/**
|
||||
* Extracts the local endpoint from the acceptor. This represents the
|
||||
* address that WebSocket++ is listening on.
|
||||
*
|
||||
* Sets a bad_descriptor error if the acceptor is not currently listening
|
||||
* or otherwise unavailable.
|
||||
*
|
||||
* @since 0.7.0
|
||||
*
|
||||
* @param ec Set to indicate what error occurred, if any.
|
||||
* @return The local endpoint
|
||||
*/
|
||||
lib::asio::ip::tcp::endpoint get_local_endpoint(lib::asio::error_code & ec) {
|
||||
if (m_acceptor) {
|
||||
return m_acceptor->local_endpoint(ec);
|
||||
} else {
|
||||
ec = lib::asio::error::make_error_code(lib::asio::error::bad_descriptor);
|
||||
return lib::asio::ip::tcp::endpoint();
|
||||
}
|
||||
}
|
||||
|
||||
/// Set up endpoint for listening manually (exception free)
|
||||
/**
|
||||
@@ -311,7 +388,7 @@ public:
|
||||
* @param ep An endpoint to read settings from
|
||||
* @param ec Set to indicate what error occurred, if any.
|
||||
*/
|
||||
void listen(boost::asio::ip::tcp::endpoint const & ep, lib::error_code & ec)
|
||||
void listen(lib::asio::ip::tcp::endpoint const & ep, lib::error_code & ec)
|
||||
{
|
||||
if (m_state != READY) {
|
||||
m_elog->write(log::elevel::library,
|
||||
@@ -323,16 +400,28 @@ public:
|
||||
|
||||
m_alog->write(log::alevel::devel,"asio::listen");
|
||||
|
||||
m_acceptor->open(ep.protocol());
|
||||
m_acceptor->set_option(boost::asio::socket_base::reuse_address(true));
|
||||
m_acceptor->bind(ep);
|
||||
if (m_listen_backlog == 0) {
|
||||
m_acceptor->listen();
|
||||
lib::asio::error_code bec;
|
||||
|
||||
m_acceptor->open(ep.protocol(),bec);
|
||||
if (!bec) {
|
||||
m_acceptor->set_option(lib::asio::socket_base::reuse_address(m_reuse_addr),bec);
|
||||
}
|
||||
if (!bec) {
|
||||
m_acceptor->bind(ep,bec);
|
||||
}
|
||||
if (!bec) {
|
||||
m_acceptor->listen(m_listen_backlog,bec);
|
||||
}
|
||||
if (bec) {
|
||||
if (m_acceptor->is_open()) {
|
||||
m_acceptor->close();
|
||||
}
|
||||
log_err(log::elevel::info,"asio listen",bec);
|
||||
ec = make_error_code(error::pass_through);
|
||||
} else {
|
||||
m_acceptor->listen(m_listen_backlog);
|
||||
m_state = LISTENING;
|
||||
ec = lib::error_code();
|
||||
}
|
||||
m_state = LISTENING;
|
||||
ec = lib::error_code();
|
||||
}
|
||||
|
||||
/// Set up endpoint for listening manually
|
||||
@@ -341,12 +430,10 @@ public:
|
||||
*
|
||||
* @param ep An endpoint to read settings from
|
||||
*/
|
||||
void listen(boost::asio::ip::tcp::endpoint const & ep) {
|
||||
void listen(lib::asio::ip::tcp::endpoint const & ep) {
|
||||
lib::error_code ec;
|
||||
listen(ep,ec);
|
||||
if (ec) {
|
||||
throw ec;
|
||||
}
|
||||
if (ec) { throw exception(ec); }
|
||||
}
|
||||
|
||||
/// Set up endpoint for listening with protocol and port (exception free)
|
||||
@@ -356,8 +443,8 @@ public:
|
||||
* listening.
|
||||
*
|
||||
* Common options include:
|
||||
* - IPv6 with mapped IPv4 for dual stack hosts boost::asio::ip::tcp::v6()
|
||||
* - IPv4 only: boost::asio::ip::tcp::v4()
|
||||
* - IPv6 with mapped IPv4 for dual stack hosts lib::asio::ip::tcp::v6()
|
||||
* - IPv4 only: lib::asio::ip::tcp::v4()
|
||||
*
|
||||
* @param internet_protocol The internet protocol to use.
|
||||
* @param port The port to listen on.
|
||||
@@ -367,7 +454,7 @@ public:
|
||||
void listen(InternetProtocol const & internet_protocol, uint16_t port,
|
||||
lib::error_code & ec)
|
||||
{
|
||||
boost::asio::ip::tcp::endpoint ep(internet_protocol, port);
|
||||
lib::asio::ip::tcp::endpoint ep(internet_protocol, port);
|
||||
listen(ep,ec);
|
||||
}
|
||||
|
||||
@@ -378,8 +465,8 @@ public:
|
||||
* listening.
|
||||
*
|
||||
* Common options include:
|
||||
* - IPv6 with mapped IPv4 for dual stack hosts boost::asio::ip::tcp::v6()
|
||||
* - IPv4 only: boost::asio::ip::tcp::v4()
|
||||
* - IPv6 with mapped IPv4 for dual stack hosts lib::asio::ip::tcp::v6()
|
||||
* - IPv4 only: lib::asio::ip::tcp::v4()
|
||||
*
|
||||
* @param internet_protocol The internet protocol to use.
|
||||
* @param port The port to listen on.
|
||||
@@ -387,7 +474,7 @@ public:
|
||||
template <typename InternetProtocol>
|
||||
void listen(InternetProtocol const & internet_protocol, uint16_t port)
|
||||
{
|
||||
boost::asio::ip::tcp::endpoint ep(internet_protocol, port);
|
||||
lib::asio::ip::tcp::endpoint ep(internet_protocol, port);
|
||||
listen(ep);
|
||||
}
|
||||
|
||||
@@ -404,7 +491,7 @@ public:
|
||||
* @param ec Set to indicate what error occurred, if any.
|
||||
*/
|
||||
void listen(uint16_t port, lib::error_code & ec) {
|
||||
listen(boost::asio::ip::tcp::v6(), port, ec);
|
||||
listen(lib::asio::ip::tcp::v6(), port, ec);
|
||||
}
|
||||
|
||||
/// Set up endpoint for listening on a port
|
||||
@@ -420,13 +507,13 @@ public:
|
||||
* @param ec Set to indicate what error occurred, if any.
|
||||
*/
|
||||
void listen(uint16_t port) {
|
||||
listen(boost::asio::ip::tcp::v6(), port);
|
||||
listen(lib::asio::ip::tcp::v6(), port);
|
||||
}
|
||||
|
||||
/// Set up endpoint for listening on a host and service (exception free)
|
||||
/**
|
||||
* Bind the internal acceptor using the given host and service. More details
|
||||
* about what host and service can be are available in the boost asio
|
||||
* about what host and service can be are available in the Asio
|
||||
* documentation for ip::basic_resolver_query::basic_resolver_query's
|
||||
* constructors.
|
||||
*
|
||||
@@ -442,7 +529,7 @@ public:
|
||||
void listen(std::string const & host, std::string const & service,
|
||||
lib::error_code & ec)
|
||||
{
|
||||
using boost::asio::ip::tcp;
|
||||
using lib::asio::ip::tcp;
|
||||
tcp::resolver r(*m_io_service);
|
||||
tcp::resolver::query query(host, service);
|
||||
tcp::resolver::iterator endpoint_iterator = r.resolve(query);
|
||||
@@ -459,7 +546,7 @@ public:
|
||||
/// Set up endpoint for listening on a host and service
|
||||
/**
|
||||
* Bind the internal acceptor using the given host and service. More details
|
||||
* about what host and service can be are available in the boost asio
|
||||
* about what host and service can be are available in the Asio
|
||||
* documentation for ip::basic_resolver_query::basic_resolver_query's
|
||||
* constructors.
|
||||
*
|
||||
@@ -476,9 +563,7 @@ public:
|
||||
{
|
||||
lib::error_code ec;
|
||||
listen(host,service,ec);
|
||||
if (ec) {
|
||||
throw ec;
|
||||
}
|
||||
if (ec) { throw exception(ec); }
|
||||
}
|
||||
|
||||
/// Stop listening (exception free)
|
||||
@@ -513,9 +598,15 @@ public:
|
||||
void stop_listening() {
|
||||
lib::error_code ec;
|
||||
stop_listening(ec);
|
||||
if (ec) {
|
||||
throw ec;
|
||||
}
|
||||
if (ec) { throw exception(ec); }
|
||||
}
|
||||
|
||||
/// Check if the endpoint is listening
|
||||
/**
|
||||
* @return Whether or not the endpoint is listening.
|
||||
*/
|
||||
bool is_listening() const {
|
||||
return (m_state == LISTENING);
|
||||
}
|
||||
|
||||
/// wraps the run method of the internal io_service object
|
||||
@@ -566,10 +657,12 @@ public:
|
||||
* called either before the endpoint has run out of work or before it was
|
||||
* started
|
||||
*
|
||||
* @since 0.4.0-alpha1
|
||||
* @since 0.3.0
|
||||
*/
|
||||
void start_perpetual() {
|
||||
m_work.reset(new boost::asio::io_service::work(*m_io_service));
|
||||
m_work = lib::make_shared<lib::asio::io_service::work>(
|
||||
lib::ref(*m_io_service)
|
||||
);
|
||||
}
|
||||
|
||||
/// Clears the endpoint's perpetual flag, allowing it to exit when empty
|
||||
@@ -578,7 +671,7 @@ public:
|
||||
* method to exit normally when it runs out of connections. If there are
|
||||
* currently active connections it will not end until they are complete.
|
||||
*
|
||||
* @since 0.4.0-alpha1
|
||||
* @since 0.3.0
|
||||
*/
|
||||
void stop_perpetual() {
|
||||
m_work.reset();
|
||||
@@ -597,11 +690,9 @@ public:
|
||||
* needed.
|
||||
*/
|
||||
timer_ptr set_timer(long duration, timer_handler callback) {
|
||||
timer_ptr new_timer(
|
||||
new boost::asio::deadline_timer(
|
||||
*m_io_service,
|
||||
boost::posix_time::milliseconds(duration)
|
||||
)
|
||||
timer_ptr new_timer = lib::make_shared<lib::asio::steady_timer>(
|
||||
*m_io_service,
|
||||
lib::asio::milliseconds(duration)
|
||||
);
|
||||
|
||||
new_timer->async_wait(
|
||||
@@ -617,7 +708,7 @@ public:
|
||||
return new_timer;
|
||||
}
|
||||
|
||||
/// Timer callback
|
||||
/// Timer handler
|
||||
/**
|
||||
* The timer pointer is included to ensure the timer isn't destroyed until
|
||||
* after it has expired.
|
||||
@@ -626,11 +717,11 @@ public:
|
||||
* @param callback The function to call back
|
||||
* @param ec A status code indicating an error, if any.
|
||||
*/
|
||||
void handle_timer(timer_ptr t, timer_handler callback,
|
||||
boost::system::error_code const & ec)
|
||||
void handle_timer(timer_ptr, timer_handler callback,
|
||||
lib::asio::error_code const & ec)
|
||||
{
|
||||
if (ec) {
|
||||
if (ec == boost::asio::error::operation_aborted) {
|
||||
if (ec == lib::asio::error::operation_aborted) {
|
||||
callback(make_error_code(transport::error::operation_aborted));
|
||||
} else {
|
||||
m_elog->write(log::elevel::info,
|
||||
@@ -653,10 +744,8 @@ public:
|
||||
lib::error_code & ec)
|
||||
{
|
||||
if (m_state != LISTENING) {
|
||||
m_elog->write(log::elevel::library,
|
||||
"asio::async_accept called from the wrong state");
|
||||
using websocketpp::error::make_error_code;
|
||||
ec = make_error_code(websocketpp::error::invalid_state);
|
||||
ec = make_error_code(websocketpp::error::async_accept_not_listening);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -693,9 +782,7 @@ public:
|
||||
void async_accept(transport_con_ptr tcon, accept_handler callback) {
|
||||
lib::error_code ec;
|
||||
async_accept(tcon,callback,ec);
|
||||
if (ec) {
|
||||
throw ec;
|
||||
}
|
||||
if (ec) { throw exception(ec); }
|
||||
}
|
||||
protected:
|
||||
/// Initialize logging
|
||||
@@ -713,16 +800,20 @@ protected:
|
||||
m_elog = e;
|
||||
}
|
||||
|
||||
void handle_accept(accept_handler callback, boost::system::error_code const
|
||||
& boost_ec)
|
||||
void handle_accept(accept_handler callback, lib::asio::error_code const &
|
||||
asio_ec)
|
||||
{
|
||||
lib::error_code ret_ec;
|
||||
|
||||
m_alog->write(log::alevel::devel, "asio::handle_accept");
|
||||
|
||||
if (boost_ec) {
|
||||
log_err(log::elevel::devel,"asio handle_accept",boost_ec);
|
||||
ret_ec = make_error_code(error::pass_through);
|
||||
if (asio_ec) {
|
||||
if (asio_ec == lib::asio::errc::operation_canceled) {
|
||||
ret_ec = make_error_code(websocketpp::error::operation_canceled);
|
||||
} else {
|
||||
log_err(log::elevel::info,"asio handle_accept",asio_ec);
|
||||
ret_ec = make_error_code(error::pass_through);
|
||||
}
|
||||
}
|
||||
|
||||
callback(ret_ec);
|
||||
@@ -731,13 +822,16 @@ protected:
|
||||
/// Initiate a new connection
|
||||
// TODO: there have to be some more failure conditions here
|
||||
void async_connect(transport_con_ptr tcon, uri_ptr u, connect_handler cb) {
|
||||
using namespace boost::asio::ip;
|
||||
using namespace lib::asio::ip;
|
||||
|
||||
// Create a resolver
|
||||
if (!m_resolver) {
|
||||
m_resolver.reset(new boost::asio::ip::tcp::resolver(*m_io_service));
|
||||
m_resolver = lib::make_shared<lib::asio::ip::tcp::resolver>(
|
||||
lib::ref(*m_io_service));
|
||||
}
|
||||
|
||||
tcon->set_uri(u);
|
||||
|
||||
std::string proxy = tcon->get_proxy();
|
||||
std::string host;
|
||||
std::string port;
|
||||
@@ -748,7 +842,7 @@ protected:
|
||||
} else {
|
||||
lib::error_code ec;
|
||||
|
||||
uri_ptr pu(new uri(proxy));
|
||||
uri_ptr pu = lib::make_shared<uri>(proxy);
|
||||
|
||||
if (!pu->get_valid()) {
|
||||
cb(make_error_code(error::proxy_invalid));
|
||||
@@ -814,7 +908,16 @@ protected:
|
||||
}
|
||||
}
|
||||
|
||||
void handle_resolve_timeout(timer_ptr dns_timer, connect_handler callback,
|
||||
/// DNS resolution timeout handler
|
||||
/**
|
||||
* The timer pointer is included to ensure the timer isn't destroyed until
|
||||
* after it has expired.
|
||||
*
|
||||
* @param dns_timer Pointer to the timer in question
|
||||
* @param callback The function to call back
|
||||
* @param ec A status code indicating an error, if any.
|
||||
*/
|
||||
void handle_resolve_timeout(timer_ptr, connect_handler callback,
|
||||
lib::error_code const & ec)
|
||||
{
|
||||
lib::error_code ret_ec;
|
||||
@@ -838,11 +941,11 @@ protected:
|
||||
}
|
||||
|
||||
void handle_resolve(transport_con_ptr tcon, timer_ptr dns_timer,
|
||||
connect_handler callback, boost::system::error_code const & ec,
|
||||
boost::asio::ip::tcp::resolver::iterator iterator)
|
||||
connect_handler callback, lib::asio::error_code const & ec,
|
||||
lib::asio::ip::tcp::resolver::iterator iterator)
|
||||
{
|
||||
if (ec == boost::asio::error::operation_aborted ||
|
||||
dns_timer->expires_from_now().is_negative())
|
||||
if (ec == lib::asio::error::operation_aborted ||
|
||||
lib::asio::is_neg(dns_timer->expires_from_now()))
|
||||
{
|
||||
m_alog->write(log::alevel::devel,"async_resolve cancelled");
|
||||
return;
|
||||
@@ -860,7 +963,7 @@ protected:
|
||||
std::stringstream s;
|
||||
s << "Async DNS resolve successful. Results: ";
|
||||
|
||||
boost::asio::ip::tcp::resolver::iterator it, end;
|
||||
lib::asio::ip::tcp::resolver::iterator it, end;
|
||||
for (it = iterator; it != end; ++it) {
|
||||
s << (*it).endpoint() << " ";
|
||||
}
|
||||
@@ -885,7 +988,7 @@ protected:
|
||||
);
|
||||
|
||||
if (config::enable_multithreading) {
|
||||
boost::asio::async_connect(
|
||||
lib::asio::async_connect(
|
||||
tcon->get_raw_socket(),
|
||||
iterator,
|
||||
tcon->get_strand()->wrap(lib::bind(
|
||||
@@ -898,7 +1001,7 @@ protected:
|
||||
))
|
||||
);
|
||||
} else {
|
||||
boost::asio::async_connect(
|
||||
lib::asio::async_connect(
|
||||
tcon->get_raw_socket(),
|
||||
iterator,
|
||||
lib::bind(
|
||||
@@ -913,7 +1016,17 @@ protected:
|
||||
}
|
||||
}
|
||||
|
||||
void handle_connect_timeout(transport_con_ptr tcon, timer_ptr con_timer,
|
||||
/// Asio connect timeout handler
|
||||
/**
|
||||
* The timer pointer is included to ensure the timer isn't destroyed until
|
||||
* after it has expired.
|
||||
*
|
||||
* @param tcon Pointer to the transport connection that is being connected
|
||||
* @param con_timer Pointer to the timer in question
|
||||
* @param callback The function to call back
|
||||
* @param ec A status code indicating an error, if any.
|
||||
*/
|
||||
void handle_connect_timeout(transport_con_ptr tcon, timer_ptr,
|
||||
connect_handler callback, lib::error_code const & ec)
|
||||
{
|
||||
lib::error_code ret_ec;
|
||||
@@ -932,15 +1045,15 @@ protected:
|
||||
}
|
||||
|
||||
m_alog->write(log::alevel::devel,"TCP connect timed out");
|
||||
tcon->cancel_socket();
|
||||
tcon->cancel_socket_checked();
|
||||
callback(ret_ec);
|
||||
}
|
||||
|
||||
void handle_connect(transport_con_ptr tcon, timer_ptr con_timer,
|
||||
connect_handler callback, boost::system::error_code const & ec)
|
||||
connect_handler callback, lib::asio::error_code const & ec)
|
||||
{
|
||||
if (ec == boost::asio::error::operation_aborted ||
|
||||
con_timer->expires_from_now().is_negative())
|
||||
if (ec == lib::asio::error::operation_aborted ||
|
||||
lib::asio::is_neg(con_timer->expires_from_now()))
|
||||
{
|
||||
m_alog->write(log::alevel::devel,"async_connect cancelled");
|
||||
return;
|
||||
@@ -962,10 +1075,6 @@ protected:
|
||||
callback(lib::error_code());
|
||||
}
|
||||
|
||||
bool is_listening() const {
|
||||
return (m_state == LISTENING);
|
||||
}
|
||||
|
||||
/// Initialize a connection
|
||||
/**
|
||||
* init is called by an endpoint once for each newly created connection.
|
||||
@@ -1022,6 +1131,7 @@ private:
|
||||
|
||||
// Network constants
|
||||
int m_listen_backlog;
|
||||
bool m_reuse_addr;
|
||||
|
||||
elog_type* m_elog;
|
||||
alog_type* m_alog;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Peter Thorson. All rights reserved.
|
||||
* Copyright (c) 2015, Peter Thorson. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
@@ -28,15 +28,13 @@
|
||||
#ifndef WEBSOCKETPP_TRANSPORT_ASIO_SOCKET_BASE_HPP
|
||||
#define WEBSOCKETPP_TRANSPORT_ASIO_SOCKET_BASE_HPP
|
||||
|
||||
#include <websocketpp/common/asio.hpp>
|
||||
#include <websocketpp/common/memory.hpp>
|
||||
#include <websocketpp/common/functional.hpp>
|
||||
#include <websocketpp/common/system_error.hpp>
|
||||
#include <websocketpp/common/cpp11.hpp>
|
||||
#include <websocketpp/common/connection_hdl.hpp>
|
||||
|
||||
#include <boost/asio.hpp>
|
||||
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
// Interface that sockets/security policies must implement
|
||||
@@ -57,6 +55,7 @@
|
||||
|
||||
// Connection
|
||||
// TODO
|
||||
// set_hostname(std::string hostname)
|
||||
// pre_init(init_handler);
|
||||
// post_init(init_handler);
|
||||
|
||||
@@ -65,6 +64,8 @@ namespace transport {
|
||||
namespace asio {
|
||||
namespace socket {
|
||||
|
||||
typedef lib::function<void(lib::asio::error_code const &)> shutdown_handler;
|
||||
|
||||
/**
|
||||
* The transport::asio::socket::* classes are a set of security/socket related
|
||||
* policies and support code for the ASIO transport types.
|
||||
@@ -95,14 +96,20 @@ namespace error {
|
||||
pass_through,
|
||||
|
||||
/// Required tls_init handler not present
|
||||
missing_tls_init_handler
|
||||
missing_tls_init_handler,
|
||||
|
||||
/// TLS Handshake Failed
|
||||
tls_handshake_failed,
|
||||
|
||||
/// Failed to set TLS SNI hostname
|
||||
tls_failed_sni_hostname
|
||||
};
|
||||
} // namespace error
|
||||
|
||||
/// Error category related to asio transport socket policies
|
||||
class socket_category : public lib::error_category {
|
||||
public:
|
||||
const char *name() const _WEBSOCKETPP_NOEXCEPT_TOKEN_ {
|
||||
char const * name() const _WEBSOCKETPP_NOEXCEPT_TOKEN_ {
|
||||
return "websocketpp.transport.asio.socket";
|
||||
}
|
||||
|
||||
@@ -119,16 +126,20 @@ public:
|
||||
case error::tls_handshake_timeout:
|
||||
return "TLS handshake timed out";
|
||||
case error::pass_through:
|
||||
return "Pass through from underlying library";
|
||||
return "Pass through from socket policy";
|
||||
case error::missing_tls_init_handler:
|
||||
return "Required tls_init handler not present.";
|
||||
case error::tls_handshake_failed:
|
||||
return "TLS handshake failed";
|
||||
case error::tls_failed_sni_hostname:
|
||||
return "Failed to set TLS SNI hostname";
|
||||
default:
|
||||
return "Unknown";
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
inline const lib::error_category& get_socket_category() {
|
||||
inline lib::error_category const & get_socket_category() {
|
||||
static socket_category instance;
|
||||
return instance;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Peter Thorson. All rights reserved.
|
||||
* Copyright (c) 2015, Peter Thorson. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
@@ -28,26 +28,32 @@
|
||||
#ifndef WEBSOCKETPP_TRANSPORT_SECURITY_NONE_HPP
|
||||
#define WEBSOCKETPP_TRANSPORT_SECURITY_NONE_HPP
|
||||
|
||||
#include <websocketpp/common/memory.hpp>
|
||||
#include <websocketpp/uri.hpp>
|
||||
|
||||
#include <websocketpp/transport/base/connection.hpp>
|
||||
#include <websocketpp/transport/asio/security/base.hpp>
|
||||
|
||||
#include <boost/asio.hpp>
|
||||
#include <websocketpp/common/asio.hpp>
|
||||
#include <websocketpp/common/memory.hpp>
|
||||
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
|
||||
namespace websocketpp {
|
||||
namespace transport {
|
||||
namespace asio {
|
||||
/// A socket policy for the asio transport that implements a plain, unencrypted
|
||||
/// socket
|
||||
namespace basic_socket {
|
||||
|
||||
typedef lib::function<void(connection_hdl,boost::asio::ip::tcp::socket&)>
|
||||
/// The signature of the socket init handler for this socket policy
|
||||
typedef lib::function<void(connection_hdl,lib::asio::ip::tcp::socket&)>
|
||||
socket_init_handler;
|
||||
|
||||
/// Basic Boost ASIO connection socket component
|
||||
/// Basic Asio connection socket component
|
||||
/**
|
||||
* transport::asio::basic_socket::connection implements a connection socket
|
||||
* component using Boost ASIO ip::tcp::socket.
|
||||
* component using Asio ip::tcp::socket.
|
||||
*/
|
||||
class connection : public lib::enable_shared_from_this<connection> {
|
||||
public:
|
||||
@@ -56,12 +62,14 @@ public:
|
||||
/// Type of a shared pointer to this connection socket component
|
||||
typedef lib::shared_ptr<type> ptr;
|
||||
|
||||
/// Type of a pointer to the ASIO io_service being used
|
||||
typedef boost::asio::io_service* io_service_ptr;
|
||||
/// Type of a pointer to the ASIO io_service strand being used
|
||||
typedef lib::shared_ptr<boost::asio::io_service::strand> strand_ptr;
|
||||
/// Type of a pointer to the Asio io_service being used
|
||||
typedef lib::asio::io_service* io_service_ptr;
|
||||
/// Type of a pointer to the Asio io_service strand being used
|
||||
typedef lib::shared_ptr<lib::asio::io_service::strand> strand_ptr;
|
||||
/// Type of the ASIO socket being used
|
||||
typedef lib::asio::ip::tcp::socket socket_type;
|
||||
/// Type of a shared pointer to the socket being used.
|
||||
typedef lib::shared_ptr<boost::asio::ip::tcp::socket> socket_ptr;
|
||||
typedef lib::shared_ptr<socket_type> socket_ptr;
|
||||
|
||||
explicit connection() : m_state(UNINITIALIZED) {
|
||||
//std::cout << "transport::asio::basic_socket::connection constructor"
|
||||
@@ -85,7 +93,7 @@ public:
|
||||
/**
|
||||
* The socket initialization handler is called after the socket object is
|
||||
* created but before it is used. This gives the application a chance to
|
||||
* set any ASIO socket options it needs.
|
||||
* set any Asio socket options it needs.
|
||||
*
|
||||
* @param h The new socket_init_handler
|
||||
*/
|
||||
@@ -97,7 +105,7 @@ public:
|
||||
/**
|
||||
* This is used internally. It can also be used to set socket options, etc
|
||||
*/
|
||||
boost::asio::ip::tcp::socket& get_socket() {
|
||||
lib::asio::ip::tcp::socket & get_socket() {
|
||||
return *m_socket;
|
||||
}
|
||||
|
||||
@@ -105,7 +113,7 @@ public:
|
||||
/**
|
||||
* This is used internally.
|
||||
*/
|
||||
boost::asio::ip::tcp::socket& get_next_layer() {
|
||||
lib::asio::ip::tcp::socket & get_next_layer() {
|
||||
return *m_socket;
|
||||
}
|
||||
|
||||
@@ -113,7 +121,7 @@ public:
|
||||
/**
|
||||
* This is used internally. It can also be used to set socket options, etc
|
||||
*/
|
||||
boost::asio::ip::tcp::socket& get_raw_socket() {
|
||||
lib::asio::ip::tcp::socket & get_raw_socket() {
|
||||
return *m_socket;
|
||||
}
|
||||
|
||||
@@ -127,16 +135,16 @@ public:
|
||||
*
|
||||
* @return A string identifying the address of the remote endpoint
|
||||
*/
|
||||
std::string get_remote_endpoint(lib::error_code &ec) const {
|
||||
std::string get_remote_endpoint(lib::error_code & ec) const {
|
||||
std::stringstream s;
|
||||
|
||||
boost::system::error_code bec;
|
||||
boost::asio::ip::tcp::endpoint ep = m_socket->remote_endpoint(bec);
|
||||
lib::asio::error_code aec;
|
||||
lib::asio::ip::tcp::endpoint ep = m_socket->remote_endpoint(aec);
|
||||
|
||||
if (bec) {
|
||||
if (aec) {
|
||||
ec = error::make_error_code(error::pass_through);
|
||||
s << "Error getting remote endpoint: " << bec
|
||||
<< " (" << bec.message() << ")";
|
||||
s << "Error getting remote endpoint: " << aec
|
||||
<< " (" << aec.message() << ")";
|
||||
return s.str();
|
||||
} else {
|
||||
ec = lib::error_code();
|
||||
@@ -148,26 +156,39 @@ protected:
|
||||
/// Perform one time initializations
|
||||
/**
|
||||
* init_asio is called once immediately after construction to initialize
|
||||
* boost::asio components to the io_service
|
||||
* Asio components to the io_service
|
||||
*
|
||||
* @param service A pointer to the endpoint's io_service
|
||||
* @param strand A shared pointer to the connection's asio strand
|
||||
* @param is_server Whether or not the endpoint is a server or not.
|
||||
*/
|
||||
lib::error_code init_asio (io_service_ptr service, strand_ptr strand,
|
||||
bool is_server)
|
||||
lib::error_code init_asio (io_service_ptr service, strand_ptr, bool)
|
||||
{
|
||||
if (m_state != UNINITIALIZED) {
|
||||
return socket::make_error_code(socket::error::invalid_state);
|
||||
}
|
||||
|
||||
m_socket.reset(new boost::asio::ip::tcp::socket(*service));
|
||||
m_socket = lib::make_shared<lib::asio::ip::tcp::socket>(
|
||||
lib::ref(*service));
|
||||
|
||||
m_state = READY;
|
||||
|
||||
return lib::error_code();
|
||||
}
|
||||
|
||||
/// Set uri hook
|
||||
/**
|
||||
* Called by the transport as a connection is being established to provide
|
||||
* the uri being connected to to the security/socket layer.
|
||||
*
|
||||
* This socket policy doesn't use the uri so it is ignored.
|
||||
*
|
||||
* @since 0.6.0
|
||||
*
|
||||
* @param u The uri to set
|
||||
*/
|
||||
void set_uri(uri_ptr) {}
|
||||
|
||||
/// Pre-initialize security policy
|
||||
/**
|
||||
* Called by the transport after a new connection is created to initialize
|
||||
@@ -216,19 +237,62 @@ protected:
|
||||
}
|
||||
|
||||
/// Cancel all async operations on this socket
|
||||
void cancel_socket() {
|
||||
m_socket->cancel();
|
||||
/**
|
||||
* Attempts to cancel all async operations on this socket and reports any
|
||||
* failures.
|
||||
*
|
||||
* NOTE: Windows XP and earlier do not support socket cancellation.
|
||||
*
|
||||
* @return The error that occurred, if any.
|
||||
*/
|
||||
lib::asio::error_code cancel_socket() {
|
||||
lib::asio::error_code ec;
|
||||
m_socket->cancel(ec);
|
||||
return ec;
|
||||
}
|
||||
|
||||
void async_shutdown(socket_shutdown_handler h) {
|
||||
boost::system::error_code ec;
|
||||
m_socket->shutdown(boost::asio::ip::tcp::socket::shutdown_both,ec);
|
||||
void async_shutdown(socket::shutdown_handler h) {
|
||||
lib::asio::error_code ec;
|
||||
m_socket->shutdown(lib::asio::ip::tcp::socket::shutdown_both, ec);
|
||||
h(ec);
|
||||
}
|
||||
|
||||
lib::error_code get_ec() const {
|
||||
return lib::error_code();
|
||||
}
|
||||
|
||||
/// Translate any security policy specific information about an error code
|
||||
/**
|
||||
* Translate_ec takes an Asio error code and attempts to convert its value
|
||||
* to an appropriate websocketpp error code. In the case that the Asio and
|
||||
* Websocketpp error types are the same (such as using boost::asio and
|
||||
* boost::system_error or using standalone asio and std::system_error the
|
||||
* code will be passed through natively.
|
||||
*
|
||||
* In the case of a mismatch (boost::asio with std::system_error) a
|
||||
* translated code will be returned. The plain socket policy does not have
|
||||
* any additional information so all such errors will be reported as the
|
||||
* generic transport pass_through error.
|
||||
*
|
||||
* @since 0.3.0
|
||||
*
|
||||
* @param ec The error code to translate_ec
|
||||
* @return The translated error code
|
||||
*/
|
||||
template <typename ErrorCodeType>
|
||||
lib::error_code translate_ec(ErrorCodeType) {
|
||||
// We don't know any more information about this error so pass through
|
||||
return make_error_code(transport::error::pass_through);
|
||||
}
|
||||
|
||||
/// Overload of translate_ec to catch cases where lib::error_code is the
|
||||
/// same type as lib::asio::error_code
|
||||
lib::error_code translate_ec(lib::error_code ec) {
|
||||
// We don't know any more information about this error, but the error is
|
||||
// the same type as the one we are translating to, so pass through
|
||||
// untranslated.
|
||||
return ec;
|
||||
}
|
||||
private:
|
||||
enum state {
|
||||
UNINITIALIZED = 0,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Peter Thorson. All rights reserved.
|
||||
* Copyright (c) 2015, Peter Thorson. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
@@ -29,31 +29,36 @@
|
||||
#define WEBSOCKETPP_TRANSPORT_SECURITY_TLS_HPP
|
||||
|
||||
#include <websocketpp/transport/asio/security/base.hpp>
|
||||
|
||||
#include <websocketpp/uri.hpp>
|
||||
|
||||
#include <websocketpp/common/asio_ssl.hpp>
|
||||
#include <websocketpp/common/asio.hpp>
|
||||
#include <websocketpp/common/connection_hdl.hpp>
|
||||
#include <websocketpp/common/functional.hpp>
|
||||
#include <websocketpp/common/memory.hpp>
|
||||
|
||||
#include <boost/asio.hpp>
|
||||
#include <boost/asio/ssl.hpp>
|
||||
#include <boost/system/error_code.hpp>
|
||||
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
|
||||
namespace websocketpp {
|
||||
namespace transport {
|
||||
namespace asio {
|
||||
/// A socket policy for the asio transport that implements a TLS encrypted
|
||||
/// socket by wrapping with an asio::ssl::stream
|
||||
namespace tls_socket {
|
||||
|
||||
typedef lib::function<void(connection_hdl,boost::asio::ssl::stream<
|
||||
boost::asio::ip::tcp::socket>&)> socket_init_handler;
|
||||
typedef lib::function<lib::shared_ptr<boost::asio::ssl::context>(connection_hdl)>
|
||||
/// The signature of the socket_init_handler for this socket policy
|
||||
typedef lib::function<void(connection_hdl,lib::asio::ssl::stream<
|
||||
lib::asio::ip::tcp::socket>&)> socket_init_handler;
|
||||
/// The signature of the tls_init_handler for this socket policy
|
||||
typedef lib::function<lib::shared_ptr<lib::asio::ssl::context>(connection_hdl)>
|
||||
tls_init_handler;
|
||||
|
||||
/// TLS enabled Boost ASIO connection socket component
|
||||
/// TLS enabled Asio connection socket component
|
||||
/**
|
||||
* transport::asio::tls_socket::connection implements a secure connection socket
|
||||
* component that uses Boost ASIO's ssl::stream to wrap an ip::tcp::socket.
|
||||
* component that uses Asio's ssl::stream to wrap an ip::tcp::socket.
|
||||
*/
|
||||
class connection : public lib::enable_shared_from_this<connection> {
|
||||
public:
|
||||
@@ -63,17 +68,15 @@ public:
|
||||
typedef lib::shared_ptr<type> ptr;
|
||||
|
||||
/// Type of the ASIO socket being used
|
||||
typedef boost::asio::ssl::stream<boost::asio::ip::tcp::socket> socket_type;
|
||||
typedef lib::asio::ssl::stream<lib::asio::ip::tcp::socket> socket_type;
|
||||
/// Type of a shared pointer to the ASIO socket being used
|
||||
typedef lib::shared_ptr<socket_type> socket_ptr;
|
||||
/// Type of a pointer to the ASIO io_service being used
|
||||
typedef boost::asio::io_service* io_service_ptr;
|
||||
typedef lib::asio::io_service * io_service_ptr;
|
||||
/// Type of a pointer to the ASIO io_service strand being used
|
||||
typedef lib::shared_ptr<boost::asio::io_service::strand> strand_ptr;
|
||||
typedef lib::shared_ptr<lib::asio::io_service::strand> strand_ptr;
|
||||
/// Type of a shared pointer to the ASIO TLS context being used
|
||||
typedef lib::shared_ptr<boost::asio::ssl::context> context_ptr;
|
||||
|
||||
typedef boost::system::error_code boost_error;
|
||||
typedef lib::shared_ptr<lib::asio::ssl::context> context_ptr;
|
||||
|
||||
explicit connection() {
|
||||
//std::cout << "transport::asio::tls_socket::connection constructor"
|
||||
@@ -97,7 +100,7 @@ public:
|
||||
/**
|
||||
* This is used internally. It can also be used to set socket options, etc
|
||||
*/
|
||||
socket_type::lowest_layer_type& get_raw_socket() {
|
||||
socket_type::lowest_layer_type & get_raw_socket() {
|
||||
return m_socket->lowest_layer();
|
||||
}
|
||||
|
||||
@@ -105,7 +108,7 @@ public:
|
||||
/**
|
||||
* This is used internally.
|
||||
*/
|
||||
socket_type::next_layer_type& get_next_layer() {
|
||||
socket_type::next_layer_type & get_next_layer() {
|
||||
return m_socket->next_layer();
|
||||
}
|
||||
|
||||
@@ -113,7 +116,7 @@ public:
|
||||
/**
|
||||
* This is used internally.
|
||||
*/
|
||||
socket_type& get_socket() {
|
||||
socket_type & get_socket() {
|
||||
return *m_socket;
|
||||
}
|
||||
|
||||
@@ -152,16 +155,16 @@ public:
|
||||
*
|
||||
* @return A string identifying the address of the remote endpoint
|
||||
*/
|
||||
std::string get_remote_endpoint(lib::error_code &ec) const {
|
||||
std::string get_remote_endpoint(lib::error_code & ec) const {
|
||||
std::stringstream s;
|
||||
|
||||
boost::system::error_code bec;
|
||||
boost::asio::ip::tcp::endpoint ep = m_socket->lowest_layer().remote_endpoint(bec);
|
||||
lib::asio::error_code aec;
|
||||
lib::asio::ip::tcp::endpoint ep = m_socket->lowest_layer().remote_endpoint(aec);
|
||||
|
||||
if (bec) {
|
||||
if (aec) {
|
||||
ec = error::make_error_code(error::pass_through);
|
||||
s << "Error getting remote endpoint: " << bec
|
||||
<< " (" << bec.message() << ")";
|
||||
s << "Error getting remote endpoint: " << aec
|
||||
<< " (" << aec.message() << ")";
|
||||
return s.str();
|
||||
} else {
|
||||
ec = lib::error_code();
|
||||
@@ -173,7 +176,7 @@ protected:
|
||||
/// Perform one time initializations
|
||||
/**
|
||||
* init_asio is called once immediately after construction to initialize
|
||||
* boost::asio components to the io_service
|
||||
* Asio components to the io_service
|
||||
*
|
||||
* @param service A pointer to the endpoint's io_service
|
||||
* @param strand A pointer to the connection's strand
|
||||
@@ -190,7 +193,8 @@ protected:
|
||||
if (!m_context) {
|
||||
return socket::make_error_code(socket::error::invalid_tls_context);
|
||||
}
|
||||
m_socket.reset(new socket_type(*service,*m_context));
|
||||
m_socket = lib::make_shared<socket_type>(
|
||||
_WEBSOCKETPP_REF(*service),lib::ref(*m_context));
|
||||
|
||||
m_io_service = service;
|
||||
m_strand = strand;
|
||||
@@ -199,6 +203,22 @@ protected:
|
||||
return lib::error_code();
|
||||
}
|
||||
|
||||
/// Set hostname hook
|
||||
/**
|
||||
* Called by the transport as a connection is being established to provide
|
||||
* the hostname being connected to to the security/socket layer.
|
||||
*
|
||||
* This socket policy uses the hostname to set the appropriate TLS SNI
|
||||
* header.
|
||||
*
|
||||
* @since 0.6.0
|
||||
*
|
||||
* @param u The uri to set
|
||||
*/
|
||||
void set_uri(uri_ptr u) {
|
||||
m_uri = u;
|
||||
}
|
||||
|
||||
/// Pre-initialize security policy
|
||||
/**
|
||||
* Called by the transport after a new connection is created to initialize
|
||||
@@ -209,6 +229,22 @@ protected:
|
||||
* @param callback Handler to call back with completion information
|
||||
*/
|
||||
void pre_init(init_handler callback) {
|
||||
// TODO: is this the best way to check whether this function is
|
||||
// available in the version of OpenSSL being used?
|
||||
// TODO: consider case where host is an IP address
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x90812f
|
||||
if (!m_is_server) {
|
||||
// For clients on systems with a suitable OpenSSL version, set the
|
||||
// TLS SNI hostname header so connecting to TLS servers using SNI
|
||||
// will work.
|
||||
long res = SSL_set_tlsext_host_name(
|
||||
get_socket().native_handle(), m_uri->get_host().c_str());
|
||||
if (!(1 == res)) {
|
||||
callback(socket::make_error_code(socket::error::tls_failed_sni_hostname));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (m_socket_init_handler) {
|
||||
m_socket_init_handler(m_hdl,get_socket());
|
||||
}
|
||||
@@ -260,11 +296,9 @@ protected:
|
||||
m_hdl = hdl;
|
||||
}
|
||||
|
||||
void handle_init(init_handler callback, const
|
||||
boost::system::error_code& ec)
|
||||
{
|
||||
void handle_init(init_handler callback,lib::asio::error_code const & ec) {
|
||||
if (ec) {
|
||||
m_ec = socket::make_error_code(socket::error::pass_through);
|
||||
m_ec = socket::make_error_code(socket::error::tls_handshake_failed);
|
||||
} else {
|
||||
m_ec = lib::error_code();
|
||||
}
|
||||
@@ -277,19 +311,83 @@ protected:
|
||||
}
|
||||
|
||||
/// Cancel all async operations on this socket
|
||||
void cancel_socket() {
|
||||
get_raw_socket().cancel();
|
||||
/**
|
||||
* Attempts to cancel all async operations on this socket and reports any
|
||||
* failures.
|
||||
*
|
||||
* NOTE: Windows XP and earlier do not support socket cancellation.
|
||||
*
|
||||
* @return The error that occurred, if any.
|
||||
*/
|
||||
lib::asio::error_code cancel_socket() {
|
||||
lib::asio::error_code ec;
|
||||
get_raw_socket().cancel(ec);
|
||||
return ec;
|
||||
}
|
||||
|
||||
void async_shutdown(socket_shutdown_handler callback) {
|
||||
m_socket->async_shutdown(callback);
|
||||
void async_shutdown(socket::shutdown_handler callback) {
|
||||
if (m_strand) {
|
||||
m_socket->async_shutdown(m_strand->wrap(callback));
|
||||
} else {
|
||||
m_socket->async_shutdown(callback);
|
||||
}
|
||||
}
|
||||
|
||||
/// Translate any security policy specific information about an error code
|
||||
/**
|
||||
* Translate_ec takes an Asio error code and attempts to convert its value
|
||||
* to an appropriate websocketpp error code. In the case that the Asio and
|
||||
* Websocketpp error types are the same (such as using boost::asio and
|
||||
* boost::system_error or using standalone asio and std::system_error the
|
||||
* code will be passed through natively.
|
||||
*
|
||||
* In the case of a mismatch (boost::asio with std::system_error) a
|
||||
* translated code will be returned. Any error that is determined to be
|
||||
* related to TLS but does not have a more specific websocketpp error code
|
||||
* is returned under the catch all error `tls_error`. Non-TLS related errors
|
||||
* are returned as the transport generic error `pass_through`
|
||||
*
|
||||
* @since 0.3.0
|
||||
*
|
||||
* @param ec The error code to translate_ec
|
||||
* @return The translated error code
|
||||
*/
|
||||
template <typename ErrorCodeType>
|
||||
lib::error_code translate_ec(ErrorCodeType ec) {
|
||||
if (ec.category() == lib::asio::error::get_ssl_category()) {
|
||||
if (ERR_GET_REASON(ec.value()) == SSL_R_SHORT_READ) {
|
||||
return make_error_code(transport::error::tls_short_read);
|
||||
} else {
|
||||
// We know it is a TLS related error, but otherwise don't know
|
||||
// more. Pass through as TLS generic.
|
||||
return make_error_code(transport::error::tls_error);
|
||||
}
|
||||
} else {
|
||||
// We don't know any more information about this error so pass
|
||||
// through
|
||||
return make_error_code(transport::error::pass_through);
|
||||
}
|
||||
}
|
||||
|
||||
/// Overload of translate_ec to catch cases where lib::error_code is the
|
||||
/// same type as lib::asio::error_code
|
||||
lib::error_code translate_ec(lib::error_code ec) {
|
||||
// Normalize the tls_short_read error as it is used by the library and
|
||||
// needs a consistent value. All other errors pass through natively.
|
||||
// TODO: how to get the SSL category from std::error?
|
||||
/*if (ec.category() == lib::asio::error::get_ssl_category()) {
|
||||
if (ERR_GET_REASON(ec.value()) == SSL_R_SHORT_READ) {
|
||||
return make_error_code(transport::error::tls_short_read);
|
||||
}
|
||||
}*/
|
||||
return ec;
|
||||
}
|
||||
private:
|
||||
socket_type::handshake_type get_handshake_type() {
|
||||
if (m_is_server) {
|
||||
return boost::asio::ssl::stream_base::server;
|
||||
return lib::asio::ssl::stream_base::server;
|
||||
} else {
|
||||
return boost::asio::ssl::stream_base::client;
|
||||
return lib::asio::ssl::stream_base::client;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -297,6 +395,7 @@ private:
|
||||
strand_ptr m_strand;
|
||||
context_ptr m_context;
|
||||
socket_ptr m_socket;
|
||||
uri_ptr m_uri;
|
||||
bool m_is_server;
|
||||
|
||||
lib::error_code m_ec;
|
||||
@@ -306,10 +405,10 @@ private:
|
||||
tls_init_handler m_tls_init_handler;
|
||||
};
|
||||
|
||||
/// TLS enabled Boost ASIO endpoint socket component
|
||||
/// TLS enabled Asio endpoint socket component
|
||||
/**
|
||||
* transport::asio::tls_socket::endpoint implements a secure endpoint socket
|
||||
* component that uses Boost ASIO's ssl::stream to wrap an ip::tcp::socket.
|
||||
* component that uses Asio's ssl::stream to wrap an ip::tcp::socket.
|
||||
*/
|
||||
class endpoint {
|
||||
public:
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Peter Thorson. All rights reserved.
|
||||
* Copyright (c) 2014, Peter Thorson. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
@@ -31,9 +31,10 @@
|
||||
#include <websocketpp/common/cpp11.hpp>
|
||||
#include <websocketpp/common/connection_hdl.hpp>
|
||||
#include <websocketpp/common/functional.hpp>
|
||||
#include <websocketpp/common/memory.hpp>
|
||||
#include <websocketpp/common/system_error.hpp>
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace websocketpp {
|
||||
/// Transport policies provide network connectivity and timers
|
||||
/**
|
||||
@@ -141,6 +142,7 @@ struct buffer {
|
||||
size_t len;
|
||||
};
|
||||
|
||||
/// Generic transport related errors
|
||||
namespace error {
|
||||
enum value {
|
||||
/// Catch-all error for transport policy errors that don't fit in other
|
||||
@@ -170,9 +172,12 @@ enum value {
|
||||
|
||||
/// Timer expired
|
||||
timeout,
|
||||
|
||||
|
||||
/// read or write after shutdown
|
||||
action_after_shutdown
|
||||
action_after_shutdown,
|
||||
|
||||
/// Other TLS error
|
||||
tls_error
|
||||
};
|
||||
|
||||
class category : public lib::error_category {
|
||||
@@ -197,12 +202,14 @@ class category : public lib::error_category {
|
||||
return "The operation is not supported by this transport";
|
||||
case eof:
|
||||
return "End of File";
|
||||
case tls_short_read:
|
||||
case tls_short_read:
|
||||
return "TLS Short Read";
|
||||
case timeout:
|
||||
return "Timer Expired";
|
||||
case action_after_shutdown:
|
||||
return "A transport action was requested after shutdown";
|
||||
case tls_error:
|
||||
return "Generic TLS related error";
|
||||
default:
|
||||
return "Unknown";
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Peter Thorson. All rights reserved.
|
||||
* Copyright (c) 2014, Peter Thorson. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
@@ -28,13 +28,8 @@
|
||||
#ifndef WEBSOCKETPP_TRANSPORT_BASE_HPP
|
||||
#define WEBSOCKETPP_TRANSPORT_BASE_HPP
|
||||
|
||||
#include <websocketpp/common/cpp11.hpp>
|
||||
#include <websocketpp/common/connection_hdl.hpp>
|
||||
#include <websocketpp/common/functional.hpp>
|
||||
#include <websocketpp/common/system_error.hpp>
|
||||
#include <websocketpp/uri.hpp>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
namespace websocketpp {
|
||||
/// Transport policies provide network connectivity and timers
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Peter Thorson. All rights reserved.
|
||||
* Copyright (c) 2014, Peter Thorson. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
@@ -30,14 +30,36 @@
|
||||
|
||||
#include <websocketpp/common/system_error.hpp>
|
||||
#include <websocketpp/common/cpp11.hpp>
|
||||
#include <websocketpp/common/functional.hpp>
|
||||
#include <websocketpp/common/connection_hdl.hpp>
|
||||
|
||||
#include <websocketpp/transport/base/connection.hpp>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace websocketpp {
|
||||
namespace transport {
|
||||
/// Transport policy that uses STL iostream for I/O and does not support timers
|
||||
namespace iostream {
|
||||
|
||||
/// The type and signature of the callback used by iostream transport to write
|
||||
typedef lib::function<lib::error_code(connection_hdl, char const *, size_t)>
|
||||
write_handler;
|
||||
|
||||
/// The type and signature of the callback used by iostream transport to perform
|
||||
/// vectored writes.
|
||||
/**
|
||||
* If a vectored write handler is not set the standard write handler will be
|
||||
* called multiple times.
|
||||
*/
|
||||
typedef lib::function<lib::error_code(connection_hdl, std::vector<transport::buffer> const
|
||||
& bufs)> vector_write_handler;
|
||||
|
||||
/// The type and signature of the callback used by iostream transport to signal
|
||||
/// a transport shutdown.
|
||||
typedef lib::function<lib::error_code(connection_hdl)> shutdown_handler;
|
||||
|
||||
/// iostream transport errors
|
||||
namespace error {
|
||||
enum value {
|
||||
|
||||
+199
-36
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Peter Thorson. All rights reserved.
|
||||
* Copyright (c) 2014, Peter Thorson. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
@@ -28,14 +28,22 @@
|
||||
#ifndef WEBSOCKETPP_TRANSPORT_IOSTREAM_CON_HPP
|
||||
#define WEBSOCKETPP_TRANSPORT_IOSTREAM_CON_HPP
|
||||
|
||||
#include <websocketpp/common/memory.hpp>
|
||||
#include <websocketpp/common/connection_hdl.hpp>
|
||||
#include <websocketpp/logger/levels.hpp>
|
||||
|
||||
#include <websocketpp/transport/base/connection.hpp>
|
||||
#include <websocketpp/transport/iostream/base.hpp>
|
||||
|
||||
#include <websocketpp/transport/base/connection.hpp>
|
||||
|
||||
#include <websocketpp/uri.hpp>
|
||||
|
||||
#include <websocketpp/logger/levels.hpp>
|
||||
|
||||
#include <websocketpp/common/connection_hdl.hpp>
|
||||
#include <websocketpp/common/memory.hpp>
|
||||
#include <websocketpp/common/platforms.hpp>
|
||||
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace websocketpp {
|
||||
@@ -99,6 +107,19 @@ public:
|
||||
m_output_stream = o;
|
||||
}
|
||||
|
||||
/// Set uri hook
|
||||
/**
|
||||
* Called by the endpoint as a connection is being established to provide
|
||||
* the uri being connected to to the transport layer.
|
||||
*
|
||||
* This transport policy doesn't use the uri so it is ignored.
|
||||
*
|
||||
* @since 0.6.0
|
||||
*
|
||||
* @param u The uri to set
|
||||
*/
|
||||
void set_uri(uri_ptr) {}
|
||||
|
||||
/// Overloaded stream input operator
|
||||
/**
|
||||
* Attempts to read input from the given stream into the transport. Bytes
|
||||
@@ -127,14 +148,13 @@ public:
|
||||
return in;
|
||||
}
|
||||
|
||||
/// Manual input supply
|
||||
/// Manual input supply (read some)
|
||||
/**
|
||||
* Copies bytes from buf into WebSocket++'s input buffers. Bytes will be
|
||||
* copied from the supplied buffer to fulfill any pending library reads. It
|
||||
* will return the number of bytes successfully processed. If there are no
|
||||
* pending reads read_some will return immediately. Not all of the bytes may
|
||||
* be able to be read in one call
|
||||
*
|
||||
* be able to be read in one call.
|
||||
*
|
||||
* @since 0.3.0-alpha4
|
||||
*
|
||||
@@ -149,6 +169,37 @@ public:
|
||||
return this->read_some_impl(buf,len);
|
||||
}
|
||||
|
||||
/// Manual input supply (read all)
|
||||
/**
|
||||
* Similar to read_some, but continues to read until all bytes in the
|
||||
* supplied buffer have been read or the connection runs out of read
|
||||
* requests.
|
||||
*
|
||||
* This method still may not read all of the bytes in the input buffer. if
|
||||
* it doesn't it indicates that the connection was most likely closed or
|
||||
* is in an error state where it is no longer accepting new input.
|
||||
*
|
||||
* @since 0.3.0
|
||||
*
|
||||
* @param buf Char buffer to read into the websocket
|
||||
* @param len Length of buf
|
||||
* @return The number of characters from buf actually read.
|
||||
*/
|
||||
size_t read_all(char const * buf, size_t len) {
|
||||
// this serializes calls to external read.
|
||||
scoped_lock_type lock(m_read_mutex);
|
||||
|
||||
size_t total_read = 0;
|
||||
size_t temp_read = 0;
|
||||
|
||||
do {
|
||||
temp_read = this->read_some_impl(buf+total_read,len-total_read);
|
||||
total_read += temp_read;
|
||||
} while (temp_read != 0 && total_read < len);
|
||||
|
||||
return total_read;
|
||||
}
|
||||
|
||||
/// Manual input supply (DEPRECATED)
|
||||
/**
|
||||
* @deprecated DEPRECATED in favor of read_some()
|
||||
@@ -273,9 +324,82 @@ public:
|
||||
* @return A handle that can be used to cancel the timer if it is no longer
|
||||
* needed.
|
||||
*/
|
||||
timer_ptr set_timer(long duration, timer_handler handler) {
|
||||
timer_ptr set_timer(long, timer_handler) {
|
||||
return timer_ptr();
|
||||
}
|
||||
|
||||
/// Sets the write handler
|
||||
/**
|
||||
* The write handler is called when the iostream transport receives data
|
||||
* that needs to be written to the appropriate output location. This handler
|
||||
* can be used in place of registering an ostream for output.
|
||||
*
|
||||
* The signature of the handler is
|
||||
* `lib::error_code (connection_hdl, char const *, size_t)` The
|
||||
* code returned will be reported and logged by the core library.
|
||||
*
|
||||
* See also, set_vector_write_handler, for an optional write handler that
|
||||
* allows more efficient handling of multiple writes at once.
|
||||
*
|
||||
* @see set_vector_write_handler
|
||||
*
|
||||
* @since 0.5.0
|
||||
*
|
||||
* @param h The handler to call when data is to be written.
|
||||
*/
|
||||
void set_write_handler(write_handler h) {
|
||||
m_write_handler = h;
|
||||
}
|
||||
|
||||
/// Sets the vectored write handler
|
||||
/**
|
||||
* The vectored write handler is called when the iostream transport receives
|
||||
* multiple chunks of data that need to be written to the appropriate output
|
||||
* location. This handler can be used in conjunction with the write_handler
|
||||
* in place of registering an ostream for output.
|
||||
*
|
||||
* The sequence of buffers represents bytes that should be written
|
||||
* consecutively and it is suggested to group the buffers into as few next
|
||||
* layer packets as possible. Vector write is used to allow implementations
|
||||
* that support it to coalesce writes into a single TCP packet or TLS
|
||||
* segment for improved efficiency.
|
||||
*
|
||||
* This is an optional handler. If it is not defined then multiple calls
|
||||
* will be made to the standard write handler.
|
||||
*
|
||||
* The signature of the handler is
|
||||
* `lib::error_code (connection_hdl, std::vector<websocketpp::transport::buffer>
|
||||
* const & bufs)`. The code returned will be reported and logged by the core
|
||||
* library. The `websocketpp::transport::buffer` type is a struct with two
|
||||
* data members. buf (char const *) and len (size_t).
|
||||
*
|
||||
* @since 0.6.0
|
||||
*
|
||||
* @param h The handler to call when vectored data is to be written.
|
||||
*/
|
||||
void set_vector_write_handler(vector_write_handler h) {
|
||||
m_vector_write_handler = h;
|
||||
}
|
||||
|
||||
/// Sets the shutdown handler
|
||||
/**
|
||||
* The shutdown handler is called when the iostream transport receives a
|
||||
* notification from the core library that it is finished with all read and
|
||||
* write operations and that the underlying transport can be cleaned up.
|
||||
*
|
||||
* If you are using iostream transport with another socket library, this is
|
||||
* a good time to close/shutdown the socket for this connection.
|
||||
*
|
||||
* The signature of the handler is `lib::error_code (connection_hdl)`. The
|
||||
* code returned will be reported and logged by the core library.
|
||||
*
|
||||
* @since 0.5.0
|
||||
*
|
||||
* @param h The handler to call on connection shutdown.
|
||||
*/
|
||||
void set_shutdown_handler(shutdown_handler h) {
|
||||
m_shutdown_handler = h;
|
||||
}
|
||||
protected:
|
||||
/// Initialize the connection transport
|
||||
/**
|
||||
@@ -344,7 +468,7 @@ protected:
|
||||
|
||||
/// Asyncronous Transport Write
|
||||
/**
|
||||
* Write len bytes in buf to the output stream. Call handler to report
|
||||
* Write len bytes in buf to the output method. Call handler to report
|
||||
* success or failure. handler may or may not be called during async_write,
|
||||
* but it must be safe for this to happen.
|
||||
*
|
||||
@@ -352,31 +476,40 @@ protected:
|
||||
* output_stream_required: No output stream was registered to write to
|
||||
* bad_stream: a ostream pass through error
|
||||
*
|
||||
* This method will attempt to write to the registered ostream first. If an
|
||||
* ostream is not registered it will use the write handler. If neither are
|
||||
* registered then an error is passed up to the connection.
|
||||
*
|
||||
* @param buf buffer to read bytes from
|
||||
* @param len number of bytes to write
|
||||
* @param handler Callback to invoke with operation status.
|
||||
*/
|
||||
void async_write(char const * buf, size_t len, write_handler handler) {
|
||||
void async_write(char const * buf, size_t len, transport::write_handler
|
||||
handler)
|
||||
{
|
||||
m_alog.write(log::alevel::devel,"iostream_con async_write");
|
||||
// TODO: lock transport state?
|
||||
|
||||
if (!m_output_stream) {
|
||||
handler(make_error_code(error::output_stream_required));
|
||||
return;
|
||||
}
|
||||
lib::error_code ec;
|
||||
|
||||
m_output_stream->write(buf,len);
|
||||
if (m_output_stream) {
|
||||
m_output_stream->write(buf,len);
|
||||
|
||||
if (m_output_stream->bad()) {
|
||||
handler(make_error_code(error::bad_stream));
|
||||
if (m_output_stream->bad()) {
|
||||
ec = make_error_code(error::bad_stream);
|
||||
}
|
||||
} else if (m_write_handler) {
|
||||
ec = m_write_handler(m_connection_hdl, buf, len);
|
||||
} else {
|
||||
handler(lib::error_code());
|
||||
ec = make_error_code(error::output_stream_required);
|
||||
}
|
||||
|
||||
handler(ec);
|
||||
}
|
||||
|
||||
/// Asyncronous Transport Write (scatter-gather)
|
||||
/**
|
||||
* Write a sequence of buffers to the output stream. Call handler to report
|
||||
* Write a sequence of buffers to the output method. Call handler to report
|
||||
* success or failure. handler may or may not be called during async_write,
|
||||
* but it must be safe for this to happen.
|
||||
*
|
||||
@@ -384,28 +517,45 @@ protected:
|
||||
* output_stream_required: No output stream was registered to write to
|
||||
* bad_stream: a ostream pass through error
|
||||
*
|
||||
* This method will attempt to write to the registered ostream first. If an
|
||||
* ostream is not registered it will use the write handler. If neither are
|
||||
* registered then an error is passed up to the connection.
|
||||
*
|
||||
* @param bufs vector of buffers to write
|
||||
* @param handler Callback to invoke with operation status.
|
||||
*/
|
||||
void async_write(std::vector<buffer> const & bufs, write_handler handler) {
|
||||
void async_write(std::vector<buffer> const & bufs, transport::write_handler
|
||||
handler)
|
||||
{
|
||||
m_alog.write(log::alevel::devel,"iostream_con async_write buffer list");
|
||||
// TODO: lock transport state?
|
||||
|
||||
if (!m_output_stream) {
|
||||
handler(make_error_code(error::output_stream_required));
|
||||
return;
|
||||
}
|
||||
lib::error_code ec;
|
||||
|
||||
std::vector<buffer>::const_iterator it;
|
||||
for (it = bufs.begin(); it != bufs.end(); it++) {
|
||||
m_output_stream->write((*it).buf,(*it).len);
|
||||
if (m_output_stream) {
|
||||
std::vector<buffer>::const_iterator it;
|
||||
for (it = bufs.begin(); it != bufs.end(); it++) {
|
||||
m_output_stream->write((*it).buf,(*it).len);
|
||||
|
||||
if (m_output_stream->bad()) {
|
||||
handler(make_error_code(error::bad_stream));
|
||||
if (m_output_stream->bad()) {
|
||||
ec = make_error_code(error::bad_stream);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if (m_vector_write_handler) {
|
||||
ec = m_vector_write_handler(m_connection_hdl, bufs);
|
||||
} else if (m_write_handler) {
|
||||
std::vector<buffer>::const_iterator it;
|
||||
for (it = bufs.begin(); it != bufs.end(); it++) {
|
||||
ec = m_write_handler(m_connection_hdl, (*it).buf, (*it).len);
|
||||
if (ec) {break;}
|
||||
}
|
||||
|
||||
} else {
|
||||
ec = make_error_code(error::output_stream_required);
|
||||
}
|
||||
|
||||
handler(lib::error_code());
|
||||
handler(ec);
|
||||
}
|
||||
|
||||
/// Set Connection Handle
|
||||
@@ -434,10 +584,20 @@ protected:
|
||||
|
||||
/// Perform cleanup on socket shutdown_handler
|
||||
/**
|
||||
* @param h The `shutdown_handler` to call back when complete
|
||||
* If a shutdown handler is set, call it and pass through its return error
|
||||
* code. Otherwise assume there is nothing to do and pass through a success
|
||||
* code.
|
||||
*
|
||||
* @param handler The `shutdown_handler` to call back when complete
|
||||
*/
|
||||
void async_shutdown(shutdown_handler handler) {
|
||||
handler(lib::error_code());
|
||||
void async_shutdown(transport::shutdown_handler handler) {
|
||||
lib::error_code ec;
|
||||
|
||||
if (m_shutdown_handler) {
|
||||
ec = m_shutdown_handler(m_connection_hdl);
|
||||
}
|
||||
|
||||
handler(ec);
|
||||
}
|
||||
private:
|
||||
void read(std::istream &in) {
|
||||
@@ -479,7 +639,7 @@ private:
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t bytes_to_copy = std::min(len,m_len-m_cursor);
|
||||
size_t bytes_to_copy = (std::min)(len,m_len-m_cursor);
|
||||
|
||||
std::copy(buf,buf+bytes_to_copy,m_buf+m_cursor);
|
||||
|
||||
@@ -527,6 +687,9 @@ private:
|
||||
// transport resources
|
||||
std::ostream * m_output_stream;
|
||||
connection_hdl m_connection_hdl;
|
||||
write_handler m_write_handler;
|
||||
vector_write_handler m_vector_write_handler;
|
||||
shutdown_handler m_shutdown_handler;
|
||||
|
||||
bool m_reading;
|
||||
bool const m_is_server;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Peter Thorson. All rights reserved.
|
||||
* Copyright (c) 2014, Peter Thorson. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
@@ -28,13 +28,15 @@
|
||||
#ifndef WEBSOCKETPP_TRANSPORT_IOSTREAM_HPP
|
||||
#define WEBSOCKETPP_TRANSPORT_IOSTREAM_HPP
|
||||
|
||||
#include <websocketpp/common/memory.hpp>
|
||||
#include <websocketpp/logger/levels.hpp>
|
||||
|
||||
#include <websocketpp/transport/base/endpoint.hpp>
|
||||
#include <websocketpp/transport/iostream/connection.hpp>
|
||||
|
||||
#include <iostream>
|
||||
#include <websocketpp/uri.hpp>
|
||||
#include <websocketpp/logger/levels.hpp>
|
||||
|
||||
#include <websocketpp/common/memory.hpp>
|
||||
|
||||
#include <ostream>
|
||||
|
||||
namespace websocketpp {
|
||||
namespace transport {
|
||||
@@ -114,6 +116,44 @@ public:
|
||||
bool is_secure() const {
|
||||
return m_is_secure;
|
||||
}
|
||||
|
||||
/// Sets the write handler
|
||||
/**
|
||||
* The write handler is called when the iostream transport receives data
|
||||
* that needs to be written to the appropriate output location. This handler
|
||||
* can be used in place of registering an ostream for output.
|
||||
*
|
||||
* The signature of the handler is
|
||||
* `lib::error_code (connection_hdl, char const *, size_t)` The
|
||||
* code returned will be reported and logged by the core library.
|
||||
*
|
||||
* @since 0.5.0
|
||||
*
|
||||
* @param h The handler to call on connection shutdown.
|
||||
*/
|
||||
void set_write_handler(write_handler h) {
|
||||
m_write_handler = h;
|
||||
}
|
||||
|
||||
/// Sets the shutdown handler
|
||||
/**
|
||||
* The shutdown handler is called when the iostream transport receives a
|
||||
* notification from the core library that it is finished with all read and
|
||||
* write operations and that the underlying transport can be cleaned up.
|
||||
*
|
||||
* If you are using iostream transport with another socket library, this is
|
||||
* a good time to close/shutdown the socket for this connection.
|
||||
*
|
||||
* The signature of the handler is lib::error_code (connection_hdl). The
|
||||
* code returned will be reported and logged by the core library.
|
||||
*
|
||||
* @since 0.5.0
|
||||
*
|
||||
* @param h The handler to call on connection shutdown.
|
||||
*/
|
||||
void set_shutdown_handler(shutdown_handler h) {
|
||||
m_shutdown_handler = h;
|
||||
}
|
||||
protected:
|
||||
/// Initialize logging
|
||||
/**
|
||||
@@ -140,7 +180,7 @@ protected:
|
||||
* @param u A URI pointer to the URI to connect to.
|
||||
* @param cb The function to call back with the results when complete.
|
||||
*/
|
||||
void async_connect(transport_con_ptr tcon, uri_ptr u, connect_handler cb) {
|
||||
void async_connect(transport_con_ptr, uri_ptr, connect_handler cb) {
|
||||
cb(lib::error_code());
|
||||
}
|
||||
|
||||
@@ -156,10 +196,19 @@ protected:
|
||||
*/
|
||||
lib::error_code init(transport_con_ptr tcon) {
|
||||
tcon->register_ostream(m_output_stream);
|
||||
if (m_shutdown_handler) {
|
||||
tcon->set_shutdown_handler(m_shutdown_handler);
|
||||
}
|
||||
if (m_write_handler) {
|
||||
tcon->set_write_handler(m_write_handler);
|
||||
}
|
||||
return lib::error_code();
|
||||
}
|
||||
private:
|
||||
std::ostream * m_output_stream;
|
||||
shutdown_handler m_shutdown_handler;
|
||||
write_handler m_write_handler;
|
||||
|
||||
elog_type * m_elog;
|
||||
alog_type * m_alog;
|
||||
bool m_is_secure;
|
||||
|
||||
+28
-27
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Peter Thorson. All rights reserved.
|
||||
* Copyright (c) 2014, Peter Thorson. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
@@ -28,11 +28,11 @@
|
||||
#ifndef WEBSOCKETPP_URI_HPP
|
||||
#define WEBSOCKETPP_URI_HPP
|
||||
|
||||
#include <websocketpp/common/memory.hpp>
|
||||
#include <websocketpp/error.hpp>
|
||||
|
||||
#include <websocketpp/common/memory.hpp>
|
||||
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
|
||||
@@ -47,27 +47,28 @@ static uint16_t const uri_default_secure_port = 443;
|
||||
|
||||
class uri {
|
||||
public:
|
||||
explicit uri(std::string const & uri) : m_valid(false) {
|
||||
explicit uri(std::string const & uri_string) : m_valid(false) {
|
||||
std::string::const_iterator it;
|
||||
std::string::const_iterator temp;
|
||||
|
||||
int state = 0;
|
||||
|
||||
it = uri.begin();
|
||||
it = uri_string.begin();
|
||||
size_t uri_len = uri_string.length();
|
||||
|
||||
if (std::equal(it,it+6,"wss://")) {
|
||||
if (uri_len >= 7 && std::equal(it,it+6,"wss://")) {
|
||||
m_secure = true;
|
||||
m_scheme = "wss";
|
||||
it += 6;
|
||||
} else if (std::equal(it,it+5,"ws://")) {
|
||||
} else if (uri_len >= 6 && std::equal(it,it+5,"ws://")) {
|
||||
m_secure = false;
|
||||
m_scheme = "ws";
|
||||
it += 5;
|
||||
} else if (std::equal(it,it+7,"http://")) {
|
||||
} else if (uri_len >= 8 && std::equal(it,it+7,"http://")) {
|
||||
m_secure = false;
|
||||
m_scheme = "http";
|
||||
it += 7;
|
||||
} else if (std::equal(it,it+8,"https://")) {
|
||||
} else if (uri_len >= 9 && std::equal(it,it+8,"https://")) {
|
||||
m_secure = true;
|
||||
m_scheme = "https";
|
||||
it += 8;
|
||||
@@ -88,14 +89,14 @@ public:
|
||||
//temp = std::find(it,it2,']');
|
||||
|
||||
temp = it;
|
||||
while (temp != uri.end()) {
|
||||
while (temp != uri_string.end()) {
|
||||
if (*temp == ']') {
|
||||
break;
|
||||
}
|
||||
++temp;
|
||||
}
|
||||
|
||||
if (temp == uri.end()) {
|
||||
if (temp == uri_string.end()) {
|
||||
return;
|
||||
} else {
|
||||
// validate IPv6 literal parts
|
||||
@@ -103,7 +104,7 @@ public:
|
||||
m_host.append(it,temp);
|
||||
}
|
||||
it = temp+1;
|
||||
if (it == uri.end()) {
|
||||
if (it == uri_string.end()) {
|
||||
state = 2;
|
||||
} else if (*it == '/') {
|
||||
state = 2;
|
||||
@@ -119,7 +120,7 @@ public:
|
||||
// IPv4 or hostname
|
||||
// extract until : or /
|
||||
while (state == 0) {
|
||||
if (it == uri.end()) {
|
||||
if (it == uri_string.end()) {
|
||||
state = 2;
|
||||
break;
|
||||
} else if (*it == '/') {
|
||||
@@ -135,9 +136,9 @@ public:
|
||||
}
|
||||
|
||||
// parse port
|
||||
std::string port = "";
|
||||
std::string port;
|
||||
while (state == 1) {
|
||||
if (it == uri.end()) {
|
||||
if (it == uri_string.end()) {
|
||||
// state is not used after this point presently.
|
||||
// this should be re-enabled if it ever is needed in a future
|
||||
// refactoring
|
||||
@@ -159,7 +160,7 @@ public:
|
||||
}
|
||||
|
||||
m_resource = "/";
|
||||
m_resource.append(it,uri.end());
|
||||
m_resource.append(it,uri_string.end());
|
||||
|
||||
|
||||
m_valid = true;
|
||||
@@ -169,7 +170,7 @@ public:
|
||||
std::string const & resource)
|
||||
: m_scheme(secure ? "wss" : "ws")
|
||||
, m_host(host)
|
||||
, m_resource(resource == "" ? "/" : resource)
|
||||
, m_resource(resource.empty() ? "/" : resource)
|
||||
, m_port(port)
|
||||
, m_secure(secure)
|
||||
, m_valid(true) {}
|
||||
@@ -177,7 +178,7 @@ public:
|
||||
uri(bool secure, std::string const & host, std::string const & resource)
|
||||
: m_scheme(secure ? "wss" : "ws")
|
||||
, m_host(host)
|
||||
, m_resource(resource == "" ? "/" : resource)
|
||||
, m_resource(resource.empty() ? "/" : resource)
|
||||
, m_port(secure ? uri_default_secure_port : uri_default_port)
|
||||
, m_secure(secure)
|
||||
, m_valid(true) {}
|
||||
@@ -186,7 +187,7 @@ public:
|
||||
std::string const & resource)
|
||||
: m_scheme(secure ? "wss" : "ws")
|
||||
, m_host(host)
|
||||
, m_resource(resource == "" ? "/" : resource)
|
||||
, m_resource(resource.empty() ? "/" : resource)
|
||||
, m_secure(secure)
|
||||
{
|
||||
lib::error_code ec;
|
||||
@@ -198,7 +199,7 @@ public:
|
||||
std::string const & resource)
|
||||
: m_scheme(scheme)
|
||||
, m_host(host)
|
||||
, m_resource(resource == "" ? "/" : resource)
|
||||
, m_resource(resource.empty() ? "/" : resource)
|
||||
, m_port(port)
|
||||
, m_secure(scheme == "wss" || scheme == "https")
|
||||
, m_valid(true) {}
|
||||
@@ -206,7 +207,7 @@ public:
|
||||
uri(std::string scheme, std::string const & host, std::string const & resource)
|
||||
: m_scheme(scheme)
|
||||
, m_host(host)
|
||||
, m_resource(resource == "" ? "/" : resource)
|
||||
, m_resource(resource.empty() ? "/" : resource)
|
||||
, m_port((scheme == "wss" || scheme == "https") ? uri_default_secure_port : uri_default_port)
|
||||
, m_secure(scheme == "wss" || scheme == "https")
|
||||
, m_valid(true) {}
|
||||
@@ -215,7 +216,7 @@ public:
|
||||
std::string const & port, std::string const & resource)
|
||||
: m_scheme(scheme)
|
||||
, m_host(host)
|
||||
, m_resource(resource == "" ? "/" : resource)
|
||||
, m_resource(resource.empty() ? "/" : resource)
|
||||
, m_secure(scheme == "wss" || scheme == "https")
|
||||
{
|
||||
lib::error_code ec;
|
||||
@@ -290,10 +291,10 @@ public:
|
||||
* @return query portion of the URI.
|
||||
*/
|
||||
std::string get_query() const {
|
||||
std::size_t found = m_resource.find('?');
|
||||
if (found != std::string::npos) {
|
||||
return m_resource.substr(found + 1);
|
||||
} else {
|
||||
std::size_t found = m_resource.find('?');
|
||||
if (found != std::string::npos) {
|
||||
return m_resource.substr(found + 1);
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
@@ -321,7 +322,7 @@ private:
|
||||
{
|
||||
ec = lib::error_code();
|
||||
|
||||
if (port == "") {
|
||||
if (port.empty()) {
|
||||
return (m_secure ? uri_default_secure_port : uri_default_port);
|
||||
}
|
||||
|
||||
|
||||
@@ -31,6 +31,8 @@
|
||||
|
||||
#include <websocketpp/common/stdint.hpp>
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace websocketpp {
|
||||
namespace utf8_validator {
|
||||
|
||||
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Peter Thorson. All rights reserved.
|
||||
* Copyright (c) 2014, Peter Thorson. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
@@ -78,7 +78,7 @@ struct ci_less : std::binary_function<std::string, std::string, bool> {
|
||||
: public std::binary_function<unsigned char,unsigned char,bool>
|
||||
{
|
||||
bool operator() (unsigned char const & c1, unsigned char const & c2) const {
|
||||
return std::tolower (c1) < std::tolower (c2);
|
||||
return tolower (c1) < tolower (c2);
|
||||
}
|
||||
};
|
||||
bool operator() (std::string const & s1, std::string const & s2) const {
|
||||
|
||||
+5
-4
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Peter Thorson. All rights reserved.
|
||||
* Copyright (c) 2015, Peter Thorson. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
@@ -42,7 +42,7 @@ namespace websocketpp {
|
||||
/// Library major version number
|
||||
static int const major_version = 0;
|
||||
/// Library minor version number
|
||||
static int const minor_version = 3;
|
||||
static int const minor_version = 7;
|
||||
/// Library patch version number
|
||||
static int const patch_version = 0;
|
||||
/// Library pre-release flag
|
||||
@@ -50,10 +50,11 @@ static int const patch_version = 0;
|
||||
* This is a textual flag indicating the type and number for pre-release
|
||||
* versions (dev, alpha, beta, rc). This will be blank for release versions.
|
||||
*/
|
||||
static char const prerelease_flag[] = "alpha4";
|
||||
|
||||
static char const prerelease_flag[] = "";
|
||||
|
||||
/// Default user agent string
|
||||
static char const user_agent[] = "WebSocket++/0.3.0-alpha4";
|
||||
static char const user_agent[] = "WebSocket++/0.7.0";
|
||||
|
||||
} // namespace websocketpp
|
||||
|
||||
|
||||
Reference in new issue
Block a user