Content-Disposition文件名中的特殊字符

jue*_*n d 30 c++ browser cgi content-disposition http-headers

此线程是如何在HTTP中编码Content-Disposition标头的filename参数的副本 但是,由于很久以前就提出这个问题并且仍然没有令人满意的答案(在我看来),我想再问一次.

我开发了一个C++ CGI应用程序,它可以提供名称中包含特殊字符的文件,例如
" weird#€= {}; filename.txt "

似乎没有可能以适合每个浏览器的方式设置HTTP Content-Dispostion

  • IE浏览器
  • 火狐
  • 歌剧
  • 苹果浏览器

我会为每个浏览器提供不同的解决方案.
现在我走了多远:

Internet Explorer(添加双引号并替换#和;)

Content-Disposition: attachment; filename="weird %23 € = { } %3B filename.txt"
Run Code Online (Sandbox Code Playgroud)

Firefox(双引号似乎工作.没有更多事情要做):

Content-Disposition: attachment; filename="weird # € = { } ; filename.txt"
Run Code Online (Sandbox Code Playgroud)

另一种工作方式:

Content-Disposition: attachment; filename*=UTF-8''weird%20%23%20%e2%82%ac%20%3D%20%7B%20%7D%20%3B%20filename.txt
Run Code Online (Sandbox Code Playgroud)

当只使用双引号时会出现这些问题:

  • =文件名中的消失
  • €将被 - 取代 -

但这有效:

Content-Disposition: attachment; filename*=UTF-8''weird%20%23%20%e2%82%ac%20%3D%20%7B%20%7D%20%3B%20filename.txt
Run Code Online (Sandbox Code Playgroud)

歌剧

使用duoble引号或使用语法:filename*= UTF-8''...会产生以下问题:

  • 文件名中多个粘贴在一起的空格减少为一个
  • {和} disapear:" ab {} cd.txt " - >" abcd.txt "
  • 文件名被删除后; 在其中:" abc; def.txt " - >" abc "

编辑2:这是因为文件名长度限制.这种语法适用于Opera:

Content-Disposition: attachment; filename*=UTF-8''weird%20%23%20%e2%82%ac%20%3D%20%7B%20%7D%20%3B%20filename.txt
Run Code Online (Sandbox Code Playgroud)

苹果浏览器

来自其他线程(如上所述)使用的建议

Content-Disposition: attachment; filename*=UTF-8''weird%20%23%20%80%20%3D%20%7B%20%7D%20%3B%20filename.txt
Run Code Online (Sandbox Code Playgroud)

不适合我.转义字符不会被翻译回来,或者浏览器想要保存到具有我的cgi应用程序名称的文件.那是因为我的编码错了.我没有根据RFC 5987进行编码.但是Safari无论如何都没有使用这种编码.所以到目前为止还没有解决这个角色的问题.

顺便说一句:UTF-8转换器http://www.rishida.net/tools/conversion/

我使用了这些测试的每个浏览器的最新版本:

  • Firefox 7
  • Internet Explorer 9
  • Chrome 15
  • 歌剧11.5
  • Safari 5.1

PS:我在键盘上尝试了所有特殊字符.我在这个帖子中只使用了那些制造麻烦的东西.

编辑:

我还尝试了一个带有键盘上所有特殊字符的文件名(可以在文件名中使用)并且不像上面的测试字符串那样工作:

完整测试字符串:

0 ! § $ % & ( ) = ` ´ { }    [ ] ² ³ @ € µ ^ ° ~ + ' # - _ . , ; ü ä ö ß 9.jpg
Run Code Online (Sandbox Code Playgroud)

编码测试字符串:

0%20%21%20%C2%A7%20%24%20%25%20%26%20%28%20%29%20%3D%20%60%20%C2%B4%20%7B%20%7D%20%20%20%20%5B%20%5D%20%C2%B2%20%C2%B3%20%40%20%E2%82%AC%20%C2%B5%20%5E%20%C2%B0%20~%20%2B%20%27%20%23%20-%20_%20.%20%2C%20%3B%20%C3%BC%20%C3%A4%20%C3%B6%20%C3%9F%209.jpg
Run Code Online (Sandbox Code Playgroud)

使用此方法:

Content-Disposition: attachment; filename*=UTF-8''0%20%21%20%C2%A7%20%24%20%25%20%26%20%28%20%29%20%3D%20%60%20%C2%B4%20%7B%20%7D%20%20%20%20%5B%20%5D%20%C2%B2%20%C2%B3%20%40%20%E2%82%AC%20%C2%B5%20%5E%20%C2%B0%20~%20%2B%20%27%20%23%20-%20_%20.%20%2C%20%3B%20%C3%BC%20%C3%A4%20%C3%B6%20%C3%9F%209.jpg
Run Code Online (Sandbox Code Playgroud)

我有以下结果:

  • Firefox有效
  • Chrome有效
  • IE:$%&()=`'{} []²³€€μ^°〜+'# - _.,; üäöß9.jpg(删除前6个字符).编辑2:这是因为浏览器的文件名长度限制.它始终从字符串的开头切断文件名.我没有深入研究这个问题,但看起来普通的文件名长度大约可以达到200个字符,而且文件名中有很多可以追溯到更多但不到250的文件名.但是没关系.
  • 歌剧:0!§$%&()=`'[]²³€€^ ^〜+'# - _.,; üäöß9.jpg(像以前一样缺少一些角色).编辑2:我缩短了我的测试字符串,因为我怀疑Opera的文件名长度"问题",因为有IE,它也在那里工作.
  • Safari无法使用该语法.那是例外.

编辑2:

到目前为止的状态是,语法filename*= UTF-8''filname转义序列"适用于除Safari之外的所有浏览器.并且唯一被Safari替换的字符是€.我想我可以忍受它.谢谢您!

编辑3:文件名长度

我注意到一些文件名长度问题.

  • Internet Explorer:文件名长度可以为147个字符.如果字符串不包含转义序列,那么这就是文件名的长度.如果是,文件名可以变化.生成的文件名短于147个字符.但它有所不同.我使用了2个转义序列,文件名缩短了5个字符,我使用了许多转义序列,文件名缩短了2个字符.我在这里找不到规则.
  • 其他浏览器似乎没有这个问题.如果文件系统可以处理它们,它们将保存文件.我尝试了250个字符,浏览器说我必须减少文件名(Chrome),或者他们自己将它缩短为220(Opera)或210(Firefox)字符.虽然Opera切断了文件.Safari试图保存那个长文件名并最终没有保存它并在下载列表中将"-1"写为文件名.

Jul*_*hke 12

Firefox,MSIE(从第9版开始),Opera,Konq和Chrome支持; MSIE8和Safari不支持; 其他支持是未知的 - RFC 5987中定义的编码.

请注意

  Content-Disposition: attachment; filename*=UTF-8''weird%20%23%20%80%20%3D%20%7B%20%7D%20%3B%20filename.txt
Run Code Online (Sandbox Code Playgroud)

你得到了欧元字符的编码错误; 它的unicode代码点不是%80,修复它应该使它在除Safari之外的任何地方工作(正确的编码是%e2%82%ac).

测试用例:

http://greenbytes.de/tech/tc2231/#attwithfn2231utf8