HTTP Message Body

この頁では、HTTPリクエスト/レスポンスの「本文」に相当するメッセージボディについて、また、それを効率的に転送するための仕組みについて解説します。

メッセージボディとは

この頁では、メッセージボディについて記述しますが、その前にまず、HTTPにおいて「メッセージ」とは何なのかということから解説いたします。 RFC 2616のsection 4.1をご覧ください。

HTTPメッセージは、クライアントからサーバへのリクエストと、サーバからクライアントへのレスポンスから成る。

 HTTP-message   = Request | Response     ; HTTP/1.1 messages

リクエスト (section 5) と レスポンス (section 6) 各メッセージは、エンティティ (メッセージの付加物) を転送するために RFC 822 の一般的なメッセージフォーマットを使用する。 両タイプとも、開始行、0 以上のヘッダフィールド ("headers"として知られているもの)、ヘッダフィールドの終了を示す (CRLF の前に何もない行のような) 空行、そして任意のメッセージボディからなる。

 generic-message = start-line
                   *(message-header CRLF)
                   CRLF
                   [ message-body ]
 start-line      = Request-Line | Status-Line

メッセージは、リクエストの場合のRequest-Lineとレスポンスの場合のStatus-Lineであるstart-lineHTTPヘッダ、そしてメッセージボディから成ります。

ところで、上文中にエンティティという語が出てきました。 メッセージとエンティティとの違いはどこにあるのでしょうか? これについては、section 1.3にある定義をご覧下さい。

メッセージ {message}
section 4 にて定義される構文を持ち構造化されたオクテットシーケンスから成り、接続を介して転送される、HTTP 通信での基本単位。
エンティティ {entity}
リクエストやレスポンスの付加物{payload} として転送される情報。 エンティティは、section 7 で記述されるように、エンティティヘッダフィールドという形での外部情報と、エンティティボディという形での内容から成る。

上記の定義を見る限りでは、その違いはあまりよくわかりません。 そこで、メッセージボディとエンティティボディの違いを明らかにするために、section 4.3, 7.2を読んでみます。

HTTP メッセージにメッセージボディがあったとしたら、それはリクエストやレスポンスに関連するエンティティボディを運ぶために使われる。 メッセージボディは、Transfer-Encoding ヘッダフィールド (section 14.41) によって示されるように、転送コーディングが適用された場合のみ、エンティティボディとは異なる。

 message-body = entity-body
              | <Transfer-Encoding にてエンコードされた entity-body>

Transfer-Encoding は、メッセージの安全かつ適切な転送を保障するアプリケーションによって、適用されるすべての転送コーディングを示すために使われなければならない。 Transfer-Encoding は、メッセージの性質であり、エンティティの性質ではないので、リクエスト/レスポンス連鎖に関わるあらゆるアプリケーションによって追加されたり削除されたりされうる。 (しかしながら、確実に転送コーディングが用いられているであろう時のために、section 3.6 にて制限を設けている。)

もし、HTTP リクエストやレスポンスと共にエンティティボディが送られてきたら、それはエンティティヘッダフィールドによって定義されるフォーマットをもってエンコーディングされている。

 entity-body    = *OCTET

エンティティボディは、section 4.3 に記されるように、メッセージボディがある時のみ、メッセージの中に存在する。 エンティティボディは、メッセージの安全かつ適切な転送を保証するために適用されるであろうあらゆる転送エンコーディングをデコードする事によってメッセージボディから得られる。

つまり、通常は「メッセージボディ」=「エンティティボディ」ですが、転送コーディングが適用された場合のみエンティティボディとは異なるものになります。

エンティティボディへのコーディング

エンティティボディを持つHTTPメッセージの場合、エンティティボディはそのままでも転送できますが、適切なコーディングを施すことによって転送効率を上げることができます。

内容コーディング

HTTP では、転送するデータ量を減らすために、エンティティボディを適した形にエンコーディングして、リソースを提供する事ができます。 これを内容コーディングと呼び、section 3.5 にて記述されています。

内容コーディング値は、エンティティに適用されている、もしくは適用できるエンコーディング変換を示す。 内容コーディングは、文書をその根本的なメディアタイプのアイデンティティを失ったり、情報の欠落する事が無いように、圧縮したり、他の有用な変換が行われる事を許可するために、主に使用される。 しばしば、エンティティはコード化された形態で保存され、直接転送され、受け取り側によってのみデコードされる。

 content-coding   = token

すべての content-coding 値は、大文字・小文字を区別しない。 HTTP/1.1 では、content-coding 値を Accept-Encoding (section 14.3) と Content-Encoding (section 14.11) ヘッダフィールドで使用する。 その値は content-coding で表されるけれども、そのエンコーディングを解読するためにはどんなデコーディングメカニズムが必要であるかを示す事は、より重要な事である。

Internet Assigned Numbers Authority (IANA) は、content-coding 値トークンに対する登録を行なっている。 初めに登録されているものには、以下のトークンが含まれる:

gzip
RFC 1952 に記述されているファイル圧縮プログラム "gzip" (GNU zip) によって作られるエンコーディングフォーマット。 このフォーマットは32 bit CRC 付きの Lempel-Ziv コーディング (LZ77) である。
compress
一般的な UNIX ファイル圧縮プログラム "compress" で作られるエンコーディングフォーマット。 このフォーマットは Lempel-Ziv-Welch コーディング (LZW) に適合している。
エンコーディングフォーマットの確認のためにプログラム名を使用する事は望ましくなく、将来的なエンコーディングを妨害する。ここでのこれらの使用は歴史的な慣例であり、決して良い方法ではない。 HTTP の過去の実装への互換性のため、アプリケーションは "x-gzip" と "x-compress" をそれぞれ "gzip" と "compress" に等価であるとみなすべきである
deflate
RFC 1951 に記述されている "deflate" 圧縮メカニズムと結合した、RFC 1950 にて定義されている "zlib" フォーマット。
identity
既定のエンコーディング、つまり圧縮・変形をしない場合に使う。 この content-coding 値は、Accept-Encoding ヘッダでのみ使用し、Content-Encoding ヘッダでは使用すべきではない

ここでポイントとなるのは、内容コーディングを施した後でも、メディアタイプは変わらないという事です。 すなわち、例えば「メディアタイプが text/html のエンティティボディを gzip で内容コーディングする」という場合でも、Content-Type の値は、application/x-gzip ではなく、text/html のままです。

転送コーディング

転送コーディングは、内容コーディングと名前が良く似て、違いがわかりにくいかもしれませんが、全く違うものです。 内容コーディングは内容を圧縮する事が念頭に置かれていますが、転送コーディングは、内容をあるエンコード方式に従って転送するという事を意味します。

転送コーディングについては、section 3.6 にて記述されています。

転送コーディング値は、ネットワークを通して "安全な転送" を保証するために、エンティティボディに適用されている、する事のできる、する必要のあるエンコーディング変換を示すために使われる。 転送コーディングは、元のエンティティではなくメッセージの特性である、という点で内容コーディングとは異なる。

 transfer-coding         = "chunked" | transfer-extension
 transfer-extension      = token *( ";" parameter )

パラメータは、attribute/value ペアの形態を為す。

 parameter               = attribute "=" value
 attribute               = token
 value                   = token | quoted-string

すべての transfer-encoding 値は、大文字・小文字を区別しない。 HTTP/1.1 では、TE ヘッダフィールド (section 14.39) と Transfer-Encoding ヘッダフィールド (section 14.41) で転送コーディング値を使用している。

HTTP/1.1 では、転送コーディングとしてチャンク形式エンコーディングのみが定義されており、section 3.6.1 にて記述されています。

チャンク形式エンコーディングは、それぞれが自身のサイズ指標を持つ、一連のチャンクと、エンティティヘッダフィールドを含むオプショナルな trailer を付加して転送するためにメッセージのボディを書き換える。 これによって、受信者が全メッセージを受信した事を確かめるために必要な情報を、動的に生成された内容と一緒に転送できるようにする。

 Chunked-Body   = *chunk
                  last-chunk
                  trailer
                  CRLF

 chunk          = chunk-size [ chunk-extension ] CRLF
                  chunk-data CRLF
 chunk-size     = 1*HEX
 last-chunk     = 1*("0") [ chunk-extension ] CRLF

 chunk-extension= *( ";" chunk-ext-name [ "=" chunk-ext-val ] )
 chunk-ext-name = token
 chunk-ext-val  = token | quoted-string
 chunk-data     = chunk-size(OCTET)
 trailer        = *(entity-header CRLF)

chunk-size フィールドは、チャンクのサイズを示す 16 進数の数字列である。 チャンク形式エンコーディングは、サイズが 0 のチャンクで終わり、空行によって終わる物{trailer} が続く。

trailer では、送信者はメッセージの末尾に HTTP ヘッダフィールドを追加できる。 Trailer ヘッダフィールドは、trailer の中に含まれたヘッダフィールドを示すために使う事ができる (section 14.40 参照)。

レスポンスでチャンク形式転送コーディングを使うサーバは、以下のどれにも当てはまらなければ、ヘッダフィールドにおいて trailer を使ってはならない

(中略)

Chunked-Body デコーディングのための例題過程は、付録の 19.4.6 で紹介されている。

すべての HTTP/1.1 アプリケーションは、"chunked" 転送コーディングを受信しデコードできなければならないし、理解できない転送コーディング拡張は無視しなければならない

 length := 0
 read chunk-size, chunk-extension (if any) and CRLF
 while (chunk-size > 0) {
    read chunk-data and CRLF
    append chunk-data to entity-body
    length := length + chunk-size
    read chunk-size and CRLF
 }
 read entity-header
 while (entity-header not empty) {
    append entity-header to existing header fields
    read entity-header
 }
 Content-Length := length
 Remove "chunked" from Transfer-Encoding

チャンク形式エンコーディングは、エンティティボディを任意の大きさのチャンク (塊) に分け、そのチャンクの大きさを書いたヘッダをつけていきます。 そうしてエンティティボディ全体にエンコードをすべて終えたら、0 CRLF をつけ加えて、エンティティボディの終了を印します。 更に、その直後に新たに HTTP ヘッダをつけ加える事が可能で、これを trailer と呼んでいます。 trailer では、エンコードされたエンティティボディについての新たなメタ情報などを付加できます。

HTTP/1.0 以前では、エンティティボディの終わりはコネクションの切断で判断していましたが、HTTP/1.1 では持続的接続がサポートされたため、エンティティボディの終わりを知るための新しい仕組みが必要となりました。 すなわち、チャンク形式とは HTTP/1.1 通信を実現するためにはとても重要な技術であり、したがってHTTP/1.1 アプリケーションはチャンク形式のデコードができなければいけません。 また、逆にチャンク形式エンコーディングは HTTP/1.1 の技術なので、通信相手が HTTP/1.0 以下である場合は使用できません

転送コーディングを施されたメッセージボディは、チャンクのヘッダ等が付加されるので、エンティティボディより大きなものになります。 この事からも、メッセージボディとエンティティボディの違いがわかると思います。

HTTP/1.1で通信するプログラムの開発者は、section 19.4.6 にチャンク形式のデコードのための疑似コードが示されていますので、この疑似コードを元に C, Perl, Javaなどのプログラム言語の文法に従って組み込みましょう。

メディアタイプ

HTTP を使ってエンティティボディを送信する場合、必ず Content-Type ヘッダを使って、そのメディアタイプを示さなければいけません。 また Accept ヘッダを使うと、Web クライアントが扱えるリソースのメディアタイプを示す事ができます。 section 3.7 では、そのメディアタイプについて記述されています。

HTTP は、Content-Type (section 14.17) と Accept (section 14.1) ヘッダフィールドにおいて、開放・拡張データタイプの決定やタイプネゴシエーションを供給するために Internet Media Type [17] を使用する。

 media-type     = type "/" subtype *( ";" parameter )
 type           = token
 subtype        = token

(section 3.6で定義されているように) attribute/value ペアの形態で、タイプ/サブタイプがあり、その後にパラメータを置く事ができる

タイプ、サブタイプ、パラメータ属性名は、大文字・小文字を区別しない。 しかし、パラメータ値は、パラメータ名の意味論に依存するので、大文字・小文字は区別されるかもしれない。 連続した空白文字 (LWS: Linear white space) は、タイプとサブタイプの間や属性とその値の間で使われてはならない。 パラメータのある無しは、メディアタイプの定義に依存するので、メディアタイプ決定のプロセスに重要なものとなるだろう。

古い HTTP アプリケーションの中には、メディアタイプパラメータを認識しないものもある事に注意せよ。 従って、実装が古い HTTP アプリケーションにデータを送る時は、タイプ/サブタイプ定義を要求した場合に時のみ、メディアタイプパラメータを使用すべきである

メディアタイプ値は、Internete Assigned Number Authority (IANA [19]) によって登録される。 メディアタイプ登録手続きの方法は、RFC 1590 において概説されている。 登録されていないメディアタイプの使用は推奨されない。

ブラウザ等のアプリケーションは、このメディアタイプを見てファイルの種類を判別します。 たまに、「"拡張子" でファイルを判別している」と思っている人がいますが、実際はそうではありません。 拡張子は、例えば人間がそのファイル名を見た時に、そのファイルの種類 (すなわちメディアタイプ) を推定できるようにするため等の、要するに便宜的につけられているだけのものなのです。 ですから、例えば「index.html というファイル名を持つ image/jpeg ファイル」というものも作成できます。

(※) ただし、時間短縮等の観点から、実際には、拡張子でファイルの種類を判別しているものもあります。 例えば、Apache というサーバでは、前もって登録しておく事で、その拡張子を持つファイルに登録したメディアタイプを発行させる事ができます。

実際に利用されているメディアタイプには、以下のようなものがあります。

type が text (テキストファイル)
text/html, text/plain, text/css, ...
type が image (画像ファイル)
image/jpeg, image/png, image/gif, ...
type が audio (音声ファイル)
audio/basic, audio/midi ...
type が video (動画ファイル)
video/mpeg, video/quicktime ...
type が application (アプリケーション用バイナリファイル)
application/octet-stream, application/zip, application/pdf ...

(※) たまに、application/x-gzip のように、x- がついているものがありますが、これは IANA には登録されていないものです。

一部のメディアタイプではパラメータを持つ事があります。 例えば text/html では、パラメータとして文字セットを示す事ができます。

HTTP に特有なメディアタイプとしては、message/httpapplication/http があります。

HTTP/1.1 プロトコルの定義に追加して、この文書ではインターネットメディアタイプ "message/http" と "application/http" についての仕様を示す。 message/http タイプは単一の HTTP リクエストやレスポンスメッセージを含むために使う事ができ、行長さやエンコーディングに関する全ての "message" タイプが受ける MIME 制限 に従う。 application/http タイプは一つ以上の HTTP リクエストやレスポンスメッセージ (混合されてはいないもの) のパイプラインを含むために使う事ができる。 以下のものが IANA にて登録されている。

メディアタイプ名message
メディアサブタイプ名http
必要なパラメータなし
省略可能なパラメータversion, msgtype
version
メッセージに同封された HTTP-Version 番号 (例えば "1.1"等)。 与えられない場合、バージョンはボディの最初の行から決定する事ができる。
msgtype
メッセージタイプ -- すなわち "request" か "response"。 与えられない場合、タイプはボディの最初の行から決定する事ができる。
エンコーディングについて"7bit", "8bit", "バイナリ" のみが許される。
セキュリティについてなし
メディアタイプ名application
メディアサブタイプ名http
必要なパラメータなし
省略可能なパラメータ version, msgtype
version
メッセージに同封された HTTP-Version 番号 (例えば "1.1"等)。 与えられない場合、バージョンはボディの最初の行から決定する事ができる。
msgtype
メッセージタイプ -- すなわち "request" か "response"。 与えられない場合、タイプはボディの最初の行から決定する事ができる。
エンコーディングについてこのタイプに含まれる HTTP メッセージは "バイナリ" フォーマットである; すなわち、 E-mail 経由で転送される時は、適切な Content-Transfer-Encoding の使用が必要である。
セキュリティについてなし

message/httpは、TRACEリクエストに対するレスポンスのボディで使用されます。 具体的には、経由するプロクシ等の中継サーバが付加するHTTPヘッダが含まれています。

application/http は、パイプラインリクエスト時に使用されます。 パイプラインについては、持続的接続とは何かを参照して下さい。

マルチパートタイプ

マルチパートとは、一通の電子メールに複数の異なる種類のデータを格納するための MIME の拡張仕様で、これを利用すると、そのボディ部には複数のデータを格納する事ができます。 データの境界は boundary に指定された文字列で示す事ができます。

HTTP では、マルチパートをサポートしています。 section 3.7.2 をご覧下さい。

MIME は、一つのメッセージボディの中に複数のエンティティをカプセル化する "multipart" タイプをいくつか供給する。 すべてのマルチパートタイプは RFC 2046 の section 5.1.1 で定義されているように、共通の構文を共有し、メディアタイプ値の一部として境界パラメータ{boundary parameter} を含めなければならない。 メッセージボディは、それ自身プロトコル要素の一部であり、それゆえに、body-parts 間の行末を表すためには CRLF のみを使用しなければならない。 RFC 2046 と異なり、どのマルチパートメッセージのエピローグ{epilogue} も空でなければならない。 そのため、HTTP アプリケーションは (たとえ元のマルチパートがエピローグを含んでいても) エピローグを転送してはならない。 これらの制限は、最後のマルチパートの境界線によってメッセージボディの "終端" を示せるように、マルチパートのメッセージボディに自己限界性質{the self-delimiting nature} を持たせるために存在する。

一般的に、HTTP はマルチパートメッセージボディを他のメディアタイプとは区別無く、すなわち単なる付加物{payload} として扱う。 ただ一つ例外は、206 (Partial Content) レスポンス中に現れる時の "multipart/byteranges" タイプ (appendix 19.2) であり、その場合 section 13.5.4 や section 14.16 で表されるような、いくつかの HTTP キャッシュメカニズムによって解釈されるだろう。 その他のすべての場合では、HTTP ユーザエージェントは、MIME ユーザエージェントがマルチパートタイプの受けとる時と同じ、ま たは似たような振る舞いをすべきである。 マルチパートメッセージボディの各々のボディ部分中の MIME ヘッダフィールドは、HTTP ではそれらの MIME 意味論による定義以上にどんな意味も持たない。

一般的には、HTTP ユーザエージェントは、MIME ユーザエージェントがマルチパートタイプの受けとる時と同じ、または似たような振る舞いをすべきである。 アプリケーションが認識できないマルチパートサブタイプを受け取った場合は、それを "multipart/mixed" に相当するものとして扱わなければならない

注: "multipart/form-data" タイプは、RFC 1867 で表されるように、特に POST リクエストメソッド経由で処理するのに合ったフォームデータを転送するために特別に定義されている。

マルチパートには次のような特徴があります。

  1. boundary の文字列にはその前に "--" が、また最後の境界線には前後に "--" が付けられる
  2. 各パートはヘッダ部ボディ部から構成される
  3. マルチパートは入れ子構造にする事ができる

HTTP のエンティティボディに利用されるマルチパートタイプには次のようなものがあります。

multipart/form-data

RFC 1867 にて、フォームを利用したファイルのアップロードが提案されていますが、この時にリクエストのエンティティボディに使われているデータ形式は multipart/form-data です。 一般に、ファイルのアップロードには FTP を利用しますが、この方法を用いれば FTP のようにアカウントを発行する事なく、アップロードが行う事ができます。 RFC 1867 中の例をご覧下さい。

サーバが以下の HTML を返したとする:

 <FORM ACTION="http://server.dom/cgi/handle"
       ENCTYPE="multipart/form-data"
       METHOD=POST>
 あなたの名前は? <INPUT TYPE=TEXT NAME=submitter>
 送るファイルは? <INPUT TYPE=FILE NAME=pics>
 </FORM>

そして、ユーザが名前欄に "Joe Blow" と打ち込み、'送るファイルは?' への応答として "file1.txt" というテキストファイルと選んだとする

クライアントは以下のデータを送り返すであろう:

 Content-type: multipart/form-data, boundary=AaB03x

 --AaB03x
 content-disposition: form-data; name="field1"

 Joe Blow
 --AaB03x
 content-disposition: form-data; name="pics"; filename="file1.txt"
 Content-Type: text/plain

  ... file1.txt の内容 ...
 --AaB03x--

もし '送るファイルは?' への応答として更に画像ファイル "file2.gif" も合わせ選んだとしたら、クライアントは以下のデータを送り返すであろう:

 Content-type: multipart/form-data, boundary=AaB03x

 --AaB03x
 content-disposition: form-data; name="field1"

 Joe Blow
 --AaB03x
 content-disposition: form-data; name="pics"
 Content-type: multipart/mixed, boundary=BbC04y

 --BbC04y
 Content-disposition: attachment; filename="file1.txt"
 Content-Type: text/plain

 ... file1.txt の内容 ...
 --BbC04y
 Content-disposition: attachment; filename="file2.gif"
 Content-type: image/gif
 Content-Transfer-Encoding: binary

   ... file2.gif の内容 ...
 --BbC04y--
 --AaB03x--

この形式の詳細については、RFC 1867RFC 2388 を参照して下さい。

multipart/byteranges

部分的GETリクエストでは、複数の範囲を指定する事ができますが、この時サーバはmultipart/byterangesというメディアタイプでリソースを返します。 詳しくは、一度に複数の部分的レスポンスを返す場合をご覧ください。

差分コーディング

HTTP にて、最も GET リクエストが試行されているリソースとは一体何でしょうか? これは、当然 HTML ファイルでしょう。 では、よくリクエストが行われる HTML ファイルとはどのようなものがあるでしょうか? これは、例えばニュースサイトであったり、Web 掲示板であったりするでしょうが、とにかくこのようなファイルの特徴として、頻繁に更新が行われるという事があります。 頻繁に更新が行われるからこそ、頻繁に取得する必要があるのですが、そのような HTML は得てしてその変更部分は僅かである場合がほとんどです。

エンティティボディの効率的な転送について、先に述べたような方法が色々と考えられてきたわけですが、このような僅かな変更のためにリソース全体を取得しなおすのは効率的であるとは言えません。 逆に言えば、キャッシュを有効に活用し、その変更部分のみを転送できるのであれば、HTTP は今までよりはるかに効率的にネットワーク帯域幅を使用できるでしょう。 そこで、これを行うために差分エンコーディング {Delta Encoding} と呼ばれる新たな手法が RFC 3229 にて提案されました。

例をあげましょう。 http://www.studyinghttp.net/weather という URL にて、本日の天気予報を掲載していると仮定します。 このサイトの「1 月 1 日に掲載される内容」と「1 月 2 日に掲載される内容」が異なるのは容易に想像がつくと思います。 しかし、この内容の更新の際にも "実際の天気に関する部分" 以外には変更点が全くないという場合が多くあります。 そのような場合、もし 1 月 1 日の内容がキャッシュに入っていれば、変更点部分、つまり差分だけを送信すれば、送信サイズを大きく節約する事ができるわけです。

ところで、差分エンコーディングでは、「現在キャッシュに入っているもの」と「現在 200 レスポンスで返されるもの」の差分が返されるわけですが、この後者を指し示す言葉が、実は RFC 2616 中には用意されていませんでした。 これについて、RFC 3229 の section 3 をご覧下さい。

"entity" の辞書による定義は、"その存在や対象、あるいは概念的現実が他と明確に区別されるもの" である [21]。 不幸にも、HTTP/1.1 中の "entity"の定義は、MIME [12] 中で使用されるそれに似ており、MIME と HTTP との誤った類推に基づくものである。

MIME では、電子メールはメッセージとは区別されるものを持っている。 MIME は "エンティティ" を "特に MIME にて定義されたヘッダフィールドと、あるメッセージかマルチパートメッセージのボディ中の一部分のいずれかの内容を参照する" ようなものとして定義している。

しかし HTTP では、GET へのレスポンスはメッセージとは区別されるものを持ってはいない。 むしろ、それはリソース (あるいはある制約のセットに従うようなバリアント) の現状を反映する。 HTTP/1.1 仕様書では、"現時点において特定されたリソースの選択されたバリアントについて GET リクエストへのレスポンスとして返される値" について記述するための用語はない。 これは、この概念が必要な場所において HTTP/1.1 仕様書中で不適切な表現に通じる。

エンティティという概念は MIME から借りてきたもので、この概念は文字通り電子メールを想定しています。 しかし、メールと Web には決定的な違いがありました。 それは、メールは「情報を送りつける」ものですが、Web は「情報を取りにいく」ものだという事です。

電子メールには、暗黙的にそのメッセージに時間の概念が含まれていると言う事ができます。 基本的に、メールというものはわざわざ同じ情報を二度も送りつけるわけがないからです (最も、SPAM 等は別ですが)。 そのため、我々は「1 月 1 日に送信されたメール」と「1 月 2 日に送信されたメール」は (たとえ、その内容が一語一句同じものであったとしても)、暗黙的に「違うもの」であると認識しているわけです。 従って、MIME では、エンティティを「送信時に送られるもの」とだけ定義しておけばよかったのです。

しかし、HTTP の場合、先程の天気予報サイトの例のように、配信元 URI は基本的に時間が経過しても変わりません (むしろ、不便なので変えるべきではありません)。 原理的に言えば「その URI で返されるべき最新の内容」のみに価値があるはずなので、例えば「1 月 1 日に返されるエンティティ」は「1 月 2 日に返されるエンティティ」によって完全に破棄・上書きされるべきなのです。 従って、HTTP では、エンティティを「受信時に送られるもの」とだけ定義しておけばよかったのです。

差分エンコーディングとは、「1 月 1 日に返されるエンティティ」+「1 月 2 日に変更された点」により、「1 月 2 日に返されるエンティティ」を完成させようという試みなので、「1 月 1 日に返されるエンティティ」と「1 月 2 日に返されるエンティティ」が明らかに違う以上、これは明確に区別されるべきものとなります。 すなわち、現在 HTTP で「エンティティ」と呼ばれているものは、本来時間軸によって区別されなければならないものだったのですが、これを暗黙のうちに使用していたために、余計な混乱をもたらす事になってしまったのです。 そこで RFC 3229 では、そのようなものを明示的に指し示すために、新たな用語を定義しました。

インスタンス{instance}
現時点において、特定されたリソースの選択されたバリアントについて、0 以上の内容コーディングが適用されているが、あらゆるインスタンス操作 (以下参照) や転送コーディングは適用されていないような、GET リクエストに対して、ステータス 200 レスポンス中にて返されるであろうエンティティ。

HTTP/1.1 では、エンティティよりも、インスタンスに関係しているので、エンティティタグについて考える事は便利である。 すなわち、与えられたリソースについて、二つの異なるレスポンスメッセージが同じエンティティタグを持っているかもしれないが、リソースの二つの異なるインスンスは決して同じ (強い) エンティティタグに対応すべきではない。

我々は、この文書にて、二つのインスタンス間の違いとしてエンコードされた HTTP レスポンスを表すために、"差分" という用語を非公式に使用する。

より形式的に言えば、差分エンコーディングは、この新しい用語に結びついた、潜在的にインスタンス上の変形のより大きなクラスのメンバーである:

インスタンス操作{instance manipulation}
部分中、あるいは複数のレスポンスメッセージ中のサーバからクライアントへ運ばれているインスタンスになるであろう一つ以上のインスタンスへの操作。 例えば、範囲選択や差分エンコーディングである。 インスタンス操作はエンドトゥエンドで行われ、しばしばクライアントにてキャッシュの使用を必要とする。

この、インスタンスとリソースやメッセージの違いは、section 4 により詳しく記されています。

 データタイプ    次のデータタイプへ移行するための操作
 ============    ====================================
 リソース
             |   必要であれば、利用可能なバリアントを選択
             v
 バリアント
             |   必要であれば、内容コーディングを適用
             v

             |   エンティティタグを計算/割り当て
             v
 インスタンス
             |   必要であれば、インスタンス操作を適用
             v      (差分エンコーディング, 範囲選択, 等々)
 エンティティボディ
             |   必要であれば、転送コーディングを適用
             v
 メッセージボディ

このインスタンスという概念によって、同一 URL から配信された、配信時刻の異なるエンティティを区別する事ができるようになり、それらのインスタンスの違いを差分と呼ぶ事にしたのです。

この差分を得るためのアルゴリズムについては、section 6 に記述されています。

いくつもの差分エンコーディングのアルゴリズムとフォーマットが、文献に記述されている:

diff -e
UNIX の "diff" プログラムはいたる所で利用可能であり、エンコーディングとデコーディングの速度が相対的に速い(デコーディングは実際には "ed" プログラムを使用して行われる)。 しかし、差分の結果のサイズは相対的に大きい。 このアルゴリズムはテキストフォーマットにのみ使用可能である。
diff -e | gzip
"diff" の出力を "gzip" [5] (あるいは、"deflate" [7, 6] ならばおそらくなお良い) のようなアルゴリズムによって圧縮する事は、よりコンパクトなエンコーディングを出力するが、エンコーディングやデコーディングのコストは"diff" によるものよりは高くなるであろう。 このアルゴリズムはテキストフォーマットにのみ使用可能である。
vcdiff (vdelta)
"vcdiff" フォーマット [19, 20] を生成するアルゴリズムは本質的にその出力を圧縮し、一般に "diff" と "gzip"の組み合わせによる出力よりも小さくなる。 またこのアルゴリズムは実行が早く、バイナリフォーマット入力にも適用できる。 "vcdiff" フォーマットは以前 "vdelta" と名付けられたアルゴリズムへの作業に基づいている。 ("vcdiff"フォーマットは、差分エンコーディングや圧縮されたフォーマットにも使用できるので、もしその使用が圧縮フォーマットとして採用されるならば、二つの異なる instance-manipulation の使用を区別するために、二つの値が登録される必要がある。 ) 最近発表された研究では、"vdelta" は総合的に最良の差分アルゴリズムであるとしている [16]
gdiff
gdiff フォーマット [14] は、差分を表現するために、一般的でアルゴリズムから独立したフォーマットとして指定された。 これはより一般的なものなので実装も容易だが、それは最もコンパクトなエンコーディングフォーマットではないかもしれない。

差分を得るために最も一般的に利用されているプログラムは、UNIX の diff というプログラムです。 この出力を利用したり、この出力を gzip で圧縮したものを利用すれば、差分エンコーディングが実現できるでしょう。

参照文献

Webリソース