Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,6 @@
</ItemGroup>
<ItemGroup>
<ClCompile Include="$(MSBuildThisFileDirectory)..\..\Source\Common\Win\utils_win.cpp" />
<ClCompile Include="$(MSBuildThisFileDirectory)..\..\Source\HTTP\Curl\CurlDynamicLoader.cpp" />
<ClCompile Include="$(MSBuildThisFileDirectory)..\..\Source\HTTP\Curl\CurlEasyRequest.cpp" />
<ClCompile Include="$(MSBuildThisFileDirectory)..\..\Source\HTTP\Curl\CurlMulti.cpp" />
<ClCompile Include="$(MSBuildThisFileDirectory)..\..\Source\HTTP\Curl\CurlProvider.cpp" />
<ClCompile Include="$(MSBuildThisFileDirectory)..\..\Source\HTTP\WinHttp\winhttp_connection.cpp" />
<ClCompile Include="$(MSBuildThisFileDirectory)..\..\Source\HTTP\WinHttp\winhttp_provider.cpp" />
<ClCompile Include="$(MSBuildThisFileDirectory)..\..\Source\HTTP\WinHttp\winhttp_websocket_hybrid.cpp" Condition="Exists('$(HCRoot)\External\boost-wintls\include\wintls.hpp') and '$(HCEnableWebSocketCompression)' == 'true'">
Expand All @@ -49,10 +45,6 @@
</ItemGroup>
<ItemGroup>
<ClInclude Include="$(MSBuildThisFileDirectory)..\..\Source\Common\Win\utils_win.h" />
<ClInclude Include="$(MSBuildThisFileDirectory)..\..\Source\HTTP\Curl\CurlDynamicLoader.h" />
<ClInclude Include="$(MSBuildThisFileDirectory)..\..\Source\HTTP\Curl\CurlEasyRequest.h" />
<ClInclude Include="$(MSBuildThisFileDirectory)..\..\Source\HTTP\Curl\CurlMulti.h" />
<ClInclude Include="$(MSBuildThisFileDirectory)..\..\Source\HTTP\Curl\CurlProvider.h" />
<ClInclude Include="$(MSBuildThisFileDirectory)..\..\Source\HTTP\WinHttp\winhttp_connection.h" />
<ClInclude Include="$(MSBuildThisFileDirectory)..\..\Source\HTTP\WinHttp\winhttp_provider.h" />
<ClInclude Include="$(MSBuildThisFileDirectory)..\..\Source\WebSocket\Websocketpp\websocketpp_websocket.h" Condition="Exists('$(HCRoot)\External\boost-wintls\include\wintls.hpp')" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,6 @@
<Filter Include="Source\Common\Win">
<UniqueIdentifier>{cebce833-dc13-4078-9dc3-23dec64d44e6}</UniqueIdentifier>
</Filter>
<Filter Include="Source\HTTP\Curl">
<UniqueIdentifier>{184db77a-e1d6-458b-ae23-8e7cb1ac3238}</UniqueIdentifier>
</Filter>
<Filter Include="Source\WebSocket\WinHttp">
<UniqueIdentifier>{70210c99-2f90-422b-b92b-53521fc41574}</UniqueIdentifier>
</Filter>
Expand All @@ -39,15 +36,6 @@
<ClCompile Include="$(MSBuildThisFileDirectory)..\..\Source\Common\Win\utils_win.cpp">
<Filter>Source\Common\Win</Filter>
</ClCompile>
<ClCompile Include="$(MSBuildThisFileDirectory)..\..\Source\HTTP\Curl\CurlEasyRequest.cpp">
<Filter>Source\HTTP\Curl</Filter>
</ClCompile>
<ClCompile Include="$(MSBuildThisFileDirectory)..\..\Source\HTTP\Curl\CurlMulti.cpp">
<Filter>Source\HTTP\Curl</Filter>
</ClCompile>
<ClCompile Include="$(MSBuildThisFileDirectory)..\..\Source\HTTP\Curl\CurlProvider.cpp">
<Filter>Source\HTTP\Curl</Filter>
</ClCompile>
<ClCompile Include="$(MSBuildThisFileDirectory)..\..\Source\Platform\GDK\PlatformComponents_GDK.cpp">
<Filter>Source\Platform\GDK</Filter>
</ClCompile>
Expand All @@ -60,9 +48,6 @@
<ClCompile Include="$(MSBuildThisFileDirectory)..\..\Source\Platform\Windows\PlatformTrace_Windows.cpp">
<Filter>Source\Platform\Windows</Filter>
</ClCompile>
<ClCompile Include="$(MSBuildThisFileDirectory)..\..\Source\HTTP\Curl\CurlDynamicLoader.cpp">
<Filter>Source\HTTP\Curl</Filter>
</ClCompile>
<ClCompile Include="$(MSBuildThisFileDirectory)..\..\Source\HTTP\WinHttp\winhttp_proxy_helper.cpp" />
<ClCompile Include="$(MSBuildThisFileDirectory)..\..\Source\WebSocket\Websocketpp\websocketpp_websocket.cpp">
<Filter>Source\WebSocket\Websocketpp</Filter>
Expand All @@ -72,29 +57,17 @@
<ClInclude Include="$(MSBuildThisFileDirectory)..\..\Source\Common\Win\utils_win.h">
<Filter>Source\Common\Win</Filter>
</ClInclude>
<ClInclude Include="$(MSBuildThisFileDirectory)..\..\Source\HTTP\Curl\CurlEasyRequest.h">
<Filter>Source\HTTP\Curl</Filter>
</ClInclude>
<ClInclude Include="$(MSBuildThisFileDirectory)..\..\Source\HTTP\Curl\CurlMulti.h">
<Filter>Source\HTTP\Curl</Filter>
</ClInclude>
<ClInclude Include="$(MSBuildThisFileDirectory)..\..\Source\HTTP\Curl\CurlProvider.h">
<Filter>Source\HTTP\Curl</Filter>
</ClInclude>
<ClInclude Include="$(MSBuildThisFileDirectory)..\..\Source\HTTP\WinHttp\winhttp_connection.h">
<Filter>Source\WebSocket\WinHttp</Filter>
</ClInclude>
<ClInclude Include="$(MSBuildThisFileDirectory)..\..\Source\HTTP\WinHttp\winhttp_provider.h">
<Filter>Source\WebSocket\WinHttp</Filter>
</ClInclude>
<ClInclude Include="$(MSBuildThisFileDirectory)..\..\Source\HTTP\Curl\CurlDynamicLoader.h">
<Filter>Source\HTTP\Curl</Filter>
</ClInclude>
<ClInclude Include="$(MSBuildThisFileDirectory)..\..\Source\WebSocket\Websocketpp\websocketpp_websocket.h">
<Filter>Source\WebSocket\Websocketpp</Filter>
</ClInclude>
<ClInclude Include="$(MSBuildThisFileDirectory)..\..\Source\WebSocket\Websocketpp\wintls_socket.hpp">
<Filter>Source\WebSocket\Websocketpp</Filter>
</ClInclude>
</ItemGroup>
</Project>
</Project>
3 changes: 1 addition & 2 deletions Build/libHttpClient.GDK.props
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,6 @@
websocketpp; we don't use its serial-port transport, so disable it.
-->
<PreprocessorDefinitions>__WRL_NO_DEFAULT_LIB__;_LIB;ASIO_DISABLE_SERIAL_PORT;$(libHttpClientDefine);%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories Condition="'$(Platform)'!='x64' AND '$(Platform)'!='ARM64'">%(AdditionalIncludeDirectories);$(GDKCrossPlatformPath)GRDK\ExtensionLibraries\Xbox.XCurl.API\Include</AdditionalIncludeDirectories>
<ControlFlowGuard>Guard</ControlFlowGuard>
<AdditionalOptions>/Zc:__cplusplus /ZH:SHA_256 /bigobj /Zi %(AdditionalOptions)</AdditionalOptions>
<PreprocessorDefinitions Condition="'$(Platform)'=='x64' OR '$(Platform)'=='ARM64'">HC_PLATFORM=HC_PLATFORM_GDK;HC_DATAMODEL=HC_DATAMODEL_LLP64;%(PreprocessorDefinitions)</PreprocessorDefinitions>
Expand All @@ -124,7 +123,7 @@
<GenerateWindowsMetadata>false</GenerateWindowsMetadata>
<FullProgramDatabaseFile Condition="'$(Configuration)'=='Debug'">true</FullProgramDatabaseFile>
<AdditionalDependencies>$(Console_Libs);%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies Condition="'$(Platform)'=='x64'">xgameruntime.lib;XCurl.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies Condition="'$(Platform)'=='x64'">xgameruntime.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies Condition="'$(Platform)'=='ARM64'">xgameruntime.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
<Lib>
Expand Down
4 changes: 3 additions & 1 deletion Build/libHttpClient.GDK/libHttpClient.GDK.NoWebSockets.def
Original file line number Diff line number Diff line change
Expand Up @@ -97,4 +97,6 @@ EXPORTS
HCTraceSetPlatformCallbacks
HCTraceSetTraceToDebugger
HCWinHttpResume
HCWinHttpSuspend
HCWinHttpSuspend
HCSettingsSetGlobalRequestLimit
HCSettingsGetGlobalRequestLimit
3 changes: 2 additions & 1 deletion Build/libHttpClient.GDK/libHttpClient.GDK.def
Original file line number Diff line number Diff line change
Expand Up @@ -128,4 +128,5 @@ EXPORTS
HCWebSocketSetPingInterval
HCHttpCallRequestGetMaxReceiveBufferSize
HCHttpCallRequestSetMaxReceiveBufferSize

HCSettingsSetGlobalRequestLimit
HCSettingsGetGlobalRequestLimit
Original file line number Diff line number Diff line change
Expand Up @@ -117,4 +117,6 @@ EXPORTS
HCHttpCallResponseSetGzipCompressed
HCHttpCallRequestSetProgressReportFunction
HCHttpCallRequestGetMaxReceiveBufferSize
HCHttpCallRequestSetMaxReceiveBufferSize
HCHttpCallRequestSetMaxReceiveBufferSize
HCSettingsSetGlobalRequestLimit
HCSettingsGetGlobalRequestLimit
2 changes: 2 additions & 0 deletions Build/libHttpClient.Win32/libHttpClient.Win32.def
Original file line number Diff line number Diff line change
Expand Up @@ -149,3 +149,5 @@ EXPORTS
HCWebSocketSetPingInterval
HCHttpCallRequestGetMaxReceiveBufferSize
HCHttpCallRequestSetMaxReceiveBufferSize
HCSettingsSetGlobalRequestLimit
HCSettingsGetGlobalRequestLimit
7 changes: 0 additions & 7 deletions Build/libHttpClient.import.props
Original file line number Diff line number Diff line change
Expand Up @@ -65,13 +65,6 @@
</Link>
</ItemDefinitionGroup>

<!--Bring in XCurl on GDK-->
<ImportGroup Condition="'$(HCPlatform)' == 'GDK' AND '$(GameDK)' != '' AND exists('$(GameDK)\$(XdkEditionTarget)\GRDK\ExtensionLibraries\Xbox.XCurl.API\ExtensionLibrary.props')">
<Import Project="$(GameDK)\$(XdkEditionTarget)\GRDK\ExtensionLibraries\Xbox.XCurl.API\ExtensionLibrary.props"/>
</ImportGroup>
<ImportGroup Condition="'$(HCPlatform)' == 'GDK' AND '$(GameDK)' != '' AND exists('$(GameDK)\$(XdkEditionTarget)\GRDK\ExtensionLibraries\Xbox.XCurl.API\DesignTime\CommonConfiguration\neutral\ExtensionLibrary.props')">
<Import Project="$(GameDK)\$(XdkEditionTarget)\GRDK\ExtensionLibraries\Xbox.XCurl.API\DesignTime\CommonConfiguration\neutral\ExtensionLibrary.props"/>
</ImportGroup>
<ItemDefinitionGroup>
<Link>
<AdditionalLibraryDirectories>%(AdditionalLibraryDirectories);$(Console_SdkLibPath)</AdditionalLibraryDirectories>
Expand Down
38 changes: 38 additions & 0 deletions Include/httpClient/httpClient.h
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,44 @@ STDAPI_(void) HCRemoveCallRoutedHandler(
/// <remarks> If it is passed a null proxy, it will reset to default. Does not include proxying web socket traffic.</remarks>
STDAPI HCSetGlobalProxy(_In_z_ const char* proxyUri) noexcept;

/// <summary>
/// Sets the maximum number of HTTP requests allowed to be in flight at one time.
/// </summary>
/// <param name="limit">The maximum number of concurrent HTTP requests. Passing 0 restores the device default.</param>
/// <returns>Result code for this API operation. Possible values are S_OK, E_NOTIMPL, or E_FAIL.</returns>
/// <remarks>
/// Requests submitted beyond this limit are queued and started automatically as earlier requests
/// complete, so HCHttpCallPerformAsync() never fails because of the limit. Callers may create and
/// submit as many HTTP calls as they like; only the number that reach the platform HTTP stack at
/// once is capped.
///
/// The limit exists to bound the memory held by in-flight requests. It defaults to 12 on Xbox
/// consoles, where that budget is tightest, and is unlimited by default everywhere else, including
/// GDK on PC. The device is detected at runtime, so the same binary running on an Xbox console and
/// on PC will pick up different defaults. Titles that want a cap on PC should set one explicitly.
///
/// This may be called before HCInitialize(). Changing the value does not affect requests that are
/// already in flight, and lowering it will not cancel them; the count drains naturally as they
/// complete.
///
/// Platform support: admission control is implemented by the WinHTTP-based HTTP provider, so the
/// limit is only supported on GDK (Xbox and PC) and Win32. On UWP, Linux, Android, iOS and macOS
/// this returns E_NOTIMPL rather than storing a value that would never throttle anything.
/// </remarks>
STDAPI HCSettingsSetGlobalRequestLimit(_In_ uint32_t limit) noexcept;

/// <summary>
/// Gets the maximum number of HTTP requests allowed to be in flight at one time.
/// </summary>
/// <param name="limit">Passes back the current concurrent HTTP request limit. 0xFFFFFFFF means unlimited.</param>
/// <returns>Result code for this API operation. Possible values are S_OK, E_INVALIDARG, E_NOTIMPL, or E_FAIL.</returns>
/// <remarks>
/// This may be called before HCInitialize(). When no limit has been set explicitly this passes back
/// the device default, which is 0xFFFFFFFF (unlimited) on every device except Xbox consoles. Returns
/// E_NOTIMPL on platforms that do not support the limit - see HCSettingsSetGlobalRequestLimit().
/// </remarks>
STDAPI HCSettingsGetGlobalRequestLimit(_Out_ uint32_t* limit) noexcept;

/////////////////////////////////////////////////////////////////////////////////////////
// Http APIs
//
Expand Down
Binary file modified Samples/Win32WebSocket/pch.cpp
Binary file not shown.
44 changes: 44 additions & 0 deletions Source/Global/global.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@
#include "../Logger/trace_internal.h"
#include "../Mock/lhc_mock.h"

#if HC_PLATFORM == HC_PLATFORM_GDK
#include "XSystem.h"
#endif

#ifndef HC_NOWEBSOCKETS
#include "../WebSocket/hcwebsocket.h"
#endif
Expand All @@ -19,6 +23,46 @@ using namespace xbox::httpclient;

NAMESPACE_XBOX_HTTP_CLIENT_BEGIN

// Unlimited is the historical behavior on every platform, so it stays the default everywhere
// except Xbox consoles. That keeps this change from regressing concurrency for titles that were
// never throttled before.
constexpr uint32_t c_unlimitedGlobalRequestLimit = UINT32_MAX;

// 0 means "no explicit limit configured"; GetGlobalRequestLimit resolves that to the device default.
// Deliberately not part of http_singleton: this must be settable before HCInitialize.
static std::atomic<uint32_t> g_globalRequestLimit{ 0 };

// Resolved per call rather than cached: the same Gaming.Desktop binary ships on Xbox consoles, GDK
// PC, Steam and Steam Deck, so the device is only knowable at runtime. Caching would also risk
// latching a wrong answer, because these APIs are callable before the game runtime is initialized.
static uint32_t DefaultGlobalRequestLimit() noexcept
{
#if HC_PLATFORM == HC_PLATFORM_GDK
// Bounds the memory held by in-flight requests on Xbox consoles, where that budget is tightest.
// Declared here rather than at namespace scope so it is not an unused constant on the platforms
// that never consult it, which build with -Werror.
constexpr uint32_t c_consoleDefaultGlobalRequestLimit = 12;

return XSystemGetDeviceType() == XSystemDeviceType::Pc
? c_unlimitedGlobalRequestLimit
: c_consoleDefaultGlobalRequestLimit;
#else
return c_unlimitedGlobalRequestLimit;
#endif
}

void SetGlobalRequestLimit(uint32_t limit) noexcept
{
// Callers pass 0 to restore the default request limit.
g_globalRequestLimit.store(limit, std::memory_order_relaxed);
}

uint32_t GetGlobalRequestLimit() noexcept
{
uint32_t const limit = g_globalRequestLimit.load(std::memory_order_relaxed);
return limit == 0 ? DefaultGlobalRequestLimit() : limit;
}

HRESULT http_singleton::singleton_access(
_In_ singleton_access_mode mode,
_In_opt_ HCInitArgs* createArgs,
Expand Down
8 changes: 8 additions & 0 deletions Source/Global/global.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,14 @@ namespace log
class logger;
}

// Process-wide cap on the number of HTTP requests allowed in flight against the platform HTTP
// stack at once. Kept outside the http_singleton so it can be configured before HCInitialize.
// Enforcement lives in the platform HTTP provider; only the WinHTTP provider (GDK and Win32)
// implements admission control today, so on other platforms this value is stored and readable but
// does not throttle.
void SetGlobalRequestLimit(uint32_t limit) noexcept;
uint32_t GetGlobalRequestLimit() noexcept;

typedef struct http_retry_after_api_state
{
http_retry_after_api_state() = default;
Expand Down
37 changes: 37 additions & 0 deletions Source/Global/global_publics.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,43 @@ try
}
CATCH_RETURN()

STDAPI
HCSettingsSetGlobalRequestLimit(_In_ uint32_t limit) noexcept
try
{
#if HC_PLATFORM == HC_PLATFORM_WIN32 || HC_PLATFORM == HC_PLATFORM_GDK
// Deliberately does not require initialization: the limit is process-wide state so it can be
// configured before HCInitialize creates the provider.
xbox::httpclient::SetGlobalRequestLimit(limit);
Comment thread
jasonsandlin marked this conversation as resolved.
return S_OK;
#else
// Admission control lives in the WinHTTP provider, which is only built for Win32 and GDK.
// Failing here is deliberate: storing a value that can never throttle anything would let a
// title believe it had configured a cap that silently does nothing.
(void)limit;
return E_NOTIMPL;
#endif
}
CATCH_RETURN()

STDAPI
HCSettingsGetGlobalRequestLimit(_Out_ uint32_t* limit) noexcept
try
{
#if HC_PLATFORM == HC_PLATFORM_WIN32 || HC_PLATFORM == HC_PLATFORM_GDK
RETURN_HR_IF(E_INVALIDARG, !limit);

*limit = xbox::httpclient::GetGlobalRequestLimit();
return S_OK;
#else
// Symmetric with HCSettingsSetGlobalRequestLimit: there is no meaningful limit to report on
// platforms whose HTTP provider does not implement admission control.
(void)limit;
return E_NOTIMPL;
#endif
}
CATCH_RETURN()

STDAPI
HCSetHttpCallPerformFunction(
_In_ HCCallPerformFunction performFunc,
Expand Down
Loading