Compare commits

..

78 Commits

Author SHA1 Message Date
Peter Thorson 3f08de3d9d alpha3 release 2013-07-16 18:19:35 -05:00
Peter Thorson a9f3821d99 rename echo_client to testee client to better reflect its role 2013-07-14 11:02:59 -05:00
Peter Thorson 2964acd6d7 disable frame payload logging by default 2013-07-14 10:57:05 -05:00
Peter Thorson d564189d4c Merge pull request #274 from hobu/master
Implement conditional cmake configuration for echo_server_tls and add cmake config for print_server and telemetry_client
2013-07-14 08:56:17 -07:00
Peter Thorson ddca46f5d6 update changelog 2013-07-14 10:52:00 -05:00
Peter Thorson 7f062297de complete and clean up sha1 refactoring
move the remainder of documentation and licenses into sha1.hpp. Remove
unused files.
2013-07-14 10:49:40 -05:00
Peter Thorson 1c199aca6e minor refactoring of sha1 code
Update code style to better match project. Add more documentation. Add
some C++ specific features to improve compatibility and reduce warnings
with C++ applications. Add original project unit tests to WebSocket++
test suite.
2013-07-14 10:34:47 -05:00
Peter Thorson b8af39fd82 formatting 2013-07-13 13:29:10 -05:00
Peter Thorson c94621bd29 case insensitive header comparisons fixes #220 and #275 2013-07-13 13:28:56 -05:00
Howard Butler b83b054c7e add CMake config for print_server and telemetry_client 2013-07-11 10:54:43 -05:00
Howard Butler f6bcb86a6c Implement conditional cmake configuration for echo_server_tls 2013-07-10 16:09:38 -05:00
Peter Thorson 28ac69c800 temporary workaround for a g++ compile issue 2013-07-09 21:59:28 -05:00
Peter Thorson b866e4e0ca Refactors URI to be exception and regex free 2013-07-09 16:50:47 -05:00
Peter Thorson cdaf57cf7d update copyright date 2013-07-09 16:45:10 -05:00
Peter Thorson 2d49035a6d remove deprecated constants 2013-07-09 16:44:29 -05:00
Peter Thorson 686b835f3d update changelog 2013-07-08 19:02:14 -05:00
Peter Thorson 8f2c4264e1 Server header/User agent adjustments & tests
Updates behavior to drop the headers if user_agent is set to the empty
string and to allow overriding the Server header from the validate
function. Updates docs and adds a number of tests
2013-07-08 18:07:33 -05:00
Peter Thorson 5c608910d5 fix interface mismatch 2013-07-05 11:44:20 -05:00
Peter Thorson 229698dbb0 add experimental connection get message buffer method 2013-07-05 11:41:47 -05:00
Peter Thorson 6bd1bfd4f2 add basic compression/decompression implimentation 2013-07-03 06:19:08 -05:00
Peter Thorson dbd0fc5372 remove debug printing 2013-07-03 06:16:42 -05:00
Peter Thorson 7454bf68f6 re-enable permessage_deflate test 2013-06-30 19:46:29 -05:00
Peter Thorson 5b7f4a8c14 remove unneeded methods 2013-06-30 19:39:03 -05:00
Peter Thorson 9dd53d2e28 code style 2013-06-30 19:38:50 -05:00
Peter Thorson 915f5c77a8 support c2s_max_window_size 2013-06-30 18:34:21 -05:00
Peter Thorson 36cae596db update documentation 2013-06-30 18:32:37 -05:00
Peter Thorson 407b931395 Add s2c_max_window_bits negotiation 2013-06-29 17:53:53 -05:00
Peter Thorson 25b530b8a8 fix bug that prevented multiple attributes from working 2013-06-27 19:49:13 -05:00
Peter Thorson 038a9aee58 setting and negotiation of c2s_no_context_takeover 2013-06-27 19:48:48 -05:00
Peter Thorson 9749c0a3d5 enable server initiated s2c_no_context_takeover 2013-06-27 19:02:28 -05:00
Peter Thorson c7b1ddd9fa permessage-deflate negotiation of s2c_no_context_takeover 2013-06-27 18:35:32 -05:00
Peter Thorson 7a0d9c0238 cleanup permessage deflate extension 2013-06-25 21:07:46 -05:00
Peter Thorson cb08f07cb0 add combination error code / string type 2013-06-25 20:59:29 -05:00
Peter Thorson 743cd7a713 HTTP cleanup and documentation 2013-06-25 20:57:30 -05:00
Peter Thorson 88fe1bfb1c Fix issue where pong timeout handler always fired 2013-06-24 14:59:19 -05:00
Peter Thorson 5fd65a934b fix typo 2013-06-24 13:35:25 -05:00
Peter Thorson bb1420fe06 endpoint code style 2013-06-24 13:33:06 -05:00
Peter Thorson 0264b63fc3 Add ping and pong endpoint wrapper methods 2013-06-24 13:32:56 -05:00
Peter Thorson 256f8325e8 spelling, documentation, and style 2013-06-23 21:06:33 -05:00
Peter Thorson ce410a9428 transport documentation and style 2013-06-23 19:41:48 -05:00
Peter Thorson 573dedcb9d transport code style 2013-06-23 16:26:37 -05:00
Peter Thorson 4f8b2bdc98 transport documentation & style 2013-06-23 16:18:03 -05:00
Peter Thorson 330d564ded Flags 64 bit literals in frame unit tests references #264 2013-06-22 20:10:49 -05:00
Peter Thorson 161a5b169a Merge pull request #262 from breyed/streamed-timestamp
Write timestamp directly to output stream
2013-06-22 17:59:03 -07:00
Peter Thorson 7d36965149 Add accessor for raw http requests references #266 2013-06-22 10:59:26 -05:00
Peter Thorson de5684aef3 add test fail handler 2013-06-22 10:50:28 -05:00
Peter Thorson fd93ad89cb update documentation and code style 2013-06-16 21:08:53 -05:00
Peter Thorson 6d620aa1e8 add documentation & update code style 2013-06-15 12:46:39 -05:00
Peter Thorson 816fe6410d update documentation & code style 2013-06-15 12:39:57 -05:00
Peter Thorson f3c65ab609 documentation 2013-06-15 12:34:11 -05:00
Peter Thorson c938d9fd15 use strict masking for incoming messages references #264 2013-06-14 21:55:14 -05:00
Peter Thorson 0b764bdc62 add byte_mask_circ 2013-06-14 21:49:24 -05:00
Peter Thorson 86e2f364de fix readme 2013-06-14 21:48:46 -05:00
Peter Thorson 54dd4c8084 look up version rather than hardcode 2013-06-14 21:48:29 -05:00
Peter Thorson cae30acf91 update byte mask to use separate input & output types references #264
In particular this allows const iterators to be use for the input types.
2013-06-12 20:52:48 -05:00
Peter Thorson 24c1804e40 update documentation 2013-06-12 19:23:05 -05:00
breyed 8c6a360600 Write timestamp directly to output stream
This uses put_time (if supported) to avoid having to first write the timestamp to a temporary buffer and then copy it to the stream.
2013-06-09 18:28:19 -05:00
Peter Thorson 5c35535ffd update changelog 2013-06-09 18:26:41 -05:00
Peter Thorson 3256c72d98 Merge pull request #261 from breyed/master
added guards to avoid macro definition when used with boost_config.hpp
2013-06-09 16:24:09 -07:00
breyed 07ab02407f added guards to avoid macro definition when used with boost_config.hpp 2013-06-09 18:03:49 -05:00
Peter Thorson edc0057a03 update unit test 2013-06-09 17:39:49 -05:00
Peter Thorson 9161119b4d bump version to alpha2 2013-06-09 17:24:24 -05:00
Peter Thorson 7db60e3429 fix poor server handling of double close frames fixes #259 2013-06-09 17:03:14 -05:00
Peter Thorson 3c0b8a81b0 Fix handling of spurious frames after close. Fixes #258 2013-06-09 16:41:04 -05:00
Peter Thorson b812fd001b Change default HTTP response error code to 426
Changes default HTTP response error code when no http_handler is
defined from 500/Internal Server Error to 426/Upgrade Required
2013-06-09 16:20:53 -05:00
Peter Thorson 3a43986d9e add documentation & normalize code style 2013-06-09 14:58:32 -05:00
Peter Thorson 64b1b52297 adds documentation on locations of version info 2013-06-09 11:07:19 -05:00
Peter Thorson dc048ed021 test use of doxygen todo command 2013-06-09 11:05:48 -05:00
Peter Thorson 60b167bcb7 updates changelog 2013-06-09 09:27:08 -05:00
Peter Thorson e680ca1ef4 add comment + TODO regarding VSPP warning 2013-06-09 09:25:30 -05:00
Peter Thorson 21d79e28c6 maybe fix markdown # escape? 2013-06-09 09:20:31 -05:00
Peter Thorson d25a254e81 remove logger dynamic allocation 2013-06-09 09:20:04 -05:00
Peter Thorson 3e144cfd75 Merge pull request #257 from zaphoyd/experimental
merge last bit of changes from experimental to master
2013-06-09 07:15:12 -07:00
Peter Thorson 096a7dbaa8 escape # in readme 2013-06-09 08:58:15 -05:00
Peter Thorson 577591aaa1 readme updates 2013-06-09 08:55:53 -05:00
Peter Thorson a401a4448d update version information to 0.3.0-alpha1 2013-06-09 08:46:54 -05:00
Peter Thorson ace76f54f9 update docs for 0.3.x in master branch fixes #197 2013-06-09 08:31:05 -05:00
Peter Thorson 1eaa1b790f update travis for 0.3.x in master 2013-06-09 08:30:03 -05:00
93 changed files with 3448 additions and 3253 deletions
+3 -1
View File
@@ -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
View File
@@ -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
+5 -2
View File
@@ -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
View File
@@ -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
View File
@@ -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
+4
View File
@@ -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 ()
+1 -1
View File
@@ -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')
+1 -1
View File
@@ -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')
+15
View File
@@ -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()
+1 -1
View File
@@ -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')
+1 -1
View File
@@ -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 ()
+1 -1
View File
@@ -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')
+2 -2
View File
@@ -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')
+1 -1
View File
@@ -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')
+10
View File
@@ -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 ()
+1 -1
View File
@@ -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')
+11
View File
@@ -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;
+1 -1
View File
@@ -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')
+1 -1
View File
@@ -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')
+4 -15
View File
@@ -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
View File
@@ -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
+1 -1
View File
@@ -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)
+53 -1
View File
@@ -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 ) {
+1 -1
View File
@@ -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;
+6 -12
View File
@@ -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);
+1 -1
View File
@@ -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)
+6 -2
View File
@@ -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')
+543
View File
@@ -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 );
}
*/
+1 -1
View File
@@ -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
View File
@@ -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;
+1 -1
View File
@@ -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)
+2 -2
View File
@@ -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)
+3 -3
View File
@@ -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
View File
@@ -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() );
}
+5 -15
View File
@@ -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() );
}
+6 -7
View File
@@ -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" );
}*/
}
+1 -1
View File
@@ -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)
+1 -1
View File
@@ -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)
+1 -1
View File
@@ -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)
+2 -1
View File
@@ -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();
}
}
+69 -1
View File
@@ -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));
+5 -1
View File
@@ -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
View File
@@ -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,
+84
View File
@@ -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
View File
@@ -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
+6
View File
@@ -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";
-148
View File
@@ -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
+30 -20
View File
@@ -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
+1 -1
View File
@@ -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;
}
+1 -1
View File
@@ -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
View File
@@ -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
View File
@@ -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;
+9 -1
View File
@@ -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
View File
@@ -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
+43 -12
View File
@@ -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,
+58 -66
View File
@@ -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
+8 -1
View File
@@ -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
View File
@@ -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 &parameters)
parameter_list &parameters)
{
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;
-3
View File
@@ -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())
+55 -20
View File
@@ -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(
+45 -9
View File
@@ -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;
+6
View File
@@ -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";
+18 -9
View File
@@ -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;
+12 -18
View File
@@ -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_
+27 -30
View File
@@ -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
+9 -10
View File
@@ -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
+3 -4
View File
@@ -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
+59 -64
View File
@@ -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;
+46 -52
View File
@@ -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
+5 -4
View File
@@ -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
-41
View File
@@ -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
-48
View File
@@ -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
-176
View File
@@ -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");
}
-589
View File
@@ -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));
}
-88
View File
@@ -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
View File
@@ -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_
-169
View File
@@ -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");
}
-149
View File
@@ -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);
}
+16 -17
View File
@@ -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
+2 -2
View File
@@ -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();
}*/
+13 -12
View File
@@ -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);
+5 -5
View File
@@ -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 {
+64 -39
View File
@@ -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_
+15 -18
View File
@@ -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
+7 -3
View File
@@ -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
View File
@@ -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
View File
@@ -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
+60
View File
@@ -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