[4] [DFN[[CODE(HTTP)@en[[[bytes]]]]]] は、[[バイト]]の範囲を表す[[範囲単位]]です。

* 仕様書

[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-2.1>'''
- [27] [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.2>
]REFS]

* 意味

[5] [[範囲単位]] [CODE(HTTP)@en[[[bytes]]]] は、データの[[オクテット列]]の部分範囲を表します
[SRC[>>3]]。

* [CODE(HTTP)@en[Range:]] ヘッダーにおける範囲の指定

[6] [CODE(HTTP)@en[[[Range:]]]] [[ヘッダー]]における[[バイト範囲]]の値は、
[[範囲単位]]の後に [CODE[[[=]]]] と範囲の[[リスト]]
([CODE(HTTP)[#]]) を記述して指定します [SRC[>>3]]。

[FIG(railroad)[
= [CODE(HTTP)@en[[[bytes]]]]
= [CODE(HTTP)@en[[[=]]]]
= 範囲
= *
== [[OWS]]
== [CODE[[[,]]]]
== [[OWS]]
== 範囲
]FIG]

[7] 範囲は、先頭の位置と末尾の位置で指定するか、先頭の位置のみで指定するか、
長さのみで指定するかのいずれかの方法で記述します [SRC[>>3]]。

[FIG(railroad)[
= |
== =
=== 位置
=== [CODE(HTTP)[[[-]]]]
=== 位置
== =
=== 位置
=== [CODE(HTTP)[[[-]]]]
== =
=== [CODE(HTTP)[[[-]]]]
=== 長さ
]FIG]

[8] 位置や長さは1文字以上の[[ASCII数字]]の列で[[十進数]]として表します [SRC[>>3]]。

;; [22] [[受信者]]は[[桁溢れ]]に注意しなければ[['''なりません''']] [SRC[>>3]]。

[FIG(railroad)[
= +
== [[ASCII数字]]
]FIG]

[9] 位置の指定は、[[バイト列]]の先頭を [[0]] とした時の位置 ([[offset]])
として解釈します。指定された先頭または最後のバイトも、範囲に含まれます。 [SRC[>>3]]

[13] 最後のバイトが指定されていない場合や、実際のデータの最後のバイトより後を指している時は、
残りすべてを表します。 [SRC[>>3]]

;; [14] [[クライアント]]が実際の長さを知らなくても取得する最大のデータ長を指定したい時に、
適当に大きな値を指定することができます。

[12] 先頭と最後が明記されていて、先頭より最後のバイトの方が小さな値の範囲は、
[[非妥当]]です [SRC[>>3]]。

[23] 先頭がデータの長さより大きな値であっても[[非妥当]]とはならないようですが、
データのどの部分も表しません。

[EG[
[10] [CODE(HTTP)@en[bytes=0-499]] は、先頭500バイトを表します [SRC[>>3]]。

[11] [CODE(HTTP)@en[bytes=500-999]] は、その後に続く500バイトを表します [SRC[>>3]]。
]EG]

[15] 長さによる範囲の指定は、データの最後から指定された数の[[バイト]]を表します。
実際のデータの長さより大きい時は、全体を表します。 [SRC[>>3]]

;; [20] 意味はありませんが、 [CODE(HTTP)[bytes=-0]] も禁止されていないようです。

[EG[
[16] 長さが10000のデータに対して [CODE(HTTP)@en[bytes=-500]] は
[CODE(HTTP)@en[bytes=9500-9999]] や [CODE(HTTP)@en[bytes=9500-]]
と同じ意味になります [SRC[>>3]]。
]EG]

[17] 範囲のリストは、それぞれの範囲によって表されるバイト列のリストを表しています。
各範囲は重複していることもあります。

[EG[
[18] [CODE(HTTP)@en[bytes=0-0,-1]] は先頭バイトと末尾バイトを表しています [SRC[>>3]]。
]EG]

[EG[
[19] [CODE(HTTP)@en[bytes=500-600,601-999]] や
[CODE(HTTP)@en[bytes=500-700,601-999]] は、
[CODE(HTTP)@en[bytes=500-999]] と同じ範囲を表していますが冗長です [SRC[>>3]]。
]EG]

[21] 範囲のリストにおいて、範囲の先頭の位置がデータの長さより小さな値か、
長さが0でないものが最低1つでもあれば、これは[RUBYB[満足可能]@en[satisfiable]]です。
そうでなければ[RUBYB[満足不能]@en[unsatisfiable]]です。 [SRC[>>3]]

[25] 妥当性や満足可能性は、[[鯖]]の [CODE(HTTP)@en[[[Range:]]]]
[[ヘッダー]]の処理で使われます。

[26] 範囲のリストにおける範囲の順序や重複、個数などについては、
[CODE(HTTP)@en[[[Range:]]]] [[ヘッダー]]の項を参照してください。

* [CODE(HTTP)@en[Content-Range:]] ヘッダーでの範囲の指定

[28] [CODE(HTTP)@en[[[Content-Range:]]]] [[ヘッダー]]における範囲の値は、
[[範囲単位]]と [CODE(charname)@en[[[SP]]]] の後に、範囲を1つ指定したものです。
[SRC[>>27]]

[FIG(railroad)[
= [CODE(HTTP)@en[[[bytes]]]]
= [CODE(charname)[[[SP]]]]
= 範囲
]FIG]

[29] 範囲は、先頭の位置、[CODE[-]]、最後の位置、[CODE[/]]、全体の長さの順に指定します。
ただし、 [CODE[/]] の前後どちらか一方は [CODE[*]] とすることができます。 [SRC[>>27]]

[FIG(railroad)[
= |
== =
=== 位置
=== [CODE[[[-]]]]
=== 位置
=== [CODE[[[/]]]]
=== |
==== 長さ
==== [CODE[[[*]]]]
== =
=== [CODE[[[*]]]]
=== [CODE[[[/]]]]
=== 長さ
]FIG]

[30] 位置や長さは、1文字以上の[[ASCII数字]]によって表します [SRC[>>27]]。
これは[[十進数]]として解釈されます。

[FIG(railroad)[
= +
== [[ASCII数字]]
]FIG]

** バイト範囲の構文

[36] [CODE(HTTP)[[[206]]]] [[応答]]では、先頭と最後の位置を指定する構文を使わなければなりません。

[33] 先頭の位置と最後の位置は、全体の先頭を [[0]] とした時の[[オフセット]]値で、
それぞれの位置の[[バイト]]をも含みます。

[34] 先頭の位置より最後の位置の方が小さい場合、[[非妥当]]です [SRC[>>27]]。

;; [35] [CODE(HTTP)@en[[[Content-Range:]]]] が[[非妥当]]の場合、それが表す[[範囲]]は無視しないといけません
([CODE(HTTP)@en[[[Content-Range:]]]] 参照)。

[32] 全体の長さのかわりの [CODE[[[*]]]] は、[[生成]]の時点で長さが分からないことを示します
[SRC[>>27]]。

[31] [[送信者]]は、分からない場合や決定しがたい場合を除き、
全体の長さを指定する[['''べきです''']]。 [SRC[>>27]]

[EG[
[39] 次の例 [SRC[>>27]] は、1234バイトのデータのうち、43個目のバイト以降が含まれることを表しています。

[PRE(HTTP code)[
Content-Range: bytes 42-1233/1234
]PRE]

[40] 次の例 [SRC[>>27]] は、長さ不明のデータのうち、43個目のバイトから1234個目のバイトまでが含まれることを表しています。
[PRE(HTTP code)[
Content-Range: bytes 42-1233/*
]PRE]
]EG]

** 長さの構文

[37] [[鯖]]は、[[バイト範囲]]の[[要求]]に対して [CODE(HTTP)[[[416]]]] [[応答]]を返す場合、
前半が [CODE[[[*]]]] の構文を使った [CODE(HTTP)[[[Content-Range:]]]]
[[ヘッダー]]を送信する[['''べきです''']] [SRC[>>27]]。

;; [38] こちらの構文では、長さ不明にはできません。長さ不明の時は[[ヘッダー]]自体を送るべきではないと思われます。

[EG[
[41] 次の例 [SRC[>>27]] は、適用対象のデータの長さが1234バイトであることを表しています。
[PRE(HTTP code)[
Content-Range: bytes */1234
]PRE]
]EG]

** [CODE(HTTP)[*/*]]

[44] [[RFC 723x]] は認めていませんが、 [[Google BigQuery]] は
[CODE(HTTP)@en[[[Content-Range:]] [[bytes]] */*]] という指定を認めています [SRC[>>45]]。

[REFS[
- [45] [CITE@ja[Loading Data with a POST Request - Google BigQuery — Google Cloud Platform]] ([TIME[2014-12-18 02:33:03 +09:00]] 版) <https://cloud.google.com/bigquery/loading-data-post-request#resume-upload>
]REFS]

* 歴史

[FIG(quote)[
[FIGCAPTION[
[2] RFC 2068・2616 (HTTP/1.1) 3.12 Range Units
]FIGCAPTION]

> HTTP/1.1 allows a client to request that only part (a range of) the
response entity be included within the response. HTTP/1.1 uses range
units in the Range (section [DEL[14.36]] [INS[14.35]]) and Content-Range (section [DEL[14.17]] [INS[14.16]])
header fields. An entity [DEL[may]] [INS[can]] be broken down into subranges according
to various structural units.

[[HTTP/1.1]] では、[[応答]][[実体]]の部分 (範囲) 
のみを応答中に含めるように[[クライアント]]が[[要求]]することを認めます。
HTTP/1.1 は、範囲単位を [CODE(HTTP)[[[Range]]]] 頭欄と 
[CODE(HTTP)[[[Content-Range]]]] 頭欄で使います。
実体は種々の構造単位に基づいて小範囲に分割できます。

>
- range-unit       = bytes-unit | other-range-unit
- bytes-unit       = "bytes"
- other-range-unit = token

> The only range unit defined by HTTP/1.1 is "bytes". HTTP/1.1
implementations [DEL[may]] [INS[MAY]] ignore ranges specified using other units.

HTTP/1.1 で定義する範囲単位は [CODE(HTTP)[[[bytes]]]] だけです。
HTTP/1.1 実装は他の単位を使って指定されている範囲を無視しても'''構いません'''。

> HTTP/1.1 has been designed to allow implementations of applications
that do not depend on knowledge of ranges.

HTTP/1.1 は範囲の知識に依存しない応用の実装を認めるように設計されています。
]FIG]

* 実装

[42] 汎用の [[Webブラウザー]]や [[HTTP鯖]]は [CODE(HTTP)@en[[[bytes]]]]
による[[範囲要求]]に (少なくても[[静的ページ]]に関しては) 対応しているのが普通です。 [TIME[2014-11-07T10:02:03.200Z]]

[43] [[ダウンロード]]に特化した[[利用者エージェント]]も [CODE(HTTP)@en[[[bytes]]]]
単位の[[範囲要求]]により[[ダウンロード]]の途中からの継続に対応しているのが普通です。

* 関連

[24] [[鯖]]は、 [CODE(HTTP)@en[[[Accept-Ranges:]] [[bytes]]]] によって[[バイト範囲]]に対応していることを明示できます。

* メモ

[1] HTTP では他の単位が使われてるのって見たことないですね。

[46] [CITE@en[draft-luotonen-http-url-byterange-01 - Byte Ranges With HTTP URLs]]
([TIME[2015-01-29 04:38:34 +09:00]] 版)
<https://tools.ietf.org/html/draft-luotonen-http-url-byterange-01>

[47] [CITE[IRC logs: freenode / #whatwg / 20150403]]
([TIME[2015-04-04 11:15:53 +09:00]] 版)
<http://krijnhoetmer.nl/irc-logs/whatwg/20150403>