Compare commits
78 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 3f08de3d9d | |||
| a9f3821d99 | |||
| 2964acd6d7 | |||
| d564189d4c | |||
| ddca46f5d6 | |||
| 7f062297de | |||
| 1c199aca6e | |||
| b8af39fd82 | |||
| c94621bd29 | |||
| b83b054c7e | |||
| f6bcb86a6c | |||
| 28ac69c800 | |||
| b866e4e0ca | |||
| cdaf57cf7d | |||
| 2d49035a6d | |||
| 686b835f3d | |||
| 8f2c4264e1 | |||
| 5c608910d5 | |||
| 229698dbb0 | |||
| 6bd1bfd4f2 | |||
| dbd0fc5372 | |||
| 7454bf68f6 | |||
| 5b7f4a8c14 | |||
| 9dd53d2e28 | |||
| 915f5c77a8 | |||
| 36cae596db | |||
| 407b931395 | |||
| 25b530b8a8 | |||
| 038a9aee58 | |||
| 9749c0a3d5 | |||
| c7b1ddd9fa | |||
| 7a0d9c0238 | |||
| cb08f07cb0 | |||
| 743cd7a713 | |||
| 88fe1bfb1c | |||
| 5fd65a934b | |||
| bb1420fe06 | |||
| 0264b63fc3 | |||
| 256f8325e8 | |||
| ce410a9428 | |||
| 573dedcb9d | |||
| 4f8b2bdc98 | |||
| 330d564ded | |||
| 161a5b169a | |||
| 7d36965149 | |||
| de5684aef3 | |||
| fd93ad89cb | |||
| 6d620aa1e8 | |||
| 816fe6410d | |||
| f3c65ab609 | |||
| c938d9fd15 | |||
| 0b764bdc62 | |||
| 86e2f364de | |||
| 54dd4c8084 | |||
| cae30acf91 | |||
| 24c1804e40 | |||
| 8c6a360600 | |||
| 5c35535ffd | |||
| 3256c72d98 | |||
| 07ab02407f | |||
| edc0057a03 | |||
| 9161119b4d | |||
| 7db60e3429 | |||
| 3c0b8a81b0 | |||
| b812fd001b | |||
| 3a43986d9e | |||
| 64b1b52297 | |||
| dc048ed021 | |||
| 60b167bcb7 | |||
| e680ca1ef4 | |||
| 21d79e28c6 | |||
| d25a254e81 | |||
| 3e144cfd75 | |||
| 096a7dbaa8 | |||
| 577591aaa1 | |||
| a401a4448d | |||
| ace76f54f9 | |||
| 1eaa1b790f |
+3
-1
@@ -10,6 +10,8 @@ env:
|
||||
script: scons -j 2 && scons test
|
||||
branches:
|
||||
only:
|
||||
- master
|
||||
- permessage-deflate
|
||||
- experimental
|
||||
- 0.3.x-cmake
|
||||
notifications:
|
||||
@@ -17,4 +19,4 @@ notifications:
|
||||
- travis@zaphoyd.com
|
||||
email:
|
||||
on_success: change
|
||||
on_failure: always
|
||||
on_failure: always
|
||||
|
||||
+4
-3
@@ -9,8 +9,8 @@ project (websocketpp)
|
||||
cmake_minimum_required (VERSION 2.6)
|
||||
|
||||
set (WEBSOCKETPP_MAJOR_VERSION 0)
|
||||
set (WEBSOCKETPP_MINOR_VERSION 2)
|
||||
set (WEBSOCKETPP_PATCH_VERSION 99)
|
||||
set (WEBSOCKETPP_MINOR_VERSION 3)
|
||||
set (WEBSOCKETPP_PATCH_VERSION 0)
|
||||
set (WEBSOCKETPP_VERSION ${WEBSOCKETPP_MAJOR_VERSION}.${WEBSOCKETPP_MINOR_VERSION}.${WEBSOCKETPP_PATCH_VERSION})
|
||||
|
||||
set(INSTALL_INCLUDE_DIR include CACHE PATH "Installation directory for header files")
|
||||
@@ -204,7 +204,8 @@ if (BUILD_TESTS OR BUILD_EXAMPLES)
|
||||
else ()
|
||||
message (FATAL_ERROR "Failed to find required dependency: boost")
|
||||
endif ()
|
||||
|
||||
|
||||
find_package(OpenSSL)
|
||||
endif()
|
||||
|
||||
############ Add projects
|
||||
|
||||
@@ -33,7 +33,7 @@ PROJECT_NAME = "websocketpp"
|
||||
# if some version control system is used.
|
||||
|
||||
|
||||
PROJECT_NUMBER = "0.3.0-dev"
|
||||
PROJECT_NUMBER = "0.3.0-alpha3"
|
||||
|
||||
|
||||
# Using the PROJECT_BRIEF tag one can provide an optional one line description
|
||||
@@ -670,7 +670,10 @@ WARN_LOGFILE =
|
||||
# directories like "/usr/src/myproject". Separate the files or directories
|
||||
# with spaces.
|
||||
|
||||
INPUT = websocketpp
|
||||
INPUT = websocketpp \
|
||||
readme.md \
|
||||
changelog.md \
|
||||
roadmap.md
|
||||
|
||||
# This tag can be used to specify the character encoding of the source files
|
||||
# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is
|
||||
|
||||
+7
-43
@@ -133,17 +133,11 @@ env_cpp11 = env.Clone ()
|
||||
|
||||
if env_cpp11['CXX'].startswith('g++'):
|
||||
# TODO: check g++ version
|
||||
|
||||
# g++ STL lacks support for <regex>
|
||||
|
||||
GCC_VERSION = commands.getoutput(env_cpp11['CXX'] + ' -dumpversion')
|
||||
|
||||
if GCC_VERSION > "4.4.0":
|
||||
print "C++11 build environment partially enabled"
|
||||
env_cpp11.Append(WSPP_CPP11_ENABLED = "true",CXXFLAGS = ['-std=c++0x'],TOOLSET = ['g++'],CPPDEFINES = ['_WEBSOCKETPP_CPP11_STL_','_WEBSOCKETPP_NO_CPP11_REGEX_'])
|
||||
# libstdc++ does not yet support <regex>
|
||||
# boost regex is a drop in replacement
|
||||
polyfill_libs += boostlibs(['regex'],env_cpp11)
|
||||
env_cpp11.Append(WSPP_CPP11_ENABLED = "true",CXXFLAGS = ['-std=c++0x'],TOOLSET = ['g++'],CPPDEFINES = ['_WEBSOCKETPP_CPP11_STL_'])
|
||||
else:
|
||||
print "C++11 build environment is not supported on this version of G++"
|
||||
elif env_cpp11['CXX'].startswith('clang++'):
|
||||
@@ -209,21 +203,21 @@ if not env['PLATFORM'].startswith('win'):
|
||||
# Main test application
|
||||
#main = SConscript('#/examples/dev/SConscript',variant_dir = builddir + 'dev',duplicate = 0)
|
||||
|
||||
# testee_server
|
||||
testee_server = SConscript('#/examples/testee_server/SConscript',variant_dir = builddir + 'testee_server',duplicate = 0)
|
||||
|
||||
# echo_server
|
||||
echo_server = SConscript('#/examples/echo_server/SConscript',variant_dir = builddir + 'echo_server',duplicate = 0)
|
||||
|
||||
# echo_server_tls
|
||||
if not env['PLATFORM'].startswith('win'):
|
||||
if tls_build:
|
||||
echo_server_tls = SConscript('#/examples/echo_server_tls/SConscript',variant_dir = builddir + 'echo_server_tls',duplicate = 0)
|
||||
|
||||
# broadcast_server
|
||||
broadcast_server = SConscript('#/examples/broadcast_server/SConscript',variant_dir = builddir + 'broadcast_server',duplicate = 0)
|
||||
|
||||
# echo_client
|
||||
echo_client = SConscript('#/examples/echo_client/SConscript',variant_dir = builddir + 'echo_client',duplicate = 0)
|
||||
# testee_server
|
||||
testee_server = SConscript('#/examples/testee_server/SConscript',variant_dir = builddir + 'testee_server',duplicate = 0)
|
||||
|
||||
# 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)
|
||||
@@ -240,33 +234,3 @@ if not env['PLATFORM'].startswith('win'):
|
||||
|
||||
# print_server
|
||||
print_server = SConscript('#/examples/print_server/SConscript',variant_dir = builddir + 'print_server',duplicate = 0)
|
||||
|
||||
#
|
||||
#wsperf = SConscript('#/examples/wsperf/SConscript',
|
||||
# variant_dir = builddir + 'wsperf',
|
||||
# duplicate = 0)
|
||||
|
||||
#echo_server = SConscript('#/examples/echo_server/SConscript',
|
||||
# variant_dir = builddir + 'echo_server',
|
||||
# duplicate = 0)
|
||||
|
||||
#if tls_build:
|
||||
# echo_server_tls = SConscript('#/examples/echo_server_tls/SConscript',
|
||||
# variant_dir = builddir + 'echo_server_tls',
|
||||
# duplicate = 0)
|
||||
|
||||
#echo_client = SConscript('#/examples/echo_client/SConscript',
|
||||
# variant_dir = builddir + 'echo_client',
|
||||
# duplicate = 0)
|
||||
|
||||
#chat_client = SConscript('#/examples/chat_client/SConscript',
|
||||
# variant_dir = builddir + 'chat_client',
|
||||
# duplicate = 0)
|
||||
|
||||
#chat_server = SConscript('#/examples/chat_server/SConscript',
|
||||
# variant_dir = builddir + 'chat_server',
|
||||
# duplicate = 0)
|
||||
|
||||
#concurrent_server = SConscript('#/examples/concurrent_server/SConscript',
|
||||
# variant_dir = builddir + 'concurrent_server',
|
||||
# duplicate = 0)
|
||||
|
||||
+38
-2
@@ -1,2 +1,38 @@
|
||||
0.3.0b1 - 2013-05-??
|
||||
- Initial Release
|
||||
HEAD
|
||||
|
||||
0.3.0-alpha3 - 2013-07-16
|
||||
- Minor refactor to bundled sha1 library
|
||||
- HTTP header comparisons are now case insensitive. #220, #275
|
||||
- Refactors URI to be exception free and not use regular expressions. This
|
||||
eliminates the dependency on boost or C++11 regex libraries allowing native
|
||||
C++11 usage on GCC 4.4 and higher and significantly reduces staticly built
|
||||
binary sizes.
|
||||
- Updates handling of Server and User-Agent headers to better handle custom
|
||||
settings and allow suppression of these headers for security purposes.
|
||||
- Fix issue where pong timeout handler always fired. Thank you Steven Klassen
|
||||
for reporting this bug.
|
||||
- Add ping and pong endpoint wrapper methods
|
||||
- Add `get_request()` pass through method to connection to allow calling methods
|
||||
specific to the HTTP policy in use.
|
||||
- Fix issue compile error with `WEBSOCKETPP_STRICT_MASKING` enabled and another
|
||||
issue where `WEBSOCKETPP_STRICT_MASKING` was not applied to incoming messages.
|
||||
Thank you Petter Norby for reporting and testing these bugs. #264
|
||||
- Add additional macro guards for use with boost_config. Thank you breyed
|
||||
for testing and code. #261
|
||||
|
||||
0.3.0-alpha2 - 2013-06-09
|
||||
- Fix a regression that caused servers being sent two close frames in a row
|
||||
to end a connection uncleanly. #259
|
||||
- Fix a regression that caused spurious frames following a legitimate close
|
||||
frames to erroneously trigger handlers. #258
|
||||
- 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
|
||||
- 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
|
||||
for testing and code. #257
|
||||
|
||||
0.3.0-alpha1 - 2013-06-09
|
||||
- Initial Release
|
||||
|
||||
@@ -72,3 +72,7 @@ endmacro ()
|
||||
macro (link_boost)
|
||||
target_link_libraries (${TARGET_NAME} ${Boost_LIBRARIES})
|
||||
endmacro ()
|
||||
|
||||
macro (link_openssl)
|
||||
target_link_libraries (${TARGET_NAME} ${OPENSSL_SSL_LIBRARY} ${OPENSSL_CRYPTO_LIBRARY})
|
||||
endmacro ()
|
||||
|
||||
@@ -17,7 +17,7 @@ if env_cpp11.has_key('WSPP_CPP11_ENABLED'):
|
||||
ALL_LIBS = boostlibs(['system'],env_cpp11) + [platform_libs] + [polyfill_libs]
|
||||
prgs += env_cpp11.Program('broadcast_server', ["broadcast_server.cpp"], LIBS = ALL_LIBS)
|
||||
else:
|
||||
ALL_LIBS = boostlibs(['system','thread','regex'],env) + [platform_libs] + [polyfill_libs]
|
||||
ALL_LIBS = boostlibs(['system','thread'],env) + [platform_libs] + [polyfill_libs]
|
||||
prgs += env.Program('broadcast_server', ["broadcast_server.cpp"], LIBS = ALL_LIBS)
|
||||
|
||||
Return('prgs')
|
||||
|
||||
@@ -17,7 +17,7 @@ if env_cpp11.has_key('WSPP_CPP11_ENABLED'):
|
||||
ALL_LIBS = boostlibs(['system'],env_cpp11) + [platform_libs] + [polyfill_libs]
|
||||
prgs += env_cpp11.Program('echo_server', ["echo_server.cpp"], LIBS = ALL_LIBS)
|
||||
else:
|
||||
ALL_LIBS = boostlibs(['system','regex'],env) + [platform_libs] + [polyfill_libs]
|
||||
ALL_LIBS = boostlibs(['system'],env) + [platform_libs] + [polyfill_libs]
|
||||
prgs += env.Program('echo_server', ["echo_server.cpp"], LIBS = ALL_LIBS)
|
||||
|
||||
Return('prgs')
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
|
||||
file (GLOB SOURCE_FILES *.cpp)
|
||||
file (GLOB HEADER_FILES *.hpp)
|
||||
|
||||
|
||||
if (OPENSSL_FOUND)
|
||||
|
||||
init_target (echo_server_tls)
|
||||
|
||||
build_executable (${TARGET_NAME} ${SOURCE_FILES} ${HEADER_FILES})
|
||||
|
||||
link_boost ()
|
||||
link_openssl()
|
||||
final_target ()
|
||||
endif()
|
||||
@@ -18,7 +18,7 @@ if env_cpp11.has_key('WSPP_CPP11_ENABLED'):
|
||||
ALL_LIBS = boostlibs(['system'],env_cpp11) + [platform_libs] + [polyfill_libs] + [tls_libs]
|
||||
prgs += env_cpp11.Program('echo_server_tls', ["echo_server_tls.cpp"], LIBS = ALL_LIBS)
|
||||
else:
|
||||
ALL_LIBS = boostlibs(['system','regex'],env) + [platform_libs] + [polyfill_libs] + [tls_libs]
|
||||
ALL_LIBS = boostlibs(['system'],env) + [platform_libs] + [polyfill_libs] + [tls_libs]
|
||||
prgs += env.Program('echo_server_tls', ["echo_server_tls.cpp"], LIBS = ALL_LIBS)
|
||||
|
||||
Return('prgs')
|
||||
|
||||
@@ -17,7 +17,7 @@ if env_cpp11.has_key('WSPP_CPP11_ENABLED'):
|
||||
ALL_LIBS = boostlibs(['system'],env_cpp11) + [platform_libs] + [polyfill_libs]
|
||||
prgs += env_cpp11.Program('iostream_server', ["iostream_server.cpp"], LIBS = ALL_LIBS)
|
||||
else:
|
||||
ALL_LIBS = boostlibs(['system','regex'],env) + [platform_libs] + [polyfill_libs]
|
||||
ALL_LIBS = boostlibs(['system'],env) + [platform_libs] + [polyfill_libs]
|
||||
prgs += env.Program('iostream_server', ["iostream_server.cpp"], LIBS = ALL_LIBS)
|
||||
|
||||
Return('prgs')
|
||||
|
||||
@@ -2,10 +2,9 @@
|
||||
file (GLOB SOURCE_FILES *.cpp)
|
||||
file (GLOB HEADER_FILES *.hpp)
|
||||
|
||||
init_target (echo_client)
|
||||
init_target (print_server)
|
||||
|
||||
build_executable (${TARGET_NAME} ${SOURCE_FILES} ${HEADER_FILES})
|
||||
|
||||
link_boost ()
|
||||
final_target ()
|
||||
|
||||
@@ -17,7 +17,7 @@ if env_cpp11.has_key('WSPP_CPP11_ENABLED'):
|
||||
ALL_LIBS = boostlibs(['system'],env_cpp11) + [platform_libs] + [polyfill_libs]
|
||||
prgs += env_cpp11.Program('print_server', ["print_server.cpp"], LIBS = ALL_LIBS)
|
||||
else:
|
||||
ALL_LIBS = boostlibs(['system','regex'],env) + [platform_libs] + [polyfill_libs]
|
||||
ALL_LIBS = boostlibs(['system'],env) + [platform_libs] + [polyfill_libs]
|
||||
prgs += env.Program('print_server', ["print_server.cpp"], LIBS = ALL_LIBS)
|
||||
|
||||
Return('prgs')
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
## Main development example
|
||||
## SIP client example
|
||||
##
|
||||
|
||||
Import('env')
|
||||
@@ -17,7 +17,7 @@ if env_cpp11.has_key('WSPP_CPP11_ENABLED'):
|
||||
ALL_LIBS = boostlibs(['system'],env_cpp11) + [platform_libs] + [polyfill_libs]
|
||||
prgs += env_cpp11.Program('sip_client', ["sip_client.cpp"], LIBS = ALL_LIBS)
|
||||
else:
|
||||
ALL_LIBS = boostlibs(['system','regex','random'],env) + [platform_libs] + [polyfill_libs]
|
||||
ALL_LIBS = boostlibs(['system','random'],env) + [platform_libs] + [polyfill_libs]
|
||||
prgs += env.Program('sip_client', ["sip_client.cpp"], LIBS = ALL_LIBS)
|
||||
|
||||
Return('prgs')
|
||||
|
||||
@@ -17,7 +17,7 @@ if env_cpp11.has_key('WSPP_CPP11_ENABLED'):
|
||||
ALL_LIBS = boostlibs(['system'],env_cpp11) + [platform_libs] + [polyfill_libs]
|
||||
prgs += env_cpp11.Program('subprotocol_server', ["subprotocol_server.cpp"], LIBS = ALL_LIBS)
|
||||
else:
|
||||
ALL_LIBS = boostlibs(['system','regex'],env) + [platform_libs] + [polyfill_libs]
|
||||
ALL_LIBS = boostlibs(['system'],env) + [platform_libs] + [polyfill_libs]
|
||||
prgs += env.Program('subprotocol_server', ["subprotocol_server.cpp"], LIBS = ALL_LIBS)
|
||||
|
||||
Return('prgs')
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
|
||||
file (GLOB SOURCE_FILES *.cpp)
|
||||
file (GLOB HEADER_FILES *.hpp)
|
||||
|
||||
init_target (telemetry_client)
|
||||
|
||||
build_executable (${TARGET_NAME} ${SOURCE_FILES} ${HEADER_FILES})
|
||||
|
||||
link_boost ()
|
||||
final_target ()
|
||||
@@ -17,7 +17,7 @@ if env_cpp11.has_key('WSPP_CPP11_ENABLED'):
|
||||
ALL_LIBS = boostlibs(['system'],env_cpp11) + [platform_libs] + [polyfill_libs]
|
||||
prgs += env_cpp11.Program('telemetry_client', ["telemetry_client.cpp"], LIBS = ALL_LIBS)
|
||||
else:
|
||||
ALL_LIBS = boostlibs(['system','regex','random'],env) + [platform_libs] + [polyfill_libs]
|
||||
ALL_LIBS = boostlibs(['system','random'],env) + [platform_libs] + [polyfill_libs]
|
||||
prgs += env.Program('telemetry_client', ["telemetry_client.cpp"], LIBS = ALL_LIBS)
|
||||
|
||||
Return('prgs')
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
|
||||
file (GLOB SOURCE_FILES *.cpp)
|
||||
file (GLOB HEADER_FILES *.hpp)
|
||||
|
||||
init_target (testee_client)
|
||||
|
||||
build_executable (${TARGET_NAME} ${SOURCE_FILES} ${HEADER_FILES})
|
||||
|
||||
link_boost ()
|
||||
final_target ()
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
## Main development example
|
||||
## Autobahn test client example
|
||||
##
|
||||
|
||||
Import('env')
|
||||
@@ -15,9 +15,9 @@ 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('echo_client', ["echo_client.cpp"], LIBS = ALL_LIBS)
|
||||
prgs += env_cpp11.Program('testee_client', ["testee_client.cpp"], LIBS = ALL_LIBS)
|
||||
else:
|
||||
ALL_LIBS = boostlibs(['system','regex','random'],env) + [platform_libs] + [polyfill_libs]
|
||||
prgs += env.Program('echo_client', ["echo_client.cpp"], LIBS = ALL_LIBS)
|
||||
ALL_LIBS = boostlibs(['system','random'],env) + [platform_libs] + [polyfill_libs]
|
||||
prgs += env.Program('testee_client', ["testee_client.cpp"], LIBS = ALL_LIBS)
|
||||
|
||||
Return('prgs')
|
||||
@@ -19,7 +19,8 @@ void on_message(client* c, websocketpp::connection_hdl hdl, message_ptr msg) {
|
||||
client::connection_ptr con = c->get_con_from_hdl(hdl);
|
||||
|
||||
if (con->get_resource() == "/getCaseCount") {
|
||||
std::cout << "Detected " << msg->get_payload() << " test cases." << std::endl;
|
||||
std::cout << "Detected " << msg->get_payload() << " test cases."
|
||||
<< std::endl;
|
||||
case_count = atoi(msg->get_payload().c_str());
|
||||
} else {
|
||||
c->send(hdl, msg->get_payload(), msg->get_opcode());
|
||||
@@ -28,7 +29,7 @@ void on_message(client* c, websocketpp::connection_hdl hdl, message_ptr msg) {
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
// Create a server endpoint
|
||||
client echo_client;
|
||||
client c;
|
||||
|
||||
std::string uri = "ws://localhost:9001";
|
||||
|
||||
@@ -38,36 +39,37 @@ int main(int argc, char* argv[]) {
|
||||
|
||||
try {
|
||||
// We expect there to be a lot of errors, so suppress them
|
||||
echo_client.clear_access_channels(websocketpp::log::alevel::all);
|
||||
echo_client.clear_error_channels(websocketpp::log::elevel::all);
|
||||
c.clear_access_channels(websocketpp::log::alevel::all);
|
||||
c.clear_error_channels(websocketpp::log::elevel::all);
|
||||
|
||||
// Initialize ASIO
|
||||
echo_client.init_asio();
|
||||
c.init_asio();
|
||||
|
||||
// Register our handlers
|
||||
echo_client.set_message_handler(bind(&on_message,&echo_client,::_1,::_2));
|
||||
c.set_message_handler(bind(&on_message,&c,::_1,::_2));
|
||||
|
||||
websocketpp::lib::error_code ec;
|
||||
client::connection_ptr con = echo_client.get_connection(uri+"/getCaseCount", ec);
|
||||
echo_client.connect(con);
|
||||
client::connection_ptr con = c.get_connection(uri+"/getCaseCount", ec);
|
||||
c.connect(con);
|
||||
|
||||
// Start the ASIO io_service run loop
|
||||
echo_client.run();
|
||||
c.run();
|
||||
|
||||
std::cout << "case count: " << case_count << std::endl;
|
||||
|
||||
for (int i = 1; i <= case_count; i++) {
|
||||
echo_client.reset();
|
||||
c.reset();
|
||||
|
||||
std::stringstream url;
|
||||
|
||||
url << uri << "/runCase?case=" << i << "&agent=WebSocket++/0.3.0-dev";
|
||||
url << uri << "/runCase?case=" << i << "&agent="
|
||||
<< websocketpp::user_agent;
|
||||
|
||||
con = echo_client.get_connection(url.str(), ec);
|
||||
con = c.get_connection(url.str(), ec);
|
||||
|
||||
echo_client.connect(con);
|
||||
c.connect(con);
|
||||
|
||||
echo_client.run();
|
||||
c.run();
|
||||
}
|
||||
|
||||
std::cout << "done" << std::endl;
|
||||
@@ -17,7 +17,7 @@ if env_cpp11.has_key('WSPP_CPP11_ENABLED'):
|
||||
ALL_LIBS = boostlibs(['system'],env_cpp11) + [platform_libs] + [polyfill_libs]
|
||||
prgs += env_cpp11.Program('testee_server', ["testee_server.cpp"], LIBS = ALL_LIBS)
|
||||
else:
|
||||
ALL_LIBS = boostlibs(['system','regex'],env) + [platform_libs] + [polyfill_libs]
|
||||
ALL_LIBS = boostlibs(['system'],env) + [platform_libs] + [polyfill_libs]
|
||||
prgs += env.Program('testee_server', ["testee_server.cpp"], LIBS = ALL_LIBS)
|
||||
|
||||
Return('prgs')
|
||||
|
||||
@@ -18,7 +18,7 @@ if env_cpp11.has_key('WSPP_CPP11_ENABLED'):
|
||||
ALL_LIBS = boostlibs(['system'],env_cpp11) + [platform_libs] + [polyfill_libs] + [tls_libs]
|
||||
prgs += env_cpp11.Program('utility_client', ["utility_client.cpp"], LIBS = ALL_LIBS)
|
||||
else:
|
||||
ALL_LIBS = boostlibs(['system','regex','random'],env) + [platform_libs] + [polyfill_libs] + [tls_libs]
|
||||
ALL_LIBS = boostlibs(['system','random'],env) + [platform_libs] + [polyfill_libs] + [tls_libs]
|
||||
prgs += env.Program('utility_client', ["utility_client.cpp"], LIBS = ALL_LIBS)
|
||||
|
||||
Return('prgs')
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
WebSocket++ (0.3.x branch)
|
||||
WebSocket++ (0.3.0-alpha3)
|
||||
==========================
|
||||
|
||||
WebSocket++ is a header only C++ library that implements RFC6455 The WebSocket
|
||||
@@ -6,18 +6,6 @@ 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.
|
||||
|
||||
*This branch is no longer "experimental". It represents the current edge release
|
||||
of the WebSocket++ library. The API of 0.3.x has some significant changes from
|
||||
0.2.x, so care should be taken when upgrading.*
|
||||
|
||||
*This branch's API is relatively stable now. Features implemented so far are
|
||||
unlikely to change (except where explicitly noted). New features will be added
|
||||
regularly until parity with the 0.2 branch is reached.*
|
||||
|
||||
*This is the preferred branch for new projects, especially those that involve
|
||||
multithreaded servers. It is better tested and documented. The 0.3.x API will
|
||||
be the basis for the 1.0 release.*
|
||||
|
||||
Major Features
|
||||
==============
|
||||
* Full support for RFC6455
|
||||
@@ -26,7 +14,8 @@ Major Features
|
||||
* 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)
|
||||
* Portable, cross platform and architecture design
|
||||
* Portable/cross platform (Posix/Windows, 32/64bit, Intel/ARM/PPC)
|
||||
* Thread-safe
|
||||
|
||||
Get Involved
|
||||
============
|
||||
@@ -46,7 +35,7 @@ https://github.com/zaphoyd/websocketpp/
|
||||
http://groups.google.com/group/websocketpp-announcements/
|
||||
|
||||
**IRC Channel**
|
||||
#websocketpp (freenode)
|
||||
#websocketpp (freenode)
|
||||
|
||||
**Discussion / Development / Support Mailing List / Forum**
|
||||
http://groups.google.com/group/websocketpp/
|
||||
|
||||
+5
-9
@@ -8,6 +8,8 @@ Complete & Tested:
|
||||
- GCC support
|
||||
- 64 bit support
|
||||
- 32 bit support
|
||||
- Logging
|
||||
- Client role
|
||||
|
||||
Implimented, needs more testing
|
||||
- TLS support
|
||||
@@ -20,26 +22,20 @@ Implimented, needs more testing
|
||||
- pong_handler
|
||||
- tcp_init_handler
|
||||
- exception/error handling
|
||||
- Logging
|
||||
- Client role
|
||||
- Subprotocol negotiation
|
||||
- Hybi 00/Hixie 76 legacy protocol support
|
||||
- Performance tuning
|
||||
- Outgoing Proxy Support
|
||||
- PowerPC support
|
||||
- Visual Studio / Windows support
|
||||
|
||||
Implimented, API not finalized
|
||||
- Timeouts
|
||||
- CMake build/install support
|
||||
- open_handler
|
||||
- close_handler
|
||||
- validate_handler
|
||||
- http_handler
|
||||
|
||||
Needs work:
|
||||
- Timeouts
|
||||
|
||||
Non-release blocking feature roadmap
|
||||
Future feature roadmap
|
||||
- Extension support
|
||||
- permessage_compress extension
|
||||
- Message buffer pool
|
||||
- CMake build/install support
|
||||
@@ -10,7 +10,7 @@ Import('polyfill_libs')
|
||||
env = env.Clone ()
|
||||
env_cpp11 = env_cpp11.Clone ()
|
||||
|
||||
BOOST_LIBS = boostlibs(['unit_test_framework','regex','system'],env) + [platform_libs]
|
||||
BOOST_LIBS = boostlibs(['unit_test_framework','system'],env) + [platform_libs]
|
||||
|
||||
objs = env.Object('connection_boost.o', ["connection.cpp"], LIBS = BOOST_LIBS)
|
||||
objs = env.Object('connection_tu2_boost.o', ["connection_tu2.cpp"], LIBS = BOOST_LIBS)
|
||||
|
||||
@@ -36,7 +36,7 @@
|
||||
|
||||
BOOST_AUTO_TEST_CASE( basic_http_request ) {
|
||||
std::string input = "GET / HTTP/1.1\r\nHost: www.example.com\r\n\r\n";
|
||||
std::string output = "HTTP/1.1 500 Internal Server Error\r\nServer: " +
|
||||
std::string output = "HTTP/1.1 426 Upgrade Required\r\nServer: " +
|
||||
std::string(websocketpp::user_agent)+"\r\n\r\n";
|
||||
|
||||
std::string o2 = run_server_test(input);
|
||||
@@ -98,6 +98,12 @@ void validate_func(server* s, websocketpp::connection_hdl hdl, message_ptr msg)
|
||||
s->send(hdl, msg->get_payload(), msg->get_opcode());
|
||||
}
|
||||
|
||||
bool validate_set_ua(server* s, websocketpp::connection_hdl hdl) {
|
||||
server::connection_ptr con = s->get_con_from_hdl(hdl);
|
||||
con->replace_header("Server","foo");
|
||||
return true;
|
||||
}
|
||||
|
||||
void http_func(server* s, websocketpp::connection_hdl hdl) {
|
||||
server::connection_ptr con = s->get_con_from_hdl(hdl);
|
||||
|
||||
@@ -140,6 +146,52 @@ BOOST_AUTO_TEST_CASE( http_request ) {
|
||||
BOOST_CHECK_EQUAL(run_server_test(s,input), output);
|
||||
}
|
||||
|
||||
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";
|
||||
|
||||
server s;
|
||||
s.set_user_agent("");
|
||||
s.set_message_handler(bind(&echo_func,&s,::_1,::_2));
|
||||
|
||||
BOOST_CHECK_EQUAL(run_server_test(s,input), output);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( request_no_server_header_override ) {
|
||||
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\nServer: foo\r\nUpgrade: websocket\r\n\r\n";
|
||||
|
||||
server s;
|
||||
s.set_user_agent("");
|
||||
s.set_message_handler(bind(&echo_func,&s,::_1,::_2));
|
||||
s.set_validate_handler(bind(&validate_set_ua,&s,::_1));
|
||||
|
||||
BOOST_CHECK_EQUAL(run_server_test(s,input), output);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( basic_client_websocket ) {
|
||||
std::string uri = "ws://localhost";
|
||||
|
||||
//std::string output = "HTTP/1.1 101 Switching Protocols\r\nConnection: upgrade\r\nSec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\nServer: foo\r\nUpgrade: websocket\r\n\r\n";
|
||||
|
||||
std::string ref = "GET / HTTP/1.1\r\nConnection: Upgrade\r\nHost: localhost\r\nSec-WebSocket-Key: AAAAAAAAAAAAAAAAAAAAAA==\r\nSec-WebSocket-Version: 13\r\nUpgrade: websocket\r\nUser-Agent: foo\r\n\r\n";
|
||||
|
||||
std::stringstream output;
|
||||
|
||||
client e;
|
||||
e.set_access_channels(websocketpp::log::alevel::none);
|
||||
e.set_error_channels(websocketpp::log::elevel::none);
|
||||
e.set_user_agent("foo");
|
||||
e.register_ostream(&output);
|
||||
|
||||
client::connection_ptr con;
|
||||
websocketpp::lib::error_code ec;
|
||||
con = e.get_connection(uri, ec);
|
||||
e.connect(con);
|
||||
|
||||
BOOST_CHECK_EQUAL(ref, output.str());
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
BOOST_AUTO_TEST_CASE( user_reject_origin ) {
|
||||
|
||||
@@ -36,7 +36,7 @@ std::string run_server_test(std::string input) {
|
||||
return run_server_test(test_server,input);
|
||||
}
|
||||
|
||||
std::string run_server_test(server& s, std::string input) {
|
||||
std::string run_server_test(server & s, std::string input) {
|
||||
server::connection_ptr con;
|
||||
std::stringstream output;
|
||||
|
||||
|
||||
@@ -32,25 +32,19 @@
|
||||
// server, no TLS, no locks, iostream based transport
|
||||
#include <websocketpp/config/core.hpp>
|
||||
#include <websocketpp/server.hpp>
|
||||
#include <websocketpp/client.hpp>
|
||||
|
||||
typedef websocketpp::server<websocketpp::config::core> server;
|
||||
/// NOTE: the "server" config is being used for the client here because we don't
|
||||
/// want to pull in the real RNG. A better way to do this might be a custom
|
||||
/// client config with the RNG explicitly stubbed out.
|
||||
typedef websocketpp::client<websocketpp::config::core> client;
|
||||
typedef websocketpp::config::core::message_type::ptr message_ptr;
|
||||
|
||||
using websocketpp::lib::placeholders::_1;
|
||||
using websocketpp::lib::placeholders::_2;
|
||||
using websocketpp::lib::bind;
|
||||
|
||||
/*class echo_handler : public server::handler {
|
||||
bool validate(connection_ptr con) {
|
||||
std::cout << "handler validate" << std::endl;
|
||||
if (con->get_origin() != "http://www.example.com") {
|
||||
con->set_status(websocketpp::http::status_code::FORBIDDEN);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};*/
|
||||
|
||||
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(server & s, std::string input);
|
||||
@@ -11,7 +11,7 @@ Import('tls_libs')
|
||||
env = env.Clone ()
|
||||
env_cpp11 = env_cpp11.Clone ()
|
||||
|
||||
BOOST_LIBS = boostlibs(['unit_test_framework','regex','system'],env) + [platform_libs] + [tls_libs]
|
||||
BOOST_LIBS = boostlibs(['unit_test_framework','system'],env) + [platform_libs] + [tls_libs]
|
||||
|
||||
objs = env.Object('endpoint_boost.o', ["endpoint.cpp"], LIBS = BOOST_LIBS)
|
||||
prgs = env.Program('test_endpoint_boost', ["endpoint_boost.o"], LIBS = BOOST_LIBS)
|
||||
|
||||
@@ -10,14 +10,18 @@ Import('polyfill_libs')
|
||||
env = env.Clone ()
|
||||
env_cpp11 = env_cpp11.Clone ()
|
||||
|
||||
BOOST_LIBS = boostlibs(['unit_test_framework','system','regex'],env) + [platform_libs]
|
||||
BOOST_LIBS = boostlibs(['unit_test_framework','system'],env) + [platform_libs] + ['z']
|
||||
|
||||
objs = env.Object('extension_boost.o', ["extension.cpp"], LIBS = BOOST_LIBS)
|
||||
objs += env.Object('permessage_deflate_boost.o', ["permessage_deflate.cpp"], LIBS = BOOST_LIBS)
|
||||
prgs = env.Program('test_extension_boost', ["extension_boost.o"], LIBS = BOOST_LIBS)
|
||||
prgs += env.Program('test_permessage_deflate_boost', ["permessage_deflate_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]
|
||||
BOOST_LIBS_CPP11 = boostlibs(['unit_test_framework'],env_cpp11) + [platform_libs] + [polyfill_libs] + ['z']
|
||||
objs += env_cpp11.Object('extension_stl.o', ["extension.cpp"], LIBS = BOOST_LIBS_CPP11)
|
||||
objs += env_cpp11.Object('permessage_deflate_stl.o', ["permessage_deflate.cpp"], LIBS = BOOST_LIBS_CPP11)
|
||||
prgs += env_cpp11.Program('test_extension_stl', ["extension_stl.o"], LIBS = BOOST_LIBS_CPP11)
|
||||
prgs += env_cpp11.Program('test_permessage_deflate_stl', ["permessage_deflate_stl.o"], LIBS = BOOST_LIBS_CPP11)
|
||||
|
||||
Return('prgs')
|
||||
|
||||
@@ -0,0 +1,543 @@
|
||||
/*
|
||||
* Copyright (c) 2011, 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 permessage_deflate
|
||||
#include <boost/test/unit_test.hpp>
|
||||
|
||||
#include <websocketpp/error.hpp>
|
||||
|
||||
#include <websocketpp/extensions/extension.hpp>
|
||||
#include <websocketpp/extensions/permessage_deflate/disabled.hpp>
|
||||
#include <websocketpp/extensions/permessage_deflate/enabled.hpp>
|
||||
|
||||
#include <string>
|
||||
|
||||
#include <websocketpp/utilities.hpp>
|
||||
#include <iostream>
|
||||
|
||||
class config {};
|
||||
|
||||
typedef websocketpp::extensions::permessage_deflate::enabled<config> enabled_type;
|
||||
typedef websocketpp::extensions::permessage_deflate::disabled<config> disabled_type;
|
||||
|
||||
struct ext_vars {
|
||||
enabled_type exts;
|
||||
enabled_type extc;
|
||||
websocketpp::lib::error_code ec;
|
||||
websocketpp::err_str_pair esp;
|
||||
websocketpp::http::attribute_list attr;
|
||||
};
|
||||
namespace pmde = websocketpp::extensions::permessage_deflate::error;
|
||||
namespace pmd_mode = websocketpp::extensions::permessage_deflate::mode;
|
||||
|
||||
// Ensure the disabled extension behaves appropriately disabled
|
||||
|
||||
BOOST_AUTO_TEST_CASE( disabled_is_disabled ) {
|
||||
disabled_type exts;
|
||||
BOOST_CHECK( !exts.is_implemented() );
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( disabled_is_off ) {
|
||||
disabled_type exts;
|
||||
BOOST_CHECK( !exts.is_enabled() );
|
||||
}
|
||||
|
||||
// Ensure the enabled version actually works
|
||||
|
||||
BOOST_AUTO_TEST_CASE( enabled_is_enabled ) {
|
||||
ext_vars v;
|
||||
BOOST_CHECK( v.exts.is_implemented() );
|
||||
BOOST_CHECK( v.extc.is_implemented() );
|
||||
}
|
||||
|
||||
|
||||
BOOST_AUTO_TEST_CASE( enabled_starts_disabled ) {
|
||||
ext_vars v;
|
||||
BOOST_CHECK( !v.exts.is_enabled() );
|
||||
BOOST_CHECK( !v.extc.is_enabled() );
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( negotiation_empty_attr ) {
|
||||
ext_vars v;
|
||||
|
||||
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( negotiation_invalid_attr ) {
|
||||
ext_vars v;
|
||||
v.attr["foo"] = "bar";
|
||||
|
||||
v.esp = v.exts.negotiate(v.attr);
|
||||
BOOST_CHECK( !v.exts.is_enabled() );
|
||||
BOOST_CHECK_EQUAL( v.esp.first, pmde::make_error_code(pmde::invalid_attributes) );
|
||||
BOOST_CHECK_EQUAL( v.esp.second, "");
|
||||
}
|
||||
|
||||
// Negotiate s2c_no_context_takeover
|
||||
BOOST_AUTO_TEST_CASE( negotiate_s2c_no_context_takeover_invalid ) {
|
||||
ext_vars v;
|
||||
v.attr["s2c_no_context_takeover"] = "foo";
|
||||
|
||||
v.esp = v.exts.negotiate(v.attr);
|
||||
BOOST_CHECK( !v.exts.is_enabled() );
|
||||
BOOST_CHECK_EQUAL( v.esp.first, pmde::make_error_code(pmde::invalid_attribute_value) );
|
||||
BOOST_CHECK_EQUAL( v.esp.second, "");
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( negotiate_s2c_no_context_takeover ) {
|
||||
ext_vars v;
|
||||
v.attr["s2c_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_AUTO_TEST_CASE( negotiate_s2c_no_context_takeover_server_initiated ) {
|
||||
ext_vars v;
|
||||
|
||||
v.exts.enable_s2c_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");
|
||||
}
|
||||
|
||||
// Negotiate c2s_no_context_takeover
|
||||
BOOST_AUTO_TEST_CASE( negotiate_c2s_no_context_takeover_invalid ) {
|
||||
ext_vars v;
|
||||
v.attr["c2s_no_context_takeover"] = "foo";
|
||||
|
||||
v.esp = v.exts.negotiate(v.attr);
|
||||
BOOST_CHECK( !v.exts.is_enabled() );
|
||||
BOOST_CHECK_EQUAL( v.esp.first, pmde::make_error_code(pmde::invalid_attribute_value) );
|
||||
BOOST_CHECK_EQUAL( v.esp.second, "");
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( negotiate_c2s_no_context_takeover ) {
|
||||
ext_vars v;
|
||||
v.attr["c2s_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_AUTO_TEST_CASE( negotiate_c2s_no_context_takeover_server_initiated ) {
|
||||
ext_vars v;
|
||||
|
||||
v.exts.enable_c2s_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");
|
||||
}
|
||||
|
||||
|
||||
// Negotiate s2c_max_window_bits
|
||||
BOOST_AUTO_TEST_CASE( negotiate_s2c_max_window_bits_invalid ) {
|
||||
ext_vars v;
|
||||
|
||||
std::vector<std::string> values;
|
||||
values.push_back("");
|
||||
values.push_back("foo");
|
||||
values.push_back("7");
|
||||
values.push_back("16");
|
||||
|
||||
std::vector<std::string>::const_iterator it;
|
||||
for (it = values.begin(); it != values.end(); ++it) {
|
||||
v.attr["s2c_max_window_bits"] = *it;
|
||||
|
||||
v.esp = v.exts.negotiate(v.attr);
|
||||
BOOST_CHECK( !v.exts.is_enabled() );
|
||||
BOOST_CHECK_EQUAL( v.esp.first, pmde::make_error_code(pmde::invalid_attribute_value) );
|
||||
BOOST_CHECK_EQUAL( v.esp.second, "");
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( negotiate_s2c_max_window_bits_valid ) {
|
||||
ext_vars v;
|
||||
v.attr["s2c_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");
|
||||
|
||||
v.attr["s2c_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_s2c_max_window_bits ) {
|
||||
ext_vars v;
|
||||
|
||||
v.ec = v.exts.set_s2c_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);
|
||||
BOOST_CHECK_EQUAL(v.ec,pmde::make_error_code(pmde::invalid_max_window_bits));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( negotiate_s2c_max_window_bits_decline ) {
|
||||
ext_vars v;
|
||||
v.attr["s2c_max_window_bits"] = "8";
|
||||
|
||||
v.ec = v.exts.set_s2c_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() );
|
||||
BOOST_CHECK_EQUAL( v.esp.first, websocketpp::lib::error_code() );
|
||||
BOOST_CHECK_EQUAL( v.esp.second, "permessage-deflate");
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( negotiate_s2c_max_window_bits_accept ) {
|
||||
ext_vars v;
|
||||
v.attr["s2c_max_window_bits"] = "8";
|
||||
|
||||
v.ec = v.exts.set_s2c_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_AUTO_TEST_CASE( negotiate_s2c_max_window_bits_largest ) {
|
||||
ext_vars v;
|
||||
v.attr["s2c_max_window_bits"] = "8";
|
||||
|
||||
v.ec = v.exts.set_s2c_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_AUTO_TEST_CASE( negotiate_s2c_max_window_bits_smallest ) {
|
||||
ext_vars v;
|
||||
v.attr["s2c_max_window_bits"] = "8";
|
||||
|
||||
v.ec = v.exts.set_s2c_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");
|
||||
}
|
||||
|
||||
// Negotiate s2c_max_window_bits
|
||||
BOOST_AUTO_TEST_CASE( negotiate_c2s_max_window_bits_invalid ) {
|
||||
ext_vars v;
|
||||
|
||||
std::vector<std::string> values;
|
||||
values.push_back("foo");
|
||||
values.push_back("7");
|
||||
values.push_back("16");
|
||||
|
||||
std::vector<std::string>::const_iterator it;
|
||||
for (it = values.begin(); it != values.end(); ++it) {
|
||||
v.attr["c2s_max_window_bits"] = *it;
|
||||
|
||||
v.esp = v.exts.negotiate(v.attr);
|
||||
BOOST_CHECK( !v.exts.is_enabled() );
|
||||
BOOST_CHECK_EQUAL( v.esp.first, pmde::make_error_code(pmde::invalid_attribute_value) );
|
||||
BOOST_CHECK_EQUAL( v.esp.second, "");
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( negotiate_c2s_max_window_bits_valid ) {
|
||||
ext_vars v;
|
||||
|
||||
v.attr["c2s_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.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");
|
||||
|
||||
v.attr["c2s_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 ) {
|
||||
ext_vars v;
|
||||
|
||||
v.ec = v.exts.set_c2s_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);
|
||||
BOOST_CHECK_EQUAL(v.ec,pmde::make_error_code(pmde::invalid_max_window_bits));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( negotiate_c2s_max_window_bits_decline ) {
|
||||
ext_vars v;
|
||||
v.attr["c2s_max_window_bits"] = "8";
|
||||
|
||||
v.ec = v.exts.set_c2s_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() );
|
||||
BOOST_CHECK_EQUAL( v.esp.first, websocketpp::lib::error_code() );
|
||||
BOOST_CHECK_EQUAL( v.esp.second, "permessage-deflate");
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( negotiate_c2s_max_window_bits_accept ) {
|
||||
ext_vars v;
|
||||
v.attr["c2s_max_window_bits"] = "8";
|
||||
|
||||
v.ec = v.exts.set_c2s_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_AUTO_TEST_CASE( negotiate_c2s_max_window_bits_largest ) {
|
||||
ext_vars v;
|
||||
v.attr["c2s_max_window_bits"] = "8";
|
||||
|
||||
v.ec = v.exts.set_c2s_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_AUTO_TEST_CASE( negotiate_c2s_max_window_bits_smallest ) {
|
||||
ext_vars v;
|
||||
v.attr["c2s_max_window_bits"] = "8";
|
||||
|
||||
v.ec = v.exts.set_c2s_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");
|
||||
}
|
||||
|
||||
|
||||
// Combinations with 2
|
||||
BOOST_AUTO_TEST_CASE( negotiate_two_client_initiated1 ) {
|
||||
ext_vars v;
|
||||
|
||||
v.attr["s2c_no_context_takeover"] = "";
|
||||
v.attr["c2s_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_AUTO_TEST_CASE( negotiate_two_client_initiated2 ) {
|
||||
ext_vars v;
|
||||
|
||||
v.attr["s2c_no_context_takeover"] = "";
|
||||
v.attr["s2c_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_AUTO_TEST_CASE( negotiate_two_client_initiated3 ) {
|
||||
ext_vars v;
|
||||
|
||||
v.attr["s2c_no_context_takeover"] = "";
|
||||
v.attr["c2s_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_AUTO_TEST_CASE( negotiate_two_client_initiated4 ) {
|
||||
ext_vars v;
|
||||
|
||||
v.attr["c2s_no_context_takeover"] = "";
|
||||
v.attr["s2c_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_AUTO_TEST_CASE( negotiate_two_client_initiated5 ) {
|
||||
ext_vars v;
|
||||
|
||||
v.attr["c2s_no_context_takeover"] = "";
|
||||
v.attr["c2s_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_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.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_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.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_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.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_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.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_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.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_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.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");
|
||||
}
|
||||
|
||||
// Compression
|
||||
/*
|
||||
BOOST_AUTO_TEST_CASE( compress_data ) {
|
||||
ext_vars v;
|
||||
|
||||
std::string in = "Hello";
|
||||
std::string out;
|
||||
std::string in2;
|
||||
std::string out2;
|
||||
|
||||
v.exts.init();
|
||||
|
||||
v.ec = v.exts.compress(in,out);
|
||||
|
||||
std::cout << "in : " << websocketpp::utility::to_hex(in) << std::endl;
|
||||
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);
|
||||
|
||||
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_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;
|
||||
|
||||
v.exts.init();
|
||||
|
||||
v.ec = v.exts.decompress(in,12,out);
|
||||
|
||||
BOOST_CHECK_EQUAL( v.ec, websocketpp::lib::error_code() );
|
||||
std::cout << "out: " << websocketpp::utility::to_hex(out) << std::endl;
|
||||
BOOST_CHECK( false );
|
||||
}
|
||||
*/
|
||||
@@ -10,7 +10,7 @@ Import('polyfill_libs')
|
||||
env = env.Clone ()
|
||||
env_cpp11 = env_cpp11.Clone ()
|
||||
|
||||
BOOST_LIBS = boostlibs(['unit_test_framework','regex'],env) + [platform_libs]
|
||||
BOOST_LIBS = boostlibs(['unit_test_framework'],env) + [platform_libs]
|
||||
|
||||
objs = env.Object('parser_boost.o', ["parser.cpp"], LIBS = BOOST_LIBS)
|
||||
prgs = env.Program('test_http_boost', ["parser_boost.o"], LIBS = BOOST_LIBS)
|
||||
|
||||
+32
-4
@@ -186,7 +186,7 @@ BOOST_AUTO_TEST_CASE( extract_all_lws ) {
|
||||
BOOST_AUTO_TEST_CASE( extract_attributes_blank ) {
|
||||
std::string s = "";
|
||||
|
||||
websocketpp::http::parser::attribute_list a;
|
||||
websocketpp::http::attribute_list a;
|
||||
std::string::const_iterator it;
|
||||
|
||||
it = websocketpp::http::parser::extract_attributes(s.begin(),s.end(),a);
|
||||
@@ -197,7 +197,7 @@ BOOST_AUTO_TEST_CASE( extract_attributes_blank ) {
|
||||
BOOST_AUTO_TEST_CASE( extract_attributes_simple ) {
|
||||
std::string s = "foo";
|
||||
|
||||
websocketpp::http::parser::attribute_list a;
|
||||
websocketpp::http::attribute_list a;
|
||||
std::string::const_iterator it;
|
||||
|
||||
it = websocketpp::http::parser::extract_attributes(s.begin(),s.end(),a);
|
||||
@@ -224,8 +224,8 @@ BOOST_AUTO_TEST_CASE( extract_parameters ) {
|
||||
|
||||
|
||||
std::string sx = "foo;bar=\"a \\\"b\\\" c\"";
|
||||
websocketpp::http::parser::parameter_list p;
|
||||
websocketpp::http::parser::attribute_list a;
|
||||
websocketpp::http::parameter_list p;
|
||||
websocketpp::http::attribute_list a;
|
||||
std::string::const_iterator it;
|
||||
|
||||
using websocketpp::http::parser::extract_parameters;
|
||||
@@ -355,6 +355,34 @@ BOOST_AUTO_TEST_CASE( extract_parameters ) {
|
||||
BOOST_CHECK_EQUAL( a.find("bar")->second, "a \"b\" c" );
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( case_insensitive_headers ) {
|
||||
websocketpp::http::parser::parser r;
|
||||
|
||||
r.replace_header("foo","bar");
|
||||
|
||||
BOOST_CHECK_EQUAL( r.get_header("foo"), "bar" );
|
||||
BOOST_CHECK_EQUAL( r.get_header("FOO"), "bar" );
|
||||
BOOST_CHECK_EQUAL( r.get_header("Foo"), "bar" );
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( case_insensitive_headers_overwrite ) {
|
||||
websocketpp::http::parser::parser r;
|
||||
|
||||
r.replace_header("foo","bar");
|
||||
|
||||
BOOST_CHECK_EQUAL( r.get_header("foo"), "bar" );
|
||||
BOOST_CHECK_EQUAL( r.get_header("Foo"), "bar" );
|
||||
|
||||
r.replace_header("Foo","baz");
|
||||
|
||||
BOOST_CHECK_EQUAL( r.get_header("foo"), "baz" );
|
||||
BOOST_CHECK_EQUAL( r.get_header("Foo"), "baz" );
|
||||
|
||||
r.remove_header("FoO");
|
||||
|
||||
BOOST_CHECK_EQUAL( r.get_header("foo"), "" );
|
||||
BOOST_CHECK_EQUAL( r.get_header("Foo"), "" );
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( blank_consume ) {
|
||||
websocketpp::http::parser::request r;
|
||||
|
||||
@@ -10,7 +10,7 @@ Import('polyfill_libs')
|
||||
env = env.Clone ()
|
||||
env_cpp11 = env_cpp11.Clone ()
|
||||
|
||||
BOOST_LIBS = boostlibs(['unit_test_framework','regex','system'],env) + [platform_libs]
|
||||
BOOST_LIBS = boostlibs(['unit_test_framework','system'],env) + [platform_libs]
|
||||
|
||||
objs = env.Object('logger_basic_boost.o', ["basic.cpp"], LIBS = BOOST_LIBS)
|
||||
prgs = env.Program('logger_basic_boost', ["logger_basic_boost.o"], LIBS = BOOST_LIBS)
|
||||
|
||||
@@ -10,7 +10,7 @@ Import('polyfill_libs')
|
||||
env = env.Clone ()
|
||||
env_cpp11 = env_cpp11.Clone ()
|
||||
|
||||
BOOST_LIBS = boostlibs(['unit_test_framework','regex','system'],env) + [platform_libs]
|
||||
BOOST_LIBS = boostlibs(['unit_test_framework','system'],env) + [platform_libs] + ['z']
|
||||
|
||||
objs = env.Object('test_processor_boost.o', ["processor.cpp"], LIBS = BOOST_LIBS)
|
||||
objs += env.Object('test_hybi13_boost.o', ["hybi13.cpp"], LIBS = BOOST_LIBS)
|
||||
@@ -27,7 +27,7 @@ prgs += env.Program('test_hybi00_boost', ["test_hybi00_boost.o"], LIBS = BOOST_L
|
||||
prgs += env.Program('test_extension_permessage_compress_boost', ["test_extension_permessage_compress_boost.o"], LIBS = BOOST_LIBS + ['z'])
|
||||
|
||||
if env_cpp11.has_key('WSPP_CPP11_ENABLED'):
|
||||
BOOST_LIBS_CPP11 = boostlibs(['unit_test_framework'],env_cpp11) + [platform_libs] + [polyfill_libs]
|
||||
BOOST_LIBS_CPP11 = boostlibs(['unit_test_framework'],env_cpp11) + [platform_libs] + [polyfill_libs] + ['z']
|
||||
# no C++11 features are used in processor so there are no C++11 versions of
|
||||
# these tests.
|
||||
objs += env_cpp11.Object('test_processor_stl.o', ["processor.cpp"], LIBS = BOOST_LIBS_CPP11)
|
||||
|
||||
@@ -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:
|
||||
@@ -81,7 +81,7 @@ BOOST_AUTO_TEST_CASE( exact_match ) {
|
||||
BOOST_CHECK_EQUAL(u->get_secure(), false);
|
||||
BOOST_CHECK_EQUAL(u->get_host(), "www.example.com");
|
||||
BOOST_CHECK_EQUAL(u->get_resource(), "/");
|
||||
BOOST_CHECK_EQUAL(u->get_port(), websocketpp::URI_DEFAULT_PORT);
|
||||
BOOST_CHECK_EQUAL(u->get_port(), websocketpp::uri_default_port);
|
||||
|
||||
env.p.process_handshake(env.req,"",env.res);
|
||||
|
||||
@@ -158,7 +158,7 @@ BOOST_AUTO_TEST_CASE( bad_host ) {
|
||||
BOOST_CHECK_EQUAL(websocketpp::processor::get_websocket_version(env.req), env.p.get_version());
|
||||
BOOST_CHECK( !env.p.validate_handshake(env.req) );
|
||||
|
||||
BOOST_CHECK_THROW( u = env.p.get_uri(env.req), websocketpp::uri_exception );
|
||||
BOOST_CHECK( !env.p.get_uri(env.req)->get_valid() );
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( extract_subprotocols ) {
|
||||
|
||||
+11
-24
@@ -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:
|
||||
@@ -82,25 +82,20 @@ BOOST_AUTO_TEST_CASE( exact_match ) {
|
||||
BOOST_CHECK(!ec);
|
||||
|
||||
websocketpp::uri_ptr u;
|
||||
bool exception = false;
|
||||
|
||||
try {
|
||||
u = p.get_uri(r);
|
||||
} catch (const websocketpp::uri_exception& e) {
|
||||
exception = true;
|
||||
}
|
||||
u = p.get_uri(r);
|
||||
|
||||
BOOST_CHECK(exception == false);
|
||||
BOOST_CHECK(u->get_secure() == false);
|
||||
BOOST_CHECK(u->get_host() == "www.example.com");
|
||||
BOOST_CHECK(u->get_resource() == "/");
|
||||
BOOST_CHECK(u->get_port() == websocketpp::uri_default_port);
|
||||
BOOST_CHECK(u->get_valid());
|
||||
BOOST_CHECK(!u->get_secure());
|
||||
BOOST_CHECK_EQUAL(u->get_host(), "www.example.com");
|
||||
BOOST_CHECK_EQUAL(u->get_resource(), "/");
|
||||
BOOST_CHECK_EQUAL(u->get_port(), websocketpp::uri_default_port);
|
||||
|
||||
p.process_handshake(r,"",response);
|
||||
|
||||
BOOST_CHECK(response.get_header("Connection") == "upgrade");
|
||||
BOOST_CHECK(response.get_header("Upgrade") == "websocket");
|
||||
BOOST_CHECK(response.get_header("Sec-WebSocket-Accept") == "s3pPLMBiTxaQ9kYGzzhZRbK+xOo=");
|
||||
BOOST_CHECK_EQUAL(response.get_header("Connection"), "upgrade");
|
||||
BOOST_CHECK_EQUAL(response.get_header("Upgrade"), "websocket");
|
||||
BOOST_CHECK_EQUAL(response.get_header("Sec-WebSocket-Accept"), "s3pPLMBiTxaQ9kYGzzhZRbK+xOo=");
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( non_get_method ) {
|
||||
@@ -181,8 +176,6 @@ BOOST_AUTO_TEST_CASE( bad_host ) {
|
||||
stub_config::con_msg_manager_type::ptr msg_manager;
|
||||
stub_config::rng_type rng;
|
||||
websocketpp::processor::hybi07<stub_config> p(false,true,msg_manager,rng);
|
||||
websocketpp::uri_ptr u;
|
||||
bool exception = false;
|
||||
websocketpp::lib::error_code ec;
|
||||
|
||||
std::string handshake = "GET / HTTP/1.1\r\nHost: www.example.com:70000\r\nConnection: upgrade\r\nUpgrade: websocket\r\nSec-WebSocket-Version: 7\r\nSec-WebSocket-Key: foo\r\n\r\n";
|
||||
@@ -194,11 +187,5 @@ BOOST_AUTO_TEST_CASE( bad_host ) {
|
||||
ec = p.validate_handshake(r);
|
||||
BOOST_CHECK( !ec );
|
||||
|
||||
try {
|
||||
u = p.get_uri(r);
|
||||
} catch (const websocketpp::uri_exception& e) {
|
||||
exception = true;
|
||||
}
|
||||
|
||||
BOOST_CHECK(exception == true);
|
||||
BOOST_CHECK( !p.get_uri(r)->get_valid() );
|
||||
}
|
||||
|
||||
@@ -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:
|
||||
@@ -82,15 +82,10 @@ BOOST_AUTO_TEST_CASE( exact_match ) {
|
||||
BOOST_CHECK(!ec);
|
||||
|
||||
websocketpp::uri_ptr u;
|
||||
bool exception = false;
|
||||
|
||||
try {
|
||||
u = p.get_uri(r);
|
||||
} catch (const websocketpp::uri_exception& e) {
|
||||
exception = true;
|
||||
}
|
||||
u = p.get_uri(r);
|
||||
|
||||
BOOST_CHECK(exception == false);
|
||||
BOOST_CHECK(u->get_valid() == true);
|
||||
BOOST_CHECK(u->get_secure() == false);
|
||||
BOOST_CHECK(u->get_host() == "www.example.com");
|
||||
BOOST_CHECK(u->get_resource() == "/");
|
||||
@@ -182,7 +177,6 @@ BOOST_AUTO_TEST_CASE( bad_host ) {
|
||||
stub_config::rng_type rng;
|
||||
websocketpp::processor::hybi08<stub_config> p(false,true,msg_manager,rng);
|
||||
websocketpp::uri_ptr u;
|
||||
bool exception = false;
|
||||
websocketpp::lib::error_code ec;
|
||||
|
||||
std::string handshake = "GET / HTTP/1.1\r\nHost: www.example.com:70000\r\nConnection: upgrade\r\nUpgrade: websocket\r\nSec-WebSocket-Version: 8\r\nSec-WebSocket-Key: foo\r\n\r\n";
|
||||
@@ -194,12 +188,8 @@ BOOST_AUTO_TEST_CASE( bad_host ) {
|
||||
ec = p.validate_handshake(r);
|
||||
BOOST_CHECK( !ec );
|
||||
|
||||
try {
|
||||
u = p.get_uri(r);
|
||||
} catch (const websocketpp::uri_exception& e) {
|
||||
exception = true;
|
||||
}
|
||||
u = p.get_uri(r);
|
||||
|
||||
BOOST_CHECK(exception == true);
|
||||
BOOST_CHECK( !u->get_valid() );
|
||||
}
|
||||
|
||||
|
||||
@@ -37,7 +37,7 @@
|
||||
#include <websocketpp/http/response.hpp>
|
||||
#include <websocketpp/message_buffer/message.hpp>
|
||||
#include <websocketpp/message_buffer/alloc.hpp>
|
||||
#include <websocketpp/random/none.hpp>
|
||||
#include <websocketpp/random/none.hpp>
|
||||
|
||||
#include <websocketpp/extensions/permessage_deflate/disabled.hpp>
|
||||
#include <websocketpp/extensions/permessage_deflate/enabled.hpp>
|
||||
@@ -200,7 +200,7 @@ BOOST_AUTO_TEST_CASE( bad_host ) {
|
||||
BOOST_CHECK( websocketpp::processor::is_websocket_handshake(env.req) );
|
||||
BOOST_CHECK_EQUAL( websocketpp::processor::get_websocket_version(env.req), env.p.get_version() );
|
||||
BOOST_CHECK( !env.p.validate_handshake(env.req) );
|
||||
BOOST_CHECK_THROW( env.p.get_uri(env.req), websocketpp::uri_exception );
|
||||
BOOST_CHECK( !env.p.get_uri(env.req)->get_valid() );
|
||||
}
|
||||
|
||||
// FRAME TESTS TO DO
|
||||
@@ -646,17 +646,16 @@ BOOST_AUTO_TEST_CASE( extract_subprotocols_invalid) {
|
||||
BOOST_CHECK_EQUAL( subps.size(), 0 );
|
||||
}
|
||||
|
||||
/*BOOST_AUTO_TEST_CASE( extension_negotiation_permessage_deflate ) {
|
||||
BOOST_AUTO_TEST_CASE( extension_negotiation_permessage_deflate ) {
|
||||
processor_setup_ext env(true);
|
||||
|
||||
env.req.replace_header("Sec-WebSocket-Extensions","permessage-deflate; foo; bar=\"x x\"");
|
||||
env.req.replace_header("Sec-WebSocket-Extensions",
|
||||
"permessage-deflate; c2s_max_window_bits");
|
||||
|
||||
std::pair<websocketpp::lib::error_code,std::string> neg_results;
|
||||
neg_results = env.p.negotiate_extensions(env.req);
|
||||
|
||||
std::cout << neg_results.first.message() << neg_results.second << std::endl;
|
||||
|
||||
BOOST_CHECK( !neg_results.first );
|
||||
BOOST_CHECK_EQUAL( neg_results.second, "permessage-deflate" );
|
||||
}*/
|
||||
}
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ Import('polyfill_libs')
|
||||
env = env.Clone ()
|
||||
env_cpp11 = env_cpp11.Clone ()
|
||||
|
||||
BOOST_LIBS = boostlibs(['unit_test_framework','system','regex','random'],env) + [platform_libs]
|
||||
BOOST_LIBS = boostlibs(['unit_test_framework','system','random'],env) + [platform_libs]
|
||||
|
||||
objs = env.Object('client_boost.o', ["client.cpp"], LIBS = BOOST_LIBS)
|
||||
objs += env.Object('server_boost.o', ["server.cpp"], 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','regex','random'],env) + [platform_libs] + [tls_libs]
|
||||
BOOST_LIBS = boostlibs(['unit_test_framework','system','thread','random'],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','regex'],env) + [platform_libs] + [tls_libs]
|
||||
BOOST_LIBS = boostlibs(['unit_test_framework','system','thread'],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)
|
||||
|
||||
@@ -146,6 +146,7 @@ struct mock_endpoint : public websocketpp::transport::asio::endpoint<config> {
|
||||
m_con.reset(new mock_con(false,alog,elog));
|
||||
websocketpp::uri_ptr uri(new websocketpp::uri(u));
|
||||
|
||||
BOOST_CHECK( uri->get_valid() );
|
||||
BOOST_CHECK_EQUAL( base::init(m_con), websocketpp::lib::error_code() );
|
||||
|
||||
base::async_connect(
|
||||
@@ -183,4 +184,4 @@ BOOST_AUTO_TEST_CASE( tls_handshake_timeout ) {
|
||||
endpoint.set_tls_init_handler(&on_tls_init);
|
||||
endpoint.connect("wss://localhost:9005");
|
||||
endpoint.run();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -84,6 +84,12 @@ using websocketpp::lib::placeholders::_1;
|
||||
using websocketpp::lib::placeholders::_2;
|
||||
using websocketpp::lib::bind;
|
||||
|
||||
template <typename T>
|
||||
void close_after_timeout(T & e, websocketpp::connection_hdl hdl, long timeout) {
|
||||
sleep(timeout);
|
||||
e.close(hdl,websocketpp::close::status::normal,"");
|
||||
}
|
||||
|
||||
void run_server(server * s, int port, bool log = false) {
|
||||
if (log) {
|
||||
s->set_access_channels(websocketpp::log::alevel::all);
|
||||
@@ -118,6 +124,34 @@ void run_client(client & c, std::string uri, bool log = false) {
|
||||
c.run();
|
||||
}
|
||||
|
||||
void run_time_limited_client(client & c, std::string uri, long timeout,
|
||||
bool log)
|
||||
{
|
||||
if (log) {
|
||||
c.set_access_channels(websocketpp::log::alevel::all);
|
||||
c.set_error_channels(websocketpp::log::elevel::all);
|
||||
} else {
|
||||
c.clear_access_channels(websocketpp::log::alevel::all);
|
||||
c.clear_error_channels(websocketpp::log::elevel::all);
|
||||
}
|
||||
c.init_asio();
|
||||
|
||||
websocketpp::lib::error_code ec;
|
||||
client::connection_ptr con = c.get_connection(uri,ec);
|
||||
BOOST_CHECK( !ec );
|
||||
c.connect(con);
|
||||
|
||||
websocketpp::lib::thread tthread(websocketpp::lib::bind(
|
||||
&close_after_timeout<client>,
|
||||
websocketpp::lib::ref(c),
|
||||
con->get_handle(),
|
||||
timeout
|
||||
));
|
||||
tthread.detach();
|
||||
|
||||
c.run();
|
||||
}
|
||||
|
||||
void run_dummy_server(int port) {
|
||||
using boost::asio::ip::tcp;
|
||||
|
||||
@@ -199,6 +233,16 @@ void fail_on_pong(websocketpp::connection_hdl hdl, std::string payload) {
|
||||
BOOST_FAIL( "expected no pong handler" );
|
||||
}
|
||||
|
||||
void fail_on_pong_timeout(websocketpp::connection_hdl hdl, std::string payload) {
|
||||
BOOST_FAIL( "expected no pong timeout" );
|
||||
}
|
||||
|
||||
void req_pong(std::string expected_payload, websocketpp::connection_hdl hdl,
|
||||
std::string payload)
|
||||
{
|
||||
BOOST_CHECK_EQUAL( expected_payload, payload );
|
||||
}
|
||||
|
||||
void fail_on_open(websocketpp::connection_hdl hdl) {
|
||||
BOOST_FAIL( "expected no open handler" );
|
||||
}
|
||||
@@ -248,13 +292,37 @@ void run_test_timer(long value) {
|
||||
BOOST_FAIL( "Test timed out" );
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( pong_no_timeout ) {
|
||||
server s;
|
||||
client c;
|
||||
|
||||
s.set_close_handler(bind(&stop_on_close,&s,::_1));
|
||||
|
||||
// send a ping when the connection is open
|
||||
c.set_open_handler(bind(&ping_on_open<client>,&c,"foo",::_1));
|
||||
// require that a pong with matching payload is received
|
||||
c.set_pong_handler(bind(&req_pong,"foo",::_1,::_2));
|
||||
// require that a pong timeout is NOT received
|
||||
c.set_pong_timeout_handler(bind(&fail_on_pong_timeout,::_1,::_2));
|
||||
|
||||
websocketpp::lib::thread sthread(websocketpp::lib::bind(&run_server,&s,9005,false));
|
||||
|
||||
// Run a client that closes the connection after 1 seconds
|
||||
run_time_limited_client(c, "http://localhost:9005", 1, false);
|
||||
|
||||
sthread.join();
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( pong_timeout ) {
|
||||
server s;
|
||||
client c;
|
||||
|
||||
s.set_ping_handler(on_ping);
|
||||
s.set_close_handler(bind(&stop_on_close,&s,::_1));
|
||||
|
||||
|
||||
c.set_fail_handler(bind(&check_ec<client>,&c,
|
||||
websocketpp::lib::error_code(),::_1));
|
||||
|
||||
c.set_pong_handler(bind(&fail_on_pong,::_1,::_2));
|
||||
c.set_open_handler(bind(&ping_on_open<client>,&c,"foo",::_1));
|
||||
c.set_pong_timeout_handler(bind(&req_pong_timeout<client>,&c,"foo",::_1,::_2));
|
||||
|
||||
@@ -10,23 +10,27 @@ Import('polyfill_libs')
|
||||
env = env.Clone ()
|
||||
env_cpp11 = env_cpp11.Clone ()
|
||||
|
||||
BOOST_LIBS = boostlibs(['unit_test_framework','regex','system'],env) + [platform_libs]
|
||||
BOOST_LIBS = boostlibs(['unit_test_framework','system'],env) + [platform_libs]
|
||||
|
||||
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)
|
||||
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)
|
||||
|
||||
if env_cpp11.has_key('WSPP_CPP11_ENABLED'):
|
||||
BOOST_LIBS_CPP11 = boostlibs(['unit_test_framework'],env_cpp11) + [platform_libs] + [polyfill_libs]
|
||||
objs += env_cpp11.Object('utilities_stl.o', ["utilities.cpp"], LIBS = BOOST_LIBS_CPP11)
|
||||
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)
|
||||
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)
|
||||
|
||||
Return('prgs')
|
||||
|
||||
+73
-2
@@ -240,7 +240,7 @@ BOOST_AUTO_TEST_CASE( prepare_masking_key ) {
|
||||
|
||||
if (sizeof(size_t) == 8) {
|
||||
BOOST_CHECK(
|
||||
frame::prepare_masking_key(key) == lib::net::htonll(0x1234567812345678)
|
||||
frame::prepare_masking_key(key) == lib::net::htonll(0x1234567812345678LL)
|
||||
);
|
||||
} else {
|
||||
BOOST_CHECK( frame::prepare_masking_key(key) == htonl(0x12345678) );
|
||||
@@ -255,7 +255,7 @@ BOOST_AUTO_TEST_CASE( prepare_masking_key2 ) {
|
||||
// One call
|
||||
if (sizeof(size_t) == 8) {
|
||||
BOOST_CHECK(
|
||||
frame::prepare_masking_key(key) == lib::net::htonll(0xD5FB70EED5FB70EE)
|
||||
frame::prepare_masking_key(key) == lib::net::htonll(0xD5FB70EED5FB70EELL)
|
||||
);
|
||||
} else {
|
||||
BOOST_CHECK( frame::prepare_masking_key(key) == htonl(0xD5FB70EE) );
|
||||
@@ -410,6 +410,43 @@ BOOST_AUTO_TEST_CASE( continuous_word_mask ) {
|
||||
BOOST_CHECK_EQUAL( pkey_temp, frame::circshift_prepared_key(pkey,3) );
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( continuous_byte_mask ) {
|
||||
uint8_t input[16];
|
||||
uint8_t output[16];
|
||||
|
||||
uint8_t masked[16] = {0x00, 0x01, 0x02, 0x03,
|
||||
0x00, 0x01, 0x02, 0x03,
|
||||
0x00, 0x01, 0x02, 0x03,
|
||||
0x00, 0x01, 0x02, 0x00};
|
||||
|
||||
frame::masking_key_type key;
|
||||
key.c[0] = 0x00;
|
||||
key.c[1] = 0x01;
|
||||
key.c[2] = 0x02;
|
||||
key.c[3] = 0x03;
|
||||
|
||||
// One call
|
||||
size_t pkey,pkey_temp;
|
||||
pkey = frame::prepare_masking_key(key);
|
||||
std::fill_n(input,16,0x00);
|
||||
std::fill_n(output,16,0x00);
|
||||
frame::byte_mask_circ(input,output,15,pkey);
|
||||
BOOST_CHECK( std::equal(output,output+16,masked) );
|
||||
|
||||
// calls not split on word boundaries
|
||||
pkey = frame::prepare_masking_key(key);
|
||||
std::fill_n(input,16,0x00);
|
||||
std::fill_n(output,16,0x00);
|
||||
|
||||
pkey_temp = frame::byte_mask_circ(input,output,7,pkey);
|
||||
BOOST_CHECK( std::equal(output,output+7,masked) );
|
||||
BOOST_CHECK( pkey_temp == frame::circshift_prepared_key(pkey,3) );
|
||||
|
||||
pkey_temp = frame::byte_mask_circ(input+7,output+7,8,pkey_temp);
|
||||
BOOST_CHECK( std::equal(output,output+16,masked) );
|
||||
BOOST_CHECK_EQUAL( pkey_temp, frame::circshift_prepared_key(pkey,3) );
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( continuous_word_mask_inplace ) {
|
||||
uint8_t buffer[16];
|
||||
|
||||
@@ -444,6 +481,40 @@ BOOST_AUTO_TEST_CASE( continuous_word_mask_inplace ) {
|
||||
BOOST_CHECK_EQUAL( pkey_temp, frame::circshift_prepared_key(pkey,3) );
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( continuous_byte_mask_inplace ) {
|
||||
uint8_t buffer[16];
|
||||
|
||||
uint8_t masked[16] = {0x00, 0x01, 0x02, 0x03,
|
||||
0x00, 0x01, 0x02, 0x03,
|
||||
0x00, 0x01, 0x02, 0x03,
|
||||
0x00, 0x01, 0x02, 0x00};
|
||||
|
||||
frame::masking_key_type key;
|
||||
key.c[0] = 0x00;
|
||||
key.c[1] = 0x01;
|
||||
key.c[2] = 0x02;
|
||||
key.c[3] = 0x03;
|
||||
|
||||
// One call
|
||||
size_t pkey,pkey_temp;
|
||||
pkey = frame::prepare_masking_key(key);
|
||||
std::fill_n(buffer,16,0x00);
|
||||
frame::byte_mask_circ(buffer,15,pkey);
|
||||
BOOST_CHECK( std::equal(buffer,buffer+16,masked) );
|
||||
|
||||
// calls not split on word boundaries
|
||||
pkey = frame::prepare_masking_key(key);
|
||||
std::fill_n(buffer,16,0x00);
|
||||
|
||||
pkey_temp = frame::byte_mask_circ(buffer,7,pkey);
|
||||
BOOST_CHECK( std::equal(buffer,buffer+7,masked) );
|
||||
BOOST_CHECK_EQUAL( pkey_temp, frame::circshift_prepared_key(pkey,3) );
|
||||
|
||||
pkey_temp = frame::byte_mask_circ(buffer+7,8,pkey_temp);
|
||||
BOOST_CHECK( std::equal(buffer,buffer+16,masked) );
|
||||
BOOST_CHECK_EQUAL( pkey_temp, frame::circshift_prepared_key(pkey,3) );
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( continuous_word_mask2 ) {
|
||||
uint8_t buffer[12] = {0xA6, 0x15, 0x97, 0xB9,
|
||||
0x81, 0x50, 0xAC, 0xBA,
|
||||
|
||||
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* Copyright (c) 2011, 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 sha1
|
||||
#include <boost/test/unit_test.hpp>
|
||||
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
#include <websocketpp/sha1/sha1.hpp>
|
||||
#include <websocketpp/utilities.hpp>
|
||||
|
||||
BOOST_AUTO_TEST_SUITE ( sha1 )
|
||||
|
||||
BOOST_AUTO_TEST_CASE( sha1_test_a ) {
|
||||
websocketpp::sha1 sha;
|
||||
uint32_t digest[5];
|
||||
|
||||
sha << "abc";
|
||||
BOOST_CHECK(sha.get_raw_digest(digest));
|
||||
|
||||
BOOST_CHECK_EQUAL( digest[0], 0xa9993e36 );
|
||||
BOOST_CHECK_EQUAL( digest[1], 0x4706816a );
|
||||
BOOST_CHECK_EQUAL( digest[2], 0xba3e2571 );
|
||||
BOOST_CHECK_EQUAL( digest[3], 0x7850c26c );
|
||||
BOOST_CHECK_EQUAL( digest[4], 0x9cd0d89d );
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( sha1_test_b ) {
|
||||
websocketpp::sha1 sha;
|
||||
uint32_t digest[5];
|
||||
|
||||
sha << "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq";
|
||||
BOOST_CHECK(sha.get_raw_digest(digest));
|
||||
|
||||
BOOST_CHECK_EQUAL( digest[0], 0x84983e44 );
|
||||
BOOST_CHECK_EQUAL( digest[1], 0x1c3bd26e );
|
||||
BOOST_CHECK_EQUAL( digest[2], 0xbaae4aa1 );
|
||||
BOOST_CHECK_EQUAL( digest[3], 0xf95129e5 );
|
||||
BOOST_CHECK_EQUAL( digest[4], 0xe54670f1 );
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( sha1_test_c ) {
|
||||
websocketpp::sha1 sha;
|
||||
uint32_t digest[5];
|
||||
|
||||
for (int i = 1; i <= 1000000; i++) {
|
||||
sha.input('a');
|
||||
}
|
||||
|
||||
BOOST_CHECK(sha.get_raw_digest(digest));
|
||||
|
||||
BOOST_CHECK_EQUAL( digest[0], 0x34aa973c );
|
||||
BOOST_CHECK_EQUAL( digest[1], 0xd4c4daa4 );
|
||||
BOOST_CHECK_EQUAL( digest[2], 0xf61eeb2b );
|
||||
BOOST_CHECK_EQUAL( digest[3], 0xdbad2731 );
|
||||
BOOST_CHECK_EQUAL( digest[4], 0x6534016f );
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
||||
+120
-213
@@ -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:
|
||||
@@ -35,296 +35,203 @@
|
||||
|
||||
// Test a regular valid ws URI
|
||||
BOOST_AUTO_TEST_CASE( uri_valid ) {
|
||||
bool exception = false;
|
||||
try {
|
||||
websocketpp::uri uri("ws://localhost:9000/chat");
|
||||
|
||||
BOOST_CHECK( uri.get_secure() == false );
|
||||
BOOST_CHECK( uri.get_host() == "localhost");
|
||||
BOOST_CHECK( uri.get_port() == 9000 );
|
||||
BOOST_CHECK( uri.get_resource() == "/chat" );
|
||||
} catch (websocketpp::uri_exception&) {
|
||||
exception = true;
|
||||
}
|
||||
|
||||
BOOST_CHECK( exception == false);
|
||||
websocketpp::uri uri("ws://localhost:9000/chat");
|
||||
|
||||
BOOST_CHECK( uri.get_valid() );
|
||||
BOOST_CHECK( !uri.get_secure() );
|
||||
BOOST_CHECK_EQUAL( uri.get_scheme(), "ws");
|
||||
BOOST_CHECK_EQUAL( uri.get_host(), "localhost");
|
||||
BOOST_CHECK_EQUAL( uri.get_port(), 9000 );
|
||||
BOOST_CHECK_EQUAL( uri.get_resource(), "/chat" );
|
||||
}
|
||||
|
||||
// Test a regular valid ws URI
|
||||
BOOST_AUTO_TEST_CASE( uri_valid_no_port_unsecure ) {
|
||||
bool exception = false;
|
||||
try {
|
||||
websocketpp::uri uri("ws://localhost/chat");
|
||||
|
||||
BOOST_CHECK( uri.get_secure() == false );
|
||||
BOOST_CHECK( uri.get_host() == "localhost");
|
||||
BOOST_CHECK( uri.get_port() == 80 );
|
||||
BOOST_CHECK( uri.get_resource() == "/chat" );
|
||||
} catch (websocketpp::uri_exception&) {
|
||||
exception = true;
|
||||
}
|
||||
|
||||
BOOST_CHECK( exception == false);
|
||||
websocketpp::uri uri("ws://localhost/chat");
|
||||
|
||||
BOOST_CHECK( uri.get_valid() );
|
||||
BOOST_CHECK( !uri.get_secure() );
|
||||
BOOST_CHECK_EQUAL( uri.get_scheme(), "ws");
|
||||
BOOST_CHECK_EQUAL( uri.get_host(), "localhost");
|
||||
BOOST_CHECK_EQUAL( uri.get_port(), 80 );
|
||||
BOOST_CHECK_EQUAL( uri.get_resource(), "/chat" );
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Valid URI with no port (secure)
|
||||
BOOST_AUTO_TEST_CASE( uri_valid_no_port_secure ) {
|
||||
bool exception = false;
|
||||
try {
|
||||
websocketpp::uri uri("wss://localhost/chat");
|
||||
|
||||
BOOST_CHECK( uri.get_secure() == true );
|
||||
BOOST_CHECK( uri.get_host() == "localhost");
|
||||
BOOST_CHECK( uri.get_port() == 443 );
|
||||
BOOST_CHECK( uri.get_resource() == "/chat" );
|
||||
} catch (websocketpp::uri_exception& e) {
|
||||
exception = true;
|
||||
std::cout << e.what() << std::endl;
|
||||
}
|
||||
|
||||
BOOST_CHECK( exception == false);
|
||||
websocketpp::uri uri("wss://localhost/chat");
|
||||
|
||||
BOOST_CHECK( uri.get_valid() );
|
||||
BOOST_CHECK( uri.get_secure() );
|
||||
BOOST_CHECK_EQUAL( uri.get_scheme(), "wss");
|
||||
BOOST_CHECK_EQUAL( uri.get_host(), "localhost");
|
||||
BOOST_CHECK_EQUAL( uri.get_port(), 443 );
|
||||
BOOST_CHECK_EQUAL( uri.get_resource(), "/chat" );
|
||||
}
|
||||
|
||||
// Valid URI with no resource
|
||||
BOOST_AUTO_TEST_CASE( uri_valid_no_resource ) {
|
||||
bool exception = false;
|
||||
try {
|
||||
websocketpp::uri uri("wss://localhost:9000");
|
||||
|
||||
BOOST_CHECK( uri.get_secure() == true );
|
||||
BOOST_CHECK( uri.get_host() == "localhost");
|
||||
BOOST_CHECK( uri.get_port() == 9000 );
|
||||
BOOST_CHECK( uri.get_resource() == "/" );
|
||||
} catch (websocketpp::uri_exception&) {
|
||||
exception = true;
|
||||
}
|
||||
|
||||
BOOST_CHECK( exception == false);
|
||||
websocketpp::uri uri("wss://localhost:9000");
|
||||
|
||||
BOOST_CHECK( uri.get_valid() );
|
||||
BOOST_CHECK( uri.get_secure() );
|
||||
BOOST_CHECK_EQUAL( uri.get_scheme(), "wss");
|
||||
BOOST_CHECK_EQUAL( uri.get_host(), "localhost");
|
||||
BOOST_CHECK_EQUAL( uri.get_port(), 9000 );
|
||||
BOOST_CHECK_EQUAL( uri.get_resource(), "/" );
|
||||
}
|
||||
|
||||
// Valid URI IPv6 Literal
|
||||
BOOST_AUTO_TEST_CASE( uri_valid_ipv6_literal ) {
|
||||
bool exception = false;
|
||||
try {
|
||||
websocketpp::uri uri("wss://[::1]:9000/chat");
|
||||
|
||||
BOOST_CHECK( uri.get_secure() == true );
|
||||
BOOST_CHECK( uri.get_host() == "::1");
|
||||
BOOST_CHECK( uri.get_port() == 9000 );
|
||||
BOOST_CHECK( uri.get_resource() == "/chat" );
|
||||
} catch (websocketpp::uri_exception&) {
|
||||
exception = true;
|
||||
}
|
||||
|
||||
BOOST_CHECK( exception == false);
|
||||
websocketpp::uri uri("wss://[::1]:9000/chat");
|
||||
|
||||
BOOST_CHECK( uri.get_valid() );
|
||||
BOOST_CHECK( uri.get_secure() );
|
||||
BOOST_CHECK_EQUAL( uri.get_scheme(), "wss");
|
||||
BOOST_CHECK_EQUAL( uri.get_host(), "::1");
|
||||
BOOST_CHECK_EQUAL( uri.get_port(), 9000 );
|
||||
BOOST_CHECK_EQUAL( uri.get_resource(), "/chat" );
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Valid URI with more complicated host
|
||||
BOOST_AUTO_TEST_CASE( uri_valid_2 ) {
|
||||
bool exception = false;
|
||||
try {
|
||||
websocketpp::uri uri("wss://thor-websocket.zaphoyd.net:88/");
|
||||
|
||||
BOOST_CHECK( uri.get_secure() == true );
|
||||
BOOST_CHECK( uri.get_host() == "thor-websocket.zaphoyd.net");
|
||||
BOOST_CHECK( uri.get_port() == 88 );
|
||||
BOOST_CHECK( uri.get_resource() == "/" );
|
||||
} catch (websocketpp::uri_exception&) {
|
||||
exception = true;
|
||||
}
|
||||
|
||||
BOOST_CHECK( exception == false);
|
||||
websocketpp::uri uri("wss://thor-websocket.zaphoyd.net:88/");
|
||||
|
||||
BOOST_CHECK( uri.get_valid() );
|
||||
BOOST_CHECK( uri.get_secure() );
|
||||
BOOST_CHECK_EQUAL( uri.get_scheme(), "wss");
|
||||
BOOST_CHECK_EQUAL( uri.get_host(), "thor-websocket.zaphoyd.net");
|
||||
BOOST_CHECK_EQUAL( uri.get_port(), 88 );
|
||||
BOOST_CHECK_EQUAL( uri.get_resource(), "/" );
|
||||
}
|
||||
|
||||
|
||||
// Invalid URI (port too long)
|
||||
BOOST_AUTO_TEST_CASE( uri_invalid_long_port ) {
|
||||
bool exception = false;
|
||||
try {
|
||||
websocketpp::uri uri("wss://localhost:900000/chat");
|
||||
} catch (websocketpp::uri_exception&) {
|
||||
exception = true;
|
||||
}
|
||||
|
||||
BOOST_CHECK( exception == true);
|
||||
websocketpp::uri uri("wss://localhost:900000/chat");
|
||||
|
||||
BOOST_CHECK( !uri.get_valid() );
|
||||
}
|
||||
|
||||
// Invalid URI (bogus scheme method)
|
||||
BOOST_AUTO_TEST_CASE( uri_invalid_scheme ) {
|
||||
bool exception = false;
|
||||
try {
|
||||
websocketpp::uri uri("foo://localhost:9000/chat");
|
||||
} catch (websocketpp::uri_exception&) {
|
||||
exception = true;
|
||||
}
|
||||
websocketpp::uri uri("foo://localhost:9000/chat");
|
||||
|
||||
BOOST_CHECK( exception == true);
|
||||
BOOST_CHECK( !uri.get_valid() );
|
||||
}
|
||||
|
||||
// Valid URI (http method)
|
||||
BOOST_AUTO_TEST_CASE( uri_http_scheme ) {
|
||||
bool exception = false;
|
||||
try {
|
||||
websocketpp::uri uri("http://localhost:9000/chat");
|
||||
|
||||
BOOST_CHECK( uri.get_secure() == false );
|
||||
BOOST_CHECK( uri.get_host() == "localhost");
|
||||
BOOST_CHECK( uri.get_port() == 9000 );
|
||||
BOOST_CHECK( uri.get_resource() == "/chat" );
|
||||
} catch (websocketpp::uri_exception&) {
|
||||
exception = true;
|
||||
}
|
||||
|
||||
BOOST_CHECK( exception == false);
|
||||
websocketpp::uri uri("http://localhost:9000/chat");
|
||||
|
||||
BOOST_CHECK( uri.get_valid() );
|
||||
BOOST_CHECK( !uri.get_secure() );
|
||||
BOOST_CHECK_EQUAL( uri.get_scheme(), "http");
|
||||
BOOST_CHECK_EQUAL( uri.get_host(), "localhost");
|
||||
BOOST_CHECK_EQUAL( uri.get_port(), 9000 );
|
||||
BOOST_CHECK_EQUAL( uri.get_resource(), "/chat" );
|
||||
}
|
||||
|
||||
// Valid URI IPv4 literal
|
||||
BOOST_AUTO_TEST_CASE( uri_valid_ipv4_literal ) {
|
||||
bool exception = false;
|
||||
try {
|
||||
websocketpp::uri uri("wss://127.0.0.1:9000/chat");
|
||||
|
||||
BOOST_CHECK( uri.get_secure() == true );
|
||||
BOOST_CHECK( uri.get_host() == "127.0.0.1");
|
||||
BOOST_CHECK( uri.get_port() == 9000 );
|
||||
BOOST_CHECK( uri.get_resource() == "/chat" );
|
||||
} catch (websocketpp::uri_exception&) {
|
||||
exception = true;
|
||||
}
|
||||
|
||||
BOOST_CHECK( exception == false);
|
||||
websocketpp::uri uri("wss://127.0.0.1:9000/chat");
|
||||
|
||||
BOOST_CHECK( uri.get_valid() );
|
||||
BOOST_CHECK( uri.get_secure() );
|
||||
BOOST_CHECK_EQUAL( uri.get_scheme(), "wss");
|
||||
BOOST_CHECK_EQUAL( uri.get_host(), "127.0.0.1");
|
||||
BOOST_CHECK_EQUAL( uri.get_port(), 9000 );
|
||||
BOOST_CHECK_EQUAL( uri.get_resource(), "/chat" );
|
||||
}
|
||||
|
||||
// Valid URI complicated resource path
|
||||
BOOST_AUTO_TEST_CASE( uri_valid_3 ) {
|
||||
bool exception = false;
|
||||
try {
|
||||
websocketpp::uri uri("wss://localhost:9000/chat/foo/bar");
|
||||
|
||||
BOOST_CHECK( uri.get_secure() == true );
|
||||
BOOST_CHECK( uri.get_host() == "localhost");
|
||||
BOOST_CHECK( uri.get_port() == 9000 );
|
||||
BOOST_CHECK( uri.get_resource() == "/chat/foo/bar" );
|
||||
} catch (websocketpp::uri_exception&) {
|
||||
exception = true;
|
||||
}
|
||||
|
||||
BOOST_CHECK( exception == false);
|
||||
websocketpp::uri uri("wss://localhost:9000/chat/foo/bar");
|
||||
|
||||
BOOST_CHECK( uri.get_valid() );
|
||||
BOOST_CHECK( uri.get_secure() );
|
||||
BOOST_CHECK_EQUAL( uri.get_scheme(), "wss");
|
||||
BOOST_CHECK_EQUAL( uri.get_host(), "localhost");
|
||||
BOOST_CHECK_EQUAL( uri.get_port(), 9000 );
|
||||
BOOST_CHECK_EQUAL( uri.get_resource(), "/chat/foo/bar" );
|
||||
}
|
||||
|
||||
// Invalid URI broken method separator
|
||||
BOOST_AUTO_TEST_CASE( uri_invalid_method_separator ) {
|
||||
bool exception = false;
|
||||
try {
|
||||
websocketpp::uri uri("wss:/localhost:9000/chat");
|
||||
} catch (websocketpp::uri_exception&) {
|
||||
exception = true;
|
||||
}
|
||||
websocketpp::uri uri("wss:/localhost:9000/chat");
|
||||
|
||||
BOOST_CHECK( exception == true);
|
||||
BOOST_CHECK( !uri.get_valid() );
|
||||
}
|
||||
|
||||
// Invalid URI port > 65535
|
||||
BOOST_AUTO_TEST_CASE( uri_invalid_gt_16_bit_port ) {
|
||||
bool exception = false;
|
||||
try {
|
||||
websocketpp::uri uri("wss:/localhost:70000/chat");
|
||||
} catch (websocketpp::uri_exception&) {
|
||||
exception = true;
|
||||
}
|
||||
websocketpp::uri uri("wss:/localhost:70000/chat");
|
||||
|
||||
BOOST_CHECK( exception == true);
|
||||
BOOST_CHECK( !uri.get_valid() );
|
||||
}
|
||||
|
||||
// Invalid URI includes uri fragment
|
||||
BOOST_AUTO_TEST_CASE( uri_invalid_fragment ) {
|
||||
bool exception = false;
|
||||
try {
|
||||
websocketpp::uri uri("wss:/localhost:70000/chat#foo");
|
||||
} catch (websocketpp::uri_exception&) {
|
||||
exception = true;
|
||||
}
|
||||
websocketpp::uri uri("wss:/localhost:70000/chat#foo");
|
||||
|
||||
BOOST_CHECK( exception == true);
|
||||
BOOST_CHECK( !uri.get_valid() );
|
||||
}
|
||||
|
||||
// Invalid URI with no brackets around IPv6 literal
|
||||
BOOST_AUTO_TEST_CASE( uri_invalid_bad_v6_literal_1 ) {
|
||||
bool exception = false;
|
||||
try {
|
||||
websocketpp::uri uri("wss://::1/chat");
|
||||
} catch (websocketpp::uri_exception&) {
|
||||
exception = true;
|
||||
}
|
||||
|
||||
BOOST_CHECK( exception == true);
|
||||
websocketpp::uri uri("wss://::1/chat");
|
||||
|
||||
BOOST_CHECK( !uri.get_valid() );
|
||||
}
|
||||
|
||||
// Invalid URI with port and no brackets around IPv6 literal
|
||||
BOOST_AUTO_TEST_CASE( uri_invalid_bad_v6_literal_2 ) {
|
||||
bool exception = false;
|
||||
try {
|
||||
websocketpp::uri uri("wss://::1:2009/chat");
|
||||
} catch (websocketpp::uri_exception&) {
|
||||
exception = true;
|
||||
}
|
||||
|
||||
BOOST_CHECK( exception == true);
|
||||
websocketpp::uri uri("wss://::1:2009/chat");
|
||||
|
||||
BOOST_CHECK( !uri.get_valid() );
|
||||
}
|
||||
|
||||
// Valid URI complicated resource path with query
|
||||
BOOST_AUTO_TEST_CASE( uri_valid_4 ) {
|
||||
bool exception = false;
|
||||
try {
|
||||
websocketpp::uri uri("wss://localhost:9000/chat/foo/bar?foo=bar");
|
||||
|
||||
BOOST_CHECK( uri.get_secure() == true );
|
||||
BOOST_CHECK( uri.get_host() == "localhost");
|
||||
BOOST_CHECK( uri.get_port() == 9000 );
|
||||
BOOST_CHECK( uri.get_resource() == "/chat/foo/bar?foo=bar" );
|
||||
} catch (websocketpp::uri_exception&) {
|
||||
exception = true;
|
||||
}
|
||||
|
||||
BOOST_CHECK( exception == false);
|
||||
websocketpp::uri uri("wss://localhost:9000/chat/foo/bar?foo=bar");
|
||||
|
||||
BOOST_CHECK( uri.get_valid() );
|
||||
BOOST_CHECK( uri.get_secure() );
|
||||
BOOST_CHECK_EQUAL( uri.get_scheme(), "wss" );
|
||||
BOOST_CHECK_EQUAL( uri.get_host(), "localhost");
|
||||
BOOST_CHECK_EQUAL( uri.get_port(), 9000 );
|
||||
BOOST_CHECK_EQUAL( uri.get_resource(), "/chat/foo/bar?foo=bar" );
|
||||
}
|
||||
|
||||
// Valid URI with a mapped v4 ipv6 literal
|
||||
BOOST_AUTO_TEST_CASE( uri_valid_v4_mapped ) {
|
||||
bool exception = false;
|
||||
try {
|
||||
websocketpp::uri uri("wss://[0000:0000:0000:0000:0000:0000:192.168.1.1]:9000/");
|
||||
|
||||
BOOST_CHECK( uri.get_secure() == true );
|
||||
BOOST_CHECK( uri.get_host() == "0000:0000:0000:0000:0000:0000:192.168.1.1");
|
||||
BOOST_CHECK( uri.get_port() == 9000 );
|
||||
BOOST_CHECK( uri.get_resource() == "/" );
|
||||
} catch (websocketpp::uri_exception&) {
|
||||
exception = true;
|
||||
}
|
||||
websocketpp::uri uri("wss://[0000:0000:0000:0000:0000:0000:192.168.1.1]:9000/");
|
||||
|
||||
BOOST_CHECK( exception == false);
|
||||
BOOST_CHECK( uri.get_valid() );
|
||||
BOOST_CHECK( uri.get_secure() );
|
||||
BOOST_CHECK_EQUAL( uri.get_scheme(), "wss" );
|
||||
BOOST_CHECK_EQUAL( uri.get_host(), "0000:0000:0000:0000:0000:0000:192.168.1.1");
|
||||
BOOST_CHECK_EQUAL( uri.get_port(), 9000 );
|
||||
BOOST_CHECK_EQUAL( uri.get_resource(), "/" );
|
||||
}
|
||||
|
||||
// Valid URI with a v6 address with mixed case
|
||||
BOOST_AUTO_TEST_CASE( uri_valid_v6_mixed_case ) {
|
||||
bool exception = false;
|
||||
try {
|
||||
websocketpp::uri uri("wss://[::10aB]:9000/");
|
||||
|
||||
BOOST_CHECK( uri.get_secure() == true );
|
||||
BOOST_CHECK( uri.get_host() == "::10aB");
|
||||
BOOST_CHECK( uri.get_port() == 9000 );
|
||||
BOOST_CHECK( uri.get_resource() == "/" );
|
||||
} catch (websocketpp::uri_exception&) {
|
||||
exception = true;
|
||||
}
|
||||
websocketpp::uri uri("wss://[::10aB]:9000/");
|
||||
|
||||
BOOST_CHECK( exception == false);
|
||||
BOOST_CHECK( uri.get_valid() == true );
|
||||
BOOST_CHECK( uri.get_secure() == true );
|
||||
BOOST_CHECK_EQUAL( uri.get_scheme(), "wss" );
|
||||
BOOST_CHECK_EQUAL( uri.get_host(), "::10aB");
|
||||
BOOST_CHECK_EQUAL( uri.get_port(), 9000 );
|
||||
BOOST_CHECK_EQUAL( uri.get_resource(), "/" );
|
||||
}
|
||||
|
||||
// TODO: tests for the other two constructors
|
||||
// Invalid IPv6 literal
|
||||
/*BOOST_AUTO_TEST_CASE( uri_invalid_v6_nonhex ) {
|
||||
websocketpp::uri uri("wss://[g::1]:9000/");
|
||||
|
||||
BOOST_CHECK( uri.get_valid() == false );
|
||||
}*/
|
||||
|
||||
// TODO: tests for the other two constructors
|
||||
|
||||
@@ -56,6 +56,12 @@ BOOST_AUTO_TEST_CASE( substr_not_found ) {
|
||||
BOOST_CHECK(websocketpp::utility::ci_find_substr(haystack,needle) == haystack.end());
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( to_lower ) {
|
||||
std::string in = "AbCd";
|
||||
|
||||
BOOST_CHECK_EQUAL(websocketpp::utility::to_lower(in), "abcd");
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( string_replace_all ) {
|
||||
std::string source = "foo \"bar\" baz";
|
||||
std::string dest = "foo \\\"bar\\\" baz";
|
||||
|
||||
@@ -1,148 +0,0 @@
|
||||
/*
|
||||
* 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:
|
||||
* * 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_HPP
|
||||
#define WEBSOCKETPP_COMMON_HPP
|
||||
|
||||
// TODO/NOTE:
|
||||
// _WEBSOCKETPP_CPP11_MEMORY_ and _WEBSOCKETPP_CPP11_FUNCTIONAL_ presently
|
||||
// only work if either both or neither is defined. It might not make sense to
|
||||
// have separate options for them both.
|
||||
//
|
||||
|
||||
|
||||
/**
|
||||
* _WEBSOCKETPP_CPP11_STL_ enables the use of a C++11 STL. Doing this requires
|
||||
* that you link to a C++11 STL, that your copy of boost be linked to that same
|
||||
* STL, and that your compiler supports a minimum set of C++11 features.
|
||||
*
|
||||
* Required Features:
|
||||
* - noexcept
|
||||
*/
|
||||
|
||||
// Optional C++11 support features
|
||||
#ifndef __has_feature // Optional of course.
|
||||
#define __has_feature(x) 0 // Compatibility with non-clang compilers.
|
||||
#endif
|
||||
#ifndef __has_extension
|
||||
#define __has_extension __has_feature // Compatibility with pre-3.0 compilers.
|
||||
#endif
|
||||
|
||||
// Enable initializer lists on clang when available.
|
||||
#if __has_feature(cxx_generalized_initializers)
|
||||
#define _WEBSOCKETPP_INITIALIZER_LISTS_
|
||||
#endif
|
||||
|
||||
// Enable deleted functions when available.
|
||||
#if __has_feature(cxx_deleted_functions)
|
||||
#define _WEBSOCKETPP_DELETED_FUNCTIONS_
|
||||
#endif
|
||||
|
||||
// Enable rvalue references when available.
|
||||
#if __has_feature(cxx_rvalue_references)
|
||||
#define _WEBSOCKETPP_RVALUE_REFERENCES_
|
||||
#endif
|
||||
|
||||
// Use C++11 native Alias Templates instead of a hack.
|
||||
//#define _WEBSOCKETPP_CPP11_ALIAS_TEMPLATES_
|
||||
|
||||
#ifdef _WEBSOCKETPP_CPP11_
|
||||
#define _WEBSOCKETPP_DELETED_FUNCTIONS_
|
||||
#define _WEBSOCKETPP_RVALUE_REFERENCES_
|
||||
#endif
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace websocketpp {
|
||||
|
||||
// Size of the transport read buffer. Increasing may improve performance for
|
||||
// large reads. Higher values will increase memory usage linearly with
|
||||
// connection count.
|
||||
|
||||
const size_t DEFAULT_READ_THRESHOLD = 1; // 512 would be a more sane value
|
||||
|
||||
// Maximum size in bytes before rejecting an HTTP header as too big.
|
||||
// Is defined in websocketpp/http/constants.hpp
|
||||
|
||||
// Default user agent.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
namespace close {
|
||||
namespace status {
|
||||
enum value {
|
||||
INVALID_END = 999,
|
||||
NORMAL = 1000,
|
||||
GOING_AWAY = 1001,
|
||||
PROTOCOL_ERROR = 1002,
|
||||
UNSUPPORTED_DATA = 1003,
|
||||
RSV_ADHOC_1 = 1004,
|
||||
NO_STATUS = 1005,
|
||||
ABNORMAL_CLOSE = 1006,
|
||||
INVALID_PAYLOAD = 1007,
|
||||
POLICY_VIOLATION = 1008,
|
||||
MESSAGE_TOO_BIG = 1009,
|
||||
EXTENSION_REQUIRE = 1010,
|
||||
INTERNAL_ENDPOINT_ERROR = 1011,
|
||||
RSV_ADHOC_2 = 1012,
|
||||
RSV_ADHOC_3 = 1013,
|
||||
RSV_ADHOC_4 = 1014,
|
||||
TLS_HANDSHAKE = 1015,
|
||||
RSV_START = 1016,
|
||||
RSV_END = 2999,
|
||||
INVALID_START = 5000
|
||||
};
|
||||
|
||||
inline bool reserved(value s) {
|
||||
return ((s >= RSV_START && s <= RSV_END) || s == RSV_ADHOC_1
|
||||
|| s == RSV_ADHOC_2 || s == RSV_ADHOC_3 || s == RSV_ADHOC_4);
|
||||
}
|
||||
|
||||
// Codes invalid on the wire
|
||||
inline bool invalid(value s) {
|
||||
return ((s <= INVALID_END || s >= INVALID_START) ||
|
||||
s == NO_STATUS ||
|
||||
s == ABNORMAL_CLOSE ||
|
||||
s == TLS_HANDSHAKE);
|
||||
}
|
||||
|
||||
// TODO functions for application ranges?
|
||||
} // namespace status
|
||||
} // namespace close
|
||||
|
||||
|
||||
|
||||
#include <websocketpp/common/memory.hpp>
|
||||
#include <websocketpp/common/functional.hpp>
|
||||
#include <websocketpp/common/regex.hpp>
|
||||
#include <websocketpp/common/system_error.hpp>
|
||||
|
||||
#endif // WEBSOCKETPP_COMMON_HPP
|
||||
@@ -44,40 +44,50 @@
|
||||
#ifdef _WEBSOCKETPP_CPP11_STL_
|
||||
// This flag indicates that all of the C++11 language features are available
|
||||
// to us.
|
||||
#define _WEBSOCKETPP_NOEXCEPT_TOKEN_ noexcept
|
||||
#define _WEBSOCKETPP_CONSTEXPR_TOKEN_ constexpr
|
||||
#define _WEBSOCKETPP_INITIALIZER_LISTS_
|
||||
#ifndef _WEBSOCKETPP_NOEXCEPT_TOKEN_
|
||||
#define _WEBSOCKETPP_NOEXCEPT_TOKEN_ noexcept
|
||||
#endif
|
||||
#ifndef _WEBSOCKETPP_CONSTEXPR_TOKEN_
|
||||
#define _WEBSOCKETPP_CONSTEXPR_TOKEN_ constexpr
|
||||
#endif
|
||||
#ifndef _WEBSOCKETPP_INITIALIZER_LISTS_
|
||||
#define _WEBSOCKETPP_INITIALIZER_LISTS_
|
||||
#endif
|
||||
#else
|
||||
// Test for noexcept
|
||||
#ifdef _WEBSOCKETPP_NOEXCEPT_
|
||||
// build system says we have noexcept
|
||||
#define _WEBSOCKETPP_NOEXCEPT_TOKEN_ noexcept
|
||||
#else
|
||||
#if __has_feature(cxx_noexcept)
|
||||
// clang feature detect says we have noexcept
|
||||
#ifndef _WEBSOCKETPP_NOEXCEPT_TOKEN_
|
||||
#ifdef _WEBSOCKETPP_NOEXCEPT_
|
||||
// build system says we have noexcept
|
||||
#define _WEBSOCKETPP_NOEXCEPT_TOKEN_ noexcept
|
||||
#else
|
||||
// assume we don't have noexcept
|
||||
#define _WEBSOCKETPP_NOEXCEPT_TOKEN_
|
||||
#if __has_feature(cxx_noexcept)
|
||||
// clang feature detect says we have noexcept
|
||||
#define _WEBSOCKETPP_NOEXCEPT_TOKEN_ noexcept
|
||||
#else
|
||||
// assume we don't have noexcept
|
||||
#define _WEBSOCKETPP_NOEXCEPT_TOKEN_
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Test for constexpr
|
||||
#ifdef _WEBSOCKETPP_CONSTEXPR_
|
||||
// build system says we have constexpr
|
||||
#define _WEBSOCKETPP_CONSTEXPR_TOKEN_ constexpr
|
||||
#else
|
||||
#if __has_feature(cxx_constexpr)
|
||||
// clang feature detect says we have constexpr
|
||||
#ifndef _WEBSOCKETPP_CONSTEXPR_TOKEN_
|
||||
#ifdef _WEBSOCKETPP_CONSTEXPR_
|
||||
// build system says we have constexpr
|
||||
#define _WEBSOCKETPP_CONSTEXPR_TOKEN_ constexpr
|
||||
#else
|
||||
// assume we don't have constexpr
|
||||
#define _WEBSOCKETPP_CONSTEXPR_TOKEN_
|
||||
#if __has_feature(cxx_constexpr)
|
||||
// clang feature detect says we have constexpr
|
||||
#define _WEBSOCKETPP_CONSTEXPR_TOKEN_ constexpr
|
||||
#else
|
||||
// assume we don't have constexpr
|
||||
#define _WEBSOCKETPP_CONSTEXPR_TOKEN_
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Enable initializer lists on clang when available.
|
||||
#if __has_feature(cxx_generalized_initializers)
|
||||
#if __has_feature(cxx_generalized_initializers) && !defined(_WEBSOCKETPP_INITIALIZER_LISTS_)
|
||||
#define _WEBSOCKETPP_INITIALIZER_LISTS_
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -54,7 +54,7 @@ namespace lib {
|
||||
using boost::bind;
|
||||
using boost::ref;
|
||||
namespace placeholders {
|
||||
// TODO: there has got to be a better way than this
|
||||
/// \todo this feels hacky, is there a better way?
|
||||
using ::_1;
|
||||
using ::_2;
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
* don't fit somewhere else better.
|
||||
*/
|
||||
|
||||
#if defined(WIN32)
|
||||
#if defined(WIN32) && !defined(NOMINMAX)
|
||||
// don't define min and max macros that conflict with std::min and std::max
|
||||
#define NOMINMAX
|
||||
#endif
|
||||
|
||||
+191
-61
@@ -47,27 +47,125 @@
|
||||
|
||||
namespace websocketpp {
|
||||
|
||||
/// The type and function signature of an open handler
|
||||
/**
|
||||
* The open handler is called once for every successful WebSocket connection
|
||||
* attempt. Either the fail handler or the open handler will be called for each
|
||||
* WebSocket connection attempt. HTTP Connections that did not attempt to
|
||||
* upgrade the connection to the WebSocket protocol will trigger the http
|
||||
* handler instead of fail/open.
|
||||
*/
|
||||
typedef lib::function<void(connection_hdl)> open_handler;
|
||||
|
||||
/// The type and function signature of a close handler
|
||||
/**
|
||||
* The close handler is called once for every successfully established
|
||||
* connection after it is no longer capable of sending or receiving new messages
|
||||
*
|
||||
* The close handler will be called exactly once for every connection for which
|
||||
* the open handler was called.
|
||||
*/
|
||||
typedef lib::function<void(connection_hdl)> close_handler;
|
||||
|
||||
/// The type and function signature of a fail handler
|
||||
/**
|
||||
* The fail handler is called once for every unsuccessful WebSocket connection
|
||||
* attempt. Either the fail handler or the open handler will be called for each
|
||||
* WebSocket connection attempt. HTTP Connections that did not attempt to
|
||||
* upgrade the connection to the WebSocket protocol will trigger the http
|
||||
* handler instead of fail/open.
|
||||
*/
|
||||
typedef lib::function<void(connection_hdl)> fail_handler;
|
||||
|
||||
/// The type and function signature of an interrupt handler
|
||||
/**
|
||||
* The interrupt handler is called when a connection receives an interrupt
|
||||
* request from the application. Interrupts allow the application to trigger a
|
||||
* handler to be run in the absense of a WebSocket level handler trigger (like
|
||||
* a new message).
|
||||
*
|
||||
* This is typically used by another application thread to schedule some tasks
|
||||
* that can only be run from within the handler chain for thread safety reasons.
|
||||
*/
|
||||
typedef lib::function<void(connection_hdl)> interrupt_handler;
|
||||
|
||||
typedef lib::function<void(connection_hdl)> handshake_init_handler;
|
||||
|
||||
/// The type and function signature of a ping handler
|
||||
/**
|
||||
* The ping handler is called when the connection receives a WebSocket ping
|
||||
* control frame. The string argument contains the ping payload. The payload is
|
||||
* a binary string up to 126 bytes in length. The ping handler returns a bool,
|
||||
* true if a pong response should be sent, false if the pong response should be
|
||||
* suppressed.
|
||||
*/
|
||||
typedef lib::function<bool(connection_hdl,std::string)> ping_handler;
|
||||
|
||||
/// The type and function signature of a pong handler
|
||||
/**
|
||||
* The pong handler is called when the connection receives a WebSocket pong
|
||||
* control frame. The string argument contains the pong payload. The payload is
|
||||
* a binary string up to 126 bytes in length.
|
||||
*/
|
||||
typedef lib::function<void(connection_hdl,std::string)> pong_handler;
|
||||
|
||||
/// The type and function signature of a pong timeout handler
|
||||
/**
|
||||
* The pong timeout handler is called when a ping goes unanswered by a pong for
|
||||
* longer than the locally specified timeout period.
|
||||
*/
|
||||
typedef lib::function<void(connection_hdl,std::string)> pong_timeout_handler;
|
||||
|
||||
/// The type and function signature of a validate 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
|
||||
* connections and the ability to negotiate extensions and subprotocols.
|
||||
*
|
||||
* The validate handler return value indicates whether or not the connection
|
||||
* should be accepted. Additional methods may be called during the function to
|
||||
* set response headers, set HTTP return/error codes, etc.
|
||||
*/
|
||||
typedef lib::function<bool(connection_hdl)> validate_handler;
|
||||
|
||||
/// The type and function signature of a http handler
|
||||
/**
|
||||
* The http handler is called when an HTTP connection is made that does not
|
||||
* attempt to upgrade the connection to the WebSocket protocol. This allows
|
||||
* WebSocket++ servers to respond to these requests with regular HTTP responses.
|
||||
*
|
||||
* This can be used to deliver error pages & dashboards and to deliver static
|
||||
* files such as the base HTML & JavaScript for an otherwise single page
|
||||
* WebSocket application.
|
||||
*
|
||||
* Note: WebSocket++ is designed to be a high performance WebSocket server. It
|
||||
* is not tuned to provide a full featured, high performance, HTTP web server
|
||||
* solution. The HTTP handler is appropriate only for low volume HTTP traffic.
|
||||
* If you expect to serve high volumes of HTTP traffic a dedicated HTTP web
|
||||
* server is strongly recommended.
|
||||
*
|
||||
* The default HTTP handler will return a 426 Upgrade Required error. Custom
|
||||
* handlers may override the response status code to deliver any type of
|
||||
* response.
|
||||
*/
|
||||
typedef lib::function<void(connection_hdl)> http_handler;
|
||||
|
||||
// constants related to the default WebSocket protocol versions available
|
||||
#ifdef _WEBSOCKETPP_INITIALIZER_LISTS_ // simplified C++11 version
|
||||
static const std::vector<int> VERSIONS_SUPPORTED = {0,7,8,13};
|
||||
/// Container that stores the list of protocol versions supported
|
||||
/**
|
||||
* @todo Move this to configs to allow compile/runtime disabling or enabling
|
||||
* of protocol versions
|
||||
*/
|
||||
static std::vector<int> const versions_supported = {0,7,8,13};
|
||||
#else
|
||||
static const int HELPER[] = {0,7,8,13};
|
||||
static const std::vector<int> VERSIONS_SUPPORTED(HELPER,HELPER+4);
|
||||
/// Helper array to get around lack of initializer lists pre C++11
|
||||
static int const helper[] = {0,7,8,13};
|
||||
/// Container that stores the list of protocol versions supported
|
||||
/**
|
||||
* @todo Move this to configs to allow compile/runtime disabling or enabling
|
||||
* of protocol versions
|
||||
*/
|
||||
static std::vector<int> const versions_supported(helper,helper+4);
|
||||
#endif
|
||||
|
||||
namespace session {
|
||||
@@ -178,7 +276,7 @@ private:
|
||||
};
|
||||
public:
|
||||
|
||||
explicit connection(bool is_server, const std::string& ua, alog_type& alog,
|
||||
explicit connection(bool is_server, std::string const & ua, alog_type& alog,
|
||||
elog_type& elog, rng_type & rng)
|
||||
: transport_con_type(is_server,alog,elog)
|
||||
, m_user_agent(ua)
|
||||
@@ -193,12 +291,11 @@ public:
|
||||
, m_rng(rng)
|
||||
, m_local_close_code(close::status::abnormal_close)
|
||||
, m_remote_close_code(close::status::abnormal_close)
|
||||
, m_was_clean(false)
|
||||
{
|
||||
m_alog.write(log::alevel::devel,"connection constructor");
|
||||
}
|
||||
|
||||
// Public Interface
|
||||
|
||||
///////////////////////////
|
||||
// Set Handler Callbacks //
|
||||
///////////////////////////
|
||||
@@ -354,7 +451,9 @@ public:
|
||||
size_t get_buffered_amount() const;
|
||||
|
||||
/// DEPRECATED: use get_buffered_amount instead
|
||||
size_t buffered_amount() const {return get_buffered_amount();}
|
||||
size_t buffered_amount() const {
|
||||
return get_buffered_amount();
|
||||
}
|
||||
|
||||
////////////////////
|
||||
// Action Methods //
|
||||
@@ -372,7 +471,7 @@ public:
|
||||
* @param op The opcode to generated the message with. Default is
|
||||
* frame::opcode::text
|
||||
*/
|
||||
lib::error_code send(const std::string& payload, frame::opcode::value op =
|
||||
lib::error_code send(std::string const & payload, frame::opcode::value op =
|
||||
frame::opcode::TEXT);
|
||||
|
||||
/// Send a message (raw array overload)
|
||||
@@ -389,7 +488,7 @@ public:
|
||||
* @param op The opcode to generated the message with. Default is
|
||||
* frame::opcode::binary
|
||||
*/
|
||||
lib::error_code send(const void* payload, size_t len, frame::opcode::value
|
||||
lib::error_code send(void const * payload, size_t len, frame::opcode::value
|
||||
op = frame::opcode::BINARY);
|
||||
|
||||
/// Add a message to the outgoing send queue
|
||||
@@ -399,7 +498,7 @@ public:
|
||||
* and then added
|
||||
*
|
||||
* Errors are returned via an exception
|
||||
* TODO: make exception system_error rather than error_code
|
||||
* \todo make exception system_error rather than error_code
|
||||
*
|
||||
* This method invokes the m_write_lock mutex
|
||||
*
|
||||
@@ -437,13 +536,13 @@ public:
|
||||
*
|
||||
* @param payload Payload to be used for the ping
|
||||
*/
|
||||
void ping(const std::string& payload);
|
||||
void ping(std::string const & payload);
|
||||
|
||||
/// exception free variant of ping
|
||||
void ping(const std::string & payload, lib::error_code & ec);
|
||||
void ping(std::string const & payload, lib::error_code & ec);
|
||||
|
||||
/// Utility method that gets called back when the ping timer expires
|
||||
void handle_pong_timeout(std::string payload, const lib::error_code & ec);
|
||||
void handle_pong_timeout(std::string payload, lib::error_code const & ec);
|
||||
|
||||
/// Send a pong
|
||||
/**
|
||||
@@ -455,10 +554,10 @@ public:
|
||||
*
|
||||
* @param payload Payload to be used for the pong
|
||||
*/
|
||||
void pong(const std::string & payload);
|
||||
void pong(std::string const & payload);
|
||||
|
||||
/// exception free variant of pong
|
||||
void pong(const std::string & payload, lib::error_code & ec);
|
||||
void pong(std::string const & payload, lib::error_code & ec);
|
||||
|
||||
/// Close the connection
|
||||
/**
|
||||
@@ -478,13 +577,12 @@ public:
|
||||
* if necessary.
|
||||
*
|
||||
* @param code The close code to send
|
||||
*
|
||||
* @param reason The close reason to send
|
||||
*/
|
||||
void close(const close::status::value code, const std::string & reason);
|
||||
void close(close::status::value const code, std::string const & reason);
|
||||
|
||||
/// exception free variant of close
|
||||
void close(const close::status::value code, const std::string & reason,
|
||||
void close(close::status::value const code, std::string const & reason,
|
||||
lib::error_code & ec);
|
||||
|
||||
////////////////////////////////////////////////
|
||||
@@ -507,7 +605,7 @@ public:
|
||||
*
|
||||
* @return The host component of the connection URI
|
||||
*/
|
||||
const std::string& get_host() const;
|
||||
std::string const & get_host() const;
|
||||
|
||||
/// Returns the resource component of the connection URI
|
||||
/**
|
||||
@@ -516,7 +614,7 @@ public:
|
||||
*
|
||||
* @return The resource component of the connection URI
|
||||
*/
|
||||
const std::string& get_resource() const;
|
||||
std::string const & get_resource() const;
|
||||
|
||||
/// Returns the port component of the connection URI
|
||||
/**
|
||||
@@ -556,7 +654,7 @@ public:
|
||||
*
|
||||
* @return The negotiated subprotocol
|
||||
*/
|
||||
const std::string& get_subprotocol() const;
|
||||
std::string const & get_subprotocol() const;
|
||||
|
||||
/// Gets all of the subprotocols requested by the client
|
||||
/**
|
||||
@@ -565,7 +663,7 @@ public:
|
||||
*
|
||||
* @return A vector of the requested subprotocol
|
||||
*/
|
||||
const std::vector<std::string> & get_requested_subprotocols() const;
|
||||
std::vector<std::string> const & get_requested_subprotocols() const;
|
||||
|
||||
/// Adds the given subprotocol string to the request list (exception free)
|
||||
/**
|
||||
@@ -577,11 +675,10 @@ public:
|
||||
* preference.
|
||||
*
|
||||
* @param request The subprotocol to request
|
||||
*
|
||||
* @param ec A reference to an error code that will be filled in the case of
|
||||
* errors
|
||||
*/
|
||||
void add_subprotocol(const std::string &request, lib::error_code & ec);
|
||||
void add_subprotocol(std::string const & request, lib::error_code & ec);
|
||||
|
||||
/// Adds the given subprotocol string to the request list
|
||||
/**
|
||||
@@ -594,7 +691,7 @@ public:
|
||||
*
|
||||
* @param request The subprotocol to request
|
||||
*/
|
||||
void add_subprotocol(const std::string &request);
|
||||
void add_subprotocol(std::string const & request);
|
||||
|
||||
/// Select a subprotocol to use (exception free)
|
||||
/**
|
||||
@@ -606,11 +703,10 @@ public:
|
||||
* This member function is valid on server endpoints/connections only
|
||||
*
|
||||
* @param value The subprotocol to select
|
||||
*
|
||||
* @param ec A reference to an error code that will be filled in the case of
|
||||
* errors
|
||||
*/
|
||||
void select_subprotocol(const std::string & value, lib::error_code & ec);
|
||||
void select_subprotocol(std::string const & value, lib::error_code & ec);
|
||||
|
||||
/// Select a subprotocol to use
|
||||
/**
|
||||
@@ -623,7 +719,7 @@ public:
|
||||
*
|
||||
* @param value The subprotocol to select
|
||||
*/
|
||||
void select_subprotocol(const std::string & value);
|
||||
void select_subprotocol(std::string const & value);
|
||||
|
||||
/////////////////////////////////////////////////////////////
|
||||
// Pass-through access to the request and response objects //
|
||||
@@ -634,16 +730,18 @@ public:
|
||||
* Retrieve the value of a header from the handshake HTTP request.
|
||||
*
|
||||
* @param key Name of the header to get
|
||||
* @return The value of the header
|
||||
*/
|
||||
const std::string & get_request_header(const std::string &key);
|
||||
std::string const & get_request_header(std::string const & key);
|
||||
|
||||
/// Retrieve a response header
|
||||
/**
|
||||
* Retrieve the value of a header from the handshake HTTP request.
|
||||
*
|
||||
* @param key Name of the header to get
|
||||
* @return The value of the header
|
||||
*/
|
||||
const std::string & get_response_header(const std::string &key);
|
||||
std::string const & get_response_header(std::string const & key);
|
||||
|
||||
/// Set response status code and message
|
||||
/**
|
||||
@@ -674,7 +772,7 @@ public:
|
||||
* @param msg Message to set
|
||||
* @see websocketpp::http::response::set_status
|
||||
*/
|
||||
void set_status(http::status_code::value code, const std::string& msg);
|
||||
void set_status(http::status_code::value code, std::string const & msg);
|
||||
|
||||
/// Set response body content
|
||||
/**
|
||||
@@ -689,7 +787,7 @@ public:
|
||||
* @param value String data to include as the body content.
|
||||
* @see websocketpp::http::response::set_body
|
||||
*/
|
||||
void set_body(const std::string& value);
|
||||
void set_body(std::string const & value);
|
||||
|
||||
/// Append a header
|
||||
/**
|
||||
@@ -705,7 +803,7 @@ public:
|
||||
* @see replace_header
|
||||
* @see websocketpp::http::parser::append_header
|
||||
*/
|
||||
void append_header(const std::string &key,const std::string &val);
|
||||
void append_header(std::string const &key, std::string const & val);
|
||||
|
||||
/// Replace a header
|
||||
/**
|
||||
@@ -720,7 +818,7 @@ public:
|
||||
* @see add_header
|
||||
* @see websocketpp::http::parser::replace_header
|
||||
*/
|
||||
void replace_header(const std::string &key,const std::string &val);
|
||||
void replace_header(std::string const & key, std::string const & val);
|
||||
|
||||
/// Remove a header
|
||||
/**
|
||||
@@ -732,7 +830,25 @@ public:
|
||||
* @param key The name of the header to remove
|
||||
* @see websocketpp::http::parser::remove_header
|
||||
*/
|
||||
void remove_header(const std::string &key);
|
||||
void remove_header(std::string const & key);
|
||||
|
||||
/// Get request object
|
||||
/**
|
||||
* Direct access to request object. This can be used to call methods of the
|
||||
* request object that are not part of the standard request API that
|
||||
* connection wraps.
|
||||
*
|
||||
* Note use of this method involves using behavior specific to the
|
||||
* configured HTTP policy. Such behavior may not work with alternate HTTP
|
||||
* policies.
|
||||
*
|
||||
* @since 0.3.0-alpha3
|
||||
*
|
||||
* @return A const reference to the raw request object
|
||||
*/
|
||||
request_type const & get_request() const {
|
||||
return m_request;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////
|
||||
// Pass-through access to the other connection information //
|
||||
@@ -765,7 +881,7 @@ public:
|
||||
*
|
||||
* @return The connection's origin value from the opening handshake.
|
||||
*/
|
||||
const std::string& get_origin() const;
|
||||
std::string const & get_origin() const;
|
||||
|
||||
/// Return the connection state.
|
||||
/**
|
||||
@@ -841,22 +957,39 @@ public:
|
||||
transport_con_type::set_handle(hdl);
|
||||
}
|
||||
|
||||
/// Get a message buffer
|
||||
/**
|
||||
* @internal
|
||||
*
|
||||
* Warning: This is not guaranteed to be part of the public release API
|
||||
*
|
||||
* Message buffers are used to store message payloads and other message
|
||||
* metadata.
|
||||
*
|
||||
* @return A new message.
|
||||
*/
|
||||
message_ptr get_message(websocketpp::frame::opcode::value op, size_t size)
|
||||
const
|
||||
{
|
||||
return m_msg_manager->get_message(op, size);
|
||||
}
|
||||
|
||||
void start();
|
||||
|
||||
void read_handshake(size_t num_bytes);
|
||||
|
||||
void handle_read_handshake(const lib::error_code& ec,
|
||||
void handle_read_handshake(lib::error_code const & ec,
|
||||
size_t bytes_transferred);
|
||||
void handle_read_http_response(const lib::error_code& ec,
|
||||
void handle_read_http_response(lib::error_code const & ec,
|
||||
size_t bytes_transferred);
|
||||
|
||||
void handle_send_http_response(const lib::error_code& ec);
|
||||
void handle_send_http_request(const lib::error_code& ec);
|
||||
void handle_send_http_response(lib::error_code const & ec);
|
||||
void handle_send_http_request(lib::error_code const & ec);
|
||||
|
||||
void handle_open_handshake_timeout(lib::error_code const & ec);
|
||||
void handle_close_handshake_timeout(lib::error_code const & ec);
|
||||
|
||||
void handle_read_frame(const lib::error_code& ec,
|
||||
void handle_read_frame(lib::error_code const & ec,
|
||||
size_t bytes_transferred);
|
||||
|
||||
/// Get array of WebSocket protocol versions that this connection supports.
|
||||
@@ -866,12 +999,12 @@ public:
|
||||
/// internally by the endpoint class.
|
||||
void set_termination_handler(termination_handler new_handler);
|
||||
|
||||
void terminate(const lib::error_code & ec);
|
||||
void handle_terminate(terminate_status tstat, const lib::error_code& ec);
|
||||
void terminate(lib::error_code const & ec);
|
||||
void handle_terminate(terminate_status tstat, lib::error_code const & ec);
|
||||
|
||||
/// Checks if there are frames in the send queue and if there are sends one
|
||||
/**
|
||||
* TODO: unit tests
|
||||
* \todo unit tests
|
||||
*
|
||||
* This method locks the m_write_lock mutex
|
||||
*/
|
||||
@@ -879,7 +1012,7 @@ public:
|
||||
|
||||
/// Process the results of a frame write operation and start the next write
|
||||
/**
|
||||
* TODO: unit tests
|
||||
* \todo unit tests
|
||||
*
|
||||
* This method locks the m_write_lock mutex
|
||||
*
|
||||
@@ -889,9 +1022,9 @@ public:
|
||||
* @param ec A status code from the transport layer, zero on success,
|
||||
* non-zero otherwise.
|
||||
*/
|
||||
void handle_write_frame(bool terminate, const lib::error_code& ec);
|
||||
void handle_write_frame(bool terminate, lib::error_code const & ec);
|
||||
protected:
|
||||
void handle_transport_init(const lib::error_code& ec);
|
||||
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.
|
||||
@@ -963,13 +1096,11 @@ private:
|
||||
* other settings (such as silent close).
|
||||
*
|
||||
* @param code The close code to send
|
||||
*
|
||||
* @param reason The close reason to send
|
||||
*
|
||||
* @return A status code, zero on success, non-zero otherwise
|
||||
*/
|
||||
lib::error_code send_close_ack(close::status::value code =
|
||||
close::status::blank, const std::string &reason = "");
|
||||
close::status::blank, std::string const & reason = "");
|
||||
|
||||
/// Send close frame
|
||||
/**
|
||||
@@ -982,15 +1113,12 @@ private:
|
||||
* whether or not to terminate the TCP connection after sending it.
|
||||
*
|
||||
* @param code The close code to send
|
||||
*
|
||||
* @param reason The close reason to send
|
||||
*
|
||||
* @param ack Whether or not this is an acknowledgement close frame
|
||||
*
|
||||
* @return A status code, zero on success, non-zero otherwise
|
||||
*/
|
||||
lib::error_code send_close_frame(close::status::value code =
|
||||
close::status::blank, const std::string &reason = "", bool ack = false,
|
||||
close::status::blank, std::string const & reason = "", bool ack = false,
|
||||
bool terminal = false);
|
||||
|
||||
/// Get a pointer to a new WebSocket protocol processor for a given version
|
||||
@@ -1011,7 +1139,7 @@ private:
|
||||
*
|
||||
* Must be called while holding m_write_lock
|
||||
*
|
||||
* TODO: unit tests
|
||||
* @todo unit tests
|
||||
*
|
||||
* @param msg The message to push
|
||||
*/
|
||||
@@ -1024,7 +1152,7 @@ private:
|
||||
*
|
||||
* Must be called while holding m_write_lock
|
||||
*
|
||||
* TODO: unit tests
|
||||
* @todo unit tests
|
||||
*
|
||||
* @return the message_ptr at the front of the queue
|
||||
*/
|
||||
@@ -1097,8 +1225,8 @@ private:
|
||||
timer_ptr m_handshake_timer;
|
||||
timer_ptr m_ping_timer;
|
||||
|
||||
// TODO: this is not memory efficient. this value is not used after the
|
||||
// handshake.
|
||||
/// @todo this is not memory efficient. this value is not used after the
|
||||
/// handshake.
|
||||
std::string m_handshake_buffer;
|
||||
|
||||
/// Pointer to the processor object for this connection
|
||||
@@ -1150,7 +1278,7 @@ private:
|
||||
// of the whole connection.
|
||||
std::vector<std::string> m_requested_subprotocols;
|
||||
|
||||
const bool m_is_server;
|
||||
bool const m_is_server;
|
||||
alog_type& m_alog;
|
||||
elog_type& m_elog;
|
||||
|
||||
@@ -1172,6 +1300,8 @@ private:
|
||||
/// Detailed internal error code
|
||||
lib::error_code m_ec;
|
||||
|
||||
bool m_was_clean;
|
||||
|
||||
/// Whether or not this endpoint initiated the closing handshake.
|
||||
bool m_closed_by_me;
|
||||
|
||||
|
||||
+72
-24
@@ -30,14 +30,13 @@
|
||||
|
||||
#include <websocketpp/connection.hpp>
|
||||
#include <websocketpp/logger/levels.hpp>
|
||||
#include <websocketpp/version.hpp>
|
||||
|
||||
#include <iostream>
|
||||
#include <set>
|
||||
|
||||
namespace websocketpp {
|
||||
|
||||
static const char user_agent[] = "WebSocket++/0.3.0dev";
|
||||
|
||||
/// Creates and manages connections associated with a WebSocket endpoint
|
||||
template <typename connection, typename config>
|
||||
class endpoint : public config::transport_type, public config::endpoint_base {
|
||||
@@ -89,8 +88,8 @@ public:
|
||||
typedef lib::shared_ptr<connection_weak_ptr> hdl_type;
|
||||
|
||||
explicit endpoint(bool is_server)
|
||||
: m_alog(config::alog_level,&std::cout)
|
||||
, m_elog(config::elog_level,&std::cerr)
|
||||
: m_alog(config::alog_level, &std::cout)
|
||||
, m_elog(config::elog_level, &std::cerr)
|
||||
, m_user_agent(::websocketpp::user_agent)
|
||||
, m_is_server(is_server)
|
||||
{
|
||||
@@ -107,7 +106,7 @@ public:
|
||||
* Returns the user agent string that this endpoint will use when creating
|
||||
* new connections.
|
||||
*
|
||||
* The default value for this version is WebSocket++/0.3.0dev
|
||||
* The default value for this version is stored in websocketpp::user_agent
|
||||
*
|
||||
* @return The user agent string.
|
||||
*/
|
||||
@@ -118,16 +117,27 @@ public:
|
||||
|
||||
/// Sets the user agent string that this endpoint will use
|
||||
/**
|
||||
* Sets the user agent string that this endpoint will use when creating
|
||||
* new connections. Changing this value will only affect future connections.
|
||||
* Sets the identifier that this endpoint will use when creating new
|
||||
* connections. Changing this value will only affect future connections.
|
||||
* For client endpoints this will be sent as the "User-Agent" header in
|
||||
* outgoing requests. For server endpoints this will be sent in the "Server"
|
||||
* response header.
|
||||
*
|
||||
* Setting this value to the empty string will suppress the use of the
|
||||
* Server and User-Agent headers. This is typically done to hide
|
||||
* implementation details for security purposes.
|
||||
*
|
||||
* For best results set this before accepting or opening connections.
|
||||
*
|
||||
* The default value for this version is WebSocket++/0.3.0dev
|
||||
* The default value for this version is stored in websocketpp::user_agent
|
||||
*
|
||||
* This can be overridden on an individual connection basis by setting a
|
||||
* custom "Server" header during the validate handler or "User-Agent"
|
||||
* header on a connection before calling connect().
|
||||
*
|
||||
* @param ua The string to set the user agent to.
|
||||
*/
|
||||
void set_user_agent(const std::string& ua) {
|
||||
void set_user_agent(std::string const & ua) {
|
||||
scoped_lock_type guard(m_mutex);
|
||||
m_user_agent = ua;
|
||||
}
|
||||
@@ -190,21 +200,17 @@ public:
|
||||
|
||||
/// Get reference to access logger
|
||||
/**
|
||||
* TODO
|
||||
*
|
||||
* @return A reference to the access logger
|
||||
*/
|
||||
alog_type& get_alog() {
|
||||
alog_type & get_alog() {
|
||||
return m_alog;
|
||||
}
|
||||
|
||||
/// Get reference to error logger
|
||||
/**
|
||||
* TODO
|
||||
*
|
||||
* @return A reference to the error logger
|
||||
*/
|
||||
elog_type& get_elog() {
|
||||
elog_type & get_elog() {
|
||||
return m_elog;
|
||||
}
|
||||
|
||||
@@ -271,23 +277,65 @@ public:
|
||||
void interrupt(connection_hdl hdl, lib::error_code & ec);
|
||||
void interrupt(connection_hdl hdl);
|
||||
|
||||
void send(connection_hdl hdl, const std::string& payload,
|
||||
void send(connection_hdl hdl, std::string const & payload,
|
||||
frame::opcode::value op, lib::error_code & ec);
|
||||
void send(connection_hdl hdl, const std::string& payload,
|
||||
void send(connection_hdl hdl, std::string const & payload,
|
||||
frame::opcode::value op);
|
||||
|
||||
void send(connection_hdl hdl, const void* payload, size_t len,
|
||||
void send(connection_hdl hdl, void const * payload, size_t len,
|
||||
frame::opcode::value op, lib::error_code & ec);
|
||||
void send(connection_hdl hdl, const void* payload, size_t len,
|
||||
void send(connection_hdl hdl, void const * payload, size_t len,
|
||||
frame::opcode::value op);
|
||||
|
||||
void send(connection_hdl hdl, message_ptr msg, lib::error_code & ec);
|
||||
void send(connection_hdl hdl, message_ptr msg);
|
||||
|
||||
void close(connection_hdl hdl, const close::status::value code,
|
||||
const std::string & reason, lib::error_code & ec);
|
||||
void close(connection_hdl hdl, const close::status::value code,
|
||||
const std::string & reason);
|
||||
void close(connection_hdl hdl, close::status::value const code,
|
||||
std::string const & reason, lib::error_code & ec);
|
||||
void close(connection_hdl hdl, close::status::value const code,
|
||||
std::string const & reason);
|
||||
|
||||
/// Send a ping to a specific connection
|
||||
/**
|
||||
* @since 0.3.0-alpha3
|
||||
*
|
||||
* @param [in] hdl The connection_hdl of the connection to send to.
|
||||
* @param [in] payload The payload string to send.
|
||||
* @param [out] ec A reference to an error code to fill in
|
||||
*/
|
||||
void ping(connection_hdl hdl, std::string const & payload,
|
||||
lib::error_code & ec);
|
||||
/// Send a ping to a specific connection
|
||||
/**
|
||||
* Exception variant of `ping`
|
||||
*
|
||||
* @since 0.3.0-alpha3
|
||||
*
|
||||
* @param [in] hdl The connection_hdl of the connection to send to.
|
||||
* @param [in] payload The payload string to send.
|
||||
*/
|
||||
void ping(connection_hdl hdl, std::string const & payload);
|
||||
|
||||
/// Send a pong to a specific connection
|
||||
/**
|
||||
* @since 0.3.0-alpha3
|
||||
*
|
||||
* @param [in] hdl The connection_hdl of the connection to send to.
|
||||
* @param [in] payload The payload string to send.
|
||||
* @param [out] ec A reference to an error code to fill in
|
||||
*/
|
||||
void pong(connection_hdl hdl, std::string const & payload,
|
||||
lib::error_code & ec);
|
||||
/// Send a pong to a specific connection
|
||||
/**
|
||||
* Exception variant of `pong`
|
||||
*
|
||||
* @since 0.3.0-alpha3
|
||||
*
|
||||
* @param [in] hdl The connection_hdl of the connection to send to.
|
||||
* @param [in] payload The payload string to send.
|
||||
*/
|
||||
void pong(connection_hdl hdl, std::string const & payload);
|
||||
|
||||
/// Retrieves a connection_ptr from a connection_hdl (exception free)
|
||||
/**
|
||||
@@ -349,7 +397,7 @@ private:
|
||||
std::set<connection_ptr> m_connections;
|
||||
|
||||
// static settings
|
||||
const bool m_is_server;
|
||||
bool const m_is_server;
|
||||
|
||||
// endpoint state
|
||||
mutex_type m_mutex;
|
||||
|
||||
@@ -35,6 +35,9 @@
|
||||
|
||||
namespace websocketpp {
|
||||
|
||||
/// Combination error code / string type for returning two values
|
||||
typedef std::pair<lib::error_code,std::string> err_str_pair;
|
||||
|
||||
// setup for errors that should be propogated back to the user.
|
||||
namespace error {
|
||||
enum value {
|
||||
@@ -108,7 +111,10 @@ enum value {
|
||||
open_handshake_timeout,
|
||||
|
||||
/// WebSocket close handshake timed out
|
||||
close_handshake_timeout
|
||||
close_handshake_timeout,
|
||||
|
||||
/// Invalid port in URI
|
||||
invalid_port
|
||||
}; // enum value
|
||||
|
||||
|
||||
@@ -168,6 +174,8 @@ public:
|
||||
return "The opening handshake timed out";
|
||||
case error::close_handshake_timeout:
|
||||
return "The closing handshake timed out";
|
||||
case error::invalid_port:
|
||||
return "Invalid URI port";
|
||||
default:
|
||||
return "Unknown";
|
||||
}
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
#include <websocketpp/common/cpp11.hpp>
|
||||
#include <websocketpp/common/system_error.hpp>
|
||||
|
||||
#include <websocketpp/http/constants.hpp>
|
||||
#include <websocketpp/extensions/extension.hpp>
|
||||
|
||||
#include <map>
|
||||
@@ -49,11 +50,10 @@ namespace permessage_deflate {
|
||||
*/
|
||||
template <typename config>
|
||||
class disabled {
|
||||
typedef typename config::request_type::attribute_list attribute_list;
|
||||
typedef std::pair<lib::error_code,std::string> err_str_pair;
|
||||
|
||||
public:
|
||||
err_str_pair negotiate(const attribute_list& attributes) {
|
||||
err_str_pair negotiate(http::attribute_list const & attributes) {
|
||||
return make_pair(make_error_code(error::disabled),std::string());
|
||||
}
|
||||
|
||||
@@ -69,17 +69,17 @@ public:
|
||||
return false;
|
||||
}
|
||||
|
||||
lib::error_code compress(const std::string in, std::string &out) {
|
||||
lib::error_code compress(std::string const & in, std::string & out) {
|
||||
return make_error_code(error::disabled);
|
||||
}
|
||||
|
||||
lib::error_code decompress(const uint8_t * buf, size_t len,
|
||||
std::string &out)
|
||||
lib::error_code decompress(uint8_t const * buf, size_t len,
|
||||
std::string & out)
|
||||
{
|
||||
return make_error_code(error::disabled);
|
||||
}
|
||||
|
||||
lib::error_code decompress(const std::string in, std::string &out) {
|
||||
lib::error_code decompress(std::string const & in, std::string & out) {
|
||||
return make_error_code(error::disabled);
|
||||
}
|
||||
};
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
+63
-9
@@ -298,9 +298,9 @@ size_t prepare_masking_key(masking_key_type const & key);
|
||||
size_t circshift_prepared_key(size_t prepared_key, size_t offset);
|
||||
|
||||
// Functions for performing xor based masking and unmasking
|
||||
template <typename iter_type>
|
||||
void byte_mask(iter_type b, iter_type e, iter_type o, masking_key_type const &
|
||||
key, size_t key_offset = 0);
|
||||
template <typename input_iter, typename output_iter>
|
||||
void byte_mask(input_iter b, input_iter e, output_iter o, masking_key_type
|
||||
const & key, size_t key_offset = 0);
|
||||
template <typename iter_type>
|
||||
void byte_mask(iter_type b, iter_type e, masking_key_type const & key,
|
||||
size_t key_offset = 0);
|
||||
@@ -666,14 +666,16 @@ inline size_t circshift_prepared_key(size_t prepared_key, size_t offset) {
|
||||
*
|
||||
* @param key_offset offset value to start masking at.
|
||||
*/
|
||||
template <typename iter_type>
|
||||
void byte_mask(iter_type b, iter_type e, iter_type o, const masking_key_type&
|
||||
key, size_t key_offset)
|
||||
template <typename input_iter, typename output_iter>
|
||||
void byte_mask(input_iter first, input_iter last, output_iter result,
|
||||
masking_key_type const & key, size_t key_offset)
|
||||
{
|
||||
size_t key_index = key_offset%4;
|
||||
for (iter_type i = b, j = o; i != e; i++, j++) {
|
||||
*j = *i ^ key.c[key_index++];
|
||||
while (first != last) {
|
||||
*result = *first ^ key.c[key_index++];
|
||||
key_index %= 4;
|
||||
++result;
|
||||
++first;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -695,7 +697,7 @@ void byte_mask(iter_type b, iter_type e, iter_type o, const masking_key_type&
|
||||
* @param key_offset offset value to start masking at.
|
||||
*/
|
||||
template <typename iter_type>
|
||||
void byte_mask(iter_type b, iter_type e, const masking_key_type& key,
|
||||
void byte_mask(iter_type b, iter_type e, masking_key_type const & key,
|
||||
size_t key_offset)
|
||||
{
|
||||
byte_mask(b,e,b,key,key_offset);
|
||||
@@ -829,6 +831,58 @@ inline size_t word_mask_circ(uint8_t* data, size_t length, size_t prepared_key){
|
||||
return word_mask_circ(data,data,length,prepared_key);
|
||||
}
|
||||
|
||||
/// Circular byte aligned mask/unmask
|
||||
/**
|
||||
* Performs a circular mask/unmask in byte sized chunks using pre-prepared keys
|
||||
* that store state between calls. Best for providing streaming masking or
|
||||
* unmasking of small chunks at a time of a larger message. Requires that the
|
||||
* underlying allocated size of the data buffer be a multiple of the word size.
|
||||
* Data in the buffer after `length` will be overwritten only with the same
|
||||
* values that were originally present.
|
||||
*
|
||||
* word_mask returns a copy of prepared_key circularly shifted based on the
|
||||
* length value. The returned value may be fed back into byte_mask when more
|
||||
* data is available.
|
||||
*
|
||||
* @param data Character buffer to mask
|
||||
*
|
||||
* @param length Length of data
|
||||
*
|
||||
* @param prepared_key Prepared key to use.
|
||||
*
|
||||
* @return the prepared_key shifted to account for the input length
|
||||
*/
|
||||
inline size_t byte_mask_circ(uint8_t * input, uint8_t * output, size_t length,
|
||||
size_t prepared_key)
|
||||
{
|
||||
uint32_converter key;
|
||||
key.i = prepared_key;
|
||||
|
||||
for (size_t i = 0; i < length; ++i) {
|
||||
output[i] = input[i] ^ key.c[i % 4];
|
||||
}
|
||||
|
||||
return circshift_prepared_key(prepared_key,length % 4);
|
||||
}
|
||||
|
||||
/// Circular byte aligned mask/unmask (in place)
|
||||
/**
|
||||
* In place version of byte_mask_circ
|
||||
*
|
||||
* @see byte_mask_circ
|
||||
*
|
||||
* @param data Character buffer to read from and write to
|
||||
*
|
||||
* @param length Length of data
|
||||
*
|
||||
* @param prepared_key Prepared key to use.
|
||||
*
|
||||
* @return the prepared_key shifted to account for the input length
|
||||
*/
|
||||
inline size_t byte_mask_circ(uint8_t* data, size_t length, size_t prepared_key){
|
||||
return byte_mask_circ(data,data,length,prepared_key);
|
||||
}
|
||||
|
||||
} // namespace frame
|
||||
} // namespace websocketpp
|
||||
|
||||
|
||||
@@ -28,24 +28,48 @@
|
||||
#ifndef HTTP_CONSTANTS_HPP
|
||||
#define HTTP_CONSTANTS_HPP
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace websocketpp {
|
||||
namespace http {
|
||||
static const char header_delimiter[] = "\r\n";
|
||||
static const char header_separator[] = ": ";
|
||||
static const std::string empty_header = "";
|
||||
/// The type of an HTTP attribute list
|
||||
/**
|
||||
* The attribute list is an unordered key/value map. Encoded attribute
|
||||
* values are delimited by semicolons.
|
||||
*/
|
||||
typedef std::map<std::string,std::string> attribute_list;
|
||||
|
||||
// Maximum size in bytes before rejecting an HTTP header as too big.
|
||||
const size_t max_header_size = 16000;
|
||||
/// The type of an HTTP parameter list
|
||||
/**
|
||||
* The parameter list is an ordered pairing of a parameter and its
|
||||
* associated attribute list. Encoded parameter values are delimited by
|
||||
* commas.
|
||||
*/
|
||||
typedef std::vector< std::pair<std::string,attribute_list> > parameter_list;
|
||||
|
||||
// Number of bytes to use for temporary istream read buffers
|
||||
const size_t istream_buffer = 512;
|
||||
/// Literal value of the HTTP header delimiter
|
||||
static char const header_delimiter[] = "\r\n";
|
||||
|
||||
// invalid HTTP token characters
|
||||
// 0x00 - 0x32, 0x7f-0xff
|
||||
// ( ) < > @ , ; : \ " / [ ] ? = { }
|
||||
static const char header_token[] = {
|
||||
/// Literal value of the HTTP header separator
|
||||
static char const header_separator[] = ": ";
|
||||
|
||||
/// Literal value of an empty header
|
||||
static std::string const empty_header = "";
|
||||
|
||||
/// Maximum size in bytes before rejecting an HTTP header as too big.
|
||||
size_t const max_header_size = 16000;
|
||||
|
||||
/// Number of bytes to use for temporary istream read buffers
|
||||
size_t const istream_buffer = 512;
|
||||
|
||||
/// invalid HTTP token characters
|
||||
/**
|
||||
* 0x00 - 0x32, 0x7f-0xff
|
||||
* ( ) < > @ , ; : \ " / [ ] ? = { }
|
||||
*/
|
||||
static char const header_token[] = {
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 00..0f
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 10..1f
|
||||
0,1,0,1,1,1,1,1,0,0,1,1,0,1,1,0, // 20..2f
|
||||
@@ -64,23 +88,30 @@ namespace http {
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // f0..ff
|
||||
};
|
||||
|
||||
/// Is the character a token
|
||||
inline bool is_token_char(unsigned char c) {
|
||||
return (header_token[c] == 1);
|
||||
}
|
||||
|
||||
/// Is the character a non-token
|
||||
inline bool is_not_token_char(unsigned char c) {
|
||||
return !header_token[c];
|
||||
}
|
||||
|
||||
// Space (32) or horizontal tab (9)
|
||||
/// Is the character whitespace
|
||||
/**
|
||||
* whitespace is space (32) or horizontal tab (9)
|
||||
*/
|
||||
inline bool is_whitespace_char(unsigned char c) {
|
||||
return (c == 9 || c == 32);
|
||||
}
|
||||
|
||||
/// Is the character non-whitespace
|
||||
inline bool is_not_whitespace_char(unsigned char c) {
|
||||
return (c != 9 && c != 32);
|
||||
}
|
||||
|
||||
/// HTTP Status codes
|
||||
namespace status_code {
|
||||
enum value {
|
||||
uninitialized = 0,
|
||||
|
||||
@@ -30,67 +30,45 @@
|
||||
|
||||
#include <algorithm>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
|
||||
namespace websocketpp {
|
||||
namespace http {
|
||||
namespace parser {
|
||||
|
||||
inline bool parser::parse_parameter_list(const std::string& in,
|
||||
parameter_list& out) const
|
||||
{
|
||||
if (in.size() == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string::const_iterator it;
|
||||
it = extract_parameters(in.begin(),in.end(),out);
|
||||
return (it == in.begin());
|
||||
}
|
||||
|
||||
inline bool parser::get_header_as_plist(const std::string& key,
|
||||
parameter_list& out) const
|
||||
{
|
||||
header_list::const_iterator it = m_headers.find(key);
|
||||
|
||||
// If this header doesn't exist it is valid
|
||||
if (it == m_headers.end()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// If this header exists but is empty it is valid
|
||||
if (it->second.size() == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return this->parse_parameter_list(it->second,out);
|
||||
}
|
||||
|
||||
inline void parser::set_version(const std::string& version) {
|
||||
// TODO: validation?
|
||||
|
||||
// first four chars == HTTP/
|
||||
|
||||
inline void parser::set_version(std::string const & version) {
|
||||
m_version = version;
|
||||
}
|
||||
|
||||
inline const std::string& parser::get_header(const std::string& key) const {
|
||||
|
||||
inline std::string const & parser::get_header(std::string const & key) const {
|
||||
header_list::const_iterator h = m_headers.find(key);
|
||||
|
||||
|
||||
if (h == m_headers.end()) {
|
||||
return empty_header;
|
||||
} else {
|
||||
return h->second;
|
||||
}
|
||||
}
|
||||
|
||||
inline void parser::append_header(const std::string &key,const std::string
|
||||
&val)
|
||||
|
||||
inline bool parser::get_header_as_plist(std::string const & key,
|
||||
parameter_list & out) const
|
||||
{
|
||||
header_list::const_iterator it = m_headers.find(key);
|
||||
|
||||
if (it == m_headers.end() || it->second.size() == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return this->parse_parameter_list(it->second,out);
|
||||
}
|
||||
|
||||
inline void parser::append_header(std::string const & key, std::string const &
|
||||
val)
|
||||
{
|
||||
if (std::find_if(key.begin(),key.end(),is_not_token_char) != key.end()) {
|
||||
throw exception("Invalid header name",status_code::bad_request);
|
||||
}
|
||||
|
||||
// TODO: prevent use of reserved headers?
|
||||
|
||||
if (this->get_header(key) == "") {
|
||||
m_headers[key] = val;
|
||||
} else {
|
||||
@@ -98,33 +76,45 @@ inline void parser::append_header(const std::string &key,const std::string
|
||||
}
|
||||
}
|
||||
|
||||
inline void parser::replace_header(const std::string &key,const std::string
|
||||
&val)
|
||||
inline void parser::replace_header(std::string const & key, std::string const &
|
||||
val)
|
||||
{
|
||||
m_headers[key] = val;
|
||||
}
|
||||
|
||||
inline void parser::remove_header(const std::string &key) {
|
||||
inline void parser::remove_header(std::string const & key) {
|
||||
m_headers.erase(key);
|
||||
}
|
||||
|
||||
inline void parser::set_body(const std::string& value) {
|
||||
inline void parser::set_body(std::string const & value) {
|
||||
if (value.size() == 0) {
|
||||
remove_header("Content-Length");
|
||||
m_body = "";
|
||||
return;
|
||||
}
|
||||
|
||||
std::stringstream foo;
|
||||
foo << value.size();
|
||||
replace_header("Content-Length", foo.str());
|
||||
|
||||
std::stringstream len;
|
||||
len << value.size();
|
||||
replace_header("Content-Length", len.str());
|
||||
m_body = value;
|
||||
}
|
||||
|
||||
inline bool parser::parse_headers(std::istream& s) {
|
||||
inline bool parser::parse_parameter_list(std::string const & in,
|
||||
parameter_list & out) const
|
||||
{
|
||||
if (in.size() == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string::const_iterator it;
|
||||
it = extract_parameters(in.begin(),in.end(),out);
|
||||
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') {
|
||||
@@ -132,9 +122,9 @@ inline bool parser::parse_headers(std::istream& s) {
|
||||
} 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));
|
||||
}
|
||||
@@ -143,17 +133,6 @@ inline bool parser::parse_headers(std::istream& s) {
|
||||
return true;
|
||||
}
|
||||
|
||||
inline std::string parser::raw_headers() const {
|
||||
std::stringstream raw;
|
||||
|
||||
header_list::const_iterator it;
|
||||
for (it = m_headers.begin(); it != m_headers.end(); it++) {
|
||||
raw << it->first << ": " << it->second << "\r\n";
|
||||
}
|
||||
|
||||
return raw.str();
|
||||
}
|
||||
|
||||
inline void parser::process_header(std::string::iterator begin,
|
||||
std::string::iterator end)
|
||||
{
|
||||
@@ -172,6 +151,19 @@ inline void parser::process_header(std::string::iterator begin,
|
||||
std::string(cursor+sizeof(header_separator)-1,end));
|
||||
}
|
||||
|
||||
inline std::string parser::raw_headers() const {
|
||||
std::stringstream raw;
|
||||
|
||||
header_list::const_iterator it;
|
||||
for (it = m_headers.begin(); it != m_headers.end(); it++) {
|
||||
raw << it->first << ": " << it->second << "\r\n";
|
||||
}
|
||||
|
||||
return raw.str();
|
||||
}
|
||||
|
||||
|
||||
|
||||
} // namespace parser
|
||||
} // namespace http
|
||||
} // namespace websocketpp
|
||||
|
||||
@@ -148,7 +148,14 @@ 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) {
|
||||
// TODO: validation?
|
||||
m_uri = uri;
|
||||
|
||||
+197
-109
@@ -32,6 +32,7 @@
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
|
||||
#include <websocketpp/utilities.hpp>
|
||||
#include <websocketpp/http/constants.hpp>
|
||||
|
||||
namespace websocketpp {
|
||||
@@ -47,10 +48,18 @@ namespace state {
|
||||
};
|
||||
}
|
||||
|
||||
typedef std::map<std::string,std::string> header_list;
|
||||
typedef std::map<std::string, std::string, utility::ci_less > header_list;
|
||||
|
||||
/// Read until a non-token character is found and then return the token and
|
||||
/// iterator to the next character to read
|
||||
/// Read and return the next token in the stream
|
||||
/**
|
||||
* Read until a non-token character is found and then return the token and
|
||||
* iterator to the next character to read
|
||||
*
|
||||
* @param begin An iterator to the beginning of the sequence
|
||||
* @param end An iterator to the end of the sequence
|
||||
* @return A pair containing the token and an iterator to the next character in
|
||||
* the stream
|
||||
*/
|
||||
template <typename InputIterator>
|
||||
std::pair<std::string,InputIterator> extract_token(InputIterator begin,
|
||||
InputIterator end)
|
||||
@@ -59,6 +68,17 @@ std::pair<std::string,InputIterator> extract_token(InputIterator begin,
|
||||
return std::make_pair(std::string(begin,it),it);
|
||||
}
|
||||
|
||||
/// Read and return the next quoted string in the stream
|
||||
/**
|
||||
* Read a double quoted string starting at `begin`. The quotes themselves are
|
||||
* stripped. The quoted value is returned along with an iterator to the next
|
||||
* character to read
|
||||
*
|
||||
* @param begin An iterator to the beginning of the sequence
|
||||
* @param end An iterator to the end of the sequence
|
||||
* @return A pair containing the string read and an iterator to the next
|
||||
* character in the stream
|
||||
*/
|
||||
template <typename InputIterator>
|
||||
std::pair<std::string,InputIterator> extract_quoted_string(InputIterator begin,
|
||||
InputIterator end)
|
||||
@@ -97,8 +117,15 @@ std::pair<std::string,InputIterator> extract_quoted_string(InputIterator begin,
|
||||
return std::make_pair("",begin);
|
||||
}
|
||||
|
||||
/// Read one unit of linear white space and return the iterator to the character
|
||||
/// afterwards. If ret = begin no whitespace was extracted.
|
||||
/// Read and discard one unit of linear whitespace
|
||||
/**
|
||||
* Read one unit of linear white space and return the iterator to the character
|
||||
* afterwards. If `begin` is returned, no whitespace was extracted.
|
||||
*
|
||||
* @param begin An iterator to the beginning of the sequence
|
||||
* @param end An iterator to the end of the sequence
|
||||
* @return An iterator to the character after the linear whitespace read
|
||||
*/
|
||||
template <typename InputIterator>
|
||||
InputIterator extract_lws(InputIterator begin, InputIterator end) {
|
||||
InputIterator it = begin;
|
||||
@@ -114,7 +141,16 @@ InputIterator extract_lws(InputIterator begin, InputIterator end) {
|
||||
return it;
|
||||
}
|
||||
|
||||
/// SImilar to extract_lws but extracts all lws instead of just one line
|
||||
/// Read and discard linear whitespace
|
||||
/**
|
||||
* Read linear white space until a non-lws character is read and return an
|
||||
* iterator to that character. If `begin` is returned, no whitespace was
|
||||
* extracted.
|
||||
*
|
||||
* @param begin An iterator to the beginning of the sequence
|
||||
* @param end An iterator to the end of the sequence
|
||||
* @return An iterator to the character after the linear whitespace read
|
||||
*/
|
||||
template <typename InputIterator>
|
||||
InputIterator extract_all_lws(InputIterator begin, InputIterator end) {
|
||||
InputIterator old_it;
|
||||
@@ -131,40 +167,21 @@ InputIterator extract_all_lws(InputIterator begin, InputIterator end) {
|
||||
return new_it;
|
||||
}
|
||||
|
||||
/*
|
||||
struct attribute {
|
||||
attribute(const std::string &n, const std::string &v)
|
||||
: name(n), value(v){}
|
||||
|
||||
std::string name;
|
||||
std::string value;
|
||||
};
|
||||
typedef std::vector<attribute> attribute_list;
|
||||
|
||||
struct parameter {
|
||||
parameter(std::string n) : name(n) {}
|
||||
|
||||
void add_attribute(const attribute& p) {
|
||||
attributes.push_back(p);
|
||||
}
|
||||
|
||||
void add_attribute(const std::string& key, const std::string & value) {
|
||||
attributes.push_back(attribute(key,value));
|
||||
}
|
||||
|
||||
std::string name;
|
||||
attribute_list attributes;
|
||||
};
|
||||
typedef std::vector<parameter> parameter_list;
|
||||
*/
|
||||
|
||||
//typedef std::map<std::string,std::string> string_map;
|
||||
//typedef std::vector< std::pair< std::string, attribute_list > > parameter_list;
|
||||
|
||||
typedef std::map<std::string,std::string> attribute_list;
|
||||
//typedef std::map<std::string,attribute_list> parameter_list;
|
||||
typedef std::vector< std::pair< std::string, attribute_list > > parameter_list;
|
||||
|
||||
/// Extract HTTP attributes
|
||||
/**
|
||||
* An http attributes list is a semicolon delimited list of key value pairs in
|
||||
* the format: *( ";" attribute "=" value ) where attribute is a token and value
|
||||
* is a token or quoted string.
|
||||
*
|
||||
* Attributes extracted are appended to the supplied attributes list
|
||||
* `attributes`.
|
||||
*
|
||||
* @param [in] begin An iterator to the beginning of the sequence
|
||||
* @param [in] end An iterator to the end of the sequence
|
||||
* @param [out] attributes A reference to the attributes list to append
|
||||
* attribute/value pairs extracted to
|
||||
* @return An iterator to the character after the last atribute read
|
||||
*/
|
||||
template <typename InputIterator>
|
||||
InputIterator extract_attributes(InputIterator begin, InputIterator end,
|
||||
attribute_list & attributes)
|
||||
@@ -249,9 +266,23 @@ InputIterator extract_attributes(InputIterator begin, InputIterator end,
|
||||
return cursor;
|
||||
}
|
||||
|
||||
/// Extract HTTP parameters
|
||||
/**
|
||||
* An http parameters list is a comma delimited list of tokens followed by
|
||||
* optional semicolon delimited attributes lists.
|
||||
*
|
||||
* Parameters extracted are appended to the supplied parameters list
|
||||
* `parameters`.
|
||||
*
|
||||
* @param [in] begin An iterator to the beginning of the sequence
|
||||
* @param [in] end An iterator to the end of the sequence
|
||||
* @param [out] parameters A reference to the parameters list to append
|
||||
* paramter values extracted to
|
||||
* @return An iterator to the character after the last parameter read
|
||||
*/
|
||||
template <typename InputIterator>
|
||||
InputIterator extract_parameters(InputIterator begin, InputIterator end,
|
||||
parameter_list ¶meters)
|
||||
parameter_list ¶meters)
|
||||
{
|
||||
InputIterator cursor;
|
||||
|
||||
@@ -336,76 +367,107 @@ InputIterator extract_parameters(InputIterator begin, InputIterator end,
|
||||
return cursor;
|
||||
}
|
||||
|
||||
/// Base HTTP parser
|
||||
/**
|
||||
* Includes methods and data elements common to all types of HTTP messages such
|
||||
* as headers, versions, bodies, etc.
|
||||
*/
|
||||
class parser {
|
||||
public:
|
||||
typedef http::parser::attribute_list attribute_list;
|
||||
typedef http::parser::parameter_list parameter_list;
|
||||
|
||||
// Convenience method versions of some of the free utility functions.
|
||||
bool parse_parameter_list(const std::string& in, parameter_list& out) const;
|
||||
|
||||
/// Set the HTTP version string
|
||||
/**
|
||||
* @param version HTTP version string to use. Must be in format HTTP/x.y
|
||||
* where x and y are positive integers.
|
||||
*/
|
||||
void set_version(const std::string& version);
|
||||
|
||||
public:
|
||||
/// Get the HTTP version string
|
||||
const std::string& get_version() const {
|
||||
/**
|
||||
* @return The version string for this parser
|
||||
*/
|
||||
std::string const & get_version() const {
|
||||
return m_version;
|
||||
}
|
||||
|
||||
/// Get the HTTP header with name `key`
|
||||
|
||||
/// Set HTTP parser Version
|
||||
/**
|
||||
* @param key Name of the header to return
|
||||
* @return Value of the header
|
||||
* Input should be in format: HTTP/x.y where x and y are positive integers.
|
||||
* @todo Does this method need any validation?
|
||||
*
|
||||
* @param [in] version The value to set the HTTP version to.
|
||||
*/
|
||||
const std::string& get_header(const std::string& key) const;
|
||||
|
||||
/// Get the body string
|
||||
const std::string& get_body() const {
|
||||
void set_version(std::string const & version);
|
||||
|
||||
/// Get the value of an HTTP header
|
||||
/**
|
||||
* @todo Make this method case insensitive.
|
||||
*
|
||||
* @param [in] key The name/key of the header to get.
|
||||
* @return The value associated with the given HTTP header key.
|
||||
*/
|
||||
std::string const & get_header(std::string const & key) const;
|
||||
|
||||
/// Extract an HTTP parameter list from a parser header.
|
||||
/**
|
||||
* If the header requested doesn't exist or exists and is empty the
|
||||
* parameter list is valid (but empty).
|
||||
*
|
||||
* @param [in] key The name/key of the HTTP header to use as input.
|
||||
* @param [out] out The parameter list to store extracted parameters in.
|
||||
* @return Whether or not the input was a valid parameter list.
|
||||
*/
|
||||
bool get_header_as_plist(std::string const & key, parameter_list & out)
|
||||
const;
|
||||
|
||||
/// Append a value to an existing HTTP header
|
||||
/**
|
||||
* This method will set the value of the HTTP header `key` with the
|
||||
* indicated value. If a header with the name `key` already exists, `val`
|
||||
* will be appended to the existing value.
|
||||
*
|
||||
* @todo Make this method case insensitive.
|
||||
* @todo Should there be any restrictions on which keys are allowed?
|
||||
* @todo Exception free varient
|
||||
*
|
||||
* @see replace_header
|
||||
*
|
||||
* @param [in] key The name/key of the header to append to.
|
||||
* @param [in] val The value to append.
|
||||
*/
|
||||
void append_header(std::string const & key, std::string const & val);
|
||||
|
||||
/// Set a value for an HTTP header, replacing an existing value
|
||||
/**
|
||||
* This method will set the value of the HTTP header `key` with the
|
||||
* indicated value. If a header with the name `key` already exists, `val`
|
||||
* will replace the existing value.
|
||||
*
|
||||
* @todo Make this method case insensitive.
|
||||
* @todo Should there be any restrictions on which keys are allowed?
|
||||
* @todo Exception free varient
|
||||
*
|
||||
* @see append_header
|
||||
*
|
||||
* @param [in] key The name/key of the header to append to.
|
||||
* @param [in] val The value to append.
|
||||
*/
|
||||
void replace_header(std::string const & key, std::string const & val);
|
||||
|
||||
/// Remove a header from the parser
|
||||
/**
|
||||
* Removes the header entirely from the parser. This is different than
|
||||
* setting the value of the header to blank.
|
||||
*
|
||||
* @todo Make this method case insensitive.
|
||||
*
|
||||
* @param [in] key The name/key of the header to remove.
|
||||
*/
|
||||
void remove_header(std::string const & key);
|
||||
|
||||
/// Set HTTP body
|
||||
/**
|
||||
* Sets the body of the HTTP object and fills in the appropriate content
|
||||
* length header.
|
||||
*
|
||||
* @param [in] value The value to set the body to.
|
||||
*/
|
||||
std::string const & get_body() const {
|
||||
return m_body;
|
||||
}
|
||||
|
||||
/// Get the HTTP header with name `key`
|
||||
/**
|
||||
*
|
||||
* @param key The header name to retrieve
|
||||
*
|
||||
* @param out A reference to a parameter list to store any extracted
|
||||
* paramters.
|
||||
*
|
||||
* @return True if the value of this header was not a valid parameter list
|
||||
*/
|
||||
bool get_header_as_plist(const std::string& key, parameter_list& out) const;
|
||||
|
||||
/// Append a header
|
||||
/**
|
||||
* If a header with this name already exists the value will be appended to
|
||||
* the existing header to form a comma separated list of values. Use
|
||||
* replace_header to overwrite existing values.
|
||||
*
|
||||
* @param key Name of the header to set
|
||||
* @param val Value to add
|
||||
* @see replace_header
|
||||
*/
|
||||
void append_header(const std::string &key,const std::string &val);
|
||||
|
||||
/// Replace a header
|
||||
/**
|
||||
* If a header with this name already exists the old value will be replaced
|
||||
* Use add_header to append to a list of existing values.
|
||||
*
|
||||
* @param key Name of the header to set
|
||||
* @param val Value to set
|
||||
* @see add_header
|
||||
*/
|
||||
void replace_header(const std::string &key,const std::string &val);
|
||||
|
||||
/// Remove a header
|
||||
void remove_header(const std::string &key);
|
||||
|
||||
/// Set body content
|
||||
/**
|
||||
* Set the body content of the HTTP response to the parameter string. Note
|
||||
@@ -415,15 +477,41 @@ public:
|
||||
*
|
||||
* @param value String data to include as the body content.
|
||||
*/
|
||||
void set_body(const std::string& value);
|
||||
void set_body(std::string const & value);
|
||||
|
||||
/// Extract an HTTP parameter list from a string.
|
||||
/**
|
||||
* @param [in] in The input string.
|
||||
* @param [out] out The parameter list to store extracted parameters in.
|
||||
* @return Whether or not the input was a valid parameter list.
|
||||
*/
|
||||
bool parse_parameter_list(std::string const & in, parameter_list & out)
|
||||
const;
|
||||
protected:
|
||||
/// DEPRECATED Read headers out of an istream
|
||||
bool parse_headers(std::istream& s);
|
||||
|
||||
/// Helper function for consume. Process header line
|
||||
/// 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.
|
||||
*
|
||||
* @param [in] begin An iterator to the beginning of the sequence.
|
||||
* @param [in] end An iterator to the end of the sequence.
|
||||
*/
|
||||
void process_header(std::string::iterator begin, std::string::iterator end);
|
||||
|
||||
/// Return headers in raw string form.
|
||||
|
||||
/// Generate and return the HTTP headers as a string
|
||||
/**
|
||||
* Each headers will be followed by the \r\n sequence including the last one.
|
||||
* A second \r\n sequence (blank header) is not appended by this method
|
||||
*
|
||||
* @return The HTTP headers as a string.
|
||||
*/
|
||||
std::string raw_headers() const;
|
||||
|
||||
std::string m_version;
|
||||
|
||||
@@ -49,9 +49,6 @@ class request : public parser {
|
||||
public:
|
||||
typedef request type;
|
||||
typedef lib::shared_ptr<type> ptr;
|
||||
|
||||
typedef parser::attribute_list attribute_list;
|
||||
typedef parser::parameter_list parameter_list;
|
||||
|
||||
request()
|
||||
: m_buf(new std::string())
|
||||
|
||||
@@ -577,7 +577,7 @@ void connection<config>::start() {
|
||||
}
|
||||
|
||||
template <typename config>
|
||||
void connection<config>::handle_transport_init(const lib::error_code& ec) {
|
||||
void connection<config>::handle_transport_init(lib::error_code const & ec) {
|
||||
m_alog.write(log::alevel::devel,"connection handle_transport_init");
|
||||
|
||||
{
|
||||
@@ -896,7 +896,10 @@ void connection<config>::handle_read_frame(const lib::error_code& ec,
|
||||
"null message from m_processor");
|
||||
} else if (!is_control(msg->get_opcode())) {
|
||||
// data message, dispatch to user
|
||||
if (m_message_handler) {
|
||||
if (m_state != session::state::open) {
|
||||
m_elog.write(log::elevel::warn,
|
||||
"got non-close data frame in state closing");
|
||||
} else if (m_message_handler) {
|
||||
m_message_handler(m_connection_hdl, msg);
|
||||
}
|
||||
} else {
|
||||
@@ -959,7 +962,7 @@ bool connection<config>::initialize_processor() {
|
||||
std::stringstream ss;
|
||||
std::string sep = "";
|
||||
std::vector<int>::const_iterator it;
|
||||
for (it = VERSIONS_SUPPORTED.begin(); it != VERSIONS_SUPPORTED.end(); it++)
|
||||
for (it = versions_supported.begin(); it != versions_supported.end(); it++)
|
||||
{
|
||||
ss << sep << *it;
|
||||
sep = ",";
|
||||
@@ -978,17 +981,22 @@ bool connection<config>::process_handshake_request() {
|
||||
m_alog.write(log::alevel::devel,"HTTP REQUEST");
|
||||
|
||||
// extract URI from request
|
||||
try {
|
||||
m_uri = processor::get_uri_from_host(m_request,(transport_con_type::is_secure() ? "https" : "http"));
|
||||
} catch (const websocketpp::uri_exception& e) {
|
||||
m_uri = processor::get_uri_from_host(
|
||||
m_request,
|
||||
(transport_con_type::is_secure() ? "https" : "http")
|
||||
);
|
||||
|
||||
if (!m_uri->get_valid()) {
|
||||
m_alog.write(log::alevel::devel,
|
||||
std::string("BAD REQUEST: uri failed to parse: ")+e.what());
|
||||
std::string("Bad request: failed to parse uri"));
|
||||
m_response.set_status(http::status_code::bad_request);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (m_http_handler) {
|
||||
m_http_handler(m_connection_hdl);
|
||||
} else {
|
||||
set_status(http::status_code::upgrade_required);
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -1028,11 +1036,12 @@ bool connection<config>::process_handshake_request() {
|
||||
}
|
||||
|
||||
// extract URI from request
|
||||
try {
|
||||
m_uri = m_processor->get_uri(m_request);
|
||||
} catch (const websocketpp::uri_exception& e) {
|
||||
m_uri = m_processor->get_uri(m_request);
|
||||
|
||||
|
||||
if (!m_uri->get_valid()) {
|
||||
m_alog.write(log::alevel::devel,
|
||||
std::string("BAD REQUEST: uri failed to parse: ")+e.what());
|
||||
std::string("Bad request: failed to parse uri"));
|
||||
m_response.set_status(http::status_code::bad_request);
|
||||
return false;
|
||||
}
|
||||
@@ -1088,10 +1097,14 @@ void connection<config>::send_http_response() {
|
||||
|
||||
m_response.set_version("HTTP/1.1");
|
||||
|
||||
// Set some common headers
|
||||
m_response.replace_header("Server",m_user_agent);
|
||||
|
||||
|
||||
// Set server header based on the user agent settings
|
||||
if (m_response.get_header("Server") == "") {
|
||||
if (!m_user_agent.empty()) {
|
||||
m_response.replace_header("Server",m_user_agent);
|
||||
} else {
|
||||
m_response.remove_header("Server");
|
||||
}
|
||||
}
|
||||
|
||||
// have the processor generate the raw bytes for the wire (if it exists)
|
||||
if (m_processor) {
|
||||
@@ -1201,9 +1214,13 @@ void connection<config>::send_http_request() {
|
||||
return;
|
||||
}
|
||||
|
||||
// Unless the user has overridden the user agent, send generic WS++
|
||||
// Unless the user has overridden the user agent, send generic WS++ UA.
|
||||
if (m_request.get_header("User-Agent") == "") {
|
||||
m_request.replace_header("User-Agent",m_user_agent);
|
||||
if (!m_user_agent.empty()) {
|
||||
m_request.replace_header("User-Agent",m_user_agent);
|
||||
} else {
|
||||
m_request.remove_header("User-Agent");
|
||||
}
|
||||
}
|
||||
|
||||
m_handshake_buffer = m_request.raw();
|
||||
@@ -1620,7 +1637,7 @@ void connection<config>::atomic_state_check(istate_type req,
|
||||
template <typename config>
|
||||
const std::vector<int>& connection<config>::get_supported_versions() const
|
||||
{
|
||||
return VERSIONS_SUPPORTED;
|
||||
return versions_supported;
|
||||
}
|
||||
|
||||
template <typename config>
|
||||
@@ -1635,7 +1652,16 @@ void connection<config>::process_control_frame(typename
|
||||
std::stringstream s;
|
||||
s << "Control frame received with opcode " << op;
|
||||
m_alog.write(log::alevel::control,s.str());
|
||||
|
||||
|
||||
if (m_state == session::state::closed) {
|
||||
m_elog.write(log::elevel::warn,"got frame in state closed");
|
||||
return;
|
||||
}
|
||||
if (op != frame::opcode::CLOSE && m_state != session::state::open) {
|
||||
m_elog.write(log::elevel::warn,"got non-close frame in state closing");
|
||||
return;
|
||||
}
|
||||
|
||||
if (op == frame::opcode::PING) {
|
||||
bool pong = true;
|
||||
|
||||
@@ -1654,6 +1680,9 @@ void connection<config>::process_control_frame(typename
|
||||
if (m_pong_handler) {
|
||||
m_pong_handler(m_connection_hdl, msg->get_payload());
|
||||
}
|
||||
if (m_ping_timer) {
|
||||
m_ping_timer->cancel();
|
||||
}
|
||||
} else if (op == frame::opcode::CLOSE) {
|
||||
m_alog.write(log::alevel::devel,"got close frame");
|
||||
// record close code and reason somewhere
|
||||
@@ -1710,10 +1739,12 @@ void connection<config>::process_control_frame(typename
|
||||
m_elog.write(log::elevel::devel,
|
||||
"send_close_ack error: "+ec.message());
|
||||
}
|
||||
} else if (m_state == session::state::closing) {
|
||||
} else if (m_state == session::state::closing && !m_was_clean) {
|
||||
// ack of our close
|
||||
m_alog.write(log::alevel::devel,"Got acknowledgement of close");
|
||||
|
||||
m_was_clean = true;
|
||||
|
||||
// If we are a server terminate the connection now. Clients should
|
||||
// leave the connection open to give the server an opportunity to
|
||||
// initiate the TCP close. The client's timer will handle closing
|
||||
@@ -1801,6 +1832,10 @@ lib::error_code connection<config>::send_close_frame(close::status::value code,
|
||||
|
||||
m_state = session::state::closing;
|
||||
|
||||
if (ack) {
|
||||
m_was_clean = true;
|
||||
}
|
||||
|
||||
// Start a timer so we don't wait forever for the acknowledgement close
|
||||
// frame
|
||||
m_handshake_timer = transport_con_type::set_timer(
|
||||
|
||||
@@ -109,8 +109,8 @@ void endpoint<connection,config>::interrupt(connection_hdl hdl) {
|
||||
}
|
||||
|
||||
template <typename connection, typename config>
|
||||
void endpoint<connection,config>::send(connection_hdl hdl,
|
||||
const std::string& payload, frame::opcode::value op, lib::error_code & ec)
|
||||
void endpoint<connection,config>::send(connection_hdl hdl, std::string const &
|
||||
payload, frame::opcode::value op, lib::error_code & ec)
|
||||
{
|
||||
connection_ptr con = get_con_from_hdl(hdl,ec);
|
||||
if (ec) {return;}
|
||||
@@ -119,7 +119,7 @@ void endpoint<connection,config>::send(connection_hdl hdl,
|
||||
}
|
||||
|
||||
template <typename connection, typename config>
|
||||
void endpoint<connection,config>::send(connection_hdl hdl, const std::string&
|
||||
void endpoint<connection,config>::send(connection_hdl hdl, std::string const &
|
||||
payload, frame::opcode::value op)
|
||||
{
|
||||
lib::error_code ec;
|
||||
@@ -128,7 +128,7 @@ void endpoint<connection,config>::send(connection_hdl hdl, const std::string&
|
||||
}
|
||||
|
||||
template <typename connection, typename config>
|
||||
void endpoint<connection,config>::send(connection_hdl hdl, const void * payload,
|
||||
void endpoint<connection,config>::send(connection_hdl hdl, void const * payload,
|
||||
size_t len, frame::opcode::value op, lib::error_code & ec)
|
||||
{
|
||||
connection_ptr con = get_con_from_hdl(hdl,ec);
|
||||
@@ -137,7 +137,7 @@ void endpoint<connection,config>::send(connection_hdl hdl, const void * payload,
|
||||
}
|
||||
|
||||
template <typename connection, typename config>
|
||||
void endpoint<connection,config>::send(connection_hdl hdl, const void * payload,
|
||||
void endpoint<connection,config>::send(connection_hdl hdl, void const * payload,
|
||||
size_t len, frame::opcode::value op)
|
||||
{
|
||||
lib::error_code ec;
|
||||
@@ -162,8 +162,8 @@ void endpoint<connection,config>::send(connection_hdl hdl, message_ptr msg) {
|
||||
}
|
||||
|
||||
template <typename connection, typename config>
|
||||
void endpoint<connection,config>::close(connection_hdl hdl,
|
||||
const close::status::value code, const std::string & reason,
|
||||
void endpoint<connection,config>::close(connection_hdl hdl, close::status::value
|
||||
const code, std::string const & reason,
|
||||
lib::error_code & ec)
|
||||
{
|
||||
connection_ptr con = get_con_from_hdl(hdl,ec);
|
||||
@@ -172,14 +172,50 @@ void endpoint<connection,config>::close(connection_hdl hdl,
|
||||
}
|
||||
|
||||
template <typename connection, typename config>
|
||||
void endpoint<connection,config>::close(connection_hdl hdl,
|
||||
const close::status::value code, const std::string & reason)
|
||||
void endpoint<connection,config>::close(connection_hdl hdl, close::status::value
|
||||
const code, std::string const & reason)
|
||||
{
|
||||
lib::error_code ec;
|
||||
close(hdl,code,reason,ec);
|
||||
if (ec) { throw ec; }
|
||||
}
|
||||
|
||||
template <typename connection, typename config>
|
||||
void endpoint<connection,config>::ping(connection_hdl hdl, std::string const &
|
||||
payload, lib::error_code & ec)
|
||||
{
|
||||
connection_ptr con = get_con_from_hdl(hdl,ec);
|
||||
if (ec) {return;}
|
||||
con->ping(payload,ec);
|
||||
}
|
||||
|
||||
template <typename connection, typename config>
|
||||
void endpoint<connection,config>::ping(connection_hdl hdl, std::string const &
|
||||
payload)
|
||||
{
|
||||
lib::error_code ec;
|
||||
ping(hdl,payload,ec);
|
||||
if (ec) { throw ec; }
|
||||
}
|
||||
|
||||
template <typename connection, typename config>
|
||||
void endpoint<connection,config>::pong(connection_hdl hdl, std::string const &
|
||||
payload, lib::error_code & ec)
|
||||
{
|
||||
connection_ptr con = get_con_from_hdl(hdl,ec);
|
||||
if (ec) {return;}
|
||||
con->pong(payload,ec);
|
||||
}
|
||||
|
||||
template <typename connection, typename config>
|
||||
void endpoint<connection,config>::pong(connection_hdl hdl, std::string const &
|
||||
payload)
|
||||
{
|
||||
lib::error_code ec;
|
||||
pong(hdl,payload,ec);
|
||||
if (ec) { throw ec; }
|
||||
}
|
||||
|
||||
template <typename connection, typename config>
|
||||
void endpoint<connection,config>::remove_connection(connection_ptr con) {
|
||||
std::stringstream s;
|
||||
|
||||
@@ -31,6 +31,12 @@
|
||||
namespace websocketpp {
|
||||
namespace utility {
|
||||
|
||||
inline std::string to_lower(std::string const & in) {
|
||||
std::string out = in;
|
||||
std::transform(out.begin(),out.end(),out.begin(),::tolower);
|
||||
return out;
|
||||
}
|
||||
|
||||
inline std::string to_hex(const std::string& input) {
|
||||
std::string output;
|
||||
std::string hex = "0123456789ABCDEF";
|
||||
|
||||
@@ -42,6 +42,7 @@
|
||||
|
||||
#include <ctime>
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
|
||||
#include <websocketpp/common/stdint.hpp>
|
||||
#include <websocketpp/logger/levels.hpp>
|
||||
@@ -85,7 +86,7 @@ public:
|
||||
void write(level channel, const std::string& msg) {
|
||||
scoped_lock_type lock(m_lock);
|
||||
if (!this->dynamic_test(channel)) { return; }
|
||||
*m_out << "[" << get_timestamp() << "] "
|
||||
*m_out << "[" << timestamp << "] "
|
||||
<< "[" << names::channel_name(channel) << "] "
|
||||
<< msg << "\n";
|
||||
m_out->flush();
|
||||
@@ -94,7 +95,7 @@ public:
|
||||
void write(level channel, const char* msg) {
|
||||
scoped_lock_type lock(m_lock);
|
||||
if (!this->dynamic_test(channel)) { return; }
|
||||
*m_out << "[" << get_timestamp() << "] "
|
||||
*m_out << "[" << timestamp << "] "
|
||||
<< "[" << names::channel_name(channel) << "] "
|
||||
<< msg << "\n";
|
||||
m_out->flush();
|
||||
@@ -111,17 +112,25 @@ private:
|
||||
typedef typename concurrency::scoped_lock_type scoped_lock_type;
|
||||
typedef typename concurrency::mutex_type mutex_type;
|
||||
|
||||
// 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.
|
||||
std::string get_timestamp() {
|
||||
// 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.
|
||||
//
|
||||
// TODO: find a workaround for this or make this format user settable
|
||||
static std::ostream& timestamp(std::ostream& os) {
|
||||
std::time_t t = std::time(NULL);
|
||||
char buffer[40];
|
||||
std::strftime(buffer,sizeof(buffer),"%Y-%m-%d %H:%M:%S",std::localtime(&t));
|
||||
return buffer;
|
||||
std::tm* lt = std::localtime(&t);
|
||||
#ifdef _WEBSOCKETPP_CPP11_CHRONO_
|
||||
return os << std::put_time(lt,"%Y-%m-%d %H:%M:%S");
|
||||
#else // Falls back to strftime, which requires a temporary copy of the string.
|
||||
char buffer[20];
|
||||
std::strftime(buffer,sizeof(buffer),"%Y-%m-%d %H:%M:%S",lt);
|
||||
return os << buffer;
|
||||
#endif
|
||||
}
|
||||
|
||||
mutex_type m_lock;
|
||||
|
||||
|
||||
const level m_static_channels;
|
||||
level m_dynamic_channels;
|
||||
std::ostream* m_out;
|
||||
|
||||
@@ -44,14 +44,14 @@ namespace processor {
|
||||
/// Constants related to processing WebSocket connections
|
||||
namespace constants {
|
||||
|
||||
static const char upgrade_token[] = "websocket";
|
||||
static const char connection_token[] = "upgrade";
|
||||
static const char handshake_guid[] = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
|
||||
static char const upgrade_token[] = "websocket";
|
||||
static char const connection_token[] = "upgrade";
|
||||
static char const handshake_guid[] = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
|
||||
|
||||
} // namespace constants
|
||||
|
||||
|
||||
// Processor class related error codes
|
||||
/// Processor class related error codes
|
||||
namespace error_cat {
|
||||
enum value {
|
||||
BAD_REQUEST = 0, // Error was the result of improperly formatted user input
|
||||
@@ -62,17 +62,7 @@ enum value {
|
||||
};
|
||||
} // namespace error_cat
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Generic Processor error codes usable by all processor types
|
||||
*/
|
||||
/// Error code category and codes used by all processor types
|
||||
namespace error {
|
||||
enum processor_errors {
|
||||
/// Catch-all error for processor policy errors that don't fit in other
|
||||
@@ -164,11 +154,12 @@ enum processor_errors {
|
||||
extensions_disabled
|
||||
};
|
||||
|
||||
/// Category for processor errors
|
||||
class processor_category : public lib::error_category {
|
||||
public:
|
||||
processor_category() {}
|
||||
|
||||
const char *name() const _WEBSOCKETPP_NOEXCEPT_TOKEN_ {
|
||||
char const * name() const _WEBSOCKETPP_NOEXCEPT_TOKEN_ {
|
||||
return "websocketpp.processor";
|
||||
}
|
||||
|
||||
@@ -238,11 +229,13 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
inline const lib::error_category& get_processor_category() {
|
||||
/// Get a reference to a static copy of the processor error category
|
||||
inline lib::error_category const & get_processor_category() {
|
||||
static processor_category instance;
|
||||
return instance;
|
||||
}
|
||||
|
||||
/// Create an error code with the given value and the processor category
|
||||
inline lib::error_code make_error_code(error::processor_errors e) {
|
||||
return lib::error_code(static_cast<int>(e), get_processor_category());
|
||||
}
|
||||
@@ -290,10 +283,11 @@ inline close::status::value to_ws(lib::error_code ec) {
|
||||
} // namespace error
|
||||
} // namespace processor
|
||||
} // namespace websocketpp
|
||||
|
||||
_WEBSOCKETPP_ERROR_CODE_ENUM_NS_START_
|
||||
template<> struct is_error_code_enum<websocketpp::processor::error::processor_errors>
|
||||
{
|
||||
static const bool value = true;
|
||||
static bool const value = true;
|
||||
};
|
||||
_WEBSOCKETPP_ERROR_CODE_ENUM_NS_END_
|
||||
|
||||
|
||||
@@ -30,20 +30,13 @@
|
||||
|
||||
#include <cstdlib>
|
||||
|
||||
// For htonl
|
||||
#if defined(WIN32)
|
||||
#include <winsock2.h>
|
||||
#else
|
||||
#include <arpa/inet.h>
|
||||
#endif
|
||||
|
||||
#include <websocketpp/processors/processor.hpp>
|
||||
|
||||
#include <websocketpp/frame.hpp>
|
||||
#include <websocketpp/utf8_validator.hpp>
|
||||
|
||||
#include <websocketpp/common/network.hpp>
|
||||
#include <websocketpp/common/md5.hpp>
|
||||
|
||||
#include <websocketpp/processors/processor.hpp>
|
||||
|
||||
namespace websocketpp {
|
||||
namespace processor {
|
||||
|
||||
@@ -75,7 +68,7 @@ public:
|
||||
return 0;
|
||||
}
|
||||
|
||||
lib::error_code validate_handshake(const request_type& r) const {
|
||||
lib::error_code validate_handshake(request_type const & r) const {
|
||||
if (r.get_method() != "GET") {
|
||||
return make_error_code(error::invalid_http_method);
|
||||
}
|
||||
@@ -98,8 +91,8 @@ public:
|
||||
return lib::error_code();
|
||||
}
|
||||
|
||||
lib::error_code process_handshake(const request_type& req, const
|
||||
std::string & subprotocol, response_type& res) const
|
||||
lib::error_code process_handshake(request_type const & req,
|
||||
std::string const & subprotocol, response_type & res) const
|
||||
{
|
||||
char key_final[16];
|
||||
|
||||
@@ -148,36 +141,36 @@ public:
|
||||
}
|
||||
|
||||
// outgoing client connection processing is not supported for this version
|
||||
lib::error_code client_handshake_request(request_type& req, uri_ptr uri,
|
||||
const std::vector<std::string> & subprotocols) const
|
||||
lib::error_code client_handshake_request(request_type& req, uri_ptr uri,
|
||||
std::vector<std::string> const & subprotocols) const
|
||||
{
|
||||
return error::make_error_code(error::no_protocol_support);
|
||||
}
|
||||
|
||||
lib::error_code validate_server_handshake_response(const request_type& req,
|
||||
response_type& res) const
|
||||
lib::error_code validate_server_handshake_response(request_type const & req,
|
||||
response_type & res) const
|
||||
{
|
||||
return error::make_error_code(error::no_protocol_support);
|
||||
}
|
||||
|
||||
std::string get_raw(const response_type& res) const {
|
||||
std::string get_raw(response_type const & res) const {
|
||||
response_type temp = res;
|
||||
temp.remove_header("Sec-WebSocket-Key3");
|
||||
return temp.raw() + res.get_header("Sec-WebSocket-Key3");
|
||||
}
|
||||
|
||||
const std::string& get_origin(const request_type& r) const {
|
||||
std::string const & get_origin(request_type const & r) const {
|
||||
return r.get_header("Origin");
|
||||
}
|
||||
|
||||
// hybi00 doesn't support subprotocols so there never will be any requested
|
||||
lib::error_code extract_subprotocols(const request_type & req,
|
||||
lib::error_code extract_subprotocols(request_type const & req,
|
||||
std::vector<std::string> & subprotocol_list)
|
||||
{
|
||||
return lib::error_code();
|
||||
}
|
||||
|
||||
uri_ptr get_uri(const request_type& request) const {
|
||||
uri_ptr get_uri(request_type const & request) const {
|
||||
std::string h = request.get_header("Host");
|
||||
|
||||
size_t last_colon = h.rfind(":");
|
||||
@@ -202,6 +195,11 @@ public:
|
||||
// TODO: check if get_uri is a full uri
|
||||
}
|
||||
|
||||
/// Get hybi00 handshake key3
|
||||
/**
|
||||
* @todo This doesn't appear to be used anymore. It might be able to be
|
||||
* removed
|
||||
*/
|
||||
std::string get_key3() const {
|
||||
return "";
|
||||
}
|
||||
@@ -306,11 +304,11 @@ public:
|
||||
}
|
||||
|
||||
// generate header
|
||||
out->set_header(std::string(reinterpret_cast<const char*>(&msg_hdr),1));
|
||||
out->set_header(std::string(reinterpret_cast<char const *>(&msg_hdr),1));
|
||||
|
||||
// process payload
|
||||
out->set_payload(i);
|
||||
out->append_payload(std::string(reinterpret_cast<const char*>(&msg_ftr),1));
|
||||
out->append_payload(std::string(reinterpret_cast<char const *>(&msg_ftr),1));
|
||||
|
||||
// hybi00 doesn't support compression
|
||||
// hybi00 doesn't have masking
|
||||
@@ -320,7 +318,7 @@ public:
|
||||
return lib::error_code();
|
||||
}
|
||||
|
||||
lib::error_code prepare_ping(const std::string & in, message_ptr out) const
|
||||
lib::error_code prepare_ping(std::string const & in, message_ptr out) const
|
||||
{
|
||||
return lib::error_code(error::no_protocol_support);
|
||||
}
|
||||
@@ -330,8 +328,8 @@ public:
|
||||
return lib::error_code(error::no_protocol_support);
|
||||
}
|
||||
|
||||
lib::error_code prepare_close(close::status::value code,
|
||||
const std::string & reason, message_ptr out) const
|
||||
lib::error_code prepare_close(close::status::value code,
|
||||
std::string const & reason, message_ptr out) const
|
||||
{
|
||||
if (!out) {
|
||||
return lib::error_code(error::invalid_arguments);
|
||||
@@ -346,7 +344,7 @@ public:
|
||||
return lib::error_code();
|
||||
}
|
||||
private:
|
||||
void decode_client_key(const std::string& key, char* result) const {
|
||||
void decode_client_key(std::string const & key, char * result) const {
|
||||
unsigned int spaces = 0;
|
||||
std::string digits = "";
|
||||
uint32_t num;
|
||||
@@ -378,8 +376,8 @@ private:
|
||||
FATAL_ERROR = 3
|
||||
};
|
||||
|
||||
const uint8_t msg_hdr;
|
||||
const uint8_t msg_ftr;
|
||||
uint8_t const msg_hdr;
|
||||
uint8_t const msg_ftr;
|
||||
|
||||
state m_state;
|
||||
|
||||
@@ -388,7 +386,6 @@ private:
|
||||
utf8_validator::validator m_validator;
|
||||
};
|
||||
|
||||
|
||||
} // namespace processor
|
||||
} // namespace websocketpp
|
||||
|
||||
|
||||
@@ -41,28 +41,27 @@ template <typename config>
|
||||
class hybi07 : public hybi08<config> {
|
||||
public:
|
||||
typedef typename config::request_type request_type;
|
||||
|
||||
|
||||
typedef typename config::con_msg_manager_type::ptr msg_manager_ptr;
|
||||
typedef typename config::rng_type rng_type;
|
||||
|
||||
explicit hybi07(bool secure,bool server, msg_manager_ptr manager,
|
||||
rng_type& rng)
|
||||
: hybi08<config>(secure, server, manager, rng) {}
|
||||
|
||||
|
||||
explicit hybi07(bool secure, bool server, msg_manager_ptr manager,
|
||||
rng_type& rng)
|
||||
: hybi08<config>(secure, server, manager, rng) {}
|
||||
|
||||
// outgoing client connection processing is not supported for this version
|
||||
lib::error_code client_handshake_request(request_type& req, uri_ptr uri,
|
||||
const std::vector<std::string> & subprotocols) const
|
||||
lib::error_code client_handshake_request(request_type & req, uri_ptr uri,
|
||||
std::vector<std::string> const & subprotocols) const
|
||||
{
|
||||
return error::make_error_code(error::no_protocol_support);
|
||||
}
|
||||
|
||||
|
||||
int get_version() const {
|
||||
return 7;
|
||||
}
|
||||
private:
|
||||
};
|
||||
|
||||
|
||||
} // namespace processor
|
||||
} // namespace websocketpp
|
||||
|
||||
|
||||
@@ -51,8 +51,8 @@ public:
|
||||
: hybi13<config>(secure, server, manager, rng) {}
|
||||
|
||||
// outgoing client connection processing is not supported for this version
|
||||
lib::error_code client_handshake_request(request_type& req, uri_ptr uri,
|
||||
const std::vector<std::string> & subprotocols) const
|
||||
lib::error_code client_handshake_request(request_type& req, uri_ptr uri,
|
||||
std::vector<std::string> const & subprotocols) const
|
||||
{
|
||||
return error::make_error_code(error::no_protocol_support);
|
||||
}
|
||||
@@ -61,13 +61,12 @@ public:
|
||||
return 8;
|
||||
}
|
||||
|
||||
const std::string& get_origin(const request_type& r) const {
|
||||
const std::string& get_origin(request_type const & r) const {
|
||||
return r.get_header("Sec-WebSocket-Origin");
|
||||
}
|
||||
private:
|
||||
};
|
||||
|
||||
|
||||
} // namespace processor
|
||||
} // namespace websocketpp
|
||||
|
||||
|
||||
@@ -28,18 +28,11 @@
|
||||
#ifndef WEBSOCKETPP_PROCESSOR_HYBI13_HPP
|
||||
#define WEBSOCKETPP_PROCESSOR_HYBI13_HPP
|
||||
|
||||
// For htonl
|
||||
#if defined(WIN32)
|
||||
#include <winsock2.h>
|
||||
#else
|
||||
#include <arpa/inet.h>
|
||||
#endif
|
||||
|
||||
#include <cassert>
|
||||
|
||||
#include <websocketpp/frame.hpp>
|
||||
#include <websocketpp/utf8_validator.hpp>
|
||||
|
||||
#include <websocketpp/common/network.hpp>
|
||||
#include <websocketpp/http/constants.hpp>
|
||||
|
||||
#include <websocketpp/processors/processor.hpp>
|
||||
@@ -91,7 +84,7 @@ public:
|
||||
return m_permessage_deflate.is_implemented();
|
||||
}
|
||||
|
||||
err_str_pair negotiate_extensions(const request_type& req) {
|
||||
err_str_pair negotiate_extensions(request_type const & req) {
|
||||
err_str_pair ret;
|
||||
|
||||
// Respect blanket disabling of all extensions and don't even parse
|
||||
@@ -101,7 +94,7 @@ public:
|
||||
return ret;
|
||||
}
|
||||
|
||||
typename request_type::parameter_list p;
|
||||
http::parameter_list p;
|
||||
|
||||
bool error = req.get_header_as_plist("Sec-WebSocket-Extensions",p);
|
||||
|
||||
@@ -115,18 +108,15 @@ public:
|
||||
return ret;
|
||||
}
|
||||
|
||||
typename request_type::parameter_list::const_iterator it;
|
||||
http::parameter_list::const_iterator it;
|
||||
|
||||
if (m_permessage_deflate.is_implemented()) {
|
||||
err_str_pair neg_ret;
|
||||
for (it = p.begin(); it != p.end(); ++it) {
|
||||
// look through each extension, if the key is permessage-deflate
|
||||
if (it->first == "permessage-deflate") {
|
||||
std::cout << "mark3: " << std::endl;
|
||||
neg_ret = m_permessage_deflate.negotiate(it->second);
|
||||
|
||||
std::cout << neg_ret.first.message() << " - " << neg_ret.second << std::endl;
|
||||
|
||||
if (neg_ret.first) {
|
||||
// Figure out if this is an error that should halt all
|
||||
// extension negotiations or simply cause negotiation of
|
||||
@@ -146,7 +136,7 @@ public:
|
||||
return ret;
|
||||
}
|
||||
|
||||
lib::error_code validate_handshake(const request_type& r) const {
|
||||
lib::error_code validate_handshake(request_type const & r) const {
|
||||
if (r.get_method() != "GET") {
|
||||
return make_error_code(error::invalid_http_method);
|
||||
}
|
||||
@@ -170,7 +160,7 @@ public:
|
||||
* generic struct if other user input parameters to the processed handshake
|
||||
* are found.
|
||||
*/
|
||||
lib::error_code process_handshake(const request_type& request, const
|
||||
lib::error_code process_handshake(request_type const & request, const
|
||||
std::string & subprotocol, response_type& response) const
|
||||
{
|
||||
std::string server_key = request.get_header("Sec-WebSocket-Key");
|
||||
@@ -193,7 +183,7 @@ public:
|
||||
}
|
||||
|
||||
lib::error_code client_handshake_request(request_type& req, uri_ptr
|
||||
uri, const std::vector<std::string> & subprotocols) const
|
||||
uri, std::vector<std::string> const & subprotocols) const
|
||||
{
|
||||
req.set_method("GET");
|
||||
req.set_uri(uri->get_resource());
|
||||
@@ -229,7 +219,7 @@ public:
|
||||
return lib::error_code();
|
||||
}
|
||||
|
||||
lib::error_code validate_server_handshake_response(const request_type& req,
|
||||
lib::error_code validate_server_handshake_response(request_type const & req,
|
||||
response_type& res) const
|
||||
{
|
||||
// A valid response has an HTTP 101 switching protocols code
|
||||
@@ -238,7 +228,7 @@ public:
|
||||
}
|
||||
|
||||
// And the upgrade token in an upgrade header
|
||||
const std::string& upgrade_header = res.get_header("Upgrade");
|
||||
std::string const & upgrade_header = res.get_header("Upgrade");
|
||||
if (utility::ci_find_substr(upgrade_header, constants::upgrade_token,
|
||||
sizeof(constants::upgrade_token)-1) == upgrade_header.end())
|
||||
{
|
||||
@@ -246,7 +236,7 @@ public:
|
||||
}
|
||||
|
||||
// And the websocket token in the connection header
|
||||
const std::string& con_header = res.get_header("Connection");
|
||||
std::string const & con_header = res.get_header("Connection");
|
||||
if (utility::ci_find_substr(con_header, constants::connection_token,
|
||||
sizeof(constants::connection_token)-1) == con_header.end())
|
||||
{
|
||||
@@ -264,22 +254,22 @@ public:
|
||||
return lib::error_code();
|
||||
}
|
||||
|
||||
std::string get_raw(const response_type& res) const {
|
||||
std::string get_raw(response_type const & res) const {
|
||||
return res.raw();
|
||||
}
|
||||
|
||||
const std::string& get_origin(const request_type& r) const {
|
||||
std::string const & get_origin(request_type const & r) const {
|
||||
return r.get_header("Origin");
|
||||
}
|
||||
|
||||
lib::error_code extract_subprotocols(const request_type & req,
|
||||
lib::error_code extract_subprotocols(request_type const & req,
|
||||
std::vector<std::string> & subprotocol_list)
|
||||
{
|
||||
if (!req.get_header("Sec-WebSocket-Protocol").empty()) {
|
||||
typename request_type::parameter_list p;
|
||||
http::parameter_list p;
|
||||
|
||||
if (!req.get_header_as_plist("Sec-WebSocket-Protocol",p)) {
|
||||
typename request_type::parameter_list::const_iterator it;
|
||||
http::parameter_list::const_iterator it;
|
||||
|
||||
for (it = p.begin(); it != p.end(); ++it) {
|
||||
subprotocol_list.push_back(it->first);
|
||||
@@ -291,7 +281,7 @@ public:
|
||||
return lib::error_code();
|
||||
}
|
||||
|
||||
uri_ptr get_uri(const request_type& request) const {
|
||||
uri_ptr get_uri(request_type const & request) const {
|
||||
return get_uri_from_host(request,(base::m_secure ? "wss" : "ws"));
|
||||
}
|
||||
|
||||
@@ -503,9 +493,7 @@ public:
|
||||
* TODO: tests
|
||||
*
|
||||
* @param in An unprepared message to prepare
|
||||
*
|
||||
* @param out A message to be overwritten with the prepared message
|
||||
*
|
||||
* @return error code
|
||||
*/
|
||||
virtual lib::error_code prepare_data_frame(message_ptr in, message_ptr out)
|
||||
@@ -577,16 +565,17 @@ public:
|
||||
return lib::error_code();
|
||||
}
|
||||
|
||||
lib::error_code prepare_ping(const std::string& in, message_ptr out) const {
|
||||
/// Get URI
|
||||
lib::error_code prepare_ping(std::string const & in, message_ptr out) const {
|
||||
return this->prepare_control(frame::opcode::PING,in,out);
|
||||
}
|
||||
|
||||
lib::error_code prepare_pong(const std::string& in, message_ptr out) const {
|
||||
lib::error_code prepare_pong(std::string const & in, message_ptr out) const {
|
||||
return this->prepare_control(frame::opcode::PONG,in,out);
|
||||
}
|
||||
|
||||
virtual lib::error_code prepare_close(close::status::value code,
|
||||
const std::string & reason, message_ptr out) const
|
||||
std::string const & reason, message_ptr out) const
|
||||
{
|
||||
if (close::status::reserved(code)) {
|
||||
return make_error_code(error::reserved_close_code);
|
||||
@@ -625,12 +614,12 @@ protected:
|
||||
lib::error_code process_handshake_key(std::string & key) const {
|
||||
key.append(constants::handshake_guid);
|
||||
|
||||
SHA1 sha;
|
||||
uint32_t message_digest[5];
|
||||
sha1 sha;
|
||||
uint32_t message_digest[5];
|
||||
|
||||
sha << key.c_str();
|
||||
|
||||
if (sha.Result(message_digest)){
|
||||
if (sha.get_raw_digest(message_digest)){
|
||||
// convert sha1 hash bytes to network byte order because this sha1
|
||||
// library works on ints rather than bytes
|
||||
for (int i = 0; i < 5; i++) {
|
||||
@@ -638,7 +627,7 @@ protected:
|
||||
}
|
||||
|
||||
key = base64_encode(
|
||||
reinterpret_cast<const unsigned char*>(message_digest),
|
||||
reinterpret_cast<unsigned char const *>(message_digest),
|
||||
20
|
||||
);
|
||||
|
||||
@@ -649,7 +638,7 @@ protected:
|
||||
}
|
||||
|
||||
/// Reads bytes from buf into m_basic_header
|
||||
size_t copy_basic_header_bytes(const uint8_t * buf, size_t len) {
|
||||
size_t copy_basic_header_bytes(uint8_t const * buf, size_t len) {
|
||||
if (len == 0 || m_bytes_needed == 0) {
|
||||
return 0;
|
||||
}
|
||||
@@ -681,7 +670,7 @@ protected:
|
||||
}
|
||||
|
||||
/// Reads bytes from buf into m_extended_header
|
||||
size_t copy_extended_header_bytes(const uint8_t * buf, size_t len) {
|
||||
size_t copy_extended_header_bytes(uint8_t const * buf, size_t len) {
|
||||
size_t bytes_to_read = std::min(m_bytes_needed,len);
|
||||
|
||||
std::copy(buf,buf+bytes_to_read,m_extended_header.bytes+m_cursor);
|
||||
@@ -701,24 +690,29 @@ protected:
|
||||
* bytes actually needed. At most min(m_bytes_needed,len) will be processed.
|
||||
*
|
||||
* @param buf Input/working buffer
|
||||
*
|
||||
* @param len Length of buf
|
||||
*
|
||||
* @return Number of bytes processed or zero in case of an error
|
||||
*
|
||||
*/
|
||||
size_t process_payload_bytes(uint8_t * buf, size_t len, lib::error_code& ec)
|
||||
{
|
||||
// unmask if masked
|
||||
if (frame::get_masked(m_basic_header)) {
|
||||
m_current_msg->prepared_key = frame::word_mask_circ(
|
||||
buf,
|
||||
len,
|
||||
m_current_msg->prepared_key
|
||||
);
|
||||
#ifdef WEBSOCKETPP_STRICT_MASKING
|
||||
m_current_msg->prepared_key = frame::byte_mask_circ(
|
||||
buf,
|
||||
len,
|
||||
m_current_msg->prepared_key
|
||||
);
|
||||
#else
|
||||
m_current_msg->prepared_key = frame::word_mask_circ(
|
||||
buf,
|
||||
len,
|
||||
m_current_msg->prepared_key
|
||||
);
|
||||
#endif
|
||||
}
|
||||
|
||||
std::string& out = m_current_msg->msg_ptr->get_raw_payload();
|
||||
std::string & out = m_current_msg->msg_ptr->get_raw_payload();
|
||||
size_t offset = out.size();
|
||||
|
||||
// decompress message if needed.
|
||||
@@ -758,15 +752,12 @@ protected:
|
||||
* Validates an incoming hybi13 basic header.
|
||||
*
|
||||
* @param h The basic header to validate
|
||||
*
|
||||
* @param is_server Whether or not the endpoint that received this frame
|
||||
* is a server.
|
||||
*
|
||||
* @param new_msg Whether or not this is the first frame of the message
|
||||
*
|
||||
* @return 0 on success or a non-zero error code on failure
|
||||
*/
|
||||
lib::error_code validate_incoming_basic_header(const frame::basic_header &h,
|
||||
lib::error_code validate_incoming_basic_header(frame::basic_header const & h,
|
||||
bool is_server, bool new_msg) const
|
||||
{
|
||||
frame::opcode::value op = frame::get_opcode(h);
|
||||
@@ -837,15 +828,15 @@ protected:
|
||||
/**
|
||||
* Validates an incoming hybi13 full header.
|
||||
*
|
||||
* @todo unit test for the >32 bit frames on 32 bit systems case
|
||||
*
|
||||
* @param h The basic header to validate
|
||||
*
|
||||
* @param e The extended header to validate
|
||||
*
|
||||
* @return An error_code, non-zero values indicate why the validation
|
||||
* failed
|
||||
*/
|
||||
lib::error_code validate_incoming_extended_header(const frame::basic_header h,
|
||||
const frame::extended_header e) const
|
||||
lib::error_code validate_incoming_extended_header(frame::basic_header h,
|
||||
frame::extended_header e) const
|
||||
{
|
||||
uint8_t basic_size = frame::get_basic_size(h);
|
||||
uint64_t payload_size = frame::get_payload_size(h,e);
|
||||
@@ -864,7 +855,6 @@ protected:
|
||||
}
|
||||
|
||||
// Check for >32bit frames on 32 bit systems
|
||||
// TODO: unit test for this case
|
||||
if (sizeof(size_t) == 4 && (payload_size >> 32)) {
|
||||
return make_error_code(error::requires_64bit);
|
||||
}
|
||||
@@ -872,15 +862,23 @@ protected:
|
||||
return lib::error_code();
|
||||
}
|
||||
|
||||
void masked_copy (const std::string & i, std::string & o,
|
||||
/// Copy and mask/unmask in one operation
|
||||
/**
|
||||
* Reads input from one string and writes unmasked output to another.
|
||||
*
|
||||
* @param [in] i The input string.
|
||||
* @param [out] o The output string.
|
||||
* @param [in] key The masking key to use for masking/unmasking
|
||||
*/
|
||||
void masked_copy (std::string const & i, std::string & o,
|
||||
frame::masking_key_type key) const
|
||||
{
|
||||
#ifdef WEBSOCKETPP_STRICT_MASKING
|
||||
frame::byte_mask(i.begin(),i.end(),o.begin(),key);
|
||||
#else
|
||||
websocketpp::frame::word_mask_exact(
|
||||
reinterpret_cast<uint8_t*>(const_cast<char*>(i.data())),
|
||||
reinterpret_cast<uint8_t*>(const_cast<char*>(o.data())),
|
||||
reinterpret_cast<uint8_t *>(const_cast<char *>(i.data())),
|
||||
reinterpret_cast<uint8_t *>(const_cast<char *>(o.data())),
|
||||
i.size(),
|
||||
key
|
||||
);
|
||||
@@ -892,15 +890,12 @@ protected:
|
||||
* Internal control frame building method. Handles validation, masking, etc
|
||||
*
|
||||
* @param op The control opcode to use
|
||||
*
|
||||
* @param payload The payload to use
|
||||
*
|
||||
* @param out The message buffer to store the prepared frame in
|
||||
*
|
||||
* @return Status code, zero on success, non-zero on error
|
||||
*/
|
||||
lib::error_code prepare_control(frame::opcode::value op,
|
||||
const std::string & payload, message_ptr out) const
|
||||
std::string const & payload, message_ptr out) const
|
||||
{
|
||||
if (!out) {
|
||||
return make_error_code(error::invalid_arguments);
|
||||
@@ -984,7 +979,7 @@ protected:
|
||||
msg_metadata m_control_msg;
|
||||
|
||||
// Pointer to the metadata associated with the frame being read
|
||||
msg_metadata *m_current_msg;
|
||||
msg_metadata * m_current_msg;
|
||||
|
||||
// Extended header of current frame
|
||||
frame::extended_header m_extended_header;
|
||||
@@ -995,7 +990,7 @@ protected:
|
||||
// utf8 validator
|
||||
// compression state
|
||||
|
||||
rng_type& m_rng;
|
||||
rng_type & m_rng;
|
||||
|
||||
// Overall state of the processor
|
||||
state m_state;
|
||||
|
||||
@@ -39,23 +39,34 @@
|
||||
#include <string>
|
||||
|
||||
namespace websocketpp {
|
||||
/// Processors encapsulate the protocol rules specific to each WebSocket version
|
||||
/**
|
||||
* The processors namespace includes a number of free functions that operate on
|
||||
* various WebSocket related data structures and perform processing that is not
|
||||
* related to specific versions of the protocol.
|
||||
*
|
||||
* It also includes the abstract interface for the protocol specific processing
|
||||
* engines. These engines wrap all of the logic necessary for parsing and
|
||||
* validating WebSocket handshakes and messages of specific protocol version
|
||||
* and set of allowed extensions.
|
||||
*
|
||||
* An instance of a processor represents the state of a single WebSocket
|
||||
* connection of the associated version. One processor instance is needed per
|
||||
* logical WebSocket connection.
|
||||
*/
|
||||
namespace processor {
|
||||
|
||||
// Free functions related to version/protocol independent WebSocket handshake
|
||||
// processing
|
||||
|
||||
/// Determine whether or not a generic HTTP request is a WebSocket handshake
|
||||
/// request_type
|
||||
/// Determine whether or not a generic HTTP request is a WebSocket handshake
|
||||
/**
|
||||
* @param r The HTTP request to read.
|
||||
*
|
||||
* @return true if the request is a WebSocket handshake, false otherwise
|
||||
* @return True if the request is a WebSocket handshake, false otherwise
|
||||
*/
|
||||
template <typename request_type>
|
||||
bool is_websocket_handshake(request_type& r) {
|
||||
using utility::ci_find_substr;
|
||||
|
||||
const std::string& upgrade_header = r.get_header("Upgrade");
|
||||
std::string const & upgrade_header = r.get_header("Upgrade");
|
||||
|
||||
if (ci_find_substr(upgrade_header, constants::upgrade_token,
|
||||
sizeof(constants::upgrade_token)-1) == upgrade_header.end())
|
||||
@@ -63,7 +74,7 @@ bool is_websocket_handshake(request_type& r) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const std::string& con_header = r.get_header("Connection");
|
||||
std::string const & con_header = r.get_header("Connection");
|
||||
|
||||
if (ci_find_substr(con_header, constants::connection_token,
|
||||
sizeof(constants::connection_token)-1) == con_header.end())
|
||||
@@ -106,6 +117,15 @@ int get_websocket_version(request_type& r) {
|
||||
return version;
|
||||
}
|
||||
|
||||
/// Extract a URI ptr from the host header of the request
|
||||
/**
|
||||
* @param request The request to extract the Host header from.
|
||||
*
|
||||
* @param scheme The scheme under which this request was received (ws, wss,
|
||||
* http, https, etc)
|
||||
*
|
||||
* @return A uri_pointer that encodes the value of the host header.
|
||||
*/
|
||||
template <typename request_type>
|
||||
uri_ptr get_uri_from_host(request_type & request, std::string scheme) {
|
||||
std::string h = request.get_header("Host");
|
||||
@@ -129,31 +149,7 @@ uri_ptr get_uri_from_host(request_type & request, std::string scheme) {
|
||||
}
|
||||
}
|
||||
|
||||
// All other functions are WebSocket version dependent. processor is a base
|
||||
// class for version dependent processing functions.
|
||||
|
||||
// A processor class collects and wraps all of the logic necessary for parsing
|
||||
// and validating WebSocket handshakes and messages of specific protocol version
|
||||
// and set of allowed extensions.
|
||||
//
|
||||
// An instance of a processor represents the state of a single WebSocket
|
||||
// connection of the associated version. One processor instance is needed per
|
||||
// logical WebSocket connection.
|
||||
//
|
||||
// Basic usage pattern:
|
||||
//
|
||||
// while(len = read(buf)) {
|
||||
// if (processor.consume(buf,len) == 0) {
|
||||
// // handle errors
|
||||
// }
|
||||
// if (processor.ready()) {
|
||||
// message_ptr msg = processor.get_message();
|
||||
//
|
||||
// // handle msg;
|
||||
// }
|
||||
// }
|
||||
|
||||
/// WebSocket protocol processor base class
|
||||
/// WebSocket protocol processor abstract base class
|
||||
template <typename config>
|
||||
class processor {
|
||||
public:
|
||||
@@ -169,8 +165,7 @@ public:
|
||||
|
||||
virtual ~processor() {}
|
||||
|
||||
/// Returns the version of the WebSocket protocol that this processor
|
||||
/// understands.
|
||||
/// Get the protocol version of this processor
|
||||
virtual int get_version() const = 0;
|
||||
|
||||
/// Returns whether or not the permessage_compress extension is implemented
|
||||
@@ -188,7 +183,7 @@ public:
|
||||
* requested extensions are supported by this processor. If they are their
|
||||
* settings data is initialized.
|
||||
*/
|
||||
virtual err_str_pair negotiate_extensions(const request_type& request) {
|
||||
virtual err_str_pair negotiate_extensions(request_type const & request) {
|
||||
return err_str_pair();
|
||||
}
|
||||
|
||||
@@ -201,7 +196,7 @@ public:
|
||||
* @return A status code, 0 on success, non-zero for specific sorts of
|
||||
* failure
|
||||
*/
|
||||
virtual lib::error_code validate_handshake(const request_type& request)
|
||||
virtual lib::error_code validate_handshake(request_type const & request)
|
||||
const = 0;
|
||||
|
||||
/// Calculate the appropriate response for this websocket request
|
||||
@@ -214,8 +209,8 @@ public:
|
||||
*
|
||||
* @return An error code, 0 on success, non-zero for other errors
|
||||
*/
|
||||
virtual lib::error_code process_handshake(const request_type& req, const
|
||||
std::string & subprotocol, response_type& res) const = 0;
|
||||
virtual lib::error_code process_handshake(request_type const & req,
|
||||
std::string const & subprotocol, response_type& res) const = 0;
|
||||
|
||||
/// Fill in an HTTP request for an outgoing connection handshake
|
||||
/**
|
||||
@@ -223,8 +218,8 @@ public:
|
||||
*
|
||||
* @return An error code, 0 on success, non-zero for other errors
|
||||
*/
|
||||
virtual lib::error_code client_handshake_request(request_type& req,
|
||||
uri_ptr uri, const std::vector<std::string> & subprotocols) const = 0;
|
||||
virtual lib::error_code client_handshake_request(request_type & req,
|
||||
uri_ptr uri, std::vector<std::string> const & subprotocols) const = 0;
|
||||
|
||||
/// Validate the server's response to an outgoing handshake request
|
||||
/**
|
||||
@@ -234,14 +229,14 @@ public:
|
||||
*
|
||||
* @return An error code, 0 on success, non-zero for other errors
|
||||
*/
|
||||
virtual lib::error_code validate_server_handshake_response(const
|
||||
request_type & req, response_type & res) const = 0;
|
||||
virtual lib::error_code validate_server_handshake_response(request_type
|
||||
const & req, response_type & res) const = 0;
|
||||
|
||||
/// Given a completed response, get the raw bytes to put on the wire
|
||||
virtual std::string get_raw(const response_type& request) const = 0;
|
||||
virtual std::string get_raw(response_type const & request) const = 0;
|
||||
|
||||
/// Return the value of the header containing the CORS origin.
|
||||
virtual const std::string& get_origin(const request_type& request)
|
||||
virtual std::string const & get_origin(request_type const & request)
|
||||
const = 0;
|
||||
|
||||
/// Extracts requested subprotocols from a handshake request
|
||||
@@ -258,7 +253,7 @@ public:
|
||||
std::vector<std::string> & subprotocol_list) = 0;
|
||||
|
||||
/// Extracts client uri from a handshake request
|
||||
virtual uri_ptr get_uri(const request_type& request) const = 0;
|
||||
virtual uri_ptr get_uri(request_type const & request) const = 0;
|
||||
|
||||
/// process new websocket connection bytes
|
||||
/**
|
||||
@@ -329,7 +324,7 @@ public:
|
||||
*
|
||||
* @return Status code, zero on success, non-zero on failure
|
||||
*/
|
||||
virtual lib::error_code prepare_ping(const std::string & in,
|
||||
virtual lib::error_code prepare_ping(std::string const & in,
|
||||
message_ptr out) const = 0;
|
||||
|
||||
/// Prepare a pong frame
|
||||
@@ -343,7 +338,7 @@ public:
|
||||
*
|
||||
* @return Status code, zero on success, non-zero on failure
|
||||
*/
|
||||
virtual lib::error_code prepare_pong(const std::string & in,
|
||||
virtual lib::error_code prepare_pong(std::string const & in,
|
||||
message_ptr out) const = 0;
|
||||
|
||||
/// Prepare a close frame
|
||||
@@ -362,13 +357,12 @@ public:
|
||||
* @return Status code, zero on success, non-zero on failure
|
||||
*/
|
||||
virtual lib::error_code prepare_close(close::status::value code,
|
||||
const std::string & reason, message_ptr out) const = 0;
|
||||
std::string const & reason, message_ptr out) const = 0;
|
||||
protected:
|
||||
const bool m_secure;
|
||||
const bool m_server;
|
||||
bool const m_secure;
|
||||
bool const m_server;
|
||||
};
|
||||
|
||||
|
||||
} // namespace processor
|
||||
} // namespace websocketpp
|
||||
|
||||
|
||||
@@ -110,13 +110,14 @@ public:
|
||||
*/
|
||||
connection_ptr get_connection(const std::string& u, lib::error_code &ec) {
|
||||
// parse uri
|
||||
try {
|
||||
uri_ptr location(new uri(u));
|
||||
return get_connection(location, ec);
|
||||
} catch (uri_exception) {
|
||||
uri_ptr location(new uri(u));
|
||||
|
||||
if (!location->get_valid()) {
|
||||
ec = error::make_error_code(error::invalid_uri);
|
||||
return connection_ptr();
|
||||
}
|
||||
|
||||
return get_connection(location, ec);
|
||||
}
|
||||
|
||||
/// Begin the connection process for the given connection
|
||||
|
||||
@@ -1,41 +0,0 @@
|
||||
#
|
||||
# Makefile
|
||||
#
|
||||
# Copyright (C) 1998, 2009
|
||||
# Paul E. Jones <paulej@packetizer.com>
|
||||
# All Rights Reserved.
|
||||
#
|
||||
#############################################################################
|
||||
# $Id: Makefile 12 2009-06-22 19:34:25Z paulej $
|
||||
#############################################################################
|
||||
#
|
||||
# Description:
|
||||
# This is a makefile for UNIX to build the programs sha, shacmp, and
|
||||
# shatest
|
||||
#
|
||||
#
|
||||
|
||||
CC = g++
|
||||
|
||||
CFLAGS = -c -O2 -Wall -D_FILE_OFFSET_BITS=64
|
||||
|
||||
LIBS =
|
||||
|
||||
OBJS = sha1.o
|
||||
|
||||
all: sha shacmp shatest
|
||||
|
||||
sha: sha.o $(OBJS)
|
||||
$(CC) -o $@ sha.o $(OBJS) $(LIBS)
|
||||
|
||||
shacmp: shacmp.o $(OBJS)
|
||||
$(CC) -o $@ shacmp.o $(OBJS) $(LIBS)
|
||||
|
||||
shatest: shatest.o $(OBJS)
|
||||
$(CC) -o $@ shatest.o $(OBJS) $(LIBS)
|
||||
|
||||
%.o: %.cpp
|
||||
$(CC) $(CFLAGS) -o $@ $<
|
||||
|
||||
clean:
|
||||
$(RM) *.o sha shacmp shatest
|
||||
@@ -1,48 +0,0 @@
|
||||
#
|
||||
# Makefile.nt
|
||||
#
|
||||
# Copyright (C) 1998, 2009
|
||||
# Paul E. Jones <paulej@packetizer.com>
|
||||
# All Rights Reserved.
|
||||
#
|
||||
#############################################################################
|
||||
# $Id: Makefile.nt 13 2009-06-22 20:20:32Z paulej $
|
||||
#############################################################################
|
||||
#
|
||||
# Description:
|
||||
# This is a makefile for Win32 to build the programs sha, shacmp, and
|
||||
# shatest
|
||||
#
|
||||
# Portability Issues:
|
||||
# Designed to work with Visual C++
|
||||
#
|
||||
#
|
||||
|
||||
.silent:
|
||||
|
||||
!include <win32.mak>
|
||||
|
||||
RM = del /q
|
||||
|
||||
LIBS = $(conlibs) setargv.obj
|
||||
|
||||
CFLAGS = -D _CRT_SECURE_NO_WARNINGS /EHsc /O2 /W3
|
||||
|
||||
OBJS = sha1.obj
|
||||
|
||||
all: sha.exe shacmp.exe shatest.exe
|
||||
|
||||
sha.exe: sha.obj $(OBJS)
|
||||
$(link) $(conflags) -out:$@ sha.obj $(OBJS) $(LIBS)
|
||||
|
||||
shacmp.exe: shacmp.obj $(OBJS)
|
||||
$(link) $(conflags) -out:$@ shacmp.obj $(OBJS) $(LIBS)
|
||||
|
||||
shatest.exe: shatest.obj $(OBJS)
|
||||
$(link) $(conflags) -out:$@ shatest.obj $(OBJS) $(LIBS)
|
||||
|
||||
.cpp.obj:
|
||||
$(cc) $(CFLAGS) $(cflags) $(cvars) $<
|
||||
|
||||
clean:
|
||||
$(RM) *.obj sha.exe shacmp.exe shatest.exe
|
||||
@@ -1,176 +0,0 @@
|
||||
/*
|
||||
* sha.cpp
|
||||
*
|
||||
* Copyright (C) 1998, 2009
|
||||
* Paul E. Jones <paulej@packetizer.com>
|
||||
* All Rights Reserved
|
||||
*
|
||||
*****************************************************************************
|
||||
* $Id: sha.cpp 13 2009-06-22 20:20:32Z paulej $
|
||||
*****************************************************************************
|
||||
*
|
||||
* Description:
|
||||
* This utility will display the message digest (fingerprint) for
|
||||
* the specified file(s).
|
||||
*
|
||||
* Portability Issues:
|
||||
* None.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#ifdef WIN32
|
||||
#include <io.h>
|
||||
#endif
|
||||
#include <fcntl.h>
|
||||
#include "sha1.h"
|
||||
|
||||
/*
|
||||
* Function prototype
|
||||
*/
|
||||
void usage();
|
||||
|
||||
|
||||
/*
|
||||
* main
|
||||
*
|
||||
* Description:
|
||||
* This is the entry point for the program
|
||||
*
|
||||
* Parameters:
|
||||
* argc: [in]
|
||||
* This is the count of arguments in the argv array
|
||||
* argv: [in]
|
||||
* This is an array of filenames for which to compute message digests
|
||||
*
|
||||
* Returns:
|
||||
* Nothing.
|
||||
*
|
||||
* Comments:
|
||||
*
|
||||
*/
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
SHA1 sha; // SHA-1 class
|
||||
FILE *fp; // File pointer for reading files
|
||||
char c; // Character read from file
|
||||
unsigned message_digest[5]; // Message digest from "sha"
|
||||
int i; // Counter
|
||||
bool reading_stdin; // Are we reading standard in?
|
||||
bool read_stdin = false; // Have we read stdin?
|
||||
|
||||
/*
|
||||
* Check the program arguments and print usage information if -?
|
||||
* or --help is passed as the first argument.
|
||||
*/
|
||||
if (argc > 1 && (!strcmp(argv[1],"-?") || !strcmp(argv[1],"--help")))
|
||||
{
|
||||
usage();
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* For each filename passed in on the command line, calculate the
|
||||
* SHA-1 value and display it.
|
||||
*/
|
||||
for(i = 0; i < argc; i++)
|
||||
{
|
||||
/*
|
||||
* We start the counter at 0 to guarantee entry into the for loop.
|
||||
* So if 'i' is zero, we will increment it now. If there is no
|
||||
* argv[1], we will use STDIN below.
|
||||
*/
|
||||
if (i == 0)
|
||||
{
|
||||
i++;
|
||||
}
|
||||
|
||||
if (argc == 1 || !strcmp(argv[i],"-"))
|
||||
{
|
||||
#ifdef WIN32
|
||||
_setmode(_fileno(stdin), _O_BINARY);
|
||||
#endif
|
||||
fp = stdin;
|
||||
reading_stdin = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!(fp = fopen(argv[i],"rb")))
|
||||
{
|
||||
fprintf(stderr, "sha: unable to open file %s\n", argv[i]);
|
||||
return 2;
|
||||
}
|
||||
reading_stdin = false;
|
||||
}
|
||||
|
||||
/*
|
||||
* We do not want to read STDIN multiple times
|
||||
*/
|
||||
if (reading_stdin)
|
||||
{
|
||||
if (read_stdin)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
read_stdin = true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Reset the SHA1 object and process input
|
||||
*/
|
||||
sha.Reset();
|
||||
|
||||
c = fgetc(fp);
|
||||
while(!feof(fp))
|
||||
{
|
||||
sha.Input(c);
|
||||
c = fgetc(fp);
|
||||
}
|
||||
|
||||
if (!reading_stdin)
|
||||
{
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
if (!sha.Result(message_digest))
|
||||
{
|
||||
fprintf(stderr,"sha: could not compute message digest for %s\n",
|
||||
reading_stdin?"STDIN":argv[i]);
|
||||
}
|
||||
else
|
||||
{
|
||||
printf( "%08X %08X %08X %08X %08X - %s\n",
|
||||
message_digest[0],
|
||||
message_digest[1],
|
||||
message_digest[2],
|
||||
message_digest[3],
|
||||
message_digest[4],
|
||||
reading_stdin?"STDIN":argv[i]);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* usage
|
||||
*
|
||||
* Description:
|
||||
* This function will display program usage information to the user.
|
||||
*
|
||||
* Parameters:
|
||||
* None.
|
||||
*
|
||||
* Returns:
|
||||
* Nothing.
|
||||
*
|
||||
* Comments:
|
||||
*
|
||||
*/
|
||||
void usage()
|
||||
{
|
||||
printf("usage: sha <file> [<file> ...]\n");
|
||||
printf("\tThis program will display the message digest (fingerprint)\n");
|
||||
printf("\tfor files using the Secure Hashing Algorithm (SHA-1).\n");
|
||||
}
|
||||
@@ -1,589 +0,0 @@
|
||||
/*
|
||||
* sha1.cpp
|
||||
*
|
||||
* Copyright (C) 1998, 2009
|
||||
* Paul E. Jones <paulej@packetizer.com>
|
||||
* All Rights Reserved.
|
||||
*
|
||||
*****************************************************************************
|
||||
* $Id: sha1.cpp 12 2009-06-22 19:34:25Z paulej $
|
||||
*****************************************************************************
|
||||
*
|
||||
* Description:
|
||||
* This class implements the Secure Hashing Standard as defined
|
||||
* in FIPS PUB 180-1 published April 17, 1995.
|
||||
*
|
||||
* The Secure Hashing Standard, which uses the Secure Hashing
|
||||
* Algorithm (SHA), produces a 160-bit message digest for a
|
||||
* given data stream. In theory, it is highly improbable that
|
||||
* two messages will produce the same message digest. Therefore,
|
||||
* this algorithm can serve as a means of providing a "fingerprint"
|
||||
* for a message.
|
||||
*
|
||||
* Portability Issues:
|
||||
* SHA-1 is defined in terms of 32-bit "words". This code was
|
||||
* written with the expectation that the processor has at least
|
||||
* a 32-bit machine word size. If the machine word size is larger,
|
||||
* the code should still function properly. One caveat to that
|
||||
* is that the input functions taking characters and character arrays
|
||||
* assume that only 8 bits of information are stored in each character.
|
||||
*
|
||||
* Caveats:
|
||||
* SHA-1 is designed to work with messages less than 2^64 bits long.
|
||||
* Although SHA-1 allows a message digest to be generated for
|
||||
* messages of any number of bits less than 2^64, this implementation
|
||||
* only works with messages with a length that is a multiple of 8
|
||||
* bits.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#include "sha1.h"
|
||||
|
||||
/*
|
||||
* SHA1
|
||||
*
|
||||
* Description:
|
||||
* This is the constructor for the sha1 class.
|
||||
*
|
||||
* Parameters:
|
||||
* None.
|
||||
*
|
||||
* Returns:
|
||||
* Nothing.
|
||||
*
|
||||
* Comments:
|
||||
*
|
||||
*/
|
||||
SHA1::SHA1()
|
||||
{
|
||||
Reset();
|
||||
}
|
||||
|
||||
/*
|
||||
* ~SHA1
|
||||
*
|
||||
* Description:
|
||||
* This is the destructor for the sha1 class
|
||||
*
|
||||
* Parameters:
|
||||
* None.
|
||||
*
|
||||
* Returns:
|
||||
* Nothing.
|
||||
*
|
||||
* Comments:
|
||||
*
|
||||
*/
|
||||
SHA1::~SHA1()
|
||||
{
|
||||
// The destructor does nothing
|
||||
}
|
||||
|
||||
/*
|
||||
* Reset
|
||||
*
|
||||
* Description:
|
||||
* This function will initialize the sha1 class member variables
|
||||
* in preparation for computing a new message digest.
|
||||
*
|
||||
* Parameters:
|
||||
* None.
|
||||
*
|
||||
* Returns:
|
||||
* Nothing.
|
||||
*
|
||||
* Comments:
|
||||
*
|
||||
*/
|
||||
void SHA1::Reset()
|
||||
{
|
||||
Length_Low = 0;
|
||||
Length_High = 0;
|
||||
Message_Block_Index = 0;
|
||||
|
||||
H[0] = 0x67452301;
|
||||
H[1] = 0xEFCDAB89;
|
||||
H[2] = 0x98BADCFE;
|
||||
H[3] = 0x10325476;
|
||||
H[4] = 0xC3D2E1F0;
|
||||
|
||||
Computed = false;
|
||||
Corrupted = false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Result
|
||||
*
|
||||
* Description:
|
||||
* This function will return the 160-bit message digest into the
|
||||
* array provided.
|
||||
*
|
||||
* Parameters:
|
||||
* message_digest_array: [out]
|
||||
* This is an array of five unsigned integers which will be filled
|
||||
* with the message digest that has been computed.
|
||||
*
|
||||
* Returns:
|
||||
* True if successful, false if it failed.
|
||||
*
|
||||
* Comments:
|
||||
*
|
||||
*/
|
||||
bool SHA1::Result(unsigned *message_digest_array)
|
||||
{
|
||||
int i; // Counter
|
||||
|
||||
if (Corrupted)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!Computed)
|
||||
{
|
||||
PadMessage();
|
||||
Computed = true;
|
||||
}
|
||||
|
||||
for(i = 0; i < 5; i++)
|
||||
{
|
||||
message_digest_array[i] = H[i];
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Input
|
||||
*
|
||||
* Description:
|
||||
* This function accepts an array of octets as the next portion of
|
||||
* the message.
|
||||
*
|
||||
* Parameters:
|
||||
* message_array: [in]
|
||||
* An array of characters representing the next portion of the
|
||||
* message.
|
||||
*
|
||||
* Returns:
|
||||
* Nothing.
|
||||
*
|
||||
* Comments:
|
||||
*
|
||||
*/
|
||||
void SHA1::Input( const unsigned char *message_array,
|
||||
unsigned length)
|
||||
{
|
||||
if (!length)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (Computed || Corrupted)
|
||||
{
|
||||
Corrupted = true;
|
||||
return;
|
||||
}
|
||||
|
||||
while(length-- && !Corrupted)
|
||||
{
|
||||
Message_Block[Message_Block_Index++] = (*message_array & 0xFF);
|
||||
|
||||
Length_Low += 8;
|
||||
Length_Low &= 0xFFFFFFFF; // Force it to 32 bits
|
||||
if (Length_Low == 0)
|
||||
{
|
||||
Length_High++;
|
||||
Length_High &= 0xFFFFFFFF; // Force it to 32 bits
|
||||
if (Length_High == 0)
|
||||
{
|
||||
Corrupted = true; // Message is too long
|
||||
}
|
||||
}
|
||||
|
||||
if (Message_Block_Index == 64)
|
||||
{
|
||||
ProcessMessageBlock();
|
||||
}
|
||||
|
||||
message_array++;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Input
|
||||
*
|
||||
* Description:
|
||||
* This function accepts an array of octets as the next portion of
|
||||
* the message.
|
||||
*
|
||||
* Parameters:
|
||||
* message_array: [in]
|
||||
* An array of characters representing the next portion of the
|
||||
* message.
|
||||
* length: [in]
|
||||
* The length of the message_array
|
||||
*
|
||||
* Returns:
|
||||
* Nothing.
|
||||
*
|
||||
* Comments:
|
||||
*
|
||||
*/
|
||||
void SHA1::Input( const char *message_array,
|
||||
unsigned length)
|
||||
{
|
||||
Input((unsigned char *) message_array, length);
|
||||
}
|
||||
|
||||
/*
|
||||
* Input
|
||||
*
|
||||
* Description:
|
||||
* This function accepts a single octets as the next message element.
|
||||
*
|
||||
* Parameters:
|
||||
* message_element: [in]
|
||||
* The next octet in the message.
|
||||
*
|
||||
* Returns:
|
||||
* Nothing.
|
||||
*
|
||||
* Comments:
|
||||
*
|
||||
*/
|
||||
void SHA1::Input(unsigned char message_element)
|
||||
{
|
||||
Input(&message_element, 1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Input
|
||||
*
|
||||
* Description:
|
||||
* This function accepts a single octet as the next message element.
|
||||
*
|
||||
* Parameters:
|
||||
* message_element: [in]
|
||||
* The next octet in the message.
|
||||
*
|
||||
* Returns:
|
||||
* Nothing.
|
||||
*
|
||||
* Comments:
|
||||
*
|
||||
*/
|
||||
void SHA1::Input(char message_element)
|
||||
{
|
||||
Input((unsigned char *) &message_element, 1);
|
||||
}
|
||||
|
||||
/*
|
||||
* operator<<
|
||||
*
|
||||
* Description:
|
||||
* This operator makes it convenient to provide character strings to
|
||||
* the SHA1 object for processing.
|
||||
*
|
||||
* Parameters:
|
||||
* message_array: [in]
|
||||
* The character array to take as input.
|
||||
*
|
||||
* Returns:
|
||||
* A reference to the SHA1 object.
|
||||
*
|
||||
* Comments:
|
||||
* Each character is assumed to hold 8 bits of information.
|
||||
*
|
||||
*/
|
||||
SHA1& SHA1::operator<<(const char *message_array)
|
||||
{
|
||||
const char *p = message_array;
|
||||
|
||||
while(*p)
|
||||
{
|
||||
Input(*p);
|
||||
p++;
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
/*
|
||||
* operator<<
|
||||
*
|
||||
* Description:
|
||||
* This operator makes it convenient to provide character strings to
|
||||
* the SHA1 object for processing.
|
||||
*
|
||||
* Parameters:
|
||||
* message_array: [in]
|
||||
* The character array to take as input.
|
||||
*
|
||||
* Returns:
|
||||
* A reference to the SHA1 object.
|
||||
*
|
||||
* Comments:
|
||||
* Each character is assumed to hold 8 bits of information.
|
||||
*
|
||||
*/
|
||||
SHA1& SHA1::operator<<(const unsigned char *message_array)
|
||||
{
|
||||
const unsigned char *p = message_array;
|
||||
|
||||
while(*p)
|
||||
{
|
||||
Input(*p);
|
||||
p++;
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
/*
|
||||
* operator<<
|
||||
*
|
||||
* Description:
|
||||
* This function provides the next octet in the message.
|
||||
*
|
||||
* Parameters:
|
||||
* message_element: [in]
|
||||
* The next octet in the message
|
||||
*
|
||||
* Returns:
|
||||
* A reference to the SHA1 object.
|
||||
*
|
||||
* Comments:
|
||||
* The character is assumed to hold 8 bits of information.
|
||||
*
|
||||
*/
|
||||
SHA1& SHA1::operator<<(const char message_element)
|
||||
{
|
||||
Input((unsigned char *) &message_element, 1);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
/*
|
||||
* operator<<
|
||||
*
|
||||
* Description:
|
||||
* This function provides the next octet in the message.
|
||||
*
|
||||
* Parameters:
|
||||
* message_element: [in]
|
||||
* The next octet in the message
|
||||
*
|
||||
* Returns:
|
||||
* A reference to the SHA1 object.
|
||||
*
|
||||
* Comments:
|
||||
* The character is assumed to hold 8 bits of information.
|
||||
*
|
||||
*/
|
||||
SHA1& SHA1::operator<<(const unsigned char message_element)
|
||||
{
|
||||
Input(&message_element, 1);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
/*
|
||||
* ProcessMessageBlock
|
||||
*
|
||||
* Description:
|
||||
* This function will process the next 512 bits of the message
|
||||
* stored in the Message_Block array.
|
||||
*
|
||||
* Parameters:
|
||||
* None.
|
||||
*
|
||||
* Returns:
|
||||
* Nothing.
|
||||
*
|
||||
* Comments:
|
||||
* Many of the variable names in this function, especially the single
|
||||
* character names, were used because those were the names used
|
||||
* in the publication.
|
||||
*
|
||||
*/
|
||||
void SHA1::ProcessMessageBlock()
|
||||
{
|
||||
const unsigned K[] = { // Constants defined for SHA-1
|
||||
0x5A827999,
|
||||
0x6ED9EBA1,
|
||||
0x8F1BBCDC,
|
||||
0xCA62C1D6
|
||||
};
|
||||
int t; // Loop counter
|
||||
unsigned temp; // Temporary word value
|
||||
unsigned W[80]; // Word sequence
|
||||
unsigned A, B, C, D, E; // Word buffers
|
||||
|
||||
/*
|
||||
* Initialize the first 16 words in the array W
|
||||
*/
|
||||
for(t = 0; t < 16; t++)
|
||||
{
|
||||
W[t] = ((unsigned) Message_Block[t * 4]) << 24;
|
||||
W[t] |= ((unsigned) Message_Block[t * 4 + 1]) << 16;
|
||||
W[t] |= ((unsigned) Message_Block[t * 4 + 2]) << 8;
|
||||
W[t] |= ((unsigned) Message_Block[t * 4 + 3]);
|
||||
}
|
||||
|
||||
for(t = 16; t < 80; t++)
|
||||
{
|
||||
W[t] = CircularShift(1,W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16]);
|
||||
}
|
||||
|
||||
A = H[0];
|
||||
B = H[1];
|
||||
C = H[2];
|
||||
D = H[3];
|
||||
E = H[4];
|
||||
|
||||
for(t = 0; t < 20; t++)
|
||||
{
|
||||
temp = CircularShift(5,A) + ((B & C) | ((~B) & D)) + E + W[t] + K[0];
|
||||
temp &= 0xFFFFFFFF;
|
||||
E = D;
|
||||
D = C;
|
||||
C = CircularShift(30,B);
|
||||
B = A;
|
||||
A = temp;
|
||||
}
|
||||
|
||||
for(t = 20; t < 40; t++)
|
||||
{
|
||||
temp = CircularShift(5,A) + (B ^ C ^ D) + E + W[t] + K[1];
|
||||
temp &= 0xFFFFFFFF;
|
||||
E = D;
|
||||
D = C;
|
||||
C = CircularShift(30,B);
|
||||
B = A;
|
||||
A = temp;
|
||||
}
|
||||
|
||||
for(t = 40; t < 60; t++)
|
||||
{
|
||||
temp = CircularShift(5,A) +
|
||||
((B & C) | (B & D) | (C & D)) + E + W[t] + K[2];
|
||||
temp &= 0xFFFFFFFF;
|
||||
E = D;
|
||||
D = C;
|
||||
C = CircularShift(30,B);
|
||||
B = A;
|
||||
A = temp;
|
||||
}
|
||||
|
||||
for(t = 60; t < 80; t++)
|
||||
{
|
||||
temp = CircularShift(5,A) + (B ^ C ^ D) + E + W[t] + K[3];
|
||||
temp &= 0xFFFFFFFF;
|
||||
E = D;
|
||||
D = C;
|
||||
C = CircularShift(30,B);
|
||||
B = A;
|
||||
A = temp;
|
||||
}
|
||||
|
||||
H[0] = (H[0] + A) & 0xFFFFFFFF;
|
||||
H[1] = (H[1] + B) & 0xFFFFFFFF;
|
||||
H[2] = (H[2] + C) & 0xFFFFFFFF;
|
||||
H[3] = (H[3] + D) & 0xFFFFFFFF;
|
||||
H[4] = (H[4] + E) & 0xFFFFFFFF;
|
||||
|
||||
Message_Block_Index = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* PadMessage
|
||||
*
|
||||
* Description:
|
||||
* According to the standard, the message must be padded to an even
|
||||
* 512 bits. The first padding bit must be a '1'. The last 64 bits
|
||||
* represent the length of the original message. All bits in between
|
||||
* should be 0. This function will pad the message according to those
|
||||
* rules by filling the message_block array accordingly. It will also
|
||||
* call ProcessMessageBlock() appropriately. When it returns, it
|
||||
* can be assumed that the message digest has been computed.
|
||||
*
|
||||
* Parameters:
|
||||
* None.
|
||||
*
|
||||
* Returns:
|
||||
* Nothing.
|
||||
*
|
||||
* Comments:
|
||||
*
|
||||
*/
|
||||
void SHA1::PadMessage()
|
||||
{
|
||||
/*
|
||||
* Check to see if the current message block is too small to hold
|
||||
* the initial padding bits and length. If so, we will pad the
|
||||
* block, process it, and then continue padding into a second block.
|
||||
*/
|
||||
if (Message_Block_Index > 55)
|
||||
{
|
||||
Message_Block[Message_Block_Index++] = 0x80;
|
||||
while(Message_Block_Index < 64)
|
||||
{
|
||||
Message_Block[Message_Block_Index++] = 0;
|
||||
}
|
||||
|
||||
ProcessMessageBlock();
|
||||
|
||||
while(Message_Block_Index < 56)
|
||||
{
|
||||
Message_Block[Message_Block_Index++] = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Message_Block[Message_Block_Index++] = 0x80;
|
||||
while(Message_Block_Index < 56)
|
||||
{
|
||||
Message_Block[Message_Block_Index++] = 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* Store the message length as the last 8 octets
|
||||
*/
|
||||
Message_Block[56] = (Length_High >> 24) & 0xFF;
|
||||
Message_Block[57] = (Length_High >> 16) & 0xFF;
|
||||
Message_Block[58] = (Length_High >> 8) & 0xFF;
|
||||
Message_Block[59] = (Length_High) & 0xFF;
|
||||
Message_Block[60] = (Length_Low >> 24) & 0xFF;
|
||||
Message_Block[61] = (Length_Low >> 16) & 0xFF;
|
||||
Message_Block[62] = (Length_Low >> 8) & 0xFF;
|
||||
Message_Block[63] = (Length_Low) & 0xFF;
|
||||
|
||||
ProcessMessageBlock();
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* CircularShift
|
||||
*
|
||||
* Description:
|
||||
* This member function will perform a circular shifting operation.
|
||||
*
|
||||
* Parameters:
|
||||
* bits: [in]
|
||||
* The number of bits to shift (1-31)
|
||||
* word: [in]
|
||||
* The value to shift (assumes a 32-bit integer)
|
||||
*
|
||||
* Returns:
|
||||
* The shifted value.
|
||||
*
|
||||
* Comments:
|
||||
*
|
||||
*/
|
||||
unsigned SHA1::CircularShift(int bits, unsigned word)
|
||||
{
|
||||
return ((word << bits) & 0xFFFFFFFF) | ((word & 0xFFFFFFFF) >> (32-bits));
|
||||
}
|
||||
@@ -1,88 +0,0 @@
|
||||
/*
|
||||
* sha1.h
|
||||
*
|
||||
* Copyright (C) 1998, 2009
|
||||
* Paul E. Jones <paulej@packetizer.com>
|
||||
* All Rights Reserved.
|
||||
*
|
||||
*****************************************************************************
|
||||
* $Id: sha1.h 12 2009-06-22 19:34:25Z paulej $
|
||||
*****************************************************************************
|
||||
*
|
||||
* Description:
|
||||
* This class implements the Secure Hashing Standard as defined
|
||||
* in FIPS PUB 180-1 published April 17, 1995.
|
||||
*
|
||||
* Many of the variable names in this class, especially the single
|
||||
* character names, were used because those were the names used
|
||||
* in the publication.
|
||||
*
|
||||
* Please read the file sha1.cpp for more information.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _SHA1_H_
|
||||
#define _SHA1_H_
|
||||
|
||||
class SHA1
|
||||
{
|
||||
public:
|
||||
|
||||
SHA1();
|
||||
virtual ~SHA1();
|
||||
|
||||
/*
|
||||
* Re-initialize the class
|
||||
*/
|
||||
void Reset();
|
||||
|
||||
/*
|
||||
* Returns the message digest
|
||||
*/
|
||||
bool Result(unsigned *message_digest_array);
|
||||
|
||||
/*
|
||||
* Provide input to SHA1
|
||||
*/
|
||||
void Input( const unsigned char *message_array,
|
||||
unsigned length);
|
||||
void Input( const char *message_array,
|
||||
unsigned length);
|
||||
void Input(unsigned char message_element);
|
||||
void Input(char message_element);
|
||||
SHA1& operator<<(const char *message_array);
|
||||
SHA1& operator<<(const unsigned char *message_array);
|
||||
SHA1& operator<<(const char message_element);
|
||||
SHA1& operator<<(const unsigned char message_element);
|
||||
|
||||
private:
|
||||
|
||||
/*
|
||||
* Process the next 512 bits of the message
|
||||
*/
|
||||
void ProcessMessageBlock();
|
||||
|
||||
/*
|
||||
* Pads the current message block to 512 bits
|
||||
*/
|
||||
void PadMessage();
|
||||
|
||||
/*
|
||||
* Performs a circular left shift operation
|
||||
*/
|
||||
inline unsigned CircularShift(int bits, unsigned word);
|
||||
|
||||
unsigned H[5]; // Message digest buffers
|
||||
|
||||
unsigned Length_Low; // Message length in bits
|
||||
unsigned Length_High; // Message length in bits
|
||||
|
||||
unsigned char Message_Block[64]; // 512-bit message blocks
|
||||
int Message_Block_Index; // Index into message block array
|
||||
|
||||
bool Computed; // Is the digest computed?
|
||||
bool Corrupted; // Is the message digest corruped?
|
||||
|
||||
};
|
||||
|
||||
#endif // _SHA1_H_
|
||||
+376
-321
@@ -1,16 +1,27 @@
|
||||
/*
|
||||
* sha1.hpp
|
||||
* sha1.hpp
|
||||
*
|
||||
* Copyright (C) 1998, 2009
|
||||
* Paul E. Jones <paulej@packetizer.com>
|
||||
* All Rights Reserved.
|
||||
* Copyright (C) 1998, 2009
|
||||
* Paul E. Jones <paulej@packetizer.com>
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* Modifications were done in 2012 by Peter Thorson (webmaster@zaphoyd.com) to allow
|
||||
* header only usage of the library. These changes are distributed under the original
|
||||
* freeware license.
|
||||
* Modifications were done in 2012-13 by Peter Thorson (webmaster@zaphoyd.com)
|
||||
* to allow header only usage of the library and use C++ features to better
|
||||
* support C++ usage. These changes are distributed under the original freeware
|
||||
* license included below
|
||||
*
|
||||
* Freeware Public License (FPL)
|
||||
*
|
||||
* This software is licensed as "freeware." Permission to distribute
|
||||
* this software in source and binary forms, including incorporation
|
||||
* into other products, is hereby granted without a fee. THIS SOFTWARE
|
||||
* IS PROVIDED 'AS IS' AND WITHOUT ANY EXPRESSED OR IMPLIED WARRANTIES,
|
||||
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
* AND FITNESS FOR A PARTICULAR PURPOSE. THE AUTHOR SHALL NOT BE HELD
|
||||
* LIABLE FOR ANY DAMAGES RESULTING FROM THE USE OF THIS SOFTWARE, EITHER
|
||||
* DIRECTLY OR INDIRECTLY, INCLUDING, BUT NOT LIMITED TO, LOSS OF DATA
|
||||
* OR DATA BEING RENDERED INACCURATE.
|
||||
*
|
||||
*****************************************************************************
|
||||
* $Id: sha1.h 12 2009-06-22 19:34:25Z paulej $
|
||||
*****************************************************************************
|
||||
*
|
||||
* Description:
|
||||
@@ -21,331 +32,375 @@
|
||||
* character names, were used because those were the names used
|
||||
* in the publication.
|
||||
*
|
||||
* Please read the file sha1.cpp for more information.
|
||||
* The Secure Hashing Standard, which uses the Secure Hashing
|
||||
* Algorithm (SHA), produces a 160-bit message digest for a
|
||||
* given data stream. In theory, it is highly improbable that
|
||||
* two messages will produce the same message digest. Therefore,
|
||||
* this algorithm can serve as a means of providing a "fingerprint"
|
||||
* for a message.
|
||||
*
|
||||
* Portability Issues:
|
||||
* SHA-1 is defined in terms of 32-bit "words". This code was
|
||||
* written with the expectation that the processor has at least
|
||||
* a 32-bit machine word size. If the machine word size is larger,
|
||||
* the code should still function properly. One caveat to that
|
||||
* is that the input functions taking characters and character arrays
|
||||
* assume that only 8 bits of information are stored in each character.
|
||||
*
|
||||
* Caveats:
|
||||
* SHA-1 is designed to work with messages less than 2^64 bits long.
|
||||
* Although SHA-1 allows a message digest to be generated for
|
||||
* messages of any number of bits less than 2^64, this implementation
|
||||
* only works with messages with a length that is a multiple of 8
|
||||
* bits.
|
||||
*
|
||||
*****************************************************************************
|
||||
*/
|
||||
|
||||
#ifndef _SHA1_H_
|
||||
#define _SHA1_H_
|
||||
|
||||
#include <websocketpp/common/stdint.hpp>
|
||||
|
||||
namespace websocketpp {
|
||||
|
||||
/// Provides SHA1 hashing functionality
|
||||
class SHA1
|
||||
{
|
||||
public:
|
||||
class sha1 {
|
||||
public:
|
||||
sha1() {
|
||||
reset();
|
||||
}
|
||||
|
||||
SHA1() {
|
||||
Reset();
|
||||
}
|
||||
virtual ~SHA1() {}
|
||||
virtual ~sha1() {}
|
||||
|
||||
/*
|
||||
* Re-initialize the class
|
||||
*/
|
||||
void Reset() {
|
||||
Length_Low = 0;
|
||||
Length_High = 0;
|
||||
Message_Block_Index = 0;
|
||||
|
||||
H[0] = 0x67452301;
|
||||
H[1] = 0xEFCDAB89;
|
||||
H[2] = 0x98BADCFE;
|
||||
H[3] = 0x10325476;
|
||||
H[4] = 0xC3D2E1F0;
|
||||
|
||||
Computed = false;
|
||||
Corrupted = false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns the message digest
|
||||
*/
|
||||
bool Result(unsigned *message_digest_array) {
|
||||
int i; // Counter
|
||||
|
||||
if (Corrupted)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!Computed)
|
||||
{
|
||||
PadMessage();
|
||||
Computed = true;
|
||||
}
|
||||
|
||||
for(i = 0; i < 5; i++)
|
||||
{
|
||||
message_digest_array[i] = H[i];
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Provide input to SHA1
|
||||
*/
|
||||
void Input( const unsigned char *message_array,
|
||||
unsigned length)
|
||||
{
|
||||
if (!length)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (Computed || Corrupted)
|
||||
{
|
||||
Corrupted = true;
|
||||
return;
|
||||
}
|
||||
|
||||
while(length-- && !Corrupted)
|
||||
{
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(push)
|
||||
#pragma warning(suppress: 6386) // Suppresses Visual Studio code analysis for write overrun. It doesn't know the index into Message_Block is protected by checking length.
|
||||
#endif
|
||||
Message_Block[Message_Block_Index++] = (*message_array & 0xFF);
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
Length_Low += 8;
|
||||
Length_Low &= 0xFFFFFFFF; // Force it to 32 bits
|
||||
if (Length_Low == 0)
|
||||
{
|
||||
Length_High++;
|
||||
Length_High &= 0xFFFFFFFF; // Force it to 32 bits
|
||||
if (Length_High == 0)
|
||||
{
|
||||
Corrupted = true; // Message is too long
|
||||
}
|
||||
}
|
||||
|
||||
if (Message_Block_Index == 64)
|
||||
{
|
||||
ProcessMessageBlock();
|
||||
}
|
||||
|
||||
message_array++;
|
||||
}
|
||||
}
|
||||
void Input( const char *message_array,
|
||||
unsigned length)
|
||||
{
|
||||
Input((unsigned char *) message_array, length);
|
||||
}
|
||||
void Input(unsigned char message_element)
|
||||
{
|
||||
Input(&message_element, 1);
|
||||
}
|
||||
void Input(char message_element)
|
||||
{
|
||||
Input((unsigned char *) &message_element, 1);
|
||||
}
|
||||
SHA1& operator<<(const char *message_array)
|
||||
{
|
||||
const char *p = message_array;
|
||||
|
||||
while(*p)
|
||||
{
|
||||
Input(*p);
|
||||
p++;
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
SHA1& operator<<(const unsigned char *message_array)
|
||||
{
|
||||
const unsigned char *p = message_array;
|
||||
|
||||
while(*p)
|
||||
{
|
||||
Input(*p);
|
||||
p++;
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
SHA1& operator<<(const char message_element)
|
||||
{
|
||||
Input((unsigned char *) &message_element, 1);
|
||||
|
||||
return *this;
|
||||
}
|
||||
SHA1& operator<<(const unsigned char message_element)
|
||||
{
|
||||
Input(&message_element, 1);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
/*
|
||||
* Process the next 512 bits of the message
|
||||
*/
|
||||
void ProcessMessageBlock()
|
||||
{
|
||||
const unsigned K[] = { // Constants defined for SHA-1
|
||||
0x5A827999,
|
||||
0x6ED9EBA1,
|
||||
0x8F1BBCDC,
|
||||
0xCA62C1D6
|
||||
};
|
||||
int t; // Loop counter
|
||||
unsigned temp; // Temporary word value
|
||||
unsigned W[80]; // Word sequence
|
||||
unsigned A, B, C, D, E; // Word buffers
|
||||
|
||||
/*
|
||||
* Initialize the first 16 words in the array W
|
||||
*/
|
||||
for(t = 0; t < 16; t++)
|
||||
{
|
||||
W[t] = ((unsigned) Message_Block[t * 4]) << 24;
|
||||
W[t] |= ((unsigned) Message_Block[t * 4 + 1]) << 16;
|
||||
W[t] |= ((unsigned) Message_Block[t * 4 + 2]) << 8;
|
||||
W[t] |= ((unsigned) Message_Block[t * 4 + 3]);
|
||||
}
|
||||
|
||||
for(t = 16; t < 80; t++)
|
||||
{
|
||||
W[t] = CircularShift(1,W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16]);
|
||||
}
|
||||
|
||||
A = H[0];
|
||||
B = H[1];
|
||||
C = H[2];
|
||||
D = H[3];
|
||||
E = H[4];
|
||||
|
||||
for(t = 0; t < 20; t++)
|
||||
{
|
||||
temp = CircularShift(5,A) + ((B & C) | ((~B) & D)) + E + W[t] + K[0];
|
||||
temp &= 0xFFFFFFFF;
|
||||
E = D;
|
||||
D = C;
|
||||
C = CircularShift(30,B);
|
||||
B = A;
|
||||
A = temp;
|
||||
}
|
||||
|
||||
for(t = 20; t < 40; t++)
|
||||
{
|
||||
temp = CircularShift(5,A) + (B ^ C ^ D) + E + W[t] + K[1];
|
||||
temp &= 0xFFFFFFFF;
|
||||
E = D;
|
||||
D = C;
|
||||
C = CircularShift(30,B);
|
||||
B = A;
|
||||
A = temp;
|
||||
}
|
||||
|
||||
for(t = 40; t < 60; t++)
|
||||
{
|
||||
temp = CircularShift(5,A) +
|
||||
((B & C) | (B & D) | (C & D)) + E + W[t] + K[2];
|
||||
temp &= 0xFFFFFFFF;
|
||||
E = D;
|
||||
D = C;
|
||||
C = CircularShift(30,B);
|
||||
B = A;
|
||||
A = temp;
|
||||
}
|
||||
|
||||
for(t = 60; t < 80; t++)
|
||||
{
|
||||
temp = CircularShift(5,A) + (B ^ C ^ D) + E + W[t] + K[3];
|
||||
temp &= 0xFFFFFFFF;
|
||||
E = D;
|
||||
D = C;
|
||||
C = CircularShift(30,B);
|
||||
B = A;
|
||||
A = temp;
|
||||
}
|
||||
|
||||
H[0] = (H[0] + A) & 0xFFFFFFFF;
|
||||
H[1] = (H[1] + B) & 0xFFFFFFFF;
|
||||
H[2] = (H[2] + C) & 0xFFFFFFFF;
|
||||
H[3] = (H[3] + D) & 0xFFFFFFFF;
|
||||
H[4] = (H[4] + E) & 0xFFFFFFFF;
|
||||
|
||||
Message_Block_Index = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Pads the current message block to 512 bits
|
||||
*/
|
||||
void PadMessage()
|
||||
{
|
||||
/*
|
||||
* Check to see if the current message block is too small to hold
|
||||
* the initial padding bits and length. If so, we will pad the
|
||||
* block, process it, and then continue padding into a second block.
|
||||
*/
|
||||
if (Message_Block_Index > 55)
|
||||
{
|
||||
Message_Block[Message_Block_Index++] = 0x80;
|
||||
while(Message_Block_Index < 64)
|
||||
{
|
||||
Message_Block[Message_Block_Index++] = 0;
|
||||
}
|
||||
|
||||
ProcessMessageBlock();
|
||||
|
||||
while(Message_Block_Index < 56)
|
||||
{
|
||||
Message_Block[Message_Block_Index++] = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Message_Block[Message_Block_Index++] = 0x80;
|
||||
while(Message_Block_Index < 56)
|
||||
{
|
||||
Message_Block[Message_Block_Index++] = 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* Store the message length as the last 8 octets
|
||||
*/
|
||||
Message_Block[56] = (Length_High >> 24) & 0xFF;
|
||||
Message_Block[57] = (Length_High >> 16) & 0xFF;
|
||||
Message_Block[58] = (Length_High >> 8) & 0xFF;
|
||||
Message_Block[59] = (Length_High) & 0xFF;
|
||||
Message_Block[60] = (Length_Low >> 24) & 0xFF;
|
||||
Message_Block[61] = (Length_Low >> 16) & 0xFF;
|
||||
Message_Block[62] = (Length_Low >> 8) & 0xFF;
|
||||
Message_Block[63] = (Length_Low) & 0xFF;
|
||||
|
||||
ProcessMessageBlock();
|
||||
}
|
||||
|
||||
/*
|
||||
* Performs a circular left shift operation
|
||||
*/
|
||||
inline unsigned CircularShift(int bits, unsigned word)
|
||||
{
|
||||
return ((word << bits) & 0xFFFFFFFF) | ((word & 0xFFFFFFFF) >> (32-bits));
|
||||
}
|
||||
|
||||
unsigned H[5]; // Message digest buffers
|
||||
|
||||
unsigned Length_Low; // Message length in bits
|
||||
unsigned Length_High; // Message length in bits
|
||||
|
||||
unsigned char Message_Block[64]; // 512-bit message blocks
|
||||
int Message_Block_Index; // Index into message block array
|
||||
|
||||
bool Computed; // Is the digest computed?
|
||||
bool Corrupted; // Is the message digest corruped?
|
||||
/// Re-initialize the class
|
||||
void reset() {
|
||||
length_low = 0;
|
||||
length_high = 0;
|
||||
message_block_index = 0;
|
||||
|
||||
H[0] = 0x67452301;
|
||||
H[1] = 0xEFCDAB89;
|
||||
H[2] = 0x98BADCFE;
|
||||
H[3] = 0x10325476;
|
||||
H[4] = 0xC3D2E1F0;
|
||||
|
||||
computed = false;
|
||||
corrupted = false;
|
||||
}
|
||||
|
||||
/// Extract the message digest as a raw integer array
|
||||
/**
|
||||
* @param [out] message_digest_array Integer array to store the message in
|
||||
* @return Whether or not the extraction was sucessful
|
||||
*/
|
||||
bool get_raw_digest(uint32_t * message_digest_array) {
|
||||
if (corrupted) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!computed) {
|
||||
pad_message();
|
||||
computed = true;
|
||||
}
|
||||
|
||||
for (int i = 0; i < 5; i++) {
|
||||
message_digest_array[i] = H[i];
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// Provide input to SHA1
|
||||
/**
|
||||
* @param [in] message_array The input bytes
|
||||
* @param [in] length Length of the message array
|
||||
*/
|
||||
void input(unsigned char const * message_array, uint32_t length) {
|
||||
if (!length) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (computed || corrupted) {
|
||||
corrupted = true;
|
||||
return;
|
||||
}
|
||||
|
||||
while (length-- && !corrupted) {
|
||||
// Suppresses Visual Studio code analysis for write overrun. It doesn't know the
|
||||
// index into Message_Block is protected by checking length.
|
||||
//
|
||||
// TODO: is there a more compatible way to write the original code to avoid
|
||||
// this sort of warning?
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(push)
|
||||
#pragma warning(suppress: 6386)
|
||||
#endif
|
||||
message_block[message_block_index++] = (*message_array & 0xFF);
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
length_low += 8;
|
||||
length_low &= 0xFFFFFFFF; // Force it to 32 bits
|
||||
if (length_low == 0) {
|
||||
length_high++;
|
||||
length_high &= 0xFFFFFFFF; // Force it to 32 bits
|
||||
if (length_high == 0) {
|
||||
corrupted = true; // Message is too long
|
||||
}
|
||||
}
|
||||
|
||||
if (message_block_index == 64) {
|
||||
process_message_block();
|
||||
}
|
||||
|
||||
message_array++;
|
||||
}
|
||||
}
|
||||
|
||||
/// Provide input to SHA1
|
||||
/**
|
||||
* Overload with signed message array
|
||||
*
|
||||
* @param [in] message_array The input bytes
|
||||
* @param [in] length Length of the message array
|
||||
*/
|
||||
void input(char const * message_array, uint32_t length) {
|
||||
input(reinterpret_cast<const unsigned char *>(message_array), length);
|
||||
}
|
||||
|
||||
/// Provide input to SHA1
|
||||
/**
|
||||
* Overload with a single unsigned char
|
||||
*
|
||||
* @param [in] message_element The character to input
|
||||
*/
|
||||
void input(unsigned char message_element) {
|
||||
input(&message_element, 1);
|
||||
}
|
||||
|
||||
/// Provide input to SHA1
|
||||
/**
|
||||
* Overload with a single signed char
|
||||
*
|
||||
* @param [in] message_element The character to input
|
||||
*/
|
||||
void input(char message_element) {
|
||||
input(reinterpret_cast<unsigned char *>(&message_element), 1);
|
||||
}
|
||||
|
||||
/// Provide input to SHA1
|
||||
/**
|
||||
* Overload via signed char array stream input
|
||||
*
|
||||
* @param [in] message_array The character array to input
|
||||
*/
|
||||
sha1& operator<<(char const * message_array) {
|
||||
char const * p = message_array;
|
||||
|
||||
while(*p) {
|
||||
input(*p);
|
||||
p++;
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// Provide input to SHA1
|
||||
/**
|
||||
* Overload via unsigned char array stream input
|
||||
*
|
||||
* @param [in] message_array The character array to input
|
||||
*/
|
||||
sha1& operator<<(unsigned char const * message_array) {
|
||||
unsigned char const * p = message_array;
|
||||
|
||||
while(*p) {
|
||||
input(*p);
|
||||
p++;
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// Provide input to SHA1
|
||||
/**
|
||||
* Overload via signed char stream input
|
||||
*
|
||||
* @param [in] message_element The character to input
|
||||
*/
|
||||
sha1& operator<<(char message_element) {
|
||||
input((unsigned char *) &message_element, 1);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// Provide input to SHA1
|
||||
/**
|
||||
* Overload via unsigned char stream input
|
||||
*
|
||||
* @param [in] message_element The character to input
|
||||
*/
|
||||
sha1& operator<<(unsigned char message_element) {
|
||||
input(&message_element, 1);
|
||||
|
||||
return *this;
|
||||
}
|
||||
private:
|
||||
/// Process the next 512 bits of the message
|
||||
/**
|
||||
* Many of the variable names in this function, especially the single
|
||||
* character names, were used because those were the names used
|
||||
* in the publication.
|
||||
*/
|
||||
void process_message_block() {
|
||||
// Constants defined for SHA-1
|
||||
uint32_t const K[] = { 0x5A827999,
|
||||
0x6ED9EBA1,
|
||||
0x8F1BBCDC,
|
||||
0xCA62C1D6 };
|
||||
uint32_t temp; // Temporary word value
|
||||
uint32_t W[80]; // Word sequence
|
||||
uint32_t A, B, C, D, E; // Word buffers
|
||||
|
||||
// Initialize the first 16 words in the array W
|
||||
for (int t = 0; t < 16; t++) {
|
||||
W[t] = ((uint32_t) message_block[t * 4]) << 24;
|
||||
W[t] |= ((uint32_t) message_block[t * 4 + 1]) << 16;
|
||||
W[t] |= ((uint32_t) message_block[t * 4 + 2]) << 8;
|
||||
W[t] |= ((uint32_t) message_block[t * 4 + 3]);
|
||||
}
|
||||
|
||||
for (int t = 16; t < 80; t++) {
|
||||
W[t] = CircularShift(1,W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16]);
|
||||
}
|
||||
|
||||
A = H[0];
|
||||
B = H[1];
|
||||
C = H[2];
|
||||
D = H[3];
|
||||
E = H[4];
|
||||
|
||||
for (int t = 0; t < 20; t++) {
|
||||
temp = CircularShift(5,A) + ((B & C) | ((~B) & D)) + E + W[t] + K[0];
|
||||
temp &= 0xFFFFFFFF;
|
||||
E = D;
|
||||
D = C;
|
||||
C = CircularShift(30,B);
|
||||
B = A;
|
||||
A = temp;
|
||||
}
|
||||
|
||||
for (int t = 20; t < 40; t++) {
|
||||
temp = CircularShift(5,A) + (B ^ C ^ D) + E + W[t] + K[1];
|
||||
temp &= 0xFFFFFFFF;
|
||||
E = D;
|
||||
D = C;
|
||||
C = CircularShift(30,B);
|
||||
B = A;
|
||||
A = temp;
|
||||
}
|
||||
|
||||
for (int t = 40; t < 60; t++) {
|
||||
temp = CircularShift(5,A) +
|
||||
((B & C) | (B & D) | (C & D)) + E + W[t] + K[2];
|
||||
temp &= 0xFFFFFFFF;
|
||||
E = D;
|
||||
D = C;
|
||||
C = CircularShift(30,B);
|
||||
B = A;
|
||||
A = temp;
|
||||
}
|
||||
|
||||
for (int t = 60; t < 80; t++) {
|
||||
temp = CircularShift(5,A) + (B ^ C ^ D) + E + W[t] + K[3];
|
||||
temp &= 0xFFFFFFFF;
|
||||
E = D;
|
||||
D = C;
|
||||
C = CircularShift(30,B);
|
||||
B = A;
|
||||
A = temp;
|
||||
}
|
||||
|
||||
H[0] = (H[0] + A) & 0xFFFFFFFF;
|
||||
H[1] = (H[1] + B) & 0xFFFFFFFF;
|
||||
H[2] = (H[2] + C) & 0xFFFFFFFF;
|
||||
H[3] = (H[3] + D) & 0xFFFFFFFF;
|
||||
H[4] = (H[4] + E) & 0xFFFFFFFF;
|
||||
|
||||
message_block_index = 0;
|
||||
}
|
||||
|
||||
/// Pads the current message block to 512 bits
|
||||
/**
|
||||
* According to the standard, the message must be padded to an even
|
||||
* 512 bits. The first padding bit must be a '1'. The last 64 bits
|
||||
* represent the length of the original message. All bits in between
|
||||
* should be 0. This function will pad the message according to those
|
||||
* rules by filling the message_block array accordingly. It will also
|
||||
* call ProcessMessageBlock() appropriately. When it returns, it
|
||||
* can be assumed that the message digest has been computed.
|
||||
*/
|
||||
void pad_message() {
|
||||
// Check to see if the current message block is too small to hold
|
||||
// the initial padding bits and length. If so, we will pad the
|
||||
// block, process it, and then continue padding into a second block.
|
||||
if (message_block_index > 55) {
|
||||
message_block[message_block_index++] = 0x80;
|
||||
while(message_block_index < 64) {
|
||||
message_block[message_block_index++] = 0;
|
||||
}
|
||||
|
||||
process_message_block();
|
||||
|
||||
while(message_block_index < 56) {
|
||||
message_block[message_block_index++] = 0;
|
||||
}
|
||||
} else {
|
||||
message_block[message_block_index++] = 0x80;
|
||||
while(message_block_index < 56) {
|
||||
message_block[message_block_index++] = 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Store the message length as the last 8 octets
|
||||
message_block[56] = (length_high >> 24) & 0xFF;
|
||||
message_block[57] = (length_high >> 16) & 0xFF;
|
||||
message_block[58] = (length_high >> 8) & 0xFF;
|
||||
message_block[59] = (length_high) & 0xFF;
|
||||
message_block[60] = (length_low >> 24) & 0xFF;
|
||||
message_block[61] = (length_low >> 16) & 0xFF;
|
||||
message_block[62] = (length_low >> 8) & 0xFF;
|
||||
message_block[63] = (length_low) & 0xFF;
|
||||
|
||||
process_message_block();
|
||||
}
|
||||
|
||||
/// Performs a circular left shift operation
|
||||
/**
|
||||
* @param [in] bits How many bits to shift
|
||||
* @param [in] word The word to shift
|
||||
* @return The shifted word
|
||||
*/
|
||||
inline uint32_t CircularShift(int bits, uint32_t word) {
|
||||
return ((word << bits) & 0xFFFFFFFF) | ((word & 0xFFFFFFFF) >> (32-bits));
|
||||
}
|
||||
|
||||
uint32_t H[5]; // Message digest buffers
|
||||
|
||||
uint32_t length_low; // Message length in bits
|
||||
uint32_t length_high; // Message length in bits
|
||||
|
||||
unsigned char message_block[64]; // 512-bit message blocks
|
||||
int message_block_index; // Index into message block array
|
||||
|
||||
bool computed; // Is the digest computed?
|
||||
bool corrupted; // Is the message digest corruped?
|
||||
|
||||
};
|
||||
|
||||
} // namespace websocketpp
|
||||
|
||||
|
||||
#endif // _SHA1_H_
|
||||
|
||||
@@ -1,169 +0,0 @@
|
||||
/*
|
||||
* shacmp.cpp
|
||||
*
|
||||
* Copyright (C) 1998, 2009
|
||||
* Paul E. Jones <paulej@packetizer.com>
|
||||
* All Rights Reserved
|
||||
*
|
||||
*****************************************************************************
|
||||
* $Id: shacmp.cpp 12 2009-06-22 19:34:25Z paulej $
|
||||
*****************************************************************************
|
||||
*
|
||||
* Description:
|
||||
* This utility will compare two files by producing a message digest
|
||||
* for each file using the Secure Hashing Algorithm and comparing
|
||||
* the message digests. This function will return 0 if they
|
||||
* compare or 1 if they do not or if there is an error.
|
||||
* Errors result in a return code higher than 1.
|
||||
*
|
||||
* Portability Issues:
|
||||
* none.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "sha1.h"
|
||||
|
||||
/*
|
||||
* Return codes
|
||||
*/
|
||||
#define SHA1_COMPARE 0
|
||||
#define SHA1_NO_COMPARE 1
|
||||
#define SHA1_USAGE_ERROR 2
|
||||
#define SHA1_FILE_ERROR 3
|
||||
|
||||
/*
|
||||
* Function prototype
|
||||
*/
|
||||
void usage();
|
||||
|
||||
/*
|
||||
* main
|
||||
*
|
||||
* Description:
|
||||
* This is the entry point for the program
|
||||
*
|
||||
* Parameters:
|
||||
* argc: [in]
|
||||
* This is the count of arguments in the argv array
|
||||
* argv: [in]
|
||||
* This is an array of filenames for which to compute message digests
|
||||
*
|
||||
* Returns:
|
||||
* Nothing.
|
||||
*
|
||||
* Comments:
|
||||
*
|
||||
*/
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
SHA1 sha; // SHA-1 class
|
||||
FILE *fp; // File pointer for reading files
|
||||
char c; // Character read from file
|
||||
unsigned message_digest[2][5]; // Message digest for files
|
||||
int i; // Counter
|
||||
bool message_match; // Message digest match flag
|
||||
int returncode;
|
||||
|
||||
/*
|
||||
* If we have two arguments, we will assume they are filenames. If
|
||||
* we do not have to arguments, call usage() and exit.
|
||||
*/
|
||||
if (argc != 3)
|
||||
{
|
||||
usage();
|
||||
return SHA1_USAGE_ERROR;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the message digests for each file
|
||||
*/
|
||||
for(i = 1; i <= 2; i++)
|
||||
{
|
||||
sha.Reset();
|
||||
|
||||
if (!(fp = fopen(argv[i],"rb")))
|
||||
{
|
||||
fprintf(stderr, "sha: unable to open file %s\n", argv[i]);
|
||||
return SHA1_FILE_ERROR;
|
||||
}
|
||||
|
||||
c = fgetc(fp);
|
||||
while(!feof(fp))
|
||||
{
|
||||
sha.Input(c);
|
||||
c = fgetc(fp);
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
|
||||
if (!sha.Result(message_digest[i-1]))
|
||||
{
|
||||
fprintf(stderr,"shacmp: could not compute message digest for %s\n",
|
||||
argv[i]);
|
||||
return SHA1_FILE_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Compare the message digest values
|
||||
*/
|
||||
message_match = true;
|
||||
for(i = 0; i < 5; i++)
|
||||
{
|
||||
if (message_digest[0][i] != message_digest[1][i])
|
||||
{
|
||||
message_match = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (message_match)
|
||||
{
|
||||
printf("Fingerprints match:\n");
|
||||
returncode = SHA1_COMPARE;
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("Fingerprints do not match:\n");
|
||||
returncode = SHA1_NO_COMPARE;
|
||||
}
|
||||
|
||||
printf( "\t%08X %08X %08X %08X %08X\n",
|
||||
message_digest[0][0],
|
||||
message_digest[0][1],
|
||||
message_digest[0][2],
|
||||
message_digest[0][3],
|
||||
message_digest[0][4]);
|
||||
printf( "\t%08X %08X %08X %08X %08X\n",
|
||||
message_digest[1][0],
|
||||
message_digest[1][1],
|
||||
message_digest[1][2],
|
||||
message_digest[1][3],
|
||||
message_digest[1][4]);
|
||||
|
||||
return returncode;
|
||||
}
|
||||
|
||||
/*
|
||||
* usage
|
||||
*
|
||||
* Description:
|
||||
* This function will display program usage information to the user.
|
||||
*
|
||||
* Parameters:
|
||||
* None.
|
||||
*
|
||||
* Returns:
|
||||
* Nothing.
|
||||
*
|
||||
* Comments:
|
||||
*
|
||||
*/
|
||||
void usage()
|
||||
{
|
||||
printf("usage: shacmp <file> <file>\n");
|
||||
printf("\tThis program will compare the message digests (fingerprints)\n");
|
||||
printf("\tfor two files using the Secure Hashing Algorithm (SHA-1).\n");
|
||||
}
|
||||
@@ -1,149 +0,0 @@
|
||||
/*
|
||||
* shatest.cpp
|
||||
*
|
||||
* Copyright (C) 1998, 2009
|
||||
* Paul E. Jones <paulej@packetizer.com>
|
||||
* All Rights Reserved
|
||||
*
|
||||
*****************************************************************************
|
||||
* $Id: shatest.cpp 12 2009-06-22 19:34:25Z paulej $
|
||||
*****************************************************************************
|
||||
*
|
||||
* Description:
|
||||
* This file will exercise the SHA1 class and perform the three
|
||||
* tests documented in FIPS PUB 180-1.
|
||||
*
|
||||
* Portability Issues:
|
||||
* None.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <iostream>
|
||||
#include "sha1.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
/*
|
||||
* Define patterns for testing
|
||||
*/
|
||||
#define TESTA "abc"
|
||||
#define TESTB "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"
|
||||
|
||||
/*
|
||||
* Function prototype
|
||||
*/
|
||||
void DisplayMessageDigest(unsigned *message_digest);
|
||||
|
||||
/*
|
||||
* main
|
||||
*
|
||||
* Description:
|
||||
* This is the entry point for the program
|
||||
*
|
||||
* Parameters:
|
||||
* None.
|
||||
*
|
||||
* Returns:
|
||||
* Nothing.
|
||||
*
|
||||
* Comments:
|
||||
*
|
||||
*/
|
||||
int main()
|
||||
{
|
||||
SHA1 sha;
|
||||
unsigned message_digest[5];
|
||||
|
||||
/*
|
||||
* Perform test A
|
||||
*/
|
||||
cout << endl << "Test A: 'abc'" << endl;
|
||||
|
||||
sha.Reset();
|
||||
sha << TESTA;
|
||||
|
||||
if (!sha.Result(message_digest))
|
||||
{
|
||||
cerr << "ERROR-- could not compute message digest" << endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
DisplayMessageDigest(message_digest);
|
||||
cout << "Should match:" << endl;
|
||||
cout << '\t' << "A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D" << endl;
|
||||
}
|
||||
|
||||
/*
|
||||
* Perform test B
|
||||
*/
|
||||
cout << endl << "Test B: " << TESTB << endl;
|
||||
|
||||
sha.Reset();
|
||||
sha << TESTB;
|
||||
|
||||
if (!sha.Result(message_digest))
|
||||
{
|
||||
cerr << "ERROR-- could not compute message digest" << endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
DisplayMessageDigest(message_digest);
|
||||
cout << "Should match:" << endl;
|
||||
cout << '\t' << "84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1" << endl;
|
||||
}
|
||||
|
||||
/*
|
||||
* Perform test C
|
||||
*/
|
||||
cout << endl << "Test C: One million 'a' characters" << endl;
|
||||
|
||||
sha.Reset();
|
||||
for(int i = 1; i <= 1000000; i++) sha.Input('a');
|
||||
|
||||
if (!sha.Result(message_digest))
|
||||
{
|
||||
cerr << "ERROR-- could not compute message digest" << endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
DisplayMessageDigest(message_digest);
|
||||
cout << "Should match:" << endl;
|
||||
cout << '\t' << "34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F" << endl;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* DisplayMessageDigest
|
||||
*
|
||||
* Description:
|
||||
* Display Message Digest array
|
||||
*
|
||||
* Parameters:
|
||||
* None.
|
||||
*
|
||||
* Returns:
|
||||
* Nothing.
|
||||
*
|
||||
* Comments:
|
||||
*
|
||||
*/
|
||||
void DisplayMessageDigest(unsigned *message_digest)
|
||||
{
|
||||
ios::fmtflags flags;
|
||||
|
||||
cout << '\t';
|
||||
|
||||
flags = cout.setf(ios::hex|ios::uppercase,ios::basefield);
|
||||
cout.setf(ios::uppercase);
|
||||
|
||||
for(int i = 0; i < 5 ; i++)
|
||||
{
|
||||
cout << message_digest[i] << ' ';
|
||||
}
|
||||
|
||||
cout << endl;
|
||||
|
||||
cout.setf(flags);
|
||||
}
|
||||
@@ -39,42 +39,39 @@
|
||||
namespace websocketpp {
|
||||
namespace transport {
|
||||
/// Transport policy that uses boost::asio
|
||||
namespace asio {
|
||||
|
||||
typedef lib::function<void(const boost::system::error_code &)>
|
||||
socket_shutdown_handler;
|
||||
|
||||
/**
|
||||
* This policy uses a single boost::asio io_service to provide transport
|
||||
* services to a WebSocket++ endpoint.
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
* services to a WebSocket++ endpoint.
|
||||
*/
|
||||
namespace asio {
|
||||
|
||||
typedef lib::function<void(boost::system::error_code const &)>
|
||||
socket_shutdown_handler;
|
||||
|
||||
/// Asio transport errors
|
||||
namespace error {
|
||||
enum value {
|
||||
/// Catch-all error for transport policy errors that don't fit in other
|
||||
/// categories
|
||||
general = 1,
|
||||
|
||||
|
||||
/// async_read_at_least call requested more bytes than buffer can store
|
||||
invalid_num_bytes,
|
||||
|
||||
|
||||
/// there was an error in the underlying transport library
|
||||
pass_through,
|
||||
|
||||
|
||||
/// The connection to the requested proxy server failed
|
||||
proxy_failed,
|
||||
|
||||
|
||||
/// Invalid Proxy URI
|
||||
proxy_invalid
|
||||
};
|
||||
|
||||
/// Asio transport error category
|
||||
class category : public lib::error_category {
|
||||
public:
|
||||
const char *name() const _WEBSOCKETPP_NOEXCEPT_TOKEN_ {
|
||||
char const * name() const _WEBSOCKETPP_NOEXCEPT_TOKEN_ {
|
||||
return "websocketpp.transport.asio";
|
||||
}
|
||||
|
||||
@@ -96,11 +93,13 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
inline const lib::error_category& get_category() {
|
||||
/// Get a reference to a static copy of the asio transport error category
|
||||
inline lib::error_category const & get_category() {
|
||||
static category instance;
|
||||
return instance;
|
||||
}
|
||||
|
||||
/// Create an error code with the given value and the asio transport category
|
||||
inline lib::error_code make_error_code(error::value e) {
|
||||
return lib::error_code(static_cast<int>(e), get_category());
|
||||
}
|
||||
@@ -113,7 +112,7 @@ inline lib::error_code make_error_code(error::value e) {
|
||||
_WEBSOCKETPP_ERROR_CODE_ENUM_NS_START_
|
||||
template<> struct is_error_code_enum<websocketpp::transport::asio::error::value>
|
||||
{
|
||||
static const bool value = true;
|
||||
static bool const value = true;
|
||||
};
|
||||
_WEBSOCKETPP_ERROR_CODE_ENUM_NS_END_
|
||||
#endif // WEBSOCKETPP_TRANSPORT_ASIO_HPP
|
||||
|
||||
@@ -771,7 +771,7 @@ protected:
|
||||
*
|
||||
* Might need a strand at some point?
|
||||
*/
|
||||
lib::error_code interrupt(inturrupt_handler handler) {
|
||||
lib::error_code interrupt(interrupt_handler handler) {
|
||||
m_io_service->post(handler);
|
||||
return lib::error_code();
|
||||
}
|
||||
@@ -781,7 +781,7 @@ protected:
|
||||
return lib::error_code();
|
||||
}
|
||||
|
||||
/*void handle_inturrupt(inturrupt_handler handler) {
|
||||
/*void handle_interrupt(interrupt_handler handler) {
|
||||
handler();
|
||||
}*/
|
||||
|
||||
|
||||
@@ -414,22 +414,23 @@ protected:
|
||||
host = u->get_host();
|
||||
port = u->get_port_str();
|
||||
} else {
|
||||
try {
|
||||
lib::error_code ec;
|
||||
lib::error_code ec;
|
||||
|
||||
uri_ptr pu(new uri(proxy));
|
||||
ec = tcon->proxy_init(u->get_authority());
|
||||
if (ec) {
|
||||
cb(tcon->get_handle(),ec);
|
||||
return;
|
||||
}
|
||||
|
||||
host = pu->get_host();
|
||||
port = pu->get_port_str();
|
||||
} catch (uri_exception) {
|
||||
uri_ptr pu(new uri(proxy));
|
||||
|
||||
if (!pu->get_valid()) {
|
||||
cb(tcon->get_handle(),make_error_code(error::proxy_invalid));
|
||||
return;
|
||||
}
|
||||
|
||||
ec = tcon->proxy_init(u->get_authority());
|
||||
if (ec) {
|
||||
cb(tcon->get_handle(),ec);
|
||||
return;
|
||||
}
|
||||
|
||||
host = pu->get_host();
|
||||
port = pu->get_port_str();
|
||||
}
|
||||
|
||||
tcp::resolver::query query(host,port);
|
||||
|
||||
@@ -41,7 +41,7 @@
|
||||
|
||||
// Interface that sockets/security policies must implement
|
||||
|
||||
/**
|
||||
/*
|
||||
* Endpoint Interface
|
||||
*
|
||||
* bool is_secure() const;
|
||||
@@ -55,10 +55,10 @@
|
||||
*/
|
||||
|
||||
|
||||
/// Connection
|
||||
/// TODO
|
||||
/// pre_init(init_handler);
|
||||
/// post_init(init_handler);
|
||||
// Connection
|
||||
// TODO
|
||||
// pre_init(init_handler);
|
||||
// post_init(init_handler);
|
||||
|
||||
namespace websocketpp {
|
||||
namespace transport {
|
||||
|
||||
@@ -35,51 +35,76 @@
|
||||
#include <websocketpp/common/system_error.hpp>
|
||||
|
||||
namespace websocketpp {
|
||||
/// Transport policies provide network connectivity and timers
|
||||
/**
|
||||
* ### Connection Interface
|
||||
*
|
||||
* Transport connection components needs to provide:
|
||||
*
|
||||
* *Warning: This documentation section and the transport connection interface
|
||||
* are not complete.*
|
||||
*
|
||||
* **async_read_at_least**\n
|
||||
* `void async_read_at_least(size_t num_bytes, char *buf, size_t len,
|
||||
* read_handler handler)`\n
|
||||
* start an async read for at least num_bytes and at most len
|
||||
* bytes into buf. Call handler when done with number of bytes read.
|
||||
*
|
||||
* WebSocket++ promises to have only one async_read_at_least in flight at a
|
||||
* time. The transport must promise to only call read_handler once per async
|
||||
* read
|
||||
*
|
||||
* **async_write**\n
|
||||
* `void async_write(const char* buf, size_t len, write_handler handler)`\n
|
||||
* `void async_write(std::vector<buffer> & bufs, write_handler handler)`\n
|
||||
* Start a write of all of the data in buf or bufs. In second case data is
|
||||
* written sequentially and in place without copying anything to a temporary
|
||||
* location.
|
||||
*
|
||||
* Websocket++ promises to have only one async_write in flight at a time.
|
||||
* The transport must promise to only call the write_handler once per async
|
||||
* write
|
||||
*
|
||||
* **remote_endpoint**\n
|
||||
* `std::string remote_endpoint()`\n
|
||||
* retrieve address of remote endpoint
|
||||
*
|
||||
* **is_secure**\n
|
||||
* `void is_secure()`\n
|
||||
* whether or not the connection to the remote endpoint is secure
|
||||
*
|
||||
* **dispatch**\n
|
||||
* `lib::error_code dispatch(dispatch_handler handler)`: invoke handler within
|
||||
* the transport's event system if it uses one.
|
||||
*/
|
||||
namespace transport {
|
||||
|
||||
/**
|
||||
* Transport needs to provide:
|
||||
* - async_read_at_least(size_t num_bytes, char *buf, size_t len, read_handler handler)
|
||||
* start an async read for at least num_bytes and at most len bytes into buf. Call
|
||||
* handler when done with number of bytes read.
|
||||
*
|
||||
* WebSocket++ promises to have only one async_read_at_least in flight at a
|
||||
* time. The transport must promise to only call read_handler once per async
|
||||
* read
|
||||
*
|
||||
* - async_write(const char* buf, size_t len, write_handler handler)
|
||||
* - async_write(std::vector<buffer> & bufs, write_handler handler)
|
||||
* start an async write of all of the data in buf or bufs. In second case data
|
||||
* is written sequentially and in place without copying anything to a temporary
|
||||
* location.
|
||||
*
|
||||
* Websocket++ promises to have only one async_write in flight at a time.
|
||||
* The transport must promise to only call the write_handler once per async
|
||||
* write
|
||||
*
|
||||
* - std::string remote_endpoint(): retrieve address of remote endpoint
|
||||
* - is_secure(): whether or not the connection to the remote endpoint is secure
|
||||
* - lib::error_code dispatch(dispatch_handler handler): invoke handler within
|
||||
* the transport's event system if it uses one.
|
||||
*/
|
||||
/// The type and signature of the callback passed to the init hook
|
||||
typedef lib::function<void(lib::error_code const &)> init_handler;
|
||||
|
||||
/// The type and signature of the callback passed to the read method
|
||||
typedef lib::function<void(lib::error_code const &,size_t)> read_handler;
|
||||
|
||||
/// The type and signature of the callback passed to the write method
|
||||
typedef lib::function<void(lib::error_code const &)> write_handler;
|
||||
|
||||
// Connection callbacks
|
||||
typedef lib::function<void(const lib::error_code&)> init_handler;
|
||||
typedef lib::function<void(const lib::error_code&,size_t)> read_handler;
|
||||
typedef lib::function<void(const lib::error_code&)> write_handler;
|
||||
typedef lib::function<void(const lib::error_code&)> timer_handler;
|
||||
typedef lib::function<void(const lib::error_code&)> shutdown_handler;
|
||||
typedef lib::function<void()> inturrupt_handler;
|
||||
/// The type and signature of the callback passed to the read method
|
||||
typedef lib::function<void(lib::error_code const &)> timer_handler;
|
||||
|
||||
/// The type and signature of the callback passed to the shutdown method
|
||||
typedef lib::function<void(lib::error_code const &)> shutdown_handler;
|
||||
|
||||
/// The type and signature of the callback passed to the interrupt method
|
||||
typedef lib::function<void()> interrupt_handler;
|
||||
|
||||
/// The type and signature of the callback passed to the dispatch method
|
||||
typedef lib::function<void()> dispatch_handler;
|
||||
|
||||
typedef lib::function<void()> connection_lock;
|
||||
|
||||
/// A simple utility buffer class
|
||||
struct buffer {
|
||||
buffer(const char * b, size_t l) : buf(b),len(l) {}
|
||||
buffer(char const * b, size_t l) : buf(b),len(l) {}
|
||||
|
||||
const char* buf;
|
||||
char const * buf;
|
||||
size_t len;
|
||||
};
|
||||
|
||||
@@ -118,7 +143,7 @@ class category : public lib::error_category {
|
||||
public:
|
||||
category() {}
|
||||
|
||||
const char *name() const _WEBSOCKETPP_NOEXCEPT_TOKEN_ {
|
||||
char const * name() const _WEBSOCKETPP_NOEXCEPT_TOKEN_ {
|
||||
return "websocketpp.transport";
|
||||
}
|
||||
|
||||
@@ -146,7 +171,7 @@ class category : public lib::error_category {
|
||||
}
|
||||
};
|
||||
|
||||
inline const lib::error_category& get_category() {
|
||||
inline lib::error_category const & get_category() {
|
||||
static category instance;
|
||||
return instance;
|
||||
}
|
||||
@@ -161,7 +186,7 @@ inline lib::error_code make_error_code(error::value e) {
|
||||
_WEBSOCKETPP_ERROR_CODE_ENUM_NS_START_
|
||||
template<> struct is_error_code_enum<websocketpp::transport::error::value>
|
||||
{
|
||||
static const bool value = true;
|
||||
static bool const value = true;
|
||||
};
|
||||
_WEBSOCKETPP_ERROR_CODE_ENUM_NS_END_
|
||||
|
||||
|
||||
@@ -38,30 +38,27 @@
|
||||
|
||||
namespace websocketpp {
|
||||
/// Transport policies provide network connectivity and timers
|
||||
namespace transport {
|
||||
|
||||
// Endpoint callbacks
|
||||
typedef lib::function<void(connection_hdl,const lib::error_code&)> accept_handler;
|
||||
typedef lib::function<void(connection_hdl,const lib::error_code&)> connect_handler;
|
||||
|
||||
typedef lib::function<void()> endpoint_lock;
|
||||
|
||||
// Endpoint interface
|
||||
// Methods a transport endpoint must implement
|
||||
|
||||
/// Initialize a connection
|
||||
/**
|
||||
* Signature: lib::error_code init(transport_con_ptr tcon);
|
||||
*
|
||||
* ### Endpoint Interface
|
||||
*
|
||||
* Transport endpoint components needs to provide:
|
||||
*
|
||||
* **init**\n
|
||||
* `lib::error_code init(transport_con_ptr tcon)`\n
|
||||
* init is called by an endpoint once for each newly created connection.
|
||||
* It's purpose is to give the transport policy the chance to perform any
|
||||
* transport specific initialization that couldn't be done via the default
|
||||
* constructor.
|
||||
*
|
||||
* @param tcon A pointer to the transport portion of the connection.
|
||||
*
|
||||
* @return A status code indicating the success or failure of the operation
|
||||
*/
|
||||
namespace transport {
|
||||
|
||||
/// The type and signature of the callback passed to the accept method
|
||||
typedef lib::function<void(connection_hdl, lib::error_code const &)>
|
||||
accept_handler;
|
||||
|
||||
/// The type and signature of the callback passed to the connect method
|
||||
typedef lib::function<void(connection_hdl, lib::error_code const &)>
|
||||
connect_handler;
|
||||
|
||||
} // namespace transport
|
||||
} // namespace websocketpp
|
||||
|
||||
@@ -38,6 +38,7 @@ namespace transport {
|
||||
/// Transport policy that uses STL iostream for I/O and does not support timers
|
||||
namespace iostream {
|
||||
|
||||
/// iostream transport errors
|
||||
namespace error {
|
||||
enum value {
|
||||
/// Catch-all error for transport policy errors that don't fit in other
|
||||
@@ -58,11 +59,12 @@ enum value {
|
||||
bad_stream
|
||||
};
|
||||
|
||||
/// iostream transport error category
|
||||
class category : public lib::error_category {
|
||||
public:
|
||||
category() {}
|
||||
|
||||
const char *name() const _WEBSOCKETPP_NOEXCEPT_TOKEN_ {
|
||||
char const * name() const _WEBSOCKETPP_NOEXCEPT_TOKEN_ {
|
||||
return "websocketpp.transport.iostream";
|
||||
}
|
||||
|
||||
@@ -84,11 +86,13 @@ class category : public lib::error_category {
|
||||
}
|
||||
};
|
||||
|
||||
inline const lib::error_category& get_category() {
|
||||
/// Get a reference to a static copy of the iostream transport error category
|
||||
inline lib::error_category const & get_category() {
|
||||
static category instance;
|
||||
return instance;
|
||||
}
|
||||
|
||||
/// Get an error code with the given value and the iostream transport category
|
||||
inline lib::error_code make_error_code(error::value e) {
|
||||
return lib::error_code(static_cast<int>(e), get_category());
|
||||
}
|
||||
@@ -100,7 +104,7 @@ inline lib::error_code make_error_code(error::value e) {
|
||||
_WEBSOCKETPP_ERROR_CODE_ENUM_NS_START_
|
||||
template<> struct is_error_code_enum<websocketpp::transport::iostream::error::value>
|
||||
{
|
||||
static const bool value = true;
|
||||
static bool const value = true;
|
||||
};
|
||||
_WEBSOCKETPP_ERROR_CODE_ENUM_NS_END_
|
||||
|
||||
|
||||
+135
-114
@@ -29,89 +29,50 @@
|
||||
#define WEBSOCKETPP_URI_HPP
|
||||
|
||||
#include <websocketpp/common/memory.hpp>
|
||||
#include <websocketpp/common/regex.hpp>
|
||||
#include <websocketpp/error.hpp>
|
||||
|
||||
#include <exception>
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
|
||||
namespace websocketpp {
|
||||
|
||||
// WebSocket URI only (not http/etc)
|
||||
|
||||
class uri_exception : public std::exception {
|
||||
public:
|
||||
uri_exception(const std::string& msg) : m_msg(msg) {}
|
||||
~uri_exception() throw() {}
|
||||
|
||||
virtual const char* what() const throw() {
|
||||
return m_msg.c_str();
|
||||
}
|
||||
private:
|
||||
std::string m_msg;
|
||||
};
|
||||
|
||||
// TODO: figure out why this fixes horrible linking errors.
|
||||
static const uint16_t URI_DEFAULT_PORT = 80;
|
||||
static const uint16_t uri_default_port = 80;
|
||||
static const uint16_t URI_DEFAULT_SECURE_PORT = 443;
|
||||
static const uint16_t uri_default_secure_port = 443;
|
||||
|
||||
/// Default port for ws://
|
||||
static uint16_t const uri_default_port = 80;
|
||||
/// Default port for wss://
|
||||
static uint16_t const uri_default_secure_port = 443;
|
||||
|
||||
class uri {
|
||||
public:
|
||||
explicit uri(const std::string& uri) {
|
||||
// TODO: should this split resource into path/query?
|
||||
lib::cmatch matches;
|
||||
const lib::regex expression("(http|https|ws|wss)://([^/:\\[]+|\\[[0-9a-fA-F:.]+\\])(:\\d{1,5})?(/[^#]*)?");
|
||||
|
||||
if (lib::regex_match(uri.c_str(), matches, expression)) {
|
||||
m_scheme = matches[1];
|
||||
m_secure = (m_scheme == "wss" || m_scheme == "https");
|
||||
m_host = matches[2];
|
||||
|
||||
// strip brackets from IPv6 literal URIs
|
||||
if (m_host[0] == '[') {
|
||||
m_host = m_host.substr(1,m_host.size()-2);
|
||||
}
|
||||
|
||||
std::string port(matches[3]);
|
||||
|
||||
if (port != "") {
|
||||
// strip off the :
|
||||
// this could probably be done with a better regex.
|
||||
port = port.substr(1);
|
||||
}
|
||||
|
||||
m_port = get_port_from_string(port);
|
||||
|
||||
m_resource = matches[4];
|
||||
|
||||
if (m_resource == "") {
|
||||
m_resource = "/";
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
throw websocketpp::uri_exception("Error parsing WebSocket URI");
|
||||
}
|
||||
|
||||
/*explicit uri(const std::string& uri) {
|
||||
// test for ws or wss
|
||||
explicit uri(std::string const & uri) : m_valid(false) {
|
||||
std::string::const_iterator it;
|
||||
std::string::const_iterator temp;
|
||||
|
||||
int state = 0;
|
||||
|
||||
it = uri.begin();
|
||||
|
||||
if (std::equal(it,it+6,"wss://")) {
|
||||
m_secure = true;
|
||||
m_scheme = "wss";
|
||||
it += 6;
|
||||
} else if (std::equal(it,it+5,"ws://")) {
|
||||
m_secure = false;
|
||||
m_scheme = "ws";
|
||||
it += 5;
|
||||
} else if (std::equal(it,it+7,"http://")) {
|
||||
m_secure = false;
|
||||
m_scheme = "http";
|
||||
it += 7;
|
||||
} else if (std::equal(it,it+8,"https://")) {
|
||||
m_secure = true;
|
||||
m_scheme = "https";
|
||||
it += 8;
|
||||
} else {
|
||||
// error
|
||||
return;
|
||||
}
|
||||
|
||||
// extract host.
|
||||
@@ -122,101 +83,156 @@ public:
|
||||
++it;
|
||||
// IPv6 literal
|
||||
// extract IPv6 digits until ]
|
||||
temp = std::find(it,uri.end(),']');
|
||||
|
||||
// TODO: this doesn't work on g++... not sure why
|
||||
//temp = std::find(it,it2,']');
|
||||
|
||||
temp = it;
|
||||
while (temp != uri.end()) {
|
||||
if (*temp == ']') {
|
||||
break;
|
||||
}
|
||||
++temp;
|
||||
}
|
||||
|
||||
if (temp == uri.end()) {
|
||||
// error
|
||||
return;
|
||||
} else {
|
||||
// validate IPv6 literal parts
|
||||
// can contain numbers, a-f and A-F
|
||||
m_host.append(it,temp);
|
||||
}
|
||||
it = temp+1;
|
||||
if (it == uri.end()) {
|
||||
state = 2;
|
||||
} else if (*it == '/') {
|
||||
state = 2;
|
||||
++it;
|
||||
} else if (*it == ':') {
|
||||
state = 1;
|
||||
++it;
|
||||
} else {
|
||||
// problem
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
// IPv4 or hostname
|
||||
// extract until : or /
|
||||
while (state == 0) {
|
||||
if (it == uri.end()) {
|
||||
state = 2;
|
||||
break;
|
||||
} else if (*it == '/') {
|
||||
state = 2;
|
||||
} else if (*it == ':') {
|
||||
// end hostname start port
|
||||
state = 1;
|
||||
} else {
|
||||
m_host += *it;
|
||||
}
|
||||
++it;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: should this split resource into path/query?
|
||||
lib::cmatch matches;
|
||||
const lib::regex expression("(ws|wss)://([^/:\\[]+|\\[[0-9a-fA-F:.]+\\])(:\\d{1,5})?(/[^#]*)?");
|
||||
|
||||
if (lib::regex_match(uri.c_str(), matches, expression)) {
|
||||
m_secure = (matches[1] == "wss");
|
||||
m_host = matches[2];
|
||||
|
||||
// strip brackets from IPv6 literal URIs
|
||||
if (m_host[0] == '[') {
|
||||
m_host = m_host.substr(1,m_host.size()-2);
|
||||
|
||||
// parse port
|
||||
std::string port = "";
|
||||
while (state == 1) {
|
||||
if (it == uri.end()) {
|
||||
state = 3;
|
||||
break;
|
||||
} else if (*it == '/') {
|
||||
state = 3;
|
||||
} else {
|
||||
port += *it;
|
||||
}
|
||||
|
||||
std::string port(matches[3]);
|
||||
|
||||
if (port != "") {
|
||||
// strip off the :
|
||||
// this could probably be done with a better regex.
|
||||
port = port.substr(1);
|
||||
}
|
||||
|
||||
m_port = get_port_from_string(port);
|
||||
|
||||
m_resource = matches[4];
|
||||
|
||||
if (m_resource == "") {
|
||||
m_resource = "/";
|
||||
}
|
||||
|
||||
++it;
|
||||
}
|
||||
|
||||
lib::error_code ec;
|
||||
m_port = get_port_from_string(port, ec);
|
||||
|
||||
if (ec) {
|
||||
return;
|
||||
}
|
||||
|
||||
throw websocketpp::uri_exception("Error parsing WebSocket URI");
|
||||
|
||||
}*/
|
||||
m_resource = "/";
|
||||
m_resource.append(it,uri.end());
|
||||
|
||||
|
||||
m_valid = true;
|
||||
}
|
||||
|
||||
uri(bool secure, const std::string& host, uint16_t port, const std::string& resource)
|
||||
uri(bool secure, std::string const & host, uint16_t port,
|
||||
std::string const & resource)
|
||||
: m_scheme(secure ? "wss" : "ws")
|
||||
, m_host(host)
|
||||
, m_resource(resource == "" ? "/" : resource)
|
||||
, m_port(port)
|
||||
, m_secure(secure) {}
|
||||
, m_secure(secure)
|
||||
, m_valid(true) {}
|
||||
|
||||
uri(bool secure, const std::string& host, const std::string& resource)
|
||||
uri(bool secure, std::string const & host, std::string const & resource)
|
||||
: m_scheme(secure ? "wss" : "ws")
|
||||
, m_host(host)
|
||||
, m_resource(resource == "" ? "/" : resource)
|
||||
, m_port(secure ? uri_default_secure_port : uri_default_port)
|
||||
, m_secure(secure) {}
|
||||
, m_secure(secure)
|
||||
, m_valid(true) {}
|
||||
|
||||
uri(bool secure, const std::string& host, const std::string& port, const std::string& resource)
|
||||
uri(bool secure, std::string const & host, std::string const & port,
|
||||
std::string const & resource)
|
||||
: m_scheme(secure ? "wss" : "ws")
|
||||
, m_host(host)
|
||||
, m_resource(resource == "" ? "/" : resource)
|
||||
, m_port(get_port_from_string(port))
|
||||
, m_secure(secure) {}
|
||||
, m_secure(secure)
|
||||
{
|
||||
lib::error_code ec;
|
||||
m_port = get_port_from_string(port,ec);
|
||||
m_valid = !ec;
|
||||
}
|
||||
|
||||
|
||||
uri(std::string scheme, const std::string& host, uint16_t port, const std::string& resource)
|
||||
uri(std::string const & scheme, std::string const & host, uint16_t port,
|
||||
std::string const & resource)
|
||||
: m_scheme(scheme)
|
||||
, m_host(host)
|
||||
, m_resource(resource == "" ? "/" : resource)
|
||||
, m_port(port)
|
||||
, m_secure(scheme == "wss" || scheme == "https") {}
|
||||
, m_secure(scheme == "wss" || scheme == "https")
|
||||
, m_valid(true) {}
|
||||
|
||||
uri(std::string scheme, const std::string& host, const std::string& resource)
|
||||
uri(std::string scheme, std::string const & host, std::string const & resource)
|
||||
: m_scheme(scheme)
|
||||
, m_host(host)
|
||||
, m_resource(resource == "" ? "/" : resource)
|
||||
, m_port((scheme == "wss" || scheme == "https") ? uri_default_secure_port : uri_default_port)
|
||||
, m_secure(scheme == "wss" || scheme == "https") {}
|
||||
, m_secure(scheme == "wss" || scheme == "https")
|
||||
, m_valid(true) {}
|
||||
|
||||
uri(std::string scheme, const std::string& host, const std::string& port, const std::string& resource)
|
||||
uri(std::string const & scheme, std::string const & host,
|
||||
std::string const & port, std::string const & resource)
|
||||
: m_scheme(scheme)
|
||||
, m_host(host)
|
||||
, m_resource(resource == "" ? "/" : resource)
|
||||
, m_port(get_port_from_string(port))
|
||||
, m_secure(scheme == "wss" || scheme == "https") {}
|
||||
, m_secure(scheme == "wss" || scheme == "https")
|
||||
{
|
||||
lib::error_code ec;
|
||||
m_port = get_port_from_string(port,ec);
|
||||
m_valid = !ec;
|
||||
}
|
||||
|
||||
bool get_valid() const {
|
||||
return m_valid;
|
||||
}
|
||||
|
||||
bool get_secure() const {
|
||||
return m_secure;
|
||||
}
|
||||
|
||||
const std::string& get_host() const {
|
||||
std::string const & get_scheme() const {
|
||||
return m_scheme;
|
||||
}
|
||||
|
||||
std::string const & get_host() const {
|
||||
return m_host;
|
||||
}
|
||||
|
||||
@@ -246,7 +262,7 @@ public:
|
||||
return p.str();
|
||||
}
|
||||
|
||||
const std::string& get_resource() const {
|
||||
std::string const & get_resource() const {
|
||||
return m_resource;
|
||||
}
|
||||
|
||||
@@ -282,7 +298,11 @@ public:
|
||||
void set_port(const std::string& port);
|
||||
void set_resource(const std::string& resource);*/
|
||||
private:
|
||||
uint16_t get_port_from_string(const std::string& port) const {
|
||||
uint16_t get_port_from_string(std::string const & port, lib::error_code &
|
||||
ec) const
|
||||
{
|
||||
ec = lib::error_code();
|
||||
|
||||
if (port == "") {
|
||||
return (m_secure ? uri_default_secure_port : uri_default_port);
|
||||
}
|
||||
@@ -290,11 +310,11 @@ private:
|
||||
unsigned int t_port = static_cast<unsigned int>(atoi(port.c_str()));
|
||||
|
||||
if (t_port > 65535) {
|
||||
throw websocketpp::uri_exception("Port must be less than 65535");
|
||||
ec = error::make_error_code(error::invalid_port);
|
||||
}
|
||||
|
||||
if (t_port == 0) {
|
||||
throw websocketpp::uri_exception("Error parsing port string: "+port);
|
||||
ec = error::make_error_code(error::invalid_port);
|
||||
}
|
||||
|
||||
return static_cast<uint16_t>(t_port);
|
||||
@@ -305,6 +325,7 @@ private:
|
||||
std::string m_resource;
|
||||
uint16_t m_port;
|
||||
bool m_secure;
|
||||
bool m_valid;
|
||||
};
|
||||
|
||||
typedef lib::shared_ptr<uri> uri_ptr;
|
||||
|
||||
+121
-26
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2012, 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:
|
||||
@@ -28,55 +28,150 @@
|
||||
#ifndef WEBSOCKETPP_UTILITIES_HPP
|
||||
#define WEBSOCKETPP_UTILITIES_HPP
|
||||
|
||||
#include <algorithm>
|
||||
#include <websocketpp/common/stdint.hpp>
|
||||
|
||||
#include <algorithm>
|
||||
#include <string>
|
||||
|
||||
namespace websocketpp {
|
||||
/// Generic non-websocket specific utility functions and data structures
|
||||
namespace utility {
|
||||
|
||||
// case insensitive find
|
||||
// http://stackoverflow.com/questions/3152241/case-insensitive-stdstring-find
|
||||
|
||||
// templated version of my_equal so it could work with both char and wchar_t
|
||||
/// Helper functor for case insensitive find
|
||||
/**
|
||||
* Based on code from
|
||||
* http://stackoverflow.com/questions/3152241/case-insensitive-stdstring-find
|
||||
*
|
||||
* templated version of my_equal so it could work with both char and wchar_t
|
||||
*/
|
||||
template<typename charT>
|
||||
struct my_equal {
|
||||
my_equal( const std::locale& loc ) : loc_(loc) {}
|
||||
/// Construct the functor with the given locale
|
||||
/**
|
||||
* @param [in] loc The locale to use for determining the case of values
|
||||
*/
|
||||
my_equal(std::locale const & loc ) : m_loc(loc) {}
|
||||
|
||||
/// Perform a case insensitive comparison
|
||||
/**
|
||||
* @param ch1 The first value to compare
|
||||
* @param ch2 The second value to compare
|
||||
* @return Whether or not the two values are equal when both are converted
|
||||
* to uppercase using the given locale.
|
||||
*/
|
||||
bool operator()(charT ch1, charT ch2) {
|
||||
return std::toupper(ch1, loc_) == std::toupper(ch2, loc_);
|
||||
return std::toupper(ch1, m_loc) == std::toupper(ch2, m_loc);
|
||||
}
|
||||
private:
|
||||
const std::locale& loc_;
|
||||
std::locale const & m_loc;
|
||||
};
|
||||
|
||||
// find substring (case insensitive)
|
||||
/// Helper less than functor for case insensitive find
|
||||
/**
|
||||
* Based on code from
|
||||
* http://stackoverflow.com/questions/3152241/case-insensitive-stdstring-find
|
||||
*/
|
||||
struct ci_less : std::binary_function<std::string, std::string, bool> {
|
||||
// case-independent (ci) compare_less binary function
|
||||
struct nocase_compare
|
||||
: public std::binary_function<unsigned char,unsigned char,bool>
|
||||
{
|
||||
bool operator() (unsigned char const & c1, unsigned char const & c2) const {
|
||||
return std::tolower (c1) < std::tolower (c2);
|
||||
}
|
||||
};
|
||||
bool operator() (std::string const & s1, std::string const & s2) const {
|
||||
return std::lexicographical_compare
|
||||
(s1.begin (), s1.end (), // source range
|
||||
s2.begin (), s2.end (), // dest range
|
||||
nocase_compare ()); // comparison
|
||||
}
|
||||
};
|
||||
|
||||
/// Find substring (case insensitive)
|
||||
/**
|
||||
* @param [in] haystack The string to search in
|
||||
* @param [in] needle The string to search for
|
||||
* @param [in] loc The locale to use for determining the case of values.
|
||||
* Defaults to the current locale.
|
||||
* @return An iterator to the first element of the first occurrance of needle in
|
||||
* haystack. If the sequence is not found, the function returns
|
||||
* haystack.end()
|
||||
*/
|
||||
template<typename T>
|
||||
typename T::const_iterator ci_find_substr( const T& str1, const T& str2,
|
||||
const std::locale& loc = std::locale() )
|
||||
typename T::const_iterator ci_find_substr(T const & haystack, T const & needle,
|
||||
std::locale const & loc = std::locale())
|
||||
{
|
||||
return std::search( str1.begin(), str1.end(),
|
||||
str2.begin(), str2.end(), my_equal<typename T::value_type>(loc) );
|
||||
return std::search( haystack.begin(), haystack.end(),
|
||||
needle.begin(), needle.end(), my_equal<typename T::value_type>(loc) );
|
||||
}
|
||||
|
||||
/// Find substring (case insensitive)
|
||||
/**
|
||||
* @todo Is this still used? This method may not make sense.. should use
|
||||
* iterators or be less generic. As is it is too tightly coupled to std::string
|
||||
*
|
||||
* @param [in] haystack The string to search in
|
||||
* @param [in] needle The string to search for as a char array of values
|
||||
* @param [in] size Length of needle
|
||||
* @param [in] loc The locale to use for determining the case of values.
|
||||
* Defaults to the current locale.
|
||||
* @return An iterator to the first element of the first occurrance of needle in
|
||||
* haystack. If the sequence is not found, the function returns
|
||||
* haystack.end()
|
||||
*/
|
||||
template<typename T>
|
||||
typename T::const_iterator ci_find_substr(const T& str1,
|
||||
const typename T::value_type* str2, typename T::size_type size,
|
||||
const std::locale& loc = std::locale())
|
||||
typename T::const_iterator ci_find_substr(T const & haystack,
|
||||
typename T::value_type const * needle, typename T::size_type size,
|
||||
std::locale const & loc = std::locale())
|
||||
{
|
||||
return std::search( str1.begin(), str1.end(),
|
||||
str2, str2+size, my_equal<typename T::value_type>(loc) );
|
||||
return std::search( haystack.begin(), haystack.end(),
|
||||
needle, needle+size, my_equal<typename T::value_type>(loc) );
|
||||
}
|
||||
|
||||
/// Convert a string to lowercase
|
||||
/**
|
||||
* @param [in] in The string to convert
|
||||
* @return The converted string
|
||||
*/
|
||||
std::string to_lower(std::string const & in);
|
||||
|
||||
|
||||
std::string string_replace_all(std::string subject, const std::string& search,
|
||||
const std::string& replace);
|
||||
/// Replace all occurrances of a substring with another
|
||||
/**
|
||||
* @param [in] subject The string to search in
|
||||
* @param [in] search The string to search for
|
||||
* @param [in] replace The string to replace with
|
||||
* @return A copy of `subject` with all occurances of `search` replaced with
|
||||
* `replace`
|
||||
*/
|
||||
std::string string_replace_all(std::string subject, std::string const & search,
|
||||
std::string const & replace);
|
||||
|
||||
/// Convert std::string to ascii printed string of hex digits
|
||||
std::string to_hex(const std::string& input);
|
||||
/**
|
||||
* @param [in] input The string to print
|
||||
* @return A copy of `input` converted to the printable representation of the
|
||||
* hex values of its data.
|
||||
*/
|
||||
std::string to_hex(std::string const & input);
|
||||
|
||||
/// Convert c string to ascii printed string of hex digits
|
||||
std::string to_hex(const uint8_t* input, size_t length);
|
||||
std::string to_hex(const char* input, size_t length);
|
||||
/// Convert byte array (uint8_t) to ascii printed string of hex digits
|
||||
/**
|
||||
* @param [in] input The byte array to print
|
||||
* @param [in] length The length of input
|
||||
* @return A copy of `input` converted to the printable representation of the
|
||||
* hex values of its data.
|
||||
*/
|
||||
std::string to_hex(uint8_t const * input, size_t length);
|
||||
|
||||
/// Convert char array to ascii printed string of hex digits
|
||||
/**
|
||||
* @param [in] input The char array to print
|
||||
* @param [in] length The length of input
|
||||
* @return A copy of `input` converted to the printable representation of the
|
||||
* hex values of its data.
|
||||
*/
|
||||
std::string to_hex(char const * input, size_t length);
|
||||
|
||||
} // namespace utility
|
||||
} // namespace websocketpp
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* 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:
|
||||
* * 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_VERSION_HPP
|
||||
#define WEBSOCKETPP_VERSION_HPP
|
||||
|
||||
/// Namespace for the WebSocket++ project
|
||||
namespace websocketpp {
|
||||
|
||||
/*
|
||||
other places where version information is kept
|
||||
- readme.md
|
||||
- changelog.md
|
||||
- Doxyfile
|
||||
- CMakeLists.txt
|
||||
*/
|
||||
|
||||
/// Library major version number
|
||||
static int const major_version = 0;
|
||||
/// Library minor version number
|
||||
static int const minor_version = 3;
|
||||
/// Library patch version number
|
||||
static int const patch_version = 0;
|
||||
/// Library pre-release flag
|
||||
/**
|
||||
* This is a textual flag indicating the type and number for pre-release
|
||||
* versions (dev, alpha, beta, rc). This will be blank for release versions.
|
||||
*/
|
||||
static char const prerelease_flag[] = "alpha3";
|
||||
|
||||
/// Default user agent string
|
||||
static char const user_agent[] = "WebSocket++/0.3.0-alpha3";
|
||||
|
||||
} // namespace websocketpp
|
||||
|
||||
#endif // WEBSOCKETPP_VERSION_HPP
|
||||
Reference in New Issue
Block a user