> ## Documentation Index
> Fetch the complete documentation index at: https://devdocs.xbox.com/llms.txt
> Use this file to discover all available pages before exploring further.

# カスタム HTTP スタックのデバッグ

> カスタム HTTP スタックのデバッグ

この記事は、タイトルが xCurl の代わりにカスタム HTTP スタックを直接使用し、Fiddler などのプロキシを通じてトラフィックをデバッグする必要がある場合に使用します。

## このガイダンスを使用する場面

このガイダンスは、次のいずれかに該当する場合に特に有用です。

* タイトルがプロキシ設定を直接検査または適用する必要がある。
* デバッグ ワークフローが Fiddler または他の開発プロキシに依存している。
* HTTP スタックがセキュリティ プロバイダーとして Schannel を使用しておらず、プロキシ証明書を明示的にロードする必要がある。

一般的なセキュリティ ガイダンスについては、[Microsoft Game Development Kit タイトル向けのセキュアな Web リクエストと WebSocket のベスト プラクティス](https://learn.microsoft.com/gaming/gdk/docs/gdk-dev/game-principles/security/communication-security/communication-security-impl/gc-secure-webrequest-impl) を参照してください。

## XBOX および PC でのプロキシ設定

XBOX でプロキシ設定を扱う場合、ビルドおよびターゲット環境でその経路が利用できるなら、`WinHttpGetProxySettingsEx` と `WinHttpProxySettingsTypeXBox` の組み合わせを優先してください。XBOX 上では、この API は 2026 年 4 月版 Microsoft Game Development Kit (GDK) 以降、プロキシ設定を読み取るための今後を見据えた API です。

XBOX でそれより前の GDK をターゲットとする場合、XBOX 固有のプロキシ設定経路は利用できません。この場合は、HTTP スタック内でプロキシ アドレスとポートを手動で設定してください。この記事で後述する証明書のロード手順は、XBOX 固有のプロキシ アドレス API が利用できない旧 GDK でも依然として適用されます。

PC タイトルも WinHTTP を通じてプロキシ設定を照会できますが、XBOX のフローをそのままコピーしないでください。PC では `WinHttpGetProxySettingsEx` は非同期であるため、`WinHttpGetProxySettingsResultEx` を呼び出して返されたプロキシ値を HTTP スタックにコピーする前に、処理の完了を待機してください。

libcurl を使用する例では、XBOX のプロキシ設定 API でプロキシ アドレスを解決し、それをスタックに直接渡します。セッションは `WINHTTP_FLAG_ASYNC` で開き、同期的な完了と `ERROR_IO_PENDING` の戻り値の両方を処理できるよう、ステータス コールバックを登録します。次の例は呼び出しの流れを示しています。

```cpp theme={null}
// WinHttpCreateProxyResolver is not declared in WinHttp.h when using the GDK.
WINHTTPAPI DWORD WINAPI WinHttpCreateProxyResolver(HINTERNET hSession, HINTERNET* phResolver);

std::string ResolveXboxProxy()
{
    HINTERNET session = WinHttpOpen(
        L"CustomHttp/1.0",
        WINHTTP_ACCESS_TYPE_AUTOMATIC_PROXY,
        WINHTTP_NO_PROXY_NAME,
        WINHTTP_NO_PROXY_BYPASS,
        WINHTTP_FLAG_ASYNC);
    if (!session)
        return {};

    struct ProxyContext
    {
        HANDLE event;
        DWORD  error;
    };

    ProxyContext ctx{ CreateEventW(nullptr, TRUE, FALSE, nullptr), ERROR_SUCCESS };

    WinHttpSetStatusCallback(session,
        [](HINTERNET, DWORD_PTR context, DWORD status, LPVOID info, DWORD)
        {
            auto* c = reinterpret_cast<ProxyContext*>(context);
            if (status == WINHTTP_CALLBACK_STATUS_GETPROXYFORURL_COMPLETE)
            {
                c->error = ERROR_SUCCESS;
                SetEvent(c->event);
            }
            else if (status == WINHTTP_CALLBACK_STATUS_REQUEST_ERROR)
            {
                c->error = reinterpret_cast<WINHTTP_ASYNC_RESULT*>(info)->dwError;
                SetEvent(c->event);
            }
        },
        WINHTTP_CALLBACK_FLAG_ALL_COMPLETIONS,
        0);

    HINTERNET resolver = nullptr;
    if (WinHttpCreateProxyResolver(session, &resolver) != ERROR_SUCCESS)
    {
        CloseHandle(ctx.event);
        WinHttpCloseHandle(session);
        return {};
    }

    DWORD result = WinHttpGetProxySettingsEx(
        resolver,
        WinHttpProxySettingsTypeXBox,
        nullptr,
        reinterpret_cast<DWORD_PTR>(&ctx));

    if (result == ERROR_IO_PENDING)
    {
        // Wait for the async callback to fire (5-second timeout).
        WaitForSingleObject(ctx.event, 5000);
        result = ctx.error;
    }

    std::string proxyAddress;
    if (result == ERROR_SUCCESS)
    {
        WINHTTP_PROXY_SETTINGS_EX proxySettings{};
        if (WinHttpGetProxySettingsResultEx(resolver, &proxySettings) == ERROR_SUCCESS)
        {
            PCWSTR proxy =
                proxySettings.pcwszSecureProxy != nullptr
                    ? proxySettings.pcwszSecureProxy
                    : proxySettings.pcwszProxy;

            if (proxy != nullptr)
            {
                // Example function for conversion.
                proxyAddress = Utf16ToUtf8(std::wstring(proxy));
            }

            WinHttpFreeProxySettingsEx(WinHttpProxySettingsTypeXBox, &proxySettings);
        }
    }

    CloseHandle(ctx.event);
    WinHttpCloseHandle(resolver);
    WinHttpCloseHandle(session);
    return proxyAddress;
}

std::string proxyAddress = ResolveXboxProxy();
if (!proxyAddress.empty())
{
    curl_easy_setopt(curlHandle, CURLOPT_PROXY, proxyAddress.c_str());
}
```

## TLS プロバイダーの動作

### Schannel ベースのスタック

スタックが Schannel ベースの TLS 動作に依存している場合、コンソールは構成済みのプロキシ証明書を自動的に適用します。この動作は、TLS プロバイダーとして Schannel を使用する libcurl ビルドにも当てはまります。

### Schannel 以外のスタック

スタックが OpenSSL または他の非 Schannel TLS プロバイダーに依存している場合、有効なデバッグ ツールが必要とする証明書を明示的にロードするのはタイトル側の責任です。証明書のロード経路はリリース コードにも残しておきましょう。コンソールでは、必要に応じてプロキシ経由のトラフィックを診断できるように、関連するプロキシ デバッグ経路も `RETAIL` ビルドで利用できる状態を維持することを推奨します。

信頼、プロキシ、セキュア デフォルトに関するガイダンスは、[Microsoft Game Development Kit タイトル向けのセキュアな Web リクエストと WebSocket のベスト プラクティス](https://learn.microsoft.com/gaming/gdk/docs/gdk-dev/game-principles/security/communication-security/communication-security-impl/gc-secure-webrequest-impl) を参照してください。

## プロキシ ルート証明書の見つけ方

Schannel 以外のスタックでは、デバッグ ツールに対応する証明書を明示的にロードし、その経路をリリース コードに残してください。証明書の場所とサブジェクトはツールによって異なります。たとえば、[XBOX Multiplayer Analysis Tool (XMAT)](https://aka.ms/XMAT) は `CurrentUser\Root` にある証明書 `Xbox Multiplayer Analysis Tool Root Cert Authority` を使用します。次の例では、その証明書を検索し、DER エンコード済みの証明書バイトをタイトル所有のバッファーにコピーします。

```cpp theme={null}
#include <wincrypt.h>
#include <vector>

HRESULT ExtractXmatRootCertificateDer(_Out_ std::vector<uint8_t>& encodedCertificate)
{
    encodedCertificate.clear();

    constexpr DWORD certificateStoreLocation = CERT_SYSTEM_STORE_CURRENT_USER;
    constexpr wchar_t certificateStoreName[] = L"Root";
    constexpr wchar_t certificateSubjectName[] =
        L"Xbox Multiplayer Analysis Tool Root Cert Authority";

    HCERTSTORE certificateStore = CertOpenStore(
        CERT_STORE_PROV_SYSTEM_W,
        0,
        0,
        certificateStoreLocation |
            CERT_STORE_OPEN_EXISTING_FLAG |
            CERT_STORE_READONLY_FLAG,
        certificateStoreName);
    if (certificateStore == nullptr)
    {
        return HRESULT_FROM_WIN32(GetLastError());
    }

    PCCERT_CONTEXT certificate = CertFindCertificateInStore(
        certificateStore,
        X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
        0,
        CERT_FIND_SUBJECT_STR_W,
        certificateSubjectName,
        nullptr);
    if (certificate == nullptr)
    {
        HRESULT hr = HRESULT_FROM_WIN32(GetLastError());
        CertCloseStore(certificateStore, 0);
        return hr;
    }

    encodedCertificate.assign(
        certificate->pbCertEncoded,
        certificate->pbCertEncoded + certificate->cbCertEncoded);

    CertFreeCertificateContext(certificate);
    CertCloseStore(certificateStore, 0);
    return S_OK;
}
```

このステップの後、`encodedCertificate` を、TLS プロバイダーが使用する任意の証明書ロード経路に渡します。

## 推奨されるデバッグ ワークフロー

1. [XBOX 開発キット上の Fiddler](/build/console-features/networking/tools/fiddler-setup-networking) の説明に従って、XBOX Device Portal でコンソールのプロキシ設定を構成します。
2. 2026 年 4 月版 GDK 以降で XBOX をターゲットとしており、タイトルがプロキシ設定を直接検査する必要がある場合は、`WinHttpGetProxySettingsEx` と `WinHttpProxySettingsTypeXBox` を使用します。
3. PC のコード パスが WinHTTP を通じてプロキシ設定を照会する場合は、`WinHttpGetProxySettingsResultEx` を呼び出して返されたプロキシ値を適用する前に、非同期処理の結果を待機します。
4. XBOX でそれより前の GDK をターゲットとしている場合や、XBOX 固有のプロキシ設定経路を使用しないスタックを利用する場合は、タイトル内でプロキシ アドレスとポートを手動で設定します。
5. Schannel を使用している場合は、コンソールが適用する証明書に依存できます。OpenSSL または他のスタックを使用している場合は、使用しているデバッグ ツールの証明書を証明書ストアから取得し、明示的にロードします。

## 関連ページ

* [XBOX 開発キット上の Fiddler](/build/console-features/networking/tools/fiddler-setup-networking)
* [Microsoft Game Development Kit タイトル向けのセキュアな Web リクエストと WebSocket のベスト プラクティス](https://learn.microsoft.com/gaming/gdk/docs/gdk-dev/game-principles/security/communication-security/communication-security-impl/gc-secure-webrequest-impl)


## Related topics

- [XBOX での Web リクエストと HTTP スタック](/ja-jp/build/console-features/networking/web-requests/index.md)
- [カスタム CloudScript の作成](/ja-jp/services/playfab/live-service-management/service-gateway/automation/cloudscript/writing-custom-cloudscript.md)
- [PlayFab 統合 SDK でのデバッグ トレース](/ja-jp/services/playfab/sdks/unified-sdk/debug-trace.md)
- [Azure Functions を利用した PlayFab CloudScript のクイックスタート ガイド](/ja-jp/services/playfab/live-service-management/service-gateway/automation/cloudscript-af/quickstart.md)
- [Game Saves のデバッグ](/ja-jp/build/core-features/common/game-save/game-saves-debugging.md)
