From ac9351f9b3ce1d7d90e15f783d21e2998fe06174 Mon Sep 17 00:00:00 2001 From: Peter Thorson Date: Fri, 25 Oct 2013 07:23:06 -0500 Subject: [PATCH] strips LWS from incoming headers per RFC2616. fixes #301 --- changelog.md | 2 + test/http/parser.cpp | 65 ++++++++++++++++++++++++++------ websocketpp/http/constants.hpp | 2 +- websocketpp/http/impl/parser.hpp | 4 +- websocketpp/http/parser.hpp | 7 ++++ 5 files changed, 66 insertions(+), 14 deletions(-) diff --git a/changelog.md b/changelog.md index a8cfaad6da..48465be270 100644 --- a/changelog.md +++ b/changelog.md @@ -1,4 +1,6 @@ HEAD +- Fixes incorrect whitespace handling in header parsing. #301 Thank you Wolfram + Schroers for reporting - Adds URI method to extract query string from URI. Thank you Banaan for code. #298 - Numerous performance improvements. Including: tuned default buffer sizes based diff --git a/test/http/parser.cpp b/test/http/parser.cpp index 19a4909e79..8de2b26526 100644 --- a/test/http/parser.cpp +++ b/test/http/parser.cpp @@ -355,6 +355,24 @@ BOOST_AUTO_TEST_CASE( extract_parameters ) { BOOST_CHECK_EQUAL( a.find("bar")->second, "a \"b\" c" ); } +BOOST_AUTO_TEST_CASE( strip_lws ) { + std::string test1 = "foo"; + std::string test2 = " foo "; + std::string test3 = "foo "; + std::string test4 = " foo"; + std::string test5 = " foo "; + std::string test6 = " \r\n foo "; + std::string test7 = " \t foo "; + + BOOST_CHECK_EQUAL( websocketpp::http::parser::strip_lws(test1), "foo" ); + BOOST_CHECK_EQUAL( websocketpp::http::parser::strip_lws(test2), "foo" ); + BOOST_CHECK_EQUAL( websocketpp::http::parser::strip_lws(test3), "foo" ); + BOOST_CHECK_EQUAL( websocketpp::http::parser::strip_lws(test4), "foo" ); + BOOST_CHECK_EQUAL( websocketpp::http::parser::strip_lws(test5), "foo" ); + BOOST_CHECK_EQUAL( websocketpp::http::parser::strip_lws(test6), "foo" ); + BOOST_CHECK_EQUAL( websocketpp::http::parser::strip_lws(test7), "foo" ); +} + BOOST_AUTO_TEST_CASE( case_insensitive_headers ) { websocketpp::http::parser::parser r; @@ -743,12 +761,12 @@ BOOST_AUTO_TEST_CASE( header_whitespace1 ) { } BOOST_CHECK( exception == false ); - BOOST_CHECK( pos == 43 ); + BOOST_CHECK_EQUAL( pos, 43 ); BOOST_CHECK( r.ready() == true ); - BOOST_CHECK( r.get_version() == "HTTP/1.1" ); - BOOST_CHECK( r.get_method() == "GET" ); - BOOST_CHECK( r.get_uri() == "/" ); - BOOST_CHECK( r.get_header("Host") == "www.example.com" ); + BOOST_CHECK_EQUAL( r.get_version(), "HTTP/1.1" ); + BOOST_CHECK_EQUAL( r.get_method(), "GET" ); + BOOST_CHECK_EQUAL( r.get_uri(), "/" ); + BOOST_CHECK_EQUAL( r.get_header("Host"), "www.example.com" ); } BOOST_AUTO_TEST_CASE( header_whitespace2 ) { @@ -766,13 +784,13 @@ BOOST_AUTO_TEST_CASE( header_whitespace2 ) { } BOOST_CHECK( exception == false ); - BOOST_CHECK( pos == 40 ); + BOOST_CHECK_EQUAL( pos, 40 ); BOOST_CHECK( r.ready() == true ); - BOOST_CHECK( r.get_version() == "HTTP/1.1" ); - BOOST_CHECK( r.get_method() == "GET" ); - BOOST_CHECK( r.get_uri() == "/" ); - BOOST_CHECK( r.get_header("Host") == "www.example.com" ); -}*/ + BOOST_CHECK_EQUAL( r.get_version(), "HTTP/1.1" ); + BOOST_CHECK_EQUAL( r.get_method(), "GET" ); + BOOST_CHECK_EQUAL( r.get_uri(), "/" ); + BOOST_CHECK_EQUAL( r.get_header("Host"), "www.example.com" ); +} BOOST_AUTO_TEST_CASE( header_aggregation ) { websocketpp::http::parser::request r; @@ -822,6 +840,31 @@ BOOST_AUTO_TEST_CASE( wikipedia_example_response ) { BOOST_CHECK( r.get_header("Connection") == "Upgrade" ); BOOST_CHECK( r.get_header("Sec-WebSocket-Accept") == "HSmrc0sMlYUkAGmm5OPpG2HaGWk=" ); BOOST_CHECK( r.get_header("Sec-WebSocket-Protocol") == "chat" ); +BOOST_AUTO_TEST_CASE( response_with_non_standard_lws ) { + websocketpp::http::parser::response r; + + std::string raw = "HTTP/1.1 101 Switching Protocols\r\nUpgrade: websocket\r\nConnection: Upgrade\r\nSec-WebSocket-Accept:HSmrc0sMlYUkAGmm5OPpG2HaGWk=\r\nSec-WebSocket-Protocol: chat\r\n\r\n"; + + bool exception = false; + size_t pos = 0; + + try { + pos += r.consume(raw.c_str(),raw.size()); + } catch (std::exception &e) { + exception = true; + std::cout << e.what() << std::endl; + } + + BOOST_CHECK( exception == false ); + BOOST_CHECK_EQUAL( pos, 158 ); + BOOST_CHECK( r.headers_ready() ); + BOOST_CHECK_EQUAL( r.get_version(), "HTTP/1.1" ); + BOOST_CHECK_EQUAL( r.get_status_code(), websocketpp::http::status_code::switching_protocols ); + BOOST_CHECK_EQUAL( r.get_status_msg(), "Switching Protocols" ); + BOOST_CHECK_EQUAL( r.get_header("Upgrade"), "websocket" ); + BOOST_CHECK_EQUAL( r.get_header("Connection"), "Upgrade" ); + BOOST_CHECK_EQUAL( r.get_header("Sec-WebSocket-Accept"), "HSmrc0sMlYUkAGmm5OPpG2HaGWk=" ); + BOOST_CHECK_EQUAL( r.get_header("Sec-WebSocket-Protocol"), "chat" ); } BOOST_AUTO_TEST_CASE( plain_http_response ) { diff --git a/websocketpp/http/constants.hpp b/websocketpp/http/constants.hpp index 3edc3eb0fc..be3006aabd 100644 --- a/websocketpp/http/constants.hpp +++ b/websocketpp/http/constants.hpp @@ -53,7 +53,7 @@ namespace http { static char const header_delimiter[] = "\r\n"; /// Literal value of the HTTP header separator - static char const header_separator[] = ": "; + static char const header_separator[] = ":"; /// Literal value of an empty header static std::string const empty_header = ""; diff --git a/websocketpp/http/impl/parser.hpp b/websocketpp/http/impl/parser.hpp index 0ceac2ed57..d1d908135d 100644 --- a/websocketpp/http/impl/parser.hpp +++ b/websocketpp/http/impl/parser.hpp @@ -147,8 +147,8 @@ inline void parser::process_header(std::string::iterator begin, throw exception("Invalid header line",status_code::bad_request); } - append_header(std::string(begin,cursor), - std::string(cursor+sizeof(header_separator)-1,end)); + append_header(strip_lws(std::string(begin,cursor)), + strip_lws(std::string(cursor+sizeof(header_separator)-1,end))); } inline std::string parser::raw_headers() const { diff --git a/websocketpp/http/parser.hpp b/websocketpp/http/parser.hpp index 0bb52c2b6c..771c53971e 100644 --- a/websocketpp/http/parser.hpp +++ b/websocketpp/http/parser.hpp @@ -367,6 +367,13 @@ InputIterator extract_parameters(InputIterator begin, InputIterator end, return cursor; } +inline std::string strip_lws(std::string const & input) { + std::string::const_iterator begin = extract_all_lws(input.begin(),input.end()); + std::string::const_reverse_iterator end = extract_all_lws(input.rbegin(),input.rend()); + + return std::string(begin,end.base()); +} + /// Base HTTP parser /** * Includes methods and data elements common to all types of HTTP messages such