From b866e4e0cad92188a9a0482c9003361e3be8a07d Mon Sep 17 00:00:00 2001 From: Peter Thorson Date: Tue, 9 Jul 2013 16:50:47 -0500 Subject: [PATCH] Refactors URI to be exception and regex free --- SConstruct | 8 +- changelog.md | 2 + examples/broadcast_server/SConscript | 2 +- examples/echo_client/SConscript | 2 +- examples/echo_server/SConscript | 2 +- examples/echo_server_tls/SConscript | 2 +- examples/iostream_server/SConscript | 2 +- examples/print_server/SConscript | 2 +- examples/sip_client/SConscript | 4 +- examples/subprotocol_server/SConscript | 2 +- examples/telemetry_client/SConscript | 2 +- examples/testee_server/SConscript | 2 +- examples/utility_client/SConscript | 2 +- test/connection/SConscript | 2 +- test/endpoint/SConscript | 2 +- test/extension/SConscript | 2 +- test/http/SConscript | 2 +- test/logger/SConscript | 2 +- test/processors/SConscript | 2 +- test/processors/hybi00.cpp | 2 +- test/processors/hybi07.cpp | 33 +-- test/processors/hybi08.cpp | 18 +- test/processors/hybi13.cpp | 2 +- test/roles/SConscript | 2 +- test/transport/SConscript | 2 +- test/transport/asio/SConscript | 2 +- test/utility/SConscript | 2 +- test/utility/uri.cpp | 331 +++++++++--------------- websocketpp/error.hpp | 7 +- websocketpp/impl/connection_impl.hpp | 20 +- websocketpp/roles/client_endpoint.hpp | 9 +- websocketpp/transport/asio/endpoint.hpp | 25 +- websocketpp/uri.hpp | 223 ++++++++-------- 33 files changed, 313 insertions(+), 411 deletions(-) diff --git a/SConstruct b/SConstruct index 3eee6f59a2..b84d00395a 100644 --- a/SConstruct +++ b/SConstruct @@ -133,17 +133,11 @@ env_cpp11 = env.Clone () if env_cpp11['CXX'].startswith('g++'): # TODO: check g++ version - - # g++ STL lacks support for - 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 - # 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++'): diff --git a/changelog.md b/changelog.md index 39dba55d81..7d9e7144b9 100644 --- a/changelog.md +++ b/changelog.md @@ -1,4 +1,6 @@ HEAD +- Refactors URI to be exception free and not use the regular expressions. This + eliminates the dependency on boost or C++11 regex libraries. - Updates handling of Server and User-Agent headers - Fix issue where pong timeout handler always fired. Thank you Steven Klassen for reporting this bug. diff --git a/examples/broadcast_server/SConscript b/examples/broadcast_server/SConscript index a9938b871a..5786f570d1 100644 --- a/examples/broadcast_server/SConscript +++ b/examples/broadcast_server/SConscript @@ -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') diff --git a/examples/echo_client/SConscript b/examples/echo_client/SConscript index b167f741f6..82c2317eaa 100644 --- a/examples/echo_client/SConscript +++ b/examples/echo_client/SConscript @@ -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_client', ["echo_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('echo_client', ["echo_client.cpp"], LIBS = ALL_LIBS) Return('prgs') diff --git a/examples/echo_server/SConscript b/examples/echo_server/SConscript index 2de8e5e793..a2978852e6 100644 --- a/examples/echo_server/SConscript +++ b/examples/echo_server/SConscript @@ -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') diff --git a/examples/echo_server_tls/SConscript b/examples/echo_server_tls/SConscript index d0893b4a3e..e24cc4ce8b 100644 --- a/examples/echo_server_tls/SConscript +++ b/examples/echo_server_tls/SConscript @@ -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') diff --git a/examples/iostream_server/SConscript b/examples/iostream_server/SConscript index f6b24ed3d4..dc90834cfc 100644 --- a/examples/iostream_server/SConscript +++ b/examples/iostream_server/SConscript @@ -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') diff --git a/examples/print_server/SConscript b/examples/print_server/SConscript index 725ed77e39..4f0e492be4 100644 --- a/examples/print_server/SConscript +++ b/examples/print_server/SConscript @@ -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') diff --git a/examples/sip_client/SConscript b/examples/sip_client/SConscript index 1ea8b1c5be..59b62d0917 100644 --- a/examples/sip_client/SConscript +++ b/examples/sip_client/SConscript @@ -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') diff --git a/examples/subprotocol_server/SConscript b/examples/subprotocol_server/SConscript index fce0525d20..e97535ca5b 100644 --- a/examples/subprotocol_server/SConscript +++ b/examples/subprotocol_server/SConscript @@ -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') diff --git a/examples/telemetry_client/SConscript b/examples/telemetry_client/SConscript index eef1c362a8..62396a5e35 100644 --- a/examples/telemetry_client/SConscript +++ b/examples/telemetry_client/SConscript @@ -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') diff --git a/examples/testee_server/SConscript b/examples/testee_server/SConscript index f0551b8118..526886f68a 100644 --- a/examples/testee_server/SConscript +++ b/examples/testee_server/SConscript @@ -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') diff --git a/examples/utility_client/SConscript b/examples/utility_client/SConscript index 82625876aa..03c06c67ff 100644 --- a/examples/utility_client/SConscript +++ b/examples/utility_client/SConscript @@ -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') diff --git a/test/connection/SConscript b/test/connection/SConscript index c30f793e29..4ed7a4e695 100644 --- a/test/connection/SConscript +++ b/test/connection/SConscript @@ -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) diff --git a/test/endpoint/SConscript b/test/endpoint/SConscript index 58464a023a..5cb3ede911 100644 --- a/test/endpoint/SConscript +++ b/test/endpoint/SConscript @@ -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) diff --git a/test/extension/SConscript b/test/extension/SConscript index 8c6a371213..d8b425fda3 100644 --- a/test/extension/SConscript +++ b/test/extension/SConscript @@ -10,7 +10,7 @@ Import('polyfill_libs') env = env.Clone () env_cpp11 = env_cpp11.Clone () -BOOST_LIBS = boostlibs(['unit_test_framework','system','regex'],env) + [platform_libs] + ['z'] +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) diff --git a/test/http/SConscript b/test/http/SConscript index 541a71cbbe..0a24a87745 100644 --- a/test/http/SConscript +++ b/test/http/SConscript @@ -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) diff --git a/test/logger/SConscript b/test/logger/SConscript index 795a263ba1..81d607601d 100644 --- a/test/logger/SConscript +++ b/test/logger/SConscript @@ -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) diff --git a/test/processors/SConscript b/test/processors/SConscript index ad29455124..a672963cb3 100644 --- a/test/processors/SConscript +++ b/test/processors/SConscript @@ -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] + ['z'] +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) diff --git a/test/processors/hybi00.cpp b/test/processors/hybi00.cpp index d0ef10f35a..48b4932481 100644 --- a/test/processors/hybi00.cpp +++ b/test/processors/hybi00.cpp @@ -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 ) { diff --git a/test/processors/hybi07.cpp b/test/processors/hybi07.cpp index 83d0e54461..b12675eafd 100644 --- a/test/processors/hybi07.cpp +++ b/test/processors/hybi07.cpp @@ -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 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() ); } diff --git a/test/processors/hybi08.cpp b/test/processors/hybi08.cpp index 175c420436..c71f882dab 100644 --- a/test/processors/hybi08.cpp +++ b/test/processors/hybi08.cpp @@ -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 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() ); } diff --git a/test/processors/hybi13.cpp b/test/processors/hybi13.cpp index fef93c350b..6481f6e0fc 100644 --- a/test/processors/hybi13.cpp +++ b/test/processors/hybi13.cpp @@ -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 diff --git a/test/roles/SConscript b/test/roles/SConscript index 3737c846d5..e86107ece4 100644 --- a/test/roles/SConscript +++ b/test/roles/SConscript @@ -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) diff --git a/test/transport/SConscript b/test/transport/SConscript index b31a190059..74ec781ef9 100644 --- a/test/transport/SConscript +++ b/test/transport/SConscript @@ -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) diff --git a/test/transport/asio/SConscript b/test/transport/asio/SConscript index e3097cdbb1..6cae57c07b 100644 --- a/test/transport/asio/SConscript +++ b/test/transport/asio/SConscript @@ -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) diff --git a/test/utility/SConscript b/test/utility/SConscript index 6c5186abce..b9299d29e2 100644 --- a/test/utility/SConscript +++ b/test/utility/SConscript @@ -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('uri_boost.o', ["uri.cpp"], LIBS = BOOST_LIBS) objs += env.Object('utilities_boost.o', ["utilities.cpp"], LIBS = BOOST_LIBS) diff --git a/test/utility/uri.cpp b/test/utility/uri.cpp index cf52ccbf11..f85fa99830 100644 --- a/test/utility/uri.cpp +++ b/test/utility/uri.cpp @@ -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 \ No newline at end of file +// 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 diff --git a/websocketpp/error.hpp b/websocketpp/error.hpp index be941e09ce..3125584af4 100644 --- a/websocketpp/error.hpp +++ b/websocketpp/error.hpp @@ -111,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 @@ -171,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"; } diff --git a/websocketpp/impl/connection_impl.hpp b/websocketpp/impl/connection_impl.hpp index e8479eb5c0..aa82598b42 100644 --- a/websocketpp/impl/connection_impl.hpp +++ b/websocketpp/impl/connection_impl.hpp @@ -981,11 +981,14 @@ bool connection::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; } @@ -1033,11 +1036,12 @@ bool connection::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; } diff --git a/websocketpp/roles/client_endpoint.hpp b/websocketpp/roles/client_endpoint.hpp index e202c9467a..e04be8f134 100644 --- a/websocketpp/roles/client_endpoint.hpp +++ b/websocketpp/roles/client_endpoint.hpp @@ -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 diff --git a/websocketpp/transport/asio/endpoint.hpp b/websocketpp/transport/asio/endpoint.hpp index 532fecf86a..91a6c29a7f 100644 --- a/websocketpp/transport/asio/endpoint.hpp +++ b/websocketpp/transport/asio/endpoint.hpp @@ -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); diff --git a/websocketpp/uri.hpp b/websocketpp/uri.hpp index dd3f100604..cc060c5be7 100644 --- a/websocketpp/uri.hpp +++ b/websocketpp/uri.hpp @@ -29,7 +29,7 @@ #define WEBSOCKETPP_URI_HPP #include -#include +#include #include #include @@ -38,18 +38,6 @@ namespace websocketpp { -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. /// Default port for ws:// @@ -59,58 +47,32 @@ 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. @@ -123,99 +85,143 @@ public: // extract IPv6 digits until ] temp = std::find(it,uri.end(),']'); 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; } @@ -245,7 +251,7 @@ public: return p.str(); } - const std::string& get_resource() const { + std::string const & get_resource() const { return m_resource; } @@ -281,7 +287,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); } @@ -289,11 +299,11 @@ private: unsigned int t_port = static_cast(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(t_port); @@ -304,6 +314,7 @@ private: std::string m_resource; uint16_t m_port; bool m_secure; + bool m_valid; }; typedef lib::shared_ptr uri_ptr;