From f8b50f9da4c4ff8c6be198ce4156e895235437b4 Mon Sep 17 00:00:00 2001 From: garethsb-sony Date: Tue, 17 Oct 2017 17:26:37 +0100 Subject: [PATCH 1/7] Grab HTTP protocol version from the underlying request message and expose in http_request --- Release/include/cpprest/http_msg.h | 28 +++++++++++++++++++ Release/src/http/common/http_msg.cpp | 4 +++ .../src/http/listener/http_server_asio.cpp | 10 +++++++ .../src/http/listener/http_server_httpsys.cpp | 3 ++ 4 files changed, 45 insertions(+) diff --git a/Release/include/cpprest/http_msg.h b/Release/include/cpprest/http_msg.h index 8ca25edc69..b0379eeb3b 100644 --- a/Release/include/cpprest/http_msg.h +++ b/Release/include/cpprest/http_msg.h @@ -43,6 +43,22 @@ namespace client class http_client; } +/// +/// Represents the HTTP protocol version of a message, as {major, minor}. +/// +typedef std::pair http_version; + +/// +/// Predefined HTTP protocol versions. +/// +class http_versions +{ +public: + _ASYNCRTIMP const static http_version HTTP_0_9; + _ASYNCRTIMP const static http_version HTTP_1_0; + _ASYNCRTIMP const static http_version HTTP_1_1; +}; + /// /// Predefined method strings for the standard HTTP methods mentioned in the /// HTTP 1.1 specification. @@ -715,6 +731,8 @@ class _http_request final : public http::details::http_msg_base, public std::ena _ASYNCRTIMP void set_request_uri(const uri&); + const http_version& http_version() const { return m_http_version; } + const utility::string_t& remote_address() const { return m_remote_address; } const pplx::cancellation_token &cancellation_token() const { return m_cancellationToken; } @@ -757,6 +775,8 @@ class _http_request final : public http::details::http_msg_base, public std::ena void _set_base_uri(const http::uri &base_uri) { m_base_uri = base_uri; } + void _set_http_version(const http::http_version &http_version) { m_http_version = http_version; } + void _set_remote_address(const utility::string_t &remote_address) { m_remote_address = remote_address; } private: @@ -783,6 +803,8 @@ class _http_request final : public http::details::http_msg_base, public std::ena pplx::task_completion_event m_response; + http::http_version m_http_version; + utility::string_t m_remote_address; }; @@ -875,6 +897,12 @@ class http_request /// const http_headers &headers() const { return _m_impl->headers(); } + /// + /// Returns the HTTP protocol version of this request message. + /// + /// The HTTP protocol version. + const http_version& get_http_version() const { return _m_impl->http_version(); } + /// /// Returns a string representation of the remote IP address. /// diff --git a/Release/src/http/common/http_msg.cpp b/Release/src/http/common/http_msg.cpp index 6a857d7531..1adf96ed79 100644 --- a/Release/src/http/common/http_msg.cpp +++ b/Release/src/http/common/http_msg.cpp @@ -1010,6 +1010,10 @@ details::_http_request::_http_request(std::unique_ptr> major; + char dot; version >> dot; + unsigned int minor = 0; version >> minor; + m_request._get_impl()->_set_http_version({ (uint16_t)major, (uint16_t)minor }); + } + // if HTTP version is 1.0 then disable pipelining if (http_version == "HTTP/1.0") { diff --git a/Release/src/http/listener/http_server_httpsys.cpp b/Release/src/http/listener/http_server_httpsys.cpp index 9b58d20ef1..37adb1e84d 100644 --- a/Release/src/http/listener/http_server_httpsys.cpp +++ b/Release/src/http/listener/http_server_httpsys.cpp @@ -557,6 +557,9 @@ void windows_request_context::read_headers_io_completion(DWORD error_code, DWORD m_msg.set_method(parse_request_method(m_request)); parse_http_headers(m_request->Headers, m_msg.headers()); + // Get the version + m_msg._get_impl()->_set_http_version({ m_request->Version.MajorVersion, m_request->Version.MinorVersion }); + // Retrieve the remote IP address std::vector remoteAddressBuffer(50); From dff7a1c79c2da271b5718c071bc3a20889d945b8 Mon Sep 17 00:00:00 2001 From: garethsb Date: Thu, 19 Oct 2017 11:28:21 +0100 Subject: [PATCH 2/7] Use error_code overload to resolve https://github.com/Microsoft/cpprestsdk/issues/545 --- Release/src/http/listener/http_server_asio.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/Release/src/http/listener/http_server_asio.cpp b/Release/src/http/listener/http_server_asio.cpp index b58c99058b..9696707473 100644 --- a/Release/src/http/listener/http_server_asio.cpp +++ b/Release/src/http/listener/http_server_asio.cpp @@ -665,7 +665,12 @@ will_deref_and_erase_t asio_server_connection::handle_http_line(const boost::sys } // Get the remote IP address - m_request._get_impl()->_set_remote_address(utility::conversions::to_string_t(m_socket->remote_endpoint().address().to_string())); + boost::system::error_code socket_ec; + auto endpoint = m_socket->remote_endpoint(socket_ec); + if (!socket_ec) + { + m_request._get_impl()->_set_remote_address(utility::conversions::to_string_t(endpoint.address().to_string())); + } return handle_headers(); } From 1ba5ebfdb2d71d97938ecb6956a6b5bb94295794 Mon Sep 17 00:00:00 2001 From: garethsb Date: Thu, 19 Oct 2017 11:29:16 +0100 Subject: [PATCH 3/7] Rename get_http_version and get_remote_address without 'get_' prefix for consistency with rest of class public interface --- Release/include/cpprest/http_msg.h | 4 ++-- .../tests/functional/http/listener/request_handler_tests.cpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Release/include/cpprest/http_msg.h b/Release/include/cpprest/http_msg.h index b0379eeb3b..a33064f404 100644 --- a/Release/include/cpprest/http_msg.h +++ b/Release/include/cpprest/http_msg.h @@ -901,13 +901,13 @@ class http_request /// Returns the HTTP protocol version of this request message. /// /// The HTTP protocol version. - const http_version& get_http_version() const { return _m_impl->http_version(); } + const http_version& http_version() const { return _m_impl->http_version(); } /// /// Returns a string representation of the remote IP address. /// /// The remote IP address. - const utility::string_t& get_remote_address() const { return _m_impl->remote_address(); } + const utility::string_t& remote_address() const { return _m_impl->remote_address(); } /// /// Extract the body of the request message as a string value, checking that the content type is a MIME text type. diff --git a/Release/tests/functional/http/listener/request_handler_tests.cpp b/Release/tests/functional/http/listener/request_handler_tests.cpp index 33f7d0ea85..aabe98adbd 100644 --- a/Release/tests/functional/http/listener/request_handler_tests.cpp +++ b/Release/tests/functional/http/listener/request_handler_tests.cpp @@ -460,7 +460,7 @@ TEST_FIXTURE(uri_address, remote_address) listener.support(methods::GET, [&requestCount](http_request request) { - const string_t& remoteAddr = request.get_remote_address(); + const string_t& remoteAddr = request.remote_address(); const string_t& localhost4 = string_t(U("127.0.0.1")); const string_t& localhost6 = string_t(U("::1")); From 85e04503eb87add2328dfe96c3f0835fc9579a2a Mon Sep 17 00:00:00 2001 From: garethsb Date: Thu, 19 Oct 2017 12:52:17 +0100 Subject: [PATCH 4/7] Add test case for http_version --- .../http/listener/request_handler_tests.cpp | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/Release/tests/functional/http/listener/request_handler_tests.cpp b/Release/tests/functional/http/listener/request_handler_tests.cpp index aabe98adbd..3a1e135b13 100644 --- a/Release/tests/functional/http/listener/request_handler_tests.cpp +++ b/Release/tests/functional/http/listener/request_handler_tests.cpp @@ -448,6 +448,39 @@ TEST_FIXTURE(uri_address, test_leaks) listener.close().wait(); } +TEST_FIXTURE(uri_address, http_version) +{ + http_listener listener(U("http://localhost:45678/path1")); + listener.open().wait(); + + test_http_client::scoped_client client(U("http://localhost:45678")); + test_http_client * p_client = client.client(); + + volatile unsigned long requestCount = 0; + + listener.support(methods::GET, [&requestCount](http_request request) + { + const auto& httpVersion = request.http_version(); + + // All clients currently use HTTP/1.1 + VERIFY_IS_TRUE(httpVersion == http_versions::HTTP_1_1); + + os_utilities::interlocked_increment(&requestCount); + request.reply(status_codes::NoContent); + }); + + // Send a request to the listener + VERIFY_ARE_EQUAL(0, p_client->request(methods::GET, U("/path1"))); + + p_client->next_response().then([](test_response *p_response) + { + http_asserts::assert_test_response_equals(p_response, status_codes::NoContent); + }).wait(); + + VERIFY_IS_TRUE(requestCount >= 1); + listener.close().wait(); +} + TEST_FIXTURE(uri_address, remote_address) { http_listener listener(U("http://localhost:45678/path1")); From bc71f403ff17a4e4bcfc415c16af5f94d6f34f54 Mon Sep 17 00:00:00 2001 From: garethsb-sony Date: Thu, 9 Nov 2017 15:38:28 +0000 Subject: [PATCH 5/7] Fix GCC "error: changes meaning of 'http_version'..." that should have been in commit:1ba5ebfd --- Release/include/cpprest/http_msg.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Release/include/cpprest/http_msg.h b/Release/include/cpprest/http_msg.h index a33064f404..3963718f8c 100644 --- a/Release/include/cpprest/http_msg.h +++ b/Release/include/cpprest/http_msg.h @@ -731,7 +731,7 @@ class _http_request final : public http::details::http_msg_base, public std::ena _ASYNCRTIMP void set_request_uri(const uri&); - const http_version& http_version() const { return m_http_version; } + const http::http_version& http_version() const { return m_http_version; } const utility::string_t& remote_address() const { return m_remote_address; } @@ -901,7 +901,7 @@ class http_request /// Returns the HTTP protocol version of this request message. /// /// The HTTP protocol version. - const http_version& http_version() const { return _m_impl->http_version(); } + const http::http_version& http_version() const { return _m_impl->http_version(); } /// /// Returns a string representation of the remote IP address. From 1d358474c02e2c4c3e2043b97e04d0777be2fb90 Mon Sep 17 00:00:00 2001 From: Robert Schumacher Date: Wed, 24 Jan 2018 13:27:56 -0800 Subject: [PATCH 6/7] Use struct for http_version instead of pair. --- Release/include/cpprest/http_msg.h | 24 ++++++++++++++----- Release/src/http/common/http_msg.cpp | 12 ++++++---- .../src/http/listener/http_server_asio.cpp | 11 +++++---- .../src/http/listener/http_server_httpsys.cpp | 3 +-- 4 files changed, 33 insertions(+), 17 deletions(-) diff --git a/Release/include/cpprest/http_msg.h b/Release/include/cpprest/http_msg.h index 3963718f8c..41232fde4a 100644 --- a/Release/include/cpprest/http_msg.h +++ b/Release/include/cpprest/http_msg.h @@ -46,7 +46,19 @@ namespace client /// /// Represents the HTTP protocol version of a message, as {major, minor}. /// -typedef std::pair http_version; +struct http_version +{ + uint8_t major; + uint8_t minor; + + inline bool operator==(const http_version& other) const { return major == other.major && minor == other.minor; } + inline bool operator<(const http_version& other) const { return major < other.major || (major == other.major && minor < other.minor); } + + inline bool operator!=(const http_version& other) const { return !(*this == other); } + inline bool operator>=(const http_version& other) const { return !(*this < other); } + inline bool operator>(const http_version& other) const { return !(*this < other || *this == other); } + inline bool operator<=(const http_version& other) const { return *this < other || *this == other; } +}; /// /// Predefined HTTP protocol versions. @@ -54,9 +66,9 @@ typedef std::pair http_version; class http_versions { public: - _ASYNCRTIMP const static http_version HTTP_0_9; - _ASYNCRTIMP const static http_version HTTP_1_0; - _ASYNCRTIMP const static http_version HTTP_1_1; + _ASYNCRTIMP static const http_version HTTP_0_9; + _ASYNCRTIMP static const http_version HTTP_1_0; + _ASYNCRTIMP static const http_version HTTP_1_1; }; /// @@ -731,7 +743,7 @@ class _http_request final : public http::details::http_msg_base, public std::ena _ASYNCRTIMP void set_request_uri(const uri&); - const http::http_version& http_version() const { return m_http_version; } + http::http_version http_version() const { return m_http_version; } const utility::string_t& remote_address() const { return m_remote_address; } @@ -901,7 +913,7 @@ class http_request /// Returns the HTTP protocol version of this request message. /// /// The HTTP protocol version. - const http::http_version& http_version() const { return _m_impl->http_version(); } + http::http_version http_version() const { return _m_impl->http_version(); } /// /// Returns a string representation of the remote IP address. diff --git a/Release/src/http/common/http_msg.cpp b/Release/src/http/common/http_msg.cpp index 1adf96ed79..abe927b118 100644 --- a/Release/src/http/common/http_msg.cpp +++ b/Release/src/http/common/http_msg.cpp @@ -995,7 +995,8 @@ details::_http_request::_http_request(http::method mtd) : m_method(std::move(mtd)), m_initiated_response(0), m_server_context(), - m_cancellationToken(pplx::cancellation_token::none()) + m_cancellationToken(pplx::cancellation_token::none()), + m_http_version(http::http_version{0, 0}) { if(m_method.empty()) { @@ -1006,13 +1007,14 @@ details::_http_request::_http_request(http::method mtd) details::_http_request::_http_request(std::unique_ptr server_context) : m_initiated_response(0), m_server_context(std::move(server_context)), - m_cancellationToken(pplx::cancellation_token::none()) + m_cancellationToken(pplx::cancellation_token::none()), + m_http_version(http::http_version{0, 0}) { } -const http_version http_versions::HTTP_0_9{ 0, 9 }; -const http_version http_versions::HTTP_1_0{ 1, 0 }; -const http_version http_versions::HTTP_1_1{ 1, 1 }; +const http_version http_versions::HTTP_0_9 = { 0, 9 }; +const http_version http_versions::HTTP_1_0 = { 1, 0 }; +const http_version http_versions::HTTP_1_1 = { 1, 1 }; #define _METHODS #define DAT(a,b) const method methods::a = b; diff --git a/Release/src/http/listener/http_server_asio.cpp b/Release/src/http/listener/http_server_asio.cpp index 9696707473..c807e70556 100644 --- a/Release/src/http/listener/http_server_asio.cpp +++ b/Release/src/http/listener/http_server_asio.cpp @@ -649,17 +649,20 @@ will_deref_and_erase_t asio_server_connection::handle_http_line(const boost::sys // Get the version std::string http_version = http_path_and_version.substr(http_path_and_version.size() - VersionPortionSize + 1, VersionPortionSize - 2); + auto m_request_impl = m_request._get_impl().get(); + web::http::http_version parsed_version = { 0, 0 }; if (boost::starts_with(http_version, "HTTP/")) { std::istringstream version{ http_version.substr(5) }; - unsigned int major = 0; version >> major; + version >> parsed_version.major; char dot; version >> dot; - unsigned int minor = 0; version >> minor; - m_request._get_impl()->_set_http_version({ (uint16_t)major, (uint16_t)minor }); + version >> parsed_version.minor; + + m_request_impl->_set_http_version(parsed_version); } // if HTTP version is 1.0 then disable pipelining - if (http_version == "HTTP/1.0") + if (parsed_version == web::http::http_versions::HTTP_1_0) { m_close = true; } diff --git a/Release/src/http/listener/http_server_httpsys.cpp b/Release/src/http/listener/http_server_httpsys.cpp index 37adb1e84d..17761fc46e 100644 --- a/Release/src/http/listener/http_server_httpsys.cpp +++ b/Release/src/http/listener/http_server_httpsys.cpp @@ -557,8 +557,7 @@ void windows_request_context::read_headers_io_completion(DWORD error_code, DWORD m_msg.set_method(parse_request_method(m_request)); parse_http_headers(m_request->Headers, m_msg.headers()); - // Get the version - m_msg._get_impl()->_set_http_version({ m_request->Version.MajorVersion, m_request->Version.MinorVersion }); + m_msg._get_impl()->_set_http_version({ (uint8_t)m_request->Version.MajorVersion, (uint8_t)m_request->Version.MinorVersion }); // Retrieve the remote IP address std::vector remoteAddressBuffer(50); From 154e322e02936d22eb389f2fa3a757370fb1ff0d Mon Sep 17 00:00:00 2001 From: Robert Schumacher Date: Wed, 24 Jan 2018 13:28:12 -0800 Subject: [PATCH 7/7] Restore get_remote_address to avoid breaking source compat --- Release/include/cpprest/http_msg.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Release/include/cpprest/http_msg.h b/Release/include/cpprest/http_msg.h index 41232fde4a..2defd81ffd 100644 --- a/Release/include/cpprest/http_msg.h +++ b/Release/include/cpprest/http_msg.h @@ -921,6 +921,9 @@ class http_request /// The remote IP address. const utility::string_t& remote_address() const { return _m_impl->remote_address(); } + CASABLANCA_DEPRECATED("Use `remote_address()` instead.") + const utility::string_t& get_remote_address() const { return _m_impl->remote_address(); } + /// /// Extract the body of the request message as a string value, checking that the content type is a MIME text type. /// A body can only be extracted once because in some cases an optimization is made where the data is 'moved' out.