conditional request

条件付き要求 (HTTP)

[8] 事前条件の指定がある要求のことを、条件付き要求 (conditional request) といいます。 は事前条件が満たされる場合には要求メソッドで指定された処理を対象資源に対して実行しますが、 事前条件が満たされなければ処理は実行せずにエラーを返します。

[9] 条件付き要求は、キャッシュより新しい場合のみ資源を取得したい時や、 他者の編集との衝突に注意しつつにある資源を更新したい時などに使われます。

仕様書

意味

[4] 条件付き要求 (conditional request) は、 対象資源要求メソッド意味を適用する前に確認されるべき事前条件を示すヘッダーをいくつか含む要求です >>3 1.

[7] 事前条件として記述される資源のメタデータのことを、検証子といいます >>3 2.

条件付きヘッダー

[2] 次の要求ヘッダー条件付き (conditional) に分類されています >>1

[11] これらは RFC 7232 では事前条件 (precondition) >>10 ヘッダーと呼ばれています。
[109] If-Range:Range: とは別物で、 Range:範囲要求用なので条件付きではありません。

[99] RFC 4918>>2 に加えて次のヘッダー条件付き (conditional) に分類しています >>100RFC 723x はなぜかこれらに言及していませんが、分類名やヘッダーの性格から、 RFC 723x における「条件付き」と RFC 4918 の「条件付き」 は同じ分類と考えても良さそうです。

[105] 一覧の JSON データがあります。

[108] ヘッダー名の一覧を取得するには:

$ curl -fL https://raw.githubusercontent.com/manakai/data-web-defs/master/data/headers.json | ./jq '.headers | map(select(.http.conditional)) | map (.name)'

文脈

[67] 条件付き要求は、次の場面で使われます。

クライアントの処理モデル

[37] クライアント生成する各ヘッダーの構文的要件については、 各ヘッダーの項を参照。

[38] 鯖の処理モデルの項の通り、条件付き要求に対応する必要はないので、 クライアントは条件が無視されて通常の応答が返された場合にも対処できる必要があります。

[69] 検証のためにキャッシュ条件付き要求を行う場合は、 次のように処理します。

  1. [70] 要求転送します。
  2. [71] 応答304 だった場合、
    1. [72] 蓄積された応答を更新します >>73
    2. [54] 更新した後の蓄積された応答を再利用します >>35, >>73
  3. [74] 応答5xx だった場合、 以前蓄積された応答を再利用して構いません >>73
  4. [75] それ以外の場合 >>73
    1. [76] 蓄積された応答を新しいもので置換して構いません。
    2. [77] 新しい応答を再利用します。

[78] キャッシュ304 応答を受信した場合 (検証以外も含みます。) には、次のように処理します。

  1. [84] 新しい応答強い検証子を含む場合は、
    1. [85] 同じ強い検証子を持つ蓄積された応答すべてを (あれば) 選択します >>83
  2. [86] そうでなく新しい応答弱い検証子を含む場合で、 同じ弱い検証子を持つ蓄積された応答がある場合は、
    1. [87] そのうち最新のもののみを選択します >>83
  3. [88] そうでない場合で、蓄積された応答が1つだけあり、 検証子が含まれない場合には、
    1. [89] その蓄積された応答を選択します >>83
  4. [90] 選択した蓄積された応答があれば、それぞれについて、
    1. [91] 警告符号 1xxWarning: ヘッダー蓄積された応答から削除します >>83
    2. [92] 304 応答に含まれるWarning: 以外のヘッダーについて、 蓄積された応答の対応するヘッダーを置き換えます >>83
  5. [80] 外向きクライアント条件付き要求を作成した場合、 例えばキャッシュを持つ利用者エージェント共有串条件付きGET を送信した場合には、304 応答をそのクライアント転送するべきです >>79
  6. [82] そうでない場合は、更新した蓄積された応答転送します。
[81] なぜ >>80SHOULD でしかないのかは不明です。
[94] 元の蓄積された応答に含まれないヘッダー304 応答に含まれる場合の処理は明記されていませんが、 蓄積された応答に追加するべきと思われます。
[98] 範囲要求の場合の処理モデル (応答の結合方法) と似ています。

鯖の処理モデル

[45] 受信者であるキャッシュ起源鯖は、 要求を次のように処理しなければなりません >>18, >>29

  1. [22] 要求をチェックし、必要があればエラーの応答を返したり、 リダイレクト応答を返したりします。その場合ここで終わります。 >>18
  2. [24] 要求メソッド選択された表現の選択や編集に関わるものである場合 (>>27) 以外は、 そのメソッドの規定に従い処理し、ここで終わります >>18
  3. [39] 選択された表現を決定します。存在しないこともあります。
    1. [62] 起源鯖においては、実装・対象資源依存の方法で決定します。
    2. [65] キャッシュにおいては、キャッシュ項目として蓄積された応答を使って決定します。詳細はキャッシュ項目を参照。 その過程で応答を返した場合は、ここで終わります。
  4. [46] 受信者対象資源起源鯖である場合 >>18, >>29, >>35
    1. [52] 要求If-Match: ヘッダーがある場合 >>12, >>29、 その評価結果がなら、
      1. [50] >>19 の場合は 2xx を返して終わっても構いません。
      2. [51] そうしないなら、 412 を返して終わります。
    2. [53] 要求If-Match: ヘッダーがなく、 If-Unmodified-Since: ヘッダーがある場合、 >>29, >>25 その評価結果がなら、
      1. [56] >>19 の場合は 2xx を返して終わっても構いません。
      2. [57] そうしないなら、 412 を返して終わります。
  5. [26] 受信者対象資源起源鯖である場合やキャッシュとして動作する場合 >>18, >>29, >>35
    1. [48] 要求If-None-Match: ヘッダーがある場合 >>21, >>29、 評価結果がなら、
      1. [59] 要求メソッドGETHEAD なら、 304 を返して終わります。
      2. [60] それ以外なら、 412 を返して終わります。
    2. [61] 要求If-None-Match: ヘッダーがなく >>29, >>14If-Modified-Since: ヘッダーがある場合、 その評価結果がなら、
      1. [64] 要求メソッドGETHEAD なら、 304 を返して終わります >>29, >>14
    3. [55] 要求If-Range: ヘッダーがあり、 その評価結果がなら、 >>28, >>29
      1. [66] 要求メソッドGET なら、 Range: ヘッダーがあればそれを処理して 206 を返して終わって構いません。 (範囲要求を参照。)
  6. [63] 事前条件は一致したので、要求の他の指定に従って処理し、結果を返します。
    1. [31] 要求メソッドGET なら、 If-Range: ヘッダーがなく Range: ヘッダーがあればそれを処理して 206 を返して終わって構いません。 >>28 (範囲要求を参照。)
    2. [33] それ以外なら、 2xx を返します。
[13] 条件を満たすかどうかの判定については、各ヘッダーの項を参照してください。
[36] >>26>>35 ではキャッシュSHOULD としていますが、 これは一般に条件付き要求MAY なのに対しキャッシュでは SHOULD なのだと行間から推測されます。
[23] >>64>>14 ではなぜか SHOULD とされており、 >>29MUST と矛盾します。両方の要件を満たすには、 MUST と解釈するしかありません。
[34] >>66 Range: の処理は、なぜか MUST ではなく SHOULD となっています >>28206 を実装しないことが認められているので MUST なのかもしれませんが、 詳細不明です。
[58] >>54>>35 によると 200 応答を返すことになっていますが、 範囲要求なら [206 を返しても良いのでしょうか?

[27] 事前条件は選択された表現の選択や編集に関わる要求メソッド以外では無視する >>18 とされています。無視するべきメソッドとして CONNECTOPTIONSTRACE が挙げられています >>18 が、 完全なリストはなぜか提供されていません。

[40] ヘッダーの優先順位の根拠は次のように説明されています >>29

[20] If-Match:If-Unmodified-Since:起源鯖のみが処理し、キャッシュは無視することになっています >>12, >>25 が、 If-None-Match:If-Modified-Since:起源鯖だけでなくキャッシュも処理することになっています。

[41] If-Match:If-None-Match:If-Modified-Since:If-Unmodified-Since: を実装していない場合どう動作するべきか仕様上明確ではありませんが、 実際のはこれらを無視するようです。 (412304 ではありません。)

[16] 受信者は、 If-Modified-Since:If-Unmodified-Since: が妥当な HTTP-date でないとき、これを無視しなければなりません >>14, >>25

[32] If-Match:If-None-Match:If-Range: が構文的に正しくない時にどう処理するべきかは、 なぜか規定がありません。
[15] 無視ということは、条件の真偽を判断する以前に存在しないものと扱うのだと思われます。

[30] If-Range: ヘッダーは、 Range: ヘッダーが含まれていなければ無視しなければなりません >>29

[17] 同じヘッダーが複数ある時にどう処理するべきかはなぜか規定がありません。

[19] >>50>>562xx を返せるのは、状態の変更が要求されており、 最終的な状態が既に対象資源の現在の状態に反映されていると起源鯖が確認できる場合です。 すなわち、以前の応答が失われたか互換性のある変更が他の利用者エージェントにより行われたかによって利用者エージェント要求が既に成功していたことに気づいていないような場合です。 ただしそのような場合には、同じ利用者エージェントが直前の要求を繰り返していると確認できる場合を除き、 検証子ヘッダーを送ってはなりません >>12, >>25

[103] サーバーは、条件付要求のみを受け付けることにできます。 条件付要求でない要求を受け取ったら、 428 応答を返すことができます。

メモ

[413] Add cache mode concept and elaborate a bit on caching. · 99377cd · whatwg/fetch ( ( 版)) <https://github.com/whatwg/fetch/commit/99377cd334e7e4e7737c2b2fd521c74a6cf7e01a>

[101] Close #141: fix 304 handling · whatwg/fetch@1a2f6b4 ( 版) <https://github.com/whatwg/fetch/commit/1a2f6b49d616cfd74536c1a8dbed8b5c1215d548>

[102] Merge conditionals in 304 handling · whatwg/fetch@bb9313f ( 版) <https://github.com/whatwg/fetch/commit/bb9313fc04b91c10639a3d5f5454cb2a6f224b45>

[104] Understanding Conditional Requests and Refresh | IEInternals ( ()) <https://blogs.msdn.microsoft.com/ieinternals/2010/07/08/understanding-conditional-requests-and-refresh/>