[11] [[MIME型]] [DFN[[CODE(MIME)[multipart/form-data]]]]
は、 [[HTML]] の[[フォームの提出]]で使われる[[データ形式]]です。

[42] [CODE(MIME)@en[[[application/x-www-form-urlencoded]]]] と並んで [[HTTP]]
[CODE(HTTP)@en[[[POST]]]] [[要求]]で最もよく用いられる [[MIME型]]の1つです。
[[パーセント符号化]]を使う
[CODE(MIME)@en[application/x-www-form-url-encoded]]
では扱いづらい[[ファイル]] ([CODE(HTML)[<input type=file>]]) の[[提出][フォーム提出]]のために開発されましたが、
[[ファイル]]を扱わない場合にも使われています。

* 仕様書

[REFS[
- [43] '''[CITE@en[RFC 7578 - Returning Values from Forms: multipart/form-data]] ([TIME[2015-07-19 23:17:07 +09:00]] 版) <https://tools.ietf.org/html/rfc7578>'''
-- [145] [CITE@en[RFC 7578 - Returning Values from Forms: multipart/form-data]] ([TIME[2015-07-19 23:17:07 +09:00]] 版) <https://tools.ietf.org/html/rfc7578#section-4.2>
-- [72] [CITE@en[RFC 7578 - Returning Values from Forms: multipart/form-data]] ([TIME[2015-07-19 23:17:07 +09:00]] 版) <https://tools.ietf.org/html/rfc7578#section-4.3>
-- [165] [CITE@en[RFC 7578 - Returning Values from Forms: multipart/form-data]] ([TIME[2015-07-19 23:17:07 +09:00]] 版) <https://tools.ietf.org/html/rfc7578#section-4.4>
-- [32] [CITE@en[RFC 7578 - Returning Values from Forms: multipart/form-data]] ([TIME[2015-07-19 23:17:07 +09:00]] 版) <https://tools.ietf.org/html/rfc7578#section-4.5>
-- [70] [CITE@en[RFC 7578 - Returning Values from Forms: multipart/form-data]] ([TIME[2015-07-19 23:17:07 +09:00]] 版) <https://tools.ietf.org/html/rfc7578#section-5.1.3>
-- [177] [CITE@en[RFC 7578 - Returning Values from Forms: multipart/form-data]] ([TIME[2015-07-19 23:17:07 +09:00]] 版) <https://tools.ietf.org/html/rfc7578#section-5.2>
- [103] [CITE@en-US-x-hixie[HTML Standard]] ([TIME[2012-03-19 22:29:46 +09:00]] 版) <http://www.whatwg.org/specs/web-apps/current-work/#attr-fs-enctype>
- [105] [CITE@en-US-x-hixie[HTML Standard]] ([TIME[2012-03-19 22:29:46 +09:00]] 版) <http://www.whatwg.org/specs/web-apps/current-work/#form-submission-algorithm>
- [109] '''[CITE@en-US-x-hixie[HTML Standard]] ([TIME[2012-03-19 22:29:46 +09:00]] 版) <http://www.whatwg.org/specs/web-apps/current-work/#multipart-form-data>'''
]REFS]

* 意味

[157] [CODE(MIME)@en[[[multipart/form-data]]]] は、[[フォームデータ集合]]の[[提出]]のための構文です。

;; [[フォームデータ集合]]を参照。

;; [158] 理論上は [[MIME]] の仕組みにより、 [[HTML]] 
の[[フォームデータ集合]]よりも多くのものを表現できることになっています。
実用上は、それを逸脱したものはほとんど使われることはなく、
使われるとしても[[相互運用性]]の問題につながるだけです。

* 構文

[40] 基本的には、 [CODE(MIME)[[[multipart/mixed]]]] と同じ書式です。
[SRC[[[RFC 2046]], HTML 4 17.13.4.2, RFC 2388 3.]]

[159] つまり[[本体]]は、[[境界文字列]]などで区切られた[[本体部分]]の列です。

[160] [[境界文字列]]は、 [CODE(HTTP)@en[[[Content-Type:]]]] [[ヘッダー]]の
[CODE(MIME)@en[[[boundary]]]] [[引数]]によって表されます。
[CODE(MIME)@en[[[boundary]]]] [[引数]]は、[[必須]]です [SRC[>>43]]。

;; これは[[本体]]に対応する[[ヘッダー]]、つまり [[HTTP]] で送信する場合は
[[HTTPヘッダー]]、[[電子メール]]で送信する場合は[[電子メール]]の[[メッセージヘッダー]]の
[CODE(HTTP)@en[[[Content-Type:]]]] に指定する[[引数]]です。
[[本体部分]]の[[ヘッダー]]ではありません。

** 前書き、後書き

[79] どのブラウザも、[[前書き]]も[[後書き]]も[[空]]にします。
[[Opera]] が複数のファイルを[[提出]]する場合に使う [CODE(MIME)@en[[[multipart/mixed]]]]
についてもそうです。
([[HTTP]] の場合のみ調べました。)
[SRC@en[>>66]]

** 境界文字列

[24] [[境界文字列]] ([CODE(MIME)[[[boundary]]]]) はデータ中に現れてはなりません。
[SRC[HTML 4 17.13.4.2, RFC 2388 4.1]]

[89] どのブラウザも、 [CODE(MIME)@en[[[boundary]]]] [[引数]]は [[quoted-string]]
ではなく、 [[token]] として表現しています。
[SRC@en[>>66]]

[[Firefox]] の例:
[PRE(MIME example code)[
boundary=---------------------------105742468821884
]PRE]

[[Opera]] の例:
[PRE(MIME example code)[
boundary=----------ByrdxQC7rqEXna35oMxxa7
]PRE]

[[Safari]] の例:
[PRE(MIME example code)[
boundary=----WebKitFormBoundaryAAEEAAYDAACjAAHf
]PRE]

[[WinIE]] の例:
[PRE(MIME example code)[
boundary=---------------------------7d839d460bd2
]PRE]

[HISTORY[

[124] 古の [[Netscape Navigator]] は [CODE(MIME)@en[[[boundary]]]] [[引数]]を含めない不具合があったようです。

;; ひどいですね・・・。

[129] [[CGI.pm]] によれば、 [[MacIE]] の 3.01 と 3.02、 [[DreamPassport]] には[[境界文字列]]の前に
[CODE(MIME)[--]] を含めない不具合があったようです。

]HISTORY]

** transport-padding

[125] [[MIME]] の規定によれば、境界文字列のある行の最後には任意個の[[空白]]が挿入されることがあり、
[[利用者エージェント]]はこれを無視して解釈しなければなりません。

;; [126] これは生成することは認められていませんが、
[[メール]]では[[転送路]]の途中で追加されることがあり得たためそのような規定になっています。

[127] [[HTTP]] の[[鯖]]がこれに対応しているかは怪しいです。

[128] [[Perlモジュール]] [[HTTP::Body]] はこれに対応していないようです。ほどほどよく使われているモジュールのようなので、
[[Web互換性]]のためには必要ないということでしょう。

;; [130] [[CGI.pm]] はコードが酷くてよくわからないのですが (実際に試してみたらいいのでしょうが・・・)、
処理がいいかげんなのでたまたま対応できてるようにも見えます。

** 改行

[8] MIME の規定により、境界行や実体頭欄の末端の改行は [CODE(char)[[[CRLF]]]] 
でなければなりません。 [CODE(char)[[[CR]]]] や [CODE(char)[[[LF]]]] 
だけではいけません。

[25] 他のすべての MIME 転送同様、改行は [CODE(char)[[[CRLF]]]] とします
[SRC[HTML 4 17.13.4.2]]。
と HTML 4 も言っています。 ([Q[転送]]とはどこからどこまでか、
曖昧であるのが問題ではありますが。)

[9] >>8 は大前提なんですが、
一方で HTTP ではいい加減な実装が多いので、もしかしたら・・・ [CODE(char)[CR]]
だけとか [CODE(char)[LF]] だけとかで送ってくる糞
UA もあったりするんでしょうか?

多分 [[Mozilla]] とか [[Opera]]
とか [[IE]] とかの有名どころは大丈夫だと思うんですが。。。

[60]
[[MacIE]] 5.2 には [CODE(MIME)[[[boundary]]]] のところの改行の
[CODE(ABNF)[[[CR]]]] が一部欠落してしまう不具合があるそうです。

[CITE[MacのIEでのmultipart/form-dataデータ]] <http://kvasir.skirnir.net/software/software00009.ksd>

[68] 主要ブラウザは [CODE(MIME)@en[[[multipart/form-data]]]] としての[[改行]]をすべて 
[[CRLF]] と正しく送信するようです。
[SRC@en[>>66]]

[[#comment]]

** 本体部分の個数と順序

[65] [[本体部分]]の個数に特に制限は設けられていないようです。

[23] 
フォームの各欄は、応用とフォームによって定義された順で、
それぞれ [CODE(MIME)[multipart/form-data]] の[[本体部分]]とします。
[SRC[RFC 2388 4.1]] 本体部分の順序は、 RFC 2388
では規定されていません。 [SRC[RFC 2388 5.5]]

[41]
HTML の場合、[CODE(MIME)[multipart/form-data]] の[[本体部分]]は、それぞれ、
[[成功]]制御子に対応します。順序は制御子の[[文書順]]とします。
[SRC[HTML 4 17.13.4.2]]

[180] [[フォーム]]で順序が規定されている場合は、そのまま送る[['''べきです''']]
[SRC[>>177]]。[[中間器]]は入れ替えては[['''なりません''']] [SRC[>>177]]。

@@ 空の[[フォームデータ集合]]の場合

** 本体部分のヘッダー

[91] どのブラウザも、[[本体部分]]に使う可能性のある[[頭欄]]は
[CODE(MIME)@en[[[Content-Type:]]]] と [CODE(MIME)@en[[[Content-Disposition:]]]]
だけのようです。他の[[頭欄]]は見たことがありません。
[SRC@en[>>66]]

;; [161] [[HTTP]] や [[電子メール]]の[[ヘッダー]]ではなく、[[本体部分]]の[[ヘッダー]]です。

[146] [[本体部分]]には、 [CODE(MIME)@en[[[Content-Disposition:]]]]
[[ヘッダー]]で [[disposition型]] [CODE(MIME)@en[[[form-data]]]]
を指定しなければ[['''なりません''']]。 [CODE(MIME)@en[[[name]]]]
[[引数]]もなければ[['''なりません''']]。 [SRC[>>145]]

[162] [CODE(MIME)@en[[[Content-Disposition:]]]] [[ヘッダー]]には、更に
[CODE(MIME)@en[[[filename]]]] [[引数]]も指定できます。

[163] 他の[[引数]]が使われるのは見たことがありません。

[174] [CODE(MIME)@en[[[Content-Type:]]]]、[CODE(MIME)@en[[[Content-Disposition:]]]]、
[CODE(MIME)@en[[[Content-Transfer-Encoding:]]]] 以外の [CODE(MIME)@en[[[Content-]]]]
[[ヘッダー]]を含めては[['''なりません''']]。無視しなければ[['''なりません''']]。 [SRC[>>43]]

[164] 各[[ヘッダー]]、[[引数]]の用法は、次節以降を参照。

** 欄名 (制御子名)

[28] 各欄は名前を持ちます。

[182] 同名の欄が複数含まれることもあります。
同名の欄をまとめては[['''なりません''']] [SRC[>>177]]。

;; [178] [[RFC 2388]] は次のように規定していました。名前はフォーム内で固有です。
[SRC[RFC 2388 3.]] 欄名が同じ本体部分が複数あるときの取扱いは
RFC 2388 では規定されていません。 [SRC[RFC 2388 5.]]
このような規定は、当時からまったく現実を反映していませんでした。

[179] 各本体部分は、 [CODE(MIME)[[[Content-Disposition]]]]
を [CODE(MIME)[[[form-data]]]] とし、その [CODE(MIME)[[[name]]]]
引数に対応する制御子の欄名 ([[制御子名]]) を指定します
[SRC[HTML 4 17.13.4.2, RFC 2388 3.]]。

;; [29] 詳しくは[[制御子名]]も参照。

** ファイル情報 (ファイル名など)

[147] [[本体部分]]が[[ファイル]]の内容を表す場合は、
[[本体部分]]の [CODE(MIME)@en[[[Content-Disposition:]]]] [[ヘッダー]]の
[CODE(MIME)@en[[[filename]]]] [[引数]]で[[ファイル名]]を指定する[['''べきです''']]
[SRC[>>145]]。

;; [148] [[ファイル名]]を取得できない場合や意味が無い場合もあるので、
必須ではありません [SRC[>>145]]。

;; [149] [[非ASCII文字]]の[[符号化]]の深刻な問題については、
[CODE(MIME)@en[[[filename]]]] [[引数]]の項を参照。

[44] フォーム・ソフトウェアは、[[提出]]する[[ファイル]]にファイル名やその他のファイルの属性情報をつけても構いません。
[SRC[RFC 2388 4.4]]

[33] HTML UA は提出する各ファイルにファイル名を供給するよう試みるべきです。
ファイル名は [CODE(MIME)[Content-Disposition]] 欄の
[CODE(MIME)[[[filename]]]] 引数で指定します。[SRC[HTML 4 17.13.4.2]]

[45]
提出するファイルは相互にファイル名で参照関係を持っているかもしれませんから、
ファイル名が保存されていると便利です。 [SRC[HTML 4 17.13.4.2, RFC 2388 4.4]]

ファイル名指定に関する様々な問題については、
[CODE(MIME)[[[filename]]]] 引数の説明をご覧ください。

[71] [[WinIE]] は[[フルパス名]]を値に使います。他のブラウザは狭義の[[ファイル名]]だけを値に使います。
[SRC@en[>>66]]

[74] どのブラウザでも、 [CODE(MIME)@en[[[filename]]]] は必ず
[CODE(MIME)@en[[[name]]]] の後に来るようです。
[CODE(MIME)@en[[[form-data]]]] と [CODE(MIME)@en[[[name]]]] [[引数]]と
[CODE(MIME)@en[[[filename]]]] [[引数]]の3つだけで、他の情報は付与しないみたいです。
[SRC@en[>>66]]

[131] [[Perlモジュール]] [CODE(perl)@en[[[HTTP::Body]]]] は [CODE(MIME)@en[[[filename]]]]
[[引数]]の有無によりある[[実体本体]]が[[ファイル]]かどうか判断します。たとえ[[空文字列]]であっても、
[[ファイル]]なら[[ファイル名]]が必要です。

** MIME 型

[26] ほかのすべての [CODE(MIME)[[[multipart/[VAR[*]]]]]] 型と同様、
各本体部分は省略可能 [SRC[>>165]] な [CODE(MIME)[[[Content-Type]]]]
頭欄を持ちます。省略時の既定値は [CODE(MIME)[[[text/plain]]]] です [SRC[>>165]]。

[166] 媒体型が分かっている場合は適当に札付けし、分からない場合は
[CODE(MIME)[[[application/octet-stream]]]] とする[['''べき''']]です。
[SRC[HTML 4 17.13.4.2, RFC 2388 3., RFC 2388 4.1, RFC 2388 4.2, >>165]]

[76] どのブラウザも、[[ファイル]]の場合はその[[ファイル]]の[[媒体型]]を
[CODE(MIME)@en[[[Content-Type]]:]] 欄として指定し、
それ以外の場合は [CODE(MIME)@en[[[Content-Type]]:]] 欄を省略します。
[SRC@en[>>66]]

[77] [[ファイル]]の場合、どのブラウザも、 
[WEAK[(おそらく[[拡張子]]やシステムの、またはブラウザ内蔵の対応表を使って)]]
ファイルの[[媒体型]]を推定できればその値を、できなければ
[CODE(MIME)@en[[[application/octet-stream]]]] を使うようです。
確認できた限りでは [CODE(MIME)@en[[[charset]]]] も含めて[[引数]]を指定することはありませんでした。
[SRC@en[>>66]]

** 文字コード

[84] どのブラウザも、すべての[[実体本体]]、 [CODE(MIME)@en[[[name]]]] [[引数]]、
[CODE(MIME)@en[[[filename]]]] [[引数]]に同じ [[charset]] を使うようです。
[SRC@en[>>66]]

[85] 使用することに決めた [[charset]] で表現できない[[文字]]がある場合、
[[Unicode]] における[[符号位置]]を[[十進数文字参照]]形式にしたものが代わりに挿入されます。
[SRC@en[>>66]]

;; [175] ただし、[[ファイル]]は、[[テキストファイル]]であっても無変換です。

[HISTORY[

[86] [[Opera]] は以前は [CODE(MIME)@en[[[multipart/form-data]]]] 自体の
[CODE(MIME)@en[[[Content-Type]]:]] 欄に [CODE(MIME)@en[[[charset]]]] [[引数]]を指定していましたが (>>2)、
互換性に難があったのか、現在はつけないようです。
他のブラウザも [CODE(MIME)@en[[[multipart/form-data]]]] 自体には
[CODE(MIME)@en[[[boundary]]]] [[引数]]だけしか指定しません。
[SRC@en[>>66]]

[168] [[フォームデータ]]が[[テキスト]]の時は、その[[本体部分]]の
[CODE(MIME)@en[[[Content-Type:]] [[text/plain]]]]
の [CODE(MIME)@en[[[charset]]]] [[引数]]で[[文字符号化]]を提示できます [SRC[>>32]]。

[169] しかし実際には広く使われている実装は [CODE(MIME)@en[[[charset]]]]
[[引数]]を指定しません [SRC[>>32]]。

[1] [[WinIE]] も [[Mozilla]] も [[Opera]] も、 [CODE(MIME)[multipart/form-data]] 
に含まれる[[本体部分]]には [[charsetパラメーター]]を付けてくれません。 
(ファイル送信を除いて [CODE(MIME)[[[Content-Type]]]] 欄そのものをつけません。)

[167] [[HTML4]] は、 HTML [[UA]] は[[本体部分]]の [CODE(MIME)[Content-Type]] 欄を
([CODE(MIME)[[[charset]]]] 引数を含めて) 供給するべき
[SRC[HTML 4 17.13.4.2]] と述べていました。しかし誰もそれに従っていませんでした。

[2] [[Opera]] ([[Presto]]) は、 [CODE(MIME)[multipart/form-data]] そのものに (存在しない)
[CODE(MIME)[charset]] 引数をつけてきます。
この charset 値は実際にはそれに含まれる本体部分の[[実体本体]]及び 
[CODE(MIME)[[[Content-Disposition]]]] 欄の [CODE(MIME)[[[name]]]] 
引数に適用されるようです。あ、 [CODE(MIME)[[[filename]]]] にもかな? 
今度確かめてみよう。

[4] >>2-3 の情報は、 [CODE(HTML)[[[file]]]] 
として送られる実体本体には適用できません。 (その実体の頭欄には適用されます。)
[CODE(MIME)[charset=[[unknown-8bit]]]] とでも考えるしかなさそうです。問題は、
一般の form data と file を区別する確実な方法がないことです。 
IE, Moz, Opera に限れば、 [CODE(MIME)[filename]] 引数の有無で決定できますが。。。

[5] >>4 あ、確実な方法が1つだけあります。受取る側が名前を知っていること。
これ超確実。

[88] [[HTML5]] や元の [[Web Forms 2.0]] は [CODE(MIME)@en[[[application/x-www-form-urlencoded]]]]
や [CODE(MIME)@en[[[text/plain]]]] で[[提出]]する場合については
[CODE(HTML)@en[[[_charset_]]]] hack を定義していますが、
[CODE(MIME)@en[[[multipart/form-data]]]] の処理は [[RFC 2388]] 
に丸投げしているので、 [CODE(HTML)@en[[[_charset_]]]] hack
は正式にはどこでも定義されていませんでした。

]HISTORY]

[3] その後の改訂で [[HTML Standard]] で [CODE(MIME)@en[[[multipart/form-data]]]]
の時も [[[CODE(HTML)@en[_charset_]] hack]] の扱いが規定されるようになりました。

[170] [[RFC 7578]] も、それが既定の [[charset]] を規定する [SRC[>>32]]
と述べています。

;; [171] [[ファイル]]かどうかをどのように判定するのかは述べられていません。

[87] [[Safari]] 以外のブラウザは [CODE(HTML)@en[[[_charset_]]]] hack に対応しています。
[SRC@en[>>66]]

[30] [[ファイル]]の場合、 [[MIME型]]が [CODE(MIME)@en[[[Content-Type:]]]]
[[ヘッダー]]に指定されますが、 [CODE(MIME)@en[[[charset]]]] [[引数]]を含め、
[[引数]]までは指定されないのが普通です。

;; [[Webブラウザー]]は[[利用者]]が選択した[[ファイル]]の[[文字コード]]まで知らないのが普通です。

;; [69] 歴史的事項については、 [CODE(MIME)@en[[[filename]]]] や[[制御子名]]の項目も参照。

;; [176] [[RFC 7578]] は [[RFC 2047]] [CODE(ABNF)@en[[[encoded-word]]]]
や [[RFC 2231]] の方法を使っていた実装もあるかもしれない [SRC[>>70]]
として、それら古い方法への対応の必要性も匂わせています。しかし、
そのような実装があったとしても少数で、現在となってはまったく存在感はなく、
対応する必要性は全くないと思われます。

** 本体部分の実体本体

[31]
各本体部分の[[本体]]は、ファイル選択制御子 
([[[CODE(HTMLe)[input]]//[CODE(HTML)[file]]]]) ではファイルの内容、
それ以外では[[現在値]]になります。 
[WEAK[(という説明が HTML 4 仕様書ではきちんとなされていません。)]]

[[#comment]]

*** 内容転送符号化・内容符号化

[27] 各本体部分は [ABBR[[[CTE]]] [[CODE(MIME)[[[Content-Transfer-Encoding]]]]]] 
を使ってもかまいません。
[SRC[HTML 4 17.13.4.2, RFC 2388 3., RFC 2388 4.3]]
その他 MIME の機構により暗号化・圧縮などをしても構いません。
それは [CODE(MIME)[multipart/form-data]] を生成する応用の機能です。
[SRC[RFC 2388 5.1]]

[53] ただし、 [[HTTP]] で [CODE(MIME)[[[multipart/form-data]]]]
を使う場合は、仕様が曖昧なためその中の本体部分で
[CODE(MIME)[Content-Transfer-Encoding]] を使用するべきではありません。
[CODE(HTTP)[[[Content-Encoding]]]] を本体部分に適用できるのかどうかも曖昧であり、
使わない方が良いです。
[WEAK[(対応している実装も少ないでしょう。)]] 
[CODE(HTTP)[[[Transfer-Encoding]]]] を本体部分に適用することはできません。

なお、これは [CODE(MIME)[multipart/form-data]] ''内''の各本体部分についてであり、
[CODE(MIME)[multipart/form-data]] 実体自体については >>54 をご覧下さい。

[75] どのブラウザも、[[内容符号化]]や[[内容転送符号化]]は使用しないようです。
[CODE(MIME)@en[[[Content-Transfer-Encoding]]:]] 欄や
[CODE(HTTP)@en[[[Content-Encoding]]:]] 欄も使用していないようです。
([[HTTP]] の場合のみ調べています。)
[SRC@en[>>66]]

[14] >>12 は [CODE(MIME)@en[[[Content-Transfer-Encoding:]] [[8bit]]]] と
[CODE(MIME)@en[[[Content-Transfer-Encoding:]] [[binary]]]] を1つの
[CODE(MIME)@en[[[multipart/form-data]]]] で混在させた例を示しています。

[172] [[RFC 2388]] の改訂である [[RFC 7578]] は、
[[HTTP]] のように [[CTE]] が不要なら、[[非推奨]]であり、
[CODE(MIME)@en[[[Content-Transfer-Encoding:]]]] [[ヘッダー]]を生成する[['''べきではない''']]
[SRC[>>43]] とされています。そのような実装は知られていない [SRC[>>43]]
とも述べられています。

;; [173] しかしなぜか完全に禁止しているわけではないようです。また、
[[電子メール]]で使う場合には [[CTE]] が適用される可能性はありそうです。

[REFS[
- [12] [CITE[Chunked File Upload Support - Apache Sling - Apache Software Foundation]] ([TIME[2014-09-18 15:36:49 +09:00]] 版) <https://cwiki.apache.org/confluence/display/SLING/Chunked+File+Upload+Support>
]REFS]

*** 遠隔ファイル指示子

[49] 遠隔ファイルを直接送らずに、 [CODE(MIME)[[[message/external-body]]]] 
を使ってその[[指示子]]だけを送ることができます。
[SRC[RFC 2388 5.3]]

[52]
[CODE(MIME)[message/external-body]] の使い方は色々ありますが、
[CODE(MIME)[[[access-type]]]] [CODE(MIME)[[[uri]]]]
を使って遠隔ファイルの 
[[URI参照]]を送るのが現代的でよろしいのではないでしょうか。

[83] これに対応しているブラウザや[[フォーム処理エージェント]]があるという話は聞いたことがありません。

** ファイルの個数

[73] 1つの[[欄]]が複数の[[ファイル]]を含むときは、
同じ [CODE(MIME)@en[[[name]]]] [[引数]]の異なる[[本体部分]]としなければ[['''なりません''']]
[SRC[>>72]]。

;; [82] [[HTML]] では、 [CODE(HTML)@en[[[<input type=file>]]]] に
[CODE(MIME)@en[[[multiple]]]] [[属性]]を指定することで、
[[利用者]]が複数の[[ファイル]]を選択できるようになります。

*** [CODE(MIME)@en[multipart/mixed]] 方式

[51] かつては、1つのフォーム項目として複数のファイルを同時に提出する場合には、
[CODE(MIME)[[[multipart/mixed]]]] を使って1つの[[本体部分]]とすることになっていました。
[SRC[HTML 4 17.13.4.2, RFC 2388 3., RFC 2388 4.2]]

[150] しかしこの方式は現在では[[非推奨]]とされています [SRC[>>72]]。

[151] ファイル名等はその [CODE(MIME)[multipart/mixed]]
内のそれぞれの[[本体部分]]の情報として付与します。

[34] 提出ファイルが複数の時の [CODE(MIME)[multipart/mixed]] 内の本体部分では
[CODE(MIME)[Content-Disposition: file]] とするかのような記述が仕様書にあります
[SRC[HTML 4.01 17.13.4.2]] が、
[CODE(MIME)[attachment]] の誤りだそうです [SRC[HTML 4.01 正誤表 10.]]。
[WEAK[みっともないことに HTML 4.01 正誤表は [[RFC 2388]] に責任転嫁しております(w。確かに元々 HTML 4.0 では [CODE(MIME)[attachment]] になっておりましたが、 HTML 4.01 で [Q[minor typo]] として修正されています [SRC[HTML 4.01 A.1.3]]。]]

;; [16] それと直接的に関係あるのかはわかりませんが、
サーバーが UA に保存させるのに、 dispositon 型 [CODE[file]] を指定して、 [SAMP[Content-Disposition: file; filename=foo]] のように指定することがあるようです。 ([[CGI]] script とかで。)
(正しくはやはり [CODE(MIME)@en[[[Content-Disposition: attachment]]]]。)

;; [19] [[device-upload]] も [CODE(MIME)@en[[[Content-Disposition:]] [[file]]]]
に触れていました。
[REFS[
- [18] [CITE[Form-based Device Input and Upload in HTML]] ([TIME[2014-02-24 22:02:57 +09:00]] 版) <http://www.w3.org/TR/device-upload#Extensions>
]REFS]

[152] [[HTML]] や [CODE(MIME)@en[[[multipart/form-data]]]] の仕様の側では複数の[[ファイル]]を1つの[[欄]]で[[提出]]することになってはいましたが、
実際にはこれは ([[クライアント]]側でも[[サーバー]]側でも) 対応されていませんでした。
そのまま [[Webブラウザー]]を拡張すると[[サーバー]]が意図しない
[CODE(MIME)@en[[[multipart/mixed]]]] データを受信することになってしまうため、
[[Web Forms 2.0]] は [CODE(HTMLa)@en[[[min]]]]/[CODE(HTMLa)@en[[[max]]]]
[[属性]]によって[[サーバー]]が受信を意図する[[ファイル]]の個数を明示できるようにしました。

[78] [[Opera]] 9 は [[Web Forms 2.0]] の [CODE(HTMLa)@en[[[max]]]] [[属性]]による指定を使った[[ファイル]]の複数同時[[提出]]に対応しています。
複数のファイルが含まれる場合、仕様通り [CODE(MIME)@en[[[multipart/mixed]]]]
が使われます。その[[本体部分]]については、単体の場合と同じように挿入されます。
[CODE(MIME)@en[[[Content-Disposition]]:]] の値は [[RFC 2388]] とも [[HTML4]]
とも違って [CODE(MIME)@en[[[form-data]]]] になります。
[CODE(MIME)@en[[[name]]]] [[引数]]も単一ファイルの場合と同じように指定されます
[WEAK[([CODE(MIME)@en[[[multipart/mixed]]]] の方にも指定されますが、個々の[[本体部分]]の方にも指定されます)]]。
[WEAK[(複数ファイル指定可能であっても、選択数が1つ以下なら従前の方法によります。)]]
[SRC@en[>>66]]

[153] しかし、結局複数の[[ファイル]]を受信するために[[サーバー]]側で新たに
[CODE(MIME)@en[[[multipart/mixed]]]] に対応しなければならないことには変わりありません。
[[Web Forms 2.0]] が [[HTML5]] に統合されるに当たり、
[CODE(HTMLa)@en[[[min]]]]/[CODE(HTMLa)@en[[[max]]]] [[属性]]による複数[[ファイル]]の[[提出]]機能は廃止され、
代わって新たに [CODE(HTMLa)@en[[[mutliple]]]] [[属性]]による[[提出]]が導入されました。
新方式では [CODE(MIME)@en[[[multipart/mixed]]]] を使わず、同名の複数の[[本体部分]]を用いる方法に変更されました。

[154] [[RFC 7578]] はこれを踏まえて [CODE(MIME)@en[[[multipart/mixed]]]]
を[[非推奨]]とし、 [[HTML]] が採用した方法を使わなければならないとしました。
その一方で、広い応用可能性を求める[[応用]] (例えば[[ライブラリー]])
は [CODE(MIME)@en[[[multipart/mixed]]]] 方式も対応する[['''べき''']] [SRC[>>72]]
としています。

;; [155] 実際には [[Opera]] ([[Presto]]) 以外に旧方式の実装が存在していたかも謎で、
実用上はほとんど意味が無いものです。

;; [156] [CODE(HTMLa)@en[[[multiple]]]] が指定されたら同名の複数の[[本体部分]]として表現するというのは、
[CODE(HTMLe)@en[[[select]]]] [[要素]]と共通しています。また同名の[[本体部分]]は、
[[ファイル]]以外の[[フォームデータ]]の場合に既に使われています
(特に[[チェックボックス]]の場合など)。旧仕様がなぜ敢えて[[ファイル]]の場合だけ
[CODE(MIME)@en[[[multipart/mixed]]]] を使うことにしたのかは謎です。

*** 零個のファイルを提出

[6] ファイル選択制御子 ([[[CODE(HTMLe)[input]]/[CODE(HTML)[file]]]]) 
があっても、ファイル名として何も指定されなかった場合、
WinIE も Mozilla も Opera も、空の内容を送ります。

このとき、 WinIE と Mozilla は頭欄に 
[CODE(MIME)[[[Content-Type]]: [[application/octet-stream]]]] と書いてきて、 
[CODE(MIME)[[[Content-Disposition]]]] にも [CODE(MIME)[[[filename]]=""]] 
がつきます。 Opera ではどちらもつかず、本当に空 
([CODE(MIME)[Content-Disposition: [[form-data]]; name=[VAR[名前]]]] 
と空の内容だけ) になります。

[38] 頭欄がどうであれ、空の実体を送ってしまうと [WEAK[(一般の UA の場合に)]]
ファイル未選択状態と内容が空のファイルを提出した場合が区別できなくなってしまいます。
ファイルを選択していないファイル選択制御子はそもそも[[成功]]にしてはいけないのではないでしょうか。

[80] [[HTML5]] でも選択されていない[[ファイル選択制御子]]は[[フォーム・データ集合]]に含まれない定義になっていますがね。。。

[81] どのブラウザも、選択されていなくても空の[[実体本体]]を含めるようです。
[CODE(MIME)@en[[[Content-Disposition]]:]] はファイル以外の[[制御子]]の場合と同じです
([CODE(MIME)@en[[[filename]]]] [[引数]]がつきません)。
[CODE(MIME)@en[[[Content-Type]]:]] は、 [[Opera]] 以外は
[CODE(MIME)@en[[[application/octet-stream]]]] とします。
[[Opera]] は[[欄]]自体を省略します。
[SRC@en[>>66]]

[[#comment]]

* [CODE(MIME)@en[multipart/form-data]] 符号化算法

[110] [DFN[[CODE(MIME)@en[[[multipart/form-data]]]] [RUBYB[符号化算法]@en[encoding algorithm]]]]は、
[[フォーム・データ集合]]を [CODE(MIME)@en[[[multipart/form-data]]]] [[実体]]として[[符号化]]するための[[算法]]です。

[111] [[[CODE(MIME)@en[multipart/form-data]]符号化算法]]は次のように定義されています [SRC[>>109]]。

[FIG(steps)[
= [VAR[result]] を[[空文字列]]とします。
= [RUBYB[選択された文字符号化]@en[selected character encoding]]を、
== 明示的に[[文字符号化]]を指定して呼び出された場合は、それとします。
== そうでなく、 [CODE(HTMLe)@en[[[form]]]] [[要素]]が [CODE(HTMLa)@en[[[accept-charset]]]]
[[属性]]を有する場合、
=== [[フォーム・データ集合]]に含まれる名前と値で使われている[[文字]]と、
[[利用者エージェント]]が対応している[[文字符号化]]の種類を鑑み、
[[属性]]中に含まれる[[文字符号化]]の中から [[ASCII互換文字符号化]]であるものいずれか一つとします。
=== それがない場合は、 [[UTF-8]] とします。
== そうでなく、[[文書の文字符号化]]が [[ASCII互換文字符号化]]である場合、それとします。
== そうでない場合、 [[UTF-8]] とします。
= [VAR[charset]] を選択された文字符号化の[[優先MIME名]]とします。
= [[フォーム・データ集合]]の各[RUBYB[項目]@en[entry]]について、
== 名前が [CODE(HTML)@en[[[_charset_]]]] で型が [CODE(HTML)@en[[[hidden]]]] なら、
値を [VAR[charset]] に置き換えます。
== 名前と値の[[文字]]のうち、選択された文字符号化で表現できないものを[[十進数文字参照]]に置き換えます。
=== ここ、十進数部分の[[先導0]]は特に禁止されていないようです。
= [[フォーム・データ集合]]を [[RFC 2388]] に従って符号化します。
=- 次のように対応付けます。
=-- [[フォーム・データ集合]]の[RUBYB[項目]@en[entry]] → [RUBYB[欄]@en[field]]
=-- [[フォーム・データ集合]]の項目の名前 → [RUBYB[欄名]@en[field name]]
=-- [[フォーム・データ集合]]の項目の値 → [RUBYB[欄値]@en[field value]]
=- 順序は元のままとします。
=- 同じ名前の複数の項目は別の欄として扱います。
=- [CODE(MIME)@en[[[mutlipart/mixed]]]] による[[ファイル集合]]の符号化の方法は使いません。
=- [CODE(HTML)@en[[[file]]]] でない欄の[[実体本体]]については、 
[CODE(MIME)@en[[[Content-Type:]]]] を指定しません。
=- 名前と値は選択された文字符号化により[[符号化]]します。
=-- これは仕様上明記されていませんが [[RFC 2388]] への[[意図的違反]]です。
=- ファイル名は選択された文字符号化により[[符号化]]します。
=-- 必要に応じて近似して構いません。例えば[[改行]]を除去したり、 [CODE(char)[[["]]]] を
[CODE[%22]] にしたり、表現できない文字を他の文字に置き換えたりして構いません。
=-- [[RFC 2231]] 形式を使っては[['''なりません''']]。
]FIG]

* HTML

;;
[10] HTML 4 UA は、 [CODE(MIME)[multipart/form-data]]
によるフォームの提出を実装しなければなりません [SRC[HTML 4 17.13.4]]
と規定されていました。 [[HTML5]] では[[フォーム符号化算法]]などに完全に組み込まれており、
[CODE(MIME)@en[[[mutipart/form-data]]]] に対応しない実装が適合するのか不明です。

** [CODE(HTMLa)@en[enctype]] 属性値

[104] [[HTML]] の [CODE(HTMLe)@en[[[form]]]] [[要素]]の [CODE(HTMLa)@en[[[enctype]]]] [[属性]]と、
[CODE(HTMLe)@en[[[input]]]] [[要素]]や [CODE(HTMLe)@en[[[button]]]] [[要素]]の 
[CODE(HTMLa)@en[[[formenctype]]]] [[属性]]は、[[属性値]]として [DFN[[CODE(MIME)@en[[[multipart/form-data]]]]]]
を指定することができる[[列挙型属性]]です [SRC[>>103]]。この値を指定すると、当該[[要素]]
[WEAK[(やその[[フォーム]]に属する[[要素]]であって上書きされていないもの)]] の [[enctype]]
を [CODE(MIME)@en[[[multipart/form-data]]]] に設定することができます [SRC[>>103]]。
[[要素]]の [[enctype]] は[[フォーム提出算法]]から参照されています。

;; [198] 
[CODE[enctype]] [[属性]]の[[既定値]]は
[CODE[application/x-www-form-urlencoded]]
なので、
[CODE[multipart/form-data]]
は必ず明示的に指定しなければなりません。

[108] [[enctype]] が [CODE(MIME)@en[[[multipart/form-data]]]] の時の[[適当なフォーム符号化算法]]は
[[[CODE(MIME)@en[multipart/form-data]]符号化算法]]です。 [SRC[>>105]]

** フォーム提出算法

[106] [[フォーム提出算法]]において[[提出]]する[[実体本体]]を構築するに当たり、[[提出子]]たる[[ボタン]]の[[要素]]の
[[enctype]] が参照されます。それが [CODE(MIME)@en[[[multipart/form-data]]]] である場合、
[[実体本体]]の [[MIME型]] ([CODE(MIME)@en[[[Content-Type:]]]] 欄の値) としては、
[PRE(MIME code)[
multipart/form-data; boundary=[VAR[boundary-string]]
]PRE]
... が使われます。ただし [VAR[boundary-string]] は [[[CODE(MIME)@en[multipart/form-data]]境界文字列]]です。
[SRC[>>103]]

;; [107] つまりすべて[[小文字]]で、 [CODE(charname)@en[[[SPACE]]]] が [CODE(char)[[[;]]]]
の直後に1つだけ挿入され、 [CODE(MIME)@en[[[boundary]]]] は [[token]] として表現されます。

* API

[143] [CODE(MIME)@en[[[multipart/form-data]]]] そのものに関する [[DOM]] [[API]]
はありませんが、 [CODE(MIME)@en[[[multipart/form-data]]]] で送信されることになる[[フォームデータ集合]]を表す[[オブジェクト]]として
[CODE(DOMi)@en[[[FormData]]]] があります。

[144] [CODE(DOMi)@en[[[FormData]]]] は [[XHR Standard]] により規定されていますが、
[[XHR]] 以外の目的でも使うことができます。

* 処理

** 大容量ファイルの受信

[190] [CODE(MIME)@en[multipart/form-data]] は、[[ファイルアップロード]]に使われます。
しかし実のところ [CODE(MIME)@en[multipart/form-data]] は大容量の[[ファイル]]の送受信に適した形式というわけでもありません。

[191] [CODE(MIME)@en[multipart/form-data]] に含める[[フォームデータ]]の順序は、
[[制御子]]の種別と無関係に決まります。ですから、[[ファイル]]がどこに来るかはわかりません
([[フォーム制御子]]の[[文書]]中の位置に依存します)。
受信者 ([[サーバー]]) は受信したデータの末尾まで読み終わらないと、
処理に必要なすべての[[フォームデータ]]を受信したのかどうか確実に判断することができません。

[192] つまり、[[サーバー]]は大容量の[[ファイル]]が含まれる (かもしれない)
[CODE(MIME)@en[multipart/form-data]] の[[要求本体]]を全部読み込み終わらないと、
それをどう処理するべきか判断できる保証がありません。
[[要求本体]]を単純に先頭から末尾まで読みつつ処理するなら大容量のデータを[[メモリー]]上に保持しておく必要がありますし、
それが難しそうなら[[一時ファイル]]に書き込んでから処理するしかなさそうです。
どんなデータを与えられるか事前にまったく予測できない[[プログラミング言語]]の[[ライブラリー]]などでは[[一時ファイル]]に保存する方法を選択することが多いようです。

* 関連

[93] [[WAP]] により規定された [CODE(MIME)@en[[[multipart/form-data]]]] に相当する[[バイナリー]]表現として、
[CODE(MIME)@en[[[application/vnd.wap.multipart.form-data]]]] [[媒体型]]がありました。

** HTML と [CODE(MIME)[multipart/form-data]]

[6] HTML のフォームでは [CODE(MIME)[[[application/x-www-form-urlencoded]]]]
もよく使われていますが、任意のバイナリ・データや非 ASCII 
文字を効率よく確実に扱うことができないという問題があります。
バイナリ・データや非 ASCII 文字を含むフォームの提出では、
[CODE(MIME)[multipart/form-data]] を使うべきです [SRC[HTML 4 17.13.4.2]]。
ファイル選択制御子 ([[[CODE(HTMLe)[input]]/[CODE(HTML)[file]]]])
を使う時には、 [CODE(MIME)[multipart/form-data]] を
[CODE(HTMLe)[form]] の [CODE(HTMLa)[enctype]] で指定するべきです
[SRC[HTML 4 17.3, 17.13.4.2]]。

[35] HTML のフォームで [CODE(MIME)[multipart/form-data]] で提出させたい時は、
[CODE(HTMLe)[[[form]]]] 要素の [CODE(HTMLa)[[[enctype]]]]
属性に [CODE(MIME)[multipart/form-data]] と指定しておきます。

各本体部分の文字符号化方式の決定には、 [CODE(HTMLe)[form]]
要素の [CODE(HTMLa)[[[accept-charset]]]] 属性の指定を参照します。

[[#comment]]


** 転送プロトコルと [CODE(MIME)[multipart/form-data]]

[54] [[MIME]] の規定によれば、 [CODE(MIME)[[[multipart/[VAR[*]]]]]]
のすべての[[実体]]の [CODE(MIME)[[[Content-Transfer-Encoding]]]]
は [CODE(MIME)[[[7bit]]]], [CODE(MIME)[[[8bit]]]], [CODE(MIME)[[[binary]]]]
のいずれかでなければなりません。もちろん [CODE(MIME)[multipart/form-data]]
の実体にも適用されます。

注意: [CODE(MIME)[multipart/form-data]] 
の''中''の[[本体部分]]についての規定では''ありません''。
本体部分の [ABBR[CTE]] については >>53 を参照して下さい。

[55] [[HTTP]] では [CODE(MIME)[Content-Transfer-Encoding]]
を使用しません (常に [CODE(MIME)[binary]] 相当です) が、
[CODE(HTTP)[[[Content-Encoding]]]] と [CODE(HTTP)[[[Transfer-Encoding]]]]
があります。 [CODE(HTTP)[Transfer-Encoding]] は媒体型に依存しませんので、
[CODE(MIME)[multipart/form-data]] であろうがそうでなかろうが常に使用できます。
[CODE(HTTP)[Content-Encoding]] が使用できるのかどうかは微妙なところですが、
特別規定がないのですから、使用できるのでしょう。但し、
それに対応している実装 (クライアント・鯖) がどれだけあるのかは微妙なところです。

[56] [CODE(MIME)[[[Content-MD5]]]] による簡易的な整合性情報は、
MIME では [CODE(MIME)[multipart/[VAR[*]]]] に対して使用することが認められて''いません''が、
HTTP では認められています。 [CODE(MIME)[multipart/form-data]]
についても例外ではありません。

しかし、 [CODE(MIME)[multipart/form-data]] 全体の [[MD5]]
ハッシュを計算するよりは、面倒でも個々の本体部分で計算した方が良いでしょう。
もし HTTP で提出された [CODE(MIME)[multipart/form-data]] が途中で
MIME に変換されて [WEAK[(例えば電子メイルで)]] 
送られるとすると困ったことになります。

;; [64] そんなことあるのか知りませんがw

[[#comment]]


** その他

[[#comment]]


* 保安性

[50] [CODE(MIME)[multipart/form-data]] 
を構成するプロトコル要素や[[フォーム]]の仕組み自体には、
様々な安全上の問題があることが知られています。

例えば、利用者の意図しない状態や利用者が十分な考慮を行えない状況で自動的・
半自動的にフォームを提出させると、
利用者の私的な情報や利用者の環境の安全に関わる情報が送信されてしまう虞があります。
このほかにも、フォームの提出という仕組みそのものに起因する問題が多く見つかっています。

また、ファイルを提出する際には [CODE(MIME)[filename]]
引数を使うことができますが、フォーム処理エージェント 
([CODE(MIME)[multipart/form-data]] を処理する側) 
が信頼して無防備に実際のファイル名等として使用すると、
既存の別のファイルやシステム・ファイルを上書きしたり、
その環境で扱えないファイル名のファイルが中途半端にできてしまったりする虞があります。
詳しくは [CODE(MIME)[[[filename]]]] 引数の説明をご覧ください。

このようなフォーム自体や [CODE(MIME)[multipart/form-data]]
が利用しているプロトコル要素に関する問題や、
特定の実装に依存した問題を除いては、 [CODE(MIME)[multipart/form-data]]
に関する安全上の問題は見つかっていません。

[57] 提出の途中での改竄を検出する簡易的な手段として
[CODE(MIME)[[[Content-MD5]]]] が使用できます (>>56)。
但し記述された [CODE(MIME)[Content-MD5]] 値自体が改竄されることもあり得ますから、
あくまで簡易的なものです。また、
実装している[[利用者エージェント]]は現時点で存在しないと思われます。

[58] 一般の MIME の実体の安全のための仕組みとして[[署名]]のための
[CODE(MIME)[[[multipart/signed]]]] や[[暗号化]]のための
[CODE(MIME)[[[multipart/encrypted]]]] が、
それを使った実際のシステムとして [[PGP/MIME]] や [[S/MIME]]
があります。しかし、現実に [CODE(MIME)[multipart/form-data]]
と組合せて使っている (使える) 例は聞いたことがありません。
[CODE(MIME)[multipart/form-data]] のどの部分を署名・暗号化するのか
(あるいは全体をするのか) や、フォームの提出の手続きの中でどのように処理するのかなどの詳細な標準化がなされないと
(または[[デファクト標準]]が登場しないと) 使用するのは難しいでしょう。

[59] 現実にフォームの提出の安全のために使用されているのは
[[TLS]] や [[SSL]] です。 [[HTTP]] に対応した利用者エージェントや鯖では大抵
TLS over HTTP ([[HTTPS]]) が利用できるので、
[[フォーム処理エージェント]]としては特別な処理が要らないのが普通です。
但し、 HTTP 以外の提出方法 (特に電子メイル)
にはこの方法は使えません。

* 歴史

** 実装開始

[15] 
[[WinIE 3.02]]
用の [[file upload add-on]] は
[TIME[1997年][year:1997]]の中ごろに出ました。

** RFC 1867

[REFS[
- [115] [[RFC 1867]]
]REFS]

** HTML4 と RFC 2388

[REFS[
-[116] [[HTML4]] [CSECTION[multipart/form-data]]
<http://www.w3.org/TR/html4/interact/forms.html#didx-multipartform-data>
-[117] [[HTML4]] [CSECTION[A.1.3 Minor typographical errors that were corrected]]
<http://www.w3.org/TR/html4/appendix/changes.html#h-A.1.3>
-[118] HTML 4.01 正誤表 [CITE[10. content-disposition: attachment]]
<http://www.w3.org/MarkUp/html4-updates/errata#entry-10>
- [21] '''[CITE@en[RFC 2388 - Returning Values from Forms: multipart/form-data]] ([TIME[2014-10-05 04:39:46 +09:00]] 版) <http://tools.ietf.org/html/rfc2388#section-4.4>'''
- [17] [CITE[RFC Errata Report]] ([TIME[2014-11-03 04:38:57 +09:00]] 版) <http://www.rfc-editor.org/errata_search.php?rfc=2388>
]REFS]

[92] 
RFC 1867 と RFC 2388 と HTML 4 の [CODE(MIME)[multipart/form-data]]
の規定は文章を流用していて同じようなことが書いてありますが、
少しずつ違います。独立の仕様書になっている RFC 2388 が当然一番詳しくなっています。

[FIG[
[FIGCAPTION[
[7] [[HTML 4]] の [CODE(MIME)[multipart/form-data]] への言及の変遷:
]FIGCAPTION]
= 勧告以前の HTML 4 原案では、高々紹介程度で [[RFC 1867]] にほぼ丸投げ。
= HTML 4.0 勧告第1版: ''Forms in HTML documents'' 
<http://www.w3.org/TR/REC-html40-971218/interact/forms.html#didx-multipartform-data>
= HTML 4.0 勧告第2版: ''Forms in HTML documents'' 
<http://www.w3.org/TR/1998/REC-html40-19980424/interact/forms.html#didx-multipartform-data>
-- 勧告第1版と全く同内容
= 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]] に参照先を変更
= HTML 4.01 勧告: ''Forms in HTML documents'' 
<http://www.w3.org/TR/1999/REC-html401-19991224/interact/forms.html#didx-multipartform-data>
-- typo 修正
-- 例中の [CODE(MIME)[Content-Disposition: attachment]]
を [CODE(MIME)[Content-Disposition: file]] に変更
= HTML 4.01 正誤表:
''HTML 4 Errata'' <http://www.w3.org/MarkUp/html4-updates/errata#entry-10>
-- 勧告での [CODE(MIME)[attachment]] から
[CODE(MIME)[file]] に再修正。しかも RFC 2388 に責任転嫁(藁
]FIG]

[22] [CODE(MIME)[multipart/form-data]] 内容は [[RFC 2045]]
で説明された[[多部分]] MIME データ列の規則に従います。
[CODE(MIME)[multipart/form-data]] の定義は [[IANAREG]]
から入手できます。 [SRC[HTML 4 17.13.4.2]]
と書いてありますけど、むしろ [[RFC 2046]] を読むべきでしょう。
また、後方互換性, 他の内容型との関係, 効率の問題その他については
[[RFC 1867]] [SRC[HTML 4.0 17.13.4.2]] ・ [[RFC 2388]] [SRC[HTML 4.01 17.13.4.2]]
を読むよう指示があります。
ちなみに、仕様書の発行順序は HTML 4.0 → RFC 2388 → HTML 4.01 です。

[95] [[HTML4]] は[[フォーム]]で[[非ASCII文字]]が[[提出]]される可能性がある場合に
[CODE(MIME)@en[[[application/x-www-form-urlencoded]]]] の代わりに
[CODE(MIME)@en[[[multipart/form-data]]]] を使うことを勧めていましたが、
世間からは完全に無視されています。

** device-upload

[REFS[
-[119] [CITE[Form-based Device Input and Upload in HTML]] ([TIME[2000-03-13 23:37:05 +09:00]] 版) <http://www.w3.org/1999/07/NOTE-device-upload-19990706>
]REFS]

[98] [[device-upload]] では、[[音声]]等の新しい[[ファイル]]の[[うp]]の方法に適用するための
[CODE(MIME)@en[[[device]]]] などの [CODE(MIME)@en[[[Content-Disposition]]:]] [[引数]]を提案し、
その指定方法を規定していました。

** HTML 以外への展開

[REFS[
- [112] [CITE@EN[Voice Extensible Markup Language (VoiceXML) 2.1]] ([TIME[2007-06-17 03:12:27 +09:00]] 版) <http://www.w3.org/TR/2007/REC-voicexml21-20070619/#sec-data>
- [113] [CITE@EN[XForms 1.0 (Third Edition)]] ([TIME[2007-10-30 03:02:40 +09:00]] 版) <http://www.w3.org/TR/2007/REC-xforms-20071029/#serialize-form-data>
- [114] [CITE@en[Web Services Description Language (WSDL) Version 2.0 Part 2: Adjuncts]] ([TIME[2007-06-23 05:33:39 +09:00]] 版) <http://www.w3.org/TR/2007/REC-wsdl20-adjuncts-20070626/#_http_operation_multipart_encoding>
]REFS]

[99] [[VoiceXML]] [[解釈器]]は [CODE(MIME)@en[[[multipart/form-data]]]]
に対応することが義務付けられています [SRC@en[[[VoiceXML 2.1]]]]。

[96] [[XForms]] でも、「互換性のため」としながらも [CODE(MIME)@en[[[multipart/form-data]]]]
を使うことができます。ただし、 [[XForms]] のモデル上のすべての情報を含められるわけではなく、
例えば[[属性節点]]に相当する情報は欠落します。

[[XForms]] は注記として、既存の [[HTML]] [[利用者エージェント]]は[[非ASCII文字]]等の扱いが芳しくないことを指摘しています。
それとどう関係があるのか知りませんが (だからきちんと処理するよう指導しているわけでもありません)、
[CODE(MIME)@en[[[multipart/related]]]] や [CODE(MIME)@en[[[application/xml]]]]
を使うことを勧めています。

[97] [[WSDL]] でも、 「[[XForms]] との互換性のため」として
[CODE(MIME)@en[[[multipart/form-data]]]] を使うことができます。

** WF2 と HTML5

[REFS[
-[120] [CITE@en-GB-x-Hixie[Web Forms 2.0]] ([TIME[2006-10-12 09:55:44 +09:00]] 版) <http://www.whatwg.org/specs/web-forms/current-work/#form-submission>
]REFS]

[121] [[WF2]] ははじめて[[フォーム提出算法]]を明確な形で仕様として規定しました。その中に
[CODE(MIME)@en[[[multipart/form-data]]]] による[[提出]]の方法も含まれていました。

[122] [[HTML Living Standard]] ([[HTML5]] / [[Web Applications 1.0]]) はこれを引き継ぎ、
更により明確かつ具体的に [CODE(MIME)@en[[[multipart/form-data]]]] の処理も規定しています。

[REFS[
- [101] [CITE[Bug 10461 – This algorithm needs more detail on how the data is to be actually encoded. E.g. does it depend on the document encoding, etc.]]
( ([TIME[2010-10-12 21:26:59 +09:00]] 版))
<http://www.w3.org/Bugs/Public/show_bug.cgi?id=10461>
- [102] [CITE@en[Web Applications 1.0 r5600     Redefine how we interact with RFC 2388 (multipart/form-data) in submissionFixing http://www.w3.org/Bugs/Public/show_bug.cgi?id=10461]]
( ([TIME[2010-10-12 09:10:00 +09:00]] 版))
<http://html5.org/tools/web-apps-tracker?from=5599&to=5600>
]REFS]

[123] とはいえ、いずれの仕様書も [CODE(MIME)@en[[[multipart/form-data]]]] 自体の生成の部分は
[[RFC]] に委ねており、 >>102 により曖昧な部分を明確化したとはいえ、結果として
[[delta spec]] のような状態になっています。

** RFC 7578

[46] 2015年7月には、 [[RFC 2388]] を[[廃止]]して新たに [DFN[[[RFC 7578]]]]
が出版されています。

[REFS[
- [48] [CITE@en[RFC 7578 - Returning Values from Forms: multipart/form-data]] ([TIME[2015-07-19 23:17:07 +09:00]] 版) <https://tools.ietf.org/html/rfc7578>
]REFS]

[142] [[Webブラウザー]]業界からの要求がようやく少しずつ反映されて、
実態により近い形に改訂されています。 (とはいうものの、
基本的には昔ながらの [[IETF]] の [[RFC]] のスタイルからは脱却できず、
現代 [[Web標準]]レベルの正確な仕様書にはなっていません。)

* 実装

[36] 現代のほとんどの [[WWWブラウザ]]は [CODE(MIME)[multipart/form-data]]
によるフォームの提出を実装しています。

[37]
一方、 [[CGIスクリプト]]などの鯖側は酷い状況です。
多くの実装は相手にもしていません。 [[Perl]] なら [CODE(file)[[[CGI.pm]]]] 
などを使えば自動的に対応できますが、[WEAK[最近は増えてきたとはいえ]]モジュールを
CGI スクリプトで使うことは少なく、 [CODE(MIME)[application/x-www-form-urlencoded]]
にしか対応していません。ファイルのうpがしたくなったら 
(素直にモジュールを使えばいいのに) 見よう見まねで適当に対処しようとして、
結局特定ブラウザの特定の版でしか上手く動かないようなコードを書いてみたり。
[WEAK[(で、質問掲示板で暴れてみたり。)]] お前らちゃんと仕様書読んでくださいよ。

処理系で標準または標準に近いモジュール的なものが[[要求]]の解析をしてくれることが広く知られていて、
そのモジュール的なものの作者がちゃんと仕様を読んでコードを書くような人なら、
その処理系で書かれた処理はさほど深く考えなくても自動的に 
[CODE(MIME)[multipart/form-data]] を正しく処理できるはずです。
[WEAK[よく知りませんけど、 Java servelet とか PHP はその辺きちんとしてるのではないですか?]]

[66] [[Firefox]] 3.0.4、[[Opera]] 9.61、[[Safari]] 3.2、[[WinIE 7]] の実装状況を調べてみました。

[94] [CITE@ja[enctype="multipart/form-data"で携帯からファイルアップロード « 携帯・モバイル « プログラム « Re:]] ([[kronekodow]] 著, [TIME[2008-11-25 17:16:30 +09:00]] 版) <http://blog.livedoor.jp/kronekodow/archives/64944587.html>

>SoftBankが素敵に思えた。
>データフォルダから直アップできるんですね。
>fileup_auauは(W52SHは)Browse...ってボタンは出るものの反応しない。
>DoCoMoはボタンすら出ない。
>SoftBankでも、C端末、3GC端末などによる違など全てじゃなかったり、auも一部端末なら出来たり?(HTMLやXHTMLの違いなども関係したり)とか、可能な端末の振り分けは大変そうです。


** 複数ファイルをまとめて提出

[13] 1つのファイル選択制御子 ([[[CODE(HTMLe)[input]]//[CODE(HTML)[file]]]]) 
を使って複数ファイルをうpする (>>51) のは、 [[UA]] で対応してるのはなさげ、
サーバーもおそらく全滅だろうという感じですね。 

[[www-html]] で [[Opera]] の特定の版では出来るという未確認情報がありましたが、
最新版では出来ないらしいし、勘違いかなんかじゃないかなあ。

[67] その後 [[Opera]] 9 は [[Web Forms 2.0]] に対応しましたので、
複数ファイルの[[提出]]にも対応しています。 [CODE(HTML)@en[[[file]]]] [[制御子]]用の
[CODE(HTMLa)@en[[[max]]]] [[属性]]は一旦 [[HTML5]] で削除されましたが、
[CODE(HTMLa)@en[[[multiple]]]] [[属性]]が改めて追加される予定ですから、
いずれ他のブラウザも複数ファイルの[[提出]]に対応すると期待されます。

[[#comment]]


* 試験事例

[90] [CITE[Index of /~wakaba/-temp/test/html/form/multipart-form-data]] ([TIME[2008-11-25 16:03:16 +09:00]] 版) <http://suika.fam.cx/~wakaba/-temp/test/html/form/multipart-form-data/>

* 例

[39] HTML のフォームの例 [SRC[HTML 4 17.13.4.2、改]]
[PRE(HTML)[
 <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>
]PRE]

このフォームで、文章入力欄に [SAMP[Larry]] と記入し、ファイル選択で
[SAMP(file)[file1.txt]] を指定して提出した場合 [SRC[HTML 4 17.13.4.2, 改]]:
[PRE(MIME)[
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
''''''
[VAR[... contents of file1.txt ...]]
--AaB03x--
]PRE]

更に [SAMP(file)[file2.gif]] も選択していた場合 [SRC[HTML 4 17.13.4.2, 改]]:
[PRE(MIME)[
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: [DEL[file]] [INS[attachment]]; filename="file1.txt"
Content-Type: text/plain
''''''
[VAR[... contents of file1.txt ...]]
--BbC04y
Content-Disposition: [DEL[file]] [INS[attachment]]; filename="file2.gif"
Content-Type: image/gif
Content-Transfer-Encoding: binary
''''''
[VAR[...contents of file2.gif...]]
--BbC04y--
--AaB03x--
]PRE]

[47] ユーロ通貨記号を値に使った例 [SRC[RFC 2388 4.5、改]]
[PRE(HTML)[
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--
]PRE]

[[#comment]]


* Q & A

[63] '''Q: HTML でファイルをアップロードするにはどうしたらいいですか? ファイル名しか取得できません...'''

A: ファイル名しか取得できないのは、
[CODE(MIME)[[[application/x-www-form-urlencoded]]]]
を使用しているからの可能性が高いと考えられます。
フォームの提出で [CODE(MIME)[[[multipart/form-data]]]]
を使うようにしましょう。

関連: >>61, [[[CODE(HTMLe)[input]]//[CODE(HTML)[file]]]], [[提出]]

[61] '''Q: HTML によるフォームの提出でブラウザに [CODE(MIME)[multipart/form-data]] で送ってもらうにはどうしたらいいですか?'''

A: [CODE(HTMLe)[[[form]]]] 要素の [CODE(HTMLa)[[[enctype]]]]
属性を [CODE(MIME)[[[multipart/form-data]]]] と指定してください。

ついでに、 [CODE(HTMLa)[[[accept-charset]]]] 属性に希望する[[文字コード]]も指定しておきましょう。

[CODE(HTMLa)[[[method]]]] 属性を [CODE(HTML)[[[post]]]]
にしておくのを忘れないように。

関連: [CODE(HTMLe)[[[form]]]], [CODE(HTMLa)[[[enctype]]]], [[提出]]

[62] '''Q: CGI スクリプトで [CODE(MIME)[multipart/form-data]] と [CODE(MIME)[application/x-www-form-urlencoded]] を見分けるにはどうしたらいいですか?'''

A: [[CGI]] には [CODE(CGI)[[[CONTENT_TYPE]]]] という[[メタ変数]]
([[環境変数]]) があります。その値で判別できます。

[CODE(CGI)[CONTENT_TYPE]] の値の先頭の19文字が
[CODE(MIME)[multipart/form-data]] [WEAK[(大文字・小文字の区別なし)]]
で、その次の文字が存在しないか、[[空白]] ([[間隔]]、
[[タブ]]、[[改行]]) か、[[セミコロン]] ([CODE(MIME)[;]])
なら、 [CODE(MIME)[multipart/form-data]] が使われています。

[CODE(CGI)[[[CONTENT_TYPE]]]] の値の先頭35文字が
[CODE(MIME)[application/x-www-form-urlencoded]] 
[WEAK[(大文字・小文字の区別なし)]]
で、その次の文字が存在しないか、[[空白]] ([[間隔]]、
[[タブ]]、[[改行]]) か、[[セミコロン]] ([CODE(MIME)[;]])
なら、 [CODE(MIME)[application/x-www-form-urlencoded]] が使われています。

それ以外なら、未知の何かが使われています。

関連: [CODE(MIME)[[[Content-Type]]]], [CODE(CGI)[[[CONTENT_TYPE]]]]

* メモ

[FIG(amazon)[
Web アプリケーション 開発
]FIG]

[100] [CITE@EN[XForms 1.1]]
([TIME[2009-10-20 22:51:54 +09:00]] 版)
<http://www.w3.org/TR/2009/REC-xforms-20091020/#serialize-form-data>

[132] [CITE[IRC logs: freenode / #whatwg / 20120502]]
( ([TIME[2012-05-06 21:45:58 +09:00]] 版))
<http://krijnhoetmer.nl/irc-logs/whatwg/20120502#l-1099>

[133] [CITE[IRC logs: freenode / #whatwg / 20120616]]
( ([TIME[2012-07-01 21:51:10 +09:00]] 版))
<http://krijnhoetmer.nl/irc-logs/whatwg/20120616#l-355>

[134] [CITE[''''''[''''''whatwg'''''']'''''' multipart/form-data filename encoding: unicode and special characters]]
( ([TIME[2012-07-10 06:28:16 +09:00]] 版))
<http://lists.whatwg.org/pipermail/whatwg-whatwg.org/2012-July/036579.html>

[135] [CITE@en[Bug 16909 – multipart/form-data: field name encoding is not specified; browsers do incompatible things]]
( ([TIME[2013-09-17 20:42:37 +09:00]] 版))
<https://www.w3.org/Bugs/Public/show_bug.cgi?id=16909>

[136] <https://github.com/masinter/multipart-form-data/>

[137] [CITE[IRC logs: freenode / #whatwg / 20131010]]
( ([TIME[2013-10-14 00:14:43 +09:00]] 版))
<http://krijnhoetmer.nl/irc-logs/whatwg/20131010#l-1183>

[138] ( ([TIME[2013-11-04 07:24:21 +09:00]] 版))
<http://www.ietf.org/proceedings/88/slides/slides-88-appsawg-8.pdf>

[139] [CITE[What's the holdup? · Issue #17 · masinter/multipart-form-data]]
( ([TIME[2014-07-01 07:58:13 +09:00]] 版))
<https://github.com/masinter/multipart-form-data/issues/17>

[140] [CITE[IRC logs: freenode / #whatwg / 20140630]]
( ([TIME[2014-07-01 16:52:23 +09:00]] 版))
<http://krijnhoetmer.nl/irc-logs/whatwg/20140630>

[141] [CITE@zh-tw[Ajax with FormData is Broken on IE10 / IE11 in Some Conditions « 鴨七・chitsaou]]
( ([[Yu-Cheng Chuang]] 著, [TIME[2014-07-11 03:23:29 +09:00]] 版))
<http://blog.yorkxin.org/posts/2014/02/06/ajax-with-formdata-is-broken-on-ie10-ie11>

[20] [CITE@en-US[Batch Requests | ArangoDB Documentation]]
( ([TIME[2015-01-13 16:43:59 +09:00]] 版))
<https://docs.arangodb.com/HttpBatchRequest/README.html>

[181] [CITE@en[MIME Type Detection in Windows Internet Explorer (Windows)]]
([TIME[2015-09-26 02:04:58 +09:00]] 版)
<https://msdn.microsoft.com/en-us/library/ms775147(v=vs.85).aspx>

[183] [CITE@en[Fix form submission's encoding algorithms]]
( ([[annevk]]著, [TIME[2016-05-30 23:15:22 +09:00]]))
<https://github.com/whatwg/html/commit/ec42efb1d7c3a2e34db21b8076a8a3f4bd6dfb81>

[184] [CITE@en[16909 – multipart/form-data: field name encoding is not specified; browsers do incompatible things]]
( ([TIME[2016-06-18 20:48:30 +09:00]]))
<https://www.w3.org/Bugs/Public/show_bug.cgi?id=16909>

[185] [CITE@en[RFC 2388 has been obsoleted by RFC 7578 · Issue #398 · whatwg/html]]
( ([TIME[2016-06-18 20:49:08 +09:00]]))
<https://github.com/whatwg/html/issues/398>

[186] [CITE@en[136676 – no quoting at all in MIME-Headers (Content-Disposition header not escaped)]]
( ([TIME[2016-06-18 20:50:15 +09:00]]))
<https://bugzilla.mozilla.org/show_bug.cgi?id=136676>

[187] [CITE@en[Editorial: reference RFC 7578 instead of RFC 2388]]
([[eehakkin]]著, [TIME[2016-10-28 17:06:06 +09:00]])
<https://github.com/whatwg/fetch/commit/5d5e80db32cf917233ffa4e95c032f86b7d9f42c>

[188] [CITE@en[Add a space before multipart/form-data's boundary parameter]]
([[annevk]]著, [TIME[2016-11-25 16:49:10 +09:00]])
<https://github.com/whatwg/fetch/commit/4f53460fc2d1773ef38633c3c7ac23cf1affb08c>

[189] [CITE@en[Clarify package data algorithm for FormData]]
([[eehakkin]]著, [TIME[2016-12-17 01:36:13 +09:00]])
<https://github.com/whatwg/fetch/commit/e03ee6fc7f6234005a058d9784e95861b9a0a301>

[FIG(quote)[
[FIGCAPTION[
[193] [CITE[S2-045 - Apache Struts 2 Documentation - Apache Software Foundation]]
([TIME[2017-03-22 01:25:21 +09:00]])
<https://cwiki.apache.org/confluence/display/WW/S2-045>
]FIGCAPTION]

> Implement a Servlet filter which will validate Content-Type and throw away request with suspicious values not matching multipart/form-data.

]FIG]


[FIG(quote)[
[FIGCAPTION[
[194] [CITE@en[Micropub]]
([TIME[2017-05-21 23:18:57 +09:00]])
<https://micropub.net/draft/#form-encoded-and-multipart-requests-p-1>
]FIGCAPTION]

> 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.

]FIG]


[195] [CITE[RCS MaaP Chatbot API Specifications Version 1.0]]
([TIME[2017-11-30 21:47:54 +09:00]])
<https://www.gsma.com/futurenetworks/wp-content/uploads/2017/11/FNW.11_v1.0.pdf>

[196] [CITE@en[Move _charset_ handling to construct the form data set]]
([[tkent-google]]著, [TIME[2018-04-27 17:25:35 +09:00]])
<https://github.com/whatwg/html/commit/8c212e549607a41b6d40d953b47d9f3e749533f3>

[197] [CITE@en[Move _charset_ handling from "multipart/form-data encoding algorithm"… by tkent-google · Pull Request #3645 · whatwg/html]]
([TIME[2018-05-02 12:51:02 +09:00]])
<https://github.com/whatwg/html/pull/3645>

[199] [CITE[curl - How To Use]]
([TIME[2020-09-21T09:01:13.000Z]], [TIME[2020-10-01T06:12:00.173Z]])
<https://curl.haxx.se/docs/manpage.html#-F>

[200] [CITE@en[Use UTF-8 decode without BOM for multipart/form-data]]
([[annevk]], [TIME[2019-11-04 23:23:54 +09:00]], [TIME[2021-03-06T02:52:53.000Z]])
<https://github.com/whatwg/fetch/commit/7db8ac52245d6f0abaaeec6ae1cd96553c30b737>

[201] [CITE@en[Should Body.formData() always strip the BOM? · Issue #650 · whatwg/fetch]]
([TIME[2021-03-06T02:54:53.000Z]])
<https://github.com/whatwg/fetch/issues/650>

[202] [CITE@en[Use UTF-8 decode without BOM for multipart/form-data by annevk · Pull Request #915 · whatwg/fetch]]
([TIME[2021-03-06T02:58:47.000Z]])
<https://github.com/whatwg/fetch/pull/915>

[203] [CITE@en[andreubotella/multipart-form-data: A web-spec definition of multipart/form-data and related algorithms.]]
([TIME[2021-04-21T12:20:21.000Z]])
<https://github.com/andreubotella/multipart-form-data>

[204] [CITE@en[multipart/form-data]]
([TIME[2021-03-24T15:33:02.000Z]], [TIME[2021-04-21T12:20:32.319Z]])
<https://andreubotella.github.io/multipart-form-data/>