Compare 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 a5bb90807b Merge pull request #252 from breyed/visual-studio
Fixed Visual Studio 2012 warnings and formatting
2013-06-09 07:05:53 -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
breyed e68d492ed2 Fixed Visual Studio 2012 warnings
Fixed daylight savings time formatting problem on Windows
2013-06-08 11:07:02 -05:00
90 changed files with 3400 additions and 3075 deletions

No files matched your search

+2 -1
View File
@@ -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-alpha1"
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)
+37 -1
View File
@@ -1,2 +1,38 @@
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
- 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 -3
View File
@@ -1,4 +1,4 @@
WebSocket++ (0.3.0-alpha1)
WebSocket++ (0.3.0-alpha3)
==========================
WebSocket++ is a header only C++ library that implements RFC6455 The WebSocket
@@ -14,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
============
@@ -34,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/
+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";
+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;
+71 -22
View File
@@ -88,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)
{
@@ -106,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.
*/
@@ -117,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;
}
@@ -189,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;
}
@@ -270,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)
/**
@@ -348,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 -7
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,15 +112,25 @@ private:
typedef typename concurrency::scoped_lock_type scoped_lock_type;
typedef typename concurrency::mutex_type mutex_type;
const char* 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);
std::strftime(buffer,39,"%Y-%m-%d %H:%M:%S%z",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;
char buffer[40];
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_
+29 -32
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,23 +328,23 @@ 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);
}
std::string val;
val.append(1,0xff);
val.append(1,0x00);
val.append(1,'\xff');
val.append(1,'\x00');
out->set_payload(val);
out->set_prepared(true);
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 -314
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,324 +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)
{
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++;
}
}
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;
+120 -25
View File
@@ -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
+23 -5
View File
@@ -28,14 +28,32 @@
#ifndef WEBSOCKETPP_VERSION_HPP
#define WEBSOCKETPP_VERSION_HPP
/// Namespace for the WebSocket++ project
namespace websocketpp {
static int const major_version = 0;
static int const minor_version = 3;
static int const patch_version = 0;
static char const prerelease_flag[] = "alpha1";
/*
other places where version information is kept
- readme.md
- changelog.md
- Doxyfile
- CMakeLists.txt
*/
static char const user_agent[] = "WebSocket++/0.3.0-alpha1";
/// 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