メインコンテンツまでスキップ

Appendix B. Encoding and Decoding Examples (エンコーディングとデコーディングの例)

この付録は、QPACK のエンコーディングとデコーディング操作の例を提供し、エンコーダーとデコーダーがそれぞれのストリームを介してどのように相互作用し、動的テーブルがどのように進化するかを示しています。

B.1 名前参照を持つリテラルフィールド行 (Literal Field Line With Name Reference)

この例は、静的テーブルに存在する名前を持つフィールド行のエンコーディングを示しています。エンコーダーは、静的名前参照を持つリテラル表現を使用します。

エンコーディング

エンコードするフィールド行:

custom-key: custom-value

「custom-key」が静的テーブルインデックス 15 にあると仮定すると、エンコーダーは次を生成します:

エンコードされたフィールドセクション:

0x00 0x00  # 必要挿入カウント = 0, Base = 0
0x50 0x0c 0x63 0x75 0x73 0x74 0x6f 0x6d 0x2d 0x76 0x61 0x6c 0x75 0x65
# 静的名前参照を持つリテラル、インデックス 15、値 "custom-value"

デコーディング

デコーダーはエンコードされたフィールドセクションを受信して処理します:

  1. 必要挿入カウント = 0 を読み取ります(動的テーブルエントリは不要)
  2. Base = 0 を読み取ります
  3. リテラルフィールド行表現をデコードします
  4. フィールド行を生成します: custom-key: custom-value

B.2 動的テーブルへの挿入 (Dynamic Table Insertions)

この例は、動的テーブルへのエントリの挿入と、後続のフィールドセクションでのそれらの参照を示しています。

ステップ 1: エンコーダーがエントリを挿入

エンコーダーは、動的テーブルに新しいフィールド行を挿入することを決定します:

エンコーダーストリーム:

0xc0 0x0c 0x63 0x75 0x73 0x74 0x6f 0x6d 0x2d 0x76 0x61 0x6c 0x75 0x65
# 名前参照を持つ挿入(静的インデックス 15)、値 "custom-value"

動的テーブルの状態(挿入後):

[0] custom-key: custom-value
挿入カウント: 1

ステップ 2: エンコーダーが動的エントリを参照

エンコーダーは、フィールドセクションでこのエントリを参照できるようになります:

エンコードされたフィールドセクション:

0x02 0x00  # 必要挿入カウント = 1, Base = 0
0x80 # インデックス付きフィールド行、動的テーブルインデックス 0

ステップ 3: デコーダーが処理

デコーダー:

  1. エンコーダーストリーム命令を受信してエントリを挿入します
  2. エンコードされたフィールドセクションを受信します
  3. 必要挿入カウント = 1 を確認します(絶対インデックス 0 のエントリが必要)
  4. 動的テーブルインデックス 0 からインデックス付きフィールド行をデコードします
  5. 生成します: custom-key: custom-value

ステップ 4: デコーダーが確認応答

デコーダーストリーム:

0x80  # セクション確認応答(ストリーム ID エンコード済み)

これは、デコーダーが動的テーブルエントリ 0 を参照するフィールドセクションを処理したことをエンコーダーに通知します。

B.3 投機的挿入 (Speculative Insertion)

この例は、エンコーダーが実際に使用される前に動的テーブルにエントリを挿入し、将来の使用を予測することを示しています。

ステップ 1: エンコーダーが投機的に挿入

エンコーダーストリーム:

0x4a 0x63 0x75 0x73 0x74 0x6f 0x6d 0x2d 0x6b 0x65 0x79
0x0c 0x63 0x75 0x73 0x74 0x6f 0x6d 0x2d 0x76 0x61 0x6c 0x75 0x65
# リテラル名 "custom-key"、値 "custom-value" を持つ挿入

動的テーブルの状態:

[0] custom-key: custom-value
挿入カウント: 1

ステップ 2: エンコーダーが後でエントリを使用

後続のフィールドセクションで:

エンコードされたフィールドセクション:

0x02 0x00  # 必要挿入カウント = 1, Base = 0
0x80 # インデックス付きフィールド行、動的テーブルインデックス 0

B.4 複製命令 (Duplicate Instruction)

この例は、既存の動的テーブルエントリをテーブルの前面にコピーする複製命令を示しています。

初期動的テーブルの状態

[0] custom-key: custom-value
[1] another-key: another-value
挿入カウント: 2

エンコーダーがエントリを複製

エンコーダーストリーム:

0x01  # 複製、相対インデックス 1

動的テーブルの状態(複製後):

[0] another-key: another-value  # 複製されたエントリ
[1] custom-key: custom-value
[2] another-key: another-value # 元のエントリ
挿入カウント: 3

複製されたエントリは最新のエントリになります(絶対インデックス 2、相対インデックス 0)。

B.5 Post-Base インデックス (Post-Base Indexing)

この例は、エンコーダーが Base 値の後に挿入されたエントリを参照する Post-Base インデックスを示しています。

ステップ 1: エンコーダーが Base を設定

エンコーダーは Base = 0 でフィールドセクションのエンコーディングを開始します:

エンコードされたフィールドセクションプレフィックス:

0x02 0x80  # 必要挿入カウント = 1, Base = 0, 符号 = 1(負のデルタ)

これは、必要挿入カウント = 1 であるが、Base = 0 であることを示し、フィールドセクションが絶対インデックス 0 のエントリを参照することを意味します。

ステップ 2: エンコーダーが挿入して参照

エンコーディング中に、エンコーダーは新しいエントリを挿入します:

エンコーダーストリーム:

0xc0 0x0c 0x63 0x75 0x73 0x74 0x6f 0x6d 0x2d 0x76 0x61 0x6c 0x75 0x65
# 名前参照を持つ挿入(静的インデックス 15)、値 "custom-value"

動的テーブルの状態:

[0] custom-key: custom-value
挿入カウント: 1

エンコードされたフィールドセクション(続き):

0x10  # Post-Base インデックス付きフィールド行、Post-Base インデックス = 0

これは、絶対インデックス 0 のエントリを参照します(Base + Post-Base インデックス = 0 + 0 = 0)。

ステップ 3: デコーダーが処理

デコーダー:

  1. エンコーダーストリーム命令を受信します
  2. 動的テーブルにエントリを挿入します
  3. Post-Base 参照を持つフィールドセクションを受信します
  4. 必要なエントリが利用可能になるまで必要に応じて待機します
  5. フィールド行をデコードします

B.6 ストリームキャンセル (Stream Cancellation)

この例は、デコーダーがストリームをキャンセルし、フィールドセクションが処理されないことをエンコーダーに通知することを示しています。

シナリオ

デコーダーはストリーム 4 でフィールドセクションを受信しますが、処理が完了する前にストリームがリセットされます。

デコーダーストリーム:

0x40 0x04  # ストリームキャンセル、ストリーム ID = 4

これは、エンコーダーに次のことを通知します:

  • ストリーム 4 のフィールドセクションは処理されませんでした
  • エンコーダーは確認応答を待つべきではありません
  • そのフィールドセクションのみによって参照される動的テーブルエントリは、より早く削除できます

B.7 挿入カウント増分 (Insert Count Increment)

この例は、デコーダーがフィールドセクションで参照せずに複数の挿入を確認応答するために使用する挿入カウント増分命令を示しています。

シナリオ

エンコーダーは 5 つのエントリを挿入しましたが、デコーダーはセクション確認応答を通じて 2 つのみを確認応答しました。

デコーダーストリーム:

0x03  # 挿入カウント増分、増分 = 3

これは、デコーダーが既に確認応答されたものを超えて 3 つの追加の動的テーブル挿入を受信して処理したことをエンコーダーに通知します。

B.8 完全な例: 複数のフィールドセクション (Complete Example: Multiple Field Sections)

この包括的な例は、複数のフィールドセクションを持つ完全な交換を示しています。

初期状態

エンコーダーとデコーダーの両方が空の動的テーブルで開始します。

交換 1: 最初のリクエスト

エンコーダーストリーム:

0xc0 0x0c 0x63 0x75 0x73 0x74 0x6f 0x6d 0x2d 0x76 0x61 0x6c 0x75 0x65
# 挿入: custom-key: custom-value

エンコードされたフィールドセクション(ストリーム 0):

0x02 0x00  # 必要挿入カウント = 1, Base = 0
0x80 # インデックス付き、動的インデックス 0
0x51 0x04 0x74 0x65 0x73 0x74 # 静的名前を持つリテラル、値 "test"

動的テーブルの状態:

[0] custom-key: custom-value
挿入カウント: 1

デコードされたフィールド行:

custom-key: custom-value
another-key: test

デコーダーストリーム:

0x80  # ストリーム 0 のセクション確認応答

交換 2: 2 番目のリクエスト

エンコードされたフィールドセクション(ストリーム 4):

0x02 0x00  # 必要挿入カウント = 1, Base = 0
0x80 # インデックス付き、動的インデックス 0

デコードされたフィールド行:

custom-key: custom-value

デコーダーストリーム:

0x84  # ストリーム 4 のセクション確認応答

交換 3: 削除

確認応答を受信した後、エンコーダーは新しい挿入のために必要に応じてエントリを安全に削除できます。


まとめ (Summary)

これらの例は次のことを示しています:

  1. リテラル表現: 動的テーブルなしでフィールド行をエンコード
  2. 動的テーブル管理: エントリの挿入、参照、複製
  3. 同期: デコーダーの確認応答とエンコーダーの追跡
  4. Post-Base インデックス: 最近挿入されたエントリの参照
  5. エラー回復: 不完全な処理のためのストリームキャンセル
  6. 効率的な確認応答: 一括確認応答のための挿入カウント増分

エンコーダーストリームとデコーダーストリーム間の相互作用により、順序外配信を許可しながら効率的な圧縮を可能にする適切な同期が保証されます。