[5] [DFN[[CODE(HTTP)@en[[[If-Range:]]]]]] [[ヘッダー]]は、
[[範囲要求]]を適用するべき条件を示すものです。

;; [22] この[[ヘッダー]]の値は、[[ヘッダー名]]からの想像に反して、
[[範囲]]に関する条件ではなく、[[範囲要求]]の前提条件を記述します。

* 仕様書

[REFS[
- [3] '''[CITE@en[RFC 7233 - Hypertext Transfer Protocol (HTTP/1.1): Range Requests]] ([TIME[2014-09-11 09:57:55 +09:00]] 版) <https://tools.ietf.org/html/rfc7233#section-3.2>'''
- [1] [CITE@en[RFC 7232 - Hypertext Transfer Protocol (HTTP/1.1): Conditional Requests]] ([TIME[2014-09-11 10:02:44 +09:00]] 版) <https://tools.ietf.org/html/rfc7232#section-3.5>
]REFS]

* 意味

[4] [CODE(HTTP)@en[[[If-Range:]]]] [[ヘッダー]]は、
[[選択された表現]]について[[範囲要求]]を適用するべきかどうか判断する条件を指定するものです。

;; [6] [[クライアント]]が既に[[表現]]の一部を保有しており、
他の部分も取得したいと思った時、 [CODE(HTTP)@en[[[If-Unmodified-Since:]]]]
や [CODE(HTTP)@en[[[If-Match:]]]] を使った[[条件付き要求]]と
[CODE(HTTP)@en[[[Range:]]]] を併用することで、
同じ[[表現]]の別の部分であることを保証できます。しかし、
[[鯖]]側で既に[[表現]]が変更されている場合、これらの[[ヘッダー]]だと[[条件付き要求]]は失敗してエラーが返されます。
新しい[[表現]]の全体を取得したい時は、改めて[[要求]]しなければなりません。
[CODE(HTTP)@en[[[If-Range:]]]] は、条件を満たさない時にエラーではなく[[表現]]の全体を送信するよう求めるものです。 [SRC[>>3]]

* 構文

[7] [CODE(HTTP)@en[[[If-Range:]]]] [[ヘッダー]]の値は、
[[実体タグ]]か[[HTTPの日時形式]]のいずれかです [SRC[>>3]]。

[FIG(railroad)[
= |
== [[実体タグ]]
== [[HTTPの日時形式]]
]FIG]

[10] [[クライアント]]は、弱い[[実体タグ]]を[[生成]]しては[['''なりません''']] [SRC[>>3]]。

[11] [[クライアント]]は、元の[[表現]]に[[実体タグ]]が含まれていなかった場合で、
日時が[[強い検証子]]だった場合を除き、 [CODE(HTTP)@en[[[If-Range:]]]]
[[ヘッダー]]に日時を指定しては[['''なりません''']] [SRC[>>3]]。

* 文脈

[8] [[クライアント]]は、 [CODE(HTTP)@en[[[Range:]]]] [[ヘッダー]]のない[[要求]]で
[CODE(HTTP)@en[[[If-Range:]]]] [[ヘッダー]]を[[生成]]しては[['''なりません''']] [SRC[>>3]]。

* 処理モデル

[9] [[条件付き要求]]を参照してください。

[12] [CODE(HTTP)@en[[[If-Range:]]]] [[ヘッダー]]の事前条件の評価は、
次のように行わなければ[['''なりません''']] [SRC[>>3]]。

[FIG(steps)[
= [13] [[実体タグ]]が指定されている場合、
== [14] [[選択された表現]]の[[実体タグ]]と[[強い比較]]を行います。
== [17] 一致すれば、[[真]]を返します。
== [18] 一致しなければ、[[偽]]を返します。
= [15] 日時が指定されている場合、
== [16] [[強い検証子]]でなければ[[偽]]を返します。
== [21] [[選択された表現]]の最終更新日時と比較します。
== [19] 完全に一致すれば、[[真]]を返します。
== [20] 一致しなければ、[[偽]]を返します。
]FIG]

;; [23] [CODE(HTTP)@en[[[Last-Modified:]]]] の比較は、
[CODE(HTTP)@en[[[If-Unmodified-Since:]]]] とは違って完全一致が求められます [SRC[>>3]]。

* 歴史

[FIG(quote)[
[FIGCAPTION[
[2] RFC 2068・2616 (HTTP/1.1) 14.27 If-Range
]FIGCAPTION]

> If a client has a partial copy of an entity in its cache, and wishes
to have an up-to-date copy of the entire entity in its cache, it
could use the Range request-header with a conditional GET (using
either or both of If-Unmodified-Since and If-Match.) However, if the
condition fails because the entity has been modified, the client
would then have to make a second request to obtain the entire current entity-body.

[[クライアント]]がその[[キャッシュ]]に[[実体]]の部分複製を持っており、
そのキャッシュに最新の完全な実体の複製を有したいと思ったら、
[CODE(HTTP)[[[Range]]]] 要求頭を
[[条件付GET]] ([CODE(HTTP)[[[If-Unmodified-Since]]]] と [CODE(HTTP)[[[If-Match]]]] の一方または両方を使用)
で使うことができます。しかし、実体が修正されていたがために条件が失敗したら、
クライアントは現在の完全な[[実体本体]]を得るために二番目の要求を行わなければなりません。

> The If-Range header allows a client to "short-circuit" the second
request. Informally, its meaning is `if the entity is unchanged, send
me the part(s) that I am missing; otherwise, send me the entire new
entity[INS[']].[DEL[']]

[CODE(HTTP)[If-Range]] 頭を使うと、クライアントは二番目の要求を「短絡」
できます。非公式には、この意味は「もし実体が変更されていなければ、
私が持っていない部分(群)を送ってください。そうでなければ、
新しい実体全体を送ってください。」です。

>
- If-Range = "If-Range" ":" ( entity-tag | HTTP-date )

> If the client has no entity tag for an entity, but does have a Last-Modified date, it [DEL[may]] [INS[MAY]] use that date in a[INS[n]] If-Range header. (The
server can distinguish between a valid HTTP-date and any form of
entity-tag by examining no more than two characters.) The If-Range
header [DEL[should]] [INS[SHOULD]] only be used together with a Range header, and [DEL[must]] [INS[MUST]] be
ignored if the request does not include a Range header, or if the
server does not support the sub-range operation.

クライアントが実体の[[実体札]]を持っていないものの、
[CODE(HTTP)[[[Last-Modified]]]] 日付は持っている場合は、
この日付を [CODE(HTTP)[If-Range]] 頭で使っても'''構いません'''。
([[サーバー]]は、妥当な [CODE(ABNF)[[[HTTP-date]]]] と任意の書式の
[CODE(ABNF)[[[entity-tag]]]] を高々2文字検査すれば区別できます。 [INS[(訳注: [CODE(ABNF)[entity-tag]] は必ず [CODE(HTTP)[W/"]] または [CODE(HTTP)["]] で始まります。 [CODE(HTTP)[HTTP-date]] は必ず英数字で始まりますが、紛らわしいのは [CODE(HTTP)[Wed]] で始まる場合だけです。)]])
[CODE(HTTP)[If-Range]] 頭は [CODE(HTTP)[Range]] 頭と一緒でのみ使用する'''べき'''であり、要求が
[CODE(HTTP)[Range]] 頭を含んでいない場合やサーバーは部分範囲操作に対応していない場合には無視しなければ'''なりません'''。

> If the entity tag given in the If-Range header matches the current
entity tag for the entity, then the server [DEL[should]] [INS[SHOULD]] provide the
specified sub-range of the entity using a 206 (Partial content)
response. If the entity tag does not match, then the server [DEL[should]] [INS[SHOULD]]
return the entire entity using a 200 (OK) response.

[CODE(HTTP)[If-Range]] 頭に与えられた実体頭がその実体の現在の実体札と一致する時は、
サーバーはその実体の指定された部分範囲を [CODE(HTTP)[[[206]]]] (部分内容)
[[応答]]を使って提供する'''べきです'''。実体札が一致しなければ、
サーバーは [CODE(HTTP)[[[200]]]] (了解) 応答を使って実体全体を返す'''べきです'''。
]FIG]

[24] [CITE@en[Allow range header to be set by APIs by jakearchibald · Pull Request #560 · whatwg/fetch]]
([TIME[2018-06-01 22:07:44 +09:00]])
<https://github.com/whatwg/fetch/pull/560>

[25] [CITE@en[Allow range header to be set by APIs by jakearchibald · Pull Request #560 · whatwg/fetch]]
([TIME[2018-06-01 22:07:44 +09:00]])
<https://github.com/whatwg/fetch/pull/560>