[3] MIME の多部分実体 (multipart/*
実体)
は複数の実体部分を1つにまとめて扱うことができます。
各実体は境界文字列によって区切ります。
その境界文字列は実体を構成する利用者エージェントが定められた構文的制限内で自由に決定できます。
その境界文字列を指定するのが boundary
引数です。
boundary
引数はすべての multipart/*
実体で必須です。
[41] ただし境界区切子の最後は U+0020
ではいけません >>26。
[40] 境界区切子は、1文字以上70文字以下でなければなりません >>26。
[5] 境界区切子行は、
--
から始まり、 boundary
引数の値があり、
省略可能な線形空白があり、 CRLF で終わる行です >>26。
[30] multipart/*
実体においては境界区切子行の前には
CRLF
が必要です。この CRLF
は境界の一部であり、
前の本体部分や前書きの一部ではありません。 >>26
[42] ただし最初の境界区切子行の CRLF
は、前書きが無い場合、
省略できます >>26。
[33] 最後の本体部分の後には閉じ境界区切子行を置きます。これは、境界区切子の後に --
を置いたものです >>26。
[43] ただし最後の CRLF は、後書きが無い場合、省略できます >>26。
[36] 行末の線形空白 (LWSP-char
) は、
関門で追加されたものとみなされ、無視されます >>26。
生成してはなりません >>26。
[6] ただし、ここに示された文字すべてが境界文字列として適切なわけではありません。
境界文字列は Content-Type:
欄などにおいて
boundary
引数の値として指定しますが、その際に引数値は
quoted-string
を使って指定する方法 (つまり引用符で括る方法)
と token
を使って指定する方法 (つまり括らない方法)
があります。しかし、いろいろな場面での使用を考えると引用符なしの方が安全です。
(例えば multipart/byteranges
で引用符付きだと扱えない古い HTTP UA が存在しますRFC 2616。)
そうなると、 token
で使用できない文字、すなわち
"(" / ")" / "," / "/" / ":" / "=" / "?" / " "
は使うべきではないということになります。
特に間隔は 822 メッセージでは折返しなど種々の問題がありますから、 極力使わないべきです (でも現実には意外とよく使われていたりします (そしてたまに問題を起こします))。コロンも腐った MTA・MSA などでの転送時に頭欄の名前と本体を分けるコロンと誤認されて破壊される問題があることが知られていますから、 使うべきではありません。
[827] CGI.pm は quoted-string であったとしても ,
を境界文字列で使うことを認めていません。
これはおそらく、 CGI では複数の同名のヘッダーがあったときに ,
で連結されることから、 (複数 Content-Type:
欄が存在する要求は非妥当とはいえ)
,
は境界文字列に現れると解釈が曖昧になるという判断なのでしょう。
[7] まとめると、境界文字列 boundary
は
DIGIT / ALPHA / "'" / "+" / "_" / "-" / "."
から1文字以上70文字で選ぶのがよさそうだということになります。
[9] なお、構文で最後の文字に間隔を使ってはならないことになっているのは、 古い関門が勝手に 822 メッセージ本体の行末に空白を補うことがあることが知られていたからです RFC 2046 5.1.1。
[8] 仕様上は >>5 の構文に反しない限りで自由に境界文字列を選ぶことができます。 ただし、境界文字列が多部分実体の中に含まれる本体部分の一部として含まれていてはいけません。
[9] 実際の MIME 利用者エージェントでよく使われている境界文字列は、 無作為に選んだ文字列と日付など規則的に生成した (本体部分に含まれそうにない) 文字列です。また、稀に定型メッセージなどで中身が分かりきっている場合には、 - などの簡単な文字列で済ませることもあります。
どの方法を選ぶにせよ、 生成した境界文字列が本体部分の中身に混じってしまうことがないように注意しなければなりません。 絶対に中身と衝突し得ない文字列を生成する方法はありませんが、 実際に中身を検査すれば含まれているかいないかは簡単に分かりますから、 何度か生成して確認してみれば実用的には十分です (うまい生成方法を選べば普通は1度で衝突しない文字列が得られます)。
ただし、 MIME 実体の生成方法や効率上の理由で中身の検査ができないこともあります。
multipart/x-mixed-replace
のように、
その性質上あらかじめ絶対に衝突しない境界文字列を選ぶことが不可能なものまであります。
このような場合には、使用する媒体型などの知識に基づき衝突しそうにない文字列を生成するように努力するしかありません。
(本来そのような状況では、 application/vnd.pwg-multiplexed
のような別の方法を採用するべきです。)
[13] なお、 multipart/*
は何重にも入れ子にできます。
当然、内側と外側では別の境界文字列を選ばなければなりません。
日付などに基づき生成する方法を選んだ場合は同時に同じ境界文字列を生成してしまわないように注意しなければなりません。
[10] 多部分実体は次のような構文と規定されています RFC 2046 5.1.1。
dash-boundary := "--" boundary
multipart-body := [preamble CRLF] dash-boundary transport-padding CRLF body-part *encapsulation close-delimiter transport-padding [CRLF epilogue]
transport-padding := *LWSP-char
encapsulation := delimiter transport-padding CRLF body-part
delimiter := CRLF dash-boundary
close-delimiter := delimiter "--"
preamble := discard-text
epilogue := discard-text
discard-text := *(*text CRLF) *text
body-part := MIME-part-headers [CRLF *OCTET]
(詳細は multipart/*
の項や RFC 2046 を見てください。)
[11] 境界文字列に関係する部分をまとめると、次のようになります。
CRLF
からなる境界文字列を入れます。CRLF
と
--boundary と CRLF
からなる境界文字列を入れます。CRLF
と
--boundary-- と CRLF
からなる境界文字列を入れます。ただし、 boundary
というのは boundary
引数で指定した文字列です。
最後の境界文字列は boundary
の後にも
--
が付くことと、最初の境界文字列以外では
--boundary の直前の CRLF
も境界の一部である (本体部分の一部ではない) ことに注意してください。
[12] ただし、 >>9 のような腐った関門が勝手に空白を追加しても受信側が理解できるように、
受信した側の MIME 利用者エージェントは --boundary や
--boundary-- の後に空白があっても無視することになっています
(構文の transport-padding
)。
(だからといって、送信側が意図的に空白をつけることは禁止されています)
[17] なお、古い版の MIME では一番最初の本体部分の前の境界でも
--boundary の前の CRLF
が必須とされていましたが、今日では不具合であったと考えられています。
multipart/form-data
境界文字列[824] HTML のフォーム提出算法において、
multipart/form-data
境界文字列とは、
multipart/form-data
の実体本体を生成するに当たり使われた
boundary
の文字列のことをいいます。
[826] multipart/form-data
境界文字列は、 Content-Type:
欄の値の生成に使われます。
[1] RFC 934 は電子メール内にメッセージをカプセル化して埋め込む方法を規定していました。
RFC 934 は、 -
から始まる行を encapsulation boundary
(EB) と呼び、メッセージ本文中の EB をどう処理するかを定義していました。
[21] PEM は暗号化や署名が施されたメッセージを RFC 822 メッセージに埋め込む形を採っていました。
「内側」のメッセージの前後には、 RFC 934 に添って
-----PRIVACY-ENHANCED MESSAGE BOUNDARY-----
という行を含めることになっていました >>2。
[22] 両仕様は埋め込まれたメッセージの前にある EB を pre-EB、 後にある EB を post-EB と呼んでいました。
[24] PEM の第4世代では、 pre-EB は
-----BEGIN PRIVACY-ENHANCED MESSAGE-----
、
post-EB は
-----END PRIVACY-ENHANCED MESSAGE-----
になぜか変更されています >>23。
[14] MIME の Content-Type:
欄で
boundary
引数を指定する例 RFC 2046:
Content-Type: multipart/mixed; boundary=gc0p4Jq0M2Yt08j34c0p
[15] 間違った例 RFC 2046:
Content-Type: multipart/mixed; boundary=gc0pJq0M:08jU534c0p
boundary
引数の値に :
が含まれていますが、この文字は tspecials
に含まれているので、 quoted-string
にしなければ
(値全体を二重引用符で括らなければ) なりません。
[16] multipart/alternative
を使った電子メイルの完全なメッセージの例
RFC 2046, 改:
From: Nathaniel Borenstein <nsb@bellcore.com> To: Ned Freed <ned@innosoft.com> Date: Mon, 22 Mar 1993 09:41:09 -0800 (PST) Subject: Formatted text mail MIME-Version: 1.0 Content-Type: multipart/alternative; boundary=boundary42 --boundary42 Content-Type: text/plain; charset=us-ascii ... plain text version of message goes here ... --boundary42 Content-Type: text/enriched; charset=us-ascii ... RFC 1896 text/enriched version of same message goes here ... --boundary42 Content-Type: application/x-whatever ... fanciest version of same message goes here ... --boundary42--
[19]
[mew-dist 27367] Re: < > を含むバウンダリでエラー (2007-02-07 15:22:41 +09:00
版) <http://www.mew.org/pipermail/mew-dist/2006-October/027053.html>
[20] [mew-dist 27666] MIME decoding error: No boundary parameter for multipart (pegacorn 著, 版) <http://permalink.gmane.org/gmane.mail.mew.general.japanese/6020>
[823] Apache HTTP Server Project ( ( 版)) <http://httpd.apache.org/docs/1.3/misc/known_client_problems.html#boundary-string>
[829] 境界文字列はその複数部分実体内に含まれる実体に含まれるものであってはなりません。
[830] >>829 でもこの(必然的な)規制って、 multipart/x-mixed-replace
のように複数部分が動的に生成される場合であって Content-Type:
欄を生成する時点で完全に内容を把握できない場合に満たすことを保証するのが難しい気がします。
[831] >>830 そうでなくても、常に binary CTE である HTTP での転送の時なんかに、内容と一致しない境界文字列を生成出来ない可能性がある気がします。確率はとっても低くて無視できるかもしれませんが...
[832] RFC Errata Report ( ( 版)) <http://www.rfc-editor.org/errata_search.php?rfc=2388&eid=4030>