Remove 'include windows.h' from inc/* (#5691)
* Remove 'include windows.h' from inc/* * Clang format * Qualify namespace * Clean up includes a bit further * Fix errors * Clang format * move out _detail definitions --------- Co-authored-by: Anton Kolesnyk <antkmsft@users.noreply.github.com>
This commit is contained in:
parent
c5d0549cb5
commit
ef9d2a5e18
@ -8,11 +8,13 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "azure/core/context.hpp"
|
||||
#include "azure/core/http/http.hpp"
|
||||
#include "azure/core/http/policies/policy.hpp"
|
||||
#include "azure/core/http/transport.hpp"
|
||||
#include "azure/core/platform.hpp"
|
||||
#include "azure/core/nullable.hpp"
|
||||
|
||||
#include <chrono>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
namespace Azure { namespace Core { namespace Http {
|
||||
class CurlNetworkConnection;
|
||||
|
||||
@ -10,6 +10,9 @@
|
||||
|
||||
#include "azure/core/context.hpp"
|
||||
#include "azure/core/http/http.hpp"
|
||||
#include "azure/core/http/raw_response.hpp"
|
||||
|
||||
#include <memory>
|
||||
|
||||
namespace Azure { namespace Core { namespace Http {
|
||||
|
||||
|
||||
@ -13,183 +13,141 @@
|
||||
#include "azure/core/http/policies/policy.hpp"
|
||||
#include "azure/core/http/transport.hpp"
|
||||
#include "azure/core/internal/unique_handle.hpp"
|
||||
#include "azure/core/platform.hpp"
|
||||
|
||||
#if defined(AZ_PLATFORM_WINDOWS)
|
||||
#if !defined(WIN32_LEAN_AND_MEAN)
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#endif
|
||||
#if !defined(NOMINMAX)
|
||||
#define NOMINMAX
|
||||
#endif
|
||||
#include <windows.h>
|
||||
#endif
|
||||
#include "azure/core/nullable.hpp"
|
||||
#include "azure/core/url.hpp"
|
||||
|
||||
#include <memory>
|
||||
#include <type_traits>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <wincrypt.h>
|
||||
#include <winhttp.h>
|
||||
|
||||
namespace Azure { namespace Core {
|
||||
namespace Azure { namespace Core { namespace Http {
|
||||
namespace _detail {
|
||||
class WinHttpRequest;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Sets the WinHTTP session and connection options used to customize the behavior of the
|
||||
* transport.
|
||||
*/
|
||||
struct WinHttpTransportOptions final
|
||||
{
|
||||
/**
|
||||
* @brief Unique handle for WinHTTP HINTERNET handles.
|
||||
* @brief When `true`, allows an invalid certificate authority.
|
||||
*/
|
||||
bool IgnoreUnknownCertificateAuthority{false};
|
||||
|
||||
/**
|
||||
* @brief When `true`, allows an invalid common name in a certificate.
|
||||
*/
|
||||
bool IgnoreInvalidCertificateCommonName{false};
|
||||
|
||||
/**
|
||||
* Proxy information.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief If True, enables the use of the system default proxy.
|
||||
*
|
||||
* @note HINTERNET is declared as a "void *". This means that this definition subsumes all other
|
||||
* `void *` types when used with Azure::Core::_internal::UniqueHandle.
|
||||
* @remarks Set this to "true" if you would like to use a local HTTP proxy like "Fiddler" to
|
||||
* capture and analyze HTTP traffic.
|
||||
*
|
||||
* Set to "false" by default because it is not recommended to use a proxy for production and
|
||||
* Fiddler's proxy interferes with the HTTP functional tests.
|
||||
*/
|
||||
bool EnableSystemDefaultProxy{false};
|
||||
|
||||
/**
|
||||
* @brief If True, enables checks for certificate revocation.
|
||||
*/
|
||||
bool EnableCertificateRevocationListCheck{false};
|
||||
|
||||
/**
|
||||
* @brief Proxy information.
|
||||
*
|
||||
* @remark The Proxy Information string is composed of a set of elements
|
||||
* formatted as follows:
|
||||
*
|
||||
* @code
|
||||
* (\[\<scheme\>=\]\[\<scheme\>"://"\]\<server\>\[":"\<port\>\])
|
||||
* @endcode
|
||||
*
|
||||
* Each element should be separated with semicolons or whitespace.
|
||||
*/
|
||||
std::string ProxyInformation;
|
||||
|
||||
/**
|
||||
* @brief User name for proxy authentication.
|
||||
*/
|
||||
Azure::Nullable<std::string> ProxyUserName;
|
||||
|
||||
/**
|
||||
* @brief Password for proxy authentication.
|
||||
*/
|
||||
Azure::Nullable<std::string> ProxyPassword;
|
||||
|
||||
/**
|
||||
* @brief Array of Base64 encoded DER encoded X.509 certificate. These certificates should
|
||||
* form a chain of certificates which will be used to validate the server certificate sent by
|
||||
* the server.
|
||||
*/
|
||||
std::vector<std::string> ExpectedTlsRootCertificates;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Concrete implementation of an HTTP transport that uses WinHTTP when sending and
|
||||
* receiving requests and responses over the wire.
|
||||
*/
|
||||
class WinHttpTransport : public HttpTransport {
|
||||
private:
|
||||
WinHttpTransportOptions m_options;
|
||||
// m_sessionhandle is const to ensure immutability.
|
||||
const Azure::Core::_internal::UniqueHandle<void*> m_sessionHandle;
|
||||
|
||||
Azure::Core::_internal::UniqueHandle<void*> CreateSessionHandle();
|
||||
Azure::Core::_internal::UniqueHandle<void*> CreateConnectionHandle(
|
||||
Azure::Core::Url const& url,
|
||||
Azure::Core::Context const& context);
|
||||
|
||||
std::unique_ptr<_detail::WinHttpRequest> CreateRequestHandle(
|
||||
Azure::Core::_internal::UniqueHandle<void*> const& connectionHandle,
|
||||
Azure::Core::Url const& url,
|
||||
Azure::Core::Http::HttpMethod const& method);
|
||||
|
||||
// Callback to allow a derived transport to extract the request handle. Used for WebSocket
|
||||
// transports.
|
||||
virtual void OnUpgradedConnection(std::unique_ptr<_detail::WinHttpRequest> const&){};
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief Constructs `%WinHttpTransport`.
|
||||
*
|
||||
* @param options Optional parameter to override the default settings.
|
||||
*/
|
||||
WinHttpTransport(WinHttpTransportOptions const& options = WinHttpTransportOptions());
|
||||
|
||||
/**
|
||||
* @brief Constructs `%WinHttpTransport`.
|
||||
*
|
||||
* @param options Optional parameter to override the default settings.
|
||||
*/
|
||||
/**
|
||||
* @brief Constructs `%WinHttpTransport` object based on common Azure HTTP Transport Options
|
||||
*
|
||||
*/
|
||||
template <> struct UniqueHandleHelper<HINTERNET>
|
||||
{
|
||||
static void FreeHandle(HINTERNET obj) { WinHttpCloseHandle(obj); }
|
||||
|
||||
using type = _internal::BasicUniqueHandle<void, FreeHandle>;
|
||||
};
|
||||
} // namespace _detail
|
||||
|
||||
namespace Http {
|
||||
|
||||
namespace _detail {
|
||||
|
||||
constexpr static size_t DefaultUploadChunkSize = 1024 * 64;
|
||||
constexpr static size_t MaximumUploadChunkSize = 1024 * 1024;
|
||||
|
||||
// Forward declaration for WinHttpRequest.
|
||||
class WinHttpRequest;
|
||||
} // namespace _detail
|
||||
WinHttpTransport(Azure::Core::Http::Policies::TransportOptions const& options);
|
||||
|
||||
/**
|
||||
* @brief Sets the WinHTTP session and connection options used to customize the behavior of the
|
||||
* transport.
|
||||
* @brief Implements the HTTP transport interface to send an HTTP Request and produce an
|
||||
* HTTP RawResponse.
|
||||
*
|
||||
*/
|
||||
struct WinHttpTransportOptions final
|
||||
{
|
||||
/**
|
||||
* @brief When `true`, allows an invalid certificate authority.
|
||||
*/
|
||||
bool IgnoreUnknownCertificateAuthority{false};
|
||||
virtual std::unique_ptr<RawResponse> Send(Request& request, Context const& context) override;
|
||||
|
||||
/**
|
||||
* @brief When `true`, allows an invalid common name in a certificate.
|
||||
*/
|
||||
bool IgnoreInvalidCertificateCommonName{false};
|
||||
// See also:
|
||||
// [Core Guidelines C.35: "A base class destructor should be either public
|
||||
// and virtual or protected and
|
||||
// non-virtual"](http://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#c35-a-base-class-destructor-should-be-either-public-and-virtual-or-protected-and-non-virtual)
|
||||
virtual ~WinHttpTransport();
|
||||
};
|
||||
|
||||
/**
|
||||
* Proxy information.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief If True, enables the use of the system default proxy.
|
||||
*
|
||||
* @remarks Set this to "true" if you would like to use a local HTTP proxy like "Fiddler" to
|
||||
* capture and analyze HTTP traffic.
|
||||
*
|
||||
* Set to "false" by default because it is not recommended to use a proxy for production and
|
||||
* Fiddler's proxy interferes with the HTTP functional tests.
|
||||
*/
|
||||
bool EnableSystemDefaultProxy{false};
|
||||
|
||||
/**
|
||||
* @brief If True, enables checks for certificate revocation.
|
||||
*/
|
||||
bool EnableCertificateRevocationListCheck{false};
|
||||
|
||||
/**
|
||||
* @brief Proxy information.
|
||||
*
|
||||
* @remark The Proxy Information string is composed of a set of elements
|
||||
* formatted as follows:
|
||||
*
|
||||
* @code
|
||||
* (\[\<scheme\>=\]\[\<scheme\>"://"\]\<server\>\[":"\<port\>\])
|
||||
* @endcode
|
||||
*
|
||||
* Each element should be separated with semicolons or whitespace.
|
||||
*/
|
||||
std::string ProxyInformation;
|
||||
|
||||
/**
|
||||
* @brief User name for proxy authentication.
|
||||
*/
|
||||
Azure::Nullable<std::string> ProxyUserName;
|
||||
|
||||
/**
|
||||
* @brief Password for proxy authentication.
|
||||
*/
|
||||
Azure::Nullable<std::string> ProxyPassword;
|
||||
|
||||
/**
|
||||
* @brief Array of Base64 encoded DER encoded X.509 certificate. These certificates should
|
||||
* form a chain of certificates which will be used to validate the server certificate sent by
|
||||
* the server.
|
||||
*/
|
||||
std::vector<std::string> ExpectedTlsRootCertificates;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Concrete implementation of an HTTP transport that uses WinHTTP when sending and
|
||||
* receiving requests and responses over the wire.
|
||||
*/
|
||||
class WinHttpTransport : public HttpTransport {
|
||||
private:
|
||||
WinHttpTransportOptions m_options;
|
||||
// m_sessionhandle is const to ensure immutability.
|
||||
const Azure::Core::_internal::UniqueHandle<HINTERNET> m_sessionHandle;
|
||||
|
||||
Azure::Core::_internal::UniqueHandle<HINTERNET> CreateSessionHandle();
|
||||
Azure::Core::_internal::UniqueHandle<HINTERNET> CreateConnectionHandle(
|
||||
Azure::Core::Url const& url,
|
||||
Azure::Core::Context const& context);
|
||||
std::unique_ptr<_detail::WinHttpRequest> CreateRequestHandle(
|
||||
Azure::Core::_internal::UniqueHandle<HINTERNET> const& connectionHandle,
|
||||
Azure::Core::Url const& url,
|
||||
Azure::Core::Http::HttpMethod const& method);
|
||||
|
||||
// Callback to allow a derived transport to extract the request handle. Used for WebSocket
|
||||
// transports.
|
||||
virtual void OnUpgradedConnection(std::unique_ptr<_detail::WinHttpRequest> const&){};
|
||||
|
||||
/**
|
||||
* @brief Throw an exception based on the Win32 Error code
|
||||
*
|
||||
* @param exceptionMessage Message describing error.
|
||||
* @param error Win32 Error code.
|
||||
*/
|
||||
void GetErrorAndThrow(const std::string& exceptionMessage, DWORD error = GetLastError());
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief Constructs `%WinHttpTransport`.
|
||||
*
|
||||
* @param options Optional parameter to override the default settings.
|
||||
*/
|
||||
WinHttpTransport(WinHttpTransportOptions const& options = WinHttpTransportOptions());
|
||||
|
||||
/**
|
||||
* @brief Constructs `%WinHttpTransport`.
|
||||
*
|
||||
* @param options Optional parameter to override the default settings.
|
||||
*/
|
||||
/**
|
||||
* @brief Constructs `%WinHttpTransport` object based on common Azure HTTP Transport Options
|
||||
*
|
||||
*/
|
||||
WinHttpTransport(Azure::Core::Http::Policies::TransportOptions const& options);
|
||||
|
||||
/**
|
||||
* @brief Implements the HTTP transport interface to send an HTTP Request and produce an
|
||||
* HTTP RawResponse.
|
||||
*
|
||||
*/
|
||||
virtual std::unique_ptr<RawResponse> Send(Request& request, Context const& context) override;
|
||||
|
||||
// See also:
|
||||
// [Core Guidelines C.35: "A base class destructor should be either public
|
||||
// and virtual or protected and
|
||||
// non-virtual"](http://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#c35-a-base-class-destructor-should-be-either-public-and-virtual-or-protected-and-non-virtual)
|
||||
virtual ~WinHttpTransport();
|
||||
};
|
||||
|
||||
} // namespace Http
|
||||
}} // namespace Azure::Core
|
||||
}}} // namespace Azure::Core::Http
|
||||
|
||||
@ -67,4 +67,22 @@ namespace Azure { namespace Core {
|
||||
template <typename T, template <typename> class U = _detail::UniqueHandleHelper>
|
||||
using UniqueHandle = typename U<T>::type;
|
||||
} // namespace _internal
|
||||
|
||||
namespace _detail {
|
||||
void FreeWinHttpHandleImpl(void* obj);
|
||||
|
||||
/**
|
||||
* @brief Unique handle for WinHTTP HINTERNET handles.
|
||||
*
|
||||
* @note HINTERNET is declared as a "void *". This means that this definition subsumes all other
|
||||
* `void *` types when used with Azure::Core::_internal::UniqueHandle.
|
||||
*
|
||||
*/
|
||||
template <> struct UniqueHandleHelper<void*>
|
||||
{
|
||||
static void FreeWinHttpHandle(void* obj) { FreeWinHttpHandleImpl(obj); }
|
||||
|
||||
using type = _internal::BasicUniqueHandle<void, FreeWinHttpHandle>;
|
||||
};
|
||||
} // namespace _detail
|
||||
}} // namespace Azure::Core
|
||||
|
||||
@ -20,7 +20,7 @@
|
||||
#define NOMINMAX
|
||||
#endif
|
||||
|
||||
#include <Windows.h>
|
||||
#include <windows.h>
|
||||
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
@ -30,6 +30,7 @@
|
||||
// 'GetProcAddress'.
|
||||
#include <wil\resource.h>
|
||||
#pragma warning(pop)
|
||||
#include <wincrypt.h>
|
||||
#include <winhttp.h>
|
||||
|
||||
namespace Azure { namespace Core { namespace Http { namespace _detail {
|
||||
@ -169,13 +170,6 @@ namespace Azure { namespace Core { namespace Http { namespace _detail {
|
||||
bool VerifyCertificatesInChain(
|
||||
std::vector<std::string> const& trustedCertificates,
|
||||
PCCERT_CONTEXT serverCertificate) const;
|
||||
/**
|
||||
* @brief Throw an exception based on the Win32 Error code
|
||||
*
|
||||
* @param exceptionMessage Message describing error.
|
||||
* @param error Win32 Error code.
|
||||
*/
|
||||
void GetErrorAndThrow(const std::string& exceptionMessage, DWORD error = GetLastError()) const;
|
||||
|
||||
public:
|
||||
WinHttpRequest(
|
||||
|
||||
@ -26,6 +26,7 @@
|
||||
#include <algorithm>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 6553)
|
||||
#pragma warning(disable : 6387) // An argument in result_macros.h may be '0', for the function
|
||||
@ -45,6 +46,49 @@ using namespace Azure::Core::Diagnostics::_internal;
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr static const size_t DefaultUploadChunkSize = 1024 * 64;
|
||||
constexpr static const size_t MaximumUploadChunkSize = 1024 * 1024;
|
||||
|
||||
std::string GetErrorMessage(DWORD error)
|
||||
{
|
||||
std::string errorMessage = " Error Code: " + std::to_string(error);
|
||||
|
||||
char* errorMsg = nullptr;
|
||||
if (FormatMessageA(
|
||||
FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_ALLOCATE_BUFFER,
|
||||
GetModuleHandleA("winhttp.dll"),
|
||||
error,
|
||||
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
||||
reinterpret_cast<LPSTR>(&errorMsg),
|
||||
0,
|
||||
nullptr)
|
||||
!= 0)
|
||||
{
|
||||
// Use a unique_ptr to manage the lifetime of errorMsg.
|
||||
std::unique_ptr<char, decltype(&LocalFree)> errorString(errorMsg, &LocalFree);
|
||||
errorMsg = nullptr;
|
||||
|
||||
errorMessage += ": ";
|
||||
errorMessage += errorString.get();
|
||||
// If the end of the error message is a CRLF, remove it.
|
||||
if (errorMessage.back() == '\n')
|
||||
{
|
||||
errorMessage.erase(errorMessage.size() - 1);
|
||||
if (errorMessage.back() == '\r')
|
||||
{
|
||||
errorMessage.erase(errorMessage.size() - 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
errorMessage += '.';
|
||||
return errorMessage;
|
||||
}
|
||||
|
||||
void GetErrorAndThrow(const std::string& exceptionMessage, DWORD error = GetLastError())
|
||||
{
|
||||
throw Azure::Core::Http::TransportException(exceptionMessage + GetErrorMessage(error));
|
||||
}
|
||||
|
||||
const std::string HttpScheme = "http";
|
||||
const std::string WebSocketScheme = "ws";
|
||||
|
||||
@ -243,6 +287,18 @@ std::string GetHeadersAsString(Azure::Core::Http::Request const& request)
|
||||
}
|
||||
} // namespace
|
||||
|
||||
void Azure::Core::_detail::FreeWinHttpHandleImpl(void* obj)
|
||||
{
|
||||
// If definitions from windows.h are only being used as private members and not a public API, we
|
||||
// don't want to include windows.h in inc/ headers, so that it does not end up being included in
|
||||
// customer code.
|
||||
// Formally, WinHttpCloseHandle() takes HINTERNET, which is LPVOID, which is void*. That is why we
|
||||
// defined it that way in the header, and here, we are going to static_assert that it is the same
|
||||
// type and safely cast it to HINTERNET.
|
||||
static_assert(std::is_same<HINTERNET, void*>::value, "HINTERNET == void*");
|
||||
WinHttpCloseHandle(static_cast<HINTERNET>(obj));
|
||||
}
|
||||
|
||||
// For each certificate specified in trustedCertificate, add to certificateStore.
|
||||
bool _detail::WinHttpRequest::AddCertificatesToStore(
|
||||
std::vector<std::string> const& trustedCertificates,
|
||||
@ -406,41 +462,6 @@ std::string InternetStatusToString(DWORD internetStatus)
|
||||
return rv;
|
||||
}
|
||||
#undef APPEND_ENUM_STRING
|
||||
|
||||
std::string GetErrorMessage(DWORD error)
|
||||
{
|
||||
std::string errorMessage = " Error Code: " + std::to_string(error);
|
||||
|
||||
char* errorMsg = nullptr;
|
||||
if (FormatMessage(
|
||||
FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_ALLOCATE_BUFFER,
|
||||
GetModuleHandle("winhttp.dll"),
|
||||
error,
|
||||
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
||||
reinterpret_cast<LPSTR>(&errorMsg),
|
||||
0,
|
||||
nullptr)
|
||||
!= 0)
|
||||
{
|
||||
// Use a unique_ptr to manage the lifetime of errorMsg.
|
||||
std::unique_ptr<char, decltype(&LocalFree)> errorString(errorMsg, &LocalFree);
|
||||
errorMsg = nullptr;
|
||||
|
||||
errorMessage += ": ";
|
||||
errorMessage += errorString.get();
|
||||
// If the end of the error message is a CRLF, remove it.
|
||||
if (errorMessage.back() == '\n')
|
||||
{
|
||||
errorMessage.erase(errorMessage.size() - 1);
|
||||
if (errorMessage.back() == '\r')
|
||||
{
|
||||
errorMessage.erase(errorMessage.size() - 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
errorMessage += '.';
|
||||
return errorMessage;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
namespace Azure { namespace Core { namespace Http { namespace _detail {
|
||||
@ -737,22 +758,8 @@ namespace Azure { namespace Core { namespace Http { namespace _detail {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void WinHttpRequest::GetErrorAndThrow(const std::string& exceptionMessage, DWORD error) const
|
||||
{
|
||||
std::string errorMessage = exceptionMessage + GetErrorMessage(error);
|
||||
|
||||
throw Azure::Core::Http::TransportException(errorMessage);
|
||||
}
|
||||
}}}} // namespace Azure::Core::Http::_detail
|
||||
|
||||
void WinHttpTransport::GetErrorAndThrow(const std::string& exceptionMessage, DWORD error)
|
||||
{
|
||||
std::string errorMessage = exceptionMessage + GetErrorMessage(error);
|
||||
|
||||
throw Azure::Core::Http::TransportException(errorMessage);
|
||||
}
|
||||
|
||||
Azure::Core::_internal::UniqueHandle<HINTERNET> WinHttpTransport::CreateSessionHandle()
|
||||
{
|
||||
// Use WinHttpOpen to obtain a session handle.
|
||||
@ -1101,8 +1108,8 @@ void _detail::WinHttpRequest::Upload(
|
||||
int64_t streamLength = streamBody->Length();
|
||||
|
||||
// Consider using `MaximumUploadChunkSize` here, after some perf measurements
|
||||
size_t uploadChunkSize = _detail::DefaultUploadChunkSize;
|
||||
if (streamLength < _detail::MaximumUploadChunkSize)
|
||||
size_t uploadChunkSize = DefaultUploadChunkSize;
|
||||
if (streamLength < MaximumUploadChunkSize)
|
||||
{
|
||||
uploadChunkSize = static_cast<size_t>(streamLength);
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user