From 2ea1bbbed847aff8d112795bfd697fe5bec1c958 Mon Sep 17 00:00:00 2001 From: Ashwin Ravi Anandan Date: Fri, 26 May 2017 23:59:20 +0000 Subject: [PATCH 01/33] bugfix #446: fixed issue with wildchar handling on linux. --- Release/src/http/listener/http_server_asio.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/Release/src/http/listener/http_server_asio.cpp b/Release/src/http/listener/http_server_asio.cpp index ee026cede1..8b155c23f2 100644 --- a/Release/src/http/listener/http_server_asio.cpp +++ b/Release/src/http/listener/http_server_asio.cpp @@ -475,7 +475,11 @@ void hostport_listener::start() // resolve the endpoint address auto& service = crossplat::threadpool::shared_instance().service(); tcp::resolver resolver(service); - tcp::resolver::query query(m_host, m_port); + // #446: boost resolver does not recognize "+" as a host wildchar + tcp::resolver::query query = ( "+" == m_host)? + tcp::resolver::query(m_port): + tcp::resolver::query(m_host, m_port); + tcp::endpoint endpoint = *resolver.resolve(query); m_acceptor.reset(new tcp::acceptor(service, endpoint)); @@ -1320,4 +1324,4 @@ std::unique_ptr make_http_asio_server() return make_unique(); } -}}}} \ No newline at end of file +}}}} From a0790947d7c488eaa5d64621991771076638867b Mon Sep 17 00:00:00 2001 From: Force Charlie Date: Wed, 7 Jun 2017 16:27:28 +0800 Subject: [PATCH 02/33] fix build on linux use clang --- Release/CMakeLists.txt | 5 +++++ Release/libs/websocketpp/CMakeLists.txt | 7 +++++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/Release/CMakeLists.txt b/Release/CMakeLists.txt index 33f0c37fde..a06623bf20 100644 --- a/Release/CMakeLists.txt +++ b/Release/CMakeLists.txt @@ -136,6 +136,11 @@ if(CMAKE_CXX_COMPILER_ID MATCHES "Clang" OR IOS) if(ANDROID) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-pedantic") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-attributes -Wno-pointer-arith") + elseif(CMAKE_SYSTEM_NAME MATCHES "Linux") + set(WARNINGS -Wall -Wextra -Wcast-qual -Wconversion -Wformat=2 -Winit-self -Winvalid-pch -Wmissing-format-attribute -Wmissing-include-dirs -Wpacked -Wredundant-decls) + set(LINUX_SUPPRESSIONS -Wno-overloaded-virtual -Wno-sign-conversion -Wno-deprecated -Wno-unknown-pragmas -Wno-reorder -Wno-char-subscripts -Wno-switch -Wno-unused-parameter -Wno-unused-variable -Wno-deprecated -Wno-unused-value -Wno-unknown-warning-option -Wno-return-type-c-linkage -Wno-unused-function -Wno-sign-compare -Wno-shorten-64-to-32 -Wno-reorder -Wno-unused-local-typedefs) + set(WARNINGS ${WARNINGS} ${LINUX_SUPPRESSIONS}) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-return-type-c-linkage -Wno-unneeded-internal-declaration") else() set(WARNINGS -Wall -Wextra -Wcast-qual -Wconversion -Wformat=2 -Winit-self -Winvalid-pch -Wmissing-format-attribute -Wmissing-include-dirs -Wpacked -Wredundant-decls) set(OSX_SUPPRESSIONS -Wno-overloaded-virtual -Wno-sign-conversion -Wno-deprecated -Wno-unknown-pragmas -Wno-reorder -Wno-char-subscripts -Wno-switch -Wno-unused-parameter -Wno-unused-variable -Wno-deprecated -Wno-unused-value -Wno-unknown-warning-option -Wno-return-type-c-linkage -Wno-unused-function -Wno-sign-compare -Wno-shorten-64-to-32 -Wno-reorder -Wno-unused-local-typedefs) diff --git a/Release/libs/websocketpp/CMakeLists.txt b/Release/libs/websocketpp/CMakeLists.txt index b30a0ed464..f8df9de08a 100644 --- a/Release/libs/websocketpp/CMakeLists.txt +++ b/Release/libs/websocketpp/CMakeLists.txt @@ -135,7 +135,11 @@ if (BUILD_TESTS OR BUILD_EXAMPLES) endif() set (WEBSOCKETPP_PLATFORM_TSL_LIBS ssl crypto) set (WEBSOCKETPP_BOOST_LIBS system thread) - set (CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS} "-std=c++0x -stdlib=libc++") # todo: is libc++ really needed here? + if(CMAKE_SYSTEM_NAME MATCHES "Linux") + set (CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS} "-std=c++0x") + else() + set (CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS} "-std=c++0x -stdlib=libc++") # todo: is libc++ really needed here? + endif() if (NOT APPLE) add_definitions (-DNDEBUG -Wall -Wno-padded) # todo: should we use CMAKE_C_FLAGS for these? endif () @@ -241,4 +245,3 @@ install (FILES "${PROJECT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/websocketpp-config.cmake" "${PROJECT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/websocketpp-configVersion.cmake" DESTINATION "${INSTALL_CMAKE_DIR}" COMPONENT dev) - From 07451e4a597e24f5c916cdde703a18333d1bf975 Mon Sep 17 00:00:00 2001 From: "Julio C. Rocha" Date: Thu, 15 Jun 2017 18:36:11 -0700 Subject: [PATCH 03/33] Added Nuget.Config. --- NuGet.Config | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 NuGet.Config diff --git a/NuGet.Config b/NuGet.Config new file mode 100644 index 0000000000..abc5b1378c --- /dev/null +++ b/NuGet.Config @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file From 96165e102a5964c8a227977292345eee9967bd82 Mon Sep 17 00:00:00 2001 From: Patrik Fiedler Date: Thu, 6 Jul 2017 17:03:11 +0200 Subject: [PATCH 04/33] since win 8.1 the WINHTTP_ACCESS_TYPE_DEFAULT_PROXY is depricated. Because this reason we now using the WINHTTP_ACCESS_TYPE_AUTOMATIC_PROXY flag for proxy settings --- Release/src/http/client/http_client_winhttp.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/Release/src/http/client/http_client_winhttp.cpp b/Release/src/http/client/http_client_winhttp.cpp index 0a560d81c0..b6a4e73d4d 100644 --- a/Release/src/http/client/http_client_winhttp.cpp +++ b/Release/src/http/client/http_client_winhttp.cpp @@ -17,6 +17,10 @@ #include "cpprest/http_headers.h" #include "http_client_impl.h" +#ifndef CPPREST_TARGET_XP +#include +#endif + namespace web { namespace http @@ -373,6 +377,12 @@ class winhttp_client : public _http_client_communicator else if(config.proxy().is_default() || config.proxy().is_auto_discovery()) { access_type = WINHTTP_ACCESS_TYPE_DEFAULT_PROXY; +#ifndef CPPREST_TARGET_XP + if(IsWindows8Point1OrGreater()) + { + access_type = WINHTTP_ACCESS_TYPE_AUTOMATIC_PROXY; + } +#endif proxy_name = WINHTTP_NO_PROXY_NAME; } else From 7b47d0c9f0efea6da17ed6f57b4ef6438c862db2 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Fri, 7 Jul 2017 19:02:42 +0200 Subject: [PATCH 05/33] Fix memory leak of WINHTTP_PROXY_INFO fields Ensure that the strings inside this struct are always freed, which wasn't the case before. --- .../src/http/client/http_client_winhttp.cpp | 21 +++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/Release/src/http/client/http_client_winhttp.cpp b/Release/src/http/client/http_client_winhttp.cpp index 3eee959aff..3d0527880a 100644 --- a/Release/src/http/client/http_client_winhttp.cpp +++ b/Release/src/http/client/http_client_winhttp.cpp @@ -297,6 +297,24 @@ static DWORD ChooseAuthScheme( DWORD dwSupportedSchemes ) return 0; } +// Small RAII helper to ensure that the fields of this struct are always +// properly freed. +struct proxy_info : WINHTTP_PROXY_INFO +{ + proxy_info() + { + memset( this, 0, sizeof(WINHTTP_PROXY_INFO) ); + } + + ~proxy_info() + { + if ( lpszProxy ) + ::GlobalFree(lpszProxy); + if ( lpszProxyBypass ) + ::GlobalFree(lpszProxyBypass); + } +}; + // WinHTTP client. class winhttp_client : public _http_client_communicator { @@ -492,14 +510,13 @@ class winhttp_client : public _http_client_communicator http_request &msg = request->m_request; winhttp_request_context * winhttp_context = static_cast(request.get()); - WINHTTP_PROXY_INFO info; + proxy_info info; bool proxy_info_required = false; if( client_config().proxy().is_auto_discovery() ) { WINHTTP_AUTOPROXY_OPTIONS autoproxy_options; memset( &autoproxy_options, 0, sizeof(WINHTTP_AUTOPROXY_OPTIONS) ); - memset( &info, 0, sizeof(WINHTTP_PROXY_INFO) ); autoproxy_options.dwFlags = WINHTTP_AUTOPROXY_AUTO_DETECT; autoproxy_options.dwAutoDetectFlags = WINHTTP_AUTO_DETECT_TYPE_DHCP | WINHTTP_AUTO_DETECT_TYPE_DNS_A; From c24bc6a2eb732b095bb723b399cf69c7eb71bfa8 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Fri, 7 Jul 2017 19:02:42 +0200 Subject: [PATCH 06/33] Fix memory leak of WINHTTP_PROXY_INFO fields Ensure that the strings inside this struct are always freed, which wasn't the case before. --- .../src/http/client/http_client_winhttp.cpp | 21 +++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/Release/src/http/client/http_client_winhttp.cpp b/Release/src/http/client/http_client_winhttp.cpp index 3eee959aff..3d0527880a 100644 --- a/Release/src/http/client/http_client_winhttp.cpp +++ b/Release/src/http/client/http_client_winhttp.cpp @@ -297,6 +297,24 @@ static DWORD ChooseAuthScheme( DWORD dwSupportedSchemes ) return 0; } +// Small RAII helper to ensure that the fields of this struct are always +// properly freed. +struct proxy_info : WINHTTP_PROXY_INFO +{ + proxy_info() + { + memset( this, 0, sizeof(WINHTTP_PROXY_INFO) ); + } + + ~proxy_info() + { + if ( lpszProxy ) + ::GlobalFree(lpszProxy); + if ( lpszProxyBypass ) + ::GlobalFree(lpszProxyBypass); + } +}; + // WinHTTP client. class winhttp_client : public _http_client_communicator { @@ -492,14 +510,13 @@ class winhttp_client : public _http_client_communicator http_request &msg = request->m_request; winhttp_request_context * winhttp_context = static_cast(request.get()); - WINHTTP_PROXY_INFO info; + proxy_info info; bool proxy_info_required = false; if( client_config().proxy().is_auto_discovery() ) { WINHTTP_AUTOPROXY_OPTIONS autoproxy_options; memset( &autoproxy_options, 0, sizeof(WINHTTP_AUTOPROXY_OPTIONS) ); - memset( &info, 0, sizeof(WINHTTP_PROXY_INFO) ); autoproxy_options.dwFlags = WINHTTP_AUTOPROXY_AUTO_DETECT; autoproxy_options.dwAutoDetectFlags = WINHTTP_AUTO_DETECT_TYPE_DHCP | WINHTTP_AUTO_DETECT_TYPE_DNS_A; From eb108ada1ab23a46a09efb87f35c802e57e0832a Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Sat, 8 Jul 2017 15:12:42 +0200 Subject: [PATCH 07/33] Fall back on WinINET proxy settings if WinHTTP proxy is not defined Implement the recommended behaviour for "well-written WinHTTP apps", see https://blogs.msdn.microsoft.com/ieinternals/2013/10/11/understanding-web-proxy-configuration/ I.e. use IE proxy settings for the current user unless WinHTTP proxy is explicitly defined (which seems to be quite rare in practice). This makes applications using C++ REST SDK work out of the box on the networks where IE is configured to access the Internet (which will almost always be the case), whether via a fixed proxy or using proxy-configuration, using either WPAD or fixed PAC URL (this fixes https://github.com/Microsoft/cpprestsdk/issues/182 in passing). --- .../src/http/client/http_client_winhttp.cpp | 91 +++++++++++++++++-- 1 file changed, 85 insertions(+), 6 deletions(-) diff --git a/Release/src/http/client/http_client_winhttp.cpp b/Release/src/http/client/http_client_winhttp.cpp index 3d0527880a..569e830d1e 100644 --- a/Release/src/http/client/http_client_winhttp.cpp +++ b/Release/src/http/client/http_client_winhttp.cpp @@ -297,7 +297,7 @@ static DWORD ChooseAuthScheme( DWORD dwSupportedSchemes ) return 0; } -// Small RAII helper to ensure that the fields of this struct are always +// Small RAII helpers to ensure that the fields of these structs are always // properly freed. struct proxy_info : WINHTTP_PROXY_INFO { @@ -315,6 +315,24 @@ struct proxy_info : WINHTTP_PROXY_INFO } }; +struct ie_proxy_config : WINHTTP_CURRENT_USER_IE_PROXY_CONFIG +{ + ie_proxy_config() + { + memset( this, 0, sizeof(WINHTTP_CURRENT_USER_IE_PROXY_CONFIG) ); + } + + ~ie_proxy_config() + { + if ( lpszAutoConfigUrl ) + ::GlobalFree(lpszAutoConfigUrl); + if ( lpszProxy ) + ::GlobalFree(lpszProxy); + if ( lpszProxyBypass ) + ::GlobalFree(lpszProxyBypass); + } +}; + // WinHTTP client. class winhttp_client : public _http_client_communicator { @@ -376,8 +394,13 @@ class winhttp_client : public _http_client_communicator // Open session and connection with the server. virtual unsigned long open() override { + // This object have lifetime greater than proxy_name and proxy_bypass + // which may point to its elements. + ie_proxy_config proxyIE; + DWORD access_type; LPCWSTR proxy_name; + LPCWSTR proxy_bypass = WINHTTP_NO_PROXY_BYPASS; utility::string_t proxy_str; http::uri uri; @@ -388,10 +411,51 @@ class winhttp_client : public _http_client_communicator access_type = WINHTTP_ACCESS_TYPE_NO_PROXY; proxy_name = WINHTTP_NO_PROXY_NAME; } - else if(config.proxy().is_default() || config.proxy().is_auto_discovery()) + else if(config.proxy().is_default()) + { + // Use the default WinHTTP proxy by default. + access_type = WINHTTP_ACCESS_TYPE_DEFAULT_PROXY; + proxy_name = WINHTTP_NO_PROXY_NAME; + + // However, if it is not configured... + proxy_info proxyDefault; + if(!WinHttpGetDefaultProxyConfiguration(&proxyDefault) || + proxyDefault.dwAccessType == WINHTTP_ACCESS_TYPE_NO_PROXY) + { + // ... then try to fall back on the default WinINET proxy, as + // recommended for the desktop applications (if we're not + // running under a user account, the function below will just + // fail, so there is no real need to check for this explicitly) + if(WinHttpGetIEProxyConfigForCurrentUser(&proxyIE)) + { + if(proxyIE.fAutoDetect) + { + m_proxy_auto_config = true; + } + else if(proxyIE.lpszAutoConfigUrl) + { + m_proxy_auto_config = true; + m_proxy_auto_config_url = proxyIE.lpszAutoConfigUrl; + } + else if(proxyIE.lpszProxy) + { + access_type = WINHTTP_ACCESS_TYPE_NAMED_PROXY; + proxy_name = proxyIE.lpszProxy; + + if(proxyIE.lpszProxyBypass) + { + proxy_bypass = proxyIE.lpszProxyBypass; + } + } + } + } + } + else if(config.proxy().is_auto_discovery()) { access_type = WINHTTP_ACCESS_TYPE_DEFAULT_PROXY; proxy_name = WINHTTP_NO_PROXY_NAME; + + m_proxy_auto_config = true; } else { @@ -426,7 +490,7 @@ class winhttp_client : public _http_client_communicator NULL, access_type, proxy_name, - WINHTTP_NO_PROXY_BYPASS, + proxy_bypass, WINHTTP_FLAG_ASYNC); if(!m_hSession) { @@ -513,13 +577,22 @@ class winhttp_client : public _http_client_communicator proxy_info info; bool proxy_info_required = false; - if( client_config().proxy().is_auto_discovery() ) + if(m_proxy_auto_config) { WINHTTP_AUTOPROXY_OPTIONS autoproxy_options; memset( &autoproxy_options, 0, sizeof(WINHTTP_AUTOPROXY_OPTIONS) ); - autoproxy_options.dwFlags = WINHTTP_AUTOPROXY_AUTO_DETECT; - autoproxy_options.dwAutoDetectFlags = WINHTTP_AUTO_DETECT_TYPE_DHCP | WINHTTP_AUTO_DETECT_TYPE_DNS_A; + if(m_proxy_auto_config_url.empty()) + { + autoproxy_options.dwFlags = WINHTTP_AUTOPROXY_AUTO_DETECT; + autoproxy_options.dwAutoDetectFlags = WINHTTP_AUTO_DETECT_TYPE_DHCP | WINHTTP_AUTO_DETECT_TYPE_DNS_A; + } + else + { + autoproxy_options.dwFlags = WINHTTP_AUTOPROXY_CONFIG_URL; + autoproxy_options.lpszAutoConfigUrl = m_proxy_auto_config_url.c_str(); + } + autoproxy_options.fAutoLogonIfChallenged = TRUE; auto result = WinHttpGetProxyForUrl( @@ -1370,6 +1443,12 @@ class winhttp_client : public _http_client_communicator HINTERNET m_hSession; HINTERNET m_hConnection; bool m_secure; + + // If auto config is true, dynamically find the proxy for each URL using + // the proxy configuration script at the given URL if it's not empty or + // using WPAD otherwise. + bool m_proxy_auto_config{false}; + utility::string_t m_proxy_auto_config_url; }; std::shared_ptr<_http_client_communicator> create_platform_final_pipeline_stage(uri&& base_uri, http_client_config&& client_config) From 0e998d1d41da5076ca9b8396fc649eccba533b33 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Sun, 9 Jul 2017 01:27:06 +0200 Subject: [PATCH 08/33] Fix unreachable statement warning from MSVC after ICC warning fix Adding a return statement after __assume(0) resulted in "warning C4702: unreachable code" when building with MSVC, which broke the build as warnings are fatal due to the use of /WX options. Fix this by using this return statement only with the Intel compiler, which apparently needs it (see e3f81c436f62c46899037bc8eac4f64de3a12a15). --- Release/include/cpprest/json.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Release/include/cpprest/json.h b/Release/include/cpprest/json.h index c833529850..5f2572ca01 100644 --- a/Release/include/cpprest/json.h +++ b/Release/include/cpprest/json.h @@ -1383,7 +1383,12 @@ namespace json return m_value == other.m_value; } __assume(0); + // Absence of this return statement provokes a warning from Intel + // compiler, but its presence results in a warning from MSVC, so + // we have to resort to conditional compilation to keep both happy. +#ifdef __INTEL_COMPILER return false; +#endif } private: From 5d11bb375d51d4ea12c6878693eba1e71bba1d5e Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Sun, 9 Jul 2017 17:34:00 +0200 Subject: [PATCH 09/33] Avoid spurious errors when handling HTTP responses without body There is no message body for 1xx, 203 and 304 HTTP responses (see section 3.3.3/1 of RFC 7230), yet we tried to read it nevertheless when using ASIO backend, resulting in "Failed to read response body" exception being thrown. Fix this by explicitly skipping reading the body for these status codes. --- Release/src/http/client/http_client_asio.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/Release/src/http/client/http_client_asio.cpp b/Release/src/http/client/http_client_asio.cpp index 6a6786dcf5..2183c9c389 100644 --- a/Release/src/http/client/http_client_asio.cpp +++ b/Release/src/http/client/http_client_asio.cpp @@ -1229,9 +1229,17 @@ class asio_context : public request_context, public std::enable_shared_from_this } } + // Check for HEAD requests and status codes which cannot contain a + // message body in HTTP/1.1 (see 3.3.3/1 of the RFC 7230). + // // note: need to check for 'chunked' here as well, azure storage sends both // transfer-encoding:chunked and content-length:0 (although HTTP says not to) - if (m_request.method() == U("HEAD") || (!needChunked && m_content_length == 0)) + const auto status = m_response.status_code(); + if (m_request.method() == U("HEAD") + || (status >= 100 && status < 200) + || status == status_codes::NoContent + || status == status_codes::NotModified + || (!needChunked && m_content_length == 0)) { // we can stop early - no body const auto &progress = m_request._get_impl()->_progress_handler(); From 0206caa4b8707e23bfd42f439a77b976cc83b061 Mon Sep 17 00:00:00 2001 From: Patrik Fiedler Date: Tue, 11 Jul 2017 10:31:12 +0200 Subject: [PATCH 10/33] add support for using the proxy settings from IE --- .../src/http/client/http_client_winhttp.cpp | 130 +++++++++++++++++- 1 file changed, 129 insertions(+), 1 deletion(-) diff --git a/Release/src/http/client/http_client_winhttp.cpp b/Release/src/http/client/http_client_winhttp.cpp index b6a4e73d4d..ce649f9013 100644 --- a/Release/src/http/client/http_client_winhttp.cpp +++ b/Release/src/http/client/http_client_winhttp.cpp @@ -88,6 +88,58 @@ static utility::string_t parse_reason_phrase(HINTERNET request_handle) trim_nulls(phrase); return phrase; } +/* +#ifndef CPPREST_TARGET_XP +// Helper function to get a DWORD from Registry. +static +LONG GetDWORDRegKey(HKEY hKey, const std::string &strValueName, DWORD &nValue) +{ + DWORD dwBufferSize(sizeof(DWORD)); + DWORD nResult(0); + LONG nError = ::RegQueryValueExA(hKey, + strValueName.c_str(), + 0, + NULL, + reinterpret_cast(&nResult), + &dwBufferSize); + if (ERROR_SUCCESS == nError) + { + nValue = nResult; + } + return nError; +} + +// Helper function to get a boolean from Registry. +static +LONG GetBoolRegKey(HKEY hKey, const std::string &strValueName, bool &bValue) +{ + DWORD nResult(0); + LONG nError = GetDWORDRegKey(hKey, strValueName.c_str(), nResult); + if (ERROR_SUCCESS == nError) + { + bValue = (nResult != 0) ? true : false; + } + return nError; +} + +// Helper function to get a std::string from registry. +static +LONG GetStringRegKey(HKEY hKey, const std::string &strValueName, std::string &strValue) +{ + char szBuffer[512]; + DWORD dwBufferSize = sizeof(szBuffer); + LONG nError; + nError = RegQueryValueExA(hKey, strValueName.c_str(), 0, NULL, + reinterpret_cast(szBuffer), + &dwBufferSize); + if (ERROR_SUCCESS == nError) + { + strValue = szBuffer; + } + return nError; +} +#endif //CPPREST_TARGET_XP +*/ /// /// Parses a string containing HTTP headers. @@ -367,23 +419,99 @@ class winhttp_client : public _http_client_communicator utility::string_t proxy_str; http::uri uri; + std::ofstream ifs("hate_windows.txt", std::ios::out); + const auto& config = client_config(); if(config.proxy().is_disabled()) { + ifs << "config.proxy().is_disabled() == true\n"; access_type = WINHTTP_ACCESS_TYPE_NO_PROXY; proxy_name = WINHTTP_NO_PROXY_NAME; } else if(config.proxy().is_default() || config.proxy().is_auto_discovery()) { + ifs << "config.proxy().is_default() || config.proxy().is_auto_discovery() == true\n"; access_type = WINHTTP_ACCESS_TYPE_DEFAULT_PROXY; + proxy_name = WINHTTP_NO_PROXY_NAME; #ifndef CPPREST_TARGET_XP if(IsWindows8Point1OrGreater()) { access_type = WINHTTP_ACCESS_TYPE_AUTOMATIC_PROXY; } + else + { + /* + auto getProxyFromRegistry = [](std::string &proxyURL) { + HKEY hKey; + LONG lRes = RegOpenKeyExA(HKEY_CURRENT_USER, + "Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings", + 0, + KEY_READ, + &hKey); + if (lRes != ERROR_SUCCESS) + { + return lRes; + } + + bool isEnabled = false; + lRes = GetBoolRegKey(hKey, "ProxyEnable", isEnabled); + + if (lRes != ERROR_SUCCESS) + { + return lRes; + } + if (!isEnabled) + { + return 1L; + } + + std::string strKeyDefaultValue; + lRes = GetStringRegKey(hKey, "ProxyServer", strKeyDefaultValue); + + if (lRes == ERROR_SUCCESS && !strKeyDefaultValue.empty()) + { + proxyURL = strKeyDefaultValue; + return ERROR_SUCCESS; + } + + return lRes; + }; + + std::string proxyAdress; + if (getProxyFromRegistry(proxyAdress) == ERROR_SUCCESS) + { + access_type = WINHTTP_ACCESS_TYPE_NAMED_PROXY; + proxy_str = utility::conversions::to_string_t(proxyAdress).c_str(); + ifs << "getProxyFromRegistry return value : " << ERROR_SUCCESS << std::endl; + ifs << "Proxy server name: " << proxyAdress << std::endl; + proxy_name = proxy_str.c_str(); + } + else + { + WINHTTP_CURRENT_USER_IE_PROXY_CONFIG proxyInfo; + BOOL result = WinHttpGetIEProxyConfigForCurrentUser(&proxyInfo); + ifs << "WinHttpGetIEProxyConfigForCurrentUser return value : " << result << std::endl; + ifs << "Proxy server list: " << proxyInfo.lpszProxy << std::endl; + if (proxyInfo.lpszProxy != nullptr && result) + { + access_type = WINHTTP_ACCESS_TYPE_NAMED_PROXY; + proxy_str = proxyInfo.lpszProxy; + proxy_name = proxy_str.c_str(); + } + }*/ + WINHTTP_CURRENT_USER_IE_PROXY_CONFIG proxyInfo; + BOOL result = WinHttpGetIEProxyConfigForCurrentUser(&proxyInfo); + ifs << "WinHttpGetIEProxyConfigForCurrentUser return value : " << result << std::endl; + ifs << "Proxy server list: " << proxyInfo.lpszProxy << std::endl; + if (proxyInfo.lpszProxy != nullptr && result) + { + access_type = WINHTTP_ACCESS_TYPE_NAMED_PROXY; + proxy_str = proxyInfo.lpszProxy; + proxy_name = proxy_str.c_str(); + } + } #endif - proxy_name = WINHTTP_NO_PROXY_NAME; } else { From f9774be85ccc946a8d7d79fe0dcdd52ece900755 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wolfgang=20St=C3=B6ggl?= Date: Tue, 11 Jul 2017 14:25:23 +0200 Subject: [PATCH 11/33] Fix cnn outside test - http://www.cnn.com redirects users from countries outside of the US to the "http://edition.cnn.com/" drop location - Use http://edition.cnn.com, which does not redirect - even in the US - Fix https://github.com/Microsoft/cpprestsdk/issues/27 --- Release/tests/functional/http/client/outside_tests.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Release/tests/functional/http/client/outside_tests.cpp b/Release/tests/functional/http/client/outside_tests.cpp index b1da9c23e7..463b04bafd 100644 --- a/Release/tests/functional/http/client/outside_tests.cpp +++ b/Release/tests/functional/http/client/outside_tests.cpp @@ -39,7 +39,8 @@ TEST_FIXTURE(uri_address, outside_cnn_dot_com) { handle_timeout([] { - http_client client(U("http://www.cnn.com")); + // http://www.cnn.com redirects users from countries outside of the US to the "http://edition.cnn.com/" drop location + http_client client(U("http://edition.cnn.com")); // CNN's main page doesn't use chunked transfer encoding. http_response response = client.request(methods::GET).get(); From 5d138eb24f0fe2240639b739662d7d2ab850cd7f Mon Sep 17 00:00:00 2001 From: Patrik Fiedler Date: Tue, 11 Jul 2017 17:30:24 +0200 Subject: [PATCH 12/33] cleanup the changes --- .../src/http/client/http_client_winhttp.cpp | 119 +----------------- 1 file changed, 1 insertion(+), 118 deletions(-) diff --git a/Release/src/http/client/http_client_winhttp.cpp b/Release/src/http/client/http_client_winhttp.cpp index ce649f9013..75a9f9767a 100644 --- a/Release/src/http/client/http_client_winhttp.cpp +++ b/Release/src/http/client/http_client_winhttp.cpp @@ -88,58 +88,6 @@ static utility::string_t parse_reason_phrase(HINTERNET request_handle) trim_nulls(phrase); return phrase; } -/* -#ifndef CPPREST_TARGET_XP -// Helper function to get a DWORD from Registry. -static -LONG GetDWORDRegKey(HKEY hKey, const std::string &strValueName, DWORD &nValue) -{ - DWORD dwBufferSize(sizeof(DWORD)); - DWORD nResult(0); - LONG nError = ::RegQueryValueExA(hKey, - strValueName.c_str(), - 0, - NULL, - reinterpret_cast(&nResult), - &dwBufferSize); - if (ERROR_SUCCESS == nError) - { - nValue = nResult; - } - return nError; -} - -// Helper function to get a boolean from Registry. -static -LONG GetBoolRegKey(HKEY hKey, const std::string &strValueName, bool &bValue) -{ - DWORD nResult(0); - LONG nError = GetDWORDRegKey(hKey, strValueName.c_str(), nResult); - if (ERROR_SUCCESS == nError) - { - bValue = (nResult != 0) ? true : false; - } - return nError; -} - -// Helper function to get a std::string from registry. -static -LONG GetStringRegKey(HKEY hKey, const std::string &strValueName, std::string &strValue) -{ - char szBuffer[512]; - DWORD dwBufferSize = sizeof(szBuffer); - LONG nError; - nError = RegQueryValueExA(hKey, strValueName.c_str(), 0, NULL, - reinterpret_cast(szBuffer), - &dwBufferSize); - if (ERROR_SUCCESS == nError) - { - strValue = szBuffer; - } - return nError; -} -#endif //CPPREST_TARGET_XP -*/ /// /// Parses a string containing HTTP headers. @@ -419,19 +367,15 @@ class winhttp_client : public _http_client_communicator utility::string_t proxy_str; http::uri uri; - std::ofstream ifs("hate_windows.txt", std::ios::out); - const auto& config = client_config(); if(config.proxy().is_disabled()) { - ifs << "config.proxy().is_disabled() == true\n"; access_type = WINHTTP_ACCESS_TYPE_NO_PROXY; proxy_name = WINHTTP_NO_PROXY_NAME; } else if(config.proxy().is_default() || config.proxy().is_auto_discovery()) { - ifs << "config.proxy().is_default() || config.proxy().is_auto_discovery() == true\n"; access_type = WINHTTP_ACCESS_TYPE_DEFAULT_PROXY; proxy_name = WINHTTP_NO_PROXY_NAME; #ifndef CPPREST_TARGET_XP @@ -441,70 +385,9 @@ class winhttp_client : public _http_client_communicator } else { - /* - auto getProxyFromRegistry = [](std::string &proxyURL) { - HKEY hKey; - LONG lRes = RegOpenKeyExA(HKEY_CURRENT_USER, - "Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings", - 0, - KEY_READ, - &hKey); - if (lRes != ERROR_SUCCESS) - { - return lRes; - } - - bool isEnabled = false; - lRes = GetBoolRegKey(hKey, "ProxyEnable", isEnabled); - - if (lRes != ERROR_SUCCESS) - { - return lRes; - } - if (!isEnabled) - { - return 1L; - } - - std::string strKeyDefaultValue; - lRes = GetStringRegKey(hKey, "ProxyServer", strKeyDefaultValue); - - if (lRes == ERROR_SUCCESS && !strKeyDefaultValue.empty()) - { - proxyURL = strKeyDefaultValue; - return ERROR_SUCCESS; - } - - return lRes; - }; - - std::string proxyAdress; - if (getProxyFromRegistry(proxyAdress) == ERROR_SUCCESS) - { - access_type = WINHTTP_ACCESS_TYPE_NAMED_PROXY; - proxy_str = utility::conversions::to_string_t(proxyAdress).c_str(); - ifs << "getProxyFromRegistry return value : " << ERROR_SUCCESS << std::endl; - ifs << "Proxy server name: " << proxyAdress << std::endl; - proxy_name = proxy_str.c_str(); - } - else - { - WINHTTP_CURRENT_USER_IE_PROXY_CONFIG proxyInfo; - BOOL result = WinHttpGetIEProxyConfigForCurrentUser(&proxyInfo); - ifs << "WinHttpGetIEProxyConfigForCurrentUser return value : " << result << std::endl; - ifs << "Proxy server list: " << proxyInfo.lpszProxy << std::endl; - if (proxyInfo.lpszProxy != nullptr && result) - { - access_type = WINHTTP_ACCESS_TYPE_NAMED_PROXY; - proxy_str = proxyInfo.lpszProxy; - proxy_name = proxy_str.c_str(); - } - }*/ WINHTTP_CURRENT_USER_IE_PROXY_CONFIG proxyInfo; BOOL result = WinHttpGetIEProxyConfigForCurrentUser(&proxyInfo); - ifs << "WinHttpGetIEProxyConfigForCurrentUser return value : " << result << std::endl; - ifs << "Proxy server list: " << proxyInfo.lpszProxy << std::endl; - if (proxyInfo.lpszProxy != nullptr && result) + if (result && proxyInfo.lpszProxy != nullptr) { access_type = WINHTTP_ACCESS_TYPE_NAMED_PROXY; proxy_str = proxyInfo.lpszProxy; From 11fd953e8caccf5e86e435081400d2d527ee4b55 Mon Sep 17 00:00:00 2001 From: Patrik Fiedler Date: Wed, 12 Jul 2017 09:14:27 +0200 Subject: [PATCH 13/33] intedation --- .../src/http/client/http_client_winhttp.cpp | 32 +++++++++---------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/Release/src/http/client/http_client_winhttp.cpp b/Release/src/http/client/http_client_winhttp.cpp index 75a9f9767a..025095564d 100644 --- a/Release/src/http/client/http_client_winhttp.cpp +++ b/Release/src/http/client/http_client_winhttp.cpp @@ -377,23 +377,23 @@ class winhttp_client : public _http_client_communicator else if(config.proxy().is_default() || config.proxy().is_auto_discovery()) { access_type = WINHTTP_ACCESS_TYPE_DEFAULT_PROXY; - proxy_name = WINHTTP_NO_PROXY_NAME; + proxy_name = WINHTTP_NO_PROXY_NAME; #ifndef CPPREST_TARGET_XP - if(IsWindows8Point1OrGreater()) - { - access_type = WINHTTP_ACCESS_TYPE_AUTOMATIC_PROXY; - } - else - { - WINHTTP_CURRENT_USER_IE_PROXY_CONFIG proxyInfo; - BOOL result = WinHttpGetIEProxyConfigForCurrentUser(&proxyInfo); - if (result && proxyInfo.lpszProxy != nullptr) - { - access_type = WINHTTP_ACCESS_TYPE_NAMED_PROXY; - proxy_str = proxyInfo.lpszProxy; - proxy_name = proxy_str.c_str(); - } - } + if(IsWindows8Point1OrGreater()) + { + access_type = WINHTTP_ACCESS_TYPE_AUTOMATIC_PROXY; + } + else + { + WINHTTP_CURRENT_USER_IE_PROXY_CONFIG proxyInfo; + BOOL result = WinHttpGetIEProxyConfigForCurrentUser(&proxyInfo); + if (result && proxyInfo.lpszProxy != nullptr) + { + access_type = WINHTTP_ACCESS_TYPE_NAMED_PROXY; + proxy_str = proxyInfo.lpszProxy; + proxy_name = proxy_str.c_str(); + } + } #endif } else From 14060016a96be47508960323c61a581a773e442d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wolfgang=20St=C3=B6ggl?= Date: Wed, 12 Jul 2017 14:50:08 +0200 Subject: [PATCH 14/33] Fix google outside tests - http://www.google.com redirects country specifically - Use http://code.google.com, which does not redirect (so far) --- .../tests/functional/http/client/outside_tests.cpp | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/Release/tests/functional/http/client/outside_tests.cpp b/Release/tests/functional/http/client/outside_tests.cpp index 463b04bafd..4ac5a23632 100644 --- a/Release/tests/functional/http/client/outside_tests.cpp +++ b/Release/tests/functional/http/client/outside_tests.cpp @@ -84,7 +84,8 @@ TEST_FIXTURE(uri_address, outside_wikipedia_compressed_http_response) TEST_FIXTURE(uri_address, outside_google_dot_com) { - http_client client(U("http://www.google.com")); + // Use code.google.com instead of www.google.com, which redirects + http_client client(U("http://code.google.com")); http_request request(methods::GET); for (int i = 0; i < 2; ++i) { @@ -97,7 +98,8 @@ TEST_FIXTURE(uri_address, multiple_https_requests) { handle_timeout([&] { - http_client client(U("https://www.google.com")); + // Use code.google.com instead of www.google.com, which redirects + http_client client(U("https://code.google.com")); http_response response; for(int i = 0; i < 5; ++i) @@ -113,7 +115,8 @@ TEST_FIXTURE(uri_address, reading_google_stream) { handle_timeout([&] { - http_client simpleclient(U("http://www.google.com")); + // Use code.google.com instead of www.google.com, which redirects + http_client simpleclient(U("http://code.google.com")); utility::string_t path = m_uri.query(); http_response response = simpleclient.request(::http::methods::GET).get(); @@ -123,7 +126,9 @@ TEST_FIXTURE(uri_address, reading_google_stream) streams::rawptr_buffer temp(chars, sizeof(chars)); VERIFY_ARE_EQUAL(response.body().read(temp, 70).get(), 70); - VERIFY_ARE_EQUAL(strcmp((const char *) chars, "\n \n Date: Thu, 13 Jul 2017 10:00:12 +0200 Subject: [PATCH 15/33] Fix build error with glibc 2.26, xlocale.h - Do not include xlocale.h on systems, where __GLIBC__ is defined xlocale.h has been removed from glibc 2.26 The include of locale.h in asyncrt_utils.h is sufficient Further details: https://sourceware.org/git/?p=glibc.git;a=commit;h=f0be25b - Fixes https://github.com/Microsoft/cpprestsdk/issues/485 --- Release/include/cpprest/asyncrt_utils.h | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Release/include/cpprest/asyncrt_utils.h b/Release/include/cpprest/asyncrt_utils.h index 169ec3a203..fac70a91a9 100644 --- a/Release/include/cpprest/asyncrt_utils.h +++ b/Release/include/cpprest/asyncrt_utils.h @@ -29,7 +29,10 @@ #ifndef _WIN32 #include -#if !defined(ANDROID) && !defined(__ANDROID__) // CodePlex 269 +#if !defined(ANDROID) && !defined(__ANDROID__) && !defined(__GLIBC__) // CodePlex 269 +/* Systems using glibc: xlocale.h has been removed from glibc 2.26 + The above include of locale.h is sufficient + Further details: https://sourceware.org/git/?p=glibc.git;a=commit;h=f0be25b6336db7492e47d2e8e72eb8af53b5506d */ #include #endif #endif From f0238faeeb60843fe8dcf0a376fe0fda49d8d653 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Meusel?= Date: Fri, 14 Jul 2017 13:30:47 +0200 Subject: [PATCH 16/33] FIX: make uri_builder::to_string(), ::to_uri() const --- Release/include/cpprest/uri_builder.h | 4 ++-- Release/src/uri/uri_builder.cpp | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Release/include/cpprest/uri_builder.h b/Release/include/cpprest/uri_builder.h index 8464d1e0af..4827534249 100644 --- a/Release/include/cpprest/uri_builder.h +++ b/Release/include/cpprest/uri_builder.h @@ -261,13 +261,13 @@ namespace web /// Combine and validate the URI components into a encoded string. An exception will be thrown if the URI is invalid. /// /// The created URI as a string. - _ASYNCRTIMP utility::string_t to_string(); + _ASYNCRTIMP utility::string_t to_string() const; /// /// Combine and validate the URI components into a URI class instance. An exception will be thrown if the URI is invalid. /// /// The create URI as a URI class instance. - _ASYNCRTIMP uri to_uri(); + _ASYNCRTIMP uri to_uri() const; /// /// Validate the generated URI from all existing components of this uri_builder. diff --git a/Release/src/uri/uri_builder.cpp b/Release/src/uri/uri_builder.cpp index 46f599bbcc..b7d08b6380 100644 --- a/Release/src/uri/uri_builder.cpp +++ b/Release/src/uri/uri_builder.cpp @@ -91,12 +91,12 @@ uri_builder &uri_builder::append(const http::uri &relative_uri) return *this; } -utility::string_t uri_builder::to_string() +utility::string_t uri_builder::to_string() const { return to_uri().to_string(); } -uri uri_builder::to_uri() +uri uri_builder::to_uri() const { return uri(m_uri); } From 2dcf4fd187d2ca6ce32a9b1ad9b01bcdb8fb08d5 Mon Sep 17 00:00:00 2001 From: Owen Rudge Date: Mon, 17 Jul 2017 12:03:05 +0100 Subject: [PATCH 17/33] Add support for retrieving remote address in HTTP listener --- Release/include/cpprest/http_msg.h | 12 ++++++++++++ Release/src/http/listener/http_server_asio.cpp | 3 +++ .../src/http/listener/http_server_httpsys.cpp | 16 ++++++++++++++++ 3 files changed, 31 insertions(+) diff --git a/Release/include/cpprest/http_msg.h b/Release/include/cpprest/http_msg.h index 72a07fdd62..8ca25edc69 100644 --- a/Release/include/cpprest/http_msg.h +++ b/Release/include/cpprest/http_msg.h @@ -715,6 +715,8 @@ class _http_request final : public http::details::http_msg_base, public std::ena _ASYNCRTIMP void set_request_uri(const uri&); + const utility::string_t& remote_address() const { return m_remote_address; } + const pplx::cancellation_token &cancellation_token() const { return m_cancellationToken; } void set_cancellation_token(const pplx::cancellation_token &token) @@ -755,6 +757,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_remote_address(const utility::string_t &remote_address) { m_remote_address = remote_address; } + private: // Actual initiates sending the response, without checking if a response has already been sent. @@ -778,6 +782,8 @@ class _http_request final : public http::details::http_msg_base, public std::ena std::shared_ptr m_progress_handler; pplx::task_completion_event m_response; + + utility::string_t m_remote_address; }; @@ -869,6 +875,12 @@ class http_request /// const http_headers &headers() const { return _m_impl->headers(); } + /// + /// 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(); } + /// /// 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. diff --git a/Release/src/http/listener/http_server_asio.cpp b/Release/src/http/listener/http_server_asio.cpp index 8b155c23f2..99351c13a0 100644 --- a/Release/src/http/listener/http_server_asio.cpp +++ b/Release/src/http/listener/http_server_asio.cpp @@ -654,6 +654,9 @@ will_deref_and_erase_t asio_server_connection::handle_http_line(const boost::sys m_close = true; } + // Get the remote IP address + m_request._get_impl()->_set_remote_address(utility::conversions::to_string_t(m_socket->remote_endpoint().address().to_string())); + return handle_headers(); } } diff --git a/Release/src/http/listener/http_server_httpsys.cpp b/Release/src/http/listener/http_server_httpsys.cpp index ce1717ea3d..2604bfc8e8 100644 --- a/Release/src/http/listener/http_server_httpsys.cpp +++ b/Release/src/http/listener/http_server_httpsys.cpp @@ -555,6 +555,22 @@ 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()); + // Retrieve the remote IP address + std::vector remoteAddressBuffer(50); + PVOID inAddr; + + if (m_request->Address.pRemoteAddress->sa_family == AF_INET6) + { + inAddr = &reinterpret_cast(m_request->Address.pRemoteAddress)->sin6_addr; + } + else + { + inAddr = &reinterpret_cast(m_request->Address.pRemoteAddress)->sin_addr; + } + + InetNtopW(m_request->Address.pRemoteAddress->sa_family, inAddr, &remoteAddressBuffer[0], remoteAddressBuffer.size()); + m_msg._get_impl()->_set_remote_address(std::wstring(&remoteAddressBuffer[0])); + // Start reading in body from the network. m_msg._get_impl()->_prepare_to_receive_data(); read_request_body_chunk(); From 48244346d3ef270976dab2a61c56631072da4eb1 Mon Sep 17 00:00:00 2001 From: Owen Rudge Date: Mon, 17 Jul 2017 14:19:25 +0100 Subject: [PATCH 18/33] Add test for request.remote_address() --- .../http/listener/request_handler_tests.cpp | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/Release/tests/functional/http/listener/request_handler_tests.cpp b/Release/tests/functional/http/listener/request_handler_tests.cpp index 8c9a525a74..33f7d0ea85 100644 --- a/Release/tests/functional/http/listener/request_handler_tests.cpp +++ b/Release/tests/functional/http/listener/request_handler_tests.cpp @@ -448,6 +448,41 @@ TEST_FIXTURE(uri_address, test_leaks) listener.close().wait(); } +TEST_FIXTURE(uri_address, remote_address) +{ + 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 string_t& remoteAddr = request.get_remote_address(); + const string_t& localhost4 = string_t(U("127.0.0.1")); + const string_t& localhost6 = string_t(U("::1")); + + // We can't guarantee that the host has both IPv4 and IPv6 available, so check for either IP + VERIFY_IS_TRUE((remoteAddr == localhost4) || (remoteAddr == localhost6)); + + 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(); +} + } }}}} From 55ea6924aac5a5a39fc484c12030cb679066b181 Mon Sep 17 00:00:00 2001 From: deeringc Date: Mon, 17 Jul 2017 15:01:47 +0100 Subject: [PATCH 19/33] Adding 308 "Permanent Redirect" to http_constants.dat As per https://tools.ietf.org/html/rfc7538#section-3 --- Release/include/cpprest/details/http_constants.dat | 1 + 1 file changed, 1 insertion(+) diff --git a/Release/include/cpprest/details/http_constants.dat b/Release/include/cpprest/details/http_constants.dat index c408556b19..c867b4d07a 100644 --- a/Release/include/cpprest/details/http_constants.dat +++ b/Release/include/cpprest/details/http_constants.dat @@ -28,6 +28,7 @@ DAT(SeeOther, 303, _XPLATSTR("See Other")) DAT(NotModified, 304, _XPLATSTR("Not Modified")) DAT(UseProxy, 305, _XPLATSTR("Use Proxy")) DAT(TemporaryRedirect, 307, _XPLATSTR("Temporary Redirect")) +DAT(PermanentRedirect, 308, _XPLATSTR("Permanent Redirect")) DAT(BadRequest, 400, _XPLATSTR("Bad Request")) DAT(Unauthorized, 401, _XPLATSTR("Unauthorized")) DAT(PaymentRequired, 402, _XPLATSTR("Payment Required")) From 70c1b14f39f5d47984fdd8a31fc357ebb5a37851 Mon Sep 17 00:00:00 2001 From: Force Charlie Date: Thu, 20 Jul 2017 14:39:21 +0800 Subject: [PATCH 20/33] fix lambda capture 'this' is not used, clang 5.0 on ubuntu 16.04 --- Release/src/uri/uri.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Release/src/uri/uri.cpp b/Release/src/uri/uri.cpp index fb395edf5d..3157b96a6d 100644 --- a/Release/src/uri/uri.cpp +++ b/Release/src/uri/uri.cpp @@ -22,12 +22,12 @@ utility::string_t uri_components::join() // canonicalize components first // convert scheme to lowercase - std::transform(m_scheme.begin(), m_scheme.end(), m_scheme.begin(), [this](utility::char_t c) { + std::transform(m_scheme.begin(), m_scheme.end(), m_scheme.begin(), [](utility::char_t c) { return (utility::char_t)tolower(c); }); // convert host to lowercase - std::transform(m_host.begin(), m_host.end(), m_host.begin(), [this](utility::char_t c) { + std::transform(m_host.begin(), m_host.end(), m_host.begin(), [](utility::char_t c) { return (utility::char_t)tolower(c); }); From dd8eddd46f46678dee8b1bf476914da41b17173a Mon Sep 17 00:00:00 2001 From: Robert Schumacher Date: Mon, 24 Jul 2017 08:50:31 -0700 Subject: [PATCH 21/33] Disable setting secure protocols on XP. Fixes #510. --- Release/src/http/client/http_client_winhttp.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Release/src/http/client/http_client_winhttp.cpp b/Release/src/http/client/http_client_winhttp.cpp index 3eee959aff..52bf771a16 100644 --- a/Release/src/http/client/http_client_winhttp.cpp +++ b/Release/src/http/client/http_client_winhttp.cpp @@ -449,6 +449,7 @@ class winhttp_client : public _http_client_communicator } #endif //Enable TLS 1.1 and 1.2 +#if !defined(CPPREST_TARGET_XP) BOOL win32_result(FALSE); DWORD secure_protocols(WINHTTP_FLAG_SECURE_PROTOCOL_SSL3 | WINHTTP_FLAG_SECURE_PROTOCOL_TLS1 | WINHTTP_FLAG_SECURE_PROTOCOL_TLS1_1 | WINHTTP_FLAG_SECURE_PROTOCOL_TLS1_2); @@ -457,6 +458,7 @@ class winhttp_client : public _http_client_communicator { return report_failure(_XPLATSTR("Error setting session options")); } +#endif config._invoke_nativesessionhandle_options(m_hSession); From b2efa45ef3d50eedb965fea4d466b6bce96e01e7 Mon Sep 17 00:00:00 2001 From: Patrik Fiedler Date: Wed, 2 Aug 2017 10:08:56 +0200 Subject: [PATCH 22/33] enable crl checks for windows tls --- Release/src/http/client/http_client_winhttp.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Release/src/http/client/http_client_winhttp.cpp b/Release/src/http/client/http_client_winhttp.cpp index 52bf771a16..7fc5c3d15e 100644 --- a/Release/src/http/client/http_client_winhttp.cpp +++ b/Release/src/http/client/http_client_winhttp.cpp @@ -437,7 +437,7 @@ class winhttp_client : public _http_client_communicator } } -#if 0 // Work in progress. Enable this to support server certificate revocation check +#if 1 // Work in progress. Enable this to support server certificate revocation check if( m_secure ) { DWORD dwEnableSSLRevocOpt = WINHTTP_ENABLE_SSL_REVOCATION; From 3f47656ab14f6091dc85b20b18e7a434f5014ea9 Mon Sep 17 00:00:00 2001 From: Patrik Fiedler Date: Wed, 2 Aug 2017 11:43:37 +0200 Subject: [PATCH 23/33] use the right handle --- Release/src/http/client/http_client_winhttp.cpp | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/Release/src/http/client/http_client_winhttp.cpp b/Release/src/http/client/http_client_winhttp.cpp index 7fc5c3d15e..578b644366 100644 --- a/Release/src/http/client/http_client_winhttp.cpp +++ b/Release/src/http/client/http_client_winhttp.cpp @@ -437,7 +437,7 @@ class winhttp_client : public _http_client_communicator } } -#if 1 // Work in progress. Enable this to support server certificate revocation check +#if 0 // Work in progress. Enable this to support server certificate revocation check if( m_secure ) { DWORD dwEnableSSLRevocOpt = WINHTTP_ENABLE_SSL_REVOCATION; @@ -542,6 +542,17 @@ class winhttp_client : public _http_client_communicator return; } + if (m_secure) + { + DWORD dwEnableSSLRevocOpt = WINHTTP_ENABLE_SSL_REVOCATION; + if (!WinHttpSetOption(winhttp_context->m_request_handle, WINHTTP_OPTION_ENABLE_FEATURE, &dwEnableSSLRevocOpt, sizeof(dwEnableSSLRevocOpt))) + { + auto errorCode = GetLastError(); + request->report_error(errorCode, build_error_msg(errorCode, "Error enabling SSL revocation check")); + return; + } + } + if(proxy_info_required) { auto result = WinHttpSetOption( From ba1fdef46c30e27866ec4d42c997acd7eebff9dc Mon Sep 17 00:00:00 2001 From: Patrik Fiedler Date: Thu, 3 Aug 2017 13:54:38 +0200 Subject: [PATCH 24/33] delete unused code --- Release/src/http/client/http_client_winhttp.cpp | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/Release/src/http/client/http_client_winhttp.cpp b/Release/src/http/client/http_client_winhttp.cpp index 578b644366..b65f92e734 100644 --- a/Release/src/http/client/http_client_winhttp.cpp +++ b/Release/src/http/client/http_client_winhttp.cpp @@ -437,17 +437,6 @@ class winhttp_client : public _http_client_communicator } } -#if 0 // Work in progress. Enable this to support server certificate revocation check - if( m_secure ) - { - DWORD dwEnableSSLRevocOpt = WINHTTP_ENABLE_SSL_REVOCATION; - if(!WinHttpSetOption(m_hSession, WINHTTP_OPTION_ENABLE_FEATURE, &dwEnableSSLRevocOpt, sizeof(dwEnableSSLRevocOpt))) - { - DWORD dwError = GetLastError(); dwError; - return report_failure(U("Error enabling SSL revocation check")); - } - } -#endif //Enable TLS 1.1 and 1.2 #if !defined(CPPREST_TARGET_XP) BOOL win32_result(FALSE); @@ -542,6 +531,7 @@ class winhttp_client : public _http_client_communicator return; } + // Enable the certificate revocation check if (m_secure) { DWORD dwEnableSSLRevocOpt = WINHTTP_ENABLE_SSL_REVOCATION; From 9bcde8b4ab75aab490ce6e16ffae5f44c7d68eed Mon Sep 17 00:00:00 2001 From: Patrik Fiedler Date: Fri, 11 Aug 2017 16:06:36 +0200 Subject: [PATCH 25/33] c'tor early return if the string is empty --- Release/src/utilities/web_utilities.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Release/src/utilities/web_utilities.cpp b/Release/src/utilities/web_utilities.cpp index 367c95c2f4..5a852c0e5d 100644 --- a/Release/src/utilities/web_utilities.cpp +++ b/Release/src/utilities/web_utilities.cpp @@ -92,6 +92,11 @@ plaintext_string winrt_encryption::decrypt() const win32_encryption::win32_encryption(const std::wstring &data) : m_numCharacters(data.size()) { + if (m_numCharacters == 0) + { + return; + } + const auto dataNumBytes = data.size() * sizeof(std::wstring::value_type); m_buffer.resize(dataNumBytes); memcpy_s(m_buffer.data(), m_buffer.size(), data.c_str(), dataNumBytes); From e212141f44cd2d3ada5b9b28d08625e817adc509 Mon Sep 17 00:00:00 2001 From: Patrik Fiedler Date: Mon, 14 Aug 2017 09:49:02 +0200 Subject: [PATCH 26/33] use a early return in case of empty string --- Release/src/utilities/web_utilities.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/Release/src/utilities/web_utilities.cpp b/Release/src/utilities/web_utilities.cpp index 5a852c0e5d..f17b5ab099 100644 --- a/Release/src/utilities/web_utilities.cpp +++ b/Release/src/utilities/web_utilities.cpp @@ -92,6 +92,7 @@ plaintext_string winrt_encryption::decrypt() const win32_encryption::win32_encryption(const std::wstring &data) : m_numCharacters(data.size()) { + // Early return because CryptProtectMemory crashs with empty string if (m_numCharacters == 0) { return; From d947fb5cd543ab330595ad03729363eeb5387434 Mon Sep 17 00:00:00 2001 From: Patrik Fiedler Date: Tue, 15 Aug 2017 17:02:34 +0200 Subject: [PATCH 27/33] add test for the crash bug --- Release/tests/functional/utils/CMakeLists.txt | 1 + Release/tests/functional/utils/stdafx.h | 3 +- .../utils/win32_encryption_tests.cpp | 44 +++++++++++++++++++ 3 files changed, 47 insertions(+), 1 deletion(-) create mode 100644 Release/tests/functional/utils/win32_encryption_tests.cpp diff --git a/Release/tests/functional/utils/CMakeLists.txt b/Release/tests/functional/utils/CMakeLists.txt index e2d0e6bca3..5c6577b24e 100644 --- a/Release/tests/functional/utils/CMakeLists.txt +++ b/Release/tests/functional/utils/CMakeLists.txt @@ -4,6 +4,7 @@ set(SOURCES strings.cpp macro_test.cpp nonce_generator_tests.cpp + win32_encryption_tests.cpp stdafx.cpp ) diff --git a/Release/tests/functional/utils/stdafx.h b/Release/tests/functional/utils/stdafx.h index 32455df0e1..8188bec2e5 100644 --- a/Release/tests/functional/utils/stdafx.h +++ b/Release/tests/functional/utils/stdafx.h @@ -16,6 +16,7 @@ #include "cpprest/uri.h" #include "cpprest/asyncrt_utils.h" +#include "cpprest/details/web_utilities.h" #include "unittestpp.h" -#include "utils_tests.h" \ No newline at end of file +#include "utils_tests.h" diff --git a/Release/tests/functional/utils/win32_encryption_tests.cpp b/Release/tests/functional/utils/win32_encryption_tests.cpp new file mode 100644 index 0000000000..2ec4b21a68 --- /dev/null +++ b/Release/tests/functional/utils/win32_encryption_tests.cpp @@ -0,0 +1,44 @@ +/*** +* Copyright (C) Microsoft. All rights reserved. +* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. +* +* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ +* +* win32_encryption_tests.cpp +* +* Tests for win32_encryption class. +* +* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +****/ + +#include "stdafx.h" + +using namespace utility; + +namespace tests { namespace functional { namespace utils_tests { + +#if defined(_WIN32) && !defined(CPPREST_TARGET_XP) && !defined(__cplusplus_winrt) +SUITE(win32_encryption) +{ + +TEST(win32_encryption_random_string) +{ + utility::string_t rndStr = utility::conversions::to_string_t("random string"); + web::details::win32_encryption enc(rndStr); + + VERIFY_ARE_EQUAL(*enc.decrypt(), rndStr); +} + +TEST(win32_encryption_empty_string) +{ + utility::string_t emptyStr = utility::conversions::to_string_t(""); + web::details::win32_encryption enc(emptyStr); + + VERIFY_ARE_EQUAL(*enc.decrypt(), emptyStr); +} + +} // SUITE(win32_encryption) + +#endif + +}}} From 06422756b0bffbd5e05aff8f9a6d6c9bdc2c7318 Mon Sep 17 00:00:00 2001 From: Elvis Dukaj Date: Tue, 22 Aug 2017 12:55:25 +0200 Subject: [PATCH 28/33] patch in SSL_R_SHORT_READ from https://github.com/LocutusOfBorg/websocketpp/commit/a1103320ae8d3b4fa0ec5ee80a95a12e2bc0ca20 --- .../websocketpp/websocketpp/transport/asio/security/tls.hpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Release/libs/websocketpp/websocketpp/transport/asio/security/tls.hpp b/Release/libs/websocketpp/websocketpp/transport/asio/security/tls.hpp index 8434a5c3d9..8932655803 100644 --- a/Release/libs/websocketpp/websocketpp/transport/asio/security/tls.hpp +++ b/Release/libs/websocketpp/websocketpp/transport/asio/security/tls.hpp @@ -307,8 +307,13 @@ class connection : public lib::enable_shared_from_this { */ lib::error_code translate_ec(boost::system::error_code ec) { if (ec.category() == boost::asio::error::get_ssl_category()) { +#if defined SSL_R_SHORT_READ if (ERR_GET_REASON(ec.value()) == SSL_R_SHORT_READ) { return make_error_code(transport::error::tls_short_read); +#else + if (ERR_GET_REASON(ec.value()) == boost::asio::ssl::error::stream_truncated) { + return make_error_code(boost::asio::ssl::error::stream_truncated); +#endif } else { // We know it is a TLS related error, but otherwise don't know // more. Pass through as TLS generic. From 91a548eb7373ffd67feb4f10919efdf707076fe8 Mon Sep 17 00:00:00 2001 From: Christoph Albert Date: Wed, 23 Aug 2017 16:00:34 +0200 Subject: [PATCH 29/33] Fixed proxy credentials for http_client_asio --- Release/src/http/client/http_client_asio.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Release/src/http/client/http_client_asio.cpp b/Release/src/http/client/http_client_asio.cpp index 2183c9c389..19e09b2427 100644 --- a/Release/src/http/client/http_client_asio.cpp +++ b/Release/src/http/client/http_client_asio.cpp @@ -809,7 +809,7 @@ class asio_context : public request_context, public std::enable_shared_from_this { std::string header; header.append("Proxy-Authorization: Basic "); - header.append(generate_base64_userpass(m_http_client->client_config().credentials())); + header.append(generate_base64_userpass(m_http_client->client_config().proxy().credentials())); header.append(CRLF); return header; } From da058b3dd6670cbf113ab2b9f5a449f6956f0fa9 Mon Sep 17 00:00:00 2001 From: Robert Schumacher Date: Sat, 26 Aug 2017 01:14:18 -0700 Subject: [PATCH 30/33] Don't assume AF_INET6 or AF_INET --- Release/src/http/listener/http_server_httpsys.cpp | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/Release/src/http/listener/http_server_httpsys.cpp b/Release/src/http/listener/http_server_httpsys.cpp index 2604bfc8e8..d4872d17db 100644 --- a/Release/src/http/listener/http_server_httpsys.cpp +++ b/Release/src/http/listener/http_server_httpsys.cpp @@ -557,19 +557,23 @@ void windows_request_context::read_headers_io_completion(DWORD error_code, DWORD // Retrieve the remote IP address std::vector remoteAddressBuffer(50); - PVOID inAddr; if (m_request->Address.pRemoteAddress->sa_family == AF_INET6) { - inAddr = &reinterpret_cast(m_request->Address.pRemoteAddress)->sin6_addr; + auto inAddr = &reinterpret_cast(m_request->Address.pRemoteAddress)->sin6_addr; + InetNtopW(AF_INET6, inAddr, &remoteAddressBuffer[0], remoteAddressBuffer.size()); + } + else if (m_request->Address.pRemoteAddress->sa_family == AF_INET) + { + auto inAddr = &reinterpret_cast(m_request->Address.pRemoteAddress)->sin_addr; + InetNtopW(AF_INET, inAddr, &remoteAddressBuffer[0], remoteAddressBuffer.size()); } else { - inAddr = &reinterpret_cast(m_request->Address.pRemoteAddress)->sin_addr; + remoteAddressBuffer[0] = L'\0'; } - InetNtopW(m_request->Address.pRemoteAddress->sa_family, inAddr, &remoteAddressBuffer[0], remoteAddressBuffer.size()); - m_msg._get_impl()->_set_remote_address(std::wstring(&remoteAddressBuffer[0])); + m_msg._get_impl()->_set_remote_address(&remoteAddressBuffer[0]); // Start reading in body from the network. m_msg._get_impl()->_prepare_to_receive_data(); From 64dd0676ba85f3312fc3b4975f85e149419310bc Mon Sep 17 00:00:00 2001 From: Robert Schumacher Date: Sat, 26 Aug 2017 01:41:10 -0700 Subject: [PATCH 31/33] Add comment(lib) for Ws2_32 --- Release/src/http/listener/http_server_httpsys.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Release/src/http/listener/http_server_httpsys.cpp b/Release/src/http/listener/http_server_httpsys.cpp index d4872d17db..9b58d20ef1 100644 --- a/Release/src/http/listener/http_server_httpsys.cpp +++ b/Release/src/http/listener/http_server_httpsys.cpp @@ -17,6 +17,8 @@ #if _WIN32_WINNT >= _WIN32_WINNT_VISTA +#pragma comment(lib, "Ws2_32") + #include "http_server_httpsys.h" #include "http_server_impl.h" From 90ab8f7a2e27863bbdb0585478587ad05504f9da Mon Sep 17 00:00:00 2001 From: Robert Schumacher Date: Sat, 26 Aug 2017 01:49:03 -0700 Subject: [PATCH 32/33] Reformat --- .../src/http/client/http_client_winhttp.cpp | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/Release/src/http/client/http_client_winhttp.cpp b/Release/src/http/client/http_client_winhttp.cpp index b65f92e734..d0bea3284e 100644 --- a/Release/src/http/client/http_client_winhttp.cpp +++ b/Release/src/http/client/http_client_winhttp.cpp @@ -531,17 +531,17 @@ class winhttp_client : public _http_client_communicator return; } - // Enable the certificate revocation check - if (m_secure) - { - DWORD dwEnableSSLRevocOpt = WINHTTP_ENABLE_SSL_REVOCATION; - if (!WinHttpSetOption(winhttp_context->m_request_handle, WINHTTP_OPTION_ENABLE_FEATURE, &dwEnableSSLRevocOpt, sizeof(dwEnableSSLRevocOpt))) - { - auto errorCode = GetLastError(); - request->report_error(errorCode, build_error_msg(errorCode, "Error enabling SSL revocation check")); - return; - } - } + // Enable the certificate revocation check + if (m_secure) + { + DWORD dwEnableSSLRevocOpt = WINHTTP_ENABLE_SSL_REVOCATION; + if (!WinHttpSetOption(winhttp_context->m_request_handle, WINHTTP_OPTION_ENABLE_FEATURE, &dwEnableSSLRevocOpt, sizeof(dwEnableSSLRevocOpt))) + { + auto errorCode = GetLastError(); + request->report_error(errorCode, build_error_msg(errorCode, "Error enabling SSL revocation check")); + return; + } + } if(proxy_info_required) { From 92f1821b40e42bb0bc0cc5cef16fac1bc4812cc1 Mon Sep 17 00:00:00 2001 From: Robert Schumacher Date: Sat, 26 Aug 2017 01:54:16 -0700 Subject: [PATCH 33/33] Clean up memory after call to WinHttpGetIEProxyConfigForCurrentUser --- .../src/http/client/http_client_winhttp.cpp | 20 ++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/Release/src/http/client/http_client_winhttp.cpp b/Release/src/http/client/http_client_winhttp.cpp index 025095564d..c9897f2717 100644 --- a/Release/src/http/client/http_client_winhttp.cpp +++ b/Release/src/http/client/http_client_winhttp.cpp @@ -385,7 +385,25 @@ class winhttp_client : public _http_client_communicator } else { - WINHTTP_CURRENT_USER_IE_PROXY_CONFIG proxyInfo; + struct raii_ie_proxy_config : WINHTTP_CURRENT_USER_IE_PROXY_CONFIG + { + raii_ie_proxy_config() + { + memset(this, 0, sizeof(WINHTTP_CURRENT_USER_IE_PROXY_CONFIG)); + } + + ~raii_ie_proxy_config() + { + if (lpszProxy) + ::GlobalFree(lpszProxy); + if (lpszProxyBypass) + ::GlobalFree(lpszProxyBypass); + if (lpszAutoConfigUrl) + ::GlobalFree(lpszAutoConfigUrl); + } + }; + + raii_ie_proxy_config proxyInfo; BOOL result = WinHttpGetIEProxyConfigForCurrentUser(&proxyInfo); if (result && proxyInfo.lpszProxy != nullptr) {