/
710.txt
242 lines (185 loc) · 13.9 KB
/
710.txt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
[3] [[MIME]] の[[多部分実体]] ([CODE(MIME)[[[multipart/[VAR[*]]]]]] [[実体]])
は複数の[[実体部分]]を1つにまとめて扱うことができます。
各実体は境界文字列によって区切ります。
その境界文字列は実体を構成する[[利用者エージェント]]が定められた構文的制限内で自由に決定できます。
その境界文字列を指定するのが [DFN[[CODE(MIME)[boundary]] [[引数]]]]です。
[CODE(MIME)[boundary]] 引数はすべての [CODE(MIME)[[[multipart/[VAR[*]]]]]]
実体で'''必須'''です。
[4] 仕様書:
- [[MIME]]
== 第1版: [[RFC 1340]]
== 第2版: [[RFC 1521]]
== 第3版: [[RFC 2046]]
--- [CSECTION[5.1.1. Common Syntax]]
** 境界文字列の構文
[5] [[MIME]] [SRC[RFC 2046]] によれば、境界文字列は次のように定義されています。
- [CODE(ABNF)[[DFN[boundary]] := 0*69<bchars> bcharsnospace]]
- [CODE(ABNF)[[DFN[bchars]] := bcharsnospace / " "]]
- [CODE(ABNF)[[DFN[bcharsnospace]] := DIGIT / ALPHA / "'" / "(" / ")" / "+" / "_" / "," / "-" / "." / "/" / ":" / "=" / "?"]]
つまり、境界にはここで示した文字を使うことができます。
ただし最後の文字は[[間隔]]であってはなりません。
また、境界文字列全体で1文字以上70文字以下でなければなりません。
[6] ただし、ここに示された文字すべてが境界文字列として適切なわけではありません。
境界文字列は [CODE(MIME)[[[Content-Type]]:]] 欄などにおいて
[CODE(MIME)[boundary]] 引数の値として指定しますが、その際に引数値は
[CODE(ABNF)[[[quoted-string]]]] を使って指定する方法 (つまり引用符で括る方法)
と [CODE(ABNF)[[[token]]]] を使って指定する方法 (つまり括らない方法)
があります。しかし、いろいろな場面での使用を考えると引用符なしの方が安全です。
[WEAK[(例えば [CODE(MIME)[[[multipart/byterange]]]] で引用符付きだと扱えない古い [[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]]。
** 境界文字列の選び方
[8] 仕様上は >>5 の構文に反しない限りで自由に境界文字列を選ぶことができます。
ただし、境界文字列が多部分実体の中に含まれる[[本体部分]]の一部として含まれていてはいけません。
[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:]]]]
欄の値の生成に使われます。
* 歴史
** 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]]]] と呼んでいました。
[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>
]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>