[2] [CODE(HTTP)@en[[[Range:]]]] が指定された[[要求]]を、[DFN[[RUBYB[[[範囲要求]]]@en[range request]]]]といいます。
[[範囲要求]]を使うと[[資源]]の一部分のみを[[バイト]]単位で指定して受信できます。

* 仕様書

[REFS[
- [1] [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>
-- [14] [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.1>
-- [61] [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-4.1>
-- [5] [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-4.3>
-- [40] [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-6.1>
- [81] [CITE@en[RFC 7234 - Hypertext Transfer Protocol (HTTP/1.1): Caching]] ([TIME[2014-09-11 10:19:59 +09:00]] 版) <https://tools.ietf.org/html/rfc7234#section-3.3>
- [86] [CITE@en[RFC 3229 - Delta encoding in HTTP]] ([TIME[2014-10-26 21:15:25 +09:00]] 版) <http://tools.ietf.org/html/rfc3229#section-10.1>
- [91] [CITE@en[RFC 3229 - Delta encoding in HTTP]] ([TIME[2014-10-26 21:15:25 +09:00]] 版) <http://tools.ietf.org/html/rfc3229#section-10.5.2>
- [98] [CITE@en[RFC 3229 - Delta encoding in HTTP]] ([TIME[2014-10-26 21:15:25 +09:00]] 版) <http://tools.ietf.org/html/rfc3229#section-10.10>
]REFS]

* プロトコル

[4] [[範囲要求]]は次の[[プロトコル要素]]により構成されます。

[FIG(list short)[
- [CODE(HTTP)@en[[[Range:]]]]
- [CODE(HTTP)@en[[[If-Range:]]]]
- [[範囲単位]]
- [CODE(HTTP)@en[[[Accept-Ranges:]]]]
- [CODE(HTTP)[[[206]]]]
- [CODE(HTTP)[[[416]]]]
- [CODE[456]]
- [CODE(HTTP)@en[[[Content-Range:]]]]
- [CODE(MIME)@en[[[multipart/byteranges]]]]
]FIG]

[85] [[範囲要求]]は [CODE(HTTP)@en[[[GET]]]] [[要求]]にのみ適用されます。
他の[[要求メソッド]]では使えません。

* 処理モデル

[3] [[範囲要求]]への対応は必須ではありません [SRC[>>1]]。[[範囲要求]]を受信した時、
これに対応していない場合は、通常の [CODE(HTTP)@en[[[GET]]]]
[[要求]]として処理して構いません [SRC[>>1]]。

[84] [[HTTP鯖]]の処理全体における位置付けは [[HTTP鯖]]の項を、
[[キャッシュ]]における取り扱い全体は[[キャッシュ項目]]の項を、
[[実現値操作]]との関係は[[実現値操作]]の項を参照してください。

** 範囲要求への応答

[42] [[鯖]]は、[[範囲要求]]を次のように処理しなければなりません。

[FIG(steps)[
= [41] [[条件付き要求]]なら、[[条件付き要求]]の処理の規定に従い条件を評価します。
それによって[[応答]]が決まるなら、ここで終わります。
= [45] [[鯖]]が [CODE(HTTP)@en[[[Range:]]]] [[ヘッダー]]に対応しないなら、
ここで終わり通常の方法で処理します [SRC[>>14]]。
= [43] [CODE(HTTP)@en[[[Range:]]]] [[ヘッダー]]がなければ、
[[範囲要求]]ではないので、ここで終わり通常の方法で処理します。
= [44] [[要求メソッド]]が [CODE(HTTP)@en[[[GET]]]] 以外なら、
[CODE(HTTP)@en[[[Range:]]]] [[ヘッダー]]は無視します [SRC[>>14]]。
ここで終わり通常の方法で処理します。
= [46] [CODE(HTTP)@en[[[Range:]]]] [[ヘッダー]]の[[範囲単位]]が対応しないものなら、
== [47] [[起源鯖]]は、 [CODE(HTTP)@en[[[Range:]]]] [[ヘッダー]]を無視します [SRC[>>14]]。
== [48] [[串]]は、 [CODE(HTTP)@en[[[Range:]]]] [[ヘッダー]]を捨てても構いません [SRC[>>14]]。
== [49] いずれにせよ、ここで終わり通常の方法で処理します。
= [53] [CODE(HTTP)@en[[[Range:]]]] [[ヘッダー]]の値を[[範囲単位]]ごとの構文に従い解釈します。
= [54] 3つ[[以上]]の重複する範囲を含む [CODE(HTTP)@en[[[Range:]]]]
[[ヘッダー]]や、多数の[[昇順]]でない小さな範囲を指定した [CODE(HTTP)@en[[[Range:]]]]
[[ヘッダー]]を無視したり、拒絶したりして構いません [SRC[>>14]]。
=- [55] これらを送信した[[クライアント]]は壊れているのかもしれませんし、
[[DoS攻撃]]かもしれません。 [SRC[>>14, >>40]]
== [56] 拒絶する場合は、 [CODE(HTTP)[[[416]]]] [[応答]]を返してここで終わります。
== [57] 無視する場合は、ここで終わり通常の方法で処理します。
= [60] 指定された範囲が[[非妥当]]か[[満足不能]]なら、
[CODE(HTTP)[[[416]]]] [[応答]]を返してここで終わります [SRC[>>14]]。
= [59] 指定された範囲が[[妥当]]で[[満足可能]]なら、
[[満足可能]]な[[範囲]]に対応する1つ以上の部分[[表現]]を含む [[payload]]
をもった [CODE(HTTP)[[[206]]]] [[応答]]を送信します [SRC[>>14]]。
== [71] 複数の範囲が指定されていた場合に、範囲の指定の順序に関わらず、
重なり合う範囲をまとめたり、 [[multipart]] 
による[[オーバーヘッド]]より隙間が小さいときにまとめたりしても構いません。 [SRC[>>61]]
==- [72] 一般的には [CODE(MIME)@en[[[multipart/byteranges]]]] の[[オーバーヘッド]]は
80バイト程度です。 [SRC[>>61]]
==- [73] >>54 の [[DoS攻撃]]への対策にもなります。
== [75] [CODE(MIME)@en[[[multipart/byteranges]]]] を使うか判断します。
=== [76] [CODE(HTTP)@en[[[Range:]]]] [[ヘッダー]]で指定された範囲が1つの時は、
使用しません [SRC[>>61]]。
=== [77] >>71 の場合は、どちらでも構いません [SRC[>>61]]。
=== [78] それ以外の場合は、使用します [SRC[>>61]]。
== [63] [CODE(MIME)@en[[[multipart/byteranges]]]] を使用する時は、
=== [66] 各範囲を[[本体部分]]とする [CODE(MIME)@en[[[multipart/byteranges]]]] を
[[payload]] に含めます [SRC[>>61]]。
==== [68] 範囲を指定した [CODE(HTTP)@en[[[Content-Range:]]]]
[[ヘッダー]]を[[本体部分]]に含めます [SRC[>>61]]。
==== [70] [[選択された表現]]が [CODE(HTTP)[[[200]]]] [[応答]]だった場合の[[応答]]の
[CODE(HTTP)@en[[[Content-Type:]]]] [[ヘッダー]]と同じ値の
[CODE(HTTP)@en[[[Content-Type:]]]] [[ヘッダー]]を[[本体部分]]に含める[['''べきです''']]
[SRC[>>61]]。
==== [69] 範囲のデータを[[本体部分]]の[[実体本体]]に含めます。
==- [74] [[満足不能]]な[[範囲]]や他の[[範囲]]とまとめた場合 (>>71) を除き、
[CODE(HTTP)@en[[[Range:]]]] に指定された順序で[[本体部分]]を並べる[['''べきです''']] [SRC[>>61]]。
==- [67] [[応答]]の[[ヘッダー]]としては [CODE(HTTP)@en[[[Content-Range:]]]]
を[[生成]]しては[['''なりません''']] [SRC[>>61]]。
== [62] それ以外の場合、
=== [64] 範囲を指定した [CODE(HTTP)@en[[[Content-Range:]]]]
[[ヘッダー]]を[[生成]]します [SRC[>>61]]。
=== [65] 範囲のデータを [[payload]] に含めます [SRC[>>61]]。
]FIG]

;; [51] [CODE(HTTP)@en[[[Range:]]]] [[ヘッダー]]が複数指定された時の動作は規定されていません。

;; [58] [CODE(HTTP)@en[[[Range:]]]] [[ヘッダー]]の値が構文的に正しくない場合の動作は規定されていません。

;; [52] [[起源鯖]]と中間[[キャッシュ]]は可能なら[[バイト範囲]]に対応する[RUBYB[べき]@en[ought to]]です [SRC[>>14]]。

;; [50] >>60 と >>59 はなぜか [['''MUST''']] ではなく [['''SHOULD''']]
です [SRC[>>14]]。 >>54 や >>45 の場合を考慮してなのかもしれませんが、
説明がないのでよくわかりません。また妥当・満足可能な範囲と非妥当・満足不能な範囲が混在する時、
どちらを返すべきかは不明瞭です。

;; [79] [CODE(HTTP)[[[206]]]] や [CODE(HTTP)[[[416]]]] の[[応答]]の[[ヘッダー]]については、
それぞれの項も参照してください。

;; [107] 
[[RTSP]]
では[[範囲要求]]が適用不能なときに
[CODE[456]]
を返せます。

** 部分応答の結合

[7] [[クライアント]]は、
[[HTTP接続]]が閉じられるのが早すぎた場合 ([[不完全]]な [CODE(HTTP)[[[200]]]] [[応答]])や、
[[範囲要求]]によって[[応答]]を得た場合 ([CODE(HTTP)[[[206]]]] [[応答]]) に、
同じ[[強い検証子]]を持っていればそれらを安全に組み合わせることができます [SRC[>>5, >>81]]。

[8] 結合した[[応答]]は次のように決めます。
[FIG(steps)[
= [13] 蓄積されている[[応答]]と新しい[[応答]]で[[強い検証子]]が一致するもの
([CODE(HTTP)[[[200]]]] [[応答]]と [CODE(HTTP)[[[206]]]] [[応答]]) を集めます。
= [10] 集めた[[応答]]のいずれかが [CODE(HTTP)[[[200]]]] [[応答]]なら、
== [20] 最新の [CODE(HTTP)[[[200]]]] [[応答]]の各[[ヘッダー]]を結合した[[応答]]の[[ヘッダー]]とします。 [SRC[>>51]]
== [82] [[警告符号]]が [CODE(HTTP)[[[1xx]]]] の [CODE(HTTP)@en[[[Warning:]]]]
[[ヘッダー]]があれば、削除します。 [SRC[>>81]]
= [21] そうでない場合 (いずれも [CODE(HTTP)[[[206]]]] [[応答]]の場合)、
== [22] 蓄積されている最新の[[応答]]の各[[ヘッダー]]を結合した[[応答]]の[[ヘッダー]]とします。
[SRC[>>51]]
== [23] 新しい[[応答]]の[[ヘッダー]]で結合した[[応答]]の各[[ヘッダー]]で結合した[[応答]]の[[ヘッダー]]を置き換えます。ただし [CODE(HTTP)@en[[[Content-Range:]]]] [[ヘッダー]]は除きます。
[SRC[>>51, >>81]]
== [83] [[警告符号]]が [CODE(HTTP)[[[1xx]]]] の [CODE(HTTP)@en[[[Warning:]]]]
[[ヘッダー]]があれば、削除します。 [SRC[>>81]]
= [39] 集めた[[応答]]から元のデータの復元を試みます。
= [15] データの全体が復元できた場合、
== [9] 結合した[[応答]]の[[状態符号]]は [CODE(HTTP)[[[200]]]] とします。 [SRC[>>5]]
== [12] 結合した[[応答]]の [CODE(HTTP)@en[[[Content-Length:]]]] 
[[ヘッダー]]は得られたデータの長さとします。 [SRC[>>5]]
== [38] 結合した[[応答]]の [CODE(HTTP)@en[[[Transfer-Type:]]]] [[ヘッダー]]は適切に設定します。
== [27] 結合した[[応答]]の [CODE(HTTP)@en[[[Transfer-Encoding:]]]] [[ヘッダー]]は削除します。
== [16] 結合した[[応答]]の[[メッセージ本体]]は得られたデータとします。
= [19] 全体にはならなかった場合、
== [18] 得られたデータが元のデータの最初の部分だった時は、次のようにして構いません。
=== [24] 結合した[[応答]]の[[状態符号]]は [CODE(HTTP)[[[200]]]] とします。 [SRC[>>5]]
=== [25] 結合した[[応答]]の [CODE(HTTP)@en[[[Content-Length:]]]] 
[[ヘッダー]]は得られたデータの長さとします。 [SRC[>>5]]
=== [37] 結合した[[応答]]の [CODE(HTTP)@en[[[Transfer-Type:]]]] [[ヘッダー]]は適切に設定します。
=== [28] 結合した[[応答]]の [CODE(HTTP)@en[[[Transfer-Encoding:]]]] [[ヘッダー]]は削除します。
=== [26] 結合した[[応答]]の[[メッセージ本体]]は得られたデータとします。
== [29] そうしない場合、次のようにして構いません。
=== [17] 結合した[[応答]]の[[状態符号]]は [CODE(HTTP)[[[206]]]] とします。 [SRC[>>5]]
=== [11] 結合した[[応答]]の[[メッセージ本体]]は得られたデータの各連続部分を含む
[CODE(MIME)@en[[[multipart/byteranges]]]] [[実体]]とします。 [SRC[>>5]]
=== [30] 結合した[[応答]]の [COD(HTTP)@en[[[Content-Type:]]]],
[CODE(HTTP)@en[[[Content-Length:]]]] は適当に設定し、
[CODE(HTTP)@en[[[Content-Range:]]]], [CODE(HTTP)@en[[[Transfer-Encoding:]]]]
は削除します。
== [31] そうしない場合、得られたデータの各連続部分について、
=== [32] 結合した[[応答]]の複製を用意します。
=== [33] その[[状態符号]]は [CODE(HTTP)@en[[[206]]]] とします。 [SRC[>>5]]
=== [34] その[[メッセージ本体]]はデータの連続部分とします。 [SRC[>>5]]
=== [35] その [CODE(HTTP)@en[[[Content-Range:]]]] [[ヘッダー]]を適切に設定します。 [SRC[>>5]]
=== [36] その [CODE(HTTP)@en[[[Content-Type:]]]] [[ヘッダー]]と 
[CODE(HTTP)@en[[[Content-Length:]]]] [[ヘッダー]]を適切に設定し、
[CODE(HTTP)@en[[[Transfer-Encoding:]]]] [[ヘッダー]]は削除します。
]FIG]

;; [80] [[不完全メッセージ]]も参照。

;; [90] [CODE(HTTP)[[[304]]]] の場合の処理モデル ([[応答]]と[[ヘッダー]]の結合方法)
と似ています。 [CODE(HTTP)[[[226]]]] でも同様の方法が使われます。

* 実現値操作 [CODE(HTTP)@en[range]]

[87] [[実現値操作]] [DFN[[CODE(HTTP)@en[[[range]]]]]] は、
結果が[[範囲]]選択の結果としての部分内容であることを表します [SRC[>>86]]。

[92] [[範囲]]選択とそれ以外の[[恒等]]でない[[実現値操作]]が適用された時は、
[CODE(HTTP)@en[[[IM:]]]] にその適用順序を明記しなければ[['''なりません''']] [SRC[>>91]]。

[93] [[実現値操作]]として [CODE(HTTP)@en[[[range]]]] のみが適用された時は、
[CODE(HTTP)@en[[[IM:]]]] [[ヘッダー]]を省略する[['''べきです''']]。
通常は [CODE(HTTP)[[[226]]]] ではなく [CODE(HTTP)[[[206]]]] を使います。 [SRC[>>91]]

[94] [CODE(HTTP)@en[[[IM:]]]] に [CODE(HTTP)@en[[[range]]]]
が含まれる時は、 [CODE(HTTP)@en[[[Content-Range:]]]] または
[CODE(HTTP)@en[[[Content-Type:]] [[multipart/byteranges]]]]
が含まれなければ[['''なりません''']] [SRC[>>91]]。

[95] [CODE(HTTP)@en[[[A-IM:]]]] に [CODE(HTTP)@en[[[range]]]] は1回しか指定できないと思われますが、明記されていません。

[96] [[範囲要求]]に [CODE(HTTP)@en[[[A-IM:]]]] が含まれるとき
[CODE(HTTP)@en[[[range]]]] を指定しなければならないとは明記されていません。

[97] [[キャッシュ]]における処理については、[CODE(HTTP)[[[226]]]] を参照。

[99] [CODE(MIME)@en[[[multipart/byteranges]]]] に関わる処理 [SRC[>>98]]
は [CODE(MIME)@en[[[multipart/byteranges]]]] を参照。

;; [89] [[IANA登録簿]]にも [[RFC 3229]] より登録されています [SRC[>>88]]。
[REFS[
- [88] [CITE[Instance Manipulation Values]] ([TIME[2014-01-31 02:45:13 +09:00]] 版) <http://www.iana.org/assignments/inst-man-values/inst-man-values.xhtml>
]REFS]

* メモ

[6] [CITE[http - Paging in a Rest Collection - Stack Overflow]]
( ([TIME[2014-09-17 02:47:22 +09:00]] 版))
<http://stackoverflow.com/questions/924472/paging-in-a-rest-collection>

[100] [CITE@en[draft-combs-http-indeterminate-range-00 - HTTP/1.1: Range Responses of Indeterminate Length]]
([TIME[2015-03-26 01:15:32 +09:00]] 版)
<http://tools.ietf.org/html/draft-combs-http-indeterminate-range-00>

[101] [CITE@en[draft-combs-http-indeterminate-range-01 - HTTP/1.1: Range Responses of Indeterminate Length]]
([TIME[2015-06-13 08:24:50 +09:00]] 版)
<https://tools.ietf.org/html/draft-combs-http-indeterminate-range-01>

[102] [CITE[IRC logs: freenode / #whatwg / 20150731]]
([TIME[2015-08-01 14:07:51 +09:00]] 版)
<http://krijnhoetmer.nl/irc-logs/whatwg/20150731>

[103] [CITE@ja[apacheはContent-LengthレスポンスヘッダがないとRangeリクエストが有効にならない - うまいぼうぶろぐ]]
([TIME[2016-10-22 14:02:44 +09:00]])
<http://hogem.hatenablog.com/entry/20100724/1280074122>

[104] [CITE@en[Rewrite HTTP cache integration]]
([[mnot]]著, [TIME[2017-03-23 22:51:00 +09:00]])
<https://github.com/whatwg/fetch/commit/cbca2c2f3a37084e336e14348de683f8ffa0fed9>

[105] [CITE@en[Specify identity encoding for range requests]]
([[jakearchibald]]著, [TIME[2018-06-06 16:26:21 +09:00]])
<https://github.com/whatwg/fetch/commit/2f3d04d3713f6cd0f89d491217175b55911927be>

[106] [CITE@en[Some servers seem to expect 'Accept-Encoding : identity' to serve Range requests · Issue #747 · whatwg/fetch]]
([TIME[2018-06-08 18:52:11 +09:00]])
<https://github.com/whatwg/fetch/issues/747>