WinHTTP のバージョン差異
一般に、Microsoft Game Development Kit (GDK) タイトルは、Win32 アプリケーションで WinHTTP を扱うのと同じ方法で WinHTTP と対話します。 Microsoft Game Development Kit (GDK) タイトルの開発では、WinHTTP のフラット C/C++ API のみが利用可能です。つまり、HTTP 機能はこの HTTP クライアント API 上に構築する必要があります。XBOX コンソール プロジェクトへの WinHTTP の追加
コンソールでは、ソース ファイルに#include <winhttp.h> を記述してください。Winhttp.lib を直接リンクするのではなく、XGamePlatform.lib をリンクする必要があります。Microsoft Game Development Kit (GDK) タイトルで動作するのは WINAPI_PARTITION_GAMES API ファミリの API のみです。Windows PC では、これまでどおり Winhttp.lib をリンクしてください。
Microsoft Game Development Kit (GDK) タイトルに WinHTTP を統合する例については、SimpleWinHttp サンプル を参照してください。独自の WinHTTP 実装の出発点として堅実な基盤を提供し、シンプルな非同期 API 面を公開する WinHttpManager クラスも含まれています。
ネットワーク初期化と WinHTTP
タイトルが初めて WinHttpOpen を呼び出す前に、Microsoft Game Development Kit (GDK) タイトルはネットワーク スタックが初期化されていることを確認する必要があります。タイトルの起動プロセス中にWinHttpOpen を早すぎるタイミングで呼び出すと、WinHttpOpen またはその後の WinHTTP 呼び出しが非決定的に失敗またはクラッシュする可能性があります。ネットワークが初期化済みと宣言される前は、リクエストが成功したように見えて実際には失敗していたり、その逆になったりします。ネットワーク スタックがいつ初期化されるかを判定する方法の詳細は、ネットワーク初期化 を参照してください。
タイトルのサスペンド/レジュームと WinHTTP
タイトルがサスペンド通知を受け取ったら、すべての WinHTTP ハンドルを閉じる処理を開始する必要があります。WinHTTP ハンドルのクリーンアップは非同期です。そのため、すべてのリクエスト ハンドル、続いてすべての接続ハンドル、最後にすべてのセッション ハンドルの順に閉じてください。WinHTTP ハンドルのクリーンアップが非同期になっているのは、通知スレッドの安全性を確保するためです。非同期とはいえ、WinHTTP ハンドルのクリーンアップにかかる遅延は非常に短いため、サスペンド遅延の 1 秒のタイムアウトに簡単に収まります。 レジューム時には、タイトルは前述の「ネットワーク初期化と WinHTTP」で説明した手順に従い、WinHTTP の利用を続行する前にネットワークが再び準備完了状態に戻るのを待機してください。サスペンドとレジュームのイベント間には長い時間が経過している可能性があり、WinHTTP API が再び決定的に動作するまでネットワークが安定するのを待つ必要があります。メモリと同時実行の考慮事項
WinHTTP の非同期状態が正しく、かつメモリ予算内で動作するように、同時実行される WinHTTP リクエスト数は常に 8 未満に抑えてください。この制限は、XBOX サービス API やXCurl からの呼び出しを含む、タイトル ランタイム内のすべての同時操作に適用されます。
WinSock のメモリに関する考慮事項 の拡張として、データを受信する際は、カーネル モードのメモリ プールからユーザー モード プロセスにデータをできるだけ迅速に転送し、HTTP 処理で消費されるカーネル メモリを最小化するために、常に WinHttpReadData によりバッファーを保留状態にしておく (または WinHttpQueryDataAvailable 呼び出しのコールバックを待機している状態にしておく) 必要があります。
WinHttpQueryHeaders ゲッター関数は一時的なメモリ割り当てを必要とします。内部で使用する lpdwBufferLength パラメーターと同サイズのスクラッチ バッファーを割り当て (関数が戻る前に解放されます)。このため、システム メモリの過剰な使用によるシステム不安定を避けるためにも、WINHTTP_NO_OUTPUT_BUFFER のダブル呼び出しパターンを使用してスクラッチ バッファーのサイズを最小化し、WinHttpQueryHeaders の同時呼び出し数を制限してください。ヘッダーの既定の最大サイズは、WinHTTP オプションの WINHTTP_OPTION_MAX_RESPONSE_HEADER_SIZE で指定されているとおり 64 KB です。
WinHttpOpen の考慮事項
フラグ
WinHttpOpen には、次の表のフラグを渡す必要があります。WINHTTP_ACCESS_TYPE_AUTOMATIC_PROXY、WINHTTP_NO_PROXY_NAME、WINHTTP_NO_PROXY_BYPASS を組み合わせることで、Microsoft Game Development Kit (GDK) プラットフォームは Fiddler などのプロキシやその他のエッジ ケースのネットワーク環境を自動的に処理できます。
WINHTTP_FLAG_SECURE_DEFAULTS は、Microsoft Game Development Kit (GDK) タイトルが推奨のセキュア接続動作を設定することでセキュリティのベスト プラクティスに準拠しやすくするために設計された新しいフラグです。これは XBOX One コンソールで利用可能で、Windows PC では将来の Windows OS 更新プログラムで利用可能になる予定です。既存の Windows OS バージョンで WINHTTP_FLAG_SECURE_DEFAULTS を渡そうとすると、無効なパラメーター エラーになります。このフラグには重要な副作用があります。すなわち、WINHTTP_FLAG_ASYNC フラグを暗黙的に含むため、WinHTTP を強制的に非同期モードにします。このフラグがサポートされない Windows PC OS バージョンでは、WinHTTP 実装の他の部分の差を最小化するために、代わりに WINHTTP_FLAG_ASYNC を渡してください。
WINHTTP_FLAG_SECURE_DEFAULTS フラグは、WinHttpOpenRequest に渡される対応する WINHTTP_FLAG_SECURE フラグを必要とし、暗号化されていない HTTP リクエストをブロックします。内部デバッグやテスト用の開発キットでは、WinHTTP セッション ハンドルを作成する際に WinHttpOpen に WINHTTP_FLAG_ASYNC フラグを指定できます。これにより、WinHttpOpenRequest に WINHTTP_FLAG_SECURE フラグを指定しないことで、開発中は暗号化されていない HTTP リクエストを送信できます。それでも、RETAIL でタイトルが目にするリクエスト動作と一致させるため、非デバッグ トラフィックには WINHTTP_FLAG_SECURE_DEFAULTS で開いたセッション ハンドルを使用してください。WINHTTP_OPTION_SECURE_PROTOCOLS
WinHttpOpen で新しいセッション ハンドルを作成した後は、WinHttpSetOption を WINHTTP_OPTION_SECURE_PROTOCOLS オプションで呼び出し、このセッション ハンドルが使用される URL について事前に XNetworkingQuerySecurityInformationForUrlUtf16Async を呼び出して取得した対応する XNetworkingSecurityInformation::enabledHttpSecurityProtocolFlags を渡す必要があります。また、後で TLS/SSL ハンドシェイクを検証する際に使用するため、XNetworkingSecurityInformation 構造体をコンテキスト オブジェクトに保存しておいてください。
セッション ハンドルのキャッシュ
WinHttpOpen で作成された HTTP セッション ハンドルはメモリ的に高価で、大きな起動コストがかかり、最初の HTTP リクエストを遅延させます。これらのコストを避けるため、タイトル内で HTTP セッション ハンドルをできる限りキャッシュすることを推奨します。
ただし、セッション ハンドル上で WINHTTP_OPTION_SECURE_PROTOCOLS オプションを変更することはできません。異なるセキュア プロトコル フラグごとに異なるセッション ハンドルを確保できるように、XNetworkingSecurityInformation::enabledHttpSecurityProtocolFlags の値と WinHTTP セッション ハンドルをマッピングしたキャッシュを保持してください。
タイトルが保持するキャッシュは、サスペンド通知でクリアし、レジューム時 (ネットワークが初期化されるのを待った後) にゼロから再構築する必要があります。
WinHttpConnect の考慮事項
セッション ハンドルとは異なり、WinHttpConnect で作成された接続ハンドルは決してキャッシュしないでください。新しいリクエストや再試行のたびに新しいハンドルを作成する必要があります。WinHTTP 接続ハンドルはその名前とは裏腹に、基盤となるサーバー Transmission Control Protocol (TCP) 接続とは無関係です。WinHTTP はセッション ハンドルで基盤となるサーバー接続のライフタイムを管理し、新しい接続ハンドルに対して可能な場合は既存のサーバー接続を自動的に再利用します。URL の正規化
WinHTTP は、すべての URL が a〜z、A〜Z、0〜9 の US-ASCII 文字に正規化されていることを期待します。正規化の詳細は Uniform Resource Locators (URLs) in WinHTTP を参照してください。可能な限り、タイトルで使用する URL は正規化された形でハードコーディングすることを推奨します。この形式は、WinHttpCrackUrl や WinHttpCreateUrl を使って URL を動的に正規化する際に発生するメモリ割り当てやパフォーマンスの問題を回避できます。URL の分割
WinHTTP は、WinHttpConnect には null 終端のホスト名文字列を渡し、パスとオブジェクトは WinHttpOpenRequest に渡すことを要求します。タイトルは、ある場所では完全な URL (ホスト名とパスを連結したもの) を、別の場所ではホスト名またはパスのみを渡す必要があります。動的な連結や分割のために WinHttpCrackUrl や WinHttpCreateUrl を使う必要をなくすため、両方をタイトル内でハードコーディングすることを推奨します。
WinHttpOpenRequest の考慮事項
WinHTTP 接続ハンドルと同様に、WinHttpOpenRequest 関数で作成された WinHTTP リクエスト ハンドルも決してキャッシュしないでください。新しいリクエストや再試行のたびに新しいハンドルを作成する必要があります。 セキュリティのベスト プラクティスとして、タイトルはWinHttpOpenRequest 関数を呼び出す際、常に dwFlags パラメーターに WINHTTP_FLAG_SECURE フラグを渡してください。
XBOX サービス トークンの取得と適用
Microsoft Game Development Kit (GDK) タイトルではトークンは自動挿入されません。代わりに、タイトルは Microsoft Game Development Kit (GDK) の XUser API を使って XBOX サービスの認証トークンと署名を取得する必要があります。タイトルがユーザーを取得した後は、各リクエストごとに XUserGetTokenAndSignatureUtf16Async を呼び出してトークンと署名の文字列を取得します。これら 2 つの文字列は、WinHttpAddRequestHeadersEx、WinHttpSendRequest、または WinHttpAddRequestHeaders の呼び出しでヘッダーとして渡します。
正しい署名を生成するには、XUserGetTokenAndSignatureUtf16Async はタイトルにすべてのヘッダーと本文全体を渡すことを期待します。大きな本文を伴う POST または PUT の場合、タイトルはパートナー センターで構成した本文の一部を渡すことができます。詳細は Web サービス (NDA トピック) を参照してください。現時点では、XBOX network はこの構成を取得するメカニズムを提供していません。クライアントは、値をハードコーディングするか、カスタムのタイトル固有エンドポイント経由で取得することが想定されています。
XUserGetTokenAndSignatureUtf16Async は必要なキャッシュをすべて内部で処理しており、再試行を含む HTTP の試行ごとに呼び出す必要があります。任意の HTTP リクエストで 401 Unauthorized の HTTP レスポンス ステータス コードを受け取った場合、タイトルはリクエストを再試行し、XBOX サービス認証トークンを強制的に更新してください。この更新は、XUserGetTokenAndSignatureUtf16Async で新しいトークンを取得する際に XUserGetTokenAndSignatureOptions::ForceRefresh 列挙値を渡すことで実現します。
タイトルが XUserGetTokenAndSignatureUtf16Async の呼び出しから XUserGetTokenAndSignatureUtf16Data を取得した後、タイトルは XUserGetTokenAndSignatureUtf16Data::Token と XUserGetTokenAndSignatureUtf16Data::Signature を WinHTTP に渡すための HTTP ヘッダーに変換する必要があります。Microsoft Game Development Kit (GDK) タイトル向けに複雑さを軽減する目的で、新しい WinHTTP API WinHttpAddRequestHeadersEx が追加されています。この新しい API の使用例を以下に示します。この新しい API は XBOX One コンソールで利用可能で、Windows PC では将来の Windows OS 更新プログラムで利用可能になる予定です。コンソール上では、余分な割り当てや文字列フォーマット変更を避けるため、WinHttpAddRequestHeadersEx の使用を推奨します。
デバイスまたはサインイン中のアカウントは、設定されているサンドボックスにアクセスできる必要があります。そうでない場合、
XUserGetTokenAndSignatureUtf16Data は失敗します。XBOX Network Security Authorization List (NSAL) の使用
XBOX network は、クライアントがサービスとの間でセキュアで認証済みの接続を確立できるように NSAL を使用しています。タイトルはパートナー センターの構成の一部として NSAL の内容を管理します。詳細は パートナー センターでの Web サービス構成 (NDA トピック) を参照してください。NSAL 構成は各タイトルに自動的にダウンロードされます。これは、適切な XBOX サービス トークンの生成と、タイトル固有のエンドポイントに対する証明書ピニングの両方に使用されます。}WinHTTP 非同期状態マシンの考慮事項
WinHTTP の非同期状態マシンは、コンソールでも Windows PC でも同じです。1 つまたは複数の通知に対してコールバック関数を登録するには、WinHttpSetStatusCallback 関数を使用します。WinHTTP は比較的冗長で動作が可視化されているため、デバッグ目的ではdwNotificationFlags パラメーターに WINHTTP_CALLBACK_FLAG_ALL_NOTIFICATIONS フラグを使用することを推奨します。ほとんどの通知は特に処理を必要としませんが、データをログに残しておくと問題の根本原因の発見に役立ちます。
WinHTTP は通知のために単一のスレッドを使用します。タイトルは、プロセス内のすべての HTTP リクエストの進行を止めないよう、通知関数のいずれもブロックしないようにしてください。処理されない通知はカーネル モードのメモリを増加させ、クラッシュにつながる可能性もあります。
WinHTTP は送受信バッファーをコピーしないため、対応する完了コールバックが返るまでそれらのバッファーを割り当て済みのまま保持する必要があります。WinHttpSendRequest を呼び出してから、対応する WINHTTP_CALLBACK_STATUS_SENDREQUEST_COMPLETE 通知を受信するまで、送信バッファーは有効なまま保持してください。同様に、WinHttpReadData を呼び出すたびに、対応する WINHTTP_CALLBACK_STATUS_READ_COMPLETE 通知を受信するまで受信バッファーを有効なまま保持してください。また、スタック枯渇につながる再帰の問題を避けるため、受信バッファーは少なくとも 8 KB 以上のサイズにすることを推奨します。
タイトルは、WinHttpQueryDataAvailable/WinHttpReadData の非同期サイクルを継続し、WinHTTP コールバックを長時間ブロックしないことで、WinHTTP バッファーが正しく空にされることを確認してください。
Transport Layer Security (TLS)/Secure Sockets Layer (SSL) ハンドシェイクの検証
セキュリティのベスト プラクティスとして、タイトルは TLS/SSL ハンドシェイクを検証し、TLS 1.2 のみを使用してください。 追加の検証はWINHTTP_CALLBACK_STATUS_SENDING_REQUEST 通知内で実行します。この通知内で、XNetworkingVerifyServerCertificate 関数を呼び出し、事前に対応する XNetworkingQuerySecurityInformationForUrlUtf16Async 呼び出しから取得した XNetworkingSecurityInformation 構造体を渡す必要があります。この関数は、証明書チェーンが無効な場合に失敗します。侵害されたサーバーとの間でデータが転送されないようにするために、コールバックが完了する前に 即座に WinHTTP ハンドルを閉じてください。
証明書チェーンの検証に加え、XNetworkingVerifyServerCertificate 関数はコンソール上での Fiddler 機能に必須です。
WinHTTP のデバッグ
Fiddler は WinHTTP のトラフィックを表示・デバッグするのに有用なツールです。Fiddler がタイトルのトラフィックをキャプチャできるようにするには、WinHttpOpen に WINHTTP_ACCESS_TYPE_AUTOMATIC_PROXY、WINHTTP_NO_PROXY_NAME、WINHTTP_NO_PROXY_BYPASS フラグを渡す必要があります。また、WINHTTP_CALLBACK_STATUS_SENDING_REQUEST 通知コールバック内で XNetworkingVerifyServerCertificate を呼び出す必要もあります。
HTTP Monitor は Microsoft Game Development Kit (GDK) タイトルでは動作しません。
