Skip to content

Commit 54172bf

Browse files
authored
Changing WinHTTP flags: WINHTTP_FLAG_SECURE_DEFAULTS for HTTPS, WINHTTP_FLAG_ASYNC for HTTP (#907)
* Changing WinHTTP flags: WINHTTP_FLAG_SECURE_DEFAULTS for HTTPS, WINHTTP_FLAG_ASYNC for HTTP * PR feedback * PR feedback * PR feedback
1 parent 377b092 commit 54172bf

4 files changed

Lines changed: 119 additions & 26 deletions

File tree

Samples/GDK-Http/Game.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -454,6 +454,14 @@ void Game::Update(DX::StepTimer const& /*timer*/)
454454
}
455455
break;
456456

457+
case 4:
458+
{
459+
// Test HTTP (non-HTTPS) protocol to verify WinHTTP flag handling
460+
url = "http://neverssl.com/";
461+
PerformHttpCall(url, "", false, "", false, false, false);
462+
}
463+
break;
464+
457465
default:
458466
{
459467
// All HttpCalls complete

Source/HTTP/WinHttp/winhttp_provider.cpp

Lines changed: 58 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
#include "HTTP/httpcall.h"
33
#include "winhttp_provider.h"
44
#include "winhttp_connection.h"
5+
#include "uri.h"
56

67
#if HC_PLATFORM == HC_PLATFORM_GDK
78
#include <XGameRuntimeFeature.h>
@@ -97,7 +98,7 @@ HRESULT WinHttpProvider::PerformAsync(
9798
RETURN_IF_FAILED(getSecurityInfoResult.hr);
9899

99100
// Get HSession for the call
100-
auto getHSessionResult = GetHSession(getSecurityInfoResult.Payload().enabledHttpSecurityProtocolFlags);
101+
auto getHSessionResult = GetHSession(getSecurityInfoResult.Payload().enabledHttpSecurityProtocolFlags, callHandle->url.data());
101102
RETURN_IF_FAILED(getHSessionResult.hr);
102103

103104
std::unique_lock<std::mutex> lock{ m_lock };
@@ -152,7 +153,7 @@ HRESULT WinHttpProvider::ConnectAsync(
152153
RETURN_IF_FAILED(getSecurityInfoResult.hr);
153154

154155
// Get HSession for the call
155-
auto getHSessionResult = GetHSession(getSecurityInfoResult.Payload().enabledHttpSecurityProtocolFlags);
156+
auto getHSessionResult = GetHSession(getSecurityInfoResult.Payload().enabledHttpSecurityProtocolFlags, uri.data());
156157
RETURN_IF_FAILED(getHSessionResult.hr);
157158

158159
std::unique_lock<std::mutex> lock{ m_lock };
@@ -326,8 +327,25 @@ Result<XPlatSecurityInformation> WinHttpProvider::GetSecurityInformation(const c
326327
#endif
327328
}
328329

329-
Result<HINTERNET> WinHttpProvider::GetHSession(uint32_t securityProtocolFlags)
330+
Result<HINTERNET> WinHttpProvider::GetHSession(uint32_t securityProtocolFlags, const char* url)
330331
{
332+
// Parse URL to determine scheme
333+
xbox::httpclient::Uri uri(url);
334+
if (!uri.IsValid())
335+
{
336+
return E_INVALIDARG;
337+
}
338+
339+
bool isHttps = uri.IsSecure();
340+
341+
#if HC_PLATFORM == HC_PLATFORM_GDK
342+
// Log warning for insecure HTTP requests on GDK for console certification reasons
343+
if (!isHttps)
344+
{
345+
HC_TRACE_WARNING(HTTPCLIENT, "WARNING: Insecure HTTP request \"%s\"", url);
346+
}
347+
#endif
348+
331349
std::lock_guard<std::mutex> lock(m_lock);
332350
auto iter = m_hSessions.find(securityProtocolFlags);
333351
if (iter != m_hSessions.end())
@@ -342,31 +360,40 @@ Result<HINTERNET> WinHttpProvider::GetHSession(uint32_t securityProtocolFlags)
342360
m_proxyType = get_ie_proxy_info(proxy_protocol::https, proxyUri);
343361
GetProxyName(m_proxyType, proxyUri, accessType, wProxyName);
344362

363+
// Determine WinHTTP flags based on URL scheme
364+
// Use WINHTTP_FLAG_SECURE_DEFAULTS for HTTPS and WINHTTP_FLAG_ASYNC for HTTP
365+
DWORD openFlags;
366+
if (isHttps)
367+
{
368+
// For HTTPS, use secure defaults which implies WINHTTP_FLAG_ASYNC
369+
openFlags = WINHTTP_FLAG_SECURE_DEFAULTS;
370+
}
371+
else
372+
{
373+
// For HTTP, use async only (allow insecure connections)
374+
openFlags = WINHTTP_FLAG_ASYNC;
375+
}
376+
345377
HINTERNET hSession = WinHttpOpen(
346378
nullptr,
347379
accessType,
348380
wProxyName.length() > 0 ? wProxyName.c_str() : WINHTTP_NO_PROXY_NAME,
349381
WINHTTP_NO_PROXY_BYPASS,
350-
#if HC_PLATFORM == HC_PLATFORM_GDK
351-
WINHTTP_FLAG_SECURE_DEFAULTS
352-
#else
353-
WINHTTP_FLAG_ASYNC
354-
#endif
382+
openFlags
355383
);
356384

357-
#if HC_PLATFORM == HC_PLATFORM_GDK
358385
DWORD error = GetLastError();
359-
if (error == ERROR_INVALID_PARAMETER)
386+
if (error == ERROR_INVALID_PARAMETER && isHttps)
360387
{
361-
// This might happen on older Win10 PC versions that don't support WINHTTP_FLAG_SECURE_DEFAULTS
388+
// WINHTTP_FLAG_SECURE_DEFAULTS exists only on newer Windows versions;
389+
// on earlier OS releases we will receive ERROR_INVALID_PARAMETER and should continue without it.
362390
hSession = WinHttpOpen(
363391
nullptr,
364-
WINHTTP_ACCESS_TYPE_AUTOMATIC_PROXY,
365-
WINHTTP_NO_PROXY_NAME,
392+
accessType,
393+
wProxyName.length() > 0 ? wProxyName.c_str() : WINHTTP_NO_PROXY_NAME,
366394
WINHTTP_NO_PROXY_BYPASS,
367395
WINHTTP_FLAG_ASYNC);
368396
}
369-
#endif
370397

371398
if (hSession == nullptr)
372399
{
@@ -375,28 +402,34 @@ Result<HINTERNET> WinHttpProvider::GetHSession(uint32_t securityProtocolFlags)
375402
return hr;
376403
}
377404

378-
auto result = WinHttpSetOption(
379-
hSession,
380-
WINHTTP_OPTION_SECURE_PROTOCOLS,
381-
&securityProtocolFlags,
382-
sizeof(securityProtocolFlags));
383-
if (!result)
405+
// Only set secure protocols for HTTPS requests
406+
// For HTTP requests, ignore the security protocol settings as they don't apply
407+
if (isHttps)
384408
{
385-
HRESULT hr = HRESULT_FROM_WIN32(GetLastError());
386-
HC_TRACE_ERROR_HR(HTTPCLIENT, hr, "WinHttpProvider WinHttpSetOption");
387-
return hr;
409+
auto result = WinHttpSetOption(
410+
hSession,
411+
WINHTTP_OPTION_SECURE_PROTOCOLS,
412+
&securityProtocolFlags,
413+
sizeof(securityProtocolFlags));
414+
if (!result)
415+
{
416+
HRESULT hr = HRESULT_FROM_WIN32(GetLastError());
417+
HC_TRACE_ERROR_HR(HTTPCLIENT, hr, "WinHttpProvider WinHttpSetOption WINHTTP_OPTION_SECURE_PROTOCOLS");
418+
WinHttpCloseHandle(hSession);
419+
return hr;
420+
}
388421
}
389422

390423
BOOL enableFallback = TRUE;
391-
result = WinHttpSetOption(
424+
auto result = WinHttpSetOption(
392425
hSession,
393426
WINHTTP_OPTION_IPV6_FAST_FALLBACK,
394427
&enableFallback,
395428
sizeof(enableFallback));
396429
if (!result)
397430
{
398431
HRESULT hr = HRESULT_FROM_WIN32(GetLastError());
399-
HC_TRACE_WARNING_HR(HTTPCLIENT, hr, "WinHttpProvider WinHttpSetOption");
432+
HC_TRACE_WARNING_HR(HTTPCLIENT, hr, "WinHttpProvider WinHttpSetOption WINHTTP_OPTION_IPV6_FAST_FALLBACK");
400433
}
401434

402435
if (!m_globalProxy.empty())

Source/HTTP/WinHttp/winhttp_provider.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ class WinHttpProvider
111111
HRESULT CloseAllConnections();
112112

113113
Result<XPlatSecurityInformation> GetSecurityInformation(const char* url);
114-
Result<HINTERNET> GetHSession(uint32_t securityProtolFlags);
114+
Result<HINTERNET> GetHSession(uint32_t securityProtocolFlags, const char* url);
115115

116116
static HRESULT SetGlobalProxyForHSession(HINTERNET hSession, const char* proxyUri);
117117
static HRESULT GetProxyName(_In_ proxy_type proxyType, _In_ Uri proxyUri, _Out_ DWORD& pAccessType, _Out_ http_internal_wstring& pwProxyName);

Tests/UnitTests/Tests/HttpTests.cpp

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,10 @@
99
#include "../global/global.h"
1010
#include <httpClient/httpProvider.h>
1111

12+
#if HC_PLATFORM == HC_PLATFORM_GDK
13+
#include <winhttp.h>
14+
#endif
15+
1216
#pragma warning(disable:4389)
1317

1418
using namespace xbox::httpclient;
@@ -449,6 +453,54 @@ DEFINE_TEST_CLASS(HttpTests)
449453
HCHttpCallCloseHandle(call);
450454
HCCleanup();
451455
}
456+
457+
DEFINE_TEST_CASE(TestHttpProtocol)
458+
{
459+
DEFINE_TEST_CASE_PROPERTIES(TestHttpProtocol);
460+
461+
// Test to verify HTTP (non-HTTPS) requests work correctly
462+
//
463+
// Background: This test was added to ensure HTTP protocol support remains functional
464+
// after changes to provider flag configuration that could potentially affect HTTP vs HTTPS handling.
465+
466+
VERIFY_ARE_EQUAL(S_OK, HCInitialize(nullptr));
467+
468+
HCCallHandle call = nullptr;
469+
VERIFY_ARE_EQUAL(S_OK, HCHttpCallCreate(&call));
470+
471+
// Use HTTP protocol to verify it works correctly
472+
VERIFY_ARE_EQUAL(S_OK, HCHttpCallRequestSetUrl(call, "GET", "http://example.com"));
473+
VERIFY_ARE_EQUAL(S_OK, HCHttpCallRequestSetRetryAllowed(call, false));
474+
475+
// Create a mock response for the HTTP call
476+
HCMockCallHandle mockCall;
477+
VERIFY_ARE_EQUAL(S_OK, HCMockCallCreate(&mockCall));
478+
VERIFY_ARE_EQUAL(S_OK, HCMockResponseSetStatusCode(mockCall, 200));
479+
std::string responseBody = "HTTP test successful";
480+
VERIFY_ARE_EQUAL(S_OK, HCMockResponseSetResponseBodyBytes(mockCall, (uint8_t*)responseBody.c_str(), (uint32_t)responseBody.length()));
481+
VERIFY_ARE_EQUAL(S_OK, HCMockAddMock(mockCall, "GET", "http://example.com", nullptr, 0));
482+
483+
XAsyncBlock asyncBlock = {};
484+
asyncBlock.context = call;
485+
486+
// Perform the HTTP call
487+
VERIFY_ARE_EQUAL(S_OK, HCHttpCallPerformAsync(call, &asyncBlock));
488+
489+
// Wait for completion
490+
HRESULT hr = XAsyncGetStatus(&asyncBlock, true);
491+
492+
// Verify the HTTP request succeeded
493+
VERIFY_ARE_EQUAL(S_OK, hr);
494+
495+
// Verify we got a successful HTTP response
496+
uint32_t statusCode = 0;
497+
VERIFY_ARE_EQUAL(S_OK, HCHttpCallResponseGetStatusCode(call, &statusCode));
498+
VERIFY_ARE_EQUAL(200, statusCode);
499+
500+
HCHttpCallCloseHandle(call);
501+
HCCleanup();
502+
}
503+
452504
};
453505

454506
NAMESPACE_XBOX_HTTP_CLIENT_TEST_END

0 commit comments

Comments
 (0)