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
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/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
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"))
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/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:
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/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)
-
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.
diff --git a/Release/src/http/client/http_client_asio.cpp b/Release/src/http/client/http_client_asio.cpp
index 6a6786dcf5..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;
}
@@ -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();
diff --git a/Release/src/http/client/http_client_winhttp.cpp b/Release/src/http/client/http_client_winhttp.cpp
index 3eee959aff..333cb39545 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
@@ -297,6 +301,42 @@ 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);
+ }
+};
+
+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
{
@@ -358,9 +398,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;
- utility::string_t proxy_str;
+ LPCWSTR proxy_bypass = WINHTTP_NO_PROXY_BYPASS;
http::uri uri;
const auto& config = client_config();
@@ -372,8 +416,54 @@ class winhttp_client : public _http_client_communicator
}
else if(config.proxy().is_default() || config.proxy().is_auto_discovery())
{
+ // Use the default WinHTTP proxy by default.
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;
+ }
+
+ // 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;
+ }
+ }
+ }
+ }
+#endif
+
+ if (config.proxy().is_auto_discovery())
+ {
+ m_proxy_auto_config = true;
+ }
}
else
{
@@ -388,6 +478,7 @@ class winhttp_client : public _http_client_communicator
}
else
{
+ utility::string_t proxy_str;
if (uri.port() > 0)
{
utility::ostringstream_t ss;
@@ -408,7 +499,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)
{
@@ -437,18 +528,8 @@ 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);
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 +538,7 @@ class winhttp_client : public _http_client_communicator
{
return report_failure(_XPLATSTR("Error setting session options"));
}
+#endif
config._invoke_nativesessionhandle_options(m_hSession);
@@ -492,17 +574,25 @@ 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() )
+ if(m_proxy_auto_config)
{
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;
+ 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(
@@ -540,6 +630,18 @@ 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;
+ }
+ }
+
if(proxy_info_required)
{
auto result = WinHttpSetOption(
@@ -1353,6 +1455,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)
diff --git a/Release/src/http/listener/http_server_asio.cpp b/Release/src/http/listener/http_server_asio.cpp
index ee026cede1..99351c13a0 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));
@@ -650,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();
}
}
@@ -1320,4 +1327,4 @@ std::unique_ptr make_http_asio_server()
return make_unique();
}
-}}}}
\ No newline at end of file
+}}}}
diff --git a/Release/src/http/listener/http_server_httpsys.cpp b/Release/src/http/listener/http_server_httpsys.cpp
index ce1717ea3d..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"
@@ -555,6 +557,26 @@ 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);
+
+ if (m_request->Address.pRemoteAddress->sa_family == AF_INET6)
+ {
+ 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
+ {
+ remoteAddressBuffer[0] = L'\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();
read_request_body_chunk();
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);
});
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);
}
diff --git a/Release/src/utilities/web_utilities.cpp b/Release/src/utilities/web_utilities.cpp
index 367c95c2f4..f17b5ab099 100644
--- a/Release/src/utilities/web_utilities.cpp
+++ b/Release/src/utilities/web_utilities.cpp
@@ -92,6 +92,12 @@ 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;
+ }
+
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);
diff --git a/Release/tests/functional/http/client/outside_tests.cpp b/Release/tests/functional/http/client/outside_tests.cpp
index b1da9c23e7..4ac5a23632 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();
@@ -83,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)
{
@@ -96,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)
@@ -112,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();
@@ -122,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 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();
+}
+
}
}}}}
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
+
+}}}