multipart/form-data符号化算法

multipart/form-data (MIME)

[11] MIME型 multipart/form-data は、 HTMLフォームの提出で使われるデータ形式です。

[42] application/x-www-form-urlencoded と並んで HTTP POST 要求で最もよく用いられる MIME型の1つです。 パーセント符号化を使う application/x-www-form-url-encoded では扱いづらいファイル (<input type=file>) の提出のために開発されましたが、 ファイルを扱わない場合にも使われています。

仕様書

意味

[157] multipart/form-data は、フォームデータ集合提出のための構文です。

[158] 理論上は MIME の仕組みにより、 HTMLフォームデータ集合よりも多くのものを表現できることになっています。 実用上は、それを逸脱したものはほとんど使われることはなく、 使われるとしても相互運用性の問題につながるだけです。

構文

[40] 基本的には、 multipart/mixed と同じ書式です。 RFC 2046, HTML 4 17.13.4.2, RFC 2388 3.

[159] つまり本体は、境界文字列などで区切られた本体部分の列です。

[160] 境界文字列は、 Content-Type: ヘッダーboundary 引数によって表されます。 boundary 引数は、必須です >>43

これは本体に対応するヘッダー、つまり HTTP で送信する場合は HTTPヘッダー電子メールで送信する場合は電子メールメッセージヘッダーContent-Type: に指定する引数です。 本体部分ヘッダーではありません。

前書き、後書き

[79] どのブラウザも、前書き後書きにします。 Opera が複数のファイルを提出する場合に使う multipart/mixed についてもそうです。 (HTTP の場合のみ調べました。) >>66

境界文字列

[24] 境界文字列 (boundary) はデータ中に現れてはなりません。 HTML 4 17.13.4.2, RFC 2388 4.1

[89] どのブラウザも、 boundary 引数quoted-string ではなく、 token として表現しています。 >>66

Firefox の例:

boundary=---------------------------105742468821884

Opera の例:

boundary=----------ByrdxQC7rqEXna35oMxxa7

Safari の例:

boundary=----WebKitFormBoundaryAAEEAAYDAACjAAHf

WinIE の例:

boundary=---------------------------7d839d460bd2

[124] 古の Netscape Navigatorboundary 引数を含めない不具合があったようです。

ひどいですね・・・。

[129] CGI.pm によれば、 MacIE の 3.01 と 3.02、 DreamPassport には境界文字列の前に -- を含めない不具合があったようです。

transport-padding

[125] MIME の規定によれば、境界文字列のある行の最後には任意個の空白が挿入されることがあり、 利用者エージェントはこれを無視して解釈しなければなりません。

[126] これは生成することは認められていませんが、 メールでは転送路の途中で追加されることがあり得たためそのような規定になっています。

[127] HTTPがこれに対応しているかは怪しいです。

[128] Perlモジュール HTTP::Body はこれに対応していないようです。ほどほどよく使われているモジュールのようなので、 Web互換性のためには必要ないということでしょう。

[130] CGI.pm はコードが酷くてよくわからないのですが (実際に試してみたらいいのでしょうが・・・)、 処理がいいかげんなのでたまたま対応できてるようにも見えます。

改行

[8] MIME の規定により、境界行や実体頭欄の末端の改行は CRLF でなければなりません。 CRLF だけではいけません。

[25] 他のすべての MIME 転送同様、改行は CRLF とします HTML 4 17.13.4.2。 と HTML 4 も言っています。 (転送とはどこからどこまでか、 曖昧であるのが問題ではありますが。)

[9] >>8 は大前提なんですが、 一方で HTTP ではいい加減な実装が多いので、もしかしたら・・・ CR だけとか LF だけとかで送ってくる糞 UA もあったりするんでしょうか?

多分 Mozilla とか Opera とか IE とかの有名どころは大丈夫だと思うんですが。。。

[60] MacIE 5.2 には boundary のところの改行の CR が一部欠落してしまう不具合があるそうです。

MacのIEでのmultipart/form-dataデータ <http://kvasir.skirnir.net/software/software00009.ksd>

[68] 主要ブラウザは multipart/form-data としての改行をすべて CRLF と正しく送信するようです。 >>66

本体部分の個数と順序

[65] 本体部分の個数に特に制限は設けられていないようです。

[23] フォームの各欄は、応用とフォームによって定義された順で、 それぞれ multipart/form-data本体部分とします。 RFC 2388 4.1 本体部分の順序は、 RFC 2388 では規定されていません。 RFC 2388 5.5

[41] HTML の場合、multipart/form-data本体部分は、それぞれ、 成功制御子に対応します。順序は制御子の文書順とします。 HTML 4 17.13.4.2

[180] フォームで順序が規定されている場合は、そのまま送るべきです >>177中間器は入れ替えてはなりません >>177

本体部分のヘッダー

[91] どのブラウザも、本体部分に使う可能性のある頭欄Content-Type:Content-Disposition: だけのようです。他の頭欄は見たことがありません。 >>66

[146] 本体部分には、 Content-Disposition: ヘッダーdisposition型 form-data を指定しなければなりませんname 引数もなければなりません>>145

[162] Content-Disposition: ヘッダーには、更に filename 引数も指定できます。

[163] 他の引数が使われるのは見たことがありません。

[174] Content-Type:Content-Disposition:Content-Transfer-Encoding: 以外の Content- ヘッダーを含めてはなりません。無視しなければなりません>>43

[164]ヘッダー引数の用法は、次節以降を参照。

欄名 (制御子名)

[28] 各欄は名前を持ちます。

[182] 同名の欄が複数含まれることもあります。 同名の欄をまとめてはなりません >>177

[178] RFC 2388 は次のように規定していました。名前はフォーム内で固有です。 RFC 2388 3. 欄名が同じ本体部分が複数あるときの取扱いは RFC 2388 では規定されていません。 RFC 2388 5. このような規定は、当時からまったく現実を反映していませんでした。

[179] 各本体部分は、 Content-Dispositionform-data とし、その name 引数に対応する制御子の欄名 (制御子名) を指定します HTML 4 17.13.4.2, RFC 2388 3.

[29] 詳しくは制御子名も参照。

ファイル情報 (ファイル名など)

[147] 本体部分ファイルの内容を表す場合は、 本体部分Content-Disposition: ヘッダーfilename 引数ファイル名を指定するべきです >>145

[148] ファイル名を取得できない場合や意味が無い場合もあるので、 必須ではありません >>145
[149] 非ASCII文字符号化の深刻な問題については、 filename 引数の項を参照。

[44] フォーム・ソフトウェアは、提出するファイルにファイル名やその他のファイルの属性情報をつけても構いません。 RFC 2388 4.4

[33] HTML UA は提出する各ファイルにファイル名を供給するよう試みるべきです。 ファイル名は Content-Disposition 欄の filename 引数で指定します。HTML 4 17.13.4.2

[45] 提出するファイルは相互にファイル名で参照関係を持っているかもしれませんから、 ファイル名が保存されていると便利です。 HTML 4 17.13.4.2, RFC 2388 4.4

ファイル名指定に関する様々な問題については、 filename 引数の説明をご覧ください。

[71] WinIEフルパス名を値に使います。他のブラウザは狭義のファイル名だけを値に使います。 >>66

[74] どのブラウザでも、 filename は必ず name の後に来るようです。 form-dataname 引数filename 引数の3つだけで、他の情報は付与しないみたいです。 >>66

[131] Perlモジュール HTTP::Bodyfilename 引数の有無によりある実体本体ファイルかどうか判断します。たとえ空文字列であっても、 ファイルならファイル名が必要です。

MIME 型

[26] ほかのすべての multipart/* 型と同様、 各本体部分は省略可能 >>165Content-Type 頭欄を持ちます。省略時の既定値は text/plain です >>165

[166] 媒体型が分かっている場合は適当に札付けし、分からない場合は application/octet-stream とするべきです。 HTML 4 17.13.4.2, RFC 2388 3., RFC 2388 4.1, RFC 2388 4.2, >>165

[76] どのブラウザも、ファイルの場合はそのファイル媒体型Content-Type: 欄として指定し、 それ以外の場合は Content-Type: 欄を省略します。 >>66

[77] ファイルの場合、どのブラウザも、 (おそらく拡張子やシステムの、またはブラウザ内蔵の対応表を使って) ファイルの媒体型を推定できればその値を、できなければ application/octet-stream を使うようです。 確認できた限りでは charset も含めて引数を指定することはありませんでした。 >>66

文字コード

[84] どのブラウザも、すべての実体本体name 引数filename 引数に同じ charset を使うようです。 >>66

[85] 使用することに決めた charset で表現できない文字がある場合、 Unicode における符号位置十進数文字参照形式にしたものが代わりに挿入されます。 >>66

[175] ただし、ファイルは、テキストファイルであっても無変換です。

[86] Opera は以前は multipart/form-data 自体の Content-Type: 欄に charset 引数を指定していましたが (>>2)、 互換性に難があったのか、現在はつけないようです。 他のブラウザも multipart/form-data 自体には boundary 引数だけしか指定しません。 >>66

[168] フォームデータテキストの時は、その本体部分Content-Type: text/plaincharset 引数文字符号化を提示できます >>32

[169] しかし実際には広く使われている実装は charset 引数を指定しません >>32

[1] WinIEMozillaOpera も、 multipart/form-data に含まれる本体部分には charsetパラメーターを付けてくれません。 (ファイル送信を除いて Content-Type 欄そのものをつけません。)

[167] HTML4 は、 HTML UA本体部分Content-Type 欄を (charset 引数を含めて) 供給するべき HTML 4 17.13.4.2 と述べていました。しかし誰もそれに従っていませんでした。

[2] Opera (Presto) は、 multipart/form-data そのものに (存在しない) charset 引数をつけてきます。 この charset 値は実際にはそれに含まれる本体部分の実体本体及び Content-Disposition 欄の name 引数に適用されるようです。あ、 filename にもかな? 今度確かめてみよう。

[4] >>2-3 の情報は、 file として送られる実体本体には適用できません。 (その実体の頭欄には適用されます。) charset=unknown-8bit とでも考えるしかなさそうです。問題は、 一般の form data と file を区別する確実な方法がないことです。 IE, Moz, Opera に限れば、 filename 引数の有無で決定できますが。。。

[5] >>4 あ、確実な方法が1つだけあります。受取る側が名前を知っていること。 これ超確実。

[88] HTML5 や元の Web Forms 2.0application/x-www-form-urlencodedtext/plain提出する場合については _charset_ hack を定義していますが、 multipart/form-data の処理は RFC 2388 に丸投げしているので、 _charset_ hack は正式にはどこでも定義されていませんでした。

[3] その後の改訂で HTML Standardmultipart/form-data の時も _charset_ hack の扱いが規定されるようになりました。

[170] RFC 7578 も、それが既定の charset を規定する >>32 と述べています。

[171] ファイルかどうかをどのように判定するのかは述べられていません。

[87] Safari 以外のブラウザは _charset_ hack に対応しています。 >>66

[30] ファイルの場合、 MIME型Content-Type: ヘッダーに指定されますが、 charset 引数を含め、 引数までは指定されないのが普通です。

Webブラウザー利用者が選択したファイル文字コードまで知らないのが普通です。
[69] 歴史的事項については、 filename制御子名の項目も参照。
[176] RFC 7578RFC 2047 encoded-wordRFC 2231 の方法を使っていた実装もあるかもしれない >>70 として、それら古い方法への対応の必要性も匂わせています。しかし、 そのような実装があったとしても少数で、現在となってはまったく存在感はなく、 対応する必要性は全くないと思われます。

本体部分の実体本体

[31] 各本体部分の本体は、ファイル選択制御子 (input//file) ではファイルの内容、 それ以外では現在値になります。 (という説明が HTML 4 仕様書ではきちんとなされていません。)

内容転送符号化・内容符号化

[27] 各本体部分は CTE を使ってもかまいません。 HTML 4 17.13.4.2, RFC 2388 3., RFC 2388 4.3 その他 MIME の機構により暗号化・圧縮などをしても構いません。 それは multipart/form-data を生成する応用の機能です。 RFC 2388 5.1

[53] ただし、 HTTPmultipart/form-data を使う場合は、仕様が曖昧なためその中の本体部分で Content-Transfer-Encoding を使用するべきではありません。 Content-Encoding を本体部分に適用できるのかどうかも曖昧であり、 使わない方が良いです。 (対応している実装も少ないでしょう。) Transfer-Encoding を本体部分に適用することはできません。

なお、これは multipart/form-data の各本体部分についてであり、 multipart/form-data 実体自体については >>54 をご覧下さい。

[75] どのブラウザも、内容符号化内容転送符号化は使用しないようです。 Content-Transfer-Encoding: 欄や Content-Encoding: 欄も使用していないようです。 (HTTP の場合のみ調べています。) >>66

[14] >>12Content-Transfer-Encoding: 8bitContent-Transfer-Encoding: binary を1つの multipart/form-data で混在させた例を示しています。

[172] RFC 2388 の改訂である RFC 7578 は、 HTTP のように CTE が不要なら、非推奨であり、 Content-Transfer-Encoding: ヘッダーを生成するべきではない >>43 とされています。そのような実装は知られていない >>43 とも述べられています。

[173] しかしなぜか完全に禁止しているわけではないようです。また、 電子メールで使う場合には CTE が適用される可能性はありそうです。

遠隔ファイル指示子

[49] 遠隔ファイルを直接送らずに、 message/external-body を使ってその指示子だけを送ることができます。 RFC 2388 5.3

[52] message/external-body の使い方は色々ありますが、 access-type uri を使って遠隔ファイルの URI参照を送るのが現代的でよろしいのではないでしょうか。

[83] これに対応しているブラウザやフォーム処理エージェントがあるという話は聞いたことがありません。

ファイルの個数

[73] 1つのが複数のファイルを含むときは、 同じ name 引数の異なる本体部分としなければなりません >>72

[82] HTML では、 <input type=file>multiple 属性を指定することで、 利用者が複数のファイルを選択できるようになります。

multipart/mixed 方式

[51] かつては、1つのフォーム項目として複数のファイルを同時に提出する場合には、 multipart/mixed を使って1つの本体部分とすることになっていました。 HTML 4 17.13.4.2, RFC 2388 3., RFC 2388 4.2

[150] しかしこの方式は現在では非推奨とされています >>72

[151] ファイル名等はその multipart/mixed 内のそれぞれの本体部分の情報として付与します。

[34] 提出ファイルが複数の時の multipart/mixed 内の本体部分では Content-Disposition: file とするかのような記述が仕様書にあります HTML 4.01 17.13.4.2 が、 attachment の誤りだそうです HTML 4.01 正誤表 10.みっともないことに HTML 4.01 正誤表は RFC 2388 に責任転嫁しております(w。確かに元々 HTML 4.0 では attachment になっておりましたが、 HTML 4.01 で minor typo として修正されています HTML 4.01 A.1.3

[16] それと直接的に関係あるのかはわかりませんが、 サーバーが UA に保存させるのに、 dispositon 型 file を指定して、 Content-Disposition: file; filename=foo のように指定することがあるようです。 (CGI script とかで。) (正しくはやはり Content-Disposition: attachment。)

[152] HTMLmultipart/form-data の仕様の側では複数のファイルを1つの提出することになってはいましたが、 実際にはこれは (クライアント側でもサーバー側でも) 対応されていませんでした。 そのまま Webブラウザーを拡張するとサーバーが意図しない multipart/mixed データを受信することになってしまうため、 Web Forms 2.0min/max 属性によってサーバーが受信を意図するファイルの個数を明示できるようにしました。

[78] Opera 9 は Web Forms 2.0max 属性による指定を使ったファイルの複数同時提出に対応しています。 複数のファイルが含まれる場合、仕様通り multipart/mixed が使われます。その本体部分については、単体の場合と同じように挿入されます。 Content-Disposition: の値は RFC 2388 とも HTML4 とも違って form-data になります。 name 引数も単一ファイルの場合と同じように指定されます (multipart/mixed の方にも指定されますが、個々の本体部分の方にも指定されます)(複数ファイル指定可能であっても、選択数が1つ以下なら従前の方法によります。) >>66

[153] しかし、結局複数のファイルを受信するためにサーバー側で新たに multipart/mixed に対応しなければならないことには変わりありません。 Web Forms 2.0HTML5 に統合されるに当たり、 min/max 属性による複数ファイル提出機能は廃止され、 代わって新たに mutliple 属性による提出が導入されました。 新方式では multipart/mixed を使わず、同名の複数の本体部分を用いる方法に変更されました。

[154] RFC 7578 はこれを踏まえて multipart/mixed非推奨とし、 HTML が採用した方法を使わなければならないとしました。 その一方で、広い応用可能性を求める応用 (例えばライブラリー) は multipart/mixed 方式も対応するべき >>72 としています。

[155] 実際には Opera (Presto) 以外に旧方式の実装が存在していたかも謎で、 実用上はほとんど意味が無いものです。
[156] multiple が指定されたら同名の複数の本体部分として表現するというのは、 select 要素と共通しています。また同名の本体部分は、 ファイル以外のフォームデータの場合に既に使われています (特にチェックボックスの場合など)。旧仕様がなぜ敢えてファイルの場合だけ multipart/mixed を使うことにしたのかは謎です。

零個のファイルを提出

[6] ファイル選択制御子 (input/file) があっても、ファイル名として何も指定されなかった場合、 WinIE も Mozilla も Opera も、空の内容を送ります。

このとき、 WinIE と Mozilla は頭欄に Content-Type: application/octet-stream と書いてきて、 Content-Disposition にも filename="" がつきます。 Opera ではどちらもつかず、本当に空 (Content-Disposition: form-data; name=名前 と空の内容だけ) になります。

[38] 頭欄がどうであれ、空の実体を送ってしまうと (一般の UA の場合に) ファイル未選択状態と内容が空のファイルを提出した場合が区別できなくなってしまいます。 ファイルを選択していないファイル選択制御子はそもそも成功にしてはいけないのではないでしょうか。

[80] HTML5 でも選択されていないファイル選択制御子フォーム・データ集合に含まれない定義になっていますがね。。。

[81] どのブラウザも、選択されていなくても空の実体本体を含めるようです。 Content-Disposition: はファイル以外の制御子の場合と同じです (filename 引数がつきません)。 Content-Type: は、 Opera 以外は application/octet-stream とします。 Opera自体を省略します。 >>66

multipart/form-data 符号化算法

[110] multipart/form-data 符号化算法 (encoding algorithm) は、 フォーム・データ集合multipart/form-data 実体として符号化するための算法です。

[111] multipart/form-data符号化算法は次のように定義されています >>109

  1. result空文字列とします。
  2. 選択された文字符号化 (selected character encoding) を、
    1. 明示的に文字符号化を指定して呼び出された場合は、それとします。
    2. そうでなく、 form 要素accept-charset 属性を有する場合、
      1. フォーム・データ集合に含まれる名前と値で使われている文字と、 利用者エージェントが対応している文字符号化の種類を鑑み、 属性中に含まれる文字符号化の中から ASCII互換文字符号化であるものいずれか一つとします。
      2. それがない場合は、 UTF-8 とします。
    3. そうでなく、文書の文字符号化ASCII互換文字符号化である場合、それとします。
    4. そうでない場合、 UTF-8 とします。
  3. charset を選択された文字符号化の優先MIME名とします。
  4. フォーム・データ集合の各項目 (entry) について、
    1. 名前が _charset_ で型が hidden なら、 値を charset に置き換えます。
    2. 名前と値の文字のうち、選択された文字符号化で表現できないものを十進数文字参照に置き換えます。
      1. ここ、十進数部分の先導0は特に禁止されていないようです。
  5. フォーム・データ集合RFC 2388 に従って符号化します。

HTML

[10] HTML 4 UA は、 multipart/form-data によるフォームの提出を実装しなければなりません HTML 4 17.13.4 と規定されていました。 HTML5 ではフォーム符号化算法などに完全に組み込まれており、 mutipart/form-data に対応しない実装が適合するのか不明です。

enctype 属性値

[104] HTMLform 要素enctype 属性と、 input 要素button 要素formenctype 属性は、属性値として multipart/form-data を指定することができる列挙型属性です >>103。この値を指定すると、当該要素 (やそのフォームに属する要素であって上書きされていないもの)enctypemultipart/form-data に設定することができます >>103要素enctypeフォーム提出算法から参照されています。

[108] enctypemultipart/form-data の時の適当なフォーム符号化算法multipart/form-data符号化算法です。 >>105

フォーム提出算法

[106] フォーム提出算法において提出する実体本体を構築するに当たり、提出子たるボタン要素enctype が参照されます。それが multipart/form-data である場合、 実体本体MIME型 (Content-Type: 欄の値) としては、

multipart/form-data; boundary=boundary-string
... が使われます。ただし boundary-stringmultipart/form-data境界文字列です。 >>103

[107] つまりすべて小文字で、 SPACE; の直後に1つだけ挿入され、 boundarytoken として表現されます。

API

[143] multipart/form-data そのものに関する DOM API はありませんが、 multipart/form-data で送信されることになるフォームデータ集合を表すオブジェクトとして FormData があります。

[144] FormDataXHR Standard により規定されていますが、 XHR 以外の目的でも使うことができます。

処理

大容量ファイルの受信

[190] multipart/form-data は、ファイルアップロードに使われます。 しかし実のところ multipart/form-data は大容量のファイルの送受信に適した形式というわけでもありません。

[191] multipart/form-data に含めるフォームデータの順序は、 制御子の種別と無関係に決まります。ですから、ファイルがどこに来るかはわかりません (フォーム制御子文書中の位置に依存します)。 受信者 (サーバー) は受信したデータの末尾まで読み終わらないと、 処理に必要なすべてのフォームデータを受信したのかどうか確実に判断することができません。

[192] つまり、サーバーは大容量のファイルが含まれる (かもしれない) multipart/form-data要求本体を全部読み込み終わらないと、 それをどう処理するべきか判断できる保証がありません。 要求本体を単純に先頭から末尾まで読みつつ処理するなら大容量のデータをメモリー上に保持しておく必要がありますし、 それが難しそうなら一時ファイルに書き込んでから処理するしかなさそうです。 どんなデータを与えられるか事前にまったく予測できないプログラミング言語ライブラリーなどでは一時ファイルに保存する方法を選択することが多いようです。

関連

[93] WAP により規定された multipart/form-data に相当するバイナリー表現として、 application/vnd.wap.multipart.form-data 媒体型がありました。

HTML と multipart/form-data

[6] HTML のフォームでは application/x-www-form-urlencoded もよく使われていますが、任意のバイナリ・データや非 ASCII 文字を効率よく確実に扱うことができないという問題があります。 バイナリ・データや非 ASCII 文字を含むフォームの提出では、 multipart/form-data を使うべきです HTML 4 17.13.4.2。 ファイル選択制御子 (input/file) を使う時には、 multipart/form-dataformenctype で指定するべきです HTML 4 17.3, 17.13.4.2

[35] HTML のフォームで multipart/form-data で提出させたい時は、 form 要素の enctype 属性に multipart/form-data と指定しておきます。

各本体部分の文字符号化方式の決定には、 form 要素の accept-charset 属性の指定を参照します。

転送プロトコルと multipart/form-data

[54] MIME の規定によれば、 multipart/* のすべての実体Content-Transfer-Encoding7bit, 8bit, binary のいずれかでなければなりません。もちろん multipart/form-data の実体にも適用されます。

注意: multipart/form-data本体部分についての規定ではありません。 本体部分の CTE については >>53 を参照して下さい。

[55] HTTP では Content-Transfer-Encoding を使用しません (常に binary 相当です) が、 Content-EncodingTransfer-Encoding があります。 Transfer-Encoding は媒体型に依存しませんので、 multipart/form-data であろうがそうでなかろうが常に使用できます。 Content-Encoding が使用できるのかどうかは微妙なところですが、 特別規定がないのですから、使用できるのでしょう。但し、 それに対応している実装 (クライアント・鯖) がどれだけあるのかは微妙なところです。

[56] Content-MD5 による簡易的な整合性情報は、 MIME では multipart/* に対して使用することが認められていませんが、 HTTP では認められています。 multipart/form-data についても例外ではありません。

しかし、 multipart/form-data 全体の MD5 ハッシュを計算するよりは、面倒でも個々の本体部分で計算した方が良いでしょう。 もし HTTP で提出された multipart/form-data が途中で MIME に変換されて (例えば電子メイルで) 送られるとすると困ったことになります。

[64] そんなことあるのか知りませんがw

その他

保安性

[50] multipart/form-data を構成するプロトコル要素やフォームの仕組み自体には、 様々な安全上の問題があることが知られています。

例えば、利用者の意図しない状態や利用者が十分な考慮を行えない状況で自動的・ 半自動的にフォームを提出させると、 利用者の私的な情報や利用者の環境の安全に関わる情報が送信されてしまう虞があります。 このほかにも、フォームの提出という仕組みそのものに起因する問題が多く見つかっています。

また、ファイルを提出する際には filename 引数を使うことができますが、フォーム処理エージェント (multipart/form-data を処理する側) が信頼して無防備に実際のファイル名等として使用すると、 既存の別のファイルやシステム・ファイルを上書きしたり、 その環境で扱えないファイル名のファイルが中途半端にできてしまったりする虞があります。 詳しくは filename 引数の説明をご覧ください。

このようなフォーム自体や multipart/form-data が利用しているプロトコル要素に関する問題や、 特定の実装に依存した問題を除いては、 multipart/form-data に関する安全上の問題は見つかっていません。

[57] 提出の途中での改竄を検出する簡易的な手段として Content-MD5 が使用できます (>>56)。 但し記述された Content-MD5 値自体が改竄されることもあり得ますから、 あくまで簡易的なものです。また、 実装している利用者エージェントは現時点で存在しないと思われます。

[58] 一般の MIME の実体の安全のための仕組みとして署名のための multipart/signed暗号化のための multipart/encrypted が、 それを使った実際のシステムとして PGP/MIMES/MIME があります。しかし、現実に multipart/form-data と組合せて使っている (使える) 例は聞いたことがありません。 multipart/form-data のどの部分を署名・暗号化するのか (あるいは全体をするのか) や、フォームの提出の手続きの中でどのように処理するのかなどの詳細な標準化がなされないと (またはデファクト標準が登場しないと) 使用するのは難しいでしょう。

[59] 現実にフォームの提出の安全のために使用されているのは TLSSSL です。 HTTP に対応した利用者エージェントや鯖では大抵 TLS over HTTP (HTTPS) が利用できるので、 フォーム処理エージェントとしては特別な処理が要らないのが普通です。 但し、 HTTP 以外の提出方法 (特に電子メイル) にはこの方法は使えません。

歴史

実装開始

[15] WinIE 3.02 用の file upload add-on は1997年の中ごろに出ました。

RFC 1867

HTML4 と RFC 2388

[92] RFC 1867 と RFC 2388 と HTML 4 の multipart/form-data の規定は文章を流用していて同じようなことが書いてありますが、 少しずつ違います。独立の仕様書になっている RFC 2388 が当然一番詳しくなっています。

[7] HTML 4multipart/form-data への言及の変遷:
  1. 勧告以前の HTML 4 原案では、高々紹介程度で RFC 1867 にほぼ丸投げ。
  2. HTML 4.0 勧告第1版: Forms in HTML documents <http://www.w3.org/TR/REC-html40-971218/interact/forms.html#didx-multipartform-data>
  3. HTML 4.0 勧告第2版: Forms in HTML documents <http://www.w3.org/TR/1998/REC-html40-19980424/interact/forms.html#didx-multipartform-data>
    • 勧告第1版と全く同内容
  4. HTML 4.01 勧告提案: Forms in HTML documents <http://www.w3.org/TR/1999/PR-html40-19990824/interact/forms.html#didx-multipartform-data>
    • RFC 1867 から RFC 2388 に参照先を変更
  5. HTML 4.01 勧告: Forms in HTML documents <http://www.w3.org/TR/1999/REC-html401-19991224/interact/forms.html#didx-multipartform-data>
  6. HTML 4.01 正誤表: HTML 4 Errata <http://www.w3.org/MarkUp/html4-updates/errata#entry-10>
    • 勧告での attachment から file に再修正。しかも RFC 2388 に責任転嫁(藁

[22] multipart/form-data 内容は RFC 2045 で説明された多部分 MIME データ列の規則に従います。 multipart/form-data の定義は IANAREG から入手できます。 HTML 4 17.13.4.2 と書いてありますけど、むしろ RFC 2046 を読むべきでしょう。 また、後方互換性, 他の内容型との関係, 効率の問題その他については RFC 1867 HTML 4.0 17.13.4.2RFC 2388 HTML 4.01 17.13.4.2 を読むよう指示があります。 ちなみに、仕様書の発行順序は HTML 4.0 → RFC 2388 → HTML 4.01 です。

[95] HTML4フォーム非ASCII文字提出される可能性がある場合に application/x-www-form-urlencoded の代わりに multipart/form-data を使うことを勧めていましたが、 世間からは完全に無視されています。

device-upload

[98] device-upload では、音声等の新しいファイルうpの方法に適用するための device などの Content-Disposition: 引数を提案し、 その指定方法を規定していました。

HTML 以外への展開

[99] VoiceXML 解釈器multipart/form-data に対応することが義務付けられています VoiceXML 2.1

[96] XForms でも、「互換性のため」としながらも multipart/form-data を使うことができます。ただし、 XForms のモデル上のすべての情報を含められるわけではなく、 例えば属性節点に相当する情報は欠落します。

XForms は注記として、既存の HTML 利用者エージェント非ASCII文字等の扱いが芳しくないことを指摘しています。 それとどう関係があるのか知りませんが (だからきちんと処理するよう指導しているわけでもありません)、 multipart/relatedapplication/xml を使うことを勧めています。

[97] WSDL でも、 「XForms との互換性のため」として multipart/form-data を使うことができます。

WF2 と HTML5

[121] WF2 ははじめてフォーム提出算法を明確な形で仕様として規定しました。その中に multipart/form-data による提出の方法も含まれていました。

[122] HTML Living Standard (HTML5 / Web Applications 1.0) はこれを引き継ぎ、 更により明確かつ具体的に multipart/form-data の処理も規定しています。

[123] とはいえ、いずれの仕様書も multipart/form-data 自体の生成の部分は RFC に委ねており、 >>102 により曖昧な部分を明確化したとはいえ、結果として delta spec のような状態になっています。

RFC 7578

[46] 2015年7月には、 RFC 2388廃止して新たに RFC 7578 が出版されています。

[142] Webブラウザー業界からの要求がようやく少しずつ反映されて、 実態により近い形に改訂されています。 (とはいうものの、 基本的には昔ながらの IETFRFC のスタイルからは脱却できず、 現代 Web標準レベルの正確な仕様書にはなっていません。)

実装

[36] 現代のほとんどの WWWブラウザmultipart/form-data によるフォームの提出を実装しています。

[37] 一方、 CGIスクリプトなどの鯖側は酷い状況です。 多くの実装は相手にもしていません。 Perl なら CGI.pm などを使えば自動的に対応できますが、最近は増えてきたとはいえモジュールを CGI スクリプトで使うことは少なく、 application/x-www-form-urlencoded にしか対応していません。ファイルのうpがしたくなったら (素直にモジュールを使えばいいのに) 見よう見まねで適当に対処しようとして、 結局特定ブラウザの特定の版でしか上手く動かないようなコードを書いてみたり。 (で、質問掲示板で暴れてみたり。) お前らちゃんと仕様書読んでくださいよ。

処理系で標準または標準に近いモジュール的なものが要求の解析をしてくれることが広く知られていて、 そのモジュール的なものの作者がちゃんと仕様を読んでコードを書くような人なら、 その処理系で書かれた処理はさほど深く考えなくても自動的に multipart/form-data を正しく処理できるはずです。 よく知りませんけど、 Java servelet とか PHP はその辺きちんとしてるのではないですか?

[66] Firefox 3.0.4、Opera 9.61、Safari 3.2、WinIE 7 の実装状況を調べてみました。

[94] enctype="multipart/form-data"で携帯からファイルアップロード « 携帯・モバイル « プログラム « Re: (kronekodow 著, 版) <http://blog.livedoor.jp/kronekodow/archives/64944587.html>

SoftBankが素敵に思えた。

データフォルダから直アップできるんですね。

fileup_auauは(W52SHは)Browse...ってボタンは出るものの反応しない。

DoCoMoはボタンすら出ない。

SoftBankでも、C端末、3GC端末などによる違など全てじゃなかったり、auも一部端末なら出来たり?(HTMLやXHTMLの違いなども関係したり)とか、可能な端末の振り分けは大変そうです。

複数ファイルをまとめて提出

[13] 1つのファイル選択制御子 (input//file) を使って複数ファイルをうpする (>>51) のは、 UA で対応してるのはなさげ、 サーバーもおそらく全滅だろうという感じですね。

www-htmlOpera の特定の版では出来るという未確認情報がありましたが、 最新版では出来ないらしいし、勘違いかなんかじゃないかなあ。

[67] その後 Opera 9 は Web Forms 2.0 に対応しましたので、 複数ファイルの提出にも対応しています。 file 制御子用の max 属性は一旦 HTML5 で削除されましたが、 multiple 属性が改めて追加される予定ですから、 いずれ他のブラウザも複数ファイルの提出に対応すると期待されます。

試験事例

[90] Index of /~wakaba/-temp/test/html/form/multipart-form-data ( 版) <http://suika.fam.cx/~wakaba/-temp/test/html/form/multipart-form-data/>

[39] HTML のフォームの例 HTML 4 17.13.4.2、改

 <FORM action="http://server.example/cgi/handle"
       enctype="multipart/form-data"
       method="post">
   <P>
   What is your name? <INPUT type="text" name="submit-name"><BR>
   What files are you sending? <INPUT type="file" name="files"><BR>
   <INPUT type="submit" value="Send"> <INPUT type="reset">
 </FORM>

このフォームで、文章入力欄に Larry と記入し、ファイル選択で file1.txt を指定して提出した場合 HTML 4 17.13.4.2, 改:

Content-Type: multipart/form-data; boundary=AaB03x

--AaB03x
Content-Disposition: form-data; name="submit-name"

Larry
--AaB03x
Content-Disposition: form-data; name="files"; filename="file1.txt"
Content-Type: text/plain

... contents of file1.txt ...
--AaB03x--

更に file2.gif も選択していた場合 HTML 4 17.13.4.2, 改:

Content-Type: multipart/form-data; boundary=AaB03x

--AaB03x
Content-Disposition: form-data; name="submit-name"

Larry
--AaB03x
Content-Disposition: form-data; name="files"
Content-Type: multipart/mixed; boundary=BbC04y

--BbC04y

Content-Disposition: file attachment; filename="file1.txt"
Content-Type: text/plain

... contents of file1.txt ...
--BbC04y
Content-Disposition: file attachment; filename="file2.gif"
Content-Type: image/gif
Content-Transfer-Encoding: binary

...contents of file2.gif...
--BbC04y--
--AaB03x--

[47] ユーロ通貨記号を値に使った例 RFC 2388 4.5、改

Content-Type: multipart/form-data; boundary="AaB03x"

--AaB03x
content-disposition: form-data; name="field1"
content-type: text/plain; charset=windows-1250
content-transfer-encoding: quoted-printable

Joe owes =80100.
--AaB03x--

Q & A

[63] Q: HTML でファイルをアップロードするにはどうしたらいいですか? ファイル名しか取得できません...

A: ファイル名しか取得できないのは、 application/x-www-form-urlencoded を使用しているからの可能性が高いと考えられます。 フォームの提出で multipart/form-data を使うようにしましょう。

関連: >>61, input//file, 提出

[61] Q: HTML によるフォームの提出でブラウザに multipart/form-data で送ってもらうにはどうしたらいいですか?

A: form 要素の enctype 属性を multipart/form-data と指定してください。

ついでに、 accept-charset 属性に希望する文字コードも指定しておきましょう。

method 属性を post にしておくのを忘れないように。

関連: form, enctype, 提出

[62] Q: CGI スクリプトで multipart/form-dataapplication/x-www-form-urlencoded を見分けるにはどうしたらいいですか?

A: CGI には CONTENT_TYPE というメタ変数 (環境変数) があります。その値で判別できます。

CONTENT_TYPE の値の先頭の19文字が multipart/form-data (大文字・小文字の区別なし) で、その次の文字が存在しないか、空白 (間隔タブ改行) か、セミコロン (;) なら、 multipart/form-data が使われています。

CONTENT_TYPE の値の先頭35文字が application/x-www-form-urlencoded (大文字・小文字の区別なし) で、その次の文字が存在しないか、空白 (間隔タブ改行) か、セミコロン (;) なら、 application/x-www-form-urlencoded が使われています。

それ以外なら、未知の何かが使われています。

関連: Content-Type, CONTENT_TYPE

メモ

Web アプリケーション 開発

[100] XForms 1.1 ( 版) <http://www.w3.org/TR/2009/REC-xforms-20091020/#serialize-form-data>

[132] IRC logs: freenode / #whatwg / 20120502 ( ( 版)) <http://krijnhoetmer.nl/irc-logs/whatwg/20120502#l-1099>

[133] IRC logs: freenode / #whatwg / 20120616 ( ( 版)) <http://krijnhoetmer.nl/irc-logs/whatwg/20120616#l-355>

[134] [whatwg] multipart/form-data filename encoding: unicode and special characters ( ( 版)) <http://lists.whatwg.org/pipermail/whatwg-whatwg.org/2012-July/036579.html>

[135] Bug 16909 – multipart/form-data: field name encoding is not specified; browsers do incompatible things ( ( 版)) <https://www.w3.org/Bugs/Public/show_bug.cgi?id=16909>

[136] <https://github.com/masinter/multipart-form-data/>

[137] IRC logs: freenode / #whatwg / 20131010 ( ( 版)) <http://krijnhoetmer.nl/irc-logs/whatwg/20131010#l-1183>

[138] ( ( 版)) <http://www.ietf.org/proceedings/88/slides/slides-88-appsawg-8.pdf>

[139] What's the holdup? · Issue #17 · masinter/multipart-form-data ( ( 版)) <https://github.com/masinter/multipart-form-data/issues/17>

[140] IRC logs: freenode / #whatwg / 20140630 ( ( 版)) <http://krijnhoetmer.nl/irc-logs/whatwg/20140630>

[141] Ajax with FormData is Broken on IE10 / IE11 in Some Conditions « 鴨七・chitsaou ( (Yu-Cheng Chuang 著, 版)) <http://blog.yorkxin.org/posts/2014/02/06/ajax-with-formdata-is-broken-on-ie10-ie11>

[20] Batch Requests | ArangoDB Documentation ( ( 版)) <https://docs.arangodb.com/HttpBatchRequest/README.html>

[181] MIME Type Detection in Windows Internet Explorer (Windows) ( 版) <https://msdn.microsoft.com/en-us/library/ms775147(v=vs.85).aspx>

[183] Fix form submission's encoding algorithms ( (annevk著, )) <https://github.com/whatwg/html/commit/ec42efb1d7c3a2e34db21b8076a8a3f4bd6dfb81>

[184] 16909 – multipart/form-data: field name encoding is not specified; browsers do incompatible things ( ()) <https://www.w3.org/Bugs/Public/show_bug.cgi?id=16909>

[185] RFC 2388 has been obsoleted by RFC 7578 · Issue #398 · whatwg/html ( ()) <https://github.com/whatwg/html/issues/398>

[186] 136676 – no quoting at all in MIME-Headers (Content-Disposition header not escaped) ( ()) <https://bugzilla.mozilla.org/show_bug.cgi?id=136676>

[187] Editorial: reference RFC 7578 instead of RFC 2388 (eehakkin著, ) <https://github.com/whatwg/fetch/commit/5d5e80db32cf917233ffa4e95c032f86b7d9f42c>

[188] Add a space before multipart/form-data's boundary parameter (annevk著, ) <https://github.com/whatwg/fetch/commit/4f53460fc2d1773ef38633c3c7ac23cf1affb08c>

[189] Clarify package data algorithm for FormData (eehakkin著, ) <https://github.com/whatwg/fetch/commit/e03ee6fc7f6234005a058d9784e95861b9a0a301>

[193] S2-045 - Apache Struts 2 Documentation - Apache Software Foundation () <https://cwiki.apache.org/confluence/display/WW/S2-045>

Implement a Servlet filter which will validate Content-Type and throw away request with suspicious values not matching multipart/form-data.

[194] Micropub () <https://micropub.net/draft/#form-encoded-and-multipart-requests-p-1>

For x-www-form-urlencoded and multipart/form-data requests, Micropub supports an extension of the standard URL encoding that includes explicit indicators of multi-valued properties. Specifically, this means in order to send multiple values for a given property, you must append square brackets [] to the property name.

[195] RCS MaaP Chatbot API Specifications Version 1.0 () <https://www.gsma.com/futurenetworks/wp-content/uploads/2017/11/FNW.11_v1.0.pdf>

[196] Move _charset_ handling to construct the form data set (tkent-google著, ) <https://github.com/whatwg/html/commit/8c212e549607a41b6d40d953b47d9f3e749533f3>

[197] Move _charset_ handling from "multipart/form-data encoding algorithm"… by tkent-google · Pull Request #3645 · whatwg/html () <https://github.com/whatwg/html/pull/3645>