13. Conditional Requests (条件付きリクエスト)
条件付きリクエストとは、ターゲットリソースにリクエストメソッドを適用する前にテストされる前提条件を示す1つ以上のリクエストヘッダーフィールドを含むHTTPリクエストです。セクション13.2では、前提条件がいつ評価されるか、および複数の前提条件が存在する場合の優先順位を定義しています。
条件付きGETリクエストは、HTTPキャッシュ更新のための最も効率的なメカニズムです[CACHING]。条件はPUTやDELETEなどの状態変更メソッドにも適用でき、「失われた更新」問題を防止できます。これは、あるクライアントが並行して動作している別のクライアントの作業を誤って上書きすることを防ぎます。
13.1. Preconditions (前提条件)
前提条件は通常、ターゲットリソース全体の状態(その現在の値セット)または以前に取得された表現で観察された状態(そのセット内の1つの値)に関して定義されます。リソースに複数の現在の表現があり、それぞれが独自の観察可能な状態を持つ場合、前提条件は、各リクエストから選択された表現へのマッピング(セクション3.2)が時間的に一貫していることを想定します。いずれにしても、マッピングが一貫していない場合、またはサーバーが適切な表現を選択できない場合、前提条件がfalseと評価されても害はありません。
以下で定義される各前提条件には、ターゲットリソースの以前の表現から取得されたバリデータのセットと、選択された表現のバリデータの現在の状態(セクション8.8)との比較が含まれます。したがって、これらの前提条件は、ターゲットリソースの状態がクライアントに既知の特定の状態から変更されたかどうかを評価します。そのような評価の効果は、セクション13.2で定義されているメソッドのセマンティクスと条件の選択に依存します。
他の仕様によって拡張フィールドとして定義された他の前提条件は、すべての受信者、ターゲットリソースの一般的な状態、またはリソースのグループに条件を課す場合があります。例えば、WebDAVの「If」ヘッダーフィールドは、受信者がそのフィールドを理解して実装している場合、ロックなどの複数のリソースのさまざまな側面に基づいてリクエストを条件付きにすることができます([WEBDAV]、セクション10.4)。
前提条件の拡張性は、前提条件が未知の場合に安全に無視できる場合(If-Modified-Sinceなど)、特定のユースケースに対してデプロイメントが想定できる場合、またはターゲットリソースの他のプロパティによって実装がシグナル化される場合にのみ可能です。これにより、共有デプロイメントを持つ共通の標準に焦点を当てることが奨励されます。
13.1.1. If-Match
「If-Match」ヘッダーフィールドは、受信者オリジンサーバーがターゲットリソースの少なくとも1つの現在の表現を持っている(フィールド値が「*」の場合)、またはフィールド値で提供されたエンティティタグのリストのメンバーと一致するエンティティタグを持つターゲットリソースの現在の表現を持っていることを条件としてリクエストメソッドを実行します。
オリジンサーバーは、If-Matchのエンティティタグを比較する際に強い比較関数を使用しなければなりません(MUST)(セクション8.8.3.2)。クライアントは、表現データに変更があった場合にこの前提条件がメソッドの適用を阻止することを意図しているためです。
If-Match = "*" / #entity-tag
例:
If-Match: "xyzzy"
If-Match: "xyzzy", "r2d2xxxx", "c3piozzzz"
If-Match: *
If-Matchは、複数のユーザーエージェントが同じリソースに対して並行して動作する可能性がある場合の偶発的な上書きを防ぐために、状態変更メソッド(例:POST、PUT、DELETE)と最もよく使用されます(つまり、「失われた更新」問題を防ぐため)。一般的には、選択された表現の現在のエンティティタグがIf-Matchフィールド値内のメンバーでない場合にリクエストを中止するために、表現の選択または変更を伴う任意のメソッドで使用できます。
オリジンサーバーが表現を選択するリクエストを受信し、そのリクエストにIf-Matchヘッダーフィールドが含まれている場合、オリジンサーバーはメソッドを実行する前にセクション13.2に従ってIf-Match条件を評価しなければなりません(MUST)。
受信したIf-Matchヘッダーフィールドを評価するには:
-
フィールド値が「*」の場合、オリジンサーバーがターゲットリソースの現在の表現を持っている場合、条件はtrueです。
-
フィールド値がエンティティタグのリストの場合、リストされたタグのいずれかが選択された表現のエンティティタグと一致する場合、条件はtrueです。
-
それ以外の場合、条件はfalseです。
If-Match条件を評価するオリジンサーバーは、条件がfalseと評価される場合、要求されたメソッドを実行してはなりません(MUST NOT)。代わりに、オリジンサーバーは412(Precondition Failed)ステータスコードで応答することにより、条件付きリクエストが失敗したことを示すことができます(MAY)。
または、リクエストがターゲットリソースで既に成功しているように見える状態変更操作である場合、If-Matchフィールド値にリストされた1つ以上のエンティティタグが選択された表現のエンティティタグと一致する場合、オリジンサーバーは2xx(Successful)ステータスコードで応答できます(MAY)(つまり、リソースの状態が既に期待されたものであるため、状態変更は既に成功しています)。
後でIf-Matchヘッダーフィールドを提供する予定のクライアントは、まず以前のリクエストで1つ以上のエンティティタグを取得すべきです(SHOULD)。通常は、表現のETagヘッダーフィールド(セクション8.8.3)から表現を取得することによって行われます。
13.1.2. If-None-Match
「If-None-Match」ヘッダーフィールドは、受信者オリジンサーバーがターゲットリソースの現在の表現を持っていない(フィールド値が「*」の場合)、またはフィールド値で提供されたもののいずれとも一致しないエンティティタグを持つターゲットリソースの現在の表現を持っていることを条件としてリクエストメソッドを実行します。
受信者は、If-None-Matchのエンティティタグを比較する際に弱い比較関数を使用しなければなりません(MUST)(セクション8.8.3.2)。弱いエンティティタグは、意味的に重要でない表現データへの変更があった場合でも、キャッシュ検証に使用できるためです。
If-None-Match = "*" / #entity-tag
例:
If-None-Match: "xyzzy"
If-None-Match: W/"xyzzy"
If-None-Match: "xyzzy", "r2d2xxxx", "c3piozzzz"
If-None-Match: W/"xyzzy", W/"r2d2xxxx", W/"c3piozzzz"
If-None-Match: *
If-None-Matchは主に2つの状況で使用されます:
-
GETまたはHEADと共に、エンティティタグを持たないキャッシュされた表現を更新するために使用します。オリジンサーバーがGETまたはHEADでIf-None-Matchのリクエストを受信した場合、セクション13.2に従って評価すべきです(SHOULD)。
-
他のメソッドと共に、既存の表現の不注意な変更を防ぐために使用します。リクエストが前提条件なしで表現の作成または置換以外の結果をもたらす場合、およびサーバーがそのリソースの現在の表現を持っている場合、クライアントはフィールド値が「*」のIf-None-Matchを送信すべきです(SHOULD)。
オリジンサーバーが表現を選択するリクエストを受信し、そのリクエストにIf-None-Matchヘッダーフィールドが含まれている場合、オリジンサーバーはメソッドを実行する前にセクション13.2に従ってIf-None-Match条件を評価しなければなりません(MUST)。
受信したIf-None-Matchヘッダーフィールドを評価するには:
-
フィールド値が「*」の場合、オリジンサーバーがターゲットリソースの現在の表現を持っている場合、条件はfalseです。
-
フィールド値がエンティティタグのリストの場合、リストされたタグのいずれかが選択された表現のエンティティタグと弱く一致する(セクション8.8.3.2)場合、条件はfalseです。
-
それ以外の場合、条件はtrueです。
If-None-Match条件を評価するオリジンサーバー:
-
リクエストメソッドがGETまたはHEADであり、条件がfalseと評価される場合、オリジンサーバーは304(Not Modified)レスポンスを生成すべきです(SHOULD)。
-
リクエストメソッドがGETまたはHEADでなく、条件がfalseと評価される場合、オリジンサーバーは412(Precondition Failed)レスポンスを生成しなければなりません(MUST)。
-
それ以外の場合(つまり、条件がtrue)、オリジンサーバーは通常通りリクエストを処理すべきです(SHOULD)。
13.1.3. If-Modified-Since
「If-Modified-Since」ヘッダーフィールドは、選択された表現の変更日がフィールド値で提供された日時よりも新しいことを条件としてGETまたはHEADリクエストメソッドを実行します。
If-Modified-Since = HTTP-date
例:
If-Modified-Since: Sat, 29 Oct 1994 19:43:31 GMT
受信者がオリジンサーバーであり、If-Modified-SinceがGETまたはHEADメソッドのリクエストヘッダーフィールドである場合、選択された表現のLast-Modified日付がIf-Modified-Sinceヘッダーフィールドで提供された日付以前または等しい場合、セクション13.2による評価が異なるレスポンスをもたらす場合を除き、受信者は304(Not Modified)レスポンスを送信すべきです(SHOULD)。
リクエストにIf-None-Matchヘッダーフィールドが含まれている場合、受信者はIf-Modified-Sinceを無視しなければなりません(MUST)。If-None-Matchの条件は、この場合If-Modified-Sinceの条件のより正確な置き換えと見なされ、2つの条件を独立して評価すると、それらの組み合わせの目的が妨げられます。
フィールド値で提供された日付が無効または将来の場合、受信者はIf-Modified-Sinceヘッダーフィールドを無視すべきです(SHOULD)。
13.1.4. If-Unmodified-Since
「If-Unmodified-Since」ヘッダーフィールドは、選択された表現の最終変更日がフィールド値で提供された日付以前または等しいことを条件としてリクエストメソッドを実行します。
If-Unmodified-Since = HTTP-date
例:
If-Unmodified-Since: Sat, 29 Oct 1994 19:43:31 GMT
受信者がオリジンサーバーであり、If-Unmodified-SinceがGETまたはHEAD以外のリクエストメソッドのリクエストヘッダーフィールドである場合、選択された表現のLast-Modified日付がIf-Unmodified-Sinceヘッダーフィールドで提供された日付以前または等しい場合、受信者は通常通りリクエストを処理すべきです(SHOULD)。それ以外の場合、セクション13.2による評価が異なるレスポンスをもたらす場合を除き、受信者は412(Precondition Failed)レスポンスを送信すべきです(SHOULD)。
リクエストにIf-Matchヘッダーフィールドが含まれている場合、受信者はIf-Unmodified-Sinceを無視しなければなりません(MUST)。If-Matchの条件は、この場合If-Unmodified-Sinceの条件のより正確な置き換えと見なされ、2つの条件を独立して評価すると、それらの組み合わせの目的が妨げられます。
フィールド値で提供された日付が無効または将来の場合、受信者はIf-Unmodified-Sinceヘッダーフィールドを無視すべきです(SHOULD)。
13.1.5. If-Range
「If-Range」ヘッダーフィールドは、Rangeリクエスト(セクション14)に特別な条件を提供します。提供されたバリデータが選択された表現の現在のバリデータと一致する場合、Rangeヘッダーフィールドを通常通り処理し、1つ以上の部分コンテンツを返します。バリデータが一致しない場合、Rangeヘッダーフィールドを無視し、完全な選択された表現を返します。
If-Range = entity-tag / HTTP-date
クライアントは、Rangeヘッダーフィールドを含まないリクエストでIf-Rangeヘッダーフィールドを生成してはなりません(MUST NOT)。
サーバーは、Rangeヘッダーフィールドを含まないリクエストで受信したIf-Rangeヘッダーフィールドを無視しなければなりません(MUST)。
If-Rangeの意図は、クライアントがキャッシュされた不完全な表現が古くなった場合に効率的に更新できるようにすることです。If-Rangeヘッダーフィールドが存在しない場合、不完全なキャッシュされた表現により、クライアントはそれを再検証(If-MatchまたはIf-Unmodified-Sinceを使用した条件付きリクエストを使用)し、再検証がまだ最新であることを示す場合にのみ欠落している部分を要求するか、キャッシュされた表現全体を置き換える必要があります。If-Rangeヘッダーフィールドにより、クライアントは単一のリクエストで現在の部分または完全な表現を要求することにより、この余分なラウンドトリップを回避できます。
サーバーは、フィールド値がエンティティタグの場合、強い比較関数(セクション8.8.3.2)を使用してIf-Range条件を評価します。フィールド値がHTTP-dateの場合、サーバーはそれを選択された表現のLast-Modifiedフィールド値と比較し、タイムスタンプ値が正確に等しい場合に一致します。
If-Rangeヘッダーフィールドは、If-Unmodified-SinceとLast-Modified日付、またはIf-Matchと強く一致するエンティティタグのいずれかと共にのみ使用すべきです(SHOULD)。
13.2. Evaluation of Preconditions (前提条件の評価)
13.2.1. When to Evaluate (いつ評価するか)
前提条件の定義で特に規定されていない限り、サーバーは、表現を選択するリクエストを受信したときに、メソッドを実行する前に受信したリクエスト前提条件を評価しなければなりません(MUST)。その評価はメソッドの実行に影響を与える可能性があるためです。
メソッドを実行する前に前提条件を評価することの1つの結果は、メソッドが既に実行を開始した後に受信した異なる前提条件は、その実行またはそのレスポンスセマンティクスに影響を与えないということです。
これらの前提条件は、異なる選択ステップで評価される場合があります。実際には、「選択された表現」のバリデータは、メソッドを実行する前に利用可能であることが多いため、前提条件は表現を作成または変更する前に評価できます。
13.2.2. Precedence of Preconditions (前提条件の優先順位)
単一のリクエストに複数の条件付きリクエストヘッダーフィールドが存在する場合、前提条件が適用される順序が重要になります。実際には、ターゲットリソースの状態で動作するフィールドは、If-MatchとともにIf-Unmodified-Sinceが使用される、またはIf-None-MatchとともにIf-Modified-Sinceが使用されるなど、一緒にデプロイされることがよくあります。ただし、前提条件ヘッダーフィールドの一貫性のない組み合わせが存在する可能性があります。
サーバーは、受信したリクエスト前提条件を次の順序で評価しなければなりません(MUST):
-
受信者がオリジンサーバーであり、If-Matchが存在する場合、If-Match前提条件を評価し、falseと評価される場合は412(Precondition Failed)ステータスコードで応答します。
-
受信者がオリジンサーバーであり、If-Matchが存在せず、If-Unmodified-Sinceが存在する場合、If-Unmodified-Since前提条件を評価し、falseと評価される場合は412(Precondition Failed)ステータスコードで応答します。
-
If-None-Matchが存在する場合、If-None-Match前提条件を評価し、falseと評価される場合は304(Not Modified)ステータスコード(GET/HEADの場合)または412(Precondition Failed)ステータスコード(他のメソッドの場合)で応答します。
-
受信者がオリジンサーバーであり、メソッドがGETまたはHEADであり、If-None-Matchが存在せず、If-Modified-Sinceが存在する場合、If-Modified-Since前提条件を評価し、falseと評価される場合は304(Not Modified)ステータスコードで応答します。
-
メソッドがGETであり、受信者がRangeヘッダーフィールドの有効なリクエストを持ち、If-Rangeが存在する場合、バリデータが選択された表現の現在のバリデータと一致する場合はRangeヘッダーフィールドを処理します。それ以外の場合は、Rangeヘッダーフィールドを無視し、200(OK)レスポンスと完全な選択された表現で応答します。
-
それ以外の場合、すべての条件が満たされているため、要求されたアクションを通常通り実行し、適切なレスポンスを生成します。
処理の結果として上記のレスポンスステータスコードのいずれかを生成するサーバーは、リクエストの起点が信頼されていない場合、レスポンスペイロードでターゲットリソースの状態の表現を生成すべきです(SHOULD)。
If-MatchおよびIf-Unmodified-Sinceヘッダーフィールドへの拡張は、一貫した動作を維持するために、この前提条件評価アルゴリズムを同等に更新する必要があります。