From a148540720aa645306807d8a2eb2f901b88f153e Mon Sep 17 00:00:00 2001 From: Simon Lepasteur Date: Thu, 31 Mar 2016 16:36:20 +0200 Subject: [PATCH 1/2] Fix header reading on linux listener using HTTPS. The first asynchronous read of the stream was stopping at the first CRLF (after the HTTP version) instead of reading until CRLFCRLF (the end of the header). This bug was not always noticeable because, as stated in the boost documentation: "After a successful async_read_until operation, the streambuf may contain additional data beyond the delimiter. An application will typically leave that data in the streambuf for a subsequent async_read_until operation to examine." Therefore the bug appeared only when trying to read the body of the request and the streambuf filled by async_read_until did not contain the complete header. --- Release/src/http/listener/http_server_asio.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Release/src/http/listener/http_server_asio.cpp b/Release/src/http/listener/http_server_asio.cpp index 14f3383b8e..63ea41f749 100644 --- a/Release/src/http/listener/http_server_asio.cpp +++ b/Release/src/http/listener/http_server_asio.cpp @@ -38,6 +38,7 @@ using namespace boost::asio; using namespace boost::asio::ip; #define CRLF std::string("\r\n") +#define CRLFCRLF std::string("\r\n\r\n") namespace web { @@ -144,7 +145,7 @@ struct crlf_nonascii_searcher_t } return std::make_pair(excluded, false); } -} crlf_nonascii_searcher; +} crlfcrlf_nonascii_searcher; }}}}} namespace boost @@ -205,14 +206,14 @@ void connection::start_request_response() if (m_ssl_stream) { - boost::asio::async_read_until(*m_ssl_stream, m_request_buf, CRLF, [this](const boost::system::error_code& ec, std::size_t) + boost::asio::async_read_until(*m_ssl_stream, m_request_buf, CRLFCRLF, [this](const boost::system::error_code& ec, std::size_t) { this->handle_http_line(ec); }); } else { - boost::asio::async_read_until(*m_socket, m_request_buf, crlf_nonascii_searcher, [this](const boost::system::error_code& ec, std::size_t) + boost::asio::async_read_until(*m_socket, m_request_buf, crlfcrlf_nonascii_searcher, [this](const boost::system::error_code& ec, std::size_t) { this->handle_http_line(ec); }); From 11a53dac6710e6fdd89933e76f032f5c204b1f2d Mon Sep 17 00:00:00 2001 From: Simon Lepasteur Date: Tue, 5 Apr 2016 11:36:08 +0200 Subject: [PATCH 2/2] Modify create_https_listener_get test to check that headers and body are retrieved correctly. --- .../src/http/listener/http_server_asio.cpp | 4 +- .../listener/listener_construction_tests.cpp | 51 ++++++++++++++++++- 2 files changed, 52 insertions(+), 3 deletions(-) diff --git a/Release/src/http/listener/http_server_asio.cpp b/Release/src/http/listener/http_server_asio.cpp index 63ea41f749..9454aa5175 100644 --- a/Release/src/http/listener/http_server_asio.cpp +++ b/Release/src/http/listener/http_server_asio.cpp @@ -58,7 +58,7 @@ namespace details // This is used as part of the async_read_until call below; see the // following for more details: // http://www.boost.org/doc/libs/1_55_0/doc/html/boost_asio/reference/async_read_until/overload4.html -struct crlf_nonascii_searcher_t +struct crlfcrlf_nonascii_searcher_t { enum class State { @@ -152,7 +152,7 @@ namespace boost { namespace asio { -template <> struct is_match_condition : public boost::true_type {}; +template <> struct is_match_condition : public boost::true_type {}; }} namespace web diff --git a/Release/tests/functional/http/listener/listener_construction_tests.cpp b/Release/tests/functional/http/listener/listener_construction_tests.cpp index c5d3aa6274..8e30a2b488 100644 --- a/Release/tests/functional/http/listener/listener_construction_tests.cpp +++ b/Release/tests/functional/http/listener/listener_construction_tests.cpp @@ -488,6 +488,42 @@ AvLsTlswO+wDLXM1DoKxzFBZL5o8927niqW+vZpzyGc1uPmC1MG7+MDKdZsR+e+9 XzJTD4slrGSJrcpLt/g/Jqqdjg== -----END PRIVATE KEY----- )"; + + auto body = utility::string_t{U("body content")}; + http_headers all_headers; + all_headers.add(U("Accept"), U("text/plain")); + all_headers.add(U("Accept-Charset"), U("utf-8")); + all_headers.add(U("Accept-Encoding"), U("gzip, deflate")); + all_headers.add(U("Accept-Language"), U("en-US")); + all_headers.add(U("Accept-Datetime"), U("Thu, 31 May 2007 20:35:00 GMT")); + all_headers.add(U("Authorization"), U("Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==")); + all_headers.add(U("Cache-Control"), U("no-cache")); + all_headers.add(U("Cookie"), U("$Version=1; Skin=new;")); + all_headers.add(U("Content-Length"), body.size()); + all_headers.add(U("Content-MD5"), U("Q2hlY2sgSW50ZWdyaXR5IQ==")); + all_headers.add(U("Content-Type"), U("application/x-www-form-urlencoded")); + all_headers.add(U("Date"), U("Tue, 15 Nov 1994 08:12:31 GMT")); + all_headers.add(U("Expect"), U("100-continue")); + all_headers.add(U("Forwarded"), U("for=192.0.2.60;proto=http;by=203.0.113.43Forwarded: for=192.0.2.43, for=198.51.100.17")); + all_headers.add(U("From"), U("user@example.com")); + all_headers.add(U("Host"), U("en.wikipedia.org")); + all_headers.add(U("If-Match"), U("\"737060cd8c284d8af7ad3082f209582d\"")); + all_headers.add(U("If-Modified-Since"), U("Sat, 29 Oct 1994 19:43:31 GMT")); + all_headers.add(U("If-None-Match"), U("\"737060cd8c284d8af7ad3082f209582d\"")); + all_headers.add(U("If-Range"), U("\"737060cd8c284d8af7ad3082f209582d\"")); + all_headers.add(U("If-Unmodified-Since"), U("Sat, 29 Oct 1994 19:43:31 GMT")); + all_headers.add(U("Max-Forwards"), U("10")); + all_headers.add(U("Origin"), U("http://www.example-social-network.com")); + all_headers.add(U("Pragma"), U("no-cache")); + all_headers.add(U("Proxy-Authorization"), U("Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==")); + all_headers.add(U("Range"), U("bytes=500-999")); + all_headers.add(U("Referer"), U("http://en.wikipedia.org/wiki/Main_Page")); + all_headers.add(U("TE"), U("trailers, deflate")); + all_headers.add(U("User-Agent"), U("Mozilla/5.0 (X11; Linux x86_64; rv:12.0) Gecko/20100101 Firefox/21.0")); + all_headers.add(U("Upgrade"), U("HTTP/2.0, SHTTP/1.3, IRC/6.9, RTA/x11")); + all_headers.add(U("Via"), U("1.0 fred, 1.1 example.com (Apache/1.1)")); + all_headers.add(U("Warning"), U("199 Miscellaneous warning")); + boost::asio::const_buffer cert(self_signed_cert, std::strlen(self_signed_cert)); boost::asio::const_buffer key(private_key, std::strlen(private_key)); @@ -503,9 +539,19 @@ XzJTD4slrGSJrcpLt/g/Jqqdjg== http_listener listener(m_secure_uri, server_config); listener.support(methods::GET, - [](http_request request) + [&](http_request request) { http_asserts::assert_request_equals(request, methods::GET, U("/")); + + for (auto&& h : all_headers) + { + std::cout << "HEADER - " << h.first << ": " << h.second << std::endl; + VERIFY_IS_TRUE(request.headers().has(h.first)); + VERIFY_ARE_EQUAL(h.second, request.headers().find(h.first)->second); + } + + VERIFY_ARE_EQUAL(body, request.extract_string(true).get()); + request.reply(status_codes::OK); }); @@ -522,6 +568,9 @@ XzJTD4slrGSJrcpLt/g/Jqqdjg== http_request msg(methods::GET); msg.set_request_uri(U("/")); + msg.headers() = all_headers; + msg.set_body(body); + http_asserts::assert_response_equals(client.request(msg).get(), status_codes::OK); listener.close().wait();