| Internet Engineering Task Force (IETF) | J. Reschke |
| Request for Comments: 6266 | greenbytes |
| Updates: 2616 | 2011年6月 |
| Category: Standards Track | |
| ISSN: 2070-1721 |
在 超文本传输协议 (HTTP) 中 使用 Content-Disposition 首部字段
摘要
RFC 2616 定义了 Content-Disposition 响应首部字段,但指出该字段并非 HTTP/1.1 标准的一部分。本规范接手在 HTTP 中使用的 Content-Disposition 的定义和注册,并澄清其国际化方面的问题。
本备忘录的状态
这是一个互联网标准轨道文档。
本文件是互联网工程任务组(IETF)的成果,代表 IETF 社区的共识。它已获得公开评审,并由互联网工程指导小组(IESG)批准发布。有关互联网标准的更多信息,请参阅 RFC 5741 第2节。
关于本文档当前状态、任何勘误以及如何反馈意见的信息,可在 http://www.rfc-editor.org/info/rfc6266 获取。
Copyright Notice
Copyright (c) 2011 IETF Trust and the persons identified as the document authors. All rights reserved.
This document is subject to BCP 78 and the IETF Trust's Legal Provisions Relating to IETF Documents (http://trustee.ietf.org/license-info) in effect on the date of publication of this document. Please review these documents carefully, as they describe your rights and restrictions with respect to this document. Code Components extracted from this document must include Simplified BSD License text as described in Section 4.e of the Trust Legal Provisions and are provided without warranty as described in the Simplified BSD License.
1. 引言
RFC 2616 定义了 Content-Disposition 响应首部字段(RFC2616 第 19.5.1 节), 但指出该字段并非 HTTP/1.1 标准的一部分(RFC2616 第 15.5 节):
Content-Disposition 并非 HTTP 标准的一部分,但由于它被广泛实现,我们在此记录其用法和对实现者的风险说明。
本规范接手在 HTTP 中使用的 Content-Disposition 的定义与注册。基于与现有用户代理(UA)进行的互操作性测试,本规范对邮件多用途扩展(MIME)变体([RFC2183])中定义的特性做出了完整的配置文件定义,并澄清了国际化方面的问题。
2. 符号约定
文中关键词 "MUST"、"MUST NOT"、"REQUIRED"、"SHALL"、"SHALL NOT"、"SHOULD"、"SHOULD NOT"、 "RECOMMENDED"、"MAY" 和 "OPTIONAL" 应按 [RFC2119] 中的定义来解释。
本规范使用增强巴科斯-诺尔范式(ABNF)表示法,定义见 RFC2616 第 2.1 节,并包括其关于隐含线性空白(LWS)的规则。
3. 合规性与错误处理
本规范为 Content-Disposition 首部字段的发送者(通常为 HTTP 源服务器)和接收者(通常为 HTTP 用户代理)定义了合规性标准。若实现遵从其角色相关的所有要求,则视为合规。
本规范还使用 ABNF 与文字性要求(见 第 4 节) 定义某些形式的首部字段值为无效,但并未规定对这些无效字段值的特殊处理方式。
发送者 不得 生成无效的 Content-Disposition 首部字段。
接收者 可以 采取措施从无效首部字段中恢复出可用的字段值,但 不应 直接拒绝该消息(除非这是明确期望的行为,例如实现为验证器)。因此,对无效字段的默认处理是忽略它们。
4. 首部字段定义
Content-Disposition 响应首部字段用于传达关于如何处理响应有效负载的附加信息,也可用于附加元数据,例如在本地保存响应有效负载时应使用的文件名。
4.1. 语法
content-disposition = "Content-Disposition" ":"
disposition-type *( ";" disposition-parm )
disposition-type = "inline" | "attachment" | disp-ext-type
; case-insensitive
disp-ext-type = token
disposition-parm = filename-parm | disp-ext-parm
filename-parm = "filename" "=" value
| "filename*" "=" ext-value
disp-ext-parm = token "=" value
| ext-token "=" ext-value
ext-token = <the characters in token, followed by "*">
下列条目在 [RFC2616] 中定义:
token = <token, defined in [RFC2616], Section 2.2> quoted-string = <quoted-string, defined in [RFC2616], Section 2.2> value = <value, defined in [RFC2616], Section 3.6> ; token | quoted-string
下列条目在 [RFC5987] 中定义:
ext-value = <ext-value, defined in [RFC5987], Section 3.2>
若 Content-Disposition 首部字段值中出现同一参数名的多个实例,则该字段值为无效。
注意,由于隐含线性空白的规则(参见 RFC2616 第 2.1 节),在单词(token 或 quoted-string)与分隔字符之间可以出现可选的空白。
此外,注意 ext-value 的格式允许指定自然语言(例如 "en");但对于文件名而言,这种语言标记作用有限,接收者很可能会忽略它。
4.2. 处置类型
如果处置类型与 "attachment" 匹配(不区分大小写),表示接收者应提示用户将响应保存到本地,而不是按响应的媒体类型进行正常处理。
相反,如果匹配 "inline"(不区分大小写),则表示默认处理。因此,处置类型 "inline" 仅在配合额外参数(例如文件名)时有用(见下文)。
4.3. 处置参数:“Filename”
参数 "filename" 与 "filename*"(匹配时不区分大小写)提供了用于构造保存消息有效负载时文件名的信息。
依据处置类型,这些信息可能会立即使用(比如对 "attachment" 处置类型触发的“另存为...”交互中),也可能在稍后使用(例如用户决定保存当前正在显示页面的内容时)。
"filename" 与 "filename*" 的差别在于 "filename*" 使用 [RFC5987] 中定义的编码,允许使用 ISO-8859-1 字符集之外的字符(参见 [ISO-8859-1])。
许多早于本规范的用户代理实现不了解 "filename*" 参数。因此,当同一首部字段值中同时存在 "filename" 与 "filename*" 时,接收者 应当 选择 "filename*" 并忽略 "filename"。这样,发送方可以同时发送更具表达力的 "filename*" 参数,并将 "filename" 参数作为针对旧接收者的回退(参见 第 5 节 中的示例)。
接收者应将指定的文件名仅视为建议,因此在提取所需信息时必须非常小心。具体而言:
-
接收者 不得 将文件写入其并非明确有权限写入的位置。举例来说,不应允许覆盖诸如 "/etc/passwd" 等系统重要位置。为避免该问题,一种策略是永远不要信任 filename 参数中的文件夹信息,例如仅保留最后一个路径段并只考虑实际的文件名(“路径段”为由路径分隔符 "\" 与 "/" 分隔的字段值的组成部分)。
-
许多平台不使用互联网媒体类型(参见 [RFC2046])在文件系统中保存类型信息,而是依赖文件名扩展名。信任服务器提供的文件扩展名可能在以后打开已保存文件时引入权限提升(例如 ".exe")。因此,使用文件扩展名来确定媒体类型的接收者 必须 确保所用的扩展名是安全的,并尽量与接收到的有效载荷的媒体类型相匹配。
-
接收者 应当 去除或替换那些已知会在用户界面和文件名中引起混淆的字符序列,例如控制字符以及首尾空白字符。
-
接收者还需注意在文件系统或 shell 命令中具有特殊含义的名称,比如 "." 与 ".."、"~"、"|" 以及设备名等。接收者 应当 忽略或替换这些名称。
4.4. 处置参数:扩展
4.5. 可扩展性
注意 RFC2183 第 9 节 定义了处置类型与处置参数的 IANA 注册表。此注册表由使用 Content-Disposition 的不同协议(例如 MIME 与 HTTP)共享。因此,并非所有已注册的值在 HTTP 的上下文中都有意义。
5. 示例
指示用户代理显示“另存为”对话框,文件名为 "example.html":
Content-Disposition: Attachment; filename=example.html
指示用户代理行为如同不存在 Content-Disposition 首部字段,但记住文件名 "an example.html" 以便后续保存操作:
Content-Disposition: INLINE; FILENAME= "an example.html"
注:此处使用 quoted-string 形式以便包含空格字符。
指示用户代理显示“另存为”对话框,文件名包含 Unicode 字符 U+20AC(欧元符号):
Content-Disposition: attachment;
filename*= UTF-8''%e2%82%ac%20rates
此处使用 [RFC5987] 中定义的编码来对非 ISO-8859-1 字符进行编码。
下面的示例与上例相同,但为不支持 RFC 5987 的用户代理增加了 "filename" 参数以提高兼容性:
Content-Disposition: attachment;
filename="EURO rates";
filename*=utf-8''%e2%82%ac%20rates
注:那些不支持 RFC 5987 编码的用户代理在 "filename" 之后出现 "filename*" 时会忽略 "filename*"。
6. 国际化注意事项
未来的参数也可能需要国际化支持,在这种情况下可以使用相同的编码。
7. 安全性注意事项
使用服务器提供的信息来构造本地文件名会引入许多风险。这些风险在 第 4.3 节 中进行了总结。
此外,实施者应注意适用于 HTTP 的安全性注意事项(参见 RFC2616 第 15 节),以及在 [RFC5987] 中定义的参数编码(参见 第 5 节)。
8. IANA 注意事项
8.1. 处置值与参数登记表
本规范并未对 RFC2183 第 9 节 中定义的处置值与参数的注册程序做出任何更改。
8.2. 首部字段注册
本文件更新了永久 HTTP 首部字段注册表中 Content-Disposition 首部字段的定义(参见 [RFC3864])。
- 首部字段名:
- Content-Disposition
- 适用协议:
- http
- 状态:
- standard
- 作者/变更控制者:
- IETF
- 规范文档:
- 本规范(第 4 节)
- 相关信息:
- 无
9. 致谢
感谢 Adam Barth、Rolf Eike Beer、Stewart Bryant、Bjoern Hoehrmann、Alfred Hoenes、Roar Lauritzsen、Alexey Melnikov、Henrik Nordstrom 和 Mark Nottingham 提供的宝贵反馈。
10. 参考文献
10.1. 规范性引用
- [ISO-8859-1]
- 国际标准化组织, “Information technology -- 8-bit single-byte coded graphic character sets -- Part 1: Latin alphabet No. 1”,ISO/IEC 8859-1:1998,1998 年。
- [RFC2119]
- Bradner, S.,“Key words for use in RFCs to Indicate Requirement Levels”,BCP 14,RFC 2119,1997 年 3 月。
- [RFC2616]
- Fielding, R. 等,“Hypertext Transfer Protocol -- HTTP/1.1”,RFC 2616,1999 年 6 月。
- [RFC5987]
- Reschke, J.,“Character Set and Language Encoding for Hypertext Transfer Protocol (HTTP) Header Field Parameters”,RFC 5987,2010 年 8 月。
10.2. 补充性引用
- [RFC2046]
- Freed, N. 和 N. Borenstein,“Multipurpose Internet Mail Extensions (MIME) Part Two: Media Types”,RFC 2046,1996 年 11 月。
- [RFC2047]
- Moore, K.,“MIME (Multipurpose Internet Mail Extensions) Part Three: Message Header Extensions for Non-ASCII Text”,RFC 2047,1996 年 11 月。
- [RFC2183]
- Troost, R. 等,“Communicating Presentation Information in Internet Messages: The Content-Disposition Header Field”,RFC 2183,1997 年 8 月。
- [RFC2231]
- Freed, N. 和 K. Moore,“MIME Parameter Value and Encoded Word Extensions: Character Sets, Languages, and Continuations”,RFC 2231,1997 年 11 月。
- [RFC2388]
- Masinter, L.,“Returning Values from Forms: multipart/form-data”,RFC 2388,1998 年 8 月。
- [RFC3864]
- Klyne, G. 等,“Registration Procedures for Message Header Fields”,RFC 3864,2004 年 9 月。
- [RFC3986]
- Berners-Lee, T. 等,“Uniform Resource Identifier (URI): Generic Syntax”,RFC 3986,2005 年 1 月。
- [US-ASCII]
- 美国国家标准协会, “Coded Character Set -- 7-bit American Standard Code for Information Interchange”,ANSI X3.4,1986 年。
Appendix A. 相对于 RFC 2616 的变更
与 RFC2616 第 19.5.1 节 相比,反映实际实现的下列规范性变更已被引入:
Appendix B. 与 RFC 2183 的差异
RFC2183 第 2 节 定义了若干额外的处置参数:"creation-date"、"modification-date"、"quoted-date-time" 和 "size"。大多数用户代理并未实现这些参数,因此在本规范中将其省略。
Appendix C. 国际化的替代方法
默认情况下,HTTP 首部字段参数不能携带 ISO-8859-1(参见 [ISO-8859-1])之外的字符编码(参见 [RFC2616],第 2.2 节)。对于 "filename" 参数,这当然是不可接受的限制。
为完整起见,下文描述了已尝试的各种方法,并解释为何它们不如本规范中采用的 RFC 5987 编码。
C.1. RFC 2047 编码
RFC 2047 定义了用于首部字段的编码机制,但该编码不应被用于首部字段的参数 — 详见 RFC2047 第 5 节:
一个 'encoded-word' 不得出现在 'quoted-string' 中。
...
'encoded-word' 不得用于 MIME Content-Type 或 Content-Disposition 字段的参数,或用于任何结构化字段体,除非出现在 'comment' 或 'phrase' 中。
在实践中,有些用户代理实现了该编码,有些没有(会将编码字符串暴露给用户),还有些会被其所混淆。
C.2. 百分号编码
一些用户代理接受百分号编码(参见 [RFC3986],第 2.1 节)的字符序列。用于解码的字符编码取决于多种因素,包括引用页面的编码、用户代理的区域设置、其配置以及参数的实际值。
在实践中,这种方法难以使用,因为那些不支持它的用户代理会向用户显示已转义的字符序列;而那些实现了它的用户代理,期待采用何种字符编码也难以预测。
C.3. 编码嗅探
一些用户代理会检查值(对于 quoted-string 形式默认为 ISO-8859-1),并在看起来更可能正确时切换到 UTF-8 进行解释。
与上述方法一样,这种做法不可互操作,且也存在误解实际值的风险。
Appendix D. 关于生成 Content-Disposition 首部字段的建议
为与现有和未来的用户代理成功互操作,Content-Disposition 首部字段的发送方建议采取下列做法:
- 当 US-ASCII(参见 [US-ASCII]) 足以表达所需文件名时,包含 "filename" 参数。
- 仅当文件名不包含不允许的字符(例如空格)时使用 token 形式的 filename 参数;在此类情况下,应使用 quoted-string 形式。
- 避免在 filename 参数中包含由百分号紧跟两个十六进制字符构成的序列(例如 %A9),因为一些现有实现将其视为转义字符,而另一些则直接原样传递。
- 避免在 filename 参数的 quoted-string 形式中包含 "\" 字符,因为一些用户代理未实现转义,且 "\" 可能被视为非法的路径字符。
- 尽量避免在 filename 参数中使用非 ASCII 字符。尽管大多数现有实现会将其解码为 ISO-8859-1,但有些实现会应用启发式方法检测 UTF-8,从而可能在某些名称上失败。
- 当所需文件名无法通过 "filename" 形式忠实表达时,应包含 "filename*" 参数。请注意,旧的用户代理不会处理此参数,而是回退使用 "filename" 参数的内容。
- 在发送 "filename*" 参数时,如可能也应生成一个 "filename" 参数作为不支持 "filename*" 形式的用户代理的回退。这可以通过用 US-ASCII 序列替代字符来实现(例如将 Unicode 代码点 U+00E4 替换为 "ae")。注意在某些语言环境下这可能不可行。
- 当包含作为回退的 "filename" 参数时(如上所述),由于某些现有实现的解析问题,"filename" 应首先出现。
- 当存在 "filename*" 参数时,优先使用 UTF-8 作为其编码,因为至少有一种现有实现仅实现该编码。
注意:这些建议基于编写时的用户代理行为,可能会被替代。发布本文档时,<http://purl.org/NET/http/content-disposition-tests> 提供了各种实现当前支持程度的概览。