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

4. HTTP における構造化フィールドの操作 (Working with Structured Fields in HTTP)

本節では、テキスト HTTP フィールド値およびそれと互換性のある他のエンコーディング(例えば、HPACK [RFC7541] 圧縮を使用する前の HTTP/2 [RFC7540])で構造化フィールドをシリアライズおよびパースする方法を定義します。


4.1 構造化フィールドのシリアライズ (Serializing Structured Fields)

本仕様で定義された構造が与えられた場合、HTTP フィールド値での使用に適した ASCII 文字列を返します。

メインアルゴリズム

  1. 構造が Dictionary または List であり、その値が空(メンバーがない)の場合、そのフィールドをシリアライズしません(field-name と field-value を省略します)。

  2. 構造が List の場合、「List のシリアライズ」(第 4.1.1 節)を実行した結果を output_string とします。

  3. それ以外で構造が Dictionary の場合、「Dictionary のシリアライズ」(第 4.1.2 節)を実行した結果を output_string とします。

  4. それ以外で構造が Item の場合、「Item のシリアライズ」(第 4.1.3 節)を実行した結果を output_string とします。

  5. それ以外の場合、シリアライズは失敗します。

  6. ASCII エンコーディング [RFC0020] を使用して output_string をバイト配列に変換して返します。


4.1.1 List のシリアライズ (Serializing a List)

(member_value, parameters) タプルの配列 input_list が与えられた場合、HTTP フィールド値での使用に適した ASCII 文字列を返します。

アルゴリズム

  1. output を空文字列とします。

  2. input_list の各 (member_value, parameters) について:

    • member_value が配列の場合、「Inner List のシリアライズ」(第 4.1.1.1 節)の結果を output に追加します
    • それ以外の場合、「Item のシリアライズ」(第 4.1.3 節)の結果を output に追加します
    • input_list にさらに member_values がある場合:
      • output に「,」を追加します
      • output に単一のスペース (SP) を追加します
  3. output を返します。

入力: [(1, {}), (2, {}), (3, {})]
出力: "1, 2, 3"

入力: [("foo", {}), ("bar", {a: 1})]
出力: "foo, bar;a=1"

4.1.1.1 Inner List のシリアライズ (Serializing an Inner List)

(member_value, parameters) タプルの配列 inner_list とパラメーター list_parameters が与えられた場合、ASCII 文字列を返します。

アルゴリズム

  1. output を文字列「(」とします。

  2. inner_list の各 (member_value, parameters) について:

    • 「Item のシリアライズ」の結果を output に追加します
    • inner_list にさらに値がある場合、単一のスペースを output に追加します
  3. output に「)」を追加します。

  4. 「Parameters のシリアライズ」(第 4.1.1.2 節)の結果を output に追加します。

  5. output を返します。

入力: [(1, {}), (2, {})] with parameters {lvl: 5}
出力: "(1 2);lvl=5"

4.1.1.2 Parameters のシリアライズ (Serializing Parameters)

有順序 Dictionary input_parameters(各メンバーに param_key と param_value がある)が与えられた場合、ASCII 文字列を返します。

アルゴリズム

  1. output を空文字列とします。

  2. input_parameters の各 param_key(値は param_value)について:

    • output に「;」を追加します
    • 「Key のシリアライズ」(第 4.1.1.3 節)の結果を output に追加します
    • param_value が Boolean true でない場合:
      • output に「=」を追加します
      • 「bare Item のシリアライズ」の結果を output に追加します
  3. output を返します。


4.1.1.3 Key のシリアライズ (Serializing a Key)

input_key が与えられた場合、ASCII 文字列を返します。

アルゴリズム

  1. input_key を ASCII 文字シーケンスに変換します。変換が失敗した場合、シリアライズは失敗します。

  2. input_key に lcalpha、DIGIT、「_」、「-」、「.」、「*」以外の文字が含まれている場合、シリアライズは失敗します。

  3. input_key の最初の文字が lcalpha または「*」でない場合、シリアライズは失敗します。

  4. input_key を返します。


4.1.2 Dictionary のシリアライズ (Serializing a Dictionary)

有順序 Dictionary input_dictionary(各メンバーに member_key とタプル値 (member_value, parameters) がある)が与えられた場合、ASCII 文字列を返します。

アルゴリズム

  1. output を空文字列とします。

  2. input_dictionary の各 member_key(値は (member_value, parameters))について:

    • 「Key のシリアライズ」の結果を output に追加します
    • member_value が Boolean true の場合:
      • 「Parameters のシリアライズ」の結果を output に追加します
    • それ以外の場合:
      • output に「=」を追加します
      • member_value が配列の場合、「Inner List のシリアライズ」の結果を追加します
      • それ以外の場合、「Item のシリアライズ」の結果を追加します
    • input_dictionary にさらにメンバーがある場合:
      • output に「,」を追加します
      • output に単一のスペースを追加します
  3. output を返します。


4.1.3 Item のシリアライズ (Serializing an Item)

Item bare_item と Parameters item_parameters が与えられた場合、ASCII 文字列を返します。

アルゴリズム

  1. output を空文字列とします。
  2. 「Bare Item のシリアライズ」(第 4.1.3.1 節)の結果を output に追加します。
  3. 「Parameters のシリアライズ」の結果を output に追加します。
  4. output を返します。

4.1.3.1 Bare Item のシリアライズ (Serializing a Bare Item)

input_item が与えられた場合、その型に応じて対応するシリアライズ関数を呼び出します。

  • Integer → 第 4.1.4 節
  • Decimal → 第 4.1.5 節
  • String → 第 4.1.6 節
  • Token → 第 4.1.7 節
  • Byte Sequence → 第 4.1.8 節
  • Boolean → 第 4.1.9 節

4.1.4 Integer のシリアライズ (Serializing an Integer)

アルゴリズム

  1. input_integer が -999,999,999,999,999 から 999,999,999,999,999(両端を含む)の範囲外の場合、シリアライズは失敗します。
  2. input_integer < 0 の場合、「-」を追加します。
  3. input_integer の 10 進数表現を追加します。

4.1.5 Decimal のシリアライズ (Serializing a Decimal)

アルゴリズム

  1. 小数点の右側に 3 桁を超える有効数字がある場合、3 桁に丸めます。
  2. 小数点の左側に 12 桁を超える有効数字がある場合、シリアライズは失敗します。
  3. input_decimal < 0 の場合、「-」を追加します。
  4. 整数部分の 10 進数表現を追加します。
  5. 「.」を追加します。
  6. 小数部分を追加します(0 の場合は「0」を追加)。

4.1.6 String のシリアライズ (Serializing a String)

アルゴリズム

  1. ASCII 文字シーケンスに変換します。失敗した場合、シリアライズは失敗します。
  2. %x00-1f または %x7f-ff 範囲の文字が含まれている場合、シリアライズは失敗します。
  3. DQUOTE (") を追加します。
  4. 各文字について:
    • 「\」または DQUOTE の場合、「\」を追加します
    • その文字を追加します
  5. DQUOTE を追加します。

4.1.7 Token のシリアライズ (Serializing a Token)

アルゴリズム

  1. ASCII 文字シーケンスに変換します。失敗した場合、シリアライズは失敗します。
  2. 最初の文字が ALPHA または「*」であることを確認します。
  3. 残りの文字が tchar、「:」、「/」のいずれかであることを確認します。
  4. input_token を返します。

4.1.8 Byte Sequence のシリアライズ (Serializing a Byte Sequence)

アルゴリズム

  1. 「:」を追加します。
  2. input_bytes の base64 エンコード([RFC4648] 第 4 節に従う)を追加します。
  3. 「:」を追加します。

4.1.9 Boolean のシリアライズ (Serializing a Boolean)

アルゴリズム

  1. 「?」を追加します。
  2. true の場合「1」を追加し、false の場合「0」を追加します。

4.2 構造化フィールドのパース (Parsing Structured Fields)

既知の構造化フィールドである HTTP フィールドを受信実装がパースする場合、相互運用性やセキュリティの問題を引き起こす可能性のある多くのエッジケースがあるため、注意が必要です。

メインアルゴリズム

選択されたフィールドの field-value を表すバイト配列 input_bytes(フィールドが存在しない場合は空)と field_type(「dictionary」「list」「item」のいずれか)が与えられた場合、パースされたヘッダー値を返します。

  1. input_bytes を ASCII 文字列 input_string に変換します。変換が失敗した場合、パースは失敗します。

  2. input_string の先頭のすべての SP 文字を破棄します。

  3. field_type が「list」の場合、「List のパース」(第 4.2.1 節)を実行した結果を output とします。

  4. field_type が「dictionary」の場合、「Dictionary のパース」(第 4.2.2 節)を実行した結果を output とします。

  5. field_type が「item」の場合、「Item のパース」(第 4.2.3 節)を実行した結果を output とします。

  6. input_string の先頭のすべての SP 文字を破棄します。

  7. input_string が空でない場合、パースは失敗します。

  8. それ以外の場合、output を返します。

重要な原則

  • 厳格なパース: エラーはフィールド全体が無視される原因となります
  • エラー耐性なし: 不正な形式の入力を「修正」しようとしません
  • セキュリティ優先: インジェクション攻撃と曖昧さを防ぎます

パースが失敗した場合(他のアルゴリズムを呼び出す場合を含む)、フィールド値全体を無視しなければなりません (MUST)(つまり、そのセクションにそのフィールドが存在しないものとして扱います)。


4.2.1 List のパース (Parsing a List)

ASCII 文字列 input_string が与えられた場合、(item_or_inner_list, parameters) タプルの配列を返します。

アルゴリズム

  1. members を空の配列とします。

  2. input_string が空でない間:

    • 「Item または Inner List のパース」(第 4.2.1.1 節)の結果を members に追加します
    • input_string の先頭のすべての OWS 文字を破棄します
    • input_string が空の場合、members を返します
    • input_string の最初の文字を消費します。「,」でない場合、パースは失敗します
    • input_string の先頭のすべての OWS 文字を破棄します
    • input_string が空の場合、末尾のカンマがあります。パースは失敗します
  3. 構造化データが見つかりません。members(空)を返します。


4.2.2 Dictionary のパース (Parsing a Dictionary)

ASCII 文字列 input_string が与えられた場合、値が (item_or_inner_list, parameters) タプルの有順序マップを返します。

注意: 重複した Dictionary キーが見つかった場合、最後のインスタンス以外はすべて無視されます。


4.2.3 Item のパース (Parsing an Item)

ASCII 文字列 input_string が与えられた場合、(bare_item, parameters) タプルを返します。

アルゴリズム

  1. 「Bare Item のパース」(第 4.2.3.1 節)の結果を bare_item とします。
  2. 「Parameters のパース」(第 4.2.3.2 節)の結果を parameters とします。
  3. タプル (bare_item, parameters) を返します。

4.2.4 Integer または Decimal のパース (Parsing an Integer or Decimal)

注意: このアルゴリズムは Integer(第 3.3.1 節)と Decimal(第 3.3.2 節)の両方をパースし、対応する構造を返します。


4.2.7 Byte Sequence のパース (Parsing a Byte Sequence)

実装上の注意事項

  • 一部の base64 実装では「=」パディングが正しくないエンコードデータを拒否できないため、パーサーは「=」パディングが存在しない場合に失敗すべきではありません (SHOULD NOT)。
  • パーサーは base64 アルファベット外の文字とエンコードデータ内の改行文字で失敗しなければなりません (MUST)。

完全なシリアライズ例

List の例

// 入力
[
(42, {a: 1}),
("foo", {}),
([1, 2], {b: true})
]

// 出力
"42;a=1, foo, (1 2);b"

Dictionary の例

// 入力
{
key1: (42, {a: 1}),
key2: (true, {}),
key3: ([1, 2], {})
}

// 出力
"key1=42;a=1, key2, key3=(1 2)"

Item の例

// 入力
(42, {foo: "bar", flag: true})

// 出力
"42;foo=\"bar\";flag"

重要なポイント (Key Takeaways)

シリアライズ

  1. 空値の処理: 空の List と Dictionary はシリアライズされません(フィールド全体を省略)
  2. Boolean の省略形: true 値は「=value」部分を省略します
  3. 厳格なフォーマット: 各型には正確なフォーマット要件があります
  4. 失敗即停止: 検証の失敗はシリアライズ全体を即座に失敗させます