Refactors URI to be exception and regex free

This commit is contained in:
Peter Thorson
2013-07-09 16:50:47 -05:00
parent cdaf57cf7d
commit b866e4e0ca
33 changed files with 313 additions and 411 deletions

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++'):

View File

@@ -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.

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')

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_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')

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')

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')

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')

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')

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')

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')

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')

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')

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')

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)

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)

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'],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)

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)

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)

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] + ['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)

View File

@@ -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 ) {

View File

@@ -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() );
}

View File

@@ -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() );
}

View File

@@ -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

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)

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)

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)

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('uri_boost.o', ["uri.cpp"], LIBS = BOOST_LIBS)
objs += env.Object('utilities_boost.o', ["utilities.cpp"], LIBS = BOOST_LIBS)

View File

@@ -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

View File

@@ -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";
}

View File

@@ -981,11 +981,14 @@ 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;
}
@@ -1033,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;
}

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

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);

View File

@@ -29,7 +29,7 @@
#define WEBSOCKETPP_URI_HPP
#include <websocketpp/common/memory.hpp>
#include <websocketpp/common/regex.hpp>
#include <websocketpp/error.hpp>
#include <exception>
#include <iostream>
@@ -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<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);
@@ -304,6 +314,7 @@ private:
std::string m_resource;
uint16_t m_port;
bool m_secure;
bool m_valid;
};
typedef lib::shared_ptr<uri> uri_ptr;