
[3] [[MIME]] の[[多部分実体]] ([CODE(MIME)[[[multipart/[VAR[*]]]]]] [[実体]])
は複数の[[実体部分]]を1つにまとめて扱うことができます。
各実体は境界文字列によって区切ります。
その境界文字列は実体を構成する[[利用者エージェント]]が定められた構文的制限内で自由に決定できます。
その境界文字列を指定するのが [DFN[[CODE(MIME)[boundary]] [[引数]]]]です。

[CODE(MIME)[boundary]] 引数はすべての [CODE(MIME)[[[multipart/[VAR[*]]]]]]
実体で'''必須'''です。

* 仕様書

[REFS[
- [4] [CITE@en[RFC 2046 - Multipurpose Internet Mail Extensions (MIME) Part Two: Media Types]] ([TIME[2015-03-22 13:14:46 +09:00]] 版) <http://tools.ietf.org/html/rfc2046#section-5.1>
-- [26] '''[CITE@en[RFC 2046 - Multipurpose Internet Mail Extensions (MIME) Part Two: Media Types]] ([TIME[2015-03-22 13:14:46 +09:00]] 版) <http://tools.ietf.org/html/rfc2046#section-5.1.1>'''
- [44] [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.1>
]REFS]

* 構文

[28] [CODE(MIME)@en[[[boundary]]]] [[引数]]の値は、[[境界区切子]]です。

[31] [DFN[[RUBYB[境界区切子]@en[boundary delimiter]]]]は、次の[[文字]]で構成されます 
[SRC[>>26]]。
[FIG(short list)[
- [[ASCII英数字]]
- [CODE(char)[[[']]]]
- [CODE(char)[[[(]]]]
- [CODE(char)[[[)]]]]
- [CODE(char)[[[+]]]]
- [CODE(char)[[[_]]]]
- [CODE(char)[[[,]]]]
- [CODE(char)[[[-]]]]
- [CODE(char)[[[.]]]]
- [CODE(char)[[[/]]]]
- [CODE(char)[[[:]]]]
- [CODE(char)[[[=]]]]
- [CODE(char)[[[?]]]]
- [CODE(char)[[[U+0020]]]]
]FIG]

;; [39] これらは[[メール]]の[[関門]]に対して[[頑健]]である [SRC[>>26]] とされています。

[41] ただし[[境界区切子]]の最後は [CODE(char)[[[U+0020]]]] ではいけません [SRC[>>26]]。

[40] [[境界区切子]]は、1文字[[以上]]70文字[[以下]]でなければなりません [SRC[>>26]]。

;; [32] 行頭の [CODE[--]] は[[境界区切子]]に含まれません。

[5] [DFN[[RUBYB[[[境界区切子行]]]@en[boundary delimiter line]]]]は、
[CODE[--]] から始まり、 [CODE(MIME)@en[[[boundary]]]] [[引数]]の値があり、
省略可能な[[線形空白]]があり、 [[CRLF]] で終わる[[行]]です [SRC[>>26]]。

;; [29] [CODE[--]] は [[RFC 934]] との大まかな互換性のためと、
実装方法によっては探しやすいためにあります [SRC[>>26]]。 (しかし [[RFC 934]]
と完全に互換なわけではありません。)

[30] [CODE(MIME)@en[[[multipart/*]]]] [[実体]]においては[[境界区切子行]]の前には
[CODE[[[CRLF]]]] が必要です。この [CODE[[[CRLF]]]] は境界の一部であり、
前の[[本体部分]]や[[前書き]]の一部ではありません。 [SRC[>>26]]

[FIG(railroad)[
= [[CRLF]]
= [CODE[--]]
= [[境界区切子]]
= *
== [[線形空白]]
= [[CRLF]]
]FIG]

[42] ただし最初の[[境界区切子行]]の [CODE[[[CRLF]]]] は、[[前書き]]が無い場合、
省略できます [SRC[>>26]]。

[33] 最後の[[本体部分]]の後には[RUBYB[閉じ境界区切子行]@en[close boundary delimiter line]]を置きます。これは、[[境界区切子]]の後に [CODE[--]] を置いたものです [SRC[>>26]]。

[FIG(railroad)[
= [[CRLF]]
= [CODE[--]]
= [[境界区切子]]
= [CODE[--]]
= *
== [[線形空白]]
= [[CRLF]]
]FIG]

[43] ただし最後の [[CRLF]] は、[[後書き]]が無い場合、省略できます [SRC[>>26]]。

[36] 行末の[[線形空白]] ([CODE(ABNF)@en[[[LWSP-char]]]]) は、
[[関門]]で追加されたものとみなされ、無視されます [SRC[>>26]]。
生成しては[['''なりません''']] [SRC[>>26]]。

[6] ただし、ここに示された文字すべてが境界文字列として適切なわけではありません。
境界文字列は [CODE(MIME)[[[Content-Type]]:]] 欄などにおいて
[CODE(MIME)[boundary]] 引数の値として指定しますが、その際に引数値は
[CODE(ABNF)[[[quoted-string]]]] を使って指定する方法 (つまり引用符で括る方法)
と [CODE(ABNF)[[[token]]]] を使って指定する方法 (つまり括らない方法) 
があります。しかし、いろいろな場面での使用を考えると引用符なしの方が安全です。
[WEAK[(例えば [CODE(MIME)[[[multipart/byteranges]]]] で引用符付きだと扱えない古い [[HTTP]] [[UA]] が存在します[SRC[[[RFC 2616]]]]。)]]

そうなると、 [CODE(ABNF)[token]] で使用できない文字、すなわち
[CODE(ABNF)["(" / ")" / "," / "/" / ":" / "=" / "?" / " "]] 
は使う'''べきではない'''ということになります。

特に[[間隔]]は [[822]] メッセージでは[[折返し]]など種々の問題がありますから、
極力使わない'''べきです''' (でも現実には意外とよく使われていたりします
[WEAK[(そしてたまに問題を起こします)]])。[[コロン]]も腐った [[MTA]]・[[MSA]]
などでの転送時に[[頭欄]]の[[名前]]と[[本体]]を分けるコロンと誤認されて破壊される問題があることが知られていますから、
使う'''べきではありません'''。

[827] [[CGI.pm]] は [[quoted-string]] であったとしても [CODE(char)[[[,]]]] を[[境界文字列]]で使うことを認めていません。
これはおそらく、 [[CGI]] では複数の同名の[[ヘッダー]]があったときに [CODE[[[,]]]]
で連結されることから、 [WEAK[(複数 [CODE(MIME)@en[[[Content-Type:]]]] 欄が存在する[[要求]]は非妥当とはいえ)]]
[CODE(char)[[[,]]]] は[[境界文字列]]に現れると解釈が曖昧になるという判断なのでしょう。

;; [828] と思いましたが同じような構文でそうなっていないところもあるので、
本当の意図はわかりません。

[7] まとめると、境界文字列 [CODE(MIME)[boundary]] は
[CODE(ABNF)[[[DIGIT]] / [[ALPHA]] / "'" / "+" / "_" / "-" / "."]]
から1文字以上70文字で選ぶのがよさそうだということになります。

[9] なお、構文で最後の文字に間隔を使ってはならないことになっているのは、
古い[[関門]]が勝手に [[822]] 
メッセージ本体の行末に[[空白]]を補うことがあることが知られていたからです
[SRC[RFC 2046 5.1.1]]。

* 文脈

[27] [CODE(MIME)@en[[[boundary]]]] [[引数]]は、すべての
[CODE(MIME)@en[[[multipart/*]]]] [[MIME型]]で必須です [SRC[>>26]]。

* 処理

[34] 実装は、 (行全体ではなく) 行頭と[[境界区切子]]を比較しなければなりません [SRC[>>26]]。

;; [35] [[境界区切子行]]だけではなく、[[境界区切子]]から始まる[[行]]も[[本体部分]]に含めることが禁止されています。

* 境界文字列の選び方

[8] 仕様上は >>5 の構文に反しない限りで自由に境界文字列を選ぶことができます。
ただし、境界文字列が多部分実体の中に含まれる[[本体部分]]の一部として含まれていてはいけません。

[EG[
[37] 対象データを走査せず、対象データと衝突する可能性が低い[[境界区切子]]を選ぶことにしても構いません [SRC[>>26]]。
]EG]

[EG[
[38] [[MIME]] に対応していない[[利用者エージェント]]の受信者のために可読性が高い[[境界区切子]]を選んでも構いません。その場合は衝突により注意が必要です。 [SRC[>>26]]
]EG]

[9] 実際の MIME 利用者エージェントでよく使われている境界文字列は、
無作為に選んだ文字列と日付など規則的に生成した (本体部分に含まれそうにない)
文字列です。また、稀に定型メッセージなどで中身が分かりきっている場合には、
[SAMP(MIME)[-]] などの簡単な文字列で済ませることもあります。

どの方法を選ぶにせよ、
生成した境界文字列が本体部分の中身に混じってしまうことがないように注意しなければなりません。
絶対に中身と衝突し得ない文字列を生成する方法はありませんが、
実際に中身を検査すれば含まれているかいないかは簡単に分かりますから、
何度か生成して確認してみれば実用的には十分です
[WEAK[(うまい生成方法を選べば普通は1度で衝突しない文字列が得られます)]]。

ただし、 MIME 実体の生成方法や効率上の理由で中身の検査ができないこともあります。
[CODE(MIME)[[[multipart/x-mixed-replace]]]] のように、
その性質上あらかじめ絶対に衝突しない境界文字列を選ぶことが不可能なものまであります。
このような場合には、使用する[[媒体型]]などの知識に基づき衝突しそうにない文字列を生成するように努力するしかありません。
[WEAK[(本来そのような状況では、 [CODE(MIME)[[[application/vnd.pwg-multiplexed]]]] のような別の方法を採用するべきです。)]]

[13] なお、 [CODE(MIME)[[[multipart/[VAR[*]]]]]] は何重にも[[入れ子]]にできます。
当然、内側と外側では別の境界文字列を選ばなければなりません。
日付などに基づき生成する方法を選んだ場合は同時に同じ境界文字列を生成してしまわないように注意しなければなりません。

[[#comment]]


* 多部分実体の境界文字列

[10] 多部分実体は次のような構文と規定されています [SRC[RFC 2046 5.1.1]]。
- [CODE(ABNF)[[DFN[dash-boundary]] := "--" boundary]]
- [CODE(ABNF)[[DFN[multipart-body]] := [preamble CRLF] dash-boundary transport-padding CRLF body-part *encapsulation close-delimiter transport-padding [CRLF epilogue] ]]
- [CODE(ABNF)[[DFN[transport-padding]] := *LWSP-char]]
- [CODE(ABNF)[[DFN[encapsulation]] := delimiter transport-padding CRLF body-part]]
- [CODE(ABNF)[[DFN[delimiter]] := CRLF dash-boundary]]
- [CODE(ABNF)[[DFN[close-delimiter]] := delimiter "--"]]
- [CODE(ABNF)[[DFN[preamble]] := discard-text]]
- [CODE(ABNF)[[DFN[epilogue]] := discard-text]]
- [CODE(ABNF)[[DFN[discard-text]] := *(*text CRLF) *text]]
- [CODE(ABNF)[[DFN[body-part]] := MIME-part-headers [CRLF *OCTET] ]]

(詳細は [CODE(MIME)[[[multipart/[VAR[*]]]]]] の項や [[RFC 2046]] を見てください。)

[11]
境界文字列に関係する部分をまとめると、次のようになります。
- 一番最初の本体部分の前には、 [SAMP(MIME)[--[VAR[boundary]]]]
と [CODE(ABNF)[CRLF]] からなる境界文字列を入れます。
- 本体部分と本体部分の間には、 [CODE(ABNF)[CRLF]] と
[SAMP(MIME)[--[VAR[boundary]]]] と [CODE(ABNF)[CRLF]]
からなる境界文字列を入れます。
- 一番最後の本体部分の後には、 [CODE(ABNF)[CRLF]] と 
[SAMP(MIME)[--[VAR[boundary]]--]] と [CODE(ABNF)[CRLF]] からなる境界文字列を入れます。

ただし、 [CODE(MIME)[[VAR[boundary]]]] というのは [CODE(MIME)[boundary]]
引数で指定した文字列です。
最後の境界文字列は [CODE(MIME)[[VAR[boundary]]]] の後にも
[CODE(MIME)[--]] が付くことと、最初の境界文字列''以外''では
[SAMP(MIME)[--[VAR[boundary]]]] の直前の [CODE(ABNF)[CRLF]]
も境界の一部である (本体部分の一部ではない) ことに注意してください。

[12] ただし、 >>9 のような腐った関門が勝手に[[空白]]を追加しても受信側が理解できるように、
受信した側の MIME 利用者エージェントは [SAMP(MIME)[--[VAR[boundary]]]] や
[SAMP(MIME)[--[VAR[boundary]]--]] の後に[[空白]]があっても無視することになっています
(構文の [CODE(ABNF)[transport-padding]])。 
[WEAK[(だからといって、送信側が意図的に空白をつけることは禁止されています)]]

[17] なお、古い版の MIME では一番最初の本体部分の前の境界でも
[SAMP(MIME)[--[VAR[boundary]]]] の前の [CODE(ABNF)[CRLF]]
が必須とされていましたが、今日では不具合であったと考えられています。

* [CODE(MIME)@en[multipart/form-data]] 境界文字列

[824] [[HTML]] の[[フォーム提出算法]]において、 
[DFN[[CODE(MIME)@en[multipart/form-data]] [RUBYB[境界文字列]@en[boundary string]]]]とは、
[CODE(MIME)@en[[[multipart/form-data]]]] の[[実体本体]]を生成するに当たり使われた
[CODE(MIME)@en[[[boundary]]]] の文字列のことをいいます。

[REFS[
- [825] [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-boundary-string>
]REFS]

[826] [[[CODE(MIME)@en[multipart/form-data]]境界文字列]]は、 [CODE(MIME)@en[[[Content-Type:]]]]
欄の値の生成に使われます。

* 本体部分における制約

[25] [[本体部分]]は、[[境界区切り]]と一致する、または[[境界区切り]]で始まる[[行]]を含んでは[['''なりません''']] [SRC[>>4]]。

* 歴史

** MIME 以前

[1] [[RFC 934]] は[[電子メール]]内に[[メッセージ]]をカプセル化して埋め込む方法を規定していました。
[[RFC 934]] は、 [CODE[[[-]]]] から始まる[[行]]を [DFN[[[encapsulation boundary]]]]
([DFN[[[EB]]]]) と呼び、[[メッセージ]]本文中の [[EB]] をどう処理するかを定義していました。

;; [[MIME]] とは違って何が [[EB]] であるかをメタデータとして保持しているわけではないので、
[[MUA]] が本文を走査して解釈しなければなりません。

;; 詳しくは [[RFC 934]] を参照。

;; [18] この方法はそれ以前からの慣習を規定したものである [SRC[>>2]] ようです。

[21] [[PEM]] は暗号化や署名が施された[[メッセージ]]を [[RFC 822]] [[メッセージ]]に埋め込む形を採っていました。
「内側」の[[メッセージ]]の前後には、 [[RFC 934]] に添って
[CODE[-----PRIVACY-ENHANCED MESSAGE BOUNDARY-----]] という行を含めることになっていました [SRC[>>2]]。

[22] 両仕様は埋め込まれた[[メッセージ]]の前にある [[EB]] を [DFN[[[pre-EB]]]]、
後にある [[EB]] を [DFN[[[post-EB]]]] と呼んでいました。

[24] [[PEM]] の第4世代では、 [[pre-EB]] は
[CODE[[[-----BEGIN PRIVACY-ENHANCED MESSAGE-----]]]]、
[[post-EB]] は
[CODE[[[-----END PRIVACY-ENHANCED MESSAGE-----]]]] になぜか変更されています [SRC[>>23]]。

[REFS[
- [2] [CITE@en[RFC 989 - Privacy enhancement for Internet electronic mail: Part I: Message encipherment and authentication procedures]] ([TIME[2015-02-22 16:43:49 +09:00]] 版) <https://tools.ietf.org/html/rfc989#section-4.4>
- [23] [CITE@en[RFC 1421 - Privacy Enhancement for Internet Electronic Mail: Part I: Message Encryption and Authentication Procedures]] ([TIME[2015-02-22 14:28:36 +09:00]] 版) <https://tools.ietf.org/html/rfc1421#section-4.4>
]REFS]

** MIME

[REFS[
- [[RFC 1341]]
- [[RFC 1521]]
- [[RFC 2046]]
]REFS]

* 例

[14] [[MIME]] の [CODE(MIME)[[[Content-Type]]:]] 欄で
[CODE(MIME)[boundary]] 引数を指定する例 [SRC[RFC 2046]]:
[PRE(MIME example)[
Content-Type: multipart/mixed; boundary=gc0p4Jq0M2Yt08j34c0p
]PRE]

[15]
間違った例 [SRC[RFC 2046]]:
[PRE(MIME illegal example)[
Content-Type: multipart/mixed; boundary=gc0pJq0M:08jU534c0p
]PRE]

[CODE(MIME)[boundary]] 引数の値に [CODE(char)[:]]
が含まれていますが、この文字は [CODE(ABNF)[[[tspecials]]]]
に含まれているので、 [CODE(ABNF)[[[quoted-string]]]] にしなければ
(値全体を[[二重引用符]]で括らなければ) なりません。

[16] [CODE(MIME)[[[multipart/alternative]]]] を使った[[電子メイル]]の完全なメッセージの例
[SRC[RFC 2046, 改]]:
[PRE(MIME example)[
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
[VAR[  ... plain text version of message goes here ...]]
--boundary42
Content-Type: text/enriched; charset=us-ascii
[VAR[  ... RFC 1896 text/enriched version of same message goes here ...]]
--boundary42
Content-Type: application/x-whatever
[VAR[  ... fanciest version of same message goes here ...]]
--boundary42--
]PRE]

* メモ

[19]
[CITE['''['''mew-dist 27367''']''' Re: < > を含むバウンダリでエラー]] ([CODE[2007-02-07 15:22:41 +09:00]] 版) <http://www.mew.org/pipermail/mew-dist/2006-October/027053.html>

[20]
[CITE[''''''[''''''mew-dist 27666'''''']'''''' MIME decoding error: No boundary parameter for	multipart]] ([[pegacorn]] 著, [TIME[2007-05-16 02:47:58 +09:00]] 版) <http://permalink.gmane.org/gmane.mail.mew.general.japanese/6020>

[823] [CITE[Apache HTTP Server Project]]
( ([TIME[2011-05-28 00:58:55 +09:00]] 版))
<http://httpd.apache.org/docs/1.3/misc/known_client_problems.html#boundary-string>

[829] 境界文字列はその複数部分実体内に含まれる実体に含まれるものであってはなりません。

[830] >>829 でもこの(必然的な)規制って、 [CODE[multipart/x-mixed-replace]]
のように複数部分が動的に生成される場合であって [[Content-Type:]]
欄を生成する時点で完全に内容を把握できない場合に満たすことを保証するのが難しい気がします。

[831] >>830 そうでなくても、常に [[binary]] [[CTE]] である HTTP での転送の時なんかに、内容と一致しない境界文字列を生成出来ない可能性がある気がします。確率はとっても低くて無視できるかもしれませんが...


[832] [CITE[RFC Errata Report]]
( ([TIME[2014-07-01 07:55:00 +09:00]] 版))
<http://www.rfc-editor.org/errata_search.php?rfc=2388&eid=4030>