Compare commits
175
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 | ||
|
|
ac5d7ea5af | ||
|
|
6f7ecc59cd | ||
|
|
f7cea42c92 | ||
|
|
9efb12e59b | ||
|
|
174698f1df | ||
|
|
214cedf949 | ||
|
|
c39412ee38 | ||
|
|
643e7a0ce1 | ||
|
|
349717ad46 | ||
|
|
bcd82bd6f4 | ||
|
|
8f042d95ec | ||
|
|
0278ba7895 | ||
|
|
41c37cfd93 | ||
|
|
4bea90f555 | ||
|
|
f9b08ccea1 | ||
|
|
ce0300e6dc | ||
|
|
f20b2e573f | ||
|
|
650e4c336b | ||
|
|
31c761a0a9 | ||
|
|
681c2331a1 | ||
|
|
fccc78479e | ||
|
|
3017a9c5e4 | ||
|
|
d55f28fe4b | ||
|
|
a8d4a9a66a | ||
|
|
17544d4d62 | ||
|
|
4d1693c96c | ||
|
|
875d420952 | ||
|
|
d792639c20 | ||
|
|
d4e15c89ad | ||
|
|
1d29d48bb8 | ||
|
|
09c5f6505e | ||
|
|
745ed4f77a | ||
|
|
854166364b | ||
|
|
1517d646f9 | ||
|
|
6bb36a28e7 | ||
|
|
96362774a3 | ||
|
|
0a879a6dc2 | ||
|
|
867b323af0 | ||
|
|
9dd99ead25 | ||
|
|
e3884e351b | ||
|
|
23e97bcc11 | ||
|
|
77e2e2fabb | ||
|
|
ef393f8aef | ||
|
|
99f4a66221 | ||
|
|
768472c0d4 | ||
|
|
1f061a920e | ||
|
|
07543a5dde | ||
|
|
ff9af5f8ca | ||
|
|
ffedb97372 | ||
|
|
e1f1c8873b | ||
|
|
922f1c35bc | ||
|
|
3c6c757d93 | ||
|
|
71f88c71d6 | ||
|
|
987f20feda | ||
|
|
27cea4e58f | ||
|
|
e7b2e69ecb | ||
|
|
bc868a244d | ||
|
|
77f1bf593d | ||
|
|
0a47a9a78c | ||
|
|
6578c5852e | ||
|
|
f9ff42c4b0 | ||
|
|
b9d4187e38 | ||
|
|
cbe887524e | ||
|
|
8a9b0beec0 | ||
|
|
18994f7318 | ||
|
|
3f65b2ff98 | ||
|
|
0ad2da2083 | ||
|
|
7404b506db | ||
|
|
b0efc72848 | ||
|
|
beac6e5bb6 | ||
|
|
f6c6552622 | ||
|
|
12700f2bc2 | ||
|
|
8cbe22266d | ||
|
|
c23639d394 | ||
|
|
d3ba1187de | ||
|
|
02b53d979e | ||
|
|
1d598558d8 | ||
|
|
ff3009ed26 | ||
|
|
d1f3eb9516 | ||
|
|
c0dc3c0e5f | ||
|
|
bfbfe2b052 | ||
|
|
1edc8deb01 | ||
|
|
571be82531 | ||
|
|
9ab9941f5e | ||
|
|
7dfe0d5815 | ||
|
|
088625eb53 | ||
|
|
575834b534 | ||
|
|
02dd5150fc | ||
|
|
2917d9262c | ||
|
|
fbc2966cda | ||
|
|
9de0a087b3 | ||
|
|
e9dd9cbbeb | ||
|
|
dc7431c37f | ||
|
|
5fe6f8338d | ||
|
|
19f7886ca4 | ||
|
|
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 |
No files matched your search
@@ -32,11 +32,15 @@ install_manifest.txt
|
||||
*.ncb
|
||||
*/Debug/*
|
||||
*/*/Debug/*
|
||||
bin/Debug
|
||||
*/Release/*
|
||||
*/*/Release/*
|
||||
*/RelWithDebInfo/*
|
||||
*/*/RelWithDebInfo/*
|
||||
|
||||
# explicitly allow this path with /debug/ in it
|
||||
!websocketpp/transport/debug/*
|
||||
|
||||
objs_shared/
|
||||
objs_static/
|
||||
|
||||
|
||||
+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
|
||||
|
||||
+4
-4
@@ -9,7 +9,7 @@ project (websocketpp)
|
||||
cmake_minimum_required (VERSION 2.6)
|
||||
|
||||
set (WEBSOCKETPP_MAJOR_VERSION 0)
|
||||
set (WEBSOCKETPP_MINOR_VERSION 4)
|
||||
set (WEBSOCKETPP_MINOR_VERSION 6)
|
||||
set (WEBSOCKETPP_PATCH_VERSION 0)
|
||||
set (WEBSOCKETPP_VERSION ${WEBSOCKETPP_MAJOR_VERSION}.${WEBSOCKETPP_MINOR_VERSION}.${WEBSOCKETPP_PATCH_VERSION})
|
||||
|
||||
@@ -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.4.0"
|
||||
|
||||
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
|
||||
@@ -974,7 +972,7 @@ HTML_COLORSTYLE_GAMMA = 148
|
||||
# page will contain the date and time when the page was generated. Setting
|
||||
# this to NO can help when comparing the output of multiple runs.
|
||||
|
||||
HTML_TIMESTAMP = YES
|
||||
HTML_TIMESTAMP = NO
|
||||
|
||||
# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
|
||||
# documentation will contain sections that can be hidden and shown after the
|
||||
|
||||
+23
-2
@@ -110,8 +110,22 @@ elif env['CXX'].startswith('clang++'):
|
||||
env.Append(CCFLAGS = ['-Wshadow'])
|
||||
env.Append(CCFLAGS = ['-Wunused-parameter'])
|
||||
|
||||
env.Append(CCFLAGS = ['-Wsometimes-uninitialized'])
|
||||
env.Append(CCFLAGS = ['-Wuninitialized'])
|
||||
|
||||
#env.Append(CCFLAGS = ['-Weverything'])
|
||||
#env.Append(CCFLAGS = ['-Wno-documentation'])
|
||||
#env.Append(CCFLAGS = ['-Wno-weak-vtables'])
|
||||
#env.Append(CCFLAGS = ['-Wno-global-constructors'])
|
||||
#env.Append(CCFLAGS = ['-Wno-sign-conversion'])
|
||||
#env.Append(CCFLAGS = ['-Wno-exit-time-destructors'])
|
||||
|
||||
|
||||
|
||||
|
||||
# Wpadded
|
||||
# Wsign-conversion
|
||||
#
|
||||
|
||||
platform_libs = []
|
||||
tls_libs = []
|
||||
@@ -227,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)
|
||||
@@ -239,6 +257,9 @@ debug_server = SConscript('#/examples/debug_server/SConscript',variant_dir = bui
|
||||
# subprotocol_server
|
||||
subprotocol_server = SConscript('#/examples/subprotocol_server/SConscript',variant_dir = builddir + 'subprotocol_server',duplicate = 0)
|
||||
|
||||
# telemetry_server
|
||||
telemetry_server = SConscript('#/examples/telemetry_server/SConscript',variant_dir = builddir + 'telemetry_server',duplicate = 0)
|
||||
|
||||
if not env['PLATFORM'].startswith('win'):
|
||||
# iostream_server
|
||||
iostream_server = SConscript('#/examples/iostream_server/SConscript',variant_dir = builddir + 'iostream_server',duplicate = 0)
|
||||
|
||||
+96
-1
@@ -1,3 +1,98 @@
|
||||
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 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
|
||||
- BREAKING UTILITY CHANGE: Deprecated methods `http::parser::parse_headers`,
|
||||
`http::response::parse_complete`, and `http::request::parse_complete` have
|
||||
been removed.
|
||||
- Security: Disabled SSLv3 in example servers.
|
||||
- Feature: Adds basic support for accessing HTTP request bodies in the http
|
||||
handler. #181
|
||||
- Feature: Adds the ability to register a shutdown handler when using the
|
||||
iostream transport. This provides a clean interface for triggering the shut
|
||||
down of external sockets and other cleanup without hooking in to higher level
|
||||
WebSocket handlers.
|
||||
- Feature: Adds the ability to register a write handler when using the iostream
|
||||
transport. This handler can be used to handle transport output in place of
|
||||
registering an ostream to write to.
|
||||
- Feature: Adds a new logging policy that outputs to syslog. #386 Thank you Tom
|
||||
Hughes for submitting the initial version of this policy.
|
||||
- Improvement: Message payload logging now prints text for text messages rather
|
||||
than binary.
|
||||
- Improvement: Overhaul of handshake state machine. Should make it impossible
|
||||
for exceptions to bubble out of transport methods like `io_service::run`.
|
||||
- Improvement: Overhaul of handshake error reporting. Fail handler error codes
|
||||
will be more detailed and precise. Adds new [fail] and [http] logging channels
|
||||
that log failed websocket connections and successful HTTP connections
|
||||
respectively. A new aggregate channel package, `alevel::access_core`, allows
|
||||
enabling connect, disconnect, fail, and http together. Successful HTTP
|
||||
connections will no longer trigger a fail handler.
|
||||
- Improvement: Ability to terminate connection during an http handler to cleanly
|
||||
suppress the default outgoing HTTP response.
|
||||
- Documentation: Add Sending & Receiving Messages step to chapter one of the
|
||||
`utility_client` tutorial. Update `utility_client` example to match.
|
||||
- Cleanup: Removes unused files & STL includes. Adds required STL includes.
|
||||
Normalizes include order.
|
||||
- Bug: Fixes a fatal state error when a handshake response is completed
|
||||
immediately after that handshake times out. #389
|
||||
- Bug: MinGW fixes; C++11 feature detection, localtime use. #393 Thank you
|
||||
Schebb for reporting, code, and testing.
|
||||
- Bug: Fixes an issue where `websocketpp::exception::what()` could return an out
|
||||
of scope pointer. #397 Thank you fabioang for reporting.
|
||||
- Bug: Fixes an issue where endpoints were not reset properly after a call to
|
||||
`endpoint::listen` failed. #390 Thank you wyyqyl for reporting.
|
||||
|
||||
0.4.0 - 2014-11-04
|
||||
- BREAKING API CHANGE: All WebSocket++ methods now throw an exception of type
|
||||
`websocketpp::exception` which derives from `std::exception`. This normalizes
|
||||
@@ -174,7 +269,7 @@
|
||||
- Change default HTTP response error code when no http_handler is defined from
|
||||
500/Internal Server Error to 426/Upgrade Required
|
||||
- Remove timezone from logger timestamp to work around issues with the Windows
|
||||
implimentation of strftime. Thank you breyed for testing and code. #257
|
||||
implementation of strftime. Thank you breyed for testing and code. #257
|
||||
- Switch integer literals to char literals to improve VCPP compatibility.
|
||||
Thank you breyed for testing and code. #257
|
||||
- Add MSVCPP warning suppression for the bundled SHA1 library. Thank you breyed
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#include <websocketpp/server.hpp>
|
||||
|
||||
#include <iostream>
|
||||
#include <set>
|
||||
|
||||
/*#include <boost/thread.hpp>
|
||||
#include <boost/thread/mutex.hpp>
|
||||
@@ -66,10 +67,6 @@ public:
|
||||
m_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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -130,7 +127,7 @@ public:
|
||||
}
|
||||
}
|
||||
private:
|
||||
typedef std::set<connection_hdl,std::owner_less<connection_hdl>> con_list;
|
||||
typedef std::set<connection_hdl,std::owner_less<connection_hdl> > con_list;
|
||||
|
||||
server m_server;
|
||||
con_list m_connections;
|
||||
@@ -153,7 +150,7 @@ int main() {
|
||||
|
||||
t.join();
|
||||
|
||||
} catch (std::exception & e) {
|
||||
} catch (websocketpp::exception const & e) {
|
||||
std::cout << e.what() << std::endl;
|
||||
}
|
||||
}
|
||||
@@ -36,7 +36,7 @@
|
||||
#include <iostream>
|
||||
#include <chrono>
|
||||
|
||||
typedef websocketpp::client<websocketpp::config::asio_tls_client> client;
|
||||
typedef websocketpp::client<websocketpp::config::asio_client> client;
|
||||
|
||||
using websocketpp::lib::placeholders::_1;
|
||||
using websocketpp::lib::placeholders::_2;
|
||||
@@ -63,10 +63,11 @@ public:
|
||||
|
||||
// Register our handlers
|
||||
m_endpoint.set_socket_init_handler(bind(&type::on_socket_init,this,::_1));
|
||||
m_endpoint.set_tls_init_handler(bind(&type::on_tls_init,this,::_1));
|
||||
//m_endpoint.set_tls_init_handler(bind(&type::on_tls_init,this,::_1));
|
||||
m_endpoint.set_message_handler(bind(&type::on_message,this,::_1,::_2));
|
||||
m_endpoint.set_open_handler(bind(&type::on_open,this,::_1));
|
||||
m_endpoint.set_close_handler(bind(&type::on_close,this,::_1));
|
||||
m_endpoint.set_fail_handler(bind(&type::on_fail,this,::_1));
|
||||
}
|
||||
|
||||
void start(std::string uri) {
|
||||
@@ -97,6 +98,7 @@ public:
|
||||
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);
|
||||
} catch (std::exception& e) {
|
||||
std::cout << e.what() << std::endl;
|
||||
@@ -104,6 +106,18 @@ public:
|
||||
return ctx;
|
||||
}
|
||||
|
||||
void on_fail(websocketpp::connection_hdl hdl) {
|
||||
client::connection_ptr con = m_endpoint.get_con_from_hdl(hdl);
|
||||
|
||||
std::cout << "Fail handler" << std::endl;
|
||||
std::cout << con->get_state() << std::endl;
|
||||
std::cout << con->get_local_close_code() << std::endl;
|
||||
std::cout << con->get_local_close_reason() << std::endl;
|
||||
std::cout << con->get_remote_close_code() << std::endl;
|
||||
std::cout << con->get_remote_close_reason() << std::endl;
|
||||
std::cout << con->get_ec() << " - " << con->get_ec().message() << std::endl;
|
||||
}
|
||||
|
||||
void on_open(websocketpp::connection_hdl hdl) {
|
||||
m_open = std::chrono::high_resolution_clock::now();
|
||||
m_endpoint.send(hdl, "", websocketpp::frame::opcode::text);
|
||||
|
||||
@@ -31,11 +31,60 @@
|
||||
|
||||
#include <websocketpp/config/debug_asio_no_tls.hpp>
|
||||
|
||||
// Custom logger
|
||||
#include <websocketpp/logger/syslog.hpp>
|
||||
|
||||
#include <websocketpp/server.hpp>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
typedef websocketpp::server<websocketpp::config::debug_asio> server;
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
///////////////// Custom Config for debugging custom policies //////////////////
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
struct debug_custom : public websocketpp::config::debug_asio {
|
||||
typedef debug_custom type;
|
||||
typedef debug_asio 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;
|
||||
|
||||
/// Custom Logging policies
|
||||
/*typedef websocketpp::log::syslog<concurrency_type,
|
||||
websocketpp::log::elevel> elog_type;
|
||||
typedef websocketpp::log::syslog<concurrency_type,
|
||||
websocketpp::log::alevel> alog_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;
|
||||
|
||||
static const long timeout_open_handshake = 0;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
typedef websocketpp::server<debug_custom> server;
|
||||
|
||||
using websocketpp::lib::placeholders::_1;
|
||||
using websocketpp::lib::placeholders::_2;
|
||||
@@ -44,6 +93,33 @@ using websocketpp::lib::bind;
|
||||
// pull out the type of messages sent by our config
|
||||
typedef server::message_ptr message_ptr;
|
||||
|
||||
bool validate(server *, websocketpp::connection_hdl) {
|
||||
//sleep(6);
|
||||
return true;
|
||||
}
|
||||
|
||||
void on_http(server* s, websocketpp::connection_hdl hdl) {
|
||||
server::connection_ptr con = s->get_con_from_hdl(hdl);
|
||||
|
||||
std::string res = con->get_request_body();
|
||||
|
||||
std::stringstream ss;
|
||||
ss << "got HTTP request with " << res.size() << " bytes of body data.";
|
||||
|
||||
con->set_body(ss.str());
|
||||
con->set_status(websocketpp::http::status_code::ok);
|
||||
}
|
||||
|
||||
void on_fail(server* s, websocketpp::connection_hdl hdl) {
|
||||
server::connection_ptr con = s->get_con_from_hdl(hdl);
|
||||
|
||||
std::cout << "Fail handler: " << con->get_ec() << " " << con->get_ec().message() << std::endl;
|
||||
}
|
||||
|
||||
void on_close(websocketpp::connection_hdl) {
|
||||
std::cout << "Close handler" << std::endl;
|
||||
}
|
||||
|
||||
// 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()
|
||||
@@ -74,6 +150,12 @@ int main() {
|
||||
// Register our message handler
|
||||
echo_server.set_message_handler(bind(&on_message,&echo_server,::_1,::_2));
|
||||
|
||||
echo_server.set_http_handler(bind(&on_http,&echo_server,::_1));
|
||||
echo_server.set_fail_handler(bind(&on_fail,&echo_server,::_1));
|
||||
echo_server.set_close_handler(&on_close);
|
||||
|
||||
echo_server.set_validate_handler(bind(&validate,&echo_server,::_1));
|
||||
|
||||
// Listen on port 9012
|
||||
echo_server.listen(9012);
|
||||
|
||||
|
||||
@@ -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) {
|
||||
@@ -50,10 +57,8 @@ int main() {
|
||||
|
||||
// Start the ASIO io_service run loop
|
||||
echo_server.run();
|
||||
} catch (const std::exception & e) {
|
||||
} catch (websocketpp::exception const & 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;
|
||||
}
|
||||
|
||||
@@ -46,6 +46,7 @@ context_ptr on_tls_init(websocketpp::connection_hdl hdl) {
|
||||
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);
|
||||
ctx->set_password_callback(bind(&get_password));
|
||||
ctx->use_certificate_chain_file("server.pem");
|
||||
|
||||
@@ -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,23 +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::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;
|
||||
}
|
||||
@@ -57,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-----
|
||||
|
||||
@@ -82,12 +82,8 @@ int main() {
|
||||
}
|
||||
con->eof();
|
||||
}
|
||||
} catch (const std::exception & e) {
|
||||
} catch (websocketpp::exception const & 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;
|
||||
}
|
||||
log.close();
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -78,11 +78,7 @@ int main(int argc, char* argv[]) {
|
||||
|
||||
std::cout << "done" << std::endl;
|
||||
|
||||
} catch (const std::exception & e) {
|
||||
} catch (websocketpp::exception const & 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;
|
||||
}
|
||||
}
|
||||
@@ -42,11 +42,7 @@ int main() {
|
||||
s.start_accept();
|
||||
|
||||
s.run();
|
||||
} catch (const std::exception & e) {
|
||||
} catch (websocketpp::exception const & 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
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
|
||||
file (GLOB SOURCE_FILES *.cpp)
|
||||
file (GLOB HEADER_FILES *.hpp)
|
||||
|
||||
init_target (telemetry_server)
|
||||
|
||||
build_executable (${TARGET_NAME} ${SOURCE_FILES} ${HEADER_FILES})
|
||||
|
||||
link_boost ()
|
||||
final_target ()
|
||||
@@ -0,0 +1,23 @@
|
||||
## Main development example
|
||||
##
|
||||
|
||||
Import('env')
|
||||
Import('env_cpp11')
|
||||
Import('boostlibs')
|
||||
Import('platform_libs')
|
||||
Import('polyfill_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]
|
||||
prgs += env_cpp11.Program('telemetry_server', ["telemetry_server.cpp"], LIBS = ALL_LIBS)
|
||||
else:
|
||||
ALL_LIBS = boostlibs(['system'],env) + [platform_libs] + [polyfill_libs]
|
||||
prgs += env.Program('telemetry_server', ["telemetry_server.cpp"], LIBS = ALL_LIBS)
|
||||
|
||||
Return('prgs')
|
||||
@@ -0,0 +1,85 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<title>WebSocket++ Telemetry Client</title>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<script type="text/javascript">
|
||||
var ws;
|
||||
var url;
|
||||
|
||||
function connect() {
|
||||
url = document.getElementById("server_url").value;
|
||||
|
||||
if ("WebSocket" in window) {
|
||||
ws = new WebSocket(url);
|
||||
} else if ("MozWebSocket" in window) {
|
||||
ws = new MozWebSocket(url);
|
||||
} else {
|
||||
document.getElementById("messages").innerHTML += "This Browser does not support WebSockets<br />";
|
||||
return;
|
||||
}
|
||||
ws.onopen = function(e) {
|
||||
document.getElementById("messages").innerHTML += "Client: A connection to "+ws.url+" has been opened.<br />";
|
||||
|
||||
document.getElementById("server_url").disabled = true;
|
||||
document.getElementById("toggle_connect").innerHTML = "Disconnect";
|
||||
};
|
||||
|
||||
ws.onerror = function(e) {
|
||||
document.getElementById("messages").innerHTML += "Client: An error occured, see console log for more details.<br />";
|
||||
console.log(e);
|
||||
};
|
||||
|
||||
ws.onclose = function(e) {
|
||||
document.getElementById("messages").innerHTML += "Client: The connection to "+url+" was closed. ["+e.code+(e.reason != "" ? ","+e.reason : "")+"]<br />";
|
||||
cleanup_disconnect();
|
||||
};
|
||||
|
||||
ws.onmessage = function(e) {
|
||||
document.getElementById("messages").innerHTML += "Server: "+e.data+"<br />";
|
||||
};
|
||||
}
|
||||
|
||||
function disconnect() {
|
||||
ws.close();
|
||||
cleanup_disconnect();
|
||||
}
|
||||
|
||||
function cleanup_disconnect() {
|
||||
document.getElementById("server_url").disabled = false;
|
||||
document.getElementById("toggle_connect").innerHTML = "Connect";
|
||||
}
|
||||
|
||||
function toggle_connect() {
|
||||
if (document.getElementById("server_url").disabled === false) {
|
||||
connect();
|
||||
} else {
|
||||
disconnect();
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
body,html {
|
||||
margin: 0px;
|
||||
padding: 0px;
|
||||
}
|
||||
#controls {
|
||||
float:right;
|
||||
background-color: #999;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
<div id="controls">
|
||||
<div id="server">
|
||||
<input type="text" name="server_url" id="server_url" value="ws://localhost:9002" /><br />
|
||||
<button id="toggle_connect" onclick="toggle_connect();">Connect</button>
|
||||
</div>
|
||||
</div>
|
||||
<div id="messages"></div>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,204 @@
|
||||
#include <websocketpp/config/asio_no_tls.hpp>
|
||||
|
||||
#include <websocketpp/server.hpp>
|
||||
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <set>
|
||||
#include <streambuf>
|
||||
#include <string>
|
||||
|
||||
/**
|
||||
* The telemetry server accepts connections and sends a message every second to
|
||||
* each client containing an integer count. This example can be used as the
|
||||
* basis for programs that expose a stream of telemetry data for logging,
|
||||
* dashboards, etc.
|
||||
*
|
||||
* This example uses the timer based concurrency method and is self contained
|
||||
* and singled threaded. Refer to telemetry client for an example of a similar
|
||||
* telemetry setup using threads rather than timers.
|
||||
*
|
||||
* This example also includes an example simple HTTP server that serves a web
|
||||
* dashboard displaying the count. This simple design is suitable for use
|
||||
* delivering a small number of files to a small number of clients. It is ideal
|
||||
* for cases like embedded dashboards that don't want the complexity of an extra
|
||||
* HTTP server to serve static files.
|
||||
*
|
||||
* This design *will* fall over under high traffic or DoS conditions. In such
|
||||
* cases you are much better off proxying to a real HTTP server for the http
|
||||
* requests.
|
||||
*/
|
||||
class telemetry_server {
|
||||
public:
|
||||
typedef websocketpp::connection_hdl connection_hdl;
|
||||
typedef websocketpp::server<websocketpp::config::asio> server;
|
||||
typedef websocketpp::lib::lock_guard<websocketpp::lib::mutex> scoped_lock;
|
||||
|
||||
telemetry_server() : m_count(0) {
|
||||
// set up access channels to only log interesting things
|
||||
m_endpoint.clear_access_channels(websocketpp::log::alevel::all);
|
||||
m_endpoint.set_access_channels(websocketpp::log::alevel::access_core);
|
||||
m_endpoint.set_access_channels(websocketpp::log::alevel::app);
|
||||
|
||||
// Initialize the Asio transport policy
|
||||
m_endpoint.init_asio();
|
||||
|
||||
// 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));
|
||||
}
|
||||
|
||||
void run(std::string docroot, uint16_t port) {
|
||||
std::stringstream ss;
|
||||
ss << "Running telemetry server on port "<< port <<" using docroot=" << docroot;
|
||||
m_endpoint.get_alog().write(websocketpp::log::alevel::app,ss.str());
|
||||
|
||||
m_docroot = docroot;
|
||||
|
||||
// listen on specified port
|
||||
m_endpoint.listen(port);
|
||||
|
||||
// Start the server accept loop
|
||||
m_endpoint.start_accept();
|
||||
|
||||
// Set the initial timer to start telemetry
|
||||
set_timer();
|
||||
|
||||
// Start the ASIO io_service run loop
|
||||
try {
|
||||
m_endpoint.run();
|
||||
} catch (websocketpp::exception const & e) {
|
||||
std::cout << e.what() << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
void set_timer() {
|
||||
m_timer = m_endpoint.set_timer(
|
||||
1000,
|
||||
websocketpp::lib::bind(
|
||||
&telemetry_server::on_timer,
|
||||
this,
|
||||
websocketpp::lib::placeholders::_1
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
void on_timer(websocketpp::lib::error_code const & ec) {
|
||||
if (ec) {
|
||||
// there was an error, stop telemetry
|
||||
m_endpoint.get_alog().write(websocketpp::log::alevel::app,
|
||||
"Timer Error: "+ec.message());
|
||||
return;
|
||||
}
|
||||
|
||||
std::stringstream val;
|
||||
val << "count is " << m_count++;
|
||||
|
||||
// Broadcast count to all connections
|
||||
con_list::iterator it;
|
||||
for (it = m_connections.begin(); it != m_connections.end(); ++it) {
|
||||
m_endpoint.send(*it,val.str(),websocketpp::frame::opcode::text);
|
||||
}
|
||||
|
||||
// set timer for next telemetry check
|
||||
set_timer();
|
||||
}
|
||||
|
||||
void on_http(connection_hdl hdl) {
|
||||
// Upgrade our connection handle to a full connection_ptr
|
||||
server::connection_ptr con = m_endpoint.get_con_from_hdl(hdl);
|
||||
|
||||
std::ifstream file;
|
||||
std::string filename = con->get_uri()->get_resource();
|
||||
std::string response;
|
||||
|
||||
m_endpoint.get_alog().write(websocketpp::log::alevel::app,
|
||||
"http request1: "+filename);
|
||||
|
||||
if (filename == "/") {
|
||||
filename = m_docroot+"index.html";
|
||||
} else {
|
||||
filename = m_docroot+filename.substr(1);
|
||||
}
|
||||
|
||||
m_endpoint.get_alog().write(websocketpp::log::alevel::app,
|
||||
"http request2: "+filename);
|
||||
|
||||
file.open(filename.c_str(), std::ios::in);
|
||||
if (!file) {
|
||||
// 404 error
|
||||
std::stringstream ss;
|
||||
|
||||
ss << "<!doctype html><html><head>"
|
||||
<< "<title>Error 404 (Resource not found)</title><body>"
|
||||
<< "<h1>Error 404</h1>"
|
||||
<< "<p>The requested URL " << filename << " was not found on this server.</p>"
|
||||
<< "</body></head></html>";
|
||||
|
||||
con->set_body(ss.str());
|
||||
con->set_status(websocketpp::http::status_code::not_found);
|
||||
return;
|
||||
}
|
||||
|
||||
file.seekg(0, std::ios::end);
|
||||
response.reserve(file.tellg());
|
||||
file.seekg(0, std::ios::beg);
|
||||
|
||||
response.assign((std::istreambuf_iterator<char>(file)),
|
||||
std::istreambuf_iterator<char>());
|
||||
|
||||
con->set_body(response);
|
||||
con->set_status(websocketpp::http::status_code::ok);
|
||||
}
|
||||
|
||||
void on_open(connection_hdl hdl) {
|
||||
m_connections.insert(hdl);
|
||||
}
|
||||
|
||||
void on_close(connection_hdl hdl) {
|
||||
m_connections.erase(hdl);
|
||||
}
|
||||
private:
|
||||
typedef std::set<connection_hdl,std::owner_less<connection_hdl>> con_list;
|
||||
|
||||
server m_endpoint;
|
||||
con_list m_connections;
|
||||
server::timer_ptr m_timer;
|
||||
|
||||
std::string m_docroot;
|
||||
|
||||
// Telemetry data
|
||||
uint64_t m_count;
|
||||
};
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
telemetry_server s;
|
||||
|
||||
std::string docroot;
|
||||
uint16_t port = 9002;
|
||||
|
||||
if (argc == 1) {
|
||||
std::cout << "Usage: telemetry_server [documentroot] [port]" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (argc >= 2) {
|
||||
docroot = std::string(argv[1]);
|
||||
}
|
||||
|
||||
if (argc >= 3) {
|
||||
int i = atoi(argv[2]);
|
||||
if (i <= 0 || i > 65535) {
|
||||
std::cout << "invalid port" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
port = uint16_t(i);
|
||||
}
|
||||
|
||||
s.run(docroot, port);
|
||||
return 0;
|
||||
}
|
||||
@@ -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;
|
||||
@@ -74,11 +139,7 @@ int main(int argc, char* argv[]) {
|
||||
|
||||
std::cout << "done" << std::endl;
|
||||
|
||||
} catch (const std::exception & e) {
|
||||
} catch (websocketpp::exception const & 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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
@@ -132,11 +139,7 @@ int main(int argc, char * argv[]) {
|
||||
}
|
||||
}
|
||||
|
||||
} catch (const std::exception & e) {
|
||||
} catch (websocketpp::exception const & e) {
|
||||
std::cout << "exception: " << e.what() << std::endl;
|
||||
} catch (websocketpp::lib::error_code e) {
|
||||
std::cout << "error code: " << e.message() << std::endl;
|
||||
} catch (...) {
|
||||
std::cout << "other exception" << std::endl;
|
||||
}
|
||||
}
|
||||
@@ -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')
|
||||
@@ -79,6 +79,14 @@ public:
|
||||
m_error_reason = s.str();
|
||||
}
|
||||
|
||||
void on_message(websocketpp::connection_hdl, client::message_ptr msg) {
|
||||
if (msg->get_opcode() == websocketpp::frame::opcode::text) {
|
||||
m_messages.push_back("<< " + msg->get_payload());
|
||||
} else {
|
||||
m_messages.push_back("<< " + websocketpp::utility::to_hex(msg->get_payload()));
|
||||
}
|
||||
}
|
||||
|
||||
websocketpp::connection_hdl get_hdl() const {
|
||||
return m_hdl;
|
||||
}
|
||||
@@ -91,6 +99,10 @@ public:
|
||||
return m_status;
|
||||
}
|
||||
|
||||
void record_sent_message(std::string message) {
|
||||
m_messages.push_back(">> " + message);
|
||||
}
|
||||
|
||||
friend std::ostream & operator<< (std::ostream & out, connection_metadata const & data);
|
||||
private:
|
||||
int m_id;
|
||||
@@ -99,13 +111,20 @@ private:
|
||||
std::string m_uri;
|
||||
std::string m_server;
|
||||
std::string m_error_reason;
|
||||
std::vector<std::string> m_messages;
|
||||
};
|
||||
|
||||
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);
|
||||
<< "> Error/close reason: " << (data.m_error_reason.empty() ? "N/A" : data.m_error_reason) << "\n";
|
||||
out << "> Messages Processed: (" << data.m_messages.size() << ") \n";
|
||||
|
||||
std::vector<std::string>::const_iterator it;
|
||||
for (it = data.m_messages.begin(); it != data.m_messages.end(); ++it) {
|
||||
out << *it << "\n";
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
@@ -176,6 +195,12 @@ public:
|
||||
&m_endpoint,
|
||||
websocketpp::lib::placeholders::_1
|
||||
));
|
||||
con->set_message_handler(websocketpp::lib::bind(
|
||||
&connection_metadata::on_message,
|
||||
metadata_ptr,
|
||||
websocketpp::lib::placeholders::_1,
|
||||
websocketpp::lib::placeholders::_2
|
||||
));
|
||||
|
||||
m_endpoint.connect(con);
|
||||
|
||||
@@ -197,6 +222,24 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
void send(int id, std::string message) {
|
||||
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.send(metadata_it->second->get_hdl(), message, websocketpp::frame::opcode::text, ec);
|
||||
if (ec) {
|
||||
std::cout << "> Error sending message: " << ec.message() << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
metadata_it->second->record_sent_message(message);
|
||||
}
|
||||
|
||||
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()) {
|
||||
@@ -230,6 +273,7 @@ int main() {
|
||||
std::cout
|
||||
<< "\nCommand List:\n"
|
||||
<< "connect <ws uri>\n"
|
||||
<< "send <connection id> <message>\n"
|
||||
<< "close <connection id> [<close code:default=1000>] [<close reason>]\n"
|
||||
<< "show <connection id>\n"
|
||||
<< "help: Display this help text\n"
|
||||
@@ -240,6 +284,17 @@ int main() {
|
||||
if (id != -1) {
|
||||
std::cout << "> Created connection with id " << id << std::endl;
|
||||
}
|
||||
} else if (input.substr(0,4) == "send") {
|
||||
std::stringstream ss(input);
|
||||
|
||||
std::string cmd;
|
||||
int id;
|
||||
std::string message = "";
|
||||
|
||||
ss >> cmd >> id;
|
||||
std::getline(ss,message);
|
||||
|
||||
endpoint.send(id, message);
|
||||
} else if (input.substr(0,5) == "close") {
|
||||
std::stringstream ss(input);
|
||||
|
||||
@@ -252,7 +307,7 @@ int main() {
|
||||
std::getline(ss,reason);
|
||||
|
||||
endpoint.close(id, close_code, reason);
|
||||
} else if (input.substr(0,4) == "show") {
|
||||
} else if (input.substr(0,4) == "show") {
|
||||
int id = atoi(input.substr(5).c_str());
|
||||
|
||||
connection_metadata::ptr metadata = endpoint.get_metadata(id);
|
||||
@@ -267,4 +322,4 @@ int main() {
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,12 @@
|
||||
WebSocket++ (0.4.0)
|
||||
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/
|
||||
|
||||
|
||||
@@ -30,6 +30,10 @@
|
||||
|
||||
#include "connection_tu2.hpp"
|
||||
|
||||
// Include special debugging transport
|
||||
//#include <websocketpp/config/minimal_client.hpp>
|
||||
#include <websocketpp/transport/debug/endpoint.hpp>
|
||||
|
||||
// NOTE: these tests currently test against hardcoded output values. I am not
|
||||
// sure how problematic this will be. If issues arise like order of headers the
|
||||
// output should be parsed by http::response and have values checked directly
|
||||
@@ -79,6 +83,54 @@ struct stub_config : public websocketpp::config::core {
|
||||
typedef connection_extension connection_base;
|
||||
};
|
||||
|
||||
struct debug_config_client : public websocketpp::config::core {
|
||||
typedef debug_config_client type;
|
||||
|
||||
typedef core::concurrency_type concurrency_type;
|
||||
|
||||
typedef core::request_type request_type;
|
||||
typedef core::response_type response_type;
|
||||
|
||||
typedef core::message_type message_type;
|
||||
typedef core::con_msg_manager_type con_msg_manager_type;
|
||||
typedef core::endpoint_msg_manager_type endpoint_msg_manager_type;
|
||||
|
||||
typedef core::alog_type alog_type;
|
||||
typedef core::elog_type elog_type;
|
||||
|
||||
typedef websocketpp::random::none::int_generator<uint32_t> rng_type;
|
||||
|
||||
struct transport_config {
|
||||
typedef type::concurrency_type concurrency_type;
|
||||
typedef type::elog_type elog_type;
|
||||
typedef type::alog_type alog_type;
|
||||
typedef type::request_type request_type;
|
||||
typedef type::response_type response_type;
|
||||
|
||||
/// Controls compile time enabling/disabling of thread syncronization
|
||||
/// code Disabling can provide a minor performance improvement to single
|
||||
/// threaded applications
|
||||
static bool const enable_multithreading = true;
|
||||
|
||||
/// Default timer values (in ms)
|
||||
static const long timeout_socket_pre_init = 5000;
|
||||
static const long timeout_proxy = 5000;
|
||||
static const long timeout_socket_post_init = 5000;
|
||||
static const long timeout_connect = 5000;
|
||||
static const long timeout_socket_shutdown = 5000;
|
||||
};
|
||||
|
||||
/// Transport Endpoint Component
|
||||
typedef websocketpp::transport::debug::endpoint<transport_config>
|
||||
transport_type;
|
||||
|
||||
typedef core::endpoint_base endpoint_base;
|
||||
typedef connection_extension connection_base;
|
||||
|
||||
static const websocketpp::log::level elog_level = websocketpp::log::elevel::none;
|
||||
static const websocketpp::log::level alog_level = websocketpp::log::alevel::none;
|
||||
};
|
||||
|
||||
struct connection_setup {
|
||||
connection_setup(bool p_is_server) : c(p_is_server, "", alog, elog, rng) {}
|
||||
|
||||
@@ -89,6 +141,9 @@ struct connection_setup {
|
||||
websocketpp::connection<stub_config> c;
|
||||
};
|
||||
|
||||
typedef websocketpp::client<debug_config_client> debug_client;
|
||||
typedef websocketpp::server<debug_config_client> debug_server;
|
||||
|
||||
/*void echo_func(server* s, websocketpp::connection_hdl hdl, message_ptr msg) {
|
||||
s->send(hdl, msg->get_payload(), msg->get_opcode());
|
||||
}*/
|
||||
@@ -112,6 +167,38 @@ 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)
|
||||
{
|
||||
server::connection_ptr con = s->get_con_from_hdl(hdl);
|
||||
|
||||
BOOST_CHECK_EQUAL(ec, con->get_ec());
|
||||
called = true;
|
||||
}
|
||||
|
||||
void on_open_print(server* s, websocketpp::connection_hdl hdl)
|
||||
{
|
||||
server::connection_ptr con = s->get_con_from_hdl(hdl);
|
||||
|
||||
std::cout << con->get_uri() << std::endl;
|
||||
}
|
||||
|
||||
void fail_on_open(websocketpp::connection_hdl) {
|
||||
BOOST_CHECK(false);
|
||||
}
|
||||
void fail_on_http(websocketpp::connection_hdl) {
|
||||
BOOST_CHECK(false);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( connection_extensions ) {
|
||||
connection_setup env(true);
|
||||
|
||||
@@ -145,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";
|
||||
@@ -215,6 +340,80 @@ BOOST_AUTO_TEST_CASE( set_max_message_size ) {
|
||||
BOOST_CHECK_EQUAL(run_server_test(s,input), output);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( websocket_fail_parse_error ) {
|
||||
std::string input = "asdf\r\n\r\n";
|
||||
|
||||
server s;
|
||||
websocketpp::lib::error_code ec = make_error_code(websocketpp::error::http_parse_error);
|
||||
bool called = false;
|
||||
s.set_fail_handler(bind(&check_on_fail,&s,ec,websocketpp::lib::ref(called),::_1));
|
||||
|
||||
run_server_test(s,input,false);
|
||||
BOOST_CHECK(called);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( websocket_fail_invalid_version ) {
|
||||
std::string input = "GET / HTTP/1.1\r\nHost: www.example.com\r\nConnection: upgrade\r\nUpgrade: websocket\r\nSec-WebSocket-Version: foo\r\nSec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\nOrigin: http://www.example.com\r\n\r\n";
|
||||
|
||||
server s;
|
||||
websocketpp::lib::error_code ec = make_error_code(websocketpp::error::invalid_version);
|
||||
bool called = false;
|
||||
s.set_fail_handler(bind(&check_on_fail,&s,ec,websocketpp::lib::ref(called),::_1));
|
||||
|
||||
run_server_test(s,input,false);
|
||||
BOOST_CHECK(called);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( websocket_fail_unsupported_version ) {
|
||||
std::string input = "GET / HTTP/1.1\r\nHost: www.example.com\r\nConnection: upgrade\r\nUpgrade: websocket\r\nSec-WebSocket-Version: 12\r\nSec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\nOrigin: http://www.example.com\r\n\r\n";
|
||||
|
||||
server s;
|
||||
websocketpp::lib::error_code ec = make_error_code(websocketpp::error::unsupported_version);
|
||||
bool called = false;
|
||||
s.set_fail_handler(bind(&check_on_fail,&s,ec,websocketpp::lib::ref(called),::_1));
|
||||
|
||||
run_server_test(s,input,false);
|
||||
BOOST_CHECK(called);
|
||||
}
|
||||
|
||||
/*BOOST_AUTO_TEST_CASE( websocket_fail_invalid_uri ) {
|
||||
std::string input = "GET http://345.123.123.123/foo 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";
|
||||
|
||||
server s;
|
||||
websocketpp::lib::error_code ec = make_error_code(websocketpp::error::unsupported_version);
|
||||
bool called = false;
|
||||
s.set_fail_handler(bind(&check_on_fail,&s,ec,websocketpp::lib::ref(called),::_1));
|
||||
s.set_open_handler(bind(&on_open_print,&s,::_1));
|
||||
|
||||
std::cout << run_server_test(s,input,true) << std::endl;
|
||||
BOOST_CHECK(called);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( websocket_fail_invalid_uri_http ) {
|
||||
std::string input = "GET http://345.123.123.123/foo HTTP/1.1\r\nHost: www.example.com\r\nOrigin: http://www.example.com\r\n\r\n";
|
||||
|
||||
server s;
|
||||
websocketpp::lib::error_code ec = make_error_code(websocketpp::error::unsupported_version);
|
||||
bool called = false;
|
||||
s.set_fail_handler(bind(&check_on_fail,&s,ec,websocketpp::lib::ref(called),::_1));
|
||||
s.set_open_handler(bind(&on_open_print,&s,::_1));
|
||||
|
||||
std::cout << run_server_test(s,input,true) << std::endl;
|
||||
BOOST_CHECK(called);
|
||||
}*/
|
||||
|
||||
BOOST_AUTO_TEST_CASE( websocket_fail_upgrade_required ) {
|
||||
std::string input = "GET /foo/bar HTTP/1.1\r\nHost: www.example.com\r\nOrigin: http://www.example.com\r\n\r\n";
|
||||
|
||||
server s;
|
||||
websocketpp::lib::error_code ec = make_error_code(websocketpp::error::upgrade_required);
|
||||
bool called = false;
|
||||
s.set_fail_handler(bind(&check_on_fail,&s,ec,websocketpp::lib::ref(called),::_1));
|
||||
|
||||
run_server_test(s,input,false);
|
||||
BOOST_CHECK(called);
|
||||
}
|
||||
|
||||
// TODO: set max message size in client endpoint test case
|
||||
// TODO: set max message size mid connection test case
|
||||
// TODO: [maybe] set max message size in open handler
|
||||
@@ -239,3 +438,88 @@ BOOST_AUTO_TEST_CASE( basic_text_message ) {
|
||||
BOOST_CHECK( run_server_test(input) == output);
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
BOOST_AUTO_TEST_CASE( client_handshake_timeout_race1 ) {
|
||||
debug_client c;
|
||||
|
||||
websocketpp::lib::error_code ec;
|
||||
debug_client::connection_ptr con = c.get_connection("ws://localhost:9002", ec);
|
||||
|
||||
BOOST_CHECK(!ec);
|
||||
|
||||
// This test the case where a handshake times out immediately before the
|
||||
// handler that would have completed it gets invoked. This situation happens
|
||||
// when clients are connecting to overloaded servers and on servers that are
|
||||
// overloaded.
|
||||
c.connect(con);
|
||||
|
||||
con->expire_timer(websocketpp::lib::error_code());
|
||||
// Fullfil the write to simulate the write completing immediately after
|
||||
// timer expires
|
||||
con->fullfil_write();
|
||||
|
||||
BOOST_CHECK_EQUAL(con->get_ec(), make_error_code(websocketpp::error::open_handshake_timeout));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( client_handshake_timeout_race2 ) {
|
||||
debug_client c;
|
||||
|
||||
websocketpp::lib::error_code ec;
|
||||
debug_client::connection_ptr con = c.get_connection("ws://localhost:9002", ec);
|
||||
|
||||
BOOST_CHECK(!ec);
|
||||
|
||||
std::string output = "HTTP/1.1 101 Switching Protocols\r\nConnection: upgrade\r\nSec-WebSocket-Accept: ICX+Yqv66kxgM0FcWaLWlFLwTAI=\r\nServer: foo\r\nUpgrade: websocket\r\n\r\n";
|
||||
|
||||
// This test the case where a handshake times out immediately before the
|
||||
// handler that would have completed it gets invoked. This situation happens
|
||||
// when clients are connecting to overloaded servers and on servers that are
|
||||
// overloaded.
|
||||
c.connect(con);
|
||||
con->fullfil_write();
|
||||
|
||||
con->expire_timer(websocketpp::lib::error_code());
|
||||
// Read valid handshake to simulate receiving the handshake response
|
||||
// immediately after the timer expires
|
||||
con->read_all(output.data(),output.size());
|
||||
|
||||
BOOST_CHECK_EQUAL(con->get_ec(), make_error_code(websocketpp::error::open_handshake_timeout));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( server_handshake_timeout_race1 ) {
|
||||
debug_server s;
|
||||
|
||||
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: AAAAAAAAAAAAAAAAAAAAAA==\r\n\r\n";
|
||||
|
||||
debug_server::connection_ptr con = s.get_connection();
|
||||
con->start();
|
||||
|
||||
con->expire_timer(websocketpp::lib::error_code());
|
||||
// Read handshake immediately after timer expire
|
||||
con->read_all(input.data(), input.size());
|
||||
|
||||
BOOST_CHECK_EQUAL(con->get_ec(), make_error_code(websocketpp::error::open_handshake_timeout));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( server_handshake_timeout_race2 ) {
|
||||
debug_server s;
|
||||
|
||||
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: AAAAAAAAAAAAAAAAAAAAAA==\r\n\r\n";
|
||||
|
||||
debug_server::connection_ptr con = s.get_connection();
|
||||
con->start();
|
||||
|
||||
con->read_all(input.data(), input.size());
|
||||
|
||||
con->expire_timer(websocketpp::lib::error_code());
|
||||
// Complete write immediately after timer expire
|
||||
con->fullfil_write();
|
||||
|
||||
BOOST_CHECK_EQUAL(con->get_ec(), make_error_code(websocketpp::error::open_handshake_timeout));
|
||||
}
|
||||
|
||||
|
||||
@@ -31,17 +31,22 @@ void echo_func(server* s, websocketpp::connection_hdl hdl, message_ptr msg) {
|
||||
s->send(hdl, msg->get_payload(), msg->get_opcode());
|
||||
}
|
||||
|
||||
std::string run_server_test(std::string input) {
|
||||
std::string run_server_test(std::string input, bool log) {
|
||||
server test_server;
|
||||
return run_server_test(test_server,input);
|
||||
return run_server_test(test_server,input,log);
|
||||
}
|
||||
|
||||
std::string run_server_test(server & s, std::string input) {
|
||||
std::string run_server_test(server & s, std::string input, bool log) {
|
||||
server::connection_ptr con;
|
||||
std::stringstream output;
|
||||
|
||||
s.clear_access_channels(websocketpp::log::alevel::all);
|
||||
s.clear_error_channels(websocketpp::log::elevel::all);
|
||||
if (log) {
|
||||
s.set_access_channels(websocketpp::log::alevel::all);
|
||||
s.set_error_channels(websocketpp::log::elevel::all);
|
||||
} else {
|
||||
s.clear_access_channels(websocketpp::log::alevel::all);
|
||||
s.clear_error_channels(websocketpp::log::elevel::all);
|
||||
}
|
||||
|
||||
s.register_ostream(&output);
|
||||
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
|
||||
// Test Environment:
|
||||
// server, no TLS, no locks, iostream based transport
|
||||
#include <websocketpp/config/debug.hpp>
|
||||
#include <websocketpp/config/core.hpp>
|
||||
#include <websocketpp/server.hpp>
|
||||
#include <websocketpp/client.hpp>
|
||||
@@ -46,5 +47,5 @@ using websocketpp::lib::placeholders::_2;
|
||||
using websocketpp::lib::bind;
|
||||
|
||||
void echo_func(server* s, websocketpp::connection_hdl hdl, message_ptr msg);
|
||||
std::string run_server_test(std::string input);
|
||||
std::string run_server_test(server & s, std::string input);
|
||||
std::string run_server_test(std::string input, bool log = false);
|
||||
std::string run_server_test(server & s, std::string input, bool log = false);
|
||||
@@ -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:
|
||||
@@ -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) {}
|
||||
|
||||
@@ -94,8 +123,33 @@ struct stub_config : public websocketpp::config::core {
|
||||
BOOST_AUTO_TEST_CASE( endpoint_extensions ) {
|
||||
websocketpp::server<stub_config> s;
|
||||
|
||||
BOOST_CHECK( s.extension_value == 5 );
|
||||
BOOST_CHECK( s.extension_method() == 5 );
|
||||
BOOST_CHECK_EQUAL( s.extension_value, 5 );
|
||||
BOOST_CHECK_EQUAL( s.extension_method(), 5 );
|
||||
|
||||
BOOST_CHECK( s.is_server() == true );
|
||||
BOOST_CHECK( s.is_server() );
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( listen_after_listen_failure ) {
|
||||
using websocketpp::transport::asio::error::make_error_code;
|
||||
using websocketpp::transport::asio::error::pass_through;
|
||||
|
||||
websocketpp::server<websocketpp::config::asio> server1;
|
||||
websocketpp::server<websocketpp::config::asio> server2;
|
||||
|
||||
websocketpp::lib::error_code ec;
|
||||
|
||||
server1.init_asio();
|
||||
server2.init_asio();
|
||||
|
||||
boost::asio::ip::tcp::endpoint ep1(boost::asio::ip::address::from_string("127.0.0.1"), 12345);
|
||||
boost::asio::ip::tcp::endpoint ep2(boost::asio::ip::address::from_string("127.0.0.1"), 23456);
|
||||
|
||||
server1.listen(ep1, ec);
|
||||
BOOST_CHECK(!ec);
|
||||
|
||||
server2.listen(ep1, ec);
|
||||
BOOST_REQUIRE_EQUAL(ec, make_error_code(pass_through));
|
||||
|
||||
server2.listen(ep2, ec);
|
||||
BOOST_CHECK(!ec);
|
||||
}
|
||||
@@ -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 );
|
||||
}
|
||||
*/
|
||||
+160
-1
@@ -28,6 +28,7 @@
|
||||
#define BOOST_TEST_MODULE http_parser
|
||||
#include <boost/test/unit_test.hpp>
|
||||
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
#include <websocketpp/http/request.hpp>
|
||||
@@ -479,6 +480,62 @@ BOOST_AUTO_TEST_CASE( basic_request ) {
|
||||
BOOST_CHECK( r.get_header("Host") == "www.example.com" );
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( basic_request_with_body ) {
|
||||
websocketpp::http::parser::request r;
|
||||
|
||||
std::string raw = "GET / HTTP/1.1\r\nHost: www.example.com\r\nContent-Length: 5\r\n\r\nabcdef";
|
||||
|
||||
bool exception = false;
|
||||
size_t pos = 0;
|
||||
|
||||
try {
|
||||
pos = r.consume(raw.c_str(),raw.size());
|
||||
} catch (std::exception &e) {
|
||||
exception = true;
|
||||
std::cout << e.what() << std::endl;
|
||||
}
|
||||
|
||||
BOOST_CHECK( exception == false );
|
||||
BOOST_CHECK_EQUAL( pos, 65 );
|
||||
BOOST_CHECK( r.ready() == true );
|
||||
BOOST_CHECK_EQUAL( r.get_version(), "HTTP/1.1" );
|
||||
BOOST_CHECK_EQUAL( r.get_method(), "GET" );
|
||||
BOOST_CHECK_EQUAL( r.get_uri(), "/" );
|
||||
BOOST_CHECK_EQUAL( r.get_header("Host"), "www.example.com" );
|
||||
BOOST_CHECK_EQUAL( r.get_header("Content-Length"), "5" );
|
||||
BOOST_CHECK_EQUAL( r.get_body(), "abcde" );
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( basic_request_with_body_split ) {
|
||||
websocketpp::http::parser::request r;
|
||||
|
||||
std::string raw = "GET / HTTP/1.1\r\nHost: www.example.com\r\nContent-Length: 6\r\n\r\nabc";
|
||||
std::string raw2 = "def";
|
||||
|
||||
bool exception = false;
|
||||
size_t pos = 0;
|
||||
|
||||
try {
|
||||
pos += r.consume(raw.c_str(),raw.size());
|
||||
pos += r.consume(raw2.c_str(),raw2.size());
|
||||
} catch (std::exception &e) {
|
||||
exception = true;
|
||||
std::cout << e.what() << std::endl;
|
||||
}
|
||||
|
||||
BOOST_CHECK( exception == false );
|
||||
BOOST_CHECK_EQUAL( pos, 66 );
|
||||
BOOST_CHECK( r.ready() == true );
|
||||
BOOST_CHECK_EQUAL( r.get_version(), "HTTP/1.1" );
|
||||
BOOST_CHECK_EQUAL( r.get_method(), "GET" );
|
||||
BOOST_CHECK_EQUAL( r.get_uri(), "/" );
|
||||
BOOST_CHECK_EQUAL( r.get_header("Host"), "www.example.com" );
|
||||
BOOST_CHECK_EQUAL( r.get_header("Content-Length"), "6" );
|
||||
BOOST_CHECK_EQUAL( r.get_body(), "abcdef" );
|
||||
}
|
||||
|
||||
|
||||
|
||||
BOOST_AUTO_TEST_CASE( trailing_body_characters ) {
|
||||
websocketpp::http::parser::request r;
|
||||
|
||||
@@ -502,6 +559,30 @@ BOOST_AUTO_TEST_CASE( trailing_body_characters ) {
|
||||
BOOST_CHECK( r.get_header("Host") == "www.example.com" );
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( trailing_body_characters_beyond_max_lenth ) {
|
||||
websocketpp::http::parser::request r;
|
||||
|
||||
std::string raw = "GET / HTTP/1.1\r\nHost: www.example.com\r\n\r\n";
|
||||
raw.append(websocketpp::http::max_header_size,'*');
|
||||
|
||||
bool exception = false;
|
||||
size_t pos = 0;
|
||||
|
||||
try {
|
||||
pos = r.consume(raw.c_str(),raw.size());
|
||||
} catch (...) {
|
||||
exception = true;
|
||||
}
|
||||
|
||||
BOOST_CHECK( exception == false );
|
||||
BOOST_CHECK( pos == 41 );
|
||||
BOOST_CHECK( r.ready() == true );
|
||||
BOOST_CHECK( r.get_version() == "HTTP/1.1" );
|
||||
BOOST_CHECK( r.get_method() == "GET" );
|
||||
BOOST_CHECK( r.get_uri() == "/" );
|
||||
BOOST_CHECK( r.get_header("Host") == "www.example.com" );
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( basic_split1 ) {
|
||||
websocketpp::http::parser::request r;
|
||||
|
||||
@@ -557,7 +638,8 @@ BOOST_AUTO_TEST_CASE( basic_split2 ) {
|
||||
BOOST_AUTO_TEST_CASE( max_header_len ) {
|
||||
websocketpp::http::parser::request r;
|
||||
|
||||
std::string raw(websocketpp::http::max_header_size+1,'*');
|
||||
std::string raw(websocketpp::http::max_header_size-1,'*');
|
||||
raw += "\r\n";
|
||||
|
||||
bool exception = false;
|
||||
size_t pos = 0;
|
||||
@@ -594,6 +676,27 @@ BOOST_AUTO_TEST_CASE( max_header_len_split ) {
|
||||
BOOST_CHECK( exception == true );
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( max_body_len ) {
|
||||
websocketpp::http::parser::request r;
|
||||
|
||||
r.set_max_body_size(5);
|
||||
|
||||
std::string raw = "GET / HTTP/1.1\r\nHost: www.example.com\r\nContent-Length: 6\r\n\r\nabcdef";
|
||||
|
||||
bool exception = false;
|
||||
size_t pos = 0;
|
||||
|
||||
try {
|
||||
pos += r.consume(raw.c_str(),raw.size());
|
||||
} catch (websocketpp::http::exception const & e) {
|
||||
exception = true;
|
||||
BOOST_CHECK_EQUAL(e.m_error_code,websocketpp::http::status_code::request_entity_too_large);
|
||||
}
|
||||
|
||||
BOOST_CHECK_EQUAL(r.get_max_body_size(),5);
|
||||
BOOST_CHECK( exception == true );
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( firefox_full_request ) {
|
||||
websocketpp::http::parser::request r;
|
||||
|
||||
@@ -844,6 +947,62 @@ BOOST_AUTO_TEST_CASE( wikipedia_example_response ) {
|
||||
BOOST_CHECK_EQUAL( r.get_header("Sec-WebSocket-Protocol"), "chat" );
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( wikipedia_example_response_trailing ) {
|
||||
websocketpp::http::parser::response r;
|
||||
|
||||
std::string raw = "HTTP/1.1 101 Switching Protocols\r\nUpgrade: websocket\r\nConnection: Upgrade\r\nSec-WebSocket-Accept: HSmrc0sMlYUkAGmm5OPpG2HaGWk=\r\nSec-WebSocket-Protocol: chat\r\n\r\n";
|
||||
raw += "a";
|
||||
|
||||
bool exception = false;
|
||||
size_t pos = 0;
|
||||
|
||||
try {
|
||||
pos += r.consume(raw.c_str(),raw.size());
|
||||
} catch (std::exception &e) {
|
||||
exception = true;
|
||||
std::cout << e.what() << std::endl;
|
||||
}
|
||||
|
||||
BOOST_CHECK( exception == false );
|
||||
BOOST_CHECK_EQUAL( pos, 159 );
|
||||
BOOST_CHECK( r.headers_ready() == true );
|
||||
BOOST_CHECK_EQUAL( r.get_version(), "HTTP/1.1" );
|
||||
BOOST_CHECK_EQUAL( r.get_status_code(), websocketpp::http::status_code::switching_protocols );
|
||||
BOOST_CHECK_EQUAL( r.get_status_msg(), "Switching Protocols" );
|
||||
BOOST_CHECK_EQUAL( r.get_header("Upgrade"), "websocket" );
|
||||
BOOST_CHECK_EQUAL( r.get_header("Connection"), "Upgrade" );
|
||||
BOOST_CHECK_EQUAL( r.get_header("Sec-WebSocket-Accept"), "HSmrc0sMlYUkAGmm5OPpG2HaGWk=" );
|
||||
BOOST_CHECK_EQUAL( r.get_header("Sec-WebSocket-Protocol"), "chat" );
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( wikipedia_example_response_trailing_large ) {
|
||||
websocketpp::http::parser::response r;
|
||||
|
||||
std::string raw = "HTTP/1.1 101 Switching Protocols\r\nUpgrade: websocket\r\nConnection: Upgrade\r\nSec-WebSocket-Accept: HSmrc0sMlYUkAGmm5OPpG2HaGWk=\r\nSec-WebSocket-Protocol: chat\r\n\r\n";
|
||||
raw.append(websocketpp::http::max_header_size,'*');
|
||||
|
||||
bool exception = false;
|
||||
size_t pos = 0;
|
||||
|
||||
try {
|
||||
pos += r.consume(raw.c_str(),raw.size());
|
||||
} catch (std::exception &e) {
|
||||
exception = true;
|
||||
std::cout << e.what() << std::endl;
|
||||
}
|
||||
|
||||
BOOST_CHECK( exception == false );
|
||||
BOOST_CHECK_EQUAL( pos, 159 );
|
||||
BOOST_CHECK( r.headers_ready() == true );
|
||||
BOOST_CHECK_EQUAL( r.get_version(), "HTTP/1.1" );
|
||||
BOOST_CHECK_EQUAL( r.get_status_code(), websocketpp::http::status_code::switching_protocols );
|
||||
BOOST_CHECK_EQUAL( r.get_status_msg(), "Switching Protocols" );
|
||||
BOOST_CHECK_EQUAL( r.get_header("Upgrade"), "websocket" );
|
||||
BOOST_CHECK_EQUAL( r.get_header("Connection"), "Upgrade" );
|
||||
BOOST_CHECK_EQUAL( r.get_header("Sec-WebSocket-Accept"), "HSmrc0sMlYUkAGmm5OPpG2HaGWk=" );
|
||||
BOOST_CHECK_EQUAL( r.get_header("Sec-WebSocket-Protocol"), "chat" );
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( response_with_non_standard_lws ) {
|
||||
websocketpp::http::parser::response r;
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2011, Peter Thorson. All rights reserved.
|
||||
* Copyright (c) 2014, Peter Thorson. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
@@ -273,7 +273,8 @@ void run_dummy_client(std::string port) {
|
||||
}
|
||||
}
|
||||
|
||||
bool on_ping(websocketpp::connection_hdl, std::string) {
|
||||
bool on_ping(server * s, websocketpp::connection_hdl, std::string) {
|
||||
s->get_alog().write(websocketpp::log::alevel::app,"got ping");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -291,7 +292,9 @@ void stop_on_close(server * s, websocketpp::connection_hdl hdl) {
|
||||
template <typename T>
|
||||
void ping_on_open(T * c, std::string payload, websocketpp::connection_hdl hdl) {
|
||||
typename T::connection_ptr con = c->get_con_from_hdl(hdl);
|
||||
con->ping(payload);
|
||||
websocketpp::lib::error_code ec;
|
||||
con->ping(payload,ec);
|
||||
BOOST_CHECK_EQUAL(ec, websocketpp::lib::error_code());
|
||||
}
|
||||
|
||||
void fail_on_pong(websocketpp::connection_hdl, std::string) {
|
||||
@@ -382,7 +385,7 @@ BOOST_AUTO_TEST_CASE( pong_timeout ) {
|
||||
server s;
|
||||
client c;
|
||||
|
||||
s.set_ping_handler(on_ping);
|
||||
s.set_ping_handler(bind(&on_ping, &s,::_1,::_2));
|
||||
s.set_close_handler(bind(&stop_on_close,&s,::_1));
|
||||
|
||||
c.set_fail_handler(bind(&check_ec<client>,&c,
|
||||
@@ -395,7 +398,7 @@ BOOST_AUTO_TEST_CASE( pong_timeout ) {
|
||||
websocketpp::lib::error_code(),::_1));
|
||||
|
||||
websocketpp::lib::thread sthread(websocketpp::lib::bind(&run_server,&s,9005,false));
|
||||
websocketpp::lib::thread tthread(websocketpp::lib::bind(&run_test_timer,6));
|
||||
websocketpp::lib::thread tthread(websocketpp::lib::bind(&run_test_timer,10));
|
||||
tthread.detach();
|
||||
|
||||
run_client(c, "http://localhost:9005",false);
|
||||
@@ -413,7 +416,7 @@ BOOST_AUTO_TEST_CASE( client_open_handshake_timeout ) {
|
||||
websocketpp::error::open_handshake_timeout,::_1));
|
||||
|
||||
websocketpp::lib::thread sthread(websocketpp::lib::bind(&run_dummy_server,9005));
|
||||
websocketpp::lib::thread tthread(websocketpp::lib::bind(&run_test_timer,6));
|
||||
websocketpp::lib::thread tthread(websocketpp::lib::bind(&run_test_timer,10));
|
||||
sthread.detach();
|
||||
tthread.detach();
|
||||
|
||||
@@ -430,7 +433,7 @@ BOOST_AUTO_TEST_CASE( server_open_handshake_timeout ) {
|
||||
websocketpp::error::open_handshake_timeout,::_1));
|
||||
|
||||
websocketpp::lib::thread sthread(websocketpp::lib::bind(&run_server,&s,9005,false));
|
||||
websocketpp::lib::thread tthread(websocketpp::lib::bind(&run_test_timer,6));
|
||||
websocketpp::lib::thread tthread(websocketpp::lib::bind(&run_test_timer,10));
|
||||
tthread.detach();
|
||||
|
||||
run_dummy_client("9005");
|
||||
@@ -453,7 +456,7 @@ BOOST_AUTO_TEST_CASE( client_self_initiated_close_handshake_timeout ) {
|
||||
websocketpp::error::close_handshake_timeout,::_1));
|
||||
|
||||
websocketpp::lib::thread sthread(websocketpp::lib::bind(&run_server,&s,9005,false));
|
||||
websocketpp::lib::thread tthread(websocketpp::lib::bind(&run_test_timer,6));
|
||||
websocketpp::lib::thread tthread(websocketpp::lib::bind(&run_test_timer,10));
|
||||
tthread.detach();
|
||||
|
||||
run_client(c, "http://localhost:9005", false);
|
||||
@@ -485,7 +488,7 @@ BOOST_AUTO_TEST_CASE( server_self_initiated_close_handshake_timeout ) {
|
||||
c.set_open_handler(bind(&delay,::_1,1));
|
||||
|
||||
websocketpp::lib::thread sthread(websocketpp::lib::bind(&run_server,&s,9005,false));
|
||||
websocketpp::lib::thread tthread(websocketpp::lib::bind(&run_test_timer,6));
|
||||
websocketpp::lib::thread tthread(websocketpp::lib::bind(&run_test_timer,10));
|
||||
tthread.detach();
|
||||
|
||||
run_client(c, "http://localhost:9005",false);
|
||||
@@ -563,7 +566,7 @@ BOOST_AUTO_TEST_CASE( stop_listening ) {
|
||||
c.set_open_handler(bind(&close<client>,&c,::_1));
|
||||
|
||||
websocketpp::lib::thread sthread(websocketpp::lib::bind(&run_server,&s,9005,false));
|
||||
websocketpp::lib::thread tthread(websocketpp::lib::bind(&run_test_timer,2));
|
||||
websocketpp::lib::thread tthread(websocketpp::lib::bind(&run_test_timer,5));
|
||||
tthread.detach();
|
||||
|
||||
run_client(c, "http://localhost:9005",false);
|
||||
@@ -575,17 +578,17 @@ BOOST_AUTO_TEST_CASE( pause_reading ) {
|
||||
iostream_server s;
|
||||
std::string handshake = "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\n\r\n";
|
||||
char buffer[2] = { char(0x81), char(0x80) };
|
||||
|
||||
|
||||
// suppress output (it needs a place to go to avoid error but we don't care what it is)
|
||||
std::stringstream null_output;
|
||||
s.register_ostream(&null_output);
|
||||
|
||||
|
||||
iostream_server::connection_ptr con = s.get_connection();
|
||||
con->start();
|
||||
|
||||
// read handshake, should work
|
||||
BOOST_CHECK_EQUAL( con->read_some(handshake.data(), handshake.length()), handshake.length());
|
||||
|
||||
|
||||
// pause reading and try again. The first read should work, the second should return 0
|
||||
// the first read was queued already after the handshake so it will go through because
|
||||
// reading wasn't paused when it was queued. The byte it reads wont be enough to
|
||||
@@ -603,4 +606,12 @@ 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,10 +138,24 @@ 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();
|
||||
}
|
||||
|
||||
void shutdown() {
|
||||
iostream_con::async_shutdown(
|
||||
websocketpp::lib::bind(
|
||||
&stub_con::handle_async_shutdown,
|
||||
type::get_shared(),
|
||||
websocketpp::lib::placeholders::_1
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
void handle_async_shutdown(websocketpp::lib::error_code const & e) {
|
||||
ec = e;
|
||||
}
|
||||
|
||||
websocketpp::lib::error_code ec;
|
||||
size_t indef_read_size;
|
||||
char * indef_read_buf;
|
||||
@@ -156,11 +170,11 @@ config::elog_type elogger;
|
||||
BOOST_AUTO_TEST_CASE( const_methods ) {
|
||||
iostream_con::ptr con(new iostream_con(true,alogger,elogger));
|
||||
|
||||
BOOST_CHECK( con->is_secure() == false );
|
||||
BOOST_CHECK( con->get_remote_endpoint() == "iostream transport" );
|
||||
BOOST_CHECK( !con->is_secure() );
|
||||
BOOST_CHECK_EQUAL( con->get_remote_endpoint(), "iostream transport" );
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( write_before_ostream_set ) {
|
||||
BOOST_AUTO_TEST_CASE( write_before_output_method_set ) {
|
||||
stub_con::ptr con(new stub_con(true,alogger,elogger));
|
||||
|
||||
con->write("foo");
|
||||
@@ -168,10 +182,10 @@ BOOST_AUTO_TEST_CASE( write_before_ostream_set ) {
|
||||
|
||||
std::vector<websocketpp::transport::buffer> bufs;
|
||||
con->write(bufs);
|
||||
BOOST_CHECK( con->ec == make_error_code(websocketpp::transport::iostream::error::output_stream_required) );
|
||||
BOOST_CHECK_EQUAL( con->ec, make_error_code(websocketpp::transport::iostream::error::output_stream_required) );
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( async_write ) {
|
||||
BOOST_AUTO_TEST_CASE( async_write_ostream ) {
|
||||
stub_con::ptr con(new stub_con(true,alogger,elogger));
|
||||
|
||||
std::stringstream output;
|
||||
@@ -181,10 +195,52 @@ BOOST_AUTO_TEST_CASE( async_write ) {
|
||||
con->write("foo");
|
||||
|
||||
BOOST_CHECK( !con->ec );
|
||||
BOOST_CHECK( output.str() == "foo" );
|
||||
BOOST_CHECK_EQUAL( output.str(), "foo" );
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( async_write_vector_0 ) {
|
||||
websocketpp::lib::error_code write_handler(std::string & o, websocketpp::connection_hdl, char const * buf, size_t len) {
|
||||
o += std::string(buf,len);
|
||||
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);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( async_write_handler ) {
|
||||
stub_con::ptr con(new stub_con(true,alogger,elogger));
|
||||
std::string output;
|
||||
|
||||
con->set_write_handler(websocketpp::lib::bind(
|
||||
&write_handler,
|
||||
websocketpp::lib::ref(output),
|
||||
websocketpp::lib::placeholders::_1,
|
||||
websocketpp::lib::placeholders::_2,
|
||||
websocketpp::lib::placeholders::_3
|
||||
));
|
||||
con->write("foo");
|
||||
BOOST_CHECK( !con->ec );
|
||||
BOOST_CHECK_EQUAL(output, "foo");
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( async_write_handler_error ) {
|
||||
stub_con::ptr con(new stub_con(true,alogger,elogger));
|
||||
|
||||
con->set_write_handler(&write_handler_error);
|
||||
con->write("foo");
|
||||
BOOST_CHECK_EQUAL( con->ec, make_error_code(websocketpp::transport::error::general) );
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( async_write_vector_0_ostream ) {
|
||||
std::stringstream output;
|
||||
|
||||
stub_con::ptr con(new stub_con(true,alogger,elogger));
|
||||
@@ -195,10 +251,31 @@ BOOST_AUTO_TEST_CASE( async_write_vector_0 ) {
|
||||
con->write(bufs);
|
||||
|
||||
BOOST_CHECK( !con->ec );
|
||||
BOOST_CHECK( output.str() == "" );
|
||||
BOOST_CHECK_EQUAL( output.str(), "" );
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( async_write_vector_1 ) {
|
||||
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),
|
||||
websocketpp::lib::placeholders::_1,
|
||||
websocketpp::lib::placeholders::_2,
|
||||
websocketpp::lib::placeholders::_3
|
||||
));
|
||||
|
||||
std::vector<websocketpp::transport::buffer> bufs;
|
||||
|
||||
con->write(bufs);
|
||||
|
||||
BOOST_CHECK( !con->ec );
|
||||
BOOST_CHECK_EQUAL( output, "" );
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( async_write_vector_1_ostream ) {
|
||||
std::stringstream output;
|
||||
|
||||
stub_con::ptr con(new stub_con(true,alogger,elogger));
|
||||
@@ -213,10 +290,34 @@ BOOST_AUTO_TEST_CASE( async_write_vector_1 ) {
|
||||
con->write(bufs);
|
||||
|
||||
BOOST_CHECK( !con->ec );
|
||||
BOOST_CHECK( output.str() == "foo" );
|
||||
BOOST_CHECK_EQUAL( output.str(), "foo" );
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( async_write_vector_2 ) {
|
||||
BOOST_AUTO_TEST_CASE( async_write_vector_1_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),
|
||||
websocketpp::lib::placeholders::_1,
|
||||
websocketpp::lib::placeholders::_2,
|
||||
websocketpp::lib::placeholders::_3
|
||||
));
|
||||
|
||||
std::vector<websocketpp::transport::buffer> bufs;
|
||||
|
||||
std::string foo = "foo";
|
||||
|
||||
bufs.push_back(websocketpp::transport::buffer(foo.data(),foo.size()));
|
||||
|
||||
con->write(bufs);
|
||||
|
||||
BOOST_CHECK( !con->ec );
|
||||
BOOST_CHECK_EQUAL( output, "foo" );
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( async_write_vector_2_ostream ) {
|
||||
std::stringstream output;
|
||||
|
||||
stub_con::ptr con(new stub_con(true,alogger,elogger));
|
||||
@@ -233,7 +334,58 @@ BOOST_AUTO_TEST_CASE( async_write_vector_2 ) {
|
||||
con->write(bufs);
|
||||
|
||||
BOOST_CHECK( !con->ec );
|
||||
BOOST_CHECK( output.str() == "foobar" );
|
||||
BOOST_CHECK_EQUAL( output.str(), "foobar" );
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( async_write_vector_2_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),
|
||||
websocketpp::lib::placeholders::_1,
|
||||
websocketpp::lib::placeholders::_2,
|
||||
websocketpp::lib::placeholders::_3
|
||||
));
|
||||
|
||||
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_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 ) {
|
||||
@@ -242,7 +394,7 @@ BOOST_AUTO_TEST_CASE( async_read_at_least_too_much ) {
|
||||
char buf[10];
|
||||
|
||||
con->async_read_at_least(11,buf,10);
|
||||
BOOST_CHECK( con->ec == make_error_code(websocketpp::transport::iostream::error::invalid_num_bytes) );
|
||||
BOOST_CHECK_EQUAL( con->ec, make_error_code(websocketpp::transport::iostream::error::invalid_num_bytes) );
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( async_read_at_least_double_read ) {
|
||||
@@ -252,7 +404,7 @@ BOOST_AUTO_TEST_CASE( async_read_at_least_double_read ) {
|
||||
|
||||
con->async_read_at_least(5,buf,10);
|
||||
con->async_read_at_least(5,buf,10);
|
||||
BOOST_CHECK( con->ec == make_error_code(websocketpp::transport::iostream::error::double_read) );
|
||||
BOOST_CHECK_EQUAL( con->ec, make_error_code(websocketpp::transport::iostream::error::double_read) );
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( async_read_at_least ) {
|
||||
@@ -263,32 +415,32 @@ BOOST_AUTO_TEST_CASE( async_read_at_least ) {
|
||||
memset(buf,'x',10);
|
||||
|
||||
con->async_read_at_least(5,buf,10);
|
||||
BOOST_CHECK( con->ec == make_error_code(websocketpp::error::test) );
|
||||
BOOST_CHECK_EQUAL( con->ec, make_error_code(websocketpp::error::test) );
|
||||
|
||||
std::stringstream channel;
|
||||
channel << "abcd";
|
||||
channel >> *con;
|
||||
BOOST_CHECK( channel.tellg() == -1 );
|
||||
BOOST_CHECK( con->ec == make_error_code(websocketpp::error::test) );
|
||||
BOOST_CHECK_EQUAL( channel.tellg(), -1 );
|
||||
BOOST_CHECK_EQUAL( con->ec, make_error_code(websocketpp::error::test) );
|
||||
|
||||
std::stringstream channel2;
|
||||
channel2 << "e";
|
||||
channel2 >> *con;
|
||||
BOOST_CHECK( channel2.tellg() == -1 );
|
||||
BOOST_CHECK_EQUAL( channel2.tellg(), -1 );
|
||||
BOOST_CHECK( !con->ec );
|
||||
BOOST_CHECK( std::string(buf,10) == "abcdexxxxx" );
|
||||
BOOST_CHECK_EQUAL( std::string(buf,10), "abcdexxxxx" );
|
||||
|
||||
std::stringstream channel3;
|
||||
channel3 << "f";
|
||||
channel3 >> *con;
|
||||
BOOST_CHECK( channel3.tellg() == 0 );
|
||||
BOOST_CHECK_EQUAL( channel3.tellg(), 0 );
|
||||
BOOST_CHECK( !con->ec );
|
||||
BOOST_CHECK( std::string(buf,10) == "abcdexxxxx" );
|
||||
BOOST_CHECK_EQUAL( std::string(buf,10), "abcdexxxxx" );
|
||||
con->async_read_at_least(1,buf+5,5);
|
||||
channel3 >> *con;
|
||||
BOOST_CHECK( channel3.tellg() == -1 );
|
||||
BOOST_CHECK_EQUAL( channel3.tellg(), -1 );
|
||||
BOOST_CHECK( !con->ec );
|
||||
BOOST_CHECK( std::string(buf,10) == "abcdefxxxx" );
|
||||
BOOST_CHECK_EQUAL( std::string(buf,10), "abcdefxxxx" );
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( async_read_at_least2 ) {
|
||||
@@ -299,20 +451,20 @@ BOOST_AUTO_TEST_CASE( async_read_at_least2 ) {
|
||||
memset(buf,'x',10);
|
||||
|
||||
con->async_read_at_least(5,buf,5);
|
||||
BOOST_CHECK( con->ec == make_error_code(websocketpp::error::test) );
|
||||
BOOST_CHECK_EQUAL( con->ec, make_error_code(websocketpp::error::test) );
|
||||
|
||||
std::stringstream channel;
|
||||
channel << "abcdefg";
|
||||
channel >> *con;
|
||||
BOOST_CHECK( channel.tellg() == 5 );
|
||||
BOOST_CHECK_EQUAL( channel.tellg(), 5 );
|
||||
BOOST_CHECK( !con->ec );
|
||||
BOOST_CHECK( std::string(buf,10) == "abcdexxxxx" );
|
||||
BOOST_CHECK_EQUAL( std::string(buf,10), "abcdexxxxx" );
|
||||
|
||||
con->async_read_at_least(1,buf+5,5);
|
||||
channel >> *con;
|
||||
BOOST_CHECK( channel.tellg() == -1 );
|
||||
BOOST_CHECK_EQUAL( channel.tellg(), -1 );
|
||||
BOOST_CHECK( !con->ec );
|
||||
BOOST_CHECK( std::string(buf,10) == "abcdefgxxx" );
|
||||
BOOST_CHECK_EQUAL( std::string(buf,10), "abcdefgxxx" );
|
||||
}
|
||||
|
||||
void timer_callback_stub(websocketpp::lib::error_code const &) {}
|
||||
@@ -332,7 +484,7 @@ BOOST_AUTO_TEST_CASE( async_read_at_least_read_some ) {
|
||||
memset(buf,'x',10);
|
||||
|
||||
con->async_read_at_least(5,buf,5);
|
||||
BOOST_CHECK( con->ec == make_error_code(websocketpp::error::test) );
|
||||
BOOST_CHECK_EQUAL( con->ec, make_error_code(websocketpp::error::test) );
|
||||
|
||||
char input[10] = "abcdefg";
|
||||
BOOST_CHECK_EQUAL(con->read_some(input,5), 5);
|
||||
@@ -356,7 +508,7 @@ BOOST_AUTO_TEST_CASE( async_read_at_least_read_some_indef ) {
|
||||
memset(buf,'x',20);
|
||||
|
||||
con->async_read_indef(5,buf,5);
|
||||
BOOST_CHECK( con->ec == make_error_code(websocketpp::error::test) );
|
||||
BOOST_CHECK_EQUAL( con->ec, make_error_code(websocketpp::error::test) );
|
||||
|
||||
// here we expect to return early from read some because the outstanding
|
||||
// read was for 5 bytes and we were called with 10.
|
||||
@@ -365,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);
|
||||
@@ -381,7 +533,7 @@ BOOST_AUTO_TEST_CASE( async_read_at_least_read_all ) {
|
||||
memset(buf,'x',20);
|
||||
|
||||
con->async_read_indef(5,buf,5);
|
||||
BOOST_CHECK( con->ec == make_error_code(websocketpp::error::test) );
|
||||
BOOST_CHECK_EQUAL( con->ec, make_error_code(websocketpp::error::test) );
|
||||
|
||||
char input[11] = "aaaaabbbbb";
|
||||
BOOST_CHECK_EQUAL(con->read_all(input,10), 10);
|
||||
@@ -394,7 +546,7 @@ BOOST_AUTO_TEST_CASE( eof_flag ) {
|
||||
stub_con::ptr con(new stub_con(true,alogger,elogger));
|
||||
char buf[10];
|
||||
con->async_read_at_least(5,buf,5);
|
||||
BOOST_CHECK( con->ec == make_error_code(websocketpp::error::test) );
|
||||
BOOST_CHECK_EQUAL( con->ec, make_error_code(websocketpp::error::test) );
|
||||
con->eof();
|
||||
BOOST_CHECK_EQUAL( con->ec, make_error_code(websocketpp::transport::error::eof) );
|
||||
}
|
||||
@@ -403,11 +555,31 @@ BOOST_AUTO_TEST_CASE( fatal_error_flag ) {
|
||||
stub_con::ptr con(new stub_con(true,alogger,elogger));
|
||||
char buf[10];
|
||||
con->async_read_at_least(5,buf,5);
|
||||
BOOST_CHECK( con->ec == make_error_code(websocketpp::error::test) );
|
||||
BOOST_CHECK_EQUAL( con->ec, make_error_code(websocketpp::error::test) );
|
||||
con->fatal_error();
|
||||
BOOST_CHECK_EQUAL( con->ec, make_error_code(websocketpp::transport::error::pass_through) );
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( shutdown ) {
|
||||
stub_con::ptr con(new stub_con(true,alogger,elogger));
|
||||
BOOST_CHECK_EQUAL( con->ec, make_error_code(websocketpp::error::test) );
|
||||
con->shutdown();
|
||||
BOOST_CHECK_EQUAL( con->ec, websocketpp::lib::error_code() );
|
||||
}
|
||||
|
||||
websocketpp::lib::error_code sd_handler(websocketpp::connection_hdl) {
|
||||
return make_error_code(websocketpp::transport::error::general);
|
||||
}
|
||||
|
||||
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();
|
||||
BOOST_CHECK_EQUAL( con->ec, make_error_code(websocketpp::transport::error::general) );
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( shared_pointer_memory_cleanup ) {
|
||||
stub_con::ptr con(new stub_con(true,alogger,elogger));
|
||||
|
||||
@@ -416,7 +588,7 @@ BOOST_AUTO_TEST_CASE( shared_pointer_memory_cleanup ) {
|
||||
char buf[10];
|
||||
memset(buf,'x',10);
|
||||
con->async_read_at_least(5,buf,5);
|
||||
BOOST_CHECK( con->ec == make_error_code(websocketpp::error::test) );
|
||||
BOOST_CHECK_EQUAL( con->ec, make_error_code(websocketpp::error::test) );
|
||||
BOOST_CHECK_EQUAL(con.use_count(), 2);
|
||||
|
||||
char input[10] = "foo";
|
||||
|
||||
@@ -16,11 +16,13 @@ objs = env.Object('uri_boost.o', ["uri.cpp"], LIBS = BOOST_LIBS)
|
||||
objs += env.Object('utilities_boost.o', ["utilities.cpp"], LIBS = BOOST_LIBS)
|
||||
objs += env.Object('close_boost.o', ["close.cpp"], LIBS = BOOST_LIBS)
|
||||
objs += env.Object('sha1_boost.o', ["sha1.cpp"], LIBS = BOOST_LIBS)
|
||||
objs += env.Object('error_boost.o', ["error.cpp"], LIBS = BOOST_LIBS)
|
||||
prgs = env.Program('test_uri_boost', ["uri_boost.o"], LIBS = BOOST_LIBS)
|
||||
prgs += env.Program('test_utility_boost', ["utilities_boost.o"], LIBS = BOOST_LIBS)
|
||||
prgs += env.Program('test_frame', ["frame.cpp"], LIBS = BOOST_LIBS)
|
||||
prgs += env.Program('test_close_boost', ["close_boost.o"], LIBS = BOOST_LIBS)
|
||||
prgs += env.Program('test_sha1_boost', ["sha1_boost.o"], LIBS = BOOST_LIBS)
|
||||
prgs += env.Program('test_error_boost', ["error_boost.o"], LIBS = BOOST_LIBS)
|
||||
|
||||
if env_cpp11.has_key('WSPP_CPP11_ENABLED'):
|
||||
BOOST_LIBS_CPP11 = boostlibs(['unit_test_framework'],env_cpp11) + [platform_libs] + [polyfill_libs]
|
||||
@@ -28,9 +30,11 @@ if env_cpp11.has_key('WSPP_CPP11_ENABLED'):
|
||||
objs += env_cpp11.Object('uri_stl.o', ["uri.cpp"], LIBS = BOOST_LIBS_CPP11)
|
||||
objs += env_cpp11.Object('close_stl.o', ["close.cpp"], LIBS = BOOST_LIBS_CPP11)
|
||||
objs += env_cpp11.Object('sha1_stl.o', ["sha1.cpp"], LIBS = BOOST_LIBS_CPP11)
|
||||
objs += env_cpp11.Object('error_stl.o', ["error.cpp"], LIBS = BOOST_LIBS_CPP11)
|
||||
prgs += env_cpp11.Program('test_utility_stl', ["utilities_stl.o"], LIBS = BOOST_LIBS_CPP11)
|
||||
prgs += env_cpp11.Program('test_uri_stl', ["uri_stl.o"], LIBS = BOOST_LIBS_CPP11)
|
||||
prgs += env_cpp11.Program('test_close_stl', ["close_stl.o"], LIBS = BOOST_LIBS_CPP11)
|
||||
prgs += env_cpp11.Program('test_sha1_stl', ["sha1_stl.o"], LIBS = BOOST_LIBS_CPP11)
|
||||
prgs += env_cpp11.Program('test_error_stl', ["error_stl.o"], LIBS = BOOST_LIBS_CPP11)
|
||||
|
||||
Return('prgs')
|
||||
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
//#define BOOST_TEST_DYN_LINK
|
||||
#define BOOST_TEST_MODULE error
|
||||
#include <boost/test/unit_test.hpp>
|
||||
|
||||
#include <websocketpp/error.hpp>
|
||||
|
||||
BOOST_AUTO_TEST_CASE( constructing_exceptions ) {
|
||||
websocketpp::lib::error_code test_ec = websocketpp::error::make_error_code(websocketpp::error::test);
|
||||
websocketpp::lib::error_code general_ec = websocketpp::error::make_error_code(websocketpp::error::general);
|
||||
|
||||
websocketpp::exception b("foo");
|
||||
websocketpp::exception c("foo",test_ec);
|
||||
websocketpp::exception d("");
|
||||
websocketpp::exception e("",test_ec);
|
||||
|
||||
BOOST_CHECK_EQUAL(b.what(),"foo");
|
||||
BOOST_CHECK_EQUAL(b.code(),general_ec);
|
||||
|
||||
BOOST_CHECK_EQUAL(c.what(),"foo");
|
||||
BOOST_CHECK_EQUAL(c.code(),test_ec);
|
||||
|
||||
BOOST_CHECK_EQUAL(d.what(),"Generic error");
|
||||
BOOST_CHECK_EQUAL(d.code(),general_ec);
|
||||
|
||||
BOOST_CHECK_EQUAL(e.what(),"Test Error");
|
||||
BOOST_CHECK_EQUAL(e.code(),test_ec);
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ Chat Tutorial
|
||||
=============
|
||||
|
||||
Goals of this tutorial:
|
||||
- Impliment a realtime websocket chat server
|
||||
- Implement a realtime websocket chat server
|
||||
|
||||
|
||||
Server
|
||||
|
||||
@@ -0,0 +1,335 @@
|
||||
/*
|
||||
* 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();
|
||||
}
|
||||
|
||||
void on_message(websocketpp::connection_hdl, client::message_ptr msg) {
|
||||
if (msg->get_opcode() == websocketpp::frame::opcode::text) {
|
||||
m_messages.push_back("<< " + msg->get_payload());
|
||||
} else {
|
||||
m_messages.push_back("<< " + websocketpp::utility::to_hex(msg->get_payload()));
|
||||
}
|
||||
}
|
||||
|
||||
websocketpp::connection_hdl get_hdl() const {
|
||||
return m_hdl;
|
||||
}
|
||||
|
||||
int get_id() const {
|
||||
return m_id;
|
||||
}
|
||||
|
||||
std::string get_status() const {
|
||||
return m_status;
|
||||
}
|
||||
|
||||
void record_sent_message(std::string message) {
|
||||
m_messages.push_back(">> " + message);
|
||||
}
|
||||
|
||||
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::vector<std::string> m_messages;
|
||||
};
|
||||
|
||||
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) << "\n";
|
||||
out << "> Messages Processed: (" << data.m_messages.size() << ") \n";
|
||||
|
||||
std::vector<std::string>::const_iterator it;
|
||||
for (it = data.m_messages.begin(); it != data.m_messages.end(); ++it) {
|
||||
out << *it << "\n";
|
||||
}
|
||||
|
||||
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 = websocketpp::lib::make_shared<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 = websocketpp::lib::make_shared<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
|
||||
));
|
||||
con->set_message_handler(websocketpp::lib::bind(
|
||||
&connection_metadata::on_message,
|
||||
metadata_ptr,
|
||||
websocketpp::lib::placeholders::_1,
|
||||
websocketpp::lib::placeholders::_2
|
||||
));
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
void send(int id, std::string message) {
|
||||
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.send(metadata_it->second->get_hdl(), message, websocketpp::frame::opcode::text, ec);
|
||||
if (ec) {
|
||||
std::cout << "> Error sending message: " << ec.message() << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
metadata_it->second->record_sent_message(message);
|
||||
}
|
||||
|
||||
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"
|
||||
<< "send <connection id> <message>\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,4) == "send") {
|
||||
std::stringstream ss(input);
|
||||
|
||||
std::string cmd;
|
||||
int id;
|
||||
std::string message = "";
|
||||
|
||||
ss >> cmd >> id;
|
||||
std::getline(ss,message);
|
||||
|
||||
endpoint.send(id, message);
|
||||
} 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;
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
clang++ -std=c++11 -stdlib=libc++ -I/Users/zaphoyd/software/websocketpp/ -I/Users/zaphoyd/software/boost_1_55_0/ -D_WEBSOCKETPP_CPP11_STL_ step4.cpp /Users/zaphoyd/software/boost_1_55_0/stage/lib/libboost_system.a
|
||||
|
||||
clang++ -I/Users/zaphoyd/software/websocketpp/ -I/Users/zaphoyd/software/boost_1_55_0/ step4.cpp /Users/zaphoyd/software/boost_1_55_0/stage/lib/libboost_system.a /Users/zaphoyd/software/boost_1_55_0/stage/lib/libboost_thread.a /Users/zaphoyd/software/boost_1_55_0/stage/lib/libboost_random.a
|
||||
|
||||
clang++ -std=c++11 -stdlib=libc++ -I/Users/zaphoyd/Documents/websocketpp/ -I/Users/zaphoyd/Documents/boost_1_53_0_libcpp/ -D_WEBSOCKETPP_CPP11_STL_ step4.cpp /Users/zaphoyd/Documents/boost_1_53_0_libcpp/stage/lib/libboost_system.a
|
||||
|
||||
*/
|
||||
@@ -221,7 +221,7 @@ int main() {
|
||||
|
||||
_Opening WebSocket connections_
|
||||
|
||||
This step adds two new commands to app_client. The ability to open a new connection and the ability to view information about a previously opened connection. Every connection that gets opened will be assigned an integer connection id that the user of the program can use to interact with that connection.
|
||||
This step adds two new commands to utility_client. The ability to open a new connection and the ability to view information about a previously opened connection. Every connection that gets opened will be assigned an integer connection id that the user of the program can use to interact with that connection.
|
||||
|
||||
#### New Connection Metadata Object
|
||||
|
||||
@@ -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.
|
||||
@@ -263,7 +263,7 @@ A new WebSocket connection is initiated via a three step process. First, a conne
|
||||
> **Exception throwing varients**
|
||||
> All user facing endpoint methods that take and use an `error_code` parameter have a version that throws an exception instead. These methods are identical in function and signature except for the lack of the final ec parameter. The type of the exception thrown is `websocketpp::exception`. This type derives from `std::exception` so it can be caught by catch blocks grabbing generic `std::exception`s. The `websocketpp::exception::code()` method may be used to extract the machine readable `error_code` value from an exception.
|
||||
>
|
||||
> For clarity about error handling the app_client example uses exclusively the exception free varients of these methods. Your application may choose to use either.
|
||||
> For clarity about error handling the utility_client example uses exclusively the exception free varients of these methods. Your application may choose to use either.
|
||||
|
||||
If connection creation succeeds, the next sequential connection ID is generated and a `connection_metadata` object is inserted into the connection list under that ID. Initially the metadata object stores the connection ID, the `connection_hdl`, and the URI the connection was opened to.
|
||||
|
||||
@@ -286,7 +286,7 @@ Next, the connection request is configured. For this step the only configuration
|
||||
>
|
||||
> The function signature of each handler can be looked up in the list above in the manual. In general, all handlers include the `connection_hdl` identifying which connection this even is associated with as the first parameter. Some handlers (such as the message handler) include additional parameters. Most handlers have a void return value but some (`validate`, `ping`, `tls_init`) do not. The specific meanings of the return values are documented in the handler list linked above.
|
||||
|
||||
`app_client` registers an open and a fail handler. We will use these to track whether each connection was successfully opened or failed. If it successfully opens, we will gather some information from the opening handshake and store it with our connection metadata.
|
||||
`utility_client` registers an open and a fail handler. We will use these to track whether each connection was successfully opened or failed. If it successfully opens, we will gather some information from the opening handshake and store it with our connection metadata.
|
||||
|
||||
In this example we are going to set connection specific handlers that are bound directly to the metadata object associated with our connection. This allows us to avoid performing a lookup in each handler to find the metadata object we plan to update which is a bit more efficient.
|
||||
|
||||
@@ -591,7 +591,7 @@ void close(int id, websocketpp::close::status::value code) {
|
||||
|
||||
#### Add close option to the command loop and help message
|
||||
|
||||
A close option is added to the command loop. It takes a connection ID and optionally a close code and a close reason. If no code is specified the default of 1000/Normal is used. If no reason is specified, none is sent. The `endpoint::send` method will do some error checking and abort the close request if you try and send an invalid code or a reason with invalid UTF8 formatting. Reason strings longer than 125 characters will be truncated.
|
||||
A close option is added to the command loop. It takes a connection ID and optionally a close code and a close reason. If no code is specified the default of 1000/Normal is used. If no reason is specified, none is sent. The `endpoint::close` method will do some error checking and abort the close request if you try and send an invalid code or a reason with invalid UTF8 formatting. Reason strings longer than 125 characters will be truncated.
|
||||
|
||||
An entry is also added to the help system to describe how the new command may be used.
|
||||
|
||||
@@ -654,7 +654,7 @@ Enter Command: close 0 1001 example message
|
||||
Enter Command: show 0
|
||||
> URI: ws://localhost:9002
|
||||
> Status: Closed
|
||||
> Remote Server: WebSocket++/0.3.0-alpha4
|
||||
> Remote Server: WebSocket++/0.4.0
|
||||
> Error/close reason: close code: 1001 (Going away), close reason: example message
|
||||
Enter Command: connect ws://localhost:9002
|
||||
> Created connection with id 1
|
||||
@@ -668,14 +668,158 @@ Enter Command: quit
|
||||
|
||||
_Sending and receiving messages_
|
||||
|
||||
- Sending a messages
|
||||
- terminology: WebSocket opcodes, text vs binary messages
|
||||
- Receiving a message
|
||||
This step adds a command to send a message on a given connection and updates the show command to print a transcript of all sent and received messages for that connection.
|
||||
|
||||
> ###### Terminology: WebSocket message types (opcodes)
|
||||
> WebSocket messages have types indicated by their opcode. The protocol currently specifies two different opcodes for data messages, text and binary. Text messages represent UTF8 text and will be validated as such. Binary messages represent raw binary bytes and are passed through directly with no validation.
|
||||
>
|
||||
> WebSocket++ provides the values `websocketpp::frame::opcode::text` and `websocketpp::frame::opcode::binary` that can be used to direct how outgoing messages should be sent and to check how incoming messages are formatted.
|
||||
|
||||
#### Sending Messages
|
||||
|
||||
Messages are sent using `endpoint::send`. This is a thread safe method that may be called from anywhere to queue a message for sending on the specified connection. There are three send overloads for use with different scenarios.
|
||||
|
||||
Each method takes a `connection_hdl` to indicate which connection to send the message on as well as a `frame::opcode::value` to indicate which opcode to label the message as. All overloads are also available with an exception free varient that fills in a a status/error code instead of throwing.
|
||||
|
||||
The first overload, `connection_hdl hdl, std::string const & payload, frame::opcode::value op`, takes a `std::string`. The string contents are copied into an internal buffer and can be safely modified after calling send.
|
||||
|
||||
The second overload, `connection_hdl hdl, void const * payload, size_t len, frame::opcode::value op`, takes a void * buffer and length. The buffer contents are copied and can be safely modified after calling send.
|
||||
|
||||
The third overload, `connection_hdl hdl, message_ptr msg`, takes a WebSocket++ `message_ptr`. This overload allows a message to be constructed in place before the call to send. It also may allow a single message buffer to be sent multiple times, including to multiple connections, without copying. Whether or not this actually happens depends on other factors such as whether compression is enabled. The contents of the message buffer may not be safely modified after being sent.
|
||||
|
||||
> ###### Terminology: Outgoing WebSocket message queueing & flow control
|
||||
> In many configurations, such as when the Asio based transport is in use, WebSocket++ is an asynchronous system. As such the `endpoint::send` method may return before any bytes are actually written to the outgoing socket. In cases where send is called multiple times in quick succession messages may be coalesced and sent in the same operation or even the same TCP packet. When this happens the message boundaries are preserved (each call to send will produce a separate message).
|
||||
>
|
||||
> In the case of applications that call send from inside a handler this means that no messages will be written to the socket until that handler returns. If you are planning to send many messages in this manor or need a message to be written on the wire before continuing you should look into using multiple threads or the built in timer/interrupt handler functionality.
|
||||
>
|
||||
> If the outgoing socket link is slow messages may build up in this queue. You can use `connection::get_buffered_amount` to query the current size of the written message queue to decide if you want to change your sending behavior.
|
||||
|
||||
#### Add send method to `websocket_endpoint`
|
||||
|
||||
Like the close method, send will start by looking up the given connection ID in the connection list. Next a send request is sent to the connection's handle with the specified WebSocket message and the text opcode. Finally, we record the sent message with our connection metadata object so later our show connection command can print a list of messages sent.
|
||||
|
||||
```cpp
|
||||
void send(int id, std::string message) {
|
||||
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.send(metadata_it->second->get_hdl(), message, websocketpp::frame::opcode::text, ec);
|
||||
if (ec) {
|
||||
std::cout << "> Error sending message: " << ec.message() << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
metadata_it->second->record_sent_message(message);
|
||||
}
|
||||
```
|
||||
|
||||
#### Add send option to the command loop and help message
|
||||
|
||||
A send option is added to the command loop. It takes a connection ID and a text message to send. An entry is also added to the help system to describe how the new command may be used.
|
||||
|
||||
```cpp
|
||||
else if (input.substr(0,4) == "send") {
|
||||
std::stringstream ss(input);
|
||||
|
||||
std::string cmd;
|
||||
int id;
|
||||
std::string message = "";
|
||||
|
||||
ss >> cmd >> id;
|
||||
std::getline(ss,message);
|
||||
|
||||
endpoint.send(id, message);
|
||||
}
|
||||
```
|
||||
|
||||
#### Add glue to `connection_metadata` for storing sent messages
|
||||
|
||||
In order to store messages sent on this connection some code is added to `connection_metadata`. This includes a new data member `std::vector<std::string> m_messages` to keep track of all messages sent and received as well as a method for adding a sent message in that list:
|
||||
|
||||
```cpp
|
||||
void record_sent_message(std::string message) {
|
||||
m_messages.push_back(">> " + message);
|
||||
}
|
||||
```
|
||||
|
||||
Finally the connection metadata output operator is updated to also print a list of processed messages:
|
||||
|
||||
```cpp
|
||||
out << "> Messages Processed: (" << data.m_messages.size() << ") \n";
|
||||
|
||||
std::vector<std::string>::const_iterator it;
|
||||
for (it = data.m_messages.begin(); it != data.m_messages.end(); ++it) {
|
||||
out << *it << "\n";
|
||||
}
|
||||
```
|
||||
|
||||
#### Receiving Messages
|
||||
|
||||
Messages are received by registering a message handler. This handler will be called once per message received and its signature is `void on_message(websocketpp::connection_hdl hdl, endpoint::message_ptr msg)`. The `connection_hdl`, like the similar parameter from the other handlers is a handle for the connection that the message was received on. The `message_ptr` is a pointer to an object that can be queried for the message payload, opcode, and other metadata. Note that the message_ptr type, as well as its underlying message type, is dependent on how your endpoint is configured and may be different for different configs.
|
||||
|
||||
#### Add a message handler to method to `connection_metadata`
|
||||
|
||||
The message receiving behave that we are implementing will be to collect all messages sent and received and to print them in order when the show connection command is run. The sent messages are already being added to that list. Now we add a message handler that pushes received messages to the list as well. Text messages are pushed as-is. Binary messages are first converted to printable hexadecimal format.
|
||||
|
||||
```cpp
|
||||
void on_message(websocketpp::connection_hdl hdl, client::message_ptr msg) {
|
||||
if (msg->get_opcode() == websocketpp::frame::opcode::text) {
|
||||
m_messages.push_back(msg->get_payload());
|
||||
} else {
|
||||
m_messages.push_back(websocketpp::utility::to_hex(msg->get_payload()));
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
In order to have this handler called when new messages are received we also register it with our connection. Note that unlike most other handlers, the message handler has two parameters and thus needs two placeholders.
|
||||
|
||||
```cpp
|
||||
con->set_message_handler(websocketpp::lib::bind(
|
||||
&connection_metadata::on_message,
|
||||
metadata_ptr,
|
||||
websocketpp::lib::placeholders::_1,
|
||||
websocketpp::lib::placeholders::_2
|
||||
));
|
||||
```
|
||||
|
||||
#### Build
|
||||
|
||||
There are no changes to the build instructions from step 5
|
||||
|
||||
#### Run
|
||||
|
||||
In this example run we are connecting to the WebSocket++ example echo_server. This server will repeat any message we send back to it. You can also try testing this with the echo server at `ws://echo.websocket.org` with similar results.
|
||||
|
||||
```
|
||||
Enter Command: connect ws://localhost:9002
|
||||
> Created connection with id 0
|
||||
Enter Command: send 0 example message
|
||||
Enter Command: show 0
|
||||
> URI: ws://localhost:9002
|
||||
> Status: Open
|
||||
> Remote Server: WebSocket++/0.4.0
|
||||
> Error/close reason: N/A
|
||||
> Messages Processed: (2)
|
||||
>> example message
|
||||
<< example message
|
||||
```
|
||||
|
||||
### Step 7
|
||||
|
||||
_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
|
||||
--------------------------------
|
||||
|
||||
|
||||
@@ -150,6 +150,21 @@ namespace status {
|
||||
* illegal on the wire.
|
||||
*/
|
||||
static value const tls_handshake = 1015;
|
||||
|
||||
/// A generic subprotocol error
|
||||
/**
|
||||
* Indicates that a subprotocol error occurred. Typically this involves
|
||||
* receiving a message that is not formatted as a valid message for the
|
||||
* subprotocol in use.
|
||||
*/
|
||||
static value const subprotocol_error = 3000;
|
||||
|
||||
/// A invalid subprotocol data
|
||||
/**
|
||||
* Indicates that data was received that violated the specification of the
|
||||
* subprotocol in use.
|
||||
*/
|
||||
static value const invalid_subprotocol_data = 3001;
|
||||
|
||||
/// First value in range reserved for future protocol use
|
||||
static value const rsv_start = 1016;
|
||||
@@ -235,6 +250,10 @@ namespace status {
|
||||
return "Internal endpoint error";
|
||||
case tls_handshake:
|
||||
return "TLS handshake failure";
|
||||
case subprotocol_error:
|
||||
return "Generic subprotocol error";
|
||||
case invalid_subprotocol_data:
|
||||
return "Invalid subprotocol data";
|
||||
default:
|
||||
return "Unknown";
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -51,6 +51,11 @@
|
||||
// C++11 compiler via the __cplusplus macro or the user/build system
|
||||
// supplies one of the two preprocessor defines below:
|
||||
|
||||
// This is defined to allow other WebSocket++ common headers to enable
|
||||
// C++11 features when they are detected by this file rather than
|
||||
// duplicating the above logic in every common header.
|
||||
#define _WEBSOCKETPP_CPP11_INTERNAL_
|
||||
|
||||
// _WEBSOCKETPP_CPP11_STRICT_
|
||||
//
|
||||
// This define reports to WebSocket++ that 100% of the language and library
|
||||
@@ -75,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.
|
||||
|
||||
@@ -28,12 +28,27 @@
|
||||
#ifndef WEBSOCKETPP_COMMON_FUNCTIONAL_HPP
|
||||
#define WEBSOCKETPP_COMMON_FUNCTIONAL_HPP
|
||||
|
||||
#if defined _WEBSOCKETPP_CPP11_STL_ && !defined _WEBSOCKETPP_NO_CPP11_FUNCTIONAL_
|
||||
#include <websocketpp/common/cpp11.hpp>
|
||||
|
||||
// If we've determined that we're in full C++11 mode and the user hasn't
|
||||
// explicitly disabled the use of C++11 functional header, then prefer it to
|
||||
// boost.
|
||||
#if defined _WEBSOCKETPP_CPP11_INTERNAL_ && !defined _WEBSOCKETPP_NO_CPP11_FUNCTIONAL_
|
||||
#ifndef _WEBSOCKETPP_CPP11_FUNCTIONAL_
|
||||
#define _WEBSOCKETPP_CPP11_FUNCTIONAL_
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// If we're on Visual Studio 2010 or higher and haven't explicitly disabled
|
||||
// the use of C++11 functional header then prefer it to boost.
|
||||
#if defined(_MSC_VER) && _MSC_VER >= 1600 && !defined _WEBSOCKETPP_NO_CPP11_FUNCTIONAL_
|
||||
#ifndef _WEBSOCKETPP_CPP11_FUNCTIONAL_
|
||||
#define _WEBSOCKETPP_CPP11_FUNCTIONAL_
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#ifdef _WEBSOCKETPP_CPP11_FUNCTIONAL_
|
||||
#include <functional>
|
||||
#else
|
||||
@@ -52,14 +67,14 @@ namespace lib {
|
||||
using std::bind;
|
||||
using std::ref;
|
||||
namespace placeholders = std::placeholders;
|
||||
|
||||
|
||||
// There are some cases where a C++11 compiler balks at using std::ref
|
||||
// but a C++03 compiler using boost function requires boost::ref. As such
|
||||
// lib::ref is not useful in these cases. Instead this macro allows the use
|
||||
// of boost::ref in the case of a boost compile or no reference wrapper at
|
||||
// all in the case of a C++11 compile
|
||||
#define _WEBSOCKETPP_REF(x) x
|
||||
|
||||
|
||||
template <typename T>
|
||||
void clear_function(T & x) {
|
||||
x = nullptr;
|
||||
@@ -72,11 +87,12 @@ namespace lib {
|
||||
/// \todo this feels hacky, is there a better way?
|
||||
using ::_1;
|
||||
using ::_2;
|
||||
using ::_3;
|
||||
}
|
||||
|
||||
|
||||
// See above definition for more details on what this is and why it exists
|
||||
#define _WEBSOCKETPP_REF(x) boost::ref(x)
|
||||
|
||||
|
||||
template <typename T>
|
||||
void clear_function(T & x) {
|
||||
x.clear();
|
||||
|
||||
@@ -28,12 +28,27 @@
|
||||
#ifndef WEBSOCKETPP_COMMON_MEMORY_HPP
|
||||
#define WEBSOCKETPP_COMMON_MEMORY_HPP
|
||||
|
||||
#if defined _WEBSOCKETPP_CPP11_STL_ && !defined _WEBSOCKETPP_NO_CPP11_MEMORY_
|
||||
#include <websocketpp/common/cpp11.hpp>
|
||||
|
||||
// If we've determined that we're in full C++11 mode and the user hasn't
|
||||
// explicitly disabled the use of C++11 memory header, then prefer it to
|
||||
// boost.
|
||||
#if defined _WEBSOCKETPP_CPP11_INTERNAL_ && !defined _WEBSOCKETPP_NO_CPP11_MEMORY_
|
||||
#ifndef _WEBSOCKETPP_CPP11_MEMORY_
|
||||
#define _WEBSOCKETPP_CPP11_MEMORY_
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// If we're on Visual Studio 2010 or higher and haven't explicitly disabled
|
||||
// the use of C++11 functional header then prefer it to boost.
|
||||
#if defined(_MSC_VER) && _MSC_VER >= 1600 && !defined _WEBSOCKETPP_NO_CPP11_MEMORY_
|
||||
#ifndef _WEBSOCKETPP_CPP11_MEMORY_
|
||||
#define _WEBSOCKETPP_CPP11_MEMORY_
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#ifdef _WEBSOCKETPP_CPP11_MEMORY_
|
||||
#include <memory>
|
||||
#else
|
||||
|
||||
@@ -36,13 +36,15 @@
|
||||
#include <netinet/in.h>
|
||||
#endif
|
||||
|
||||
#include <websocketpp/common/stdint.hpp>
|
||||
|
||||
namespace websocketpp {
|
||||
namespace lib {
|
||||
namespace net {
|
||||
|
||||
inline bool is_little_endian() {
|
||||
short int val = 0x1;
|
||||
char *ptr = (char*)&val;
|
||||
char *ptr = reinterpret_cast<char *>(&val);
|
||||
return (ptr[0] == 1);
|
||||
}
|
||||
|
||||
|
||||
@@ -38,4 +38,9 @@
|
||||
#define NOMINMAX
|
||||
#endif
|
||||
|
||||
// Bump up the variadic parameter max for Visual Studio 2012
|
||||
#if defined(_MSC_VER) && _MSC_VER == 1700
|
||||
#define _VARIADIC_MAX 8
|
||||
#endif
|
||||
|
||||
#endif // WEBSOCKETPP_COMMON_PLATFORMS_HPP
|
||||
@@ -28,12 +28,28 @@
|
||||
#ifndef WEBSOCKETPP_COMMON_RANDOM_DEVICE_HPP
|
||||
#define WEBSOCKETPP_COMMON_RANDOM_DEVICE_HPP
|
||||
|
||||
#if defined _WEBSOCKETPP_CPP11_STL_ && !defined _WEBSOCKETPP_NO_CPP11_RANDOM_DEVICE_
|
||||
#include <websocketpp/common/cpp11.hpp>
|
||||
|
||||
// If we've determined that we're in full C++11 mode and the user hasn't
|
||||
// explicitly disabled the use of C++11 random header, then prefer it to
|
||||
// boost.
|
||||
#if defined _WEBSOCKETPP_CPP11_INTERNAL_ && !defined _WEBSOCKETPP_NO_CPP11_RANDOM_DEVICE_
|
||||
#ifndef _WEBSOCKETPP_CPP11_RANDOM_DEVICE_
|
||||
#define _WEBSOCKETPP_CPP11_RANDOM_DEVICE_
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
// If we're on Visual Studio 2010 or higher and haven't explicitly disabled
|
||||
// the use of C++11 random header then prefer it to boost.
|
||||
#if defined(_MSC_VER) && _MSC_VER >= 1600 && !defined _WEBSOCKETPP_NO_CPP11_MEMORY_
|
||||
#ifndef _WEBSOCKETPP_CPP11_MEMORY_
|
||||
#define _WEBSOCKETPP_CPP11_MEMORY_
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#ifdef _WEBSOCKETPP_CPP11_RANDOM_DEVICE_
|
||||
#include <random>
|
||||
#else
|
||||
|
||||
@@ -28,12 +28,28 @@
|
||||
#ifndef WEBSOCKETPP_COMMON_SYSTEM_ERROR_HPP
|
||||
#define WEBSOCKETPP_COMMON_SYSTEM_ERROR_HPP
|
||||
|
||||
#if defined _WEBSOCKETPP_CPP11_STL_ && !defined _WEBSOCKETPP_NO_CPP11_SYSTEM_ERROR_
|
||||
|
||||
#include <websocketpp/common/cpp11.hpp>
|
||||
|
||||
// If we've determined that we're in full C++11 mode and the user hasn't
|
||||
// explicitly disabled the use of C++11 system_error header, then prefer it to
|
||||
// boost.
|
||||
#if defined _WEBSOCKETPP_CPP11_INTERNAL_ && !defined _WEBSOCKETPP_NO_CPP11_SYSTEM_ERROR_
|
||||
#ifndef _WEBSOCKETPP_CPP11_SYSTEM_ERROR_
|
||||
#define _WEBSOCKETPP_CPP11_SYSTEM_ERROR_
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// If we're on Visual Studio 2010 or higher and haven't explicitly disabled
|
||||
// the use of C++11 system_error header then prefer it to boost.
|
||||
#if defined(_MSC_VER) && _MSC_VER >= 1600 && !defined _WEBSOCKETPP_NO_CPP11_SYSTEM_ERROR_
|
||||
#ifndef _WEBSOCKETPP_CPP11_SYSTEM_ERROR_
|
||||
#define _WEBSOCKETPP_CPP11_SYSTEM_ERROR_
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#ifdef _WEBSOCKETPP_CPP11_SYSTEM_ERROR_
|
||||
#include <system_error>
|
||||
#else
|
||||
@@ -45,6 +61,7 @@ namespace websocketpp {
|
||||
namespace lib {
|
||||
|
||||
#ifdef _WEBSOCKETPP_CPP11_SYSTEM_ERROR_
|
||||
using std::errc;
|
||||
using std::error_code;
|
||||
using std::error_category;
|
||||
using std::error_condition;
|
||||
@@ -52,6 +69,7 @@ namespace lib {
|
||||
#define _WEBSOCKETPP_ERROR_CODE_ENUM_NS_START_ namespace std {
|
||||
#define _WEBSOCKETPP_ERROR_CODE_ENUM_NS_END_ }
|
||||
#else
|
||||
namespace errc = boost::system::errc;
|
||||
using boost::system::error_code;
|
||||
using boost::system::error_category;
|
||||
using boost::system::error_condition;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2014, Peter Thorson. All rights reserved.
|
||||
* Copyright (c) 2015, Peter Thorson. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
@@ -28,9 +28,18 @@
|
||||
#ifndef WEBSOCKETPP_COMMON_THREAD_HPP
|
||||
#define WEBSOCKETPP_COMMON_THREAD_HPP
|
||||
|
||||
#if defined _WEBSOCKETPP_CPP11_STL_ && !defined _WEBSOCKETPP_NO_CPP11_THREAD_
|
||||
#ifndef _WEBSOCKETPP_CPP11_THREAD_
|
||||
#define _WEBSOCKETPP_CPP11_THREAD_
|
||||
#include <websocketpp/common/cpp11.hpp>
|
||||
|
||||
// If we autodetect C++11 and haven't been explicitly instructed to not use
|
||||
// C++11 threads, then set the defines that instructs the rest of this header
|
||||
// to use C++11 <thread> and <mutex>
|
||||
#if defined _WEBSOCKETPP_CPP11_INTERNAL_ && !defined _WEBSOCKETPP_NO_CPP11_THREAD_
|
||||
// MinGW by default does not support C++11 thread/mutex so even if the
|
||||
// internal check for C++11 passes, ignore it if we are on MinGW
|
||||
#if (!defined(__MINGW32__) && !defined(__MINGW64__))
|
||||
#ifndef _WEBSOCKETPP_CPP11_THREAD_
|
||||
#define _WEBSOCKETPP_CPP11_THREAD_
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
#ifndef WEBSOCKETPP_COMMON_TIME_HPP
|
||||
#define WEBSOCKETPP_COMMON_TIME_HPP
|
||||
|
||||
#include <time.h>
|
||||
#include <ctime>
|
||||
|
||||
namespace websocketpp {
|
||||
namespace lib {
|
||||
@@ -40,7 +40,9 @@ namespace lib {
|
||||
/// Thread safe cross platform localtime
|
||||
inline std::tm localtime(std::time_t const & time) {
|
||||
std::tm tm_snapshot;
|
||||
#if (defined(WIN32) || defined(_WIN32) || defined(__WIN32__))
|
||||
#if (defined(__MINGW32__) || defined(__MINGW64__))
|
||||
memcpy(&tm_snapshot, ::localtime(&time), sizeof(std::tm));
|
||||
#elif (defined(WIN32) || defined(_WIN32) || defined(__WIN32__))
|
||||
localtime_s(&tm_snapshot, &time);
|
||||
#else
|
||||
localtime_r(&time, &tm_snapshot); // POSIX
|
||||
|
||||
@@ -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:
|
||||
@@ -25,47 +25,39 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef WEBSOCKETPP_ERROR_MESSAGE_HPP
|
||||
#define WEBSOCKETPP_ERROR_MESSAGE_HPP
|
||||
#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 {
|
||||
|
||||
/**
|
||||
* The transport::security::* classes are a set of security/socket related
|
||||
* policies and support code for the ASIO transport types.
|
||||
*/
|
||||
class error_msg {
|
||||
public:
|
||||
const std::string& get_msg() const {
|
||||
return m_error_msg;
|
||||
}
|
||||
|
||||
void set_msg(const std::string& msg) {
|
||||
m_error_msg = msg;
|
||||
}
|
||||
|
||||
void append_msg(const std::string& msg) {
|
||||
m_error_msg.append(msg);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void set_msg(const T& thing) {
|
||||
std::stringsteam val;
|
||||
val << thing;
|
||||
this->set_msg(val.str());
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void append_msg(const T& thing) {
|
||||
std::stringsteam val;
|
||||
val << thing;
|
||||
this->append_msg(val.str());
|
||||
}
|
||||
private:
|
||||
// error resources
|
||||
std::string m_error_msg;
|
||||
};
|
||||
#ifdef _WEBSOCKETPP_CPP11_TYPE_TRAITS_
|
||||
using std::aligned_storage;
|
||||
#else
|
||||
using boost::aligned_storage;
|
||||
#endif
|
||||
|
||||
} // namespace lib
|
||||
} // namespace websocketpp
|
||||
|
||||
#endif // WEBSOCKETPP_ERROR_MESSAGE_HPP
|
||||
#endif // WEBSOCKETPP_COMMON_TYPE_TRAITS_HPP
|
||||
@@ -226,6 +226,18 @@ struct core {
|
||||
* @since 0.3.0
|
||||
*/
|
||||
static const size_t max_message_size = 32000000;
|
||||
|
||||
/// Default maximum http body size
|
||||
/**
|
||||
* Default value for the http parser's maximum body size. Maximum body size
|
||||
* determines the point at which the library will abort reading an HTTP
|
||||
* connection with the 413/request entity too large error.
|
||||
*
|
||||
* The default is 32MB
|
||||
*
|
||||
* @since 0.5.0
|
||||
*/
|
||||
static const size_t max_http_body_size = 32000000;
|
||||
|
||||
/// Global flag for enabling/disabling extensions
|
||||
static const bool enable_extensions = true;
|
||||
|
||||
@@ -236,6 +236,18 @@ struct core_client {
|
||||
*/
|
||||
static const size_t max_message_size = 32000000;
|
||||
|
||||
/// Default maximum http body size
|
||||
/**
|
||||
* Default value for the http parser's maximum body size. Maximum body size
|
||||
* determines the point at which the library will abort reading an HTTP
|
||||
* connection with the 413/request entity too large error.
|
||||
*
|
||||
* The default is 32MB
|
||||
*
|
||||
* @since 0.5.0
|
||||
*/
|
||||
static const size_t max_http_body_size = 32000000;
|
||||
|
||||
/// Global flag for enabling/disabling extensions
|
||||
static const bool enable_extensions = true;
|
||||
|
||||
|
||||
@@ -228,6 +228,18 @@ struct debug_core {
|
||||
*/
|
||||
static const size_t max_message_size = 32000000;
|
||||
|
||||
/// Default maximum http body size
|
||||
/**
|
||||
* Default value for the http parser's maximum body size. Maximum body size
|
||||
* determines the point at which the library will abort reading an HTTP
|
||||
* connection with the 413/request entity too large error.
|
||||
*
|
||||
* The default is 32MB
|
||||
*
|
||||
* @since 0.5.0
|
||||
*/
|
||||
static const size_t max_http_body_size = 32000000;
|
||||
|
||||
/// Global flag for enabling/disabling extensions
|
||||
static const bool enable_extensions = true;
|
||||
|
||||
|
||||
@@ -112,10 +112,8 @@ struct minimal_server {
|
||||
endpoint_msg_manager_type;
|
||||
|
||||
/// Logging policies
|
||||
typedef websocketpp::log::stub<concurrency_type,
|
||||
websocketpp::log::elevel> elog_type;
|
||||
typedef websocketpp::log::stub<concurrency_type,
|
||||
websocketpp::log::alevel> alog_type;
|
||||
typedef websocketpp::log::stub elog_type;
|
||||
typedef websocketpp::log::stub alog_type;
|
||||
|
||||
/// RNG policies
|
||||
typedef websocketpp::random::none::int_generator<uint32_t> rng_type;
|
||||
@@ -256,6 +254,18 @@ struct minimal_server {
|
||||
*/
|
||||
static const size_t max_message_size = 32000000;
|
||||
|
||||
/// Default maximum http body size
|
||||
/**
|
||||
* Default value for the http parser's maximum body size. Maximum body size
|
||||
* determines the point at which the library will abort reading an HTTP
|
||||
* connection with the 413/request entity too large error.
|
||||
*
|
||||
* The default is 32MB
|
||||
*
|
||||
* @since 0.5.0
|
||||
*/
|
||||
static const size_t max_http_body_size = 32000000;
|
||||
|
||||
/// Global flag for enabling/disabling extensions
|
||||
static const bool enable_extensions = true;
|
||||
|
||||
|
||||
+143
-62
@@ -29,18 +29,18 @@
|
||||
#define WEBSOCKETPP_CONNECTION_HPP
|
||||
|
||||
#include <websocketpp/close.hpp>
|
||||
#include <websocketpp/common/connection_hdl.hpp>
|
||||
#include <websocketpp/common/cpp11.hpp>
|
||||
#include <websocketpp/common/functional.hpp>
|
||||
#include <websocketpp/error.hpp>
|
||||
#include <websocketpp/frame.hpp>
|
||||
#include <websocketpp/http/constants.hpp>
|
||||
|
||||
#include <websocketpp/logger/levels.hpp>
|
||||
#include <websocketpp/processors/processor.hpp>
|
||||
#include <websocketpp/transport/base/connection.hpp>
|
||||
#include <websocketpp/http/constants.hpp>
|
||||
|
||||
#include <websocketpp/common/connection_hdl.hpp>
|
||||
#include <websocketpp/common/cpp11.hpp>
|
||||
#include <websocketpp/common/functional.hpp>
|
||||
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
#include <queue>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
@@ -119,7 +119,7 @@ typedef lib::function<void(connection_hdl,std::string)> pong_timeout_handler;
|
||||
/**
|
||||
* The validate handler is called after a WebSocket handshake has been received
|
||||
* and processed but before it has been accepted. This gives the application a
|
||||
* chance to impliment connection details specific policies for accepting
|
||||
* chance to implement connection details specific policies for accepting
|
||||
* connections and the ability to negotiate extensions and subprotocols.
|
||||
*
|
||||
* The validate handler return value indicates whether or not the connection
|
||||
@@ -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
|
||||
@@ -311,6 +325,8 @@ public:
|
||||
, m_rng(rng)
|
||||
, m_local_close_code(close::status::abnormal_close)
|
||||
, m_remote_close_code(close::status::abnormal_close)
|
||||
, m_is_http(false)
|
||||
, m_http_state(session::http_state::init)
|
||||
, m_was_clean(false)
|
||||
{
|
||||
m_alog.write(log::alevel::devel,"connection constructor");
|
||||
@@ -533,8 +549,8 @@ public:
|
||||
|
||||
/// Get maximum message size
|
||||
/**
|
||||
* Get maximum message size. Maximum message size determines the point at which the
|
||||
* connection will fail a connection with the message_too_big protocol error.
|
||||
* Get maximum message size. Maximum message size determines the point at
|
||||
* which the connection will fail with the message_too_big protocol error.
|
||||
*
|
||||
* The default is set by the endpoint that creates the connection.
|
||||
*
|
||||
@@ -546,9 +562,9 @@ public:
|
||||
|
||||
/// Set maximum message size
|
||||
/**
|
||||
* Set maximum message size. Maximum message size determines the point at which the
|
||||
* connection will fail a connection with the message_too_big protocol error. This
|
||||
* value may be changed during the connection.
|
||||
* Set maximum message size. Maximum message size determines the point at
|
||||
* which the connection will fail with the message_too_big protocol error.
|
||||
* This value may be changed during the connection.
|
||||
*
|
||||
* The default is set by the endpoint that creates the connection.
|
||||
*
|
||||
@@ -562,6 +578,38 @@ public:
|
||||
m_processor->set_max_message_size(new_value);
|
||||
}
|
||||
}
|
||||
|
||||
/// Get maximum HTTP message body size
|
||||
/**
|
||||
* Get maximum HTTP message body size. Maximum message body size determines
|
||||
* the point at which the connection will stop reading an HTTP request whose
|
||||
* body is too large.
|
||||
*
|
||||
* The default is set by the endpoint that creates the connection.
|
||||
*
|
||||
* @since 0.5.0
|
||||
*
|
||||
* @return The maximum HTTP message body size
|
||||
*/
|
||||
size_t get_max_http_body_size() const {
|
||||
return m_request.get_max_body_size();
|
||||
}
|
||||
|
||||
/// Set maximum HTTP message body size
|
||||
/**
|
||||
* Set maximum HTTP message body size. Maximum message body size determines
|
||||
* the point at which the connection will stop reading an HTTP request whose
|
||||
* body is too large.
|
||||
*
|
||||
* The default is set by the endpoint that creates the connection.
|
||||
*
|
||||
* @since 0.5.0
|
||||
*
|
||||
* @param new_value The value to set as the maximum message size.
|
||||
*/
|
||||
void set_max_http_body_size(size_t new_value) {
|
||||
m_request.set_max_body_size(new_value);
|
||||
}
|
||||
|
||||
//////////////////////////////////
|
||||
// Uncategorized public methods //
|
||||
@@ -899,7 +947,18 @@ public:
|
||||
* @param key Name of the header to get
|
||||
* @return The value of the header
|
||||
*/
|
||||
std::string const & get_request_header(std::string const & key);
|
||||
std::string const & get_request_header(std::string const & key) const;
|
||||
|
||||
/// Retrieve a request body
|
||||
/**
|
||||
* Retrieve the value of the request body. This value is typically used with
|
||||
* PUT and POST requests to upload files or other data. Only HTTP
|
||||
* connections will ever have bodies. WebSocket connection's will always
|
||||
* have blank bodies.
|
||||
*
|
||||
* @return The value of the request body.
|
||||
*/
|
||||
std::string const & get_request_body() const;
|
||||
|
||||
/// Retrieve a response header
|
||||
/**
|
||||
@@ -908,7 +967,7 @@ public:
|
||||
* @param key Name of the header to get
|
||||
* @return The value of the header
|
||||
*/
|
||||
std::string const & get_response_header(std::string const & key);
|
||||
std::string const & get_response_header(std::string const & key) const;
|
||||
|
||||
/// Set response status code and message
|
||||
/**
|
||||
@@ -1016,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 //
|
||||
@@ -1158,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);
|
||||
@@ -1168,7 +1274,7 @@ public:
|
||||
void read_frame();
|
||||
|
||||
/// Get array of WebSocket protocol versions that this connection supports.
|
||||
const std::vector<int>& get_supported_versions() const;
|
||||
std::vector<int> const & get_supported_versions() const;
|
||||
|
||||
/// Sets the handler for a terminating connection. Should only be used
|
||||
/// internally by the endpoint class.
|
||||
@@ -1202,60 +1308,21 @@ protected:
|
||||
void handle_transport_init(lib::error_code const & ec);
|
||||
|
||||
/// Set m_processor based on information in m_request. Set m_response
|
||||
/// status and return false on error.
|
||||
bool initialize_processor();
|
||||
/// status and return an error code indicating status.
|
||||
lib::error_code initialize_processor();
|
||||
|
||||
/// Perform WebSocket handshake validation of m_request using m_processor.
|
||||
/// set m_response and return false on error.
|
||||
bool process_handshake_request();
|
||||
|
||||
/// Atomically change the internal connection state.
|
||||
/**
|
||||
* @param req The required starting state. If the internal state does not
|
||||
* match req an exception is thrown.
|
||||
*
|
||||
* @param dest The state to change to.
|
||||
*
|
||||
* @param msg The message to include in the exception thrown
|
||||
*/
|
||||
void atomic_state_change(istate_type req, istate_type dest,
|
||||
std::string msg);
|
||||
|
||||
/// Atomically change the internal and external connection state.
|
||||
/**
|
||||
* @param ireq The required starting internal state. If the internal state
|
||||
* does not match ireq an exception is thrown.
|
||||
*
|
||||
* @param idest The internal state to change to.
|
||||
*
|
||||
* @param ereq The required starting external state. If the external state
|
||||
* does not match ereq an exception is thrown.
|
||||
*
|
||||
* @param edest The external state to change to.
|
||||
*
|
||||
* @param msg The message to include in the exception thrown
|
||||
*/
|
||||
void atomic_state_change(istate_type ireq, istate_type idest,
|
||||
session::state::value ereq, session::state::value edest,
|
||||
std::string msg);
|
||||
|
||||
/// Atomically read and compared the internal state.
|
||||
/**
|
||||
* @param req The state to test against. If the internal state does not
|
||||
* match req an exception is thrown.
|
||||
*
|
||||
* @param msg The message to include in the exception thrown
|
||||
*/
|
||||
void atomic_state_check(istate_type req, std::string msg);
|
||||
/// set m_response and return an error code indicating status.
|
||||
lib::error_code process_handshake_request();
|
||||
private:
|
||||
/// Completes m_response, serializes it, and sends it out on the wire.
|
||||
void send_http_response();
|
||||
void write_http_response(lib::error_code const & ec);
|
||||
|
||||
/// Sends an opening WebSocket connect request
|
||||
void send_http_request();
|
||||
|
||||
/// Alternate path for send_http_response in error conditions
|
||||
void send_http_response_error();
|
||||
/// Alternate path for write_http_response in error conditions
|
||||
void write_http_response_error(lib::error_code const & ec);
|
||||
|
||||
/// Process control message
|
||||
/**
|
||||
@@ -1352,6 +1419,12 @@ private:
|
||||
* Includes: error code and message for why it was failed
|
||||
*/
|
||||
void log_fail_result();
|
||||
|
||||
/// Prints information about HTTP connections
|
||||
/**
|
||||
* Includes: TODO
|
||||
*/
|
||||
void log_http_result();
|
||||
|
||||
/// Prints information about an arbitrary error code on the specified channel
|
||||
template <typename error_type>
|
||||
@@ -1495,6 +1568,14 @@ private:
|
||||
|
||||
/// Detailed internal error code
|
||||
lib::error_code m_ec;
|
||||
|
||||
/// A flag that gets set once it is determined that the connection is an
|
||||
/// HTTP connection and not a WebSocket one.
|
||||
bool m_is_http;
|
||||
|
||||
/// A flag that gets set when the completion of an http connection is
|
||||
/// deferred until later.
|
||||
session::http_state::value m_http_state;
|
||||
|
||||
bool m_was_clean;
|
||||
|
||||
|
||||
+138
-23
@@ -29,10 +29,11 @@
|
||||
#define WEBSOCKETPP_ENDPOINT_HPP
|
||||
|
||||
#include <websocketpp/connection.hpp>
|
||||
|
||||
#include <websocketpp/logger/levels.hpp>
|
||||
#include <websocketpp/version.hpp>
|
||||
|
||||
#include <set>
|
||||
#include <string>
|
||||
|
||||
namespace websocketpp {
|
||||
|
||||
@@ -84,8 +85,6 @@ public:
|
||||
// TODO: organize these
|
||||
typedef typename connection_type::termination_handler termination_handler;
|
||||
|
||||
typedef lib::shared_ptr<connection_weak_ptr> hdl_type;
|
||||
|
||||
explicit endpoint(bool p_is_server)
|
||||
: m_alog(config::alog_level, log::channel_type_hint::access)
|
||||
, m_elog(config::elog_level, log::channel_type_hint::error)
|
||||
@@ -94,6 +93,7 @@ public:
|
||||
, m_close_handshake_timeout_dur(config::timeout_close_handshake)
|
||||
, m_pong_timeout_dur(config::timeout_pong)
|
||||
, m_max_message_size(config::max_message_size)
|
||||
, m_max_http_body_size(config::max_http_body_size)
|
||||
, m_is_server(p_is_server)
|
||||
{
|
||||
m_alog.set_channels(config::alog_level);
|
||||
@@ -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
|
||||
@@ -350,9 +400,10 @@ public:
|
||||
|
||||
/// Get default maximum message size
|
||||
/**
|
||||
* Get the default maximum message size that will be used for new connections created
|
||||
* by this endpoint. The maximum message size determines the point at which the
|
||||
* connection will fail a connection with the message_too_big protocol error.
|
||||
* Get the default maximum message size that will be used for new
|
||||
* connections created by this endpoint. The maximum message size determines
|
||||
* the point at which the connection will fail a connection with the
|
||||
* message_too_big protocol error.
|
||||
*
|
||||
* The default is set by the max_message_size value from the template config
|
||||
*
|
||||
@@ -364,9 +415,10 @@ public:
|
||||
|
||||
/// Set default maximum message size
|
||||
/**
|
||||
* Set the default maximum message size that will be used for new connections created
|
||||
* by this endpoint. Maximum message size determines the point at which the connection
|
||||
* will fail a connection with the message_too_big protocol error.
|
||||
* Set the default maximum message size that will be used for new
|
||||
* connections created by this endpoint. Maximum message size determines the
|
||||
* point at which the connection will fail a connection with the
|
||||
* message_too_big protocol error.
|
||||
*
|
||||
* The default is set by the max_message_size value from the template config
|
||||
*
|
||||
@@ -378,6 +430,40 @@ public:
|
||||
m_max_message_size = new_value;
|
||||
}
|
||||
|
||||
/// Get maximum HTTP message body size
|
||||
/**
|
||||
* Get maximum HTTP message body size. Maximum message body size determines
|
||||
* the point at which the connection will stop reading an HTTP request whose
|
||||
* body is too large.
|
||||
*
|
||||
* The default is set by the max_http_body_size value from the template
|
||||
* config
|
||||
*
|
||||
* @since 0.5.0
|
||||
*
|
||||
* @return The maximum HTTP message body size
|
||||
*/
|
||||
size_t get_max_http_body_size() const {
|
||||
return m_max_http_body_size;
|
||||
}
|
||||
|
||||
/// Set maximum HTTP message body size
|
||||
/**
|
||||
* Set maximum HTTP message body size. Maximum message body size determines
|
||||
* the point at which the connection will stop reading an HTTP request whose
|
||||
* body is too large.
|
||||
*
|
||||
* The default is set by the max_http_body_size value from the template
|
||||
* config
|
||||
*
|
||||
* @since 0.5.1
|
||||
*
|
||||
* @param new_value The value to set as the maximum message size.
|
||||
*/
|
||||
void set_max_http_body_size(size_t new_value) {
|
||||
m_max_http_body_size = new_value;
|
||||
}
|
||||
|
||||
/*************************************/
|
||||
/* Connection pass through functions */
|
||||
/*************************************/
|
||||
@@ -395,21 +481,21 @@ public:
|
||||
|
||||
/// Pause reading of new data (exception free)
|
||||
/**
|
||||
* Signals to the connection to halt reading of new data. While reading is paused,
|
||||
* the connection will stop reading from its associated socket. In turn this will
|
||||
* result in TCP based flow control kicking in and slowing data flow from the remote
|
||||
* endpoint.
|
||||
* Signals to the connection to halt reading of new data. While reading is
|
||||
* paused, the connection will stop reading from its associated socket. In
|
||||
* turn this will result in TCP based flow control kicking in and slowing
|
||||
* data flow from the remote endpoint.
|
||||
*
|
||||
* This is useful for applications that push new requests to a queue to be processed
|
||||
* by another thread and need a way to signal when their request queue is full without
|
||||
* blocking the network processing thread.
|
||||
* This is useful for applications that push new requests to a queue to be
|
||||
* processed by another thread and need a way to signal when their request
|
||||
* queue is full without blocking the network processing thread.
|
||||
*
|
||||
* Use `resume_reading()` to resume.
|
||||
*
|
||||
* If supported by the transport this is done asynchronously. As such reading may not
|
||||
* stop until the current read operation completes. Typically you can expect to
|
||||
* receive no more bytes after initiating a read pause than the size of the read
|
||||
* buffer.
|
||||
* If supported by the transport this is done asynchronously. As such
|
||||
* reading may not stop until the current read operation completes.
|
||||
* Typically you can expect to receive no more bytes after initiating a read
|
||||
* pause than the size of the read buffer.
|
||||
*
|
||||
* If reading is paused for this connection already nothing is changed.
|
||||
*/
|
||||
@@ -420,8 +506,8 @@ public:
|
||||
|
||||
/// Resume reading of new data (exception free)
|
||||
/**
|
||||
* Signals to the connection to resume reading of new data after it was paused by
|
||||
* `pause_reading()`.
|
||||
* Signals to the connection to resume reading of new data after it was
|
||||
* paused by `pause_reading()`.
|
||||
*
|
||||
* If reading is not paused for this connection already nothing is changed.
|
||||
*/
|
||||
@@ -430,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
|
||||
@@ -523,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) {
|
||||
@@ -565,6 +679,7 @@ private:
|
||||
long m_close_handshake_timeout_dur;
|
||||
long m_pong_timeout_dur;
|
||||
size_t m_max_message_size;
|
||||
size_t m_max_http_body_size;
|
||||
|
||||
rng_type m_rng;
|
||||
|
||||
|
||||
+38
-9
@@ -28,7 +28,9 @@
|
||||
#ifndef WEBSOCKETPP_ERROR_HPP
|
||||
#define WEBSOCKETPP_ERROR_HPP
|
||||
|
||||
#include <exception>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
#include <websocketpp/common/cpp11.hpp>
|
||||
#include <websocketpp/common/system_error.hpp>
|
||||
@@ -122,7 +124,26 @@ enum value {
|
||||
async_accept_not_listening,
|
||||
|
||||
/// The requested operation was canceled
|
||||
operation_canceled
|
||||
operation_canceled,
|
||||
|
||||
/// Connection rejected
|
||||
rejected,
|
||||
|
||||
/// Upgrade Required. This happens if an HTTP request is made to a
|
||||
/// WebSocket++ server that doesn't implement an http handler
|
||||
upgrade_required,
|
||||
|
||||
/// Invalid WebSocket protocol version
|
||||
invalid_version,
|
||||
|
||||
/// Unsupported WebSocket protocol version
|
||||
unsupported_version,
|
||||
|
||||
/// HTTP parse error
|
||||
http_parse_error,
|
||||
|
||||
/// Extension negotiation failed
|
||||
extension_neg_failed
|
||||
}; // enum value
|
||||
|
||||
|
||||
@@ -188,6 +209,18 @@ public:
|
||||
return "Async Accept not listening";
|
||||
case error::operation_canceled:
|
||||
return "Operation canceled";
|
||||
case error::rejected:
|
||||
return "Connection rejected";
|
||||
case error::upgrade_required:
|
||||
return "Upgrade required";
|
||||
case error::invalid_version:
|
||||
return "Invalid version";
|
||||
case error::unsupported_version:
|
||||
return "Unsupported version";
|
||||
case error::http_parse_error:
|
||||
return "HTTP parse error";
|
||||
case error::extension_neg_failed:
|
||||
return "Extension negotiation failed";
|
||||
default:
|
||||
return "Unknown";
|
||||
}
|
||||
@@ -218,28 +251,24 @@ namespace websocketpp {
|
||||
class exception : public std::exception {
|
||||
public:
|
||||
exception(std::string const & msg, lib::error_code ec = make_error_code(error::general))
|
||||
: m_msg(msg), m_code(ec)
|
||||
: m_msg(msg.empty() ? ec.message() : msg), m_code(ec)
|
||||
{}
|
||||
|
||||
explicit exception(lib::error_code ec)
|
||||
: m_code(ec)
|
||||
: m_msg(ec.message()), m_code(ec)
|
||||
{}
|
||||
|
||||
~exception() throw() {}
|
||||
|
||||
virtual char const * what() const throw() {
|
||||
if (m_msg.empty()) {
|
||||
return m_code.message().c_str();
|
||||
} else {
|
||||
return m_msg.c_str();
|
||||
}
|
||||
return m_msg.c_str();
|
||||
}
|
||||
|
||||
lib::error_code code() const throw() {
|
||||
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:
|
||||
@@ -46,12 +46,16 @@
|
||||
namespace websocketpp {
|
||||
namespace extensions {
|
||||
|
||||
/// Implimentation of the draft permessage-deflate WebSocket extension
|
||||
/// Implementation of the draft permessage-deflate WebSocket extension
|
||||
/**
|
||||
* ### permessage-deflate interface
|
||||
*
|
||||
* **is_implemented**\n
|
||||
* `bool is_implemented()`\n
|
||||
* **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
|
||||
@@ -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,15 +292,22 @@ public:
|
||||
}
|
||||
|
||||
m_compress_buffer.reset(new unsigned char[m_compress_buffer_size]);
|
||||
if ((m_server_no_context_takeover && is_server) ||
|
||||
(m_client_no_context_takeover && !is_server))
|
||||
{
|
||||
m_flush = Z_FULL_FLUSH;
|
||||
} else {
|
||||
m_flush = Z_SYNC_FLUSH;
|
||||
}
|
||||
m_initialized = true;
|
||||
return lib::error_code();
|
||||
}
|
||||
|
||||
/// Test if this object impliments the permessage-deflate specification
|
||||
/// Test if this object implements the permessage-deflate specification
|
||||
/**
|
||||
* Because this object does impliment it, it will always return true.
|
||||
* Because this object does implieent it, it will always return true.
|
||||
*
|
||||
* @return Whether or not this object impliments permessage-deflate
|
||||
* @return Whether or not this object implements permessage-deflate
|
||||
*/
|
||||
bool is_implemented() const {
|
||||
return true;
|
||||
@@ -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;
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
#define WEBSOCKETPP_FRAME_HPP
|
||||
|
||||
#include <algorithm>
|
||||
#include <string>
|
||||
|
||||
#include <websocketpp/common/system_error.hpp>
|
||||
#include <websocketpp/common/network.hpp>
|
||||
|
||||
@@ -28,9 +28,11 @@
|
||||
#ifndef HTTP_CONSTANTS_HPP
|
||||
#define HTTP_CONSTANTS_HPP
|
||||
|
||||
#include <exception>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <utility>
|
||||
|
||||
namespace websocketpp {
|
||||
/// HTTP handling support
|
||||
@@ -61,6 +63,9 @@ namespace http {
|
||||
|
||||
/// Maximum size in bytes before rejecting an HTTP header as too big.
|
||||
size_t const max_header_size = 16000;
|
||||
|
||||
/// Default Maximum size in bytes for HTTP message bodies.
|
||||
size_t const max_body_size = 32000000;
|
||||
|
||||
/// Number of bytes to use for temporary istream read buffers
|
||||
size_t const istream_buffer = 512;
|
||||
|
||||
@@ -29,6 +29,8 @@
|
||||
#define HTTP_PARSER_IMPL_HPP
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstdlib>
|
||||
#include <istream>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
|
||||
@@ -93,6 +95,9 @@ inline void parser::set_body(std::string const & value) {
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: should this method respect the max size? If so how should errors
|
||||
// be indicated?
|
||||
|
||||
std::stringstream len;
|
||||
len << value.size();
|
||||
replace_header("Content-Length", len.str());
|
||||
@@ -111,26 +116,46 @@ inline bool parser::parse_parameter_list(std::string const & in,
|
||||
return (it == in.begin());
|
||||
}
|
||||
|
||||
inline bool parser::parse_headers(std::istream & s) {
|
||||
std::string header;
|
||||
std::string::size_type end;
|
||||
|
||||
// get headers
|
||||
while (std::getline(s, header) && header != "\r") {
|
||||
if (header[header.size()-1] != '\r') {
|
||||
continue; // ignore malformed header lines?
|
||||
} else {
|
||||
header.erase(header.end()-1);
|
||||
}
|
||||
|
||||
end = header.find(header_separator,0);
|
||||
|
||||
if (end != std::string::npos) {
|
||||
append_header(header.substr(0,end),header.substr(end+2));
|
||||
inline bool parser::prepare_body() {
|
||||
if (get_header("Content-Length") != "") {
|
||||
std::string const & cl_header = get_header("Content-Length");
|
||||
char * end;
|
||||
|
||||
// TODO: not 100% sure what the compatibility of this method is. Also,
|
||||
// I believe this will only work up to 32bit sizes. Is there a need for
|
||||
// > 4GiB HTTP payloads?
|
||||
m_body_bytes_needed = std::strtoul(cl_header.c_str(),&end,10);
|
||||
|
||||
if (m_body_bytes_needed > m_body_bytes_max) {
|
||||
throw exception("HTTP message body too large",
|
||||
status_code::request_entity_too_large);
|
||||
}
|
||||
|
||||
m_body_encoding = body_encoding::plain;
|
||||
return true;
|
||||
} else if (get_header("Transfer-Encoding") == "chunked") {
|
||||
// TODO
|
||||
//m_body_encoding = body_encoding::chunked;
|
||||
return false;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
inline size_t parser::process_body(char const * buf, size_t len) {
|
||||
if (m_body_encoding == body_encoding::plain) {
|
||||
size_t processed = (std::min)(m_body_bytes_needed,len);
|
||||
m_body.append(buf,processed);
|
||||
m_body_bytes_needed -= processed;
|
||||
return processed;
|
||||
} else if (m_body_encoding == body_encoding::chunked) {
|
||||
// TODO:
|
||||
throw exception("Unexpected body encoding",
|
||||
status_code::internal_server_error);
|
||||
} else {
|
||||
throw exception("Unexpected body encoding",
|
||||
status_code::internal_server_error);
|
||||
}
|
||||
}
|
||||
|
||||
inline void parser::process_header(std::string::iterator begin,
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
|
||||
#include <algorithm>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
|
||||
#include <websocketpp/http/parser.hpp>
|
||||
|
||||
@@ -37,40 +38,17 @@ namespace websocketpp {
|
||||
namespace http {
|
||||
namespace parser {
|
||||
|
||||
inline bool request::parse_complete(std::istream& s) {
|
||||
std::string req;
|
||||
|
||||
// get status line
|
||||
std::getline(s, req);
|
||||
|
||||
if (req[req.size()-1] == '\r') {
|
||||
req.erase(req.end()-1);
|
||||
|
||||
std::stringstream ss(req);
|
||||
std::string val;
|
||||
|
||||
ss >> val;
|
||||
set_method(val);
|
||||
|
||||
ss >> val;
|
||||
set_uri(val);
|
||||
|
||||
ss >> val;
|
||||
set_version(val);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
return parse_headers(s);
|
||||
}
|
||||
|
||||
inline size_t request::consume(const char *buf, size_t len) {
|
||||
inline size_t request::consume(char const * buf, size_t len) {
|
||||
size_t bytes_processed;
|
||||
|
||||
if (m_ready) {return 0;}
|
||||
|
||||
if (m_buf->size() + len > max_header_size) {
|
||||
// exceeded max header size
|
||||
throw exception("Maximum header size exceeded.",
|
||||
status_code::request_header_fields_too_large);
|
||||
|
||||
if (m_body_bytes_needed > 0) {
|
||||
bytes_processed = process_body(buf,len);
|
||||
if (body_ready()) {
|
||||
m_ready = true;
|
||||
}
|
||||
return bytes_processed;
|
||||
}
|
||||
|
||||
// copy new header bytes into buffer
|
||||
@@ -88,15 +66,21 @@ inline size_t request::consume(const char *buf, size_t len) {
|
||||
header_delimiter,
|
||||
header_delimiter+sizeof(header_delimiter)-1
|
||||
);
|
||||
|
||||
//std::cout << "mark5: " << end-begin << std::endl;
|
||||
//std::cout << "mark6: " << sizeof(header_delimiter) << std::endl;
|
||||
|
||||
m_header_bytes += (end-begin+sizeof(header_delimiter));
|
||||
|
||||
if (m_header_bytes > max_header_size) {
|
||||
// exceeded max header size
|
||||
throw exception("Maximum header size exceeded.",
|
||||
status_code::request_header_fields_too_large);
|
||||
}
|
||||
|
||||
if (end == m_buf->end()) {
|
||||
// we are out of bytes. Discard the processed bytes and copy the
|
||||
// remaining unprecessed bytes to the beginning of the buffer
|
||||
std::copy(begin,end,m_buf->begin());
|
||||
m_buf->resize(static_cast<std::string::size_type>(end-begin));
|
||||
m_header_bytes -= m_buf->size();
|
||||
|
||||
return len;
|
||||
}
|
||||
@@ -107,9 +91,8 @@ inline size_t request::consume(const char *buf, size_t len) {
|
||||
if (m_method.empty() || get_header("Host") == "") {
|
||||
throw exception("Incomplete Request",status_code::bad_request);
|
||||
}
|
||||
m_ready = true;
|
||||
|
||||
size_t bytes_processed = (
|
||||
bytes_processed = (
|
||||
len - static_cast<std::string::size_type>(m_buf->end()-end)
|
||||
+ sizeof(header_delimiter) - 1
|
||||
);
|
||||
@@ -117,8 +100,22 @@ inline size_t request::consume(const char *buf, size_t len) {
|
||||
// frees memory used temporarily during request parsing
|
||||
m_buf.reset();
|
||||
|
||||
// return number of bytes processed (starting bytes - bytes left)
|
||||
return bytes_processed;
|
||||
// if this was not an upgrade request and has a content length
|
||||
// continue capturing content-length bytes and expose them as a
|
||||
// request body.
|
||||
|
||||
if (prepare_body()) {
|
||||
bytes_processed += process_body(buf+bytes_processed,len-bytes_processed);
|
||||
if (body_ready()) {
|
||||
m_ready = true;
|
||||
}
|
||||
return bytes_processed;
|
||||
} else {
|
||||
m_ready = true;
|
||||
|
||||
// return number of bytes processed (starting bytes - bytes left)
|
||||
return bytes_processed;
|
||||
}
|
||||
} else {
|
||||
if (m_method.empty()) {
|
||||
this->process(begin,end);
|
||||
@@ -131,7 +128,7 @@ inline size_t request::consume(const char *buf, size_t len) {
|
||||
}
|
||||
}
|
||||
|
||||
inline std::string request::raw() {
|
||||
inline std::string request::raw() const {
|
||||
// TODO: validation. Make sure all required fields have been set?
|
||||
std::stringstream ret;
|
||||
|
||||
@@ -141,7 +138,17 @@ inline std::string request::raw() {
|
||||
return ret.str();
|
||||
}
|
||||
|
||||
inline void request::set_method(const std::string& method) {
|
||||
inline std::string request::raw_head() const {
|
||||
// TODO: validation. Make sure all required fields have been set?
|
||||
std::stringstream ret;
|
||||
|
||||
ret << m_method << " " << m_uri << " " << get_version() << "\r\n";
|
||||
ret << raw_headers() << "\r\n";
|
||||
|
||||
return ret.str();
|
||||
}
|
||||
|
||||
inline void request::set_method(std::string const & method) {
|
||||
if (std::find_if(method.begin(),method.end(),is_not_token_char) != method.end()) {
|
||||
throw exception("Invalid method token.",status_code::bad_request);
|
||||
}
|
||||
@@ -149,14 +156,7 @@ inline void request::set_method(const std::string& method) {
|
||||
m_method = method;
|
||||
}
|
||||
|
||||
/// Set HTTP body
|
||||
/**
|
||||
* Sets the body of the HTTP object and fills in the appropriate content length
|
||||
* header
|
||||
*
|
||||
* @param value The value to set the body to.
|
||||
*/
|
||||
inline void request::set_uri(const std::string& uri) {
|
||||
inline void request::set_uri(std::string const & uri) {
|
||||
// TODO: validation?
|
||||
m_uri = uri;
|
||||
}
|
||||
|
||||
@@ -29,7 +29,9 @@
|
||||
#define HTTP_PARSER_RESPONSE_IMPL_HPP
|
||||
|
||||
#include <algorithm>
|
||||
#include <istream>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
|
||||
#include <websocketpp/http/parser.hpp>
|
||||
|
||||
@@ -37,19 +39,13 @@ namespace websocketpp {
|
||||
namespace http {
|
||||
namespace parser {
|
||||
|
||||
inline size_t response::consume(const char *buf, size_t len) {
|
||||
inline size_t response::consume(char const * buf, size_t len) {
|
||||
if (m_state == DONE) {return 0;}
|
||||
|
||||
if (m_state == BODY) {
|
||||
return this->process_body(buf,len);
|
||||
}
|
||||
|
||||
if (m_read + len > max_header_size) {
|
||||
// exceeded max header size
|
||||
throw exception("Maximum header size exceeded.",
|
||||
status_code::request_header_fields_too_large);
|
||||
}
|
||||
|
||||
// copy new header bytes into buffer
|
||||
m_buf->append(buf,len);
|
||||
|
||||
@@ -67,13 +63,22 @@ inline size_t response::consume(const char *buf, size_t len) {
|
||||
header_delimiter + sizeof(header_delimiter) - 1
|
||||
);
|
||||
|
||||
m_header_bytes += (end-begin+sizeof(header_delimiter));
|
||||
|
||||
if (m_header_bytes > max_header_size) {
|
||||
// exceeded max header size
|
||||
throw exception("Maximum header size exceeded.",
|
||||
status_code::request_header_fields_too_large);
|
||||
}
|
||||
|
||||
if (end == m_buf->end()) {
|
||||
// we are out of bytes. Discard the processed bytes and copy the
|
||||
// remaining unprecessed bytes to the beginning of the buffer
|
||||
std::copy(begin,end,m_buf->begin());
|
||||
m_buf->resize(static_cast<std::string::size_type>(end-begin));
|
||||
|
||||
m_read +=len;
|
||||
m_read += len;
|
||||
m_header_bytes -= m_buf->size();
|
||||
|
||||
return len;
|
||||
}
|
||||
@@ -170,34 +175,6 @@ inline size_t response::consume(std::istream & s) {
|
||||
return total;
|
||||
}
|
||||
|
||||
inline bool response::parse_complete(std::istream& s) {
|
||||
// parse a complete header (ie \r\n\r\n MUST be in the input stream)
|
||||
std::string line;
|
||||
|
||||
// get status line
|
||||
std::getline(s, line);
|
||||
|
||||
if (line[line.size()-1] == '\r') {
|
||||
line.erase(line.end()-1);
|
||||
|
||||
std::stringstream ss(line);
|
||||
std::string str_val;
|
||||
int int_val;
|
||||
char char_val[256];
|
||||
|
||||
ss >> str_val;
|
||||
set_version(str_val);
|
||||
|
||||
ss >> int_val;
|
||||
ss.getline(char_val,256);
|
||||
set_status(status_code::value(int_val),std::string(char_val));
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
return parse_headers(s);
|
||||
}
|
||||
|
||||
inline std::string response::raw() const {
|
||||
// TODO: validation. Make sure all required fields have been set?
|
||||
|
||||
@@ -217,7 +194,7 @@ inline void response::set_status(status_code::value code) {
|
||||
m_status_msg = get_string(code);
|
||||
}
|
||||
|
||||
inline void response::set_status(status_code::value code, const std::string&
|
||||
inline void response::set_status(status_code::value code, std::string const &
|
||||
msg)
|
||||
{
|
||||
// TODO: validation?
|
||||
@@ -255,7 +232,7 @@ inline void response::process(std::string::iterator begin,
|
||||
set_status(status_code::value(code),std::string(cursor_end+1,end));
|
||||
}
|
||||
|
||||
inline size_t response::process_body(const char *buf, size_t len) {
|
||||
inline size_t response::process_body(char const * buf, size_t len) {
|
||||
// If no content length was set then we read forever and never set m_ready
|
||||
if (m_read == 0) {
|
||||
//m_body.append(buf,len);
|
||||
|
||||
+91
-14
@@ -29,8 +29,9 @@
|
||||
#define HTTP_PARSER_HPP
|
||||
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
#include <websocketpp/utilities.hpp>
|
||||
#include <websocketpp/http/constants.hpp>
|
||||
@@ -48,6 +49,14 @@ namespace state {
|
||||
};
|
||||
}
|
||||
|
||||
namespace body_encoding {
|
||||
enum value {
|
||||
unknown,
|
||||
plain,
|
||||
chunked
|
||||
};
|
||||
}
|
||||
|
||||
typedef std::map<std::string, std::string, utility::ci_less > header_list;
|
||||
|
||||
/// Read and return the next token in the stream
|
||||
@@ -384,6 +393,12 @@ inline std::string strip_lws(std::string const & input) {
|
||||
*/
|
||||
class parser {
|
||||
public:
|
||||
parser()
|
||||
: m_header_bytes(0)
|
||||
, m_body_bytes_needed(0)
|
||||
, m_body_bytes_max(max_body_size)
|
||||
, m_body_encoding(body_encoding::unknown) {}
|
||||
|
||||
/// Get the HTTP version string
|
||||
/**
|
||||
* @return The version string for this parser
|
||||
@@ -467,12 +482,11 @@ public:
|
||||
*/
|
||||
void remove_header(std::string const & key);
|
||||
|
||||
/// Set HTTP body
|
||||
/// Get HTTP body
|
||||
/**
|
||||
* Sets the body of the HTTP object and fills in the appropriate content
|
||||
* length header.
|
||||
* Gets the body of the HTTP object
|
||||
*
|
||||
* @param [in] value The value to set the body to.
|
||||
* @return The body of the HTTP message.
|
||||
*/
|
||||
std::string const & get_body() const {
|
||||
return m_body;
|
||||
@@ -489,6 +503,32 @@ public:
|
||||
*/
|
||||
void set_body(std::string const & value);
|
||||
|
||||
/// Get body size limit
|
||||
/**
|
||||
* Retrieves the maximum number of bytes to parse & buffer before canceling
|
||||
* a request.
|
||||
*
|
||||
* @since 0.5.0
|
||||
*
|
||||
* @return The maximum length of a message body.
|
||||
*/
|
||||
size_t get_max_body_size() const {
|
||||
return m_body_bytes_max;
|
||||
}
|
||||
|
||||
/// Set body size limit
|
||||
/**
|
||||
* Set the maximum number of bytes to parse and buffer before canceling a
|
||||
* request.
|
||||
*
|
||||
* @since 0.5.0
|
||||
*
|
||||
* @param value The size to set the max body length to.
|
||||
*/
|
||||
void set_max_body_size(size_t value) {
|
||||
m_body_bytes_max = value;
|
||||
}
|
||||
|
||||
/// Extract an HTTP parameter list from a string.
|
||||
/**
|
||||
* @param [in] in The input string.
|
||||
@@ -498,14 +538,6 @@ public:
|
||||
bool parse_parameter_list(std::string const & in, parameter_list & out)
|
||||
const;
|
||||
protected:
|
||||
/// Parse headers from an istream
|
||||
/**
|
||||
* @deprecated Use process_header instead.
|
||||
*
|
||||
* @param [in] s The istream to extract headers from.
|
||||
*/
|
||||
bool parse_headers(std::istream & s);
|
||||
|
||||
/// Process a header line
|
||||
/**
|
||||
* @todo Update this method to be exception free.
|
||||
@@ -515,6 +547,45 @@ protected:
|
||||
*/
|
||||
void process_header(std::string::iterator begin, std::string::iterator end);
|
||||
|
||||
/// Prepare the parser to begin parsing body data
|
||||
/**
|
||||
* Inspects headers to determine if the message has a body that needs to be
|
||||
* read. If so, sets up the necessary state, otherwise returns false. If
|
||||
* this method returns true and loading the message body is desired call
|
||||
* `process_body` until it returns zero bytes or an error.
|
||||
*
|
||||
* Must not be called until after all headers have been processed.
|
||||
*
|
||||
* @since 0.5.0
|
||||
*
|
||||
* @return True if more bytes are needed to load the body, false otherwise.
|
||||
*/
|
||||
bool prepare_body();
|
||||
|
||||
/// Process body data
|
||||
/**
|
||||
* Parses body data.
|
||||
*
|
||||
* @since 0.5.0
|
||||
*
|
||||
* @param [in] begin An iterator to the beginning of the sequence.
|
||||
* @param [in] end An iterator to the end of the sequence.
|
||||
* @return The number of bytes processed
|
||||
*/
|
||||
size_t process_body(char const * buf, size_t len);
|
||||
|
||||
/// Check if the parser is done parsing the body
|
||||
/**
|
||||
* Behavior before a call to `prepare_body` is undefined.
|
||||
*
|
||||
* @since 0.5.0
|
||||
*
|
||||
* @return True if the message body has been completed loaded.
|
||||
*/
|
||||
bool body_ready() const {
|
||||
return (m_body_bytes_needed == 0);
|
||||
}
|
||||
|
||||
/// Generate and return the HTTP headers as a string
|
||||
/**
|
||||
* Each headers will be followed by the \r\n sequence including the last one.
|
||||
@@ -526,7 +597,13 @@ protected:
|
||||
|
||||
std::string m_version;
|
||||
header_list m_headers;
|
||||
std::string m_body;
|
||||
|
||||
size_t m_header_bytes;
|
||||
|
||||
std::string m_body;
|
||||
size_t m_body_bytes_needed;
|
||||
size_t m_body_bytes_max;
|
||||
body_encoding::value m_body_encoding;
|
||||
};
|
||||
|
||||
} // namespace parser
|
||||
|
||||
@@ -28,6 +28,8 @@
|
||||
#ifndef HTTP_PARSER_REQUEST_HPP
|
||||
#define HTTP_PARSER_REQUEST_HPP
|
||||
|
||||
#include <string>
|
||||
|
||||
#include <websocketpp/common/memory.hpp>
|
||||
#include <websocketpp/http/parser.hpp>
|
||||
|
||||
@@ -54,9 +56,6 @@ public:
|
||||
: m_buf(lib::make_shared<std::string>())
|
||||
, m_ready(false) {}
|
||||
|
||||
/// DEPRECATED parse a complete header (\r\n\r\n MUST be in the istream)
|
||||
bool parse_complete(std::istream& s);
|
||||
|
||||
/// Process bytes in the input buffer
|
||||
/**
|
||||
* Process up to len bytes from input buffer buf. Returns the number of
|
||||
@@ -77,29 +76,32 @@ public:
|
||||
* @param len Size of byte buffer
|
||||
* @return Number of bytes processed.
|
||||
*/
|
||||
size_t consume(const char *buf, size_t len);
|
||||
size_t consume(char const * buf, size_t len);
|
||||
|
||||
/// Returns whether or not the request is ready for reading.
|
||||
bool ready() const {
|
||||
return m_ready;
|
||||
}
|
||||
|
||||
/// Returns the full raw request
|
||||
std::string raw();
|
||||
/// Returns the full raw request (including the body)
|
||||
std::string raw() const;
|
||||
|
||||
/// Returns the raw request headers only (similar to an HTTP HEAD request)
|
||||
std::string raw_head() const;
|
||||
|
||||
/// Set the HTTP method. Must be a valid HTTP token
|
||||
void set_method(const std::string& method);
|
||||
void set_method(std::string const & method);
|
||||
|
||||
/// Return the request method
|
||||
const std::string& get_method() const {
|
||||
std::string const & get_method() const {
|
||||
return m_method;
|
||||
}
|
||||
|
||||
/// Set the HTTP uri. Must be a valid HTTP uri
|
||||
void set_uri(const std::string& uri);
|
||||
void set_uri(std::string const & uri);
|
||||
|
||||
/// Return the requested URI
|
||||
const std::string& get_uri() const {
|
||||
std::string const & get_uri() const {
|
||||
return m_uri;
|
||||
}
|
||||
|
||||
|
||||
@@ -28,6 +28,9 @@
|
||||
#ifndef HTTP_PARSER_RESPONSE_HPP
|
||||
#define HTTP_PARSER_RESPONSE_HPP
|
||||
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
#include <websocketpp/http/parser.hpp>
|
||||
|
||||
namespace websocketpp {
|
||||
@@ -82,8 +85,28 @@ public:
|
||||
* @param len Size of byte buffer
|
||||
* @return Number of bytes processed.
|
||||
*/
|
||||
size_t consume(const char *buf, size_t len);
|
||||
size_t consume(char const * buf, size_t len);
|
||||
|
||||
/// Process bytes in the input buffer (istream version)
|
||||
/**
|
||||
* Process bytes from istream s. Returns the number of bytes processed.
|
||||
* Bytes left unprocessed means bytes left over after the final header
|
||||
* delimiters.
|
||||
*
|
||||
* Consume is a streaming processor. It may be called multiple times on one
|
||||
* response and the full headers need not be available before processing can
|
||||
* begin. If the end of the response was reached during this call to consume
|
||||
* the ready flag will be set. Further calls to consume once ready will be
|
||||
* ignored.
|
||||
*
|
||||
* Consume will throw an http::exception in the case of an error. Typical
|
||||
* error reasons include malformed responses, incomplete responses, and max
|
||||
* header size being reached.
|
||||
*
|
||||
* @param buf Pointer to byte buffer
|
||||
* @param len Size of byte buffer
|
||||
* @return Number of bytes processed.
|
||||
*/
|
||||
size_t consume(std::istream & s);
|
||||
|
||||
/// Returns true if the response is ready.
|
||||
@@ -99,9 +122,6 @@ public:
|
||||
return (m_state == BODY || m_state == DONE);
|
||||
}
|
||||
|
||||
/// DEPRECATED parse a complete response from a pre-delimited istream
|
||||
bool parse_complete(std::istream& s);
|
||||
|
||||
/// Returns the full raw response
|
||||
std::string raw() const;
|
||||
|
||||
@@ -126,7 +146,7 @@ public:
|
||||
* @param code Code to set
|
||||
* @param msg Message to set
|
||||
*/
|
||||
void set_status(status_code::value code, const std::string& msg);
|
||||
void set_status(status_code::value code, std::string const & msg);
|
||||
|
||||
/// Return the response status code
|
||||
status_code::value get_status_code() const {
|
||||
@@ -142,7 +162,7 @@ private:
|
||||
void process(std::string::iterator begin, std::string::iterator end);
|
||||
|
||||
/// Helper function for processing body bytes
|
||||
size_t process_body(const char *buf, size_t len);
|
||||
size_t process_body(char const * buf, size_t len);
|
||||
|
||||
enum state {
|
||||
RESPONSE_LINE = 0,
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
@@ -28,6 +28,8 @@
|
||||
#ifndef WEBSOCKETPP_ENDPOINT_IMPL_HPP
|
||||
#define WEBSOCKETPP_ENDPOINT_IMPL_HPP
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace websocketpp {
|
||||
|
||||
template <typename connection, typename config>
|
||||
@@ -77,6 +79,7 @@ endpoint<connection,config>::create_connection() {
|
||||
if (m_max_message_size != config::max_message_size) {
|
||||
con->set_max_message_size(m_max_message_size);
|
||||
}
|
||||
con->set_max_http_body_size(m_max_http_body_size);
|
||||
|
||||
lib::error_code ec;
|
||||
|
||||
@@ -139,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,
|
||||
|
||||
@@ -28,6 +28,9 @@
|
||||
#ifndef WEBSOCKETPP_UTILITIES_IMPL_HPP
|
||||
#define WEBSOCKETPP_UTILITIES_IMPL_HPP
|
||||
|
||||
#include <algorithm>
|
||||
#include <string>
|
||||
|
||||
namespace websocketpp {
|
||||
namespace utility {
|
||||
|
||||
@@ -37,7 +40,7 @@ inline std::string to_lower(std::string const & in) {
|
||||
return out;
|
||||
}
|
||||
|
||||
inline std::string to_hex(const std::string& input) {
|
||||
inline std::string to_hex(std::string const & input) {
|
||||
std::string output;
|
||||
std::string hex = "0123456789ABCDEF";
|
||||
|
||||
@@ -50,7 +53,7 @@ inline std::string to_hex(const std::string& input) {
|
||||
return output;
|
||||
}
|
||||
|
||||
inline std::string to_hex(const uint8_t* input,size_t length) {
|
||||
inline std::string to_hex(uint8_t const * input, size_t length) {
|
||||
std::string output;
|
||||
std::string hex = "0123456789ABCDEF";
|
||||
|
||||
@@ -67,8 +70,8 @@ inline std::string to_hex(const char* input,size_t length) {
|
||||
return to_hex(reinterpret_cast<const uint8_t*>(input),length);
|
||||
}
|
||||
|
||||
inline std::string string_replace_all(std::string subject, const std::string&
|
||||
search, const std::string& replace)
|
||||
inline std::string string_replace_all(std::string subject, std::string const &
|
||||
search, std::string const & replace)
|
||||
{
|
||||
size_t pos = 0;
|
||||
while((pos = subject.find(search, pos)) != std::string::npos) {
|
||||
|
||||
@@ -40,14 +40,16 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <ctime>
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include <websocketpp/logger/levels.hpp>
|
||||
|
||||
#include <websocketpp/common/cpp11.hpp>
|
||||
#include <websocketpp/common/stdint.hpp>
|
||||
#include <websocketpp/common/time.hpp>
|
||||
#include <websocketpp/logger/levels.hpp>
|
||||
|
||||
#include <ctime>
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include <string>
|
||||
|
||||
namespace websocketpp {
|
||||
namespace log {
|
||||
@@ -56,28 +58,58 @@ namespace log {
|
||||
template <typename concurrency, typename names>
|
||||
class basic {
|
||||
public:
|
||||
basic<concurrency,names>(channel_type_hint::value h =
|
||||
basic<concurrency,names>(channel_type_hint::value h =
|
||||
channel_type_hint::access)
|
||||
: m_static_channels(0xffffffff)
|
||||
, m_dynamic_channels(0)
|
||||
, m_out(h == channel_type_hint::error ? &std::cerr : &std::cout) {}
|
||||
|
||||
|
||||
basic<concurrency,names>(std::ostream * out)
|
||||
: m_static_channels(0xffffffff)
|
||||
, m_dynamic_channels(0)
|
||||
, m_out(out) {}
|
||||
|
||||
basic<concurrency,names>(level c, channel_type_hint::value h =
|
||||
basic<concurrency,names>(level c, channel_type_hint::value h =
|
||||
channel_type_hint::access)
|
||||
: m_static_channels(c)
|
||||
, m_dynamic_channels(0)
|
||||
, m_out(h == channel_type_hint::error ? &std::cerr : &std::cout) {}
|
||||
|
||||
|
||||
basic<concurrency,names>(level c, std::ostream * out)
|
||||
: m_static_channels(c)
|
||||
, m_dynamic_channels(0)
|
||||
, m_out(out) {}
|
||||
|
||||
/// Destructor
|
||||
~basic<concurrency,names>() {}
|
||||
|
||||
/// Copy constructor
|
||||
basic<concurrency,names>(basic<concurrency,names> const & other)
|
||||
: m_static_channels(other.m_static_channels)
|
||||
, m_dynamic_channels(other.m_dynamic_channels)
|
||||
, m_out(other.m_out)
|
||||
{}
|
||||
|
||||
#ifdef _WEBSOCKETPP_DEFAULT_DELETE_FUNCTIONS_
|
||||
// no copy assignment operator because of const member variables
|
||||
basic<concurrency,names> & operator=(basic<concurrency,names> const &) = delete;
|
||||
#endif // _WEBSOCKETPP_DEFAULT_DELETE_FUNCTIONS_
|
||||
|
||||
#ifdef _WEBSOCKETPP_MOVE_SEMANTICS_
|
||||
/// Move constructor
|
||||
basic<concurrency,names>(basic<concurrency,names> && other)
|
||||
: m_static_channels(other.m_static_channels)
|
||||
, m_dynamic_channels(other.m_dynamic_channels)
|
||||
, m_out(other.m_out)
|
||||
{}
|
||||
|
||||
#ifdef _WEBSOCKETPP_DEFAULT_DELETE_FUNCTIONS_
|
||||
// no move assignment operator because of const member variables
|
||||
basic<concurrency,names> & operator=(basic<concurrency,names> &&) = delete;
|
||||
#endif // _WEBSOCKETPP_DEFAULT_DELETE_FUNCTIONS_
|
||||
|
||||
#endif // _WEBSOCKETPP_MOVE_SEMANTICS_
|
||||
|
||||
void set_ostream(std::ostream * out = &std::cout) {
|
||||
m_out = out;
|
||||
}
|
||||
@@ -97,6 +129,11 @@ public:
|
||||
m_dynamic_channels &= ~channels;
|
||||
}
|
||||
|
||||
/// Write a string message to the given channel
|
||||
/**
|
||||
* @param channel The channel to write to
|
||||
* @param msg The message to write
|
||||
*/
|
||||
void write(level channel, std::string const & msg) {
|
||||
scoped_lock_type lock(m_lock);
|
||||
if (!this->dynamic_test(channel)) { return; }
|
||||
@@ -106,6 +143,11 @@ public:
|
||||
m_out->flush();
|
||||
}
|
||||
|
||||
/// Write a cstring message to the given channel
|
||||
/**
|
||||
* @param channel The channel to write to
|
||||
* @param msg The message to write
|
||||
*/
|
||||
void write(level channel, char const * msg) {
|
||||
scoped_lock_type lock(m_lock);
|
||||
if (!this->dynamic_test(channel)) { return; }
|
||||
@@ -122,10 +164,13 @@ public:
|
||||
bool dynamic_test(level channel) {
|
||||
return ((channel & m_dynamic_channels) != 0);
|
||||
}
|
||||
private:
|
||||
|
||||
protected:
|
||||
typedef typename concurrency::scoped_lock_type scoped_lock_type;
|
||||
typedef typename concurrency::mutex_type mutex_type;
|
||||
mutex_type m_lock;
|
||||
|
||||
private:
|
||||
// The timestamp does not include the time zone, because on Windows with the
|
||||
// default registry settings, the time zone would be written out in full,
|
||||
// which would be obnoxiously verbose.
|
||||
@@ -143,8 +188,6 @@ private:
|
||||
#endif
|
||||
}
|
||||
|
||||
mutex_type m_lock;
|
||||
|
||||
level const m_static_channels;
|
||||
level m_dynamic_channels;
|
||||
std::ostream * m_out;
|
||||
|
||||
@@ -141,6 +141,13 @@ struct alevel {
|
||||
static level const devel = 0x400;
|
||||
/// Special channel for application specific logs. Not used by the library.
|
||||
static level const app = 0x800;
|
||||
/// Access related to HTTP requests
|
||||
static level const http = 0x1000;
|
||||
/// One line for each failed WebSocket connection with details
|
||||
static level const fail = 0x2000;
|
||||
/// Aggregate package representing the commonly used core access channels
|
||||
/// Connect, Disconnect, Fail, and HTTP
|
||||
static level const access_core = 0x00003003;
|
||||
/// Special aggregate value representing "all levels"
|
||||
static level const all = 0xffffffff;
|
||||
|
||||
@@ -180,6 +187,10 @@ struct alevel {
|
||||
return "devel";
|
||||
case app:
|
||||
return "application";
|
||||
case http:
|
||||
return "http";
|
||||
case fail:
|
||||
return "fail";
|
||||
default:
|
||||
return "unknown";
|
||||
}
|
||||
|
||||
+13
-12
@@ -28,10 +28,11 @@
|
||||
#ifndef WEBSOCKETPP_LOGGER_STUB_HPP
|
||||
#define WEBSOCKETPP_LOGGER_STUB_HPP
|
||||
|
||||
#include <string>
|
||||
#include <websocketpp/logger/levels.hpp>
|
||||
|
||||
#include <websocketpp/common/cpp11.hpp>
|
||||
#include <websocketpp/logger/levels.hpp>
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace websocketpp {
|
||||
namespace log {
|
||||
@@ -44,7 +45,7 @@ public:
|
||||
* @param hint A channel type specific hint for how to construct the logger
|
||||
*/
|
||||
explicit stub(channel_type_hint::value) {}
|
||||
|
||||
|
||||
/// Construct the logger
|
||||
/**
|
||||
* @param default_channels A set of channels to statically enable
|
||||
@@ -55,16 +56,16 @@ public:
|
||||
|
||||
/// Dynamically enable the given list of channels
|
||||
/**
|
||||
* All operations on the stub logger are no-ops and all arguments are
|
||||
* All operations on the stub logger are no-ops and all arguments are
|
||||
* ignored
|
||||
*
|
||||
* @param channels The package of channels to enable
|
||||
*/
|
||||
void set_channels(level) {}
|
||||
|
||||
|
||||
/// Dynamically disable the given list of channels
|
||||
/**
|
||||
* All operations on the stub logger are no-ops and all arguments are
|
||||
* All operations on the stub logger are no-ops and all arguments are
|
||||
* ignored
|
||||
*
|
||||
* @param channels The package of channels to disable
|
||||
@@ -75,23 +76,23 @@ public:
|
||||
/**
|
||||
* Writing on the stub logger is a no-op and all arguments are ignored
|
||||
*
|
||||
* @param channel The package of channels to write to
|
||||
* @param channel The channel to write to
|
||||
* @param msg The message to write
|
||||
*/
|
||||
void write(level, std::string const &) {}
|
||||
|
||||
|
||||
/// Write a cstring message to the given channel
|
||||
/**
|
||||
* Writing on the stub logger is a no-op and all arguments are ignored
|
||||
*
|
||||
* @param channel The package of channels to write to
|
||||
* @param channel The channel to write to
|
||||
* @param msg The message to write
|
||||
*/
|
||||
void write(level, char const *) {}
|
||||
|
||||
/// Test whether a channel is statically enabled
|
||||
/**
|
||||
* The stub logger has no channels so all arguments are ignored and
|
||||
* The stub logger has no channels so all arguments are ignored and
|
||||
* `static_test` always returns false.
|
||||
*
|
||||
* @param channel The package of channels to test
|
||||
@@ -99,10 +100,10 @@ public:
|
||||
_WEBSOCKETPP_CONSTEXPR_TOKEN_ bool static_test(level) const {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/// Test whether a channel is dynamically enabled
|
||||
/**
|
||||
* The stub logger has no channels so all arguments are ignored and
|
||||
* The stub logger has no channels so all arguments are ignored and
|
||||
* `dynamic_test` always returns false.
|
||||
*
|
||||
* @param channel The package of channels to test
|
||||
|
||||
@@ -0,0 +1,146 @@
|
||||
/*
|
||||
* Copyright (c) 2014, Peter Thorson. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the WebSocket++ Project nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*
|
||||
* The initial version of this logging policy was contributed to the WebSocket++
|
||||
* project by Tom Hughes.
|
||||
*/
|
||||
|
||||
#ifndef WEBSOCKETPP_LOGGER_SYSLOG_HPP
|
||||
#define WEBSOCKETPP_LOGGER_SYSLOG_HPP
|
||||
|
||||
#include <syslog.h>
|
||||
|
||||
#include <websocketpp/logger/basic.hpp>
|
||||
|
||||
#include <websocketpp/common/cpp11.hpp>
|
||||
#include <websocketpp/logger/levels.hpp>
|
||||
|
||||
namespace websocketpp {
|
||||
namespace log {
|
||||
|
||||
/// Basic logger that outputs to syslog
|
||||
template <typename concurrency, typename names>
|
||||
class syslog : public basic<concurrency, names> {
|
||||
public:
|
||||
typedef basic<concurrency, names> base;
|
||||
|
||||
/// Construct the logger
|
||||
/**
|
||||
* @param hint A channel type specific hint for how to construct the logger
|
||||
*/
|
||||
syslog<concurrency,names>(channel_type_hint::value hint =
|
||||
channel_type_hint::access)
|
||||
: basic<concurrency,names>(hint), m_channel_type_hint(hint) {}
|
||||
|
||||
/// Construct the logger
|
||||
/**
|
||||
* @param channels A set of channels to statically enable
|
||||
* @param hint A channel type specific hint for how to construct the logger
|
||||
*/
|
||||
syslog<concurrency,names>(level channels, channel_type_hint::value hint =
|
||||
channel_type_hint::access)
|
||||
: basic<concurrency,names>(channels, hint), m_channel_type_hint(hint) {}
|
||||
|
||||
/// Write a string message to the given channel
|
||||
/**
|
||||
* @param channel The channel to write to
|
||||
* @param msg The message to write
|
||||
*/
|
||||
void write(level channel, std::string const & msg) {
|
||||
write(channel, msg.c_str());
|
||||
}
|
||||
|
||||
/// Write a cstring message to the given channel
|
||||
/**
|
||||
* @param channel The channel to write to
|
||||
* @param msg The message to write
|
||||
*/
|
||||
void write(level channel, char const * msg) {
|
||||
scoped_lock_type lock(base::m_lock);
|
||||
if (!this->dynamic_test(channel)) { return; }
|
||||
::syslog(syslog_priority(channel), "[%s] %s",
|
||||
names::channel_name(channel), msg);
|
||||
}
|
||||
private:
|
||||
typedef typename base::scoped_lock_type scoped_lock_type;
|
||||
|
||||
/// The default level is used for all access logs and any error logs that
|
||||
/// don't trivially map to one of the standard syslog levels.
|
||||
static int const default_level = LOG_INFO;
|
||||
|
||||
/// retrieve the syslog priority code given a WebSocket++ channel
|
||||
/**
|
||||
* @param channel The level to look up
|
||||
* @return The syslog level associated with `channel`
|
||||
*/
|
||||
int syslog_priority(level channel) const {
|
||||
if (m_channel_type_hint == channel_type_hint::access) {
|
||||
return syslog_priority_access(channel);
|
||||
} else {
|
||||
return syslog_priority_error(channel);
|
||||
}
|
||||
}
|
||||
|
||||
/// retrieve the syslog priority code given a WebSocket++ error channel
|
||||
/**
|
||||
* @param channel The level to look up
|
||||
* @return The syslog level associated with `channel`
|
||||
*/
|
||||
int syslog_priority_error(level channel) const {
|
||||
switch (channel) {
|
||||
case elevel::devel:
|
||||
return LOG_DEBUG;
|
||||
case elevel::library:
|
||||
return LOG_DEBUG;
|
||||
case elevel::info:
|
||||
return LOG_INFO;
|
||||
case elevel::warn:
|
||||
return LOG_WARNING;
|
||||
case elevel::rerror:
|
||||
return LOG_ERR;
|
||||
case elevel::fatal:
|
||||
return LOG_CRIT;
|
||||
default:
|
||||
return default_level;
|
||||
}
|
||||
}
|
||||
|
||||
/// retrieve the syslog priority code given a WebSocket++ access channel
|
||||
/**
|
||||
* @param channel The level to look up
|
||||
* @return The syslog level associated with `channel`
|
||||
*/
|
||||
_WEBSOCKETPP_CONSTEXPR_TOKEN_ int syslog_priority_access(level) const {
|
||||
return default_level;
|
||||
}
|
||||
|
||||
channel_type_hint::value m_channel_type_hint;
|
||||
};
|
||||
|
||||
} // log
|
||||
} // websocketpp
|
||||
|
||||
#endif // WEBSOCKETPP_LOGGER_SYSLOG_HPP
|
||||
@@ -43,7 +43,7 @@ namespace message_buffer {
|
||||
*
|
||||
* # connection_message_manager:
|
||||
* An object that manages all of the message_buffers associated with a given
|
||||
* connection. Impliments the get_message_buffer(size) method that returns
|
||||
* connection. Implements the get_message_buffer(size) method that returns
|
||||
* a message buffer at least size bytes long.
|
||||
*
|
||||
* Message buffers are reference counted with shared ownership semantics. Once
|
||||
@@ -54,7 +54,7 @@ namespace message_buffer {
|
||||
* in the manager.
|
||||
*
|
||||
* # endpoint_message_manager:
|
||||
* An object that manages connection_message_managers. Impliments the
|
||||
* An object that manages connection_message_managers. Implements the
|
||||
* get_message_manager() method. This is used once by each connection to
|
||||
* request the message manager that they are supposed to use to manage message
|
||||
* buffers for their own use.
|
||||
@@ -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
|
||||
*/
|
||||
|
||||
@@ -42,7 +42,7 @@ namespace message_buffer {
|
||||
*
|
||||
* # connection_message_manager:
|
||||
* An object that manages all of the message_buffers associated with a given
|
||||
* connection. Impliments the get_message_buffer(size) method that returns
|
||||
* connection. Implements the get_message_buffer(size) method that returns
|
||||
* a message buffer at least size bytes long.
|
||||
*
|
||||
* Message buffers are reference counted with shared ownership semantics. Once
|
||||
@@ -53,7 +53,7 @@ namespace message_buffer {
|
||||
* in the manager.
|
||||
*
|
||||
* # endpoint_message_manager:
|
||||
* An object that manages connection_message_managers. Impliments the
|
||||
* An object that manages connection_message_managers. Implements the
|
||||
* get_message_manager() method. This is used once by each connection to
|
||||
* request the message manager that they are supposed to use to manage message
|
||||
* buffers for their own use.
|
||||
|
||||
@@ -28,14 +28,13 @@
|
||||
#ifndef WEBSOCKETPP_PROCESSOR_BASE_HPP
|
||||
#define WEBSOCKETPP_PROCESSOR_BASE_HPP
|
||||
|
||||
#include <websocketpp/common/cpp11.hpp>
|
||||
#include <websocketpp/common/system_error.hpp>
|
||||
|
||||
#include <websocketpp/close.hpp>
|
||||
#include <websocketpp/utilities.hpp>
|
||||
#include <websocketpp/uri.hpp>
|
||||
|
||||
#include <map>
|
||||
#include <websocketpp/common/cpp11.hpp>
|
||||
#include <websocketpp/common/system_error.hpp>
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace websocketpp {
|
||||
@@ -151,7 +150,11 @@ enum processor_errors {
|
||||
extension_parse_error,
|
||||
|
||||
/// Extension related operation was ignored because extensions are disabled
|
||||
extensions_disabled
|
||||
extensions_disabled,
|
||||
|
||||
/// Short Ke3 read. Hybi00 requires a third key to be read from the 8 bytes
|
||||
/// after the handshake. Less than 8 bytes were read.
|
||||
short_key3
|
||||
};
|
||||
|
||||
/// Category for processor errors
|
||||
@@ -223,6 +226,8 @@ public:
|
||||
return "Error parsing extension header";
|
||||
case error::extensions_disabled:
|
||||
return "Extensions are disabled";
|
||||
case error::short_key3:
|
||||
return "Short Hybi00 Key 3 read";
|
||||
default:
|
||||
return "Unknown";
|
||||
}
|
||||
|
||||
@@ -28,8 +28,6 @@
|
||||
#ifndef WEBSOCKETPP_PROCESSOR_HYBI00_HPP
|
||||
#define WEBSOCKETPP_PROCESSOR_HYBI00_HPP
|
||||
|
||||
#include <cstdlib>
|
||||
|
||||
#include <websocketpp/frame.hpp>
|
||||
#include <websocketpp/utf8_validator.hpp>
|
||||
#include <websocketpp/common/network.hpp>
|
||||
@@ -38,6 +36,11 @@
|
||||
|
||||
#include <websocketpp/processors/processor.hpp>
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstdlib>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace websocketpp {
|
||||
namespace processor {
|
||||
|
||||
@@ -108,7 +111,7 @@ public:
|
||||
// if it is less the final key will almost certainly be wrong.
|
||||
// TODO: decide if it is best to silently fail here or produce some sort
|
||||
// of warning or exception.
|
||||
const std::string& key3 = req.get_header("Sec-WebSocket-Key3");
|
||||
std::string const & key3 = req.get_header("Sec-WebSocket-Key3");
|
||||
std::copy(key3.c_str(),
|
||||
key3.c_str()+(std::min)(static_cast<size_t>(8), key3.size()),
|
||||
&key_final[8]);
|
||||
@@ -364,7 +367,7 @@ public:
|
||||
* @param out The message buffer to prepare the pong in.
|
||||
* @return Status code, zero on success, non-zero on failure
|
||||
*/
|
||||
lib::error_code prepare_pong(const std::string &, message_ptr) const
|
||||
lib::error_code prepare_pong(std::string const &, message_ptr) const
|
||||
{
|
||||
return lib::error_code(error::no_protocol_support);
|
||||
}
|
||||
|
||||
@@ -30,6 +30,9 @@
|
||||
|
||||
#include <websocketpp/processors/hybi08.hpp>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace websocketpp {
|
||||
namespace processor {
|
||||
|
||||
|
||||
@@ -30,6 +30,9 @@
|
||||
|
||||
#include <websocketpp/processors/hybi13.hpp>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace websocketpp {
|
||||
namespace processor {
|
||||
|
||||
@@ -68,7 +71,7 @@ public:
|
||||
return 8;
|
||||
}
|
||||
|
||||
const std::string& get_origin(request_type const & r) const {
|
||||
std::string const & get_origin(request_type const & r) const {
|
||||
return r.get_header("Sec-WebSocket-Origin");
|
||||
}
|
||||
private:
|
||||
|
||||
@@ -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,19 +28,20 @@
|
||||
#ifndef WEBSOCKETPP_PROCESSOR_HYBI13_HPP
|
||||
#define WEBSOCKETPP_PROCESSOR_HYBI13_HPP
|
||||
|
||||
#include <cassert>
|
||||
|
||||
#include <websocketpp/frame.hpp>
|
||||
#include <websocketpp/utf8_validator.hpp>
|
||||
#include <websocketpp/common/network.hpp>
|
||||
#include <websocketpp/common/platforms.hpp>
|
||||
#include <websocketpp/http/constants.hpp>
|
||||
|
||||
#include <websocketpp/processors/processor.hpp>
|
||||
|
||||
#include <websocketpp/frame.hpp>
|
||||
#include <websocketpp/http/constants.hpp>
|
||||
|
||||
#include <websocketpp/utf8_validator.hpp>
|
||||
#include <websocketpp/sha1/sha1.hpp>
|
||||
#include <websocketpp/base64/base64.hpp>
|
||||
|
||||
#include <websocketpp/common/network.hpp>
|
||||
#include <websocketpp/common/platforms.hpp>
|
||||
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <utility>
|
||||
@@ -84,7 +85,21 @@ public:
|
||||
return m_permessage_deflate.is_implemented();
|
||||
}
|
||||
|
||||
err_str_pair negotiate_extensions(request_type const & req) {
|
||||
err_str_pair negotiate_extensions(request_type const & request) {
|
||||
return negotiate_extensions_helper(request);
|
||||
}
|
||||
|
||||
err_str_pair negotiate_extensions(response_type const & response) {
|
||||
return negotiate_extensions_helper(response);
|
||||
}
|
||||
|
||||
/// Extension negotiation helper function
|
||||
/**
|
||||
* This exists mostly because the code for requests and responses is
|
||||
* identical and I can't have virtual template methods.
|
||||
*/
|
||||
template <typename header_type>
|
||||
err_str_pair negotiate_extensions_helper(header_type const & header) {
|
||||
err_str_pair ret;
|
||||
|
||||
// Respect blanket disabling of all extensions and don't even parse
|
||||
@@ -96,7 +111,7 @@ public:
|
||||
|
||||
http::parameter_list p;
|
||||
|
||||
bool error = req.get_header_as_plist("Sec-WebSocket-Extensions",p);
|
||||
bool error = header.get_header_as_plist("Sec-WebSocket-Extensions",p);
|
||||
|
||||
if (error) {
|
||||
ret.first = make_error_code(error::extension_parse_error);
|
||||
@@ -115,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) {
|
||||
@@ -127,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;
|
||||
}
|
||||
}
|
||||
@@ -160,8 +184,8 @@ public:
|
||||
* generic struct if other user input parameters to the processed handshake
|
||||
* are found.
|
||||
*/
|
||||
lib::error_code process_handshake(request_type const & request, const
|
||||
std::string & subprotocol, response_type& response) const
|
||||
lib::error_code process_handshake(request_type const & request,
|
||||
std::string const & subprotocol, response_type & response) const
|
||||
{
|
||||
std::string server_key = request.get_header("Sec-WebSocket-Key");
|
||||
|
||||
@@ -222,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();
|
||||
}
|
||||
|
||||
@@ -263,6 +294,8 @@ public:
|
||||
return error::make_error_code(error::missing_required_header);
|
||||
}
|
||||
|
||||
// check extensions
|
||||
|
||||
return lib::error_code();
|
||||
}
|
||||
|
||||
@@ -390,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.
|
||||
@@ -431,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();
|
||||
}
|
||||
@@ -453,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;
|
||||
@@ -550,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
|
||||
@@ -569,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);
|
||||
@@ -587,7 +658,19 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
// generate header
|
||||
frame::basic_header h(op,o.size(),fin,masked,compressed);
|
||||
|
||||
if (masked) {
|
||||
frame::extended_header e(o.size(),key.i);
|
||||
out->set_header(frame::prepare_header(h,e));
|
||||
} else {
|
||||
frame::extended_header e(o.size());
|
||||
out->set_header(frame::prepare_header(h,e));
|
||||
}
|
||||
|
||||
out->set_prepared(true);
|
||||
out->set_opcode(op);
|
||||
|
||||
return lib::error_code();
|
||||
}
|
||||
@@ -728,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);
|
||||
@@ -935,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:
|
||||
@@ -35,8 +35,10 @@
|
||||
#include <websocketpp/utilities.hpp>
|
||||
#include <websocketpp/uri.hpp>
|
||||
|
||||
#include <map>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
namespace websocketpp {
|
||||
/// Processors encapsulate the protocol rules specific to each WebSocket version
|
||||
@@ -103,6 +105,10 @@ bool is_websocket_handshake(request_type& r) {
|
||||
*/
|
||||
template <typename request_type>
|
||||
int get_websocket_version(request_type& r) {
|
||||
if (!r.ready()) {
|
||||
return -2;
|
||||
}
|
||||
|
||||
if (r.get_header("Sec-WebSocket-Version") == "") {
|
||||
return 0;
|
||||
}
|
||||
@@ -211,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,13 +29,16 @@
|
||||
#define WEBSOCKETPP_CLIENT_ENDPOINT_HPP
|
||||
|
||||
#include <websocketpp/endpoint.hpp>
|
||||
#include <websocketpp/uri.hpp>
|
||||
|
||||
#include <websocketpp/logger/levels.hpp>
|
||||
|
||||
#include <iostream>
|
||||
#include <websocketpp/common/system_error.hpp>
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace websocketpp {
|
||||
|
||||
|
||||
/// Client endpoint role based on the given config
|
||||
/**
|
||||
*
|
||||
|
||||
@@ -29,13 +29,13 @@
|
||||
#define WEBSOCKETPP_SERVER_ENDPOINT_HPP
|
||||
|
||||
#include <websocketpp/endpoint.hpp>
|
||||
|
||||
#include <websocketpp/logger/levels.hpp>
|
||||
|
||||
#include <iostream>
|
||||
#include <websocketpp/common/system_error.hpp>
|
||||
|
||||
namespace websocketpp {
|
||||
|
||||
|
||||
/// Server endpoint role based on the given config
|
||||
/**
|
||||
*
|
||||
@@ -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()
|
||||
|
||||
Loaded 100 of 120 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user