Compare commits
96 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 0d7052d2ae | |||
| c5510d6de0 | |||
| f931734369 | |||
| af792aeaba | |||
| 2af2135d82 | |||
| f2b38d5634 | |||
| 1b9e40040c | |||
| 8893faff53 | |||
| 430fb82e76 | |||
| 01d4109ae8 | |||
| 4cc678ee93 | |||
| acb53a379c | |||
| c18f210ea3 | |||
| f469b90bfc | |||
| 9d95501536 | |||
| 9351e73e90 | |||
| b817c4499e | |||
| 7829de34a3 | |||
| 6973f02d1c | |||
| 31b75714bd | |||
| 257b5ac8e5 | |||
| 769fe89533 | |||
| d670d69c6e | |||
| 2c843b9343 | |||
| d076e38e00 | |||
| 4331de8a29 | |||
| 6dde40d96e | |||
| d68fd03e40 | |||
| e161ffde69 | |||
| dc313effa5 | |||
| 6300e090ad | |||
| 45dfcbec3c | |||
| 39dbe3a4e0 | |||
| 371d2cdaef | |||
| 13f6da6f81 | |||
| 174698f1df | |||
| 214cedf949 | |||
| c39412ee38 | |||
| 643e7a0ce1 | |||
| 349717ad46 | |||
| bcd82bd6f4 | |||
| 8f042d95ec | |||
| 0278ba7895 | |||
| 41c37cfd93 | |||
| 4bea90f555 | |||
| f9b08ccea1 | |||
| ce0300e6dc | |||
| fccc78479e | |||
| 3017a9c5e4 | |||
| 17544d4d62 | |||
| 4d1693c96c | |||
| c021766592 | |||
| 7f7e9d2c2c | |||
| 70923eea23 | |||
| 99ae2f768c | |||
| 884e7d210c | |||
| 75dd6f3ba5 | |||
| 2ee496c08d | |||
| aabf87b6b1 | |||
| cfabe17e83 | |||
| e62823a0af | |||
| 8ce05cd228 | |||
| eb314e55de | |||
| ccbd93f725 | |||
| be9a320fc1 | |||
| 9a73b74a37 | |||
| 48add58dc2 | |||
| e967ffc74d | |||
| 475c478a2e | |||
| b8d962950f | |||
| ba0094a0eb | |||
| eb362007ab | |||
| 4d63c10be7 | |||
| 28f949d955 | |||
| 11906dc2ce | |||
| c60e089553 | |||
| b809bf3706 | |||
| 6920b39aa2 | |||
| f7376ccf46 | |||
| 243cea16db | |||
| 98a75b8cea | |||
| 5323076007 | |||
| d0d97b860b | |||
| 25e8d522b2 | |||
| bd408944fd | |||
| 14aa71091f | |||
| 4607150f82 | |||
| 359f03fb1e | |||
| 4a52e548fd | |||
| 0501f77b57 | |||
| 631261c365 | |||
| a90ccd83dd | |||
| c103032e9c | |||
| c32bebba3e | |||
| 6c6c6951e5 | |||
| aeb0e8fa7d |
+1
-1
@@ -2,7 +2,7 @@ language: cpp
|
||||
compiler:
|
||||
- gcc
|
||||
before_install:
|
||||
- sudo apt-get install libboost-regex1.48-dev libboost-system1.48-dev libboost-thread1.48-dev libboost-test1.48-dev libboost-random1.48-dev -y
|
||||
- sudo apt-get install libboost-chrono1.48-dev libboost-regex1.48-dev libboost-system1.48-dev libboost-thread1.48-dev libboost-test1.48-dev libboost-random1.48-dev -y
|
||||
env:
|
||||
global:
|
||||
- BOOST_INCLUDES=/usr/include
|
||||
|
||||
+5
-5
@@ -9,8 +9,8 @@ project (websocketpp)
|
||||
cmake_minimum_required (VERSION 2.6)
|
||||
|
||||
set (WEBSOCKETPP_MAJOR_VERSION 0)
|
||||
set (WEBSOCKETPP_MINOR_VERSION 5)
|
||||
set (WEBSOCKETPP_PATCH_VERSION 1)
|
||||
set (WEBSOCKETPP_MINOR_VERSION 6)
|
||||
set (WEBSOCKETPP_PATCH_VERSION 0)
|
||||
set (WEBSOCKETPP_VERSION ${WEBSOCKETPP_MAJOR_VERSION}.${WEBSOCKETPP_MINOR_VERSION}.${WEBSOCKETPP_PATCH_VERSION})
|
||||
|
||||
set(INSTALL_INCLUDE_DIR include CACHE PATH "Installation directory for header files")
|
||||
@@ -70,7 +70,7 @@ if (BUILD_TESTS OR BUILD_EXAMPLES)
|
||||
############ Compiler specific setup
|
||||
|
||||
set (WEBSOCKETPP_PLATFORM_LIBS "")
|
||||
set (WEBSOCKETPP_PLATFORM_TSL_LIBS "")
|
||||
set (WEBSOCKETPP_PLATFORM_TLS_LIBS "")
|
||||
set (WEBSOCKETPP_BOOST_LIBS "")
|
||||
|
||||
# VC9 and C++11 reasoning
|
||||
@@ -111,7 +111,7 @@ if (BUILD_TESTS OR BUILD_EXAMPLES)
|
||||
# g++
|
||||
if (CMAKE_COMPILER_IS_GNUCXX)
|
||||
set (WEBSOCKETPP_PLATFORM_LIBS pthread rt)
|
||||
set (WEBSOCKETPP_PLATFORM_TSL_LIBS ssl crypto)
|
||||
set (WEBSOCKETPP_PLATFORM_TLS_LIBS ssl crypto)
|
||||
set (WEBSOCKETPP_BOOST_LIBS system thread)
|
||||
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x")
|
||||
if (NOT APPLE)
|
||||
@@ -133,7 +133,7 @@ if (BUILD_TESTS OR BUILD_EXAMPLES)
|
||||
else()
|
||||
set (WEBSOCKETPP_PLATFORM_LIBS pthread)
|
||||
endif()
|
||||
set (WEBSOCKETPP_PLATFORM_TSL_LIBS ssl crypto)
|
||||
set (WEBSOCKETPP_PLATFORM_TLS_LIBS ssl crypto)
|
||||
set (WEBSOCKETPP_BOOST_LIBS system thread)
|
||||
set (CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS} "-std=c++0x -stdlib=libc++") # todo: is libc++ really needed here?
|
||||
if (NOT APPLE)
|
||||
|
||||
@@ -32,9 +32,7 @@ PROJECT_NAME = "websocketpp"
|
||||
# This could be handy for archiving the generated documentation or
|
||||
# if some version control system is used.
|
||||
|
||||
|
||||
PROJECT_NUMBER = "0.5.1"
|
||||
|
||||
PROJECT_NUMBER = "0.6.0"
|
||||
|
||||
# Using the PROJECT_BRIEF tag one can provide an optional one line description
|
||||
# for a project that appears at the top of each page and should give viewer
|
||||
|
||||
+7
-2
@@ -125,6 +125,7 @@ elif env['CXX'].startswith('clang++'):
|
||||
|
||||
# Wpadded
|
||||
# Wsign-conversion
|
||||
#
|
||||
|
||||
platform_libs = []
|
||||
tls_libs = []
|
||||
@@ -240,8 +241,12 @@ testee_server = SConscript('#/examples/testee_server/SConscript',variant_dir = b
|
||||
# testee_client
|
||||
testee_client = SConscript('#/examples/testee_client/SConscript',variant_dir = builddir + 'testee_client',duplicate = 0)
|
||||
|
||||
# utility_client
|
||||
utility_client = SConscript('#/examples/utility_client/SConscript',variant_dir = builddir + 'utility_client',duplicate = 0)
|
||||
# scratch_client
|
||||
scratch_client = SConscript('#/examples/scratch_client/SConscript',variant_dir = builddir + 'scratch_client',duplicate = 0)
|
||||
|
||||
# scratch_server
|
||||
scratch_server = SConscript('#/examples/scratch_server/SConscript',variant_dir = builddir + 'scratch_server',duplicate = 0)
|
||||
|
||||
|
||||
# debug_client
|
||||
debug_client = SConscript('#/examples/debug_client/SConscript',variant_dir = builddir + 'debug_client',duplicate = 0)
|
||||
|
||||
+46
-1
@@ -1,10 +1,55 @@
|
||||
HEAD
|
||||
|
||||
0.6.0
|
||||
- MINOR BREAKING TRANSPORT POLICY CHANGE: Custom transport policies will now be
|
||||
required to include a new method `void set_uri(uri_ptr u)`. An implementation
|
||||
is not required. The stub transport policy includes an example stub method
|
||||
that can be added to any existing custom transport policy to fulfill this
|
||||
requirement. This does not affect anyone using the bundled transports or
|
||||
configs.
|
||||
- MINOR BREAKING SOCKET POLICY CHANGE: Custom asio transport socket policies
|
||||
will now be required to include a new method `void set_uri(uri_ptr u)`. Like
|
||||
with the transport layer, an implementation is not required. This does not
|
||||
affect anyone using the bundled socket policies.
|
||||
- MINOR BREAKING DEPENDENCY CHANGE: When using Boost versions greater than or
|
||||
equal to 1.49 in C++03 mode, `libboost-chrono` is needed now instead of
|
||||
`libboost-date_time`. Users with C++11 compilers or using Boost versions 1.48
|
||||
and earlier are not affected. Note: This change affects the bundled unit test
|
||||
suite.
|
||||
- Feature: WebSocket++ Asio transport policy can now be used with the standalone
|
||||
version of Asio (1.8.0+) when a C++11 compiler and standard library are
|
||||
present. This means that it is possible now to use WebSocket++'s Asio
|
||||
transport entirely without Boost. Thank you Robert Seiler for proof of concept
|
||||
code that was used as a guide for this implementation. Fixes #324
|
||||
- Feature: Adds a vectored/scatter-gather write handler to the iostream
|
||||
transport.
|
||||
- Feature: Adds the ability to defer sending an HTTP response until sometime
|
||||
after the `http_handler` is run. This allows processing of long running http
|
||||
handlers to defer their response until it is ready without blocking the
|
||||
network thread. references #425
|
||||
- Improvement: `echo_server_tls` has been update to demonstrate how to configure
|
||||
it for Mozilla's recommended intermediate and modern TLS security profiles.
|
||||
- Improvement: `endpoint::set_timer` now uses a steady clock provided by
|
||||
`boost::chrono` or `std::chrono` where available instead of the non-monotonic
|
||||
system clock. Thank you breyed for reporting. fixes #241
|
||||
- Improvement: Outgoing TLS connections to servers using the SNI extension to
|
||||
choose a certificate will now work. Thank you moozzyk for reporting.
|
||||
Fixes #400
|
||||
- Improvement: Removes an unnecessary mutex lock in `get_con_from_hdl`.
|
||||
- Cleanup: Asio transport policy has been refactored to remove many Boost
|
||||
dependencies. On C++03 compilers the `boost::noncopyable` dependency has been
|
||||
removed and the `boost::date_time` dependency has been replaced with the newer
|
||||
`boost::chrono` when possible. On C++11 compilers the `boost::aligned_storage`
|
||||
and `boost::date_time` dependencies are gone, replaced with equivalent C++11
|
||||
standard library features.
|
||||
- Bug: Fixes a potential dangling pointer and inconsistent error message
|
||||
handling in `websocketpp::exception`. #432 Thank you Tom Swirly for the fix.
|
||||
|
||||
0.5.1 - 2015-02-27
|
||||
- Bug: Fixes an issue where some frame data was counted against the max header
|
||||
size limit, resulting in connections that included a lot of frame data
|
||||
immediately after the opening handshake to fail.
|
||||
- Bug: Fix a type in the name of the set method for `max_http_body_size`. #406
|
||||
- Bug: Fix a typo in the name of the set method for `max_http_body_size`. #406
|
||||
Thank you jplatte for reporting.
|
||||
|
||||
0.5.0 - 2015-01-22
|
||||
|
||||
@@ -19,6 +19,13 @@ void on_message(server* s, websocketpp::connection_hdl hdl, message_ptr msg) {
|
||||
<< " and message: " << msg->get_payload()
|
||||
<< std::endl;
|
||||
|
||||
// check for a special command to instruct the server to stop listening so
|
||||
// it can be cleanly exited.
|
||||
if (msg->get_payload() == "stop-listening") {
|
||||
s->stop_listening();
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
s->send(hdl, msg->get_payload(), msg->get_opcode());
|
||||
} catch (const websocketpp::lib::error_code& e) {
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
-----BEGIN DH PARAMETERS-----
|
||||
MIIBCAKCAQEAqxMGKZB8YNV8WQnbJWwwwmifc+PfVRtd1FN5v5aQSsf6dpjX3Zlh
|
||||
N1NmgecsQyg4u2EWe4Umta10QzCgYaxf6QdTCg7iprLzFNw7IvWYbQ6du12NMGDr
|
||||
hmwA6KQKwbTgPL6mSlSlcK2wTP2FzxDTNffFu10cB/6Fj4kdQjPG0c1Koz/z7OOq
|
||||
BuDElJLClS8rjp3z1xvrc7gX95dFa2KaKgOAYDkpe8tfHRhHfJeIVS/whH9hzx6r
|
||||
OBg+E5K9JyvayrUoKgPeptRKCqo8A4YevtMLpRxMup0nMUgAIv6+BGTwPAFpwgl/
|
||||
8UIVcvjh1v95PwGDM/Q8yvIBJznBYk/e2wIBAg==
|
||||
-----END DH PARAMETERS-----
|
||||
@@ -27,24 +27,66 @@ void on_message(server* s, websocketpp::connection_hdl hdl, message_ptr msg) {
|
||||
}
|
||||
}
|
||||
|
||||
void on_http(server* s, websocketpp::connection_hdl hdl) {
|
||||
server::connection_ptr con = s->get_con_from_hdl(hdl);
|
||||
|
||||
con->set_body("Hello World!");
|
||||
con->set_status(websocketpp::http::status_code::ok);
|
||||
}
|
||||
|
||||
std::string get_password() {
|
||||
return "test";
|
||||
}
|
||||
|
||||
context_ptr on_tls_init(websocketpp::connection_hdl hdl) {
|
||||
// See https://wiki.mozilla.org/Security/Server_Side_TLS for more details about
|
||||
// the TLS modes. The code below demonstrates how to implement both the modern
|
||||
enum tls_mode {
|
||||
MOZILLA_INTERMEDIATE = 1,
|
||||
MOZILLA_MODERN = 2
|
||||
};
|
||||
|
||||
context_ptr on_tls_init(tls_mode mode, websocketpp::connection_hdl hdl) {
|
||||
std::cout << "on_tls_init called with hdl: " << hdl.lock().get() << std::endl;
|
||||
context_ptr ctx = websocketpp::lib::make_shared<boost::asio::ssl::context>(boost::asio::ssl::context::tlsv1);
|
||||
std::cout << "using TLS mode: " << (mode == MOZILLA_MODERN ? "Mozilla Modern" : "Mozilla Intermediate") << std::endl;
|
||||
context_ptr ctx = websocketpp::lib::make_shared<boost::asio::ssl::context>(boost::asio::ssl::context::sslv23);
|
||||
|
||||
try {
|
||||
ctx->set_options(boost::asio::ssl::context::default_workarounds |
|
||||
boost::asio::ssl::context::no_sslv2 |
|
||||
boost::asio::ssl::context::no_sslv3 |
|
||||
boost::asio::ssl::context::single_dh_use);
|
||||
if (mode == MOZILLA_MODERN) {
|
||||
// Modern disables TLSv1
|
||||
ctx->set_options(boost::asio::ssl::context::default_workarounds |
|
||||
boost::asio::ssl::context::no_sslv2 |
|
||||
boost::asio::ssl::context::no_sslv3 |
|
||||
boost::asio::ssl::context::no_tlsv1 |
|
||||
boost::asio::ssl::context::single_dh_use);
|
||||
} else {
|
||||
ctx->set_options(boost::asio::ssl::context::default_workarounds |
|
||||
boost::asio::ssl::context::no_sslv2 |
|
||||
boost::asio::ssl::context::no_sslv3 |
|
||||
boost::asio::ssl::context::single_dh_use);
|
||||
}
|
||||
ctx->set_password_callback(bind(&get_password));
|
||||
ctx->use_certificate_chain_file("server.pem");
|
||||
ctx->use_private_key_file("server.pem", boost::asio::ssl::context::pem);
|
||||
|
||||
// Example method of generating this file:
|
||||
// `openssl dhparam -out dh.pem 2048`
|
||||
// Mozilla Intermediate suggests 1024 as the minimum size to use
|
||||
// Mozilla Modern suggests 2048 as the minimum size to use.
|
||||
ctx->use_tmp_dh_file("dh.pem");
|
||||
|
||||
std::string ciphers;
|
||||
|
||||
if (mode == MOZILLA_MODERN) {
|
||||
ciphers = "ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!3DES:!MD5:!PSK";
|
||||
} else {
|
||||
ciphers = "ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:CAMELLIA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA";
|
||||
}
|
||||
|
||||
if (SSL_CTX_set_cipher_list(ctx->native_handle() , ciphers.c_str()) != 1) {
|
||||
std::cout << "Error setting cipher list" << std::endl;
|
||||
}
|
||||
} catch (std::exception& e) {
|
||||
std::cout << e.what() << std::endl;
|
||||
std::cout << "Exception: " << e.what() << std::endl;
|
||||
}
|
||||
return ctx;
|
||||
}
|
||||
@@ -58,8 +100,8 @@ int main() {
|
||||
|
||||
// Register our message handler
|
||||
echo_server.set_message_handler(bind(&on_message,&echo_server,::_1,::_2));
|
||||
echo_server.set_tls_init_handler(bind(&on_tls_init,::_1));
|
||||
|
||||
echo_server.set_http_handler(bind(&on_http,&echo_server,::_1));
|
||||
echo_server.set_tls_init_handler(bind(&on_tls_init,MOZILLA_INTERMEDIATE,::_1));
|
||||
|
||||
// Listen on port 9002
|
||||
echo_server.listen(9002);
|
||||
|
||||
@@ -1,58 +1,55 @@
|
||||
-----BEGIN RSA PRIVATE KEY-----
|
||||
Proc-Type: 4,ENCRYPTED
|
||||
DEK-Info: DES-EDE3-CBC,A0ED66EF872A48A9
|
||||
|
||||
gXuvKojXzApVhhPVNdRliiajbC4PtwQG5c8TA7JADLgwOR7o9t6KtXEr37bDRpvB
|
||||
9aO9P+SJaK5OOp3XKPGthOdqv+tvCRTlmzmC8GjPLBX389DWT2xoGu7JkGwDtdSm
|
||||
rnF49Rlp5bfjpACk5xKNiKeDo1CWfeEJzw9Kto0g+5eMaEdors64oPzjXs3geA2g
|
||||
TxCJSHv9qSX6++pCLKKCUTbyzidAxV/Zb0AAubt5V40QKqX4HhSwwstFnTaX3tlb
|
||||
3QOdY+y04VIkM6d7qN5W8M7NzRkMpZ1qBpQcUMpkhQcRzWP2wub5AAff9D2GntRd
|
||||
4Dz1vn3u41U3Okdr0CNj+iH7byCzuokoAhk6ZQEN6WB+GTpGgfBXdtUZrfpb0MKm
|
||||
UNYP5AF2AmUqJRXhViTDVtu/V2tHF3LGuNT+W2Dz+spFZEq0byEO0N858eR0dikc
|
||||
6jOASvNQbSwD0+mkgBC1gXKKU3ngj2gpJUwljeACdWFd8N2egrZfyI05CmX7vPNC
|
||||
NXbs7k2buWNdjP4/D8IM+HDVidWzQa/kG/qokXKqllem9Egg37lUucwnP3cX2/Hw
|
||||
U2mfaBWzeZtqc+GqRp08rYIql+Reai3sUYlQMnNk01prVY47UQb+dxuqjaxGV5Xx
|
||||
Xkx0s2mfQnNRjL4S7Hjhqelufi6GpkCQ2EGsPpA+6K1ztZ0ame9Q2BE1SXeM/6vU
|
||||
rxT5nRrCxueyXAyQSGcqMX9//gSeK8WWBqG/c1IAMVDa0NWrJeOJhSziE+ta3B0m
|
||||
bHAPBY6vh0iB3lLdRlbUOPbC6R1TpxMOs+6Vbs2+OTifFpvOVymEoZq/nroyg68P
|
||||
vn5uCKogwWA7o8EArf/UTlIwWJmH9bgILdZKld4wMel2HQg16RDzm+mEXAJi52a/
|
||||
FC+fgfphdxltmUJ+rqOyR4AHULjaTWUQqTIB6sdlzgmES1nXAiE71zX//KFqomar
|
||||
O60SPPk3C1bs0x5DsvmGJa8SIfDhyd+D7NPyqwEKqrZsaotYGklNkfqxa6pa8mrc
|
||||
ejxquW1PK4FvBk26+osu5a90Jih0PcQM7DUMMr2WHdTiMSXWAiK2ToYF8Itt25Qv
|
||||
Cd0CsSYw9CJkXNr1u1+mObheaY9QYOmztnSJLy4ZO2JsMhqNwuAueIcwmhXOREq7
|
||||
kzlnGMgJcuSeAS/OBNj8Zgx0c7QQ0kzc+YmnOCsqoMtPsu/CsXJ4iJiM3Tki/2jT
|
||||
bywrTiQwE6R3a/87GREOREX+WLicZBWX3k9/4tBL5XSe1p5wPpuIRQUDvAGNfNHP
|
||||
JN7kujDF4SehilF1qtvCygAwvxHFDj+EwhXKNDKJzoZZIM15rAk3k92n2j6nz1qH
|
||||
a3xOU05yydOlO6F6w51I1QoDddmkzCRNB0TeO3D6rekHsCK1aDWmC+qRcm2ZFtVz
|
||||
sY6fdZN2NEmMQokIh9Opi1f8CSYSizPESMzdu2SF0xVO9n/IGIkn1ksK04O2BZo0
|
||||
X3LBPHLfCRsQNY1eF17bj07fYU2oPZKs/XzJiwxkqK6LFvpeAVaYrtg9fqRO/UVe
|
||||
QhUIj3BL550ocEpa15xLehLrmwzYiW5zwGjSHQ4EgZluGLCwyKGTh4QswEJRA9Rt
|
||||
MIIEowIBAAKCAQEA77v5VbFaq+geVd/RCLXoKTWj/LgXGjiOXBpJZca3o5edi7N1
|
||||
Ej41/13jfZ4OxgFIRFAALd+fU4NsObXzskth3rJLmJjUtGajRIPqF2IUVjFMmybQ
|
||||
9dUDSqPzd/bG+ul0DP7DNuiBcLC8XNC3/kchPUzVq9gNDk56jXn87kMoIkVXBWQS
|
||||
Rwk0yCtELSfwxxRCrGKgQDfXnRdwmkPe42DmKtdGksXJlUhP1UVTAXaSw1Nz64LV
|
||||
9bJje/eoDsSe4OxifVVToE6ZxIW+r1jVgrcupeYXQrSHIztl2U/rx2JkGMN0eS+P
|
||||
qrsJmkmRBN1cpgmvSV7WoM3hj6Eq71z4Dfv6EwIDAQABAoIBAEXAL19bZsI1mv3p
|
||||
TOx34MB8tuXEuhQK+ICbtVdDZhLW/iOzZxCTwSo3qwTVg/7gSKJ3lFXEhprJ1idE
|
||||
ZU8u157vyUbw0JJceoxoxSdghgI9/cf2lz2vaHHDGgeBaYt/eSB+z1WeeGrNQUDQ
|
||||
CXiWQXmQbWq+Ra4v70BSieDY8UhmzCTRhvfZV80vaY/4SnHxJ9C8Nu8/An7U3pwq
|
||||
ccfTaWMp3Q5ztmEnExF6/b1SUsnI8rzFovw/4C50AU09N/Z6zZVFsXgJAT2Kd1Tx
|
||||
HfP1vUkWZ/TJ6kcmVIV9U3uMcedBD8Rb/3M0Qdp+eymQ+1oYQ3K3/a2RlUQIeXzf
|
||||
hRbE4wECgYEA/WyULrwBsvSMPqK0K9pZpv921Yl6d4bGnpxKze7ltc9o5/LsU35q
|
||||
8u29Es7cPyhyUDOsPW8v2CNjw54t+eFGsu59bBvXZNz5gB7hTUEyLntB24cO5PmN
|
||||
kVExcMDFC6NgPaauBtUhODievKJ2C8P7sRJDAVKE9KkavDddU7nSEjMCgYEA8ivG
|
||||
AqwNXYsiIFjAo4uj3kuBFt8LU/q4m6GXI+9qyxfiJjuF1dROx5qaQGiE85VaBFUu
|
||||
gpbnjZH7s+BBgoaQhrB4i6mztljdN1KKuAlnjhB+Fywg8m8N9lAi3wIaxnIEqDkU
|
||||
vFiIFPTBCk0U7IZ/OyCrKPQTE9ApWHfBwA/vWKECgYBQixrJg61SkBCms5Vpvprx
|
||||
zY2aLniC1o33yRqpOr09PG9OENH1c19QWCjYenBbjmJOhS2/1L+zBQRnHrXkDion
|
||||
Ik8wdeTORMDzbF0U7ZyiU0BKIjGkqn/I6LI68LlvinxC+9+hgkltkek5cLTt5lrv
|
||||
Gyu6ltx02e4KVdpOiuduKwKBgQC3U0PWigCkK8ttyUIrjG5Evcu/UKH2tPpDdpQ/
|
||||
8+JYVIAyiSTLtqjcmcDjuTvMWeeHGCTZXvtzRGvSw5VUBiIqlDTtJU6SX7s3QhkZ
|
||||
MKVf+kQ5roJShJeBOzDquWEjkPTNlEiKPErn8lCgR7HrS/XNAPIRUpOOkCp8ekwF
|
||||
5Qo/gQKBgAue3TeCeIzxh4PxSAk39Uaj+AaLvlYg8C+ucEodCNQZnJ7jOO0hHkfT
|
||||
NvZBes0VukCGlBLOGRQtC3kgtyrerscnDiZOhdnJrhPIdNPC0k/p/uAfh7+C5Sxm
|
||||
rCEL0S7kORdEjlIGd5j6ZEN/HZe8FyOYSjbFAoJSlAId9WMSxycQ
|
||||
-----END RSA PRIVATE KEY-----
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIE0DCCA7igAwIBAgIJAM5MuKJezXq0MA0GCSqGSIb3DQEBBQUAMIGgMQswCQYD
|
||||
VQQGEwJVUzERMA8GA1UECBMISWxsaW5vaXMxEDAOBgNVBAcTB0NoaWNhZ28xGDAW
|
||||
BgNVBAoTD1phcGhveWQgU3R1ZGlvczEUMBIGA1UECxMLV2ViU29ja2V0KysxFjAU
|
||||
BgNVBAMTDVBldGVyIFRob3Jzb24xJDAiBgkqhkiG9w0BCQEWFXdlYm1hc3RlckB6
|
||||
YXBob3lkLmNvbTAeFw0xMTExMTUyMTIwMDZaFw0xMjExMTQyMTIwMDZaMIGgMQsw
|
||||
CQYDVQQGEwJVUzERMA8GA1UECBMISWxsaW5vaXMxEDAOBgNVBAcTB0NoaWNhZ28x
|
||||
GDAWBgNVBAoTD1phcGhveWQgU3R1ZGlvczEUMBIGA1UECxMLV2ViU29ja2V0Kysx
|
||||
FjAUBgNVBAMTDVBldGVyIFRob3Jzb24xJDAiBgkqhkiG9w0BCQEWFXdlYm1hc3Rl
|
||||
ckB6YXBob3lkLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANR0
|
||||
tdwAnIB8I9qRZ7QbzEWY95RpM7GIn0u/9oH90PzdHiE0rXSkKT+yw3XUzH0iw5t0
|
||||
5dEwSC+srSP5Vm4cA6kXc94agVVaPW89tGcdP4fHptCruSrzQsDXELCPl5UUvMpA
|
||||
YUcGisdXYPN/EeOoqb9wKWxoW5mREsyyeWWS89fYN5qU/d0QpbSvEWghqLbL/ZS2
|
||||
hOlXT9LufOeA+vHiV1/T/h5xC7ecIH02YDQw1EnqxbPmkLPcWThztLS9FiufNDRM
|
||||
Rhcoaj2b9VDHvDwdbeA0T5v5qNdG34LaapYOelxzQMOtM0f9Dgqehodyxl2qm9mR
|
||||
lq432dlOEzDnVCPNHwECAwEAAaOCAQkwggEFMB0GA1UdDgQWBBTTPKfNMnKOykhv
|
||||
+vKS7vql5JsMyzCB1QYDVR0jBIHNMIHKgBTTPKfNMnKOykhv+vKS7vql5JsMy6GB
|
||||
pqSBozCBoDELMAkGA1UEBhMCVVMxETAPBgNVBAgTCElsbGlub2lzMRAwDgYDVQQH
|
||||
EwdDaGljYWdvMRgwFgYDVQQKEw9aYXBob3lkIFN0dWRpb3MxFDASBgNVBAsTC1dl
|
||||
YlNvY2tldCsrMRYwFAYDVQQDEw1QZXRlciBUaG9yc29uMSQwIgYJKoZIhvcNAQkB
|
||||
FhV3ZWJtYXN0ZXJAemFwaG95ZC5jb22CCQDOTLiiXs16tDAMBgNVHRMEBTADAQH/
|
||||
MA0GCSqGSIb3DQEBBQUAA4IBAQB+SH0s/hrv5VYqgX6SNLzxdSLvCVsUkCdTpxwY
|
||||
wOJ84XmYcXDMhKDtZqLtOtN6pfEwVusFlC9mkieuunztCnWNmsSG83RuljJPjFSi
|
||||
1d4Id4bKEQkQ4cfnjoHKivRrViWLnxuNnLzC6tpyGH/35kKWhhr6T58AXerFgVw3
|
||||
mHvLPTr1DuhdAZA0ZuvuseVAFFAjI3RetSySwHJE3ak8KswDVfLi6E3XxMVsIWTS
|
||||
/iFsC2WwoZQlljya2V/kRYIhu+uCdqJ01wunn2BvmURPSgr4GTBF0FQ9JGpNbXxM
|
||||
TAU7oQJgyFc5sCcuEgPTO0dWVQTvdZVgay4tkmduKDRkmJBF
|
||||
MIIEpzCCA4+gAwIBAgIJAMlCHvwnJ+F/MA0GCSqGSIb3DQEBCwUAMIGTMQswCQYD
|
||||
VQQGEwJVUzELMAkGA1UECBMCSUwxEDAOBgNVBAcTB0NoaWNhZ28xGTAXBgNVBAoT
|
||||
EFdlYlNvY2tldCsrIERlbW8xIjAgBgNVBAMTGXV0aWxpdGllcy53ZWJzb2NrZXRw
|
||||
cC5vcmcxJjAkBgkqhkiG9w0BCQEWF3dlYnNvY2tldHBwQHphcGhveWQuY29tMB4X
|
||||
DTE1MDQyNTE1NTk1M1oXDTE4MDMyODE1NTk1M1owgZMxCzAJBgNVBAYTAlVTMQsw
|
||||
CQYDVQQIEwJJTDEQMA4GA1UEBxMHQ2hpY2FnbzEZMBcGA1UEChMQV2ViU29ja2V0
|
||||
KysgRGVtbzEiMCAGA1UEAxMZdXRpbGl0aWVzLndlYnNvY2tldHBwLm9yZzEmMCQG
|
||||
CSqGSIb3DQEJARYXd2Vic29ja2V0cHBAemFwaG95ZC5jb20wggEiMA0GCSqGSIb3
|
||||
DQEBAQUAA4IBDwAwggEKAoIBAQDvu/lVsVqr6B5V39EItegpNaP8uBcaOI5cGkll
|
||||
xrejl52Ls3USPjX/XeN9ng7GAUhEUAAt359Tg2w5tfOyS2HeskuYmNS0ZqNEg+oX
|
||||
YhRWMUybJtD11QNKo/N39sb66XQM/sM26IFwsLxc0Lf+RyE9TNWr2A0OTnqNefzu
|
||||
QygiRVcFZBJHCTTIK0QtJ/DHFEKsYqBAN9edF3CaQ97jYOYq10aSxcmVSE/VRVMB
|
||||
dpLDU3PrgtX1smN796gOxJ7g7GJ9VVOgTpnEhb6vWNWCty6l5hdCtIcjO2XZT+vH
|
||||
YmQYw3R5L4+quwmaSZEE3VymCa9JXtagzeGPoSrvXPgN+/oTAgMBAAGjgfswgfgw
|
||||
HQYDVR0OBBYEFAWNBET93ZzSukXGkuGb93CfmUkDMIHIBgNVHSMEgcAwgb2AFAWN
|
||||
BET93ZzSukXGkuGb93CfmUkDoYGZpIGWMIGTMQswCQYDVQQGEwJVUzELMAkGA1UE
|
||||
CBMCSUwxEDAOBgNVBAcTB0NoaWNhZ28xGTAXBgNVBAoTEFdlYlNvY2tldCsrIERl
|
||||
bW8xIjAgBgNVBAMTGXV0aWxpdGllcy53ZWJzb2NrZXRwcC5vcmcxJjAkBgkqhkiG
|
||||
9w0BCQEWF3dlYnNvY2tldHBwQHphcGhveWQuY29tggkAyUIe/Ccn4X8wDAYDVR0T
|
||||
BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEA2DRQSDmo2Q5t8MEjp6jddRIFts5t
|
||||
BDBWPSwJ0qvmheFt53MuLds2hhvMn42WGrKtVJiLiDyOWuUZ41REJZb1uaissUuY
|
||||
r9pLuP5QLdibx7+/30iDEY0OGTgtSTfgwNx8bIApBSHoZEN3/HaikqplBng2+6u/
|
||||
kTe6UnRrBJ+8JOGl+duhCXNPeSyLa2NcrxE9XpWC/k1kC9MTUF+2NuqCtK3zO8ci
|
||||
p0mqARWDSrEBYISh3dAOgDFrcX6zj+0MK+iswu3ijEdItGAjxjlQ2t4XT1T/CDbc
|
||||
ysHg04TJw7v682+v124GrnrAPYUK34OK8kFVJ60SNYRUi7euOCdTM4Lwkw==
|
||||
-----END CERTIFICATE-----
|
||||
|
||||
|
||||
@@ -13,6 +13,8 @@ int main() {
|
||||
server print_server;
|
||||
|
||||
print_server.set_message_handler(&on_message);
|
||||
print_server.set_access_channels(websocketpp::log::alevel::all);
|
||||
print_server.set_error_channels(websocketpp::log::elevel::all);
|
||||
|
||||
print_server.init_asio();
|
||||
print_server.listen(9002);
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
## Scratch client example
|
||||
##
|
||||
|
||||
Import('env')
|
||||
Import('env_cpp11')
|
||||
Import('boostlibs')
|
||||
Import('platform_libs')
|
||||
Import('polyfill_libs')
|
||||
Import('tls_libs')
|
||||
|
||||
env = env.Clone ()
|
||||
env_cpp11 = env_cpp11.Clone ()
|
||||
|
||||
prgs = []
|
||||
|
||||
# if a C++11 environment is available build using that, otherwise use boost
|
||||
if env_cpp11.has_key('WSPP_CPP11_ENABLED'):
|
||||
ALL_LIBS = boostlibs(['system'],env_cpp11) + [platform_libs] + [polyfill_libs] + [tls_libs]
|
||||
prgs += env_cpp11.Program('scratch_client', ["scratch_client.cpp"], LIBS = ALL_LIBS)
|
||||
else:
|
||||
ALL_LIBS = boostlibs(['system','random'],env) + [platform_libs] + [polyfill_libs]
|
||||
prgs += env.Program('utility_client', ["utility_client.cpp"], LIBS = ALL_LIBS)
|
||||
|
||||
Return('prgs')
|
||||
@@ -0,0 +1,270 @@
|
||||
/*
|
||||
* Copyright (c) 2014, Peter Thorson. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the WebSocket++ Project nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
// **NOTE:** This file is a snapshot of the WebSocket++ utility client tutorial.
|
||||
// Additional related material can be found in the tutorials/utility_client
|
||||
// directory of the WebSocket++ repository.
|
||||
|
||||
#include <websocketpp/config/asio_no_tls_client.hpp>
|
||||
#include <websocketpp/client.hpp>
|
||||
|
||||
#include <websocketpp/common/thread.hpp>
|
||||
#include <websocketpp/common/memory.hpp>
|
||||
|
||||
#include <cstdlib>
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
|
||||
typedef websocketpp::client<websocketpp::config::asio_client> client;
|
||||
|
||||
class connection_metadata {
|
||||
public:
|
||||
typedef websocketpp::lib::shared_ptr<connection_metadata> ptr;
|
||||
|
||||
connection_metadata(int id, websocketpp::connection_hdl hdl, std::string uri)
|
||||
: m_id(id)
|
||||
, m_hdl(hdl)
|
||||
, m_status("Connecting")
|
||||
, m_uri(uri)
|
||||
, m_server("N/A")
|
||||
{}
|
||||
|
||||
void on_open(client * c, websocketpp::connection_hdl hdl) {
|
||||
m_status = "Open";
|
||||
|
||||
client::connection_ptr con = c->get_con_from_hdl(hdl);
|
||||
m_server = con->get_response_header("Server");
|
||||
}
|
||||
|
||||
void on_fail(client * c, websocketpp::connection_hdl hdl) {
|
||||
m_status = "Failed";
|
||||
|
||||
client::connection_ptr con = c->get_con_from_hdl(hdl);
|
||||
m_server = con->get_response_header("Server");
|
||||
m_error_reason = con->get_ec().message();
|
||||
}
|
||||
|
||||
void on_close(client * c, websocketpp::connection_hdl hdl) {
|
||||
m_status = "Closed";
|
||||
client::connection_ptr con = c->get_con_from_hdl(hdl);
|
||||
std::stringstream s;
|
||||
s << "close code: " << con->get_remote_close_code() << " ("
|
||||
<< websocketpp::close::status::get_string(con->get_remote_close_code())
|
||||
<< "), close reason: " << con->get_remote_close_reason();
|
||||
m_error_reason = s.str();
|
||||
}
|
||||
|
||||
websocketpp::connection_hdl get_hdl() const {
|
||||
return m_hdl;
|
||||
}
|
||||
|
||||
int get_id() const {
|
||||
return m_id;
|
||||
}
|
||||
|
||||
std::string get_status() const {
|
||||
return m_status;
|
||||
}
|
||||
|
||||
friend std::ostream & operator<< (std::ostream & out, connection_metadata const & data);
|
||||
private:
|
||||
int m_id;
|
||||
websocketpp::connection_hdl m_hdl;
|
||||
std::string m_status;
|
||||
std::string m_uri;
|
||||
std::string m_server;
|
||||
std::string m_error_reason;
|
||||
};
|
||||
|
||||
std::ostream & operator<< (std::ostream & out, connection_metadata const & data) {
|
||||
out << "> URI: " << data.m_uri << "\n"
|
||||
<< "> Status: " << data.m_status << "\n"
|
||||
<< "> Remote Server: " << (data.m_server.empty() ? "None Specified" : data.m_server) << "\n"
|
||||
<< "> Error/close reason: " << (data.m_error_reason.empty() ? "N/A" : data.m_error_reason);
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
class websocket_endpoint {
|
||||
public:
|
||||
websocket_endpoint () : m_next_id(0) {
|
||||
m_endpoint.clear_access_channels(websocketpp::log::alevel::all);
|
||||
m_endpoint.clear_error_channels(websocketpp::log::elevel::all);
|
||||
|
||||
m_endpoint.init_asio();
|
||||
m_endpoint.start_perpetual();
|
||||
|
||||
m_thread.reset(new websocketpp::lib::thread(&client::run, &m_endpoint));
|
||||
}
|
||||
|
||||
~websocket_endpoint() {
|
||||
m_endpoint.stop_perpetual();
|
||||
|
||||
for (con_list::const_iterator it = m_connection_list.begin(); it != m_connection_list.end(); ++it) {
|
||||
if (it->second->get_status() != "Open") {
|
||||
// Only close open connections
|
||||
continue;
|
||||
}
|
||||
|
||||
std::cout << "> Closing connection " << it->second->get_id() << std::endl;
|
||||
|
||||
websocketpp::lib::error_code ec;
|
||||
m_endpoint.close(it->second->get_hdl(), websocketpp::close::status::going_away, "", ec);
|
||||
if (ec) {
|
||||
std::cout << "> Error closing connection " << it->second->get_id() << ": "
|
||||
<< ec.message() << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
m_thread->join();
|
||||
}
|
||||
|
||||
int connect(std::string const & uri) {
|
||||
websocketpp::lib::error_code ec;
|
||||
|
||||
client::connection_ptr con = m_endpoint.get_connection(uri, ec);
|
||||
|
||||
if (ec) {
|
||||
std::cout << "> Connect initialization error: " << ec.message() << std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int new_id = m_next_id++;
|
||||
connection_metadata::ptr metadata_ptr(new connection_metadata(new_id, con->get_handle(), uri));
|
||||
m_connection_list[new_id] = metadata_ptr;
|
||||
|
||||
con->set_open_handler(websocketpp::lib::bind(
|
||||
&connection_metadata::on_open,
|
||||
metadata_ptr,
|
||||
&m_endpoint,
|
||||
websocketpp::lib::placeholders::_1
|
||||
));
|
||||
con->set_fail_handler(websocketpp::lib::bind(
|
||||
&connection_metadata::on_fail,
|
||||
metadata_ptr,
|
||||
&m_endpoint,
|
||||
websocketpp::lib::placeholders::_1
|
||||
));
|
||||
con->set_close_handler(websocketpp::lib::bind(
|
||||
&connection_metadata::on_close,
|
||||
metadata_ptr,
|
||||
&m_endpoint,
|
||||
websocketpp::lib::placeholders::_1
|
||||
));
|
||||
|
||||
m_endpoint.connect(con);
|
||||
|
||||
return new_id;
|
||||
}
|
||||
|
||||
void close(int id, websocketpp::close::status::value code, std::string reason) {
|
||||
websocketpp::lib::error_code ec;
|
||||
|
||||
con_list::iterator metadata_it = m_connection_list.find(id);
|
||||
if (metadata_it == m_connection_list.end()) {
|
||||
std::cout << "> No connection found with id " << id << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
m_endpoint.close(metadata_it->second->get_hdl(), code, reason, ec);
|
||||
if (ec) {
|
||||
std::cout << "> Error initiating close: " << ec.message() << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
connection_metadata::ptr get_metadata(int id) const {
|
||||
con_list::const_iterator metadata_it = m_connection_list.find(id);
|
||||
if (metadata_it == m_connection_list.end()) {
|
||||
return connection_metadata::ptr();
|
||||
} else {
|
||||
return metadata_it->second;
|
||||
}
|
||||
}
|
||||
private:
|
||||
typedef std::map<int,connection_metadata::ptr> con_list;
|
||||
|
||||
client m_endpoint;
|
||||
websocketpp::lib::shared_ptr<websocketpp::lib::thread> m_thread;
|
||||
|
||||
con_list m_connection_list;
|
||||
int m_next_id;
|
||||
};
|
||||
|
||||
int main() {
|
||||
bool done = false;
|
||||
std::string input;
|
||||
websocket_endpoint endpoint;
|
||||
|
||||
while (!done) {
|
||||
std::cout << "Enter Command: ";
|
||||
std::getline(std::cin, input);
|
||||
|
||||
if (input == "quit") {
|
||||
done = true;
|
||||
} else if (input == "help") {
|
||||
std::cout
|
||||
<< "\nCommand List:\n"
|
||||
<< "connect <ws uri>\n"
|
||||
<< "close <connection id> [<close code:default=1000>] [<close reason>]\n"
|
||||
<< "show <connection id>\n"
|
||||
<< "help: Display this help text\n"
|
||||
<< "quit: Exit the program\n"
|
||||
<< std::endl;
|
||||
} else if (input.substr(0,7) == "connect") {
|
||||
int id = endpoint.connect(input.substr(8));
|
||||
if (id != -1) {
|
||||
std::cout << "> Created connection with id " << id << std::endl;
|
||||
}
|
||||
} else if (input.substr(0,5) == "close") {
|
||||
std::stringstream ss(input);
|
||||
|
||||
std::string cmd;
|
||||
int id;
|
||||
int close_code = websocketpp::close::status::normal;
|
||||
std::string reason = "";
|
||||
|
||||
ss >> cmd >> id >> close_code;
|
||||
std::getline(ss,reason);
|
||||
|
||||
endpoint.close(id, close_code, reason);
|
||||
} else if (input.substr(0,4) == "show") {
|
||||
int id = atoi(input.substr(5).c_str());
|
||||
|
||||
connection_metadata::ptr metadata = endpoint.get_metadata(id);
|
||||
if (metadata) {
|
||||
std::cout << *metadata << std::endl;
|
||||
} else {
|
||||
std::cout << "> Unknown connection id " << id << std::endl;
|
||||
}
|
||||
} else {
|
||||
std::cout << "> Unrecognized Command" << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
## Scratch server example
|
||||
##
|
||||
|
||||
Import('env')
|
||||
Import('env_cpp11')
|
||||
Import('boostlibs')
|
||||
Import('platform_libs')
|
||||
Import('polyfill_libs')
|
||||
Import('tls_libs')
|
||||
|
||||
env = env.Clone ()
|
||||
env_cpp11 = env_cpp11.Clone ()
|
||||
|
||||
prgs = []
|
||||
|
||||
# if a C++11 environment is available build using that, otherwise use boost
|
||||
if env_cpp11.has_key('WSPP_CPP11_ENABLED'):
|
||||
ALL_LIBS = boostlibs(['system'],env_cpp11) + [platform_libs] + [polyfill_libs] + [tls_libs] + ['z']
|
||||
prgs += env_cpp11.Program('scratch_server', ["scratch_server.cpp"], LIBS = ALL_LIBS)
|
||||
else:
|
||||
ALL_LIBS = boostlibs(['system','regex','random'],env) + [platform_libs] + [polyfill_libs] + [tls_libs] + ['z']
|
||||
prgs += env.Program('scratch_server', ["scratch_server.cpp"], LIBS = ALL_LIBS)
|
||||
|
||||
Return('prgs')
|
||||
@@ -0,0 +1,106 @@
|
||||
/**
|
||||
* This example is presently used as a scratch space. It may or may not be broken
|
||||
* at any given time.
|
||||
*/
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include <websocketpp/config/debug_asio_no_tls.hpp>
|
||||
#include <websocketpp/server.hpp>
|
||||
|
||||
#include <websocketpp/extensions/permessage_deflate/enabled.hpp>
|
||||
|
||||
struct deflate_config : public websocketpp::config::debug_core {
|
||||
typedef deflate_config type;
|
||||
typedef debug_core base;
|
||||
|
||||
typedef base::concurrency_type concurrency_type;
|
||||
|
||||
typedef base::request_type request_type;
|
||||
typedef base::response_type response_type;
|
||||
|
||||
typedef base::message_type message_type;
|
||||
typedef base::con_msg_manager_type con_msg_manager_type;
|
||||
typedef base::endpoint_msg_manager_type endpoint_msg_manager_type;
|
||||
|
||||
typedef base::alog_type alog_type;
|
||||
typedef base::elog_type elog_type;
|
||||
|
||||
typedef base::rng_type rng_type;
|
||||
|
||||
struct transport_config : public base::transport_config {
|
||||
typedef type::concurrency_type concurrency_type;
|
||||
typedef type::alog_type alog_type;
|
||||
typedef type::elog_type elog_type;
|
||||
typedef type::request_type request_type;
|
||||
typedef type::response_type response_type;
|
||||
typedef websocketpp::transport::asio::basic_socket::endpoint
|
||||
socket_type;
|
||||
};
|
||||
|
||||
typedef websocketpp::transport::asio::endpoint<transport_config>
|
||||
transport_type;
|
||||
|
||||
/// permessage_compress extension
|
||||
struct permessage_deflate_config {};
|
||||
|
||||
typedef websocketpp::extensions::permessage_deflate::enabled
|
||||
<permessage_deflate_config> permessage_deflate_type;
|
||||
};
|
||||
|
||||
typedef websocketpp::server<deflate_config> server;
|
||||
|
||||
typedef server::message_ptr message_ptr;
|
||||
|
||||
// Define a callback to handle incoming messages
|
||||
void on_message(server* s, websocketpp::connection_hdl hdl, message_ptr msg) {
|
||||
/*std::cout << "on_message called with hdl: " << hdl.lock().get()
|
||||
<< " and message (" << msg->get_payload().size() << "): " << msg->get_payload()
|
||||
<< std::endl;
|
||||
*/
|
||||
try {
|
||||
s->send(hdl, msg->get_payload(), msg->get_opcode());
|
||||
} catch (const websocketpp::lib::error_code& e) {
|
||||
std::cout << "Echo failed because: " << e
|
||||
<< "(" << e.message() << ")" << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char * argv[]) {
|
||||
// Create a server endpoint
|
||||
server echo_server;
|
||||
|
||||
try {
|
||||
// Set logging settings
|
||||
if (argc > 1 && std::string(argv[1]) == "-d") {
|
||||
echo_server.set_access_channels(websocketpp::log::alevel::all);
|
||||
echo_server.set_error_channels(websocketpp::log::elevel::all);
|
||||
} else {
|
||||
echo_server.set_access_channels(websocketpp::log::alevel::none);
|
||||
echo_server.set_error_channels(websocketpp::log::elevel::none);
|
||||
}
|
||||
|
||||
// Initialize ASIO
|
||||
echo_server.init_asio();
|
||||
|
||||
// Register our message handler
|
||||
using websocketpp::lib::placeholders::_1;
|
||||
using websocketpp::lib::placeholders::_2;
|
||||
echo_server.set_message_handler(bind(&on_message,&echo_server,_1,_2));
|
||||
|
||||
// Listen on port 9002
|
||||
echo_server.listen(9002);
|
||||
|
||||
// Start the server accept loop
|
||||
echo_server.start_accept();
|
||||
|
||||
// Start the ASIO io_service run loop
|
||||
echo_server.run();
|
||||
} catch (const std::exception & e) {
|
||||
std::cout << e.what() << std::endl;
|
||||
} catch (websocketpp::lib::error_code e) {
|
||||
std::cout << e.message() << std::endl;
|
||||
} catch (...) {
|
||||
std::cout << "other exception" << std::endl;
|
||||
}
|
||||
}
|
||||
@@ -30,9 +30,9 @@ public:
|
||||
// Bind the handlers we are using
|
||||
using websocketpp::lib::placeholders::_1;
|
||||
using websocketpp::lib::bind;
|
||||
m_client.set_open_handler(bind(&telemetry_client::on_open,this,::_1));
|
||||
m_client.set_close_handler(bind(&telemetry_client::on_close,this,::_1));
|
||||
m_client.set_fail_handler(bind(&telemetry_client::on_fail,this,::_1));
|
||||
m_client.set_open_handler(bind(&telemetry_client::on_open,this,_1));
|
||||
m_client.set_close_handler(bind(&telemetry_client::on_close,this,_1));
|
||||
m_client.set_fail_handler(bind(&telemetry_client::on_fail,this,_1));
|
||||
}
|
||||
|
||||
// This method will block until the connection is complete
|
||||
|
||||
@@ -46,9 +46,9 @@ public:
|
||||
// Bind the handlers we are using
|
||||
using websocketpp::lib::placeholders::_1;
|
||||
using websocketpp::lib::bind;
|
||||
m_endpoint.set_open_handler(bind(&telemetry_server::on_open,this,::_1));
|
||||
m_endpoint.set_close_handler(bind(&telemetry_server::on_close,this,::_1));
|
||||
m_endpoint.set_http_handler(bind(&telemetry_server::on_http,this,::_1));
|
||||
m_endpoint.set_open_handler(bind(&telemetry_server::on_open,this,_1));
|
||||
m_endpoint.set_close_handler(bind(&telemetry_server::on_close,this,_1));
|
||||
m_endpoint.set_http_handler(bind(&telemetry_server::on_http,this,_1));
|
||||
}
|
||||
|
||||
void run(std::string docroot, uint16_t port) {
|
||||
|
||||
@@ -14,10 +14,10 @@ prgs = []
|
||||
|
||||
# if a C++11 environment is available build using that, otherwise use boost
|
||||
if env_cpp11.has_key('WSPP_CPP11_ENABLED'):
|
||||
ALL_LIBS = boostlibs(['system'],env_cpp11) + [platform_libs] + [polyfill_libs]
|
||||
ALL_LIBS = boostlibs(['system'],env_cpp11) + [platform_libs] + [polyfill_libs] + ['z']
|
||||
prgs += env_cpp11.Program('testee_client', ["testee_client.cpp"], LIBS = ALL_LIBS)
|
||||
else:
|
||||
ALL_LIBS = boostlibs(['system','random'],env) + [platform_libs] + [polyfill_libs]
|
||||
ALL_LIBS = boostlibs(['system','random'],env) + [platform_libs] + [polyfill_libs] + ['z']
|
||||
prgs += env.Program('testee_client', ["testee_client.cpp"], LIBS = ALL_LIBS)
|
||||
|
||||
Return('prgs')
|
||||
|
||||
@@ -1,10 +1,75 @@
|
||||
#include <websocketpp/config/asio_no_tls_client.hpp>
|
||||
/*
|
||||
* 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:
|
||||
* * 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <websocketpp/config/asio_no_tls_client.hpp>
|
||||
#include <websocketpp/client.hpp>
|
||||
#include <websocketpp/extensions/permessage_deflate/enabled.hpp>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
typedef websocketpp::client<websocketpp::config::asio_client> client;
|
||||
struct deflate_config : public websocketpp::config::asio_client {
|
||||
typedef deflate_config type;
|
||||
typedef asio_client base;
|
||||
|
||||
typedef base::concurrency_type concurrency_type;
|
||||
|
||||
typedef base::request_type request_type;
|
||||
typedef base::response_type response_type;
|
||||
|
||||
typedef base::message_type message_type;
|
||||
typedef base::con_msg_manager_type con_msg_manager_type;
|
||||
typedef base::endpoint_msg_manager_type endpoint_msg_manager_type;
|
||||
|
||||
typedef base::alog_type alog_type;
|
||||
typedef base::elog_type elog_type;
|
||||
|
||||
typedef base::rng_type rng_type;
|
||||
|
||||
struct transport_config : public base::transport_config {
|
||||
typedef type::concurrency_type concurrency_type;
|
||||
typedef type::alog_type alog_type;
|
||||
typedef type::elog_type elog_type;
|
||||
typedef type::request_type request_type;
|
||||
typedef type::response_type response_type;
|
||||
typedef websocketpp::transport::asio::basic_socket::endpoint
|
||||
socket_type;
|
||||
};
|
||||
|
||||
typedef websocketpp::transport::asio::endpoint<transport_config>
|
||||
transport_type;
|
||||
|
||||
/// permessage_compress extension
|
||||
struct permessage_deflate_config {};
|
||||
|
||||
typedef websocketpp::extensions::permessage_deflate::enabled
|
||||
<permessage_deflate_config> permessage_deflate_type;
|
||||
};
|
||||
|
||||
typedef websocketpp::client<deflate_config> client;
|
||||
|
||||
using websocketpp::lib::placeholders::_1;
|
||||
using websocketpp::lib::placeholders::_2;
|
||||
|
||||
@@ -14,10 +14,10 @@ prgs = []
|
||||
|
||||
# if a C++11 environment is available build using that, otherwise use boost
|
||||
if env_cpp11.has_key('WSPP_CPP11_ENABLED'):
|
||||
ALL_LIBS = boostlibs(['system'],env_cpp11) + [platform_libs] + [polyfill_libs]
|
||||
ALL_LIBS = boostlibs(['system'],env_cpp11) + [platform_libs] + [polyfill_libs] + ['z']
|
||||
prgs += env_cpp11.Program('testee_server', ["testee_server.cpp"], LIBS = ALL_LIBS)
|
||||
else:
|
||||
ALL_LIBS = boostlibs(['system'],env) + [platform_libs] + [polyfill_libs]
|
||||
ALL_LIBS = boostlibs(['system'],env) + [platform_libs] + [polyfill_libs] + ['z']
|
||||
prgs += env.Program('testee_server', ["testee_server.cpp"], LIBS = ALL_LIBS)
|
||||
|
||||
Return('prgs')
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2014, Peter Thorson. All rights reserved.
|
||||
* Copyright (c) 2015, Peter Thorson. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
@@ -27,6 +27,7 @@
|
||||
|
||||
#include <websocketpp/config/asio_no_tls.hpp>
|
||||
#include <websocketpp/server.hpp>
|
||||
#include <websocketpp/extensions/permessage_deflate/enabled.hpp>
|
||||
#include <iostream>
|
||||
|
||||
struct testee_config : public websocketpp::config::asio {
|
||||
@@ -64,6 +65,12 @@ struct testee_config : public websocketpp::config::asio {
|
||||
websocketpp::log::elevel::none;
|
||||
static const websocketpp::log::level alog_level =
|
||||
websocketpp::log::alevel::none;
|
||||
|
||||
/// permessage_compress extension
|
||||
struct permessage_deflate_config {};
|
||||
|
||||
typedef websocketpp::extensions::permessage_deflate::enabled
|
||||
<permessage_deflate_config> permessage_deflate_type;
|
||||
};
|
||||
|
||||
typedef websocketpp::server<testee_config> server;
|
||||
|
||||
@@ -1,11 +1,23 @@
|
||||
## Utility client example
|
||||
##
|
||||
|
||||
file (GLOB SOURCE_FILES *.cpp)
|
||||
file (GLOB HEADER_FILES *.hpp)
|
||||
Import('env')
|
||||
Import('env_cpp11')
|
||||
Import('boostlibs')
|
||||
Import('platform_libs')
|
||||
Import('polyfill_libs')
|
||||
|
||||
init_target (utility_client)
|
||||
env = env.Clone ()
|
||||
env_cpp11 = env_cpp11.Clone ()
|
||||
|
||||
build_executable (${TARGET_NAME} ${SOURCE_FILES} ${HEADER_FILES})
|
||||
prgs = []
|
||||
|
||||
link_boost ()
|
||||
final_target ()
|
||||
# if a C++11 environment is available build using that, otherwise use boost
|
||||
if env_cpp11.has_key('WSPP_CPP11_ENABLED'):
|
||||
ALL_LIBS = boostlibs(['system'],env_cpp11) + [platform_libs] + [polyfill_libs]
|
||||
prgs += env_cpp11.Program('utility_client', ["utility_client.cpp"], LIBS = ALL_LIBS)
|
||||
else:
|
||||
ALL_LIBS = boostlibs(['system','random'],env) + [platform_libs] + [polyfill_libs]
|
||||
prgs += env.Program('utility_client', ["utility_client.cpp"], LIBS = ALL_LIBS)
|
||||
|
||||
Return('prgs')
|
||||
@@ -1,23 +1,11 @@
|
||||
## Utility client example
|
||||
##
|
||||
|
||||
Import('env')
|
||||
Import('env_cpp11')
|
||||
Import('boostlibs')
|
||||
Import('platform_libs')
|
||||
Import('polyfill_libs')
|
||||
file (GLOB SOURCE_FILES *.cpp)
|
||||
file (GLOB HEADER_FILES *.hpp)
|
||||
|
||||
env = env.Clone ()
|
||||
env_cpp11 = env_cpp11.Clone ()
|
||||
init_target (utility_client)
|
||||
|
||||
prgs = []
|
||||
build_executable (${TARGET_NAME} ${SOURCE_FILES} ${HEADER_FILES})
|
||||
|
||||
# if a C++11 environment is available build using that, otherwise use boost
|
||||
if env_cpp11.has_key('WSPP_CPP11_ENABLED'):
|
||||
ALL_LIBS = boostlibs(['system'],env_cpp11) + [platform_libs] + [polyfill_libs]
|
||||
prgs += env_cpp11.Program('utility_client', ["utility_client.cpp"], LIBS = ALL_LIBS)
|
||||
else:
|
||||
ALL_LIBS = boostlibs(['system','random'],env) + [platform_libs] + [polyfill_libs]
|
||||
prgs += env.Program('utility_client', ["utility_client.cpp"], LIBS = ALL_LIBS)
|
||||
link_boost ()
|
||||
final_target ()
|
||||
|
||||
Return('prgs')
|
||||
|
||||
@@ -322,4 +322,4 @@ int main() {
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,12 @@
|
||||
WebSocket++ (0.5.1)
|
||||
WebSocket++ (0.6.0)
|
||||
==========================
|
||||
|
||||
WebSocket++ is a header only C++ library that implements RFC6455 The WebSocket
|
||||
Protocol. It allows integrating WebSocket client and server functionality into
|
||||
C++ programs. It uses interchangeable network transport modules including one
|
||||
based on C++ iostreams and one based on Boost Asio.
|
||||
based on raw char buffers, one based on C++ iostreams, and one based on Asio
|
||||
(either via Boost or standalone). End users can write additional transport
|
||||
policies to support other networking or event libraries as needed.
|
||||
|
||||
Major Features
|
||||
==============
|
||||
@@ -13,7 +15,7 @@ Major Features
|
||||
* Message/event based interface
|
||||
* Supports secure WebSockets (TLS), IPv6, and explicit proxies.
|
||||
* Flexible dependency management (C++11 Standard Library or Boost)
|
||||
* Interchangeable network transport modules (iostream and Boost Asio)
|
||||
* Interchangeable network transport modules (raw, iostream, Asio, or custom)
|
||||
* Portable/cross platform (Posix/Windows, 32/64bit, Intel/ARM/PPC)
|
||||
* Thread-safe
|
||||
|
||||
@@ -31,6 +33,8 @@ http://www.zaphoyd.com/websocketpp/manual/
|
||||
**GitHub Repository**
|
||||
https://github.com/zaphoyd/websocketpp/
|
||||
|
||||
GitHub pull requests should be submitted to the `develop` branch.
|
||||
|
||||
**Announcements Mailing List**
|
||||
http://groups.google.com/group/websocketpp-announcements/
|
||||
|
||||
|
||||
@@ -167,6 +167,15 @@ void http_func(server* s, websocketpp::connection_hdl hdl) {
|
||||
con->set_status(websocketpp::http::status_code::ok);
|
||||
}
|
||||
|
||||
void defer_http_func(server* s, bool * deferred, websocketpp::connection_hdl hdl) {
|
||||
*deferred = true;
|
||||
|
||||
server::connection_ptr con = s->get_con_from_hdl(hdl);
|
||||
|
||||
websocketpp::lib::error_code ec = con->defer_http_response();
|
||||
BOOST_CHECK_EQUAL(ec, websocketpp::lib::error_code());
|
||||
}
|
||||
|
||||
void check_on_fail(server* s, websocketpp::lib::error_code ec, bool & called,
|
||||
websocketpp::connection_hdl hdl)
|
||||
{
|
||||
@@ -223,6 +232,44 @@ BOOST_AUTO_TEST_CASE( http_request ) {
|
||||
BOOST_CHECK_EQUAL(run_server_test(s,input), output);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( deferred_http_request ) {
|
||||
std::string input = "GET /foo/bar HTTP/1.1\r\nHost: www.example.com\r\nOrigin: http://www.example.com\r\n\r\n";
|
||||
std::string output = "HTTP/1.1 200 OK\r\nContent-Length: 8\r\nServer: ";
|
||||
output+=websocketpp::user_agent;
|
||||
output+="\r\n\r\n/foo/bar";
|
||||
|
||||
server s;
|
||||
server::connection_ptr con;
|
||||
bool deferred = false;
|
||||
s.set_http_handler(bind(&defer_http_func,&s, &deferred,::_1));
|
||||
|
||||
s.clear_access_channels(websocketpp::log::alevel::all);
|
||||
s.clear_error_channels(websocketpp::log::elevel::all);
|
||||
|
||||
std::stringstream ostream;
|
||||
s.register_ostream(&ostream);
|
||||
|
||||
con = s.get_connection();
|
||||
con->start();
|
||||
|
||||
BOOST_CHECK(!deferred);
|
||||
BOOST_CHECK_EQUAL(ostream.str(), "");
|
||||
con->read_some(input.data(),input.size());
|
||||
BOOST_CHECK(deferred);
|
||||
BOOST_CHECK_EQUAL(ostream.str(), "");
|
||||
|
||||
con->set_body(con->get_resource());
|
||||
con->set_status(websocketpp::http::status_code::ok);
|
||||
|
||||
websocketpp::lib::error_code ec;
|
||||
s.send_http_response(con->get_handle(),ec);
|
||||
BOOST_CHECK_EQUAL(ec, websocketpp::lib::error_code());
|
||||
BOOST_CHECK_EQUAL(ostream.str(), output);
|
||||
con->send_http_response(ec);
|
||||
BOOST_CHECK_EQUAL(ec, make_error_code(websocketpp::error::invalid_state));
|
||||
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( request_no_server_header ) {
|
||||
std::string input = "GET / HTTP/1.1\r\nHost: www.example.com\r\nConnection: upgrade\r\nUpgrade: websocket\r\nSec-WebSocket-Version: 13\r\nSec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\nOrigin: http://www.example.com\r\n\r\n";
|
||||
std::string output = "HTTP/1.1 101 Switching Protocols\r\nConnection: upgrade\r\nSec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\nUpgrade: websocket\r\n\r\n";
|
||||
|
||||
@@ -57,6 +57,35 @@ BOOST_AUTO_TEST_CASE( initialize_server_asio_external ) {
|
||||
s.init_asio(&ios);
|
||||
}
|
||||
|
||||
#ifdef _WEBSOCKETPP_MOVE_SEMANTICS_
|
||||
BOOST_AUTO_TEST_CASE( move_construct_server_core ) {
|
||||
websocketpp::server<websocketpp::config::core> s1;
|
||||
|
||||
websocketpp::server<websocketpp::config::core> s2(std::move(s1));
|
||||
}
|
||||
|
||||
/*
|
||||
// temporary disable because library doesn't pass
|
||||
BOOST_AUTO_TEST_CASE( emplace ) {
|
||||
std::stringstream out1;
|
||||
std::stringstream out2;
|
||||
|
||||
std::vector<websocketpp::server<websocketpp::config::asio_tls>> v;
|
||||
|
||||
v.emplace_back();
|
||||
v.emplace_back();
|
||||
|
||||
v[0].get_alog().set_ostream(&out1);
|
||||
v[0].get_alog().set_ostream(&out2);
|
||||
|
||||
v[0].get_alog().write(websocketpp::log::alevel::app,"devel0");
|
||||
v[1].get_alog().write(websocketpp::log::alevel::app,"devel1");
|
||||
BOOST_CHECK( out1.str().size() > 0 );
|
||||
BOOST_CHECK( out2.str().size() > 0 );
|
||||
}*/
|
||||
|
||||
#endif // _WEBSOCKETPP_MOVE_SEMANTICS_
|
||||
|
||||
struct endpoint_extension {
|
||||
endpoint_extension() : extension_value(5) {}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2011, Peter Thorson. All rights reserved.
|
||||
* Copyright (c) 2013, 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:
|
||||
@@ -100,10 +100,10 @@ BOOST_AUTO_TEST_CASE( negotiation_invalid_attr ) {
|
||||
BOOST_CHECK_EQUAL( v.esp.second, "");
|
||||
}
|
||||
|
||||
// Negotiate s2c_no_context_takeover
|
||||
BOOST_AUTO_TEST_CASE( negotiate_s2c_no_context_takeover_invalid ) {
|
||||
// Negotiate server_no_context_takeover
|
||||
BOOST_AUTO_TEST_CASE( negotiate_server_no_context_takeover_invalid ) {
|
||||
ext_vars v;
|
||||
v.attr["s2c_no_context_takeover"] = "foo";
|
||||
v.attr["server_no_context_takeover"] = "foo";
|
||||
|
||||
v.esp = v.exts.negotiate(v.attr);
|
||||
BOOST_CHECK( !v.exts.is_enabled() );
|
||||
@@ -111,30 +111,30 @@ BOOST_AUTO_TEST_CASE( negotiate_s2c_no_context_takeover_invalid ) {
|
||||
BOOST_CHECK_EQUAL( v.esp.second, "");
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( negotiate_s2c_no_context_takeover ) {
|
||||
BOOST_AUTO_TEST_CASE( negotiate_server_no_context_takeover ) {
|
||||
ext_vars v;
|
||||
v.attr["s2c_no_context_takeover"] = "";
|
||||
v.attr["server_no_context_takeover"] = "";
|
||||
|
||||
v.esp = v.exts.negotiate(v.attr);
|
||||
BOOST_CHECK( v.exts.is_enabled() );
|
||||
BOOST_CHECK_EQUAL( v.esp.first, websocketpp::lib::error_code() );
|
||||
BOOST_CHECK_EQUAL( v.esp.second, "permessage-deflate; s2c_no_context_takeover");
|
||||
BOOST_CHECK_EQUAL( v.esp.second, "permessage-deflate; server_no_context_takeover");
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( negotiate_s2c_no_context_takeover_server_initiated ) {
|
||||
BOOST_AUTO_TEST_CASE( negotiate_server_no_context_takeover_server_initiated ) {
|
||||
ext_vars v;
|
||||
|
||||
v.exts.enable_s2c_no_context_takeover();
|
||||
v.exts.enable_server_no_context_takeover();
|
||||
v.esp = v.exts.negotiate(v.attr);
|
||||
BOOST_CHECK( v.exts.is_enabled() );
|
||||
BOOST_CHECK_EQUAL( v.esp.first, websocketpp::lib::error_code() );
|
||||
BOOST_CHECK_EQUAL( v.esp.second, "permessage-deflate; s2c_no_context_takeover");
|
||||
BOOST_CHECK_EQUAL( v.esp.second, "permessage-deflate; server_no_context_takeover");
|
||||
}
|
||||
|
||||
// Negotiate c2s_no_context_takeover
|
||||
BOOST_AUTO_TEST_CASE( negotiate_c2s_no_context_takeover_invalid ) {
|
||||
// Negotiate client_no_context_takeover
|
||||
BOOST_AUTO_TEST_CASE( negotiate_client_no_context_takeover_invalid ) {
|
||||
ext_vars v;
|
||||
v.attr["c2s_no_context_takeover"] = "foo";
|
||||
v.attr["client_no_context_takeover"] = "foo";
|
||||
|
||||
v.esp = v.exts.negotiate(v.attr);
|
||||
BOOST_CHECK( !v.exts.is_enabled() );
|
||||
@@ -142,29 +142,29 @@ BOOST_AUTO_TEST_CASE( negotiate_c2s_no_context_takeover_invalid ) {
|
||||
BOOST_CHECK_EQUAL( v.esp.second, "");
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( negotiate_c2s_no_context_takeover ) {
|
||||
BOOST_AUTO_TEST_CASE( negotiate_client_no_context_takeover ) {
|
||||
ext_vars v;
|
||||
v.attr["c2s_no_context_takeover"] = "";
|
||||
v.attr["client_no_context_takeover"] = "";
|
||||
|
||||
v.esp = v.exts.negotiate(v.attr);
|
||||
BOOST_CHECK( v.exts.is_enabled() );
|
||||
BOOST_CHECK_EQUAL( v.esp.first, websocketpp::lib::error_code() );
|
||||
BOOST_CHECK_EQUAL( v.esp.second, "permessage-deflate; c2s_no_context_takeover");
|
||||
BOOST_CHECK_EQUAL( v.esp.second, "permessage-deflate; client_no_context_takeover");
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( negotiate_c2s_no_context_takeover_server_initiated ) {
|
||||
BOOST_AUTO_TEST_CASE( negotiate_client_no_context_takeover_server_initiated ) {
|
||||
ext_vars v;
|
||||
|
||||
v.exts.enable_c2s_no_context_takeover();
|
||||
v.exts.enable_client_no_context_takeover();
|
||||
v.esp = v.exts.negotiate(v.attr);
|
||||
BOOST_CHECK( v.exts.is_enabled() );
|
||||
BOOST_CHECK_EQUAL( v.esp.first, websocketpp::lib::error_code() );
|
||||
BOOST_CHECK_EQUAL( v.esp.second, "permessage-deflate; c2s_no_context_takeover");
|
||||
BOOST_CHECK_EQUAL( v.esp.second, "permessage-deflate; client_no_context_takeover");
|
||||
}
|
||||
|
||||
|
||||
// Negotiate s2c_max_window_bits
|
||||
BOOST_AUTO_TEST_CASE( negotiate_s2c_max_window_bits_invalid ) {
|
||||
// Negotiate server_max_window_bits
|
||||
BOOST_AUTO_TEST_CASE( negotiate_server_max_window_bits_invalid ) {
|
||||
ext_vars v;
|
||||
|
||||
std::vector<std::string> values;
|
||||
@@ -175,7 +175,7 @@ BOOST_AUTO_TEST_CASE( negotiate_s2c_max_window_bits_invalid ) {
|
||||
|
||||
std::vector<std::string>::const_iterator it;
|
||||
for (it = values.begin(); it != values.end(); ++it) {
|
||||
v.attr["s2c_max_window_bits"] = *it;
|
||||
v.attr["server_max_window_bits"] = *it;
|
||||
|
||||
v.esp = v.exts.negotiate(v.attr);
|
||||
BOOST_CHECK( !v.exts.is_enabled() );
|
||||
@@ -184,16 +184,16 @@ BOOST_AUTO_TEST_CASE( negotiate_s2c_max_window_bits_invalid ) {
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( negotiate_s2c_max_window_bits_valid ) {
|
||||
BOOST_AUTO_TEST_CASE( negotiate_server_max_window_bits_valid ) {
|
||||
ext_vars v;
|
||||
v.attr["s2c_max_window_bits"] = "8";
|
||||
v.attr["server_max_window_bits"] = "8";
|
||||
|
||||
v.esp = v.exts.negotiate(v.attr);
|
||||
BOOST_CHECK( v.exts.is_enabled() );
|
||||
BOOST_CHECK_EQUAL( v.esp.first, websocketpp::lib::error_code() );
|
||||
BOOST_CHECK_EQUAL( v.esp.second, "permessage-deflate; s2c_max_window_bits=8");
|
||||
BOOST_CHECK_EQUAL( v.esp.second, "permessage-deflate; server_max_window_bits=8");
|
||||
|
||||
v.attr["s2c_max_window_bits"] = "15";
|
||||
v.attr["server_max_window_bits"] = "15";
|
||||
|
||||
v.esp = v.exts.negotiate(v.attr);
|
||||
BOOST_CHECK( v.exts.is_enabled() );
|
||||
@@ -201,21 +201,21 @@ BOOST_AUTO_TEST_CASE( negotiate_s2c_max_window_bits_valid ) {
|
||||
BOOST_CHECK_EQUAL( v.esp.second, "permessage-deflate");
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( invalid_set_s2c_max_window_bits ) {
|
||||
BOOST_AUTO_TEST_CASE( invalid_set_server_max_window_bits ) {
|
||||
ext_vars v;
|
||||
|
||||
v.ec = v.exts.set_s2c_max_window_bits(7,pmd_mode::decline);
|
||||
v.ec = v.exts.set_server_max_window_bits(7,pmd_mode::decline);
|
||||
BOOST_CHECK_EQUAL(v.ec,pmde::make_error_code(pmde::invalid_max_window_bits));
|
||||
|
||||
v.ec = v.exts.set_s2c_max_window_bits(16,pmd_mode::decline);
|
||||
v.ec = v.exts.set_server_max_window_bits(16,pmd_mode::decline);
|
||||
BOOST_CHECK_EQUAL(v.ec,pmde::make_error_code(pmde::invalid_max_window_bits));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( negotiate_s2c_max_window_bits_decline ) {
|
||||
BOOST_AUTO_TEST_CASE( negotiate_server_max_window_bits_decline ) {
|
||||
ext_vars v;
|
||||
v.attr["s2c_max_window_bits"] = "8";
|
||||
v.attr["server_max_window_bits"] = "8";
|
||||
|
||||
v.ec = v.exts.set_s2c_max_window_bits(15,pmd_mode::decline);
|
||||
v.ec = v.exts.set_server_max_window_bits(15,pmd_mode::decline);
|
||||
v.esp = v.exts.negotiate(v.attr);
|
||||
BOOST_CHECK( v.exts.is_enabled() );
|
||||
BOOST_CHECK_EQUAL( v.ec, websocketpp::lib::error_code() );
|
||||
@@ -223,44 +223,44 @@ BOOST_AUTO_TEST_CASE( negotiate_s2c_max_window_bits_decline ) {
|
||||
BOOST_CHECK_EQUAL( v.esp.second, "permessage-deflate");
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( negotiate_s2c_max_window_bits_accept ) {
|
||||
BOOST_AUTO_TEST_CASE( negotiate_server_max_window_bits_accept ) {
|
||||
ext_vars v;
|
||||
v.attr["s2c_max_window_bits"] = "8";
|
||||
v.attr["server_max_window_bits"] = "8";
|
||||
|
||||
v.ec = v.exts.set_s2c_max_window_bits(15,pmd_mode::accept);
|
||||
v.ec = v.exts.set_server_max_window_bits(15,pmd_mode::accept);
|
||||
v.esp = v.exts.negotiate(v.attr);
|
||||
BOOST_CHECK( v.exts.is_enabled() );
|
||||
BOOST_CHECK_EQUAL( v.ec, websocketpp::lib::error_code() );
|
||||
BOOST_CHECK_EQUAL( v.esp.first, websocketpp::lib::error_code() );
|
||||
BOOST_CHECK_EQUAL( v.esp.second, "permessage-deflate; s2c_max_window_bits=8");
|
||||
BOOST_CHECK_EQUAL( v.esp.second, "permessage-deflate; server_max_window_bits=8");
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( negotiate_s2c_max_window_bits_largest ) {
|
||||
BOOST_AUTO_TEST_CASE( negotiate_server_max_window_bits_largest ) {
|
||||
ext_vars v;
|
||||
v.attr["s2c_max_window_bits"] = "8";
|
||||
v.attr["server_max_window_bits"] = "8";
|
||||
|
||||
v.ec = v.exts.set_s2c_max_window_bits(15,pmd_mode::largest);
|
||||
v.ec = v.exts.set_server_max_window_bits(15,pmd_mode::largest);
|
||||
v.esp = v.exts.negotiate(v.attr);
|
||||
BOOST_CHECK( v.exts.is_enabled() );
|
||||
BOOST_CHECK_EQUAL( v.ec, websocketpp::lib::error_code() );
|
||||
BOOST_CHECK_EQUAL( v.esp.first, websocketpp::lib::error_code() );
|
||||
BOOST_CHECK_EQUAL( v.esp.second, "permessage-deflate; s2c_max_window_bits=8");
|
||||
BOOST_CHECK_EQUAL( v.esp.second, "permessage-deflate; server_max_window_bits=8");
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( negotiate_s2c_max_window_bits_smallest ) {
|
||||
BOOST_AUTO_TEST_CASE( negotiate_server_max_window_bits_smallest ) {
|
||||
ext_vars v;
|
||||
v.attr["s2c_max_window_bits"] = "8";
|
||||
v.attr["server_max_window_bits"] = "8";
|
||||
|
||||
v.ec = v.exts.set_s2c_max_window_bits(15,pmd_mode::smallest);
|
||||
v.ec = v.exts.set_server_max_window_bits(15,pmd_mode::smallest);
|
||||
v.esp = v.exts.negotiate(v.attr);
|
||||
BOOST_CHECK( v.exts.is_enabled() );
|
||||
BOOST_CHECK_EQUAL( v.ec, websocketpp::lib::error_code() );
|
||||
BOOST_CHECK_EQUAL( v.esp.first, websocketpp::lib::error_code() );
|
||||
BOOST_CHECK_EQUAL( v.esp.second, "permessage-deflate; s2c_max_window_bits=8");
|
||||
BOOST_CHECK_EQUAL( v.esp.second, "permessage-deflate; server_max_window_bits=8");
|
||||
}
|
||||
|
||||
// Negotiate s2c_max_window_bits
|
||||
BOOST_AUTO_TEST_CASE( negotiate_c2s_max_window_bits_invalid ) {
|
||||
// Negotiate server_max_window_bits
|
||||
BOOST_AUTO_TEST_CASE( negotiate_client_max_window_bits_invalid ) {
|
||||
ext_vars v;
|
||||
|
||||
std::vector<std::string> values;
|
||||
@@ -270,7 +270,7 @@ BOOST_AUTO_TEST_CASE( negotiate_c2s_max_window_bits_invalid ) {
|
||||
|
||||
std::vector<std::string>::const_iterator it;
|
||||
for (it = values.begin(); it != values.end(); ++it) {
|
||||
v.attr["c2s_max_window_bits"] = *it;
|
||||
v.attr["client_max_window_bits"] = *it;
|
||||
|
||||
v.esp = v.exts.negotiate(v.attr);
|
||||
BOOST_CHECK( !v.exts.is_enabled() );
|
||||
@@ -279,43 +279,43 @@ BOOST_AUTO_TEST_CASE( negotiate_c2s_max_window_bits_invalid ) {
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( negotiate_c2s_max_window_bits_valid ) {
|
||||
BOOST_AUTO_TEST_CASE( negotiate_client_max_window_bits_valid ) {
|
||||
ext_vars v;
|
||||
|
||||
v.attr["c2s_max_window_bits"] = "";
|
||||
v.attr["client_max_window_bits"] = "";
|
||||
v.esp = v.exts.negotiate(v.attr);
|
||||
BOOST_CHECK( v.exts.is_enabled() );
|
||||
BOOST_CHECK_EQUAL( v.esp.first, websocketpp::lib::error_code() );
|
||||
BOOST_CHECK_EQUAL( v.esp.second, "permessage-deflate");
|
||||
|
||||
v.attr["c2s_max_window_bits"] = "8";
|
||||
v.attr["client_max_window_bits"] = "8";
|
||||
v.esp = v.exts.negotiate(v.attr);
|
||||
BOOST_CHECK( v.exts.is_enabled() );
|
||||
BOOST_CHECK_EQUAL( v.esp.first, websocketpp::lib::error_code() );
|
||||
BOOST_CHECK_EQUAL( v.esp.second, "permessage-deflate; c2s_max_window_bits=8");
|
||||
BOOST_CHECK_EQUAL( v.esp.second, "permessage-deflate; client_max_window_bits=8");
|
||||
|
||||
v.attr["c2s_max_window_bits"] = "15";
|
||||
v.attr["client_max_window_bits"] = "15";
|
||||
v.esp = v.exts.negotiate(v.attr);
|
||||
BOOST_CHECK( v.exts.is_enabled() );
|
||||
BOOST_CHECK_EQUAL( v.esp.first, websocketpp::lib::error_code() );
|
||||
BOOST_CHECK_EQUAL( v.esp.second, "permessage-deflate");
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( invalid_set_c2s_max_window_bits ) {
|
||||
BOOST_AUTO_TEST_CASE( invalid_set_client_max_window_bits ) {
|
||||
ext_vars v;
|
||||
|
||||
v.ec = v.exts.set_c2s_max_window_bits(7,pmd_mode::decline);
|
||||
v.ec = v.exts.set_client_max_window_bits(7,pmd_mode::decline);
|
||||
BOOST_CHECK_EQUAL(v.ec,pmde::make_error_code(pmde::invalid_max_window_bits));
|
||||
|
||||
v.ec = v.exts.set_c2s_max_window_bits(16,pmd_mode::decline);
|
||||
v.ec = v.exts.set_client_max_window_bits(16,pmd_mode::decline);
|
||||
BOOST_CHECK_EQUAL(v.ec,pmde::make_error_code(pmde::invalid_max_window_bits));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( negotiate_c2s_max_window_bits_decline ) {
|
||||
BOOST_AUTO_TEST_CASE( negotiate_client_max_window_bits_decline ) {
|
||||
ext_vars v;
|
||||
v.attr["c2s_max_window_bits"] = "8";
|
||||
v.attr["client_max_window_bits"] = "8";
|
||||
|
||||
v.ec = v.exts.set_c2s_max_window_bits(8,pmd_mode::decline);
|
||||
v.ec = v.exts.set_client_max_window_bits(8,pmd_mode::decline);
|
||||
v.esp = v.exts.negotiate(v.attr);
|
||||
BOOST_CHECK( v.exts.is_enabled() );
|
||||
BOOST_CHECK_EQUAL( v.ec, websocketpp::lib::error_code() );
|
||||
@@ -323,40 +323,40 @@ BOOST_AUTO_TEST_CASE( negotiate_c2s_max_window_bits_decline ) {
|
||||
BOOST_CHECK_EQUAL( v.esp.second, "permessage-deflate");
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( negotiate_c2s_max_window_bits_accept ) {
|
||||
BOOST_AUTO_TEST_CASE( negotiate_client_max_window_bits_accept ) {
|
||||
ext_vars v;
|
||||
v.attr["c2s_max_window_bits"] = "8";
|
||||
v.attr["client_max_window_bits"] = "8";
|
||||
|
||||
v.ec = v.exts.set_c2s_max_window_bits(15,pmd_mode::accept);
|
||||
v.ec = v.exts.set_client_max_window_bits(15,pmd_mode::accept);
|
||||
v.esp = v.exts.negotiate(v.attr);
|
||||
BOOST_CHECK( v.exts.is_enabled() );
|
||||
BOOST_CHECK_EQUAL( v.ec, websocketpp::lib::error_code() );
|
||||
BOOST_CHECK_EQUAL( v.esp.first, websocketpp::lib::error_code() );
|
||||
BOOST_CHECK_EQUAL( v.esp.second, "permessage-deflate; c2s_max_window_bits=8");
|
||||
BOOST_CHECK_EQUAL( v.esp.second, "permessage-deflate; client_max_window_bits=8");
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( negotiate_c2s_max_window_bits_largest ) {
|
||||
BOOST_AUTO_TEST_CASE( negotiate_client_max_window_bits_largest ) {
|
||||
ext_vars v;
|
||||
v.attr["c2s_max_window_bits"] = "8";
|
||||
v.attr["client_max_window_bits"] = "8";
|
||||
|
||||
v.ec = v.exts.set_c2s_max_window_bits(15,pmd_mode::largest);
|
||||
v.ec = v.exts.set_client_max_window_bits(15,pmd_mode::largest);
|
||||
v.esp = v.exts.negotiate(v.attr);
|
||||
BOOST_CHECK( v.exts.is_enabled() );
|
||||
BOOST_CHECK_EQUAL( v.ec, websocketpp::lib::error_code() );
|
||||
BOOST_CHECK_EQUAL( v.esp.first, websocketpp::lib::error_code() );
|
||||
BOOST_CHECK_EQUAL( v.esp.second, "permessage-deflate; c2s_max_window_bits=8");
|
||||
BOOST_CHECK_EQUAL( v.esp.second, "permessage-deflate; client_max_window_bits=8");
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( negotiate_c2s_max_window_bits_smallest ) {
|
||||
BOOST_AUTO_TEST_CASE( negotiate_client_max_window_bits_smallest ) {
|
||||
ext_vars v;
|
||||
v.attr["c2s_max_window_bits"] = "8";
|
||||
v.attr["client_max_window_bits"] = "8";
|
||||
|
||||
v.ec = v.exts.set_c2s_max_window_bits(15,pmd_mode::smallest);
|
||||
v.ec = v.exts.set_client_max_window_bits(15,pmd_mode::smallest);
|
||||
v.esp = v.exts.negotiate(v.attr);
|
||||
BOOST_CHECK( v.exts.is_enabled() );
|
||||
BOOST_CHECK_EQUAL( v.ec, websocketpp::lib::error_code() );
|
||||
BOOST_CHECK_EQUAL( v.esp.first, websocketpp::lib::error_code() );
|
||||
BOOST_CHECK_EQUAL( v.esp.second, "permessage-deflate; c2s_max_window_bits=8");
|
||||
BOOST_CHECK_EQUAL( v.esp.second, "permessage-deflate; client_max_window_bits=8");
|
||||
}
|
||||
|
||||
|
||||
@@ -364,180 +364,286 @@ BOOST_AUTO_TEST_CASE( negotiate_c2s_max_window_bits_smallest ) {
|
||||
BOOST_AUTO_TEST_CASE( negotiate_two_client_initiated1 ) {
|
||||
ext_vars v;
|
||||
|
||||
v.attr["s2c_no_context_takeover"] = "";
|
||||
v.attr["c2s_no_context_takeover"] = "";
|
||||
v.attr["server_no_context_takeover"] = "";
|
||||
v.attr["client_no_context_takeover"] = "";
|
||||
|
||||
v.esp = v.exts.negotiate(v.attr);
|
||||
BOOST_CHECK( v.exts.is_enabled() );
|
||||
BOOST_CHECK_EQUAL( v.esp.first, websocketpp::lib::error_code() );
|
||||
BOOST_CHECK_EQUAL( v.esp.second, "permessage-deflate; s2c_no_context_takeover; c2s_no_context_takeover");
|
||||
BOOST_CHECK_EQUAL( v.esp.second, "permessage-deflate; server_no_context_takeover; client_no_context_takeover");
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( negotiate_two_client_initiated2 ) {
|
||||
ext_vars v;
|
||||
|
||||
v.attr["s2c_no_context_takeover"] = "";
|
||||
v.attr["s2c_max_window_bits"] = "10";
|
||||
v.attr["server_no_context_takeover"] = "";
|
||||
v.attr["server_max_window_bits"] = "10";
|
||||
|
||||
v.esp = v.exts.negotiate(v.attr);
|
||||
BOOST_CHECK( v.exts.is_enabled() );
|
||||
BOOST_CHECK_EQUAL( v.esp.first, websocketpp::lib::error_code() );
|
||||
BOOST_CHECK_EQUAL( v.esp.second, "permessage-deflate; s2c_no_context_takeover; s2c_max_window_bits=10");
|
||||
BOOST_CHECK_EQUAL( v.esp.second, "permessage-deflate; server_no_context_takeover; server_max_window_bits=10");
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( negotiate_two_client_initiated3 ) {
|
||||
ext_vars v;
|
||||
|
||||
v.attr["s2c_no_context_takeover"] = "";
|
||||
v.attr["c2s_max_window_bits"] = "10";
|
||||
v.attr["server_no_context_takeover"] = "";
|
||||
v.attr["client_max_window_bits"] = "10";
|
||||
|
||||
v.esp = v.exts.negotiate(v.attr);
|
||||
BOOST_CHECK( v.exts.is_enabled() );
|
||||
BOOST_CHECK_EQUAL( v.esp.first, websocketpp::lib::error_code() );
|
||||
BOOST_CHECK_EQUAL( v.esp.second, "permessage-deflate; s2c_no_context_takeover; c2s_max_window_bits=10");
|
||||
BOOST_CHECK_EQUAL( v.esp.second, "permessage-deflate; server_no_context_takeover; client_max_window_bits=10");
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( negotiate_two_client_initiated4 ) {
|
||||
ext_vars v;
|
||||
|
||||
v.attr["c2s_no_context_takeover"] = "";
|
||||
v.attr["s2c_max_window_bits"] = "10";
|
||||
v.attr["client_no_context_takeover"] = "";
|
||||
v.attr["server_max_window_bits"] = "10";
|
||||
|
||||
v.esp = v.exts.negotiate(v.attr);
|
||||
BOOST_CHECK( v.exts.is_enabled() );
|
||||
BOOST_CHECK_EQUAL( v.esp.first, websocketpp::lib::error_code() );
|
||||
BOOST_CHECK_EQUAL( v.esp.second, "permessage-deflate; c2s_no_context_takeover; s2c_max_window_bits=10");
|
||||
BOOST_CHECK_EQUAL( v.esp.second, "permessage-deflate; client_no_context_takeover; server_max_window_bits=10");
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( negotiate_two_client_initiated5 ) {
|
||||
ext_vars v;
|
||||
|
||||
v.attr["c2s_no_context_takeover"] = "";
|
||||
v.attr["c2s_max_window_bits"] = "10";
|
||||
v.attr["client_no_context_takeover"] = "";
|
||||
v.attr["client_max_window_bits"] = "10";
|
||||
|
||||
v.esp = v.exts.negotiate(v.attr);
|
||||
BOOST_CHECK( v.exts.is_enabled() );
|
||||
BOOST_CHECK_EQUAL( v.esp.first, websocketpp::lib::error_code() );
|
||||
BOOST_CHECK_EQUAL( v.esp.second, "permessage-deflate; c2s_no_context_takeover; c2s_max_window_bits=10");
|
||||
BOOST_CHECK_EQUAL( v.esp.second, "permessage-deflate; client_no_context_takeover; client_max_window_bits=10");
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( negotiate_two_client_initiated6 ) {
|
||||
ext_vars v;
|
||||
|
||||
v.attr["s2c_max_window_bits"] = "10";
|
||||
v.attr["c2s_max_window_bits"] = "10";
|
||||
v.attr["server_max_window_bits"] = "10";
|
||||
v.attr["client_max_window_bits"] = "10";
|
||||
|
||||
v.esp = v.exts.negotiate(v.attr);
|
||||
BOOST_CHECK( v.exts.is_enabled() );
|
||||
BOOST_CHECK_EQUAL( v.esp.first, websocketpp::lib::error_code() );
|
||||
BOOST_CHECK_EQUAL( v.esp.second, "permessage-deflate; s2c_max_window_bits=10; c2s_max_window_bits=10");
|
||||
BOOST_CHECK_EQUAL( v.esp.second, "permessage-deflate; server_max_window_bits=10; client_max_window_bits=10");
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( negotiate_three_client_initiated1 ) {
|
||||
ext_vars v;
|
||||
|
||||
v.attr["s2c_no_context_takeover"] = "";
|
||||
v.attr["c2s_no_context_takeover"] = "";
|
||||
v.attr["s2c_max_window_bits"] = "10";
|
||||
v.attr["server_no_context_takeover"] = "";
|
||||
v.attr["client_no_context_takeover"] = "";
|
||||
v.attr["server_max_window_bits"] = "10";
|
||||
|
||||
v.esp = v.exts.negotiate(v.attr);
|
||||
BOOST_CHECK( v.exts.is_enabled() );
|
||||
BOOST_CHECK_EQUAL( v.esp.first, websocketpp::lib::error_code() );
|
||||
BOOST_CHECK_EQUAL( v.esp.second, "permessage-deflate; s2c_no_context_takeover; c2s_no_context_takeover; s2c_max_window_bits=10");
|
||||
BOOST_CHECK_EQUAL( v.esp.second, "permessage-deflate; server_no_context_takeover; client_no_context_takeover; server_max_window_bits=10");
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( negotiate_three_client_initiated2 ) {
|
||||
ext_vars v;
|
||||
|
||||
v.attr["s2c_no_context_takeover"] = "";
|
||||
v.attr["c2s_no_context_takeover"] = "";
|
||||
v.attr["c2s_max_window_bits"] = "10";
|
||||
v.attr["server_no_context_takeover"] = "";
|
||||
v.attr["client_no_context_takeover"] = "";
|
||||
v.attr["client_max_window_bits"] = "10";
|
||||
|
||||
v.esp = v.exts.negotiate(v.attr);
|
||||
BOOST_CHECK( v.exts.is_enabled() );
|
||||
BOOST_CHECK_EQUAL( v.esp.first, websocketpp::lib::error_code() );
|
||||
BOOST_CHECK_EQUAL( v.esp.second, "permessage-deflate; s2c_no_context_takeover; c2s_no_context_takeover; c2s_max_window_bits=10");
|
||||
BOOST_CHECK_EQUAL( v.esp.second, "permessage-deflate; server_no_context_takeover; client_no_context_takeover; client_max_window_bits=10");
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( negotiate_three_client_initiated3 ) {
|
||||
ext_vars v;
|
||||
|
||||
v.attr["s2c_no_context_takeover"] = "";
|
||||
v.attr["s2c_max_window_bits"] = "10";
|
||||
v.attr["c2s_max_window_bits"] = "10";
|
||||
v.attr["server_no_context_takeover"] = "";
|
||||
v.attr["server_max_window_bits"] = "10";
|
||||
v.attr["client_max_window_bits"] = "10";
|
||||
|
||||
v.esp = v.exts.negotiate(v.attr);
|
||||
BOOST_CHECK( v.exts.is_enabled() );
|
||||
BOOST_CHECK_EQUAL( v.esp.first, websocketpp::lib::error_code() );
|
||||
BOOST_CHECK_EQUAL( v.esp.second, "permessage-deflate; s2c_no_context_takeover; s2c_max_window_bits=10; c2s_max_window_bits=10");
|
||||
BOOST_CHECK_EQUAL( v.esp.second, "permessage-deflate; server_no_context_takeover; server_max_window_bits=10; client_max_window_bits=10");
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( negotiate_three_client_initiated4 ) {
|
||||
ext_vars v;
|
||||
|
||||
v.attr["c2s_no_context_takeover"] = "";
|
||||
v.attr["s2c_max_window_bits"] = "10";
|
||||
v.attr["c2s_max_window_bits"] = "10";
|
||||
v.attr["client_no_context_takeover"] = "";
|
||||
v.attr["server_max_window_bits"] = "10";
|
||||
v.attr["client_max_window_bits"] = "10";
|
||||
|
||||
v.esp = v.exts.negotiate(v.attr);
|
||||
BOOST_CHECK( v.exts.is_enabled() );
|
||||
BOOST_CHECK_EQUAL( v.esp.first, websocketpp::lib::error_code() );
|
||||
BOOST_CHECK_EQUAL( v.esp.second, "permessage-deflate; c2s_no_context_takeover; s2c_max_window_bits=10; c2s_max_window_bits=10");
|
||||
BOOST_CHECK_EQUAL( v.esp.second, "permessage-deflate; client_no_context_takeover; server_max_window_bits=10; client_max_window_bits=10");
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( negotiate_four_client_initiated ) {
|
||||
ext_vars v;
|
||||
|
||||
v.attr["s2c_no_context_takeover"] = "";
|
||||
v.attr["c2s_no_context_takeover"] = "";
|
||||
v.attr["s2c_max_window_bits"] = "10";
|
||||
v.attr["c2s_max_window_bits"] = "10";
|
||||
v.attr["server_no_context_takeover"] = "";
|
||||
v.attr["client_no_context_takeover"] = "";
|
||||
v.attr["server_max_window_bits"] = "10";
|
||||
v.attr["client_max_window_bits"] = "10";
|
||||
|
||||
v.esp = v.exts.negotiate(v.attr);
|
||||
BOOST_CHECK( v.exts.is_enabled() );
|
||||
BOOST_CHECK_EQUAL( v.esp.first, websocketpp::lib::error_code() );
|
||||
BOOST_CHECK_EQUAL( v.esp.second, "permessage-deflate; s2c_no_context_takeover; c2s_no_context_takeover; s2c_max_window_bits=10; c2s_max_window_bits=10");
|
||||
BOOST_CHECK_EQUAL( v.esp.second, "permessage-deflate; server_no_context_takeover; client_no_context_takeover; server_max_window_bits=10; client_max_window_bits=10");
|
||||
}
|
||||
|
||||
// Compression
|
||||
/*
|
||||
BOOST_AUTO_TEST_CASE( compress_data ) {
|
||||
ext_vars v;
|
||||
|
||||
std::string in = "Hello";
|
||||
std::string out;
|
||||
std::string in2;
|
||||
std::string out2;
|
||||
std::string compress_in = "Hello";
|
||||
std::string compress_out;
|
||||
std::string decompress_out;
|
||||
|
||||
v.exts.init();
|
||||
v.exts.init(true);
|
||||
|
||||
v.ec = v.exts.compress(in,out);
|
||||
|
||||
std::cout << "in : " << websocketpp::utility::to_hex(in) << std::endl;
|
||||
v.ec = v.exts.compress(compress_in,compress_out);
|
||||
BOOST_CHECK_EQUAL( v.ec, websocketpp::lib::error_code() );
|
||||
std::cout << "out: " << websocketpp::utility::to_hex(out) << std::endl;
|
||||
|
||||
in2 = out;
|
||||
|
||||
v.ec = v.exts.decompress(reinterpret_cast<const uint8_t *>(in2.data()),in2.size(),out2);
|
||||
|
||||
v.ec = v.exts.decompress(reinterpret_cast<const uint8_t *>(compress_out.data()),compress_out.size(),decompress_out);
|
||||
BOOST_CHECK_EQUAL( v.ec, websocketpp::lib::error_code() );
|
||||
std::cout << "out: " << websocketpp::utility::to_hex(out2) << std::endl;
|
||||
BOOST_CHECK_EQUAL( out, out2 );
|
||||
BOOST_CHECK_EQUAL( compress_in, decompress_out );
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( compress_data_multiple ) {
|
||||
ext_vars v;
|
||||
|
||||
v.exts.init(true);
|
||||
|
||||
for (int i = 0; i < 2; i++) {
|
||||
std::string compress_in = "Hello";
|
||||
std::string compress_out;
|
||||
std::string decompress_out;
|
||||
|
||||
v.ec = v.exts.compress(compress_in,compress_out);
|
||||
BOOST_CHECK_EQUAL( v.ec, websocketpp::lib::error_code() );
|
||||
|
||||
v.ec = v.exts.decompress(reinterpret_cast<const uint8_t *>(compress_out.data()),compress_out.size(),decompress_out);
|
||||
BOOST_CHECK_EQUAL( v.ec, websocketpp::lib::error_code() );
|
||||
BOOST_CHECK_EQUAL( compress_in, decompress_out );
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( compress_data_large ) {
|
||||
ext_vars v;
|
||||
|
||||
std::string compress_in(600,'*');
|
||||
std::string compress_out;
|
||||
std::string decompress_out;
|
||||
|
||||
websocketpp::http::attribute_list alist;
|
||||
|
||||
alist["server_max_window_bits"] = "8";
|
||||
v.exts.set_server_max_window_bits(8,websocketpp::extensions::permessage_deflate::mode::smallest);
|
||||
|
||||
v.exts.negotiate(alist);
|
||||
v.exts.init(true);
|
||||
|
||||
v.ec = v.exts.compress(compress_in,compress_out);
|
||||
BOOST_CHECK_EQUAL( v.ec, websocketpp::lib::error_code() );
|
||||
|
||||
v.ec = v.exts.decompress(reinterpret_cast<const uint8_t *>(compress_out.data()),compress_out.size(),decompress_out);
|
||||
BOOST_CHECK_EQUAL( v.ec, websocketpp::lib::error_code() );
|
||||
BOOST_CHECK_EQUAL( compress_in, decompress_out );
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( compress_data_no_context_takeover ) {
|
||||
ext_vars v;
|
||||
|
||||
std::string compress_in = "Hello";
|
||||
std::string compress_out1;
|
||||
std::string compress_out2;
|
||||
std::string decompress_out;
|
||||
|
||||
websocketpp::http::attribute_list alist;
|
||||
|
||||
alist["server_no_context_takeover"] = "";
|
||||
v.exts.enable_server_no_context_takeover();
|
||||
|
||||
v.exts.negotiate(alist);
|
||||
v.exts.init(true);
|
||||
|
||||
v.ec = v.exts.compress(compress_in,compress_out1);
|
||||
BOOST_CHECK_EQUAL( v.ec, websocketpp::lib::error_code() );
|
||||
|
||||
v.ec = v.exts.decompress(
|
||||
reinterpret_cast<const uint8_t *>(compress_out1.data()),
|
||||
compress_out1.size(),
|
||||
decompress_out
|
||||
);
|
||||
BOOST_CHECK_EQUAL( v.ec, websocketpp::lib::error_code() );
|
||||
BOOST_CHECK_EQUAL( compress_in, decompress_out );
|
||||
|
||||
decompress_out = "";
|
||||
|
||||
v.ec = v.exts.compress(compress_in,compress_out2);
|
||||
BOOST_CHECK_EQUAL( v.ec, websocketpp::lib::error_code() );
|
||||
|
||||
v.ec = v.exts.decompress(
|
||||
reinterpret_cast<const uint8_t *>(compress_out2.data()),
|
||||
compress_out2.size(),
|
||||
decompress_out
|
||||
);
|
||||
BOOST_CHECK_EQUAL( v.ec, websocketpp::lib::error_code() );
|
||||
BOOST_CHECK_EQUAL( compress_in, decompress_out );
|
||||
|
||||
BOOST_CHECK_EQUAL( compress_out1, compress_out2 );
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( compress_empty ) {
|
||||
ext_vars v;
|
||||
|
||||
std::string compress_in = "";
|
||||
std::string compress_out;
|
||||
std::string decompress_out;
|
||||
|
||||
v.exts.init(true);
|
||||
|
||||
v.ec = v.exts.compress(compress_in,compress_out);
|
||||
BOOST_CHECK_EQUAL( v.ec, websocketpp::lib::error_code() );
|
||||
|
||||
v.ec = v.exts.decompress(reinterpret_cast<const uint8_t *>(compress_out.data()),compress_out.size(),decompress_out);
|
||||
|
||||
compress_out = "";
|
||||
decompress_out = "";
|
||||
|
||||
v.ec = v.exts.compress(compress_in,compress_out);
|
||||
BOOST_CHECK_EQUAL( v.ec, websocketpp::lib::error_code() );
|
||||
|
||||
v.ec = v.exts.decompress(reinterpret_cast<const uint8_t *>(compress_out.data()),compress_out.size(),decompress_out);
|
||||
BOOST_CHECK_EQUAL( v.ec, websocketpp::lib::error_code() );
|
||||
BOOST_CHECK_EQUAL( compress_in, decompress_out );
|
||||
}
|
||||
|
||||
/// @todo: more compression tests
|
||||
/**
|
||||
* - compress at different compression levels
|
||||
*/
|
||||
|
||||
// Decompression
|
||||
BOOST_AUTO_TEST_CASE( decompress_data ) {
|
||||
ext_vars v;
|
||||
|
||||
uint8_t in[12] = {0xf2, 0x48, 0xcd, 0xc9, 0xc9, 0x07, 0x00, 0x00, 0x00, 0xff, 0xff};
|
||||
std::string out;
|
||||
uint8_t in[11] = {0xf2, 0x48, 0xcd, 0xc9, 0xc9, 0x07, 0x00, 0x00, 0x00, 0xff, 0xff};
|
||||
std::string out = "";
|
||||
std::string reference = "Hello";
|
||||
|
||||
v.exts.init();
|
||||
v.exts.init(true);
|
||||
|
||||
v.ec = v.exts.decompress(in,12,out);
|
||||
v.ec = v.exts.decompress(in,11,out);
|
||||
|
||||
BOOST_CHECK_EQUAL( v.ec, websocketpp::lib::error_code() );
|
||||
std::cout << "out: " << websocketpp::utility::to_hex(out) << std::endl;
|
||||
BOOST_CHECK( false );
|
||||
BOOST_CHECK_EQUAL( out, reference );
|
||||
}
|
||||
*/
|
||||
|
||||
@@ -34,6 +34,8 @@
|
||||
#include <websocketpp/concurrency/none.hpp>
|
||||
#include <websocketpp/concurrency/basic.hpp>
|
||||
|
||||
typedef websocketpp::log::basic<websocketpp::concurrency::basic,websocketpp::log::alevel> basic_access_log_type;
|
||||
|
||||
BOOST_AUTO_TEST_CASE( is_token_char ) {
|
||||
typedef websocketpp::log::basic<websocketpp::concurrency::none,websocketpp::log::elevel> error_log;
|
||||
|
||||
@@ -79,3 +81,65 @@ BOOST_AUTO_TEST_CASE( basic_concurrency ) {
|
||||
//std::cout << "|" << out.str() << "|" << std::endl;
|
||||
BOOST_CHECK( out.str().size() > 0 );
|
||||
}
|
||||
|
||||
|
||||
BOOST_AUTO_TEST_CASE( copy_constructor ) {
|
||||
std::stringstream out;
|
||||
|
||||
basic_access_log_type logger1(0xffffffff,&out);
|
||||
basic_access_log_type logger2(logger1);
|
||||
|
||||
logger2.set_channels(0xffffffff);
|
||||
logger2.write(websocketpp::log::alevel::devel,"devel");
|
||||
BOOST_CHECK( out.str().size() > 0 );
|
||||
}
|
||||
|
||||
#ifdef _WEBSOCKETPP_MOVE_SEMANTICS_
|
||||
BOOST_AUTO_TEST_CASE( move_constructor ) {
|
||||
std::stringstream out;
|
||||
|
||||
basic_access_log_type logger1(0xffffffff,&out);
|
||||
basic_access_log_type logger2(std::move(logger1));
|
||||
|
||||
logger2.set_channels(0xffffffff);
|
||||
logger2.write(websocketpp::log::alevel::devel,"devel");
|
||||
BOOST_CHECK( out.str().size() > 0 );
|
||||
}
|
||||
|
||||
// Emplace requires move assignment, which logger doesn't support right now
|
||||
// due to const members. This is pretty irritating and will probably result in
|
||||
// the const members being removed. For now though this test will fail to
|
||||
// compile
|
||||
/*BOOST_AUTO_TEST_CASE( emplace ) {
|
||||
std::stringstream out1;
|
||||
std::stringstream out2;
|
||||
|
||||
std::vector<basic_access_log_type> v;
|
||||
|
||||
v.emplace_back(websocketpp::log::level(0xffffffff),&out1);
|
||||
v.emplace_back(websocketpp::log::level(0xffffffff),&out2);
|
||||
|
||||
v[0].set_channels(0xffffffff);
|
||||
v[1].set_channels(0xffffffff);
|
||||
v[0].write(websocketpp::log::alevel::devel,"devel");
|
||||
v[1].write(websocketpp::log::alevel::devel,"devel");
|
||||
BOOST_CHECK( out1.str().size() > 0 );
|
||||
BOOST_CHECK( out2.str().size() > 0 );
|
||||
}*/
|
||||
#endif // #ifdef _WEBSOCKETPP_MOVE_SEMANTICS_
|
||||
|
||||
// As long as there are const member variables these can't exist
|
||||
// These remain commented as they are useful for testing the deleted operators
|
||||
/*BOOST_AUTO_TEST_CASE( copy_assign ) {
|
||||
basic_access_log_type logger1;
|
||||
basic_access_log_type logger2;
|
||||
|
||||
logger2 = logger1;
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( move_assign ) {
|
||||
basic_access_log_type logger1;
|
||||
basic_access_log_type logger2;
|
||||
|
||||
logger2 = std::move(logger1);
|
||||
}*/
|
||||
|
||||
@@ -682,7 +682,7 @@ BOOST_AUTO_TEST_CASE( extension_negotiation_permessage_deflate ) {
|
||||
processor_setup_ext env(true);
|
||||
|
||||
env.req.replace_header("Sec-WebSocket-Extensions",
|
||||
"permessage-deflate; c2s_max_window_bits");
|
||||
"permessage-deflate; client_max_window_bits");
|
||||
|
||||
std::pair<websocketpp::lib::error_code,std::string> neg_results;
|
||||
neg_results = env.p.negotiate_extensions(env.req);
|
||||
|
||||
@@ -11,7 +11,7 @@ Import('tls_libs')
|
||||
env = env.Clone ()
|
||||
env_cpp11 = env_cpp11.Clone ()
|
||||
|
||||
BOOST_LIBS = boostlibs(['unit_test_framework','system','thread','random'],env) + [platform_libs] + [tls_libs]
|
||||
BOOST_LIBS = boostlibs(['unit_test_framework','system','thread','random','chrono'],env) + [platform_libs] + [tls_libs]
|
||||
|
||||
objs = env.Object('boost_integration.o', ["integration.cpp"], LIBS = BOOST_LIBS)
|
||||
prgs = env.Program('test_boost_integration', ["boost_integration.o"], LIBS = BOOST_LIBS)
|
||||
|
||||
@@ -11,7 +11,7 @@ Import('tls_libs')
|
||||
env = env.Clone ()
|
||||
env_cpp11 = env_cpp11.Clone ()
|
||||
|
||||
BOOST_LIBS = boostlibs(['unit_test_framework','system','thread'],env) + [platform_libs] + [tls_libs]
|
||||
BOOST_LIBS = boostlibs(['unit_test_framework','system','thread','chrono'],env) + [platform_libs] + [tls_libs]
|
||||
|
||||
objs = env.Object('base_boost.o', ["base.cpp"], LIBS = BOOST_LIBS)
|
||||
objs += env.Object('timers_boost.o', ["timers.cpp"], LIBS = BOOST_LIBS)
|
||||
|
||||
@@ -607,3 +607,11 @@ BOOST_AUTO_TEST_CASE( pause_reading ) {
|
||||
BOOST_AUTO_TEST_CASE( server_connection_cleanup ) {
|
||||
server_tls s;
|
||||
}
|
||||
|
||||
#ifdef _WEBSOCKETPP_MOVE_SEMANTICS_
|
||||
BOOST_AUTO_TEST_CASE( move_construct_transport ) {
|
||||
server s1;
|
||||
|
||||
server s2(std::move(s1));
|
||||
}
|
||||
#endif // _WEBSOCKETPP_MOVE_SEMANTICS_
|
||||
|
||||
@@ -117,7 +117,7 @@ struct stub_con : public iostream_con {
|
||||
indef_read_size = num_bytes;
|
||||
indef_read_buf = buf;
|
||||
indef_read_len = len;
|
||||
|
||||
|
||||
indef_read();
|
||||
}
|
||||
|
||||
@@ -138,7 +138,7 @@ struct stub_con : public iostream_con {
|
||||
void handle_indef(websocketpp::lib::error_code const & e, size_t amt_read) {
|
||||
ec = e;
|
||||
indef_read_total += amt_read;
|
||||
|
||||
|
||||
indef_read();
|
||||
}
|
||||
|
||||
@@ -203,6 +203,15 @@ websocketpp::lib::error_code write_handler(std::string & o, websocketpp::connect
|
||||
return websocketpp::lib::error_code();
|
||||
}
|
||||
|
||||
websocketpp::lib::error_code vector_write_handler(std::string & o, websocketpp::connection_hdl, std::vector<websocketpp::transport::buffer> const & bufs) {
|
||||
std::vector<websocketpp::transport::buffer>::const_iterator it;
|
||||
for (it = bufs.begin(); it != bufs.end(); it++) {
|
||||
o += std::string((*it).buf, (*it).len);
|
||||
}
|
||||
|
||||
return websocketpp::lib::error_code();
|
||||
}
|
||||
|
||||
websocketpp::lib::error_code write_handler_error(websocketpp::connection_hdl, char const *, size_t) {
|
||||
return make_error_code(websocketpp::transport::error::general);
|
||||
}
|
||||
@@ -249,7 +258,7 @@ BOOST_AUTO_TEST_CASE( async_write_vector_0_write_handler ) {
|
||||
std::string output;
|
||||
|
||||
stub_con::ptr con(new stub_con(true,alogger,elogger));
|
||||
|
||||
|
||||
con->set_write_handler(websocketpp::lib::bind(
|
||||
&write_handler,
|
||||
websocketpp::lib::ref(output),
|
||||
@@ -354,6 +363,31 @@ BOOST_AUTO_TEST_CASE( async_write_vector_2_write_handler ) {
|
||||
BOOST_CHECK_EQUAL( output, "foobar" );
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( async_write_vector_2_vector_write_handler ) {
|
||||
std::string output;
|
||||
|
||||
stub_con::ptr con(new stub_con(true,alogger,elogger));
|
||||
con->set_vector_write_handler(websocketpp::lib::bind(
|
||||
&vector_write_handler,
|
||||
websocketpp::lib::ref(output),
|
||||
websocketpp::lib::placeholders::_1,
|
||||
websocketpp::lib::placeholders::_2
|
||||
));
|
||||
|
||||
std::vector<websocketpp::transport::buffer> bufs;
|
||||
|
||||
std::string foo = "foo";
|
||||
std::string bar = "bar";
|
||||
|
||||
bufs.push_back(websocketpp::transport::buffer(foo.data(),foo.size()));
|
||||
bufs.push_back(websocketpp::transport::buffer(bar.data(),bar.size()));
|
||||
|
||||
con->write(bufs);
|
||||
|
||||
BOOST_CHECK( !con->ec );
|
||||
BOOST_CHECK_EQUAL( output, "foobar" );
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( async_read_at_least_too_much ) {
|
||||
stub_con::ptr con(new stub_con(true,alogger,elogger));
|
||||
|
||||
@@ -483,7 +517,7 @@ BOOST_AUTO_TEST_CASE( async_read_at_least_read_some_indef ) {
|
||||
BOOST_CHECK( !con->ec );
|
||||
BOOST_CHECK_EQUAL( std::string(buf,10), "aaaaaxxxxx" );
|
||||
BOOST_CHECK_EQUAL( con->indef_read_total, 5 );
|
||||
|
||||
|
||||
// A subsequent read should read 5 more because the indef read refreshes
|
||||
// itself. The new read will start again at the beginning of the buffer.
|
||||
BOOST_CHECK_EQUAL(con->read_some(input+5,5), 5);
|
||||
@@ -539,7 +573,7 @@ websocketpp::lib::error_code sd_handler(websocketpp::connection_hdl) {
|
||||
|
||||
BOOST_AUTO_TEST_CASE( shutdown_handler ) {
|
||||
stub_con::ptr con(new stub_con(true,alogger,elogger));
|
||||
|
||||
|
||||
con->set_shutdown_handler(&sd_handler);
|
||||
BOOST_CHECK_EQUAL( con->ec, make_error_code(websocketpp::error::test) );
|
||||
con->shutdown();
|
||||
|
||||
@@ -235,7 +235,7 @@ The `websocket_endpoint` object has gained some new data members and methods. It
|
||||
A new WebSocket connection is initiated via a three step process. First, a connection request is created by `endpoint::get_connection(uri)`. Next, the connection request is configured. Lastly, the connection request is submitted back to the endpoint via `endpoint::connect()` which adds it to the queue of new connections to make.
|
||||
|
||||
> ###### Terminology `connection_ptr`
|
||||
> WebSocket++ keeps track of connection related resources using a reference counted shared pointer. The type of this pointer is `endpoint::connection_ptr`. A `connection_ptr` allows direct access to information about the connection and allows changing connection settings. Because of this direct access and their internal resource management role within the library it is not safe to for end applications to use `connection_ptr` except in the specific circumstances detailed below.
|
||||
> WebSocket++ keeps track of connection related resources using a reference counted shared pointer. The type of this pointer is `endpoint::connection_ptr`. A `connection_ptr` allows direct access to information about the connection and allows changing connection settings. Because of this direct access and their internal resource management role within the library it is not safe for end applications to use `connection_ptr` except in the specific circumstances detailed below.
|
||||
>
|
||||
> **When is it safe to use `connection_ptr`?**
|
||||
> - After `endpoint::get_connection(...)` and before `endpoint::connect()`: `get_connection` returns a `connection_ptr`. It is safe to use this pointer to configure your new connection. Once you submit the connection to `connect` you may no longer use the `connection_ptr` and should discard it immediately for optimal memory management.
|
||||
@@ -813,6 +813,13 @@ Enter Command: show 0
|
||||
|
||||
_Using TLS / Secure WebSockets_
|
||||
|
||||
- Change the includes
|
||||
- link to the new library dependencies
|
||||
- Switch the config
|
||||
- add the `tls_init_handler`
|
||||
- configure the SSL context for desired security level
|
||||
- mixing secure and non-secure connections in one application.
|
||||
|
||||
Chapter 2: Intermediate Features
|
||||
--------------------------------
|
||||
|
||||
|
||||
@@ -0,0 +1,131 @@
|
||||
/*
|
||||
* 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:
|
||||
* * 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_COMMON_ASIO_HPP
|
||||
#define WEBSOCKETPP_COMMON_ASIO_HPP
|
||||
|
||||
// This file goes to some length to preserve compatibility with versions of
|
||||
// boost older than 1.49 (where the first modern steady_timer timer based on
|
||||
// boost/std chrono was introduced.
|
||||
//
|
||||
// For the versions older than 1.49, the deadline_timer is used instead. this
|
||||
// brings in dependencies on boost date_time and it has a different interface
|
||||
// that is normalized by the `lib::asio::is_neg` and `lib::asio::milliseconds`
|
||||
// wrappers provided by this file.
|
||||
//
|
||||
// The primary reason for this continued support is that boost 1.48 is the
|
||||
// default and not easily changeable version of boost supplied by the package
|
||||
// manager of popular Linux distributions like Ubuntu 12.04 LTS. Once the need
|
||||
// for this has passed this should be cleaned up and simplified.
|
||||
|
||||
#ifdef ASIO_STANDALONE
|
||||
#include <asio/version.hpp>
|
||||
|
||||
#if (ASIO_VERSION/100000) == 1 && ((ASIO_VERSION/100)%1000) < 8
|
||||
static_assert(false, "The minimum version of standalone Asio is 1.8.0");
|
||||
#endif
|
||||
|
||||
#include <asio.hpp>
|
||||
#include <asio/steady_timer.hpp>
|
||||
#include <websocketpp/common/chrono.hpp>
|
||||
#else
|
||||
#include <boost/version.hpp>
|
||||
|
||||
// See note above about boost <1.49 compatibility. If we are running on
|
||||
// boost > 1.48 pull in the steady timer and chrono library
|
||||
#if (BOOST_VERSION/100000) == 1 && ((BOOST_VERSION/100)%1000) > 48
|
||||
#include <boost/asio/steady_timer.hpp>
|
||||
#include <websocketpp/common/chrono.hpp>
|
||||
#endif
|
||||
|
||||
#include <boost/asio.hpp>
|
||||
#include <boost/system/error_code.hpp>
|
||||
#endif
|
||||
|
||||
namespace websocketpp {
|
||||
namespace lib {
|
||||
|
||||
#ifdef ASIO_STANDALONE
|
||||
namespace asio {
|
||||
using namespace ::asio;
|
||||
// Here we assume that we will be using std::error_code with standalone
|
||||
// Asio. This is probably a good assumption, but it is possible in rare
|
||||
// cases that local Asio versions would be used.
|
||||
using std::errc;
|
||||
|
||||
// See note above about boost <1.49 compatibility. Because we require
|
||||
// a standalone Asio version of 1.8+ we are guaranteed to have
|
||||
// steady_timer available. By convention we require the chrono library
|
||||
// (either boost or std) for use with standalone Asio.
|
||||
template <typename T>
|
||||
bool is_neg(T duration) {
|
||||
return duration.count() < 0;
|
||||
}
|
||||
inline lib::chrono::milliseconds milliseconds(long duration) {
|
||||
return lib::chrono::milliseconds(duration);
|
||||
}
|
||||
} // namespace asio
|
||||
|
||||
#else
|
||||
namespace asio {
|
||||
using namespace boost::asio;
|
||||
|
||||
// See note above about boost <1.49 compatibility
|
||||
#if (BOOST_VERSION/100000) == 1 && ((BOOST_VERSION/100)%1000) > 48
|
||||
// Using boost::asio >=1.49 so we use chrono and steady_timer
|
||||
template <typename T>
|
||||
bool is_neg(T duration) {
|
||||
return duration.count() < 0;
|
||||
}
|
||||
inline lib::chrono::milliseconds milliseconds(long duration) {
|
||||
return lib::chrono::milliseconds(duration);
|
||||
}
|
||||
#else
|
||||
// Using boost::asio <1.49 we pretend a deadline timer is a steady
|
||||
// timer and wrap the negative detection and duration conversion
|
||||
// appropriately.
|
||||
typedef boost::asio::deadline_timer steady_timer;
|
||||
|
||||
template <typename T>
|
||||
bool is_neg(T duration) {
|
||||
return duration.is_negative();
|
||||
}
|
||||
inline boost::posix_time::time_duration milliseconds(long duration) {
|
||||
return boost::posix_time::milliseconds(duration);
|
||||
}
|
||||
#endif
|
||||
|
||||
using boost::system::error_code;
|
||||
namespace errc = boost::system::errc;
|
||||
} // namespace asio
|
||||
#endif
|
||||
|
||||
|
||||
} // namespace lib
|
||||
} // namespace websocketpp
|
||||
|
||||
#endif // WEBSOCKETPP_COMMON_ASIO_HPP
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* 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:
|
||||
* * 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_COMMON_ASIO_SSL_HPP
|
||||
#define WEBSOCKETPP_COMMON_ASIO_SSL_HPP
|
||||
|
||||
#ifdef ASIO_STANDALONE
|
||||
#include <asio/asio/ssl.hpp>
|
||||
#else
|
||||
#include <boost/asio/ssl.hpp>
|
||||
#endif
|
||||
|
||||
#endif // WEBSOCKETPP_COMMON_ASIO_SSL_HPP
|
||||
@@ -28,7 +28,12 @@
|
||||
#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
|
||||
@@ -44,9 +49,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
|
||||
|
||||
@@ -80,6 +80,12 @@
|
||||
#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.
|
||||
|
||||
@@ -36,6 +36,8 @@
|
||||
#include <netinet/in.h>
|
||||
#endif
|
||||
|
||||
#include <websocketpp/common/stdint.hpp>
|
||||
|
||||
namespace websocketpp {
|
||||
namespace lib {
|
||||
namespace net {
|
||||
|
||||
@@ -61,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;
|
||||
@@ -68,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;
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* 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:
|
||||
* * 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_COMMON_TYPE_TRAITS_HPP
|
||||
#define WEBSOCKETPP_COMMON_TYPE_TRAITS_HPP
|
||||
|
||||
#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_TYPE_TRAITS_
|
||||
#ifndef _WEBSOCKETPP_CPP11_TYPE_TRAITS_
|
||||
#define _WEBSOCKETPP_CPP11_TYPE_TRAITS_
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef _WEBSOCKETPP_CPP11_TYPE_TRAITS_
|
||||
#include <type_traits>
|
||||
#else
|
||||
#include <boost/aligned_storage.hpp>
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
namespace websocketpp {
|
||||
namespace lib {
|
||||
|
||||
#ifdef _WEBSOCKETPP_CPP11_TYPE_TRAITS_
|
||||
using std::aligned_storage;
|
||||
#else
|
||||
using boost::aligned_storage;
|
||||
#endif
|
||||
|
||||
} // namespace lib
|
||||
} // namespace websocketpp
|
||||
|
||||
#endif // WEBSOCKETPP_COMMON_TYPE_TRAITS_HPP
|
||||
@@ -214,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
|
||||
@@ -312,6 +326,7 @@ public:
|
||||
, 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");
|
||||
@@ -1060,6 +1075,52 @@ public:
|
||||
request_type const & get_request() const {
|
||||
return m_request;
|
||||
}
|
||||
|
||||
/// 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 //
|
||||
@@ -1202,7 +1263,8 @@ 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);
|
||||
@@ -1254,13 +1316,13 @@ protected:
|
||||
lib::error_code process_handshake_request();
|
||||
private:
|
||||
/// Completes m_response, serializes it, and sends it out on the wire.
|
||||
void send_http_response(lib::error_code const & ec);
|
||||
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(lib::error_code const & ec);
|
||||
/// Alternate path for write_http_response in error conditions
|
||||
void write_http_response_error(lib::error_code const & ec);
|
||||
|
||||
/// Process control message
|
||||
/**
|
||||
@@ -1510,6 +1572,10 @@ private:
|
||||
/// 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;
|
||||
|
||||
|
||||
@@ -104,6 +104,56 @@ public:
|
||||
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
|
||||
@@ -466,6 +516,35 @@ public:
|
||||
/// 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
|
||||
@@ -559,7 +638,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) {
|
||||
|
||||
@@ -140,7 +140,10 @@ enum value {
|
||||
unsupported_version,
|
||||
|
||||
/// HTTP parse error
|
||||
http_parse_error
|
||||
http_parse_error,
|
||||
|
||||
/// Extension negotiation failed
|
||||
extension_neg_failed
|
||||
}; // enum value
|
||||
|
||||
|
||||
@@ -216,6 +219,8 @@ public:
|
||||
return "Unsupported version";
|
||||
case error::http_parse_error:
|
||||
return "HTTP parse error";
|
||||
case error::extension_neg_failed:
|
||||
return "Extension negotiation failed";
|
||||
default:
|
||||
return "Unknown";
|
||||
}
|
||||
@@ -250,7 +255,7 @@ public:
|
||||
{}
|
||||
|
||||
explicit exception(lib::error_code ec)
|
||||
: m_code(ec)
|
||||
: m_msg(ec.message()), m_code(ec)
|
||||
{}
|
||||
|
||||
~exception() throw() {}
|
||||
@@ -263,7 +268,7 @@ public:
|
||||
return m_code;
|
||||
}
|
||||
|
||||
std::string m_msg;
|
||||
const std::string m_msg;
|
||||
lib::error_code m_code;
|
||||
};
|
||||
|
||||
|
||||
@@ -55,7 +55,7 @@ class disabled {
|
||||
public:
|
||||
/// Negotiate extension
|
||||
/**
|
||||
* The disabled extension always fails the negotiation with a disabled
|
||||
* The disabled extension always fails the negotiation with a disabled
|
||||
* error.
|
||||
*
|
||||
* @param offer Attribute from client's offer
|
||||
@@ -65,6 +65,17 @@ public:
|
||||
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 {
|
||||
@@ -77,6 +88,17 @@ public:
|
||||
return false;
|
||||
}
|
||||
|
||||
/// 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
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2014, Peter Thorson. All rights reserved.
|
||||
* Copyright (c) 2015, Peter Thorson. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
@@ -50,9 +50,13 @@ namespace extensions {
|
||||
/**
|
||||
* ### permessage-deflate interface
|
||||
*
|
||||
* **is_implemented**\n
|
||||
* `bool is_implemented()`\n
|
||||
* Returns whether or not the object implements the extension or not
|
||||
* **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
|
||||
*
|
||||
* **is_enabled**\n
|
||||
* `bool is_enabled()`\n
|
||||
@@ -136,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";
|
||||
}
|
||||
@@ -144,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());
|
||||
}
|
||||
|
||||
@@ -170,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 {
|
||||
@@ -202,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)
|
||||
{
|
||||
@@ -244,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(
|
||||
@@ -265,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) {
|
||||
@@ -283,6 +292,13 @@ 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();
|
||||
}
|
||||
@@ -329,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
|
||||
@@ -348,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
|
||||
@@ -374,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();
|
||||
}
|
||||
@@ -405,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();
|
||||
}
|
||||
@@ -423,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
|
||||
@@ -435,7 +452,7 @@ public:
|
||||
* @return Validation error or 0 on success
|
||||
*/
|
||||
lib::error_code validate_offer(http::attribute_list const &) {
|
||||
return make_error_code(error::general);
|
||||
return lib::error_code();
|
||||
}
|
||||
|
||||
/// Negotiate extension
|
||||
@@ -452,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);
|
||||
}
|
||||
@@ -479,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
|
||||
@@ -490,7 +510,13 @@ public:
|
||||
|
||||
size_t output;
|
||||
|
||||
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 {
|
||||
@@ -498,7 +524,7 @@ public:
|
||||
m_dstate.avail_out = m_compress_buffer_size;
|
||||
m_dstate.next_out = m_compress_buffer.get();
|
||||
|
||||
deflate(&m_dstate, Z_SYNC_FLUSH);
|
||||
deflate(&m_dstate, m_flush);
|
||||
|
||||
output = m_compress_buffer_size - m_dstate.avail_out;
|
||||
|
||||
@@ -553,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()) {
|
||||
@@ -589,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()) {
|
||||
@@ -605,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.
|
||||
*
|
||||
@@ -624,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.
|
||||
*
|
||||
@@ -669,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;
|
||||
|
||||
@@ -85,6 +85,7 @@ lib::error_code connection<config>::send(std::string const & payload,
|
||||
{
|
||||
message_ptr msg = m_msg_manager->get_message(op,payload.size());
|
||||
msg->append_payload(payload);
|
||||
msg->set_compressed(true);
|
||||
|
||||
return send(msg);
|
||||
}
|
||||
@@ -635,7 +636,66 @@ void connection<config>::remove_header(std::string const & key)
|
||||
}
|
||||
}
|
||||
|
||||
/// Defer HTTP Response until later
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* @return A status code, zero on success, non-zero otherwise
|
||||
*/
|
||||
template <typename config>
|
||||
lib::error_code connection<config>::defer_http_response() {
|
||||
// Cancel handshake timer, otherwise the connection will time out and we'll
|
||||
// close the connection before the app has a chance to send a response.
|
||||
if (m_handshake_timer) {
|
||||
m_handshake_timer->cancel();
|
||||
m_handshake_timer.reset();
|
||||
}
|
||||
|
||||
// Do something to signal deferral
|
||||
m_http_state = session::http_state::deferred;
|
||||
|
||||
return lib::error_code();
|
||||
}
|
||||
|
||||
/// 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
|
||||
*/
|
||||
template <typename config>
|
||||
void connection<config>::send_http_response(lib::error_code & ec) {
|
||||
{
|
||||
scoped_lock_type lock(m_connection_state_lock);
|
||||
if (m_http_state != session::http_state::deferred) {
|
||||
ec = error::make_error_code(error::invalid_state);
|
||||
return;
|
||||
}
|
||||
|
||||
m_http_state = session::http_state::body_written;
|
||||
}
|
||||
|
||||
this->write_http_response(lib::error_code());
|
||||
ec = lib::error_code();
|
||||
}
|
||||
|
||||
template <typename config>
|
||||
void connection<config>::send_http_response() {
|
||||
lib::error_code ec;
|
||||
this->send_http_response(ec);
|
||||
if (ec) {
|
||||
throw exception(ec);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -728,7 +788,7 @@ void connection<config>::read_handshake(size_t num_bytes) {
|
||||
);
|
||||
}
|
||||
|
||||
// All exit paths for this function need to call send_http_response() or submit
|
||||
// All exit paths for this function need to call write_http_response() or submit
|
||||
// a new read request with this function as the handler.
|
||||
template <typename config>
|
||||
void connection<config>::handle_read_handshake(lib::error_code const & ec,
|
||||
@@ -784,7 +844,7 @@ void connection<config>::handle_read_handshake(lib::error_code const & ec,
|
||||
// All HTTP exceptions will result in this request failing and an error
|
||||
// response being returned. No more bytes will be read in this con.
|
||||
m_response.set_status(e.m_error_code,e.m_error_msg);
|
||||
this->send_http_response_error(error::make_error_code(error::http_parse_error));
|
||||
this->write_http_response_error(error::make_error_code(error::http_parse_error));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -806,7 +866,7 @@ void connection<config>::handle_read_handshake(lib::error_code const & ec,
|
||||
if (m_request.ready()) {
|
||||
lib::error_code processor_ec = this->initialize_processor();
|
||||
if (processor_ec) {
|
||||
this->send_http_response_error(processor_ec);
|
||||
this->write_http_response_error(processor_ec);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -823,7 +883,7 @@ void connection<config>::handle_read_handshake(lib::error_code const & ec,
|
||||
// TODO: need more bytes
|
||||
m_alog.write(log::alevel::devel,"short key3 read");
|
||||
m_response.set_status(http::status_code::internal_server_error);
|
||||
this->send_http_response_error(processor::error::make_error_code(processor::error::short_key3));
|
||||
this->write_http_response_error(processor::error::make_error_code(processor::error::short_key3));
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -847,7 +907,9 @@ void connection<config>::handle_read_handshake(lib::error_code const & ec,
|
||||
|
||||
// We have the complete request. Process it.
|
||||
lib::error_code handshake_ec = this->process_handshake_request();
|
||||
this->send_http_response(handshake_ec);
|
||||
if (!m_is_http || m_http_state != session::http_state::deferred) {
|
||||
this->write_http_response(handshake_ec);
|
||||
}
|
||||
} else {
|
||||
// read at least 1 more byte
|
||||
transport_con_type::async_read_at_least(
|
||||
@@ -864,26 +926,26 @@ void connection<config>::handle_read_handshake(lib::error_code const & ec,
|
||||
}
|
||||
}
|
||||
|
||||
// send_http_response requires the request to be fully read and the connection
|
||||
// write_http_response requires the request to be fully read and the connection
|
||||
// to be in the PROCESS_HTTP_REQUEST state. In some cases we can detect errors
|
||||
// before the request is fully read (specifically at a point where we aren't
|
||||
// sure if the hybi00 key3 bytes need to be read). This method sets the correct
|
||||
// state and calls send_http_response
|
||||
// state and calls write_http_response
|
||||
template <typename config>
|
||||
void connection<config>::send_http_response_error(lib::error_code const & ec) {
|
||||
void connection<config>::write_http_response_error(lib::error_code const & ec) {
|
||||
if (m_internal_state != istate::READ_HTTP_REQUEST) {
|
||||
m_alog.write(log::alevel::devel,
|
||||
"send_http_response_error called in invalid state");
|
||||
"write_http_response_error called in invalid state");
|
||||
this->terminate(error::make_error_code(error::invalid_state));
|
||||
return;
|
||||
}
|
||||
|
||||
m_internal_state = istate::PROCESS_HTTP_REQUEST;
|
||||
|
||||
this->send_http_response(ec);
|
||||
this->write_http_response(ec);
|
||||
}
|
||||
|
||||
// All exit paths for this function need to call send_http_response() or submit
|
||||
// All exit paths for this function need to call write_http_response() or submit
|
||||
// a new read request with this function as the handler.
|
||||
template <typename config>
|
||||
void connection<config>::handle_read_frame(lib::error_code const & ec,
|
||||
@@ -965,6 +1027,12 @@ void connection<config>::handle_read_frame(lib::error_code const & ec,
|
||||
|
||||
lib::error_code consume_ec;
|
||||
|
||||
if (m_alog.static_test(log::alevel::devel)) {
|
||||
std::stringstream s;
|
||||
s << "Processing Bytes: " << utility::to_hex(reinterpret_cast<uint8_t*>(m_buf)+p,bytes_transferred-p);
|
||||
m_alog.write(log::alevel::devel,s.str());
|
||||
}
|
||||
|
||||
p += m_processor->consume(
|
||||
reinterpret_cast<uint8_t*>(m_buf)+p,
|
||||
bytes_transferred-p,
|
||||
@@ -1113,6 +1181,7 @@ lib::error_code connection<config>::process_handshake_request() {
|
||||
if (m_http_handler) {
|
||||
m_is_http = true;
|
||||
m_http_handler(m_connection_hdl);
|
||||
|
||||
if (m_state == session::state::closed) {
|
||||
return error::make_error_code(error::http_connection_ended);
|
||||
}
|
||||
@@ -1207,8 +1276,8 @@ lib::error_code connection<config>::process_handshake_request() {
|
||||
}
|
||||
|
||||
template <typename config>
|
||||
void connection<config>::send_http_response(lib::error_code const & ec) {
|
||||
m_alog.write(log::alevel::devel,"connection send_http_response");
|
||||
void connection<config>::write_http_response(lib::error_code const & ec) {
|
||||
m_alog.write(log::alevel::devel,"connection write_http_response");
|
||||
|
||||
if (ec == error::make_error_code(error::http_connection_ended)) {
|
||||
m_alog.write(log::alevel::http,"An HTTP handler took over the connection.");
|
||||
@@ -1254,7 +1323,7 @@ void connection<config>::send_http_response(lib::error_code const & ec) {
|
||||
m_handshake_buffer.data(),
|
||||
m_handshake_buffer.size(),
|
||||
lib::bind(
|
||||
&type::handle_send_http_response,
|
||||
&type::handle_write_http_response,
|
||||
type::get_shared(),
|
||||
lib::placeholders::_1
|
||||
)
|
||||
@@ -1262,8 +1331,8 @@ void connection<config>::send_http_response(lib::error_code const & ec) {
|
||||
}
|
||||
|
||||
template <typename config>
|
||||
void connection<config>::handle_send_http_response(lib::error_code const & ec) {
|
||||
m_alog.write(log::alevel::devel,"handle_send_http_response");
|
||||
void connection<config>::handle_write_http_response(lib::error_code const & ec) {
|
||||
m_alog.write(log::alevel::devel,"handle_write_http_response");
|
||||
|
||||
lib::error_code ecm = ec;
|
||||
|
||||
@@ -1279,7 +1348,7 @@ void connection<config>::handle_send_http_response(lib::error_code const & ec) {
|
||||
// usually by the handshake timer. This is basically expected
|
||||
// (though hopefully rare) and there is nothing we can do so ignore.
|
||||
m_alog.write(log::alevel::devel,
|
||||
"handle_send_http_response invoked after connection was closed");
|
||||
"handle_write_http_response invoked after connection was closed");
|
||||
return;
|
||||
} else {
|
||||
ecm = error::make_error_code(error::invalid_state);
|
||||
@@ -1294,7 +1363,7 @@ void connection<config>::handle_send_http_response(lib::error_code const & ec) {
|
||||
return;
|
||||
}
|
||||
|
||||
log_err(log::elevel::rerror,"handle_send_http_response",ecm);
|
||||
log_err(log::elevel::rerror,"handle_write_http_response",ecm);
|
||||
this->terminate(ecm);
|
||||
return;
|
||||
}
|
||||
@@ -1525,6 +1594,25 @@ void connection<config>::handle_read_http_response(lib::error_code const & ec,
|
||||
return;
|
||||
}
|
||||
|
||||
// Read extension parameters and set up values necessary for the end
|
||||
// user to complete extension negotiation.
|
||||
std::pair<lib::error_code,std::string> neg_results;
|
||||
neg_results = m_processor->negotiate_extensions(m_response);
|
||||
|
||||
if (neg_results.first) {
|
||||
// There was a fatal error in extension negotiation. For the moment
|
||||
// kill all connections that fail extension negotiation.
|
||||
|
||||
// TODO: deal with cases where the response is well formed but
|
||||
// doesn't match the options requested by the client. Its possible
|
||||
// that the best behavior in this cases is to log and continue with
|
||||
// an unextended connection.
|
||||
m_alog.write(log::alevel::devel, "Extension negotiation failed: "
|
||||
+ neg_results.first.message());
|
||||
this->terminate(make_error_code(error::extension_neg_failed));
|
||||
// TODO: close connection with reason 1010 (and list extensions)
|
||||
}
|
||||
|
||||
// response is valid, connection can now be assumed to be open
|
||||
m_internal_state = istate::PROCESS_CONNECTION;
|
||||
m_state = session::state::open;
|
||||
@@ -1608,7 +1696,10 @@ void connection<config>::terminate(lib::error_code const & ec) {
|
||||
m_local_close_reason = ec.message();
|
||||
}
|
||||
|
||||
// TODO: does this need a mutex?
|
||||
// TODO: does any of this need a mutex?
|
||||
if (m_is_http) {
|
||||
m_http_state = session::http_state::closed;
|
||||
}
|
||||
if (m_state == session::state::connecting) {
|
||||
m_state = session::state::closed;
|
||||
tstat = failed;
|
||||
|
||||
@@ -142,7 +142,21 @@ void endpoint<connection,config>::resume_reading(connection_hdl hdl) {
|
||||
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,
|
||||
|
||||
@@ -80,6 +80,36 @@ public:
|
||||
, 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;
|
||||
}
|
||||
|
||||
@@ -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) 2014, Peter Thorson. All rights reserved.
|
||||
* Copyright (c) 2015, Peter Thorson. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
@@ -85,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
|
||||
@@ -97,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);
|
||||
@@ -116,6 +130,14 @@ 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) {
|
||||
@@ -128,6 +150,7 @@ public:
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
@@ -223,6 +246,13 @@ 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();
|
||||
}
|
||||
|
||||
@@ -264,6 +294,8 @@ public:
|
||||
return error::make_error_code(error::missing_required_header);
|
||||
}
|
||||
|
||||
// check extensions
|
||||
|
||||
return lib::error_code();
|
||||
}
|
||||
|
||||
@@ -391,6 +423,10 @@ public:
|
||||
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.
|
||||
@@ -432,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();
|
||||
}
|
||||
@@ -454,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;
|
||||
@@ -551,18 +620,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
|
||||
@@ -570,6 +632,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);
|
||||
@@ -588,6 +658,17 @@ 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);
|
||||
|
||||
@@ -730,13 +811,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);
|
||||
@@ -937,7 +1018,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) 2014, Peter Thorson. All rights reserved.
|
||||
* Copyright (c) 2015, Peter Thorson. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
@@ -217,13 +217,28 @@ 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 headers to look at.
|
||||
* @param request The request or response headers to look at.
|
||||
*/
|
||||
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();
|
||||
}
|
||||
|
||||
/// validate a WebSocket handshake request for this version
|
||||
/**
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
#define WEBSOCKETPP_CLIENT_ENDPOINT_HPP
|
||||
|
||||
#include <websocketpp/endpoint.hpp>
|
||||
#include <websocketpp/uri.hpp>
|
||||
|
||||
#include <websocketpp/logger/levels.hpp>
|
||||
|
||||
|
||||
@@ -69,6 +69,28 @@ public:
|
||||
endpoint_type::m_alog.write(log::alevel::devel, "server constructor");
|
||||
}
|
||||
|
||||
/// 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()
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2014, Peter Thorson. All rights reserved.
|
||||
* Copyright (c) 2015, Peter Thorson. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
@@ -28,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,13 @@ inline custom_alloc_handler<Handler> make_custom_alloc_handler(
|
||||
template <typename config>
|
||||
class endpoint;
|
||||
|
||||
typedef lib::function<void(boost::system::error_code const &)>
|
||||
typedef lib::function<void(lib::asio::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;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2014, Peter Thorson. All rights reserved.
|
||||
* Copyright (c) 2015, Peter Thorson. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
@@ -37,15 +37,15 @@
|
||||
|
||||
#include <websocketpp/base64/base64.hpp>
|
||||
#include <websocketpp/error.hpp>
|
||||
#include <websocketpp/uri.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 <boost/asio.hpp>
|
||||
#include <boost/system/error_code.hpp>
|
||||
|
||||
#include <istream>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
@@ -57,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>
|
||||
@@ -85,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
|
||||
@@ -98,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)
|
||||
@@ -115,6 +115,22 @@ 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
|
||||
@@ -295,9 +311,9 @@ public:
|
||||
* needed.
|
||||
*/
|
||||
timer_ptr set_timer(long duration, timer_handler callback) {
|
||||
timer_ptr new_timer = lib::make_shared<boost::asio::deadline_timer>(
|
||||
timer_ptr new_timer = lib::make_shared<lib::asio::steady_timer>(
|
||||
lib::ref(*m_io_service),
|
||||
boost::posix_time::milliseconds(duration)
|
||||
lib::asio::milliseconds(duration)
|
||||
);
|
||||
|
||||
if (config::enable_multithreading) {
|
||||
@@ -331,10 +347,10 @@ public:
|
||||
* @param ec The status code
|
||||
*/
|
||||
void handle_timer(timer_ptr, timer_handler callback,
|
||||
boost::system::error_code const & ec)
|
||||
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);
|
||||
@@ -344,7 +360,7 @@ public:
|
||||
callback(lib::error_code());
|
||||
}
|
||||
}
|
||||
protected:
|
||||
|
||||
/// Get a pointer to this connection's strand
|
||||
strand_ptr get_strand() {
|
||||
return m_strand;
|
||||
@@ -353,7 +369,7 @@ protected:
|
||||
/// 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
|
||||
@@ -367,6 +383,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");
|
||||
@@ -411,7 +428,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
|
||||
@@ -422,7 +439,7 @@ protected:
|
||||
m_io_service = io_service;
|
||||
|
||||
if (config::enable_multithreading) {
|
||||
m_strand = lib::make_shared<boost::asio::strand>(
|
||||
m_strand = lib::make_shared<lib::asio::strand>(
|
||||
lib::ref(*io_service));
|
||||
|
||||
m_async_read_handler = m_strand->wrap(lib::bind(
|
||||
@@ -555,7 +572,7 @@ protected:
|
||||
lib::error_code const & ec)
|
||||
{
|
||||
if (ec == transport::error::operation_aborted ||
|
||||
(post_timer && 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;
|
||||
@@ -590,8 +607,8 @@ protected:
|
||||
|
||||
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);
|
||||
|
||||
@@ -608,7 +625,7 @@ protected:
|
||||
|
||||
// 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(
|
||||
@@ -618,7 +635,7 @@ protected:
|
||||
))
|
||||
);
|
||||
} else {
|
||||
boost::asio::async_write(
|
||||
lib::asio::async_write(
|
||||
socket_con_type::get_next_layer(),
|
||||
m_bufs,
|
||||
lib::bind(
|
||||
@@ -648,7 +665,7 @@ protected:
|
||||
}
|
||||
|
||||
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,
|
||||
@@ -660,8 +677,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;
|
||||
@@ -691,7 +708,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",
|
||||
@@ -702,7 +719,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",
|
||||
@@ -722,7 +739,7 @@ protected:
|
||||
* @param bytes_transferred The number of bytes read
|
||||
*/
|
||||
void handle_proxy_read(init_handler callback,
|
||||
boost::system::error_code const & ec, size_t)
|
||||
lib::asio::error_code const & ec, size_t)
|
||||
{
|
||||
if (m_alog.static_test(log::alevel::devel)) {
|
||||
m_alog.write(log::alevel::devel,
|
||||
@@ -732,8 +749,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;
|
||||
@@ -836,10 +853,10 @@ protected:
|
||||
"asio con async_read_at_least called with bad handler");
|
||||
}
|
||||
|
||||
boost::asio::async_read(
|
||||
lib::asio::async_read(
|
||||
socket_con_type::get_socket(),
|
||||
boost::asio::buffer(buf,len),
|
||||
boost::asio::transfer_at_least(num_bytes),
|
||||
lib::asio::buffer(buf,len),
|
||||
lib::asio::transfer_at_least(num_bytes),
|
||||
make_custom_alloc_handler(
|
||||
m_read_handler_allocator,
|
||||
m_async_read_handler
|
||||
@@ -847,14 +864,14 @@ protected:
|
||||
);
|
||||
}
|
||||
|
||||
void handle_async_read(boost::system::error_code const & ec,
|
||||
void handle_async_read(lib::asio::error_code const & ec,
|
||||
size_t bytes_transferred)
|
||||
{
|
||||
m_alog.write(log::alevel::devel, "asio con handle_async_read");
|
||||
|
||||
// translate boost error codes into more lib::error_codes
|
||||
// translate asio error codes into more lib::error_codes
|
||||
lib::error_code tec;
|
||||
if (ec == boost::asio::error::eof) {
|
||||
if (ec == lib::asio::error::eof) {
|
||||
tec = make_error_code(transport::error::eof);
|
||||
} else if (ec) {
|
||||
// We don't know much more about the error at this point. As our
|
||||
@@ -890,11 +907,11 @@ protected:
|
||||
return;
|
||||
}
|
||||
|
||||
m_bufs.push_back(boost::asio::buffer(buf,len));
|
||||
m_bufs.push_back(lib::asio::buffer(buf,len));
|
||||
|
||||
m_write_handler = handler;
|
||||
|
||||
boost::asio::async_write(
|
||||
lib::asio::async_write(
|
||||
socket_con_type::get_socket(),
|
||||
m_bufs,
|
||||
make_custom_alloc_handler(
|
||||
@@ -914,12 +931,12 @@ protected:
|
||||
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(
|
||||
lib::asio::async_write(
|
||||
socket_con_type::get_socket(),
|
||||
m_bufs,
|
||||
make_custom_alloc_handler(
|
||||
@@ -934,7 +951,7 @@ protected:
|
||||
* @param ec The status code
|
||||
* @param bytes_transferred The number of bytes read
|
||||
*/
|
||||
void handle_async_write(boost::system::error_code const & ec, size_t) {
|
||||
void handle_async_write(lib::asio::error_code const & ec, size_t) {
|
||||
m_bufs.clear();
|
||||
lib::error_code tec;
|
||||
if (ec) {
|
||||
@@ -1061,10 +1078,10 @@ protected:
|
||||
}
|
||||
|
||||
void handle_async_shutdown(timer_ptr shutdown_timer, shutdown_handler
|
||||
callback, boost::system::error_code const & 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;
|
||||
@@ -1074,7 +1091,7 @@ protected:
|
||||
|
||||
lib::error_code tec;
|
||||
if (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
|
||||
@@ -1124,7 +1141,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;
|
||||
};
|
||||
@@ -1137,7 +1154,7 @@ 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;
|
||||
|
||||
// Handlers
|
||||
tcp_init_handler m_tcp_pre_init_handler;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2014, Peter Thorson. All rights reserved.
|
||||
* Copyright (c) 2015, Peter Thorson. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
@@ -37,10 +37,6 @@
|
||||
|
||||
#include <websocketpp/common/functional.hpp>
|
||||
|
||||
#include <boost/asio.hpp>
|
||||
#include <boost/bind.hpp>
|
||||
#include <boost/system/error_code.hpp>
|
||||
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
|
||||
@@ -48,10 +44,10 @@ 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 {
|
||||
@@ -81,15 +77,15 @@ 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()
|
||||
@@ -113,23 +109,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(boost::asio::socket_base::max_connections)
|
||||
, 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;
|
||||
@@ -138,7 +139,7 @@ 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;
|
||||
@@ -150,12 +151,15 @@ public:
|
||||
rhs.m_io_service = NULL;
|
||||
rhs.m_external_io_service = false;
|
||||
rhs.m_acceptor = NULL;
|
||||
rhs.m_listen_backlog = boost::asio::socket_base::max_connections;
|
||||
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();
|
||||
@@ -183,7 +187,7 @@ public:
|
||||
|
||||
m_io_service = ptr;
|
||||
m_external_io_service = true;
|
||||
m_acceptor = lib::make_shared<boost::asio::ip::tcp::acceptor>(
|
||||
m_acceptor = lib::make_shared<lib::asio::ip::tcp::acceptor>(
|
||||
lib::ref(*m_io_service));
|
||||
|
||||
m_state = READY;
|
||||
@@ -214,7 +218,7 @@ 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);
|
||||
init_asio(new lib::asio::io_service(), ec);
|
||||
m_external_io_service = false;
|
||||
}
|
||||
|
||||
@@ -226,7 +230,7 @@ public:
|
||||
* @see init_asio(io_service_ptr ptr)
|
||||
*/
|
||||
void init_asio() {
|
||||
init_asio(new boost::asio::io_service());
|
||||
init_asio(new lib::asio::io_service());
|
||||
m_external_io_service = false;
|
||||
}
|
||||
|
||||
@@ -325,7 +329,7 @@ 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;
|
||||
}
|
||||
|
||||
@@ -337,7 +341,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,
|
||||
@@ -349,11 +353,11 @@ public:
|
||||
|
||||
m_alog->write(log::alevel::devel,"asio::listen");
|
||||
|
||||
boost::system::error_code bec;
|
||||
lib::asio::error_code bec;
|
||||
|
||||
m_acceptor->open(ep.protocol(),bec);
|
||||
if (!bec) {
|
||||
m_acceptor->set_option(boost::asio::socket_base::reuse_address(m_reuse_addr),bec);
|
||||
m_acceptor->set_option(lib::asio::socket_base::reuse_address(m_reuse_addr),bec);
|
||||
}
|
||||
if (!bec) {
|
||||
m_acceptor->bind(ep,bec);
|
||||
@@ -379,7 +383,7 @@ 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 exception(ec); }
|
||||
@@ -392,8 +396,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.
|
||||
@@ -403,7 +407,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);
|
||||
}
|
||||
|
||||
@@ -414,8 +418,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.
|
||||
@@ -423,7 +427,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);
|
||||
}
|
||||
|
||||
@@ -440,7 +444,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
|
||||
@@ -456,13 +460,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.
|
||||
*
|
||||
@@ -478,7 +482,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);
|
||||
@@ -495,7 +499,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.
|
||||
*
|
||||
@@ -609,7 +613,7 @@ public:
|
||||
* @since 0.3.0
|
||||
*/
|
||||
void start_perpetual() {
|
||||
m_work = lib::make_shared<boost::asio::io_service::work>(
|
||||
m_work = lib::make_shared<lib::asio::io_service::work>(
|
||||
lib::ref(*m_io_service)
|
||||
);
|
||||
}
|
||||
@@ -639,9 +643,9 @@ public:
|
||||
* needed.
|
||||
*/
|
||||
timer_ptr set_timer(long duration, timer_handler callback) {
|
||||
timer_ptr new_timer = lib::make_shared<boost::asio::deadline_timer>(
|
||||
timer_ptr new_timer = lib::make_shared<lib::asio::steady_timer>(
|
||||
*m_io_service,
|
||||
boost::posix_time::milliseconds(duration)
|
||||
lib::asio::milliseconds(duration)
|
||||
);
|
||||
|
||||
new_timer->async_wait(
|
||||
@@ -667,10 +671,10 @@ public:
|
||||
* @param ec A status code indicating an error, if any.
|
||||
*/
|
||||
void handle_timer(timer_ptr, timer_handler callback,
|
||||
boost::system::error_code const & ec)
|
||||
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,
|
||||
@@ -749,18 +753,18 @@ 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) {
|
||||
if (boost_ec == boost::system::errc::operation_canceled) {
|
||||
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",boost_ec);
|
||||
log_err(log::elevel::info,"asio handle_accept",asio_ec);
|
||||
ret_ec = make_error_code(error::pass_through);
|
||||
}
|
||||
}
|
||||
@@ -771,14 +775,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 = lib::make_shared<boost::asio::ip::tcp::resolver>(
|
||||
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;
|
||||
@@ -888,11 +894,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;
|
||||
@@ -910,7 +916,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() << " ";
|
||||
}
|
||||
@@ -935,7 +941,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(
|
||||
@@ -948,7 +954,7 @@ protected:
|
||||
))
|
||||
);
|
||||
} else {
|
||||
boost::asio::async_connect(
|
||||
lib::asio::async_connect(
|
||||
tcon->get_raw_socket(),
|
||||
iterator,
|
||||
lib::bind(
|
||||
@@ -997,10 +1003,10 @@ protected:
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
@@ -34,8 +34,6 @@
|
||||
#include <websocketpp/common/cpp11.hpp>
|
||||
#include <websocketpp/common/connection_hdl.hpp>
|
||||
|
||||
#include <boost/asio.hpp>
|
||||
|
||||
#include <string>
|
||||
|
||||
// Interface that sockets/security policies must implement
|
||||
@@ -56,6 +54,7 @@
|
||||
|
||||
// Connection
|
||||
// TODO
|
||||
// set_hostname(std::string hostname)
|
||||
// pre_init(init_handler);
|
||||
// post_init(init_handler);
|
||||
|
||||
@@ -97,7 +96,10 @@ namespace error {
|
||||
missing_tls_init_handler,
|
||||
|
||||
/// TLS Handshake Failed
|
||||
tls_handshake_failed
|
||||
tls_handshake_failed,
|
||||
|
||||
/// Failed to set TLS SNI hostname
|
||||
tls_failed_sni_hostname
|
||||
};
|
||||
} // namespace error
|
||||
|
||||
@@ -126,6 +128,8 @@ public:
|
||||
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";
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2014, Peter Thorson. All rights reserved.
|
||||
* Copyright (c) 2015, Peter Thorson. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
@@ -28,12 +28,13 @@
|
||||
#ifndef WEBSOCKETPP_TRANSPORT_SECURITY_NONE_HPP
|
||||
#define WEBSOCKETPP_TRANSPORT_SECURITY_NONE_HPP
|
||||
|
||||
#include <websocketpp/uri.hpp>
|
||||
|
||||
#include <websocketpp/transport/asio/security/base.hpp>
|
||||
|
||||
#include <websocketpp/common/asio.hpp>
|
||||
#include <websocketpp/common/memory.hpp>
|
||||
|
||||
#include <boost/asio.hpp>
|
||||
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
|
||||
@@ -45,13 +46,13 @@ namespace asio {
|
||||
namespace basic_socket {
|
||||
|
||||
/// The signature of the socket init handler for this socket policy
|
||||
typedef lib::function<void(connection_hdl,boost::asio::ip::tcp::socket&)>
|
||||
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:
|
||||
@@ -60,12 +61,12 @@ 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 boost::asio::ip::tcp::socket socket_type;
|
||||
typedef lib::asio::ip::tcp::socket socket_type;
|
||||
/// Type of a shared pointer to the socket being used.
|
||||
typedef lib::shared_ptr<socket_type> socket_ptr;
|
||||
|
||||
@@ -91,7 +92,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
|
||||
*/
|
||||
@@ -103,7 +104,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;
|
||||
}
|
||||
|
||||
@@ -111,7 +112,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;
|
||||
}
|
||||
|
||||
@@ -119,7 +120,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;
|
||||
}
|
||||
|
||||
@@ -133,16 +134,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();
|
||||
@@ -154,7 +155,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 shared pointer to the connection's asio strand
|
||||
@@ -166,7 +167,7 @@ protected:
|
||||
return socket::make_error_code(socket::error::invalid_state);
|
||||
}
|
||||
|
||||
m_socket = lib::make_shared<boost::asio::ip::tcp::socket>(
|
||||
m_socket = lib::make_shared<lib::asio::ip::tcp::socket>(
|
||||
lib::ref(*service));
|
||||
|
||||
m_state = READY;
|
||||
@@ -174,6 +175,19 @@ protected:
|
||||
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
|
||||
@@ -227,8 +241,8 @@ protected:
|
||||
}
|
||||
|
||||
void async_shutdown(socket_shutdown_handler h) {
|
||||
boost::system::error_code ec;
|
||||
m_socket->shutdown(boost::asio::ip::tcp::socket::shutdown_both,ec);
|
||||
lib::asio::error_code ec;
|
||||
m_socket->shutdown(lib::asio::ip::tcp::socket::shutdown_both, ec);
|
||||
h(ec);
|
||||
}
|
||||
|
||||
@@ -248,7 +262,7 @@ protected:
|
||||
* @param ec The error code to translate_ec
|
||||
* @return The translated error code
|
||||
*/
|
||||
lib::error_code translate_ec(boost::system::error_code) {
|
||||
lib::error_code translate_ec(lib::asio::error_code) {
|
||||
// We don't know any more information about this error so pass through
|
||||
return make_error_code(transport::error::pass_through);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2014, Peter Thorson. All rights reserved.
|
||||
* Copyright (c) 2015, Peter Thorson. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
@@ -30,14 +30,14 @@
|
||||
|
||||
#include <websocketpp/transport/asio/security/base.hpp>
|
||||
|
||||
#include <websocketpp/uri.hpp>
|
||||
|
||||
#include <websocketpp/common/asio.hpp>
|
||||
#include <websocketpp/common/asio_ssl.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 <sstream>
|
||||
#include <string>
|
||||
|
||||
@@ -49,16 +49,16 @@ namespace asio {
|
||||
namespace tls_socket {
|
||||
|
||||
/// The signature of the socket_init_handler for this socket policy
|
||||
typedef lib::function<void(connection_hdl,boost::asio::ssl::stream<
|
||||
boost::asio::ip::tcp::socket>&)> socket_init_handler;
|
||||
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<boost::asio::ssl::context>(connection_hdl)>
|
||||
typedef lib::function<lib::shared_ptr<lib::asio::ssl::context>(connection_hdl)>
|
||||
tls_init_handler;
|
||||
|
||||
/// TLS enabled Boost 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:
|
||||
@@ -68,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"
|
||||
@@ -102,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();
|
||||
}
|
||||
|
||||
@@ -110,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();
|
||||
}
|
||||
|
||||
@@ -118,7 +116,7 @@ public:
|
||||
/**
|
||||
* This is used internally.
|
||||
*/
|
||||
socket_type& get_socket() {
|
||||
socket_type & get_socket() {
|
||||
return *m_socket;
|
||||
}
|
||||
|
||||
@@ -157,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();
|
||||
@@ -178,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
|
||||
@@ -205,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
|
||||
@@ -215,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());
|
||||
}
|
||||
@@ -266,8 +296,7 @@ protected:
|
||||
m_hdl = hdl;
|
||||
}
|
||||
|
||||
void handle_init(init_handler callback,boost::system::error_code const & ec)
|
||||
{
|
||||
void handle_init(init_handler callback,lib::asio::error_code const & ec) {
|
||||
if (ec) {
|
||||
m_ec = socket::make_error_code(socket::error::tls_handshake_failed);
|
||||
} else {
|
||||
@@ -306,7 +335,7 @@ protected:
|
||||
* @return The translated error code
|
||||
*/
|
||||
lib::error_code translate_ec(boost::system::error_code ec) {
|
||||
if (ec.category() == boost::asio::error::get_ssl_category()) {
|
||||
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 {
|
||||
@@ -323,9 +352,9 @@ protected:
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -333,6 +362,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;
|
||||
@@ -342,10 +372,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:
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
|
||||
#include <websocketpp/transport/base/connection.hpp>
|
||||
|
||||
#include <websocketpp/uri.hpp>
|
||||
#include <websocketpp/logger/levels.hpp>
|
||||
|
||||
#include <websocketpp/common/connection_hdl.hpp>
|
||||
@@ -103,6 +104,20 @@ public:
|
||||
return false;
|
||||
}
|
||||
|
||||
/// Set uri hook
|
||||
/**
|
||||
* Called by the endpoint as a connection is being established to provide
|
||||
* the uri being connected to to the transport layer.
|
||||
*
|
||||
* Implementation is optional and can be ignored if the transport has no
|
||||
* need for this information.
|
||||
*
|
||||
* @since 0.6.0
|
||||
*
|
||||
* @param u The uri to set
|
||||
*/
|
||||
void set_uri(uri_ptr) {}
|
||||
|
||||
/// Set human readable remote endpoint address
|
||||
/**
|
||||
* Sets the remote endpoint address returned by `get_remote_endpoint`. This
|
||||
|
||||
@@ -33,7 +33,10 @@
|
||||
#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 {
|
||||
@@ -41,10 +44,19 @@ namespace transport {
|
||||
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)>
|
||||
typedef lib::function<lib::error_code(connection_hdl, char const *, size_t)>
|
||||
write_handler;
|
||||
|
||||
/// The type and signature of the callback used by iostream transport to signal
|
||||
/// 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;
|
||||
|
||||
|
||||
@@ -32,6 +32,8 @@
|
||||
|
||||
#include <websocketpp/transport/base/connection.hpp>
|
||||
|
||||
#include <websocketpp/uri.hpp>
|
||||
|
||||
#include <websocketpp/logger/levels.hpp>
|
||||
|
||||
#include <websocketpp/common/connection_hdl.hpp>
|
||||
@@ -105,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
|
||||
@@ -153,7 +168,7 @@ 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
|
||||
@@ -173,7 +188,7 @@ public:
|
||||
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;
|
||||
|
||||
@@ -312,25 +327,60 @@ public:
|
||||
timer_ptr set_timer(long, timer_handler) {
|
||||
return timer_ptr();
|
||||
}
|
||||
|
||||
|
||||
/// Sets the write handler
|
||||
/**
|
||||
* The write handler is called when the iostream transport receives data
|
||||
* that needs to be written to the appropriate output location. This handler
|
||||
* can be used in place of registering an ostream for output.
|
||||
*
|
||||
* The signature of the handler is
|
||||
* 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 on connection shutdown.
|
||||
* @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
|
||||
@@ -434,7 +484,7 @@ protected:
|
||||
* @param len number of bytes to write
|
||||
* @param handler Callback to invoke with operation status.
|
||||
*/
|
||||
void async_write(char const * buf, size_t len, transport::write_handler
|
||||
void async_write(char const * buf, size_t len, transport::write_handler
|
||||
handler)
|
||||
{
|
||||
m_alog.write(log::alevel::devel,"iostream_con async_write");
|
||||
@@ -444,7 +494,7 @@ protected:
|
||||
|
||||
if (m_output_stream) {
|
||||
m_output_stream->write(buf,len);
|
||||
|
||||
|
||||
if (m_output_stream->bad()) {
|
||||
ec = make_error_code(error::bad_stream);
|
||||
}
|
||||
@@ -492,17 +542,19 @@ protected:
|
||||
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(ec);
|
||||
}
|
||||
|
||||
@@ -540,11 +592,11 @@ protected:
|
||||
*/
|
||||
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:
|
||||
@@ -636,6 +688,7 @@ private:
|
||||
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;
|
||||
|
||||
@@ -103,6 +103,20 @@ public:
|
||||
return false;
|
||||
}
|
||||
|
||||
/// Set uri hook
|
||||
/**
|
||||
* Called by the endpoint as a connection is being established to provide
|
||||
* the uri being connected to to the transport layer.
|
||||
*
|
||||
* Implementation is optional and can be ignored if the transport has no
|
||||
* need for this information.
|
||||
*
|
||||
* @since 0.6.0
|
||||
*
|
||||
* @param u The uri to set
|
||||
*/
|
||||
void set_uri(uri_ptr) {}
|
||||
|
||||
/// Set human readable remote endpoint address
|
||||
/**
|
||||
* Sets the remote endpoint address returned by `get_remote_endpoint`. This
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2014, Peter Thorson. All rights reserved.
|
||||
* Copyright (c) 2015, Peter Thorson. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
@@ -42,18 +42,18 @@ namespace websocketpp {
|
||||
/// Library major version number
|
||||
static int const major_version = 0;
|
||||
/// Library minor version number
|
||||
static int const minor_version = 5;
|
||||
static int const minor_version = 6;
|
||||
/// Library patch version number
|
||||
static int const patch_version = 1;
|
||||
static int const patch_version = 0;
|
||||
/// Library pre-release flag
|
||||
/**
|
||||
* 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[] = "";
|
||||
static char const prerelease_flag[] = "permessagedeflate";
|
||||
|
||||
/// Default user agent string
|
||||
static char const user_agent[] = "WebSocket++/0.5.1";
|
||||
static char const user_agent[] = "WebSocketpp/0.6.0-permessagedeflate";
|
||||
|
||||
} // namespace websocketpp
|
||||
|
||||
|
||||
Reference in New Issue
Block a user