c++ - 内容处置文件名中的特殊字符

标签 c++ browser http-headers cgi content-disposition

我的问题是How to encode the filename parameter of Content-Disposition header in HTTP?的副本
但是由于这个问题是很久以前提出的,而且仍然没有令人满意的答案(我认为),因此我想再次提出。

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

似乎无法以适用于每种浏览器的方式设置HTTP Content-Dispostion

  • Internet Explorer
  • Firefox
  • Chrome
  • 歌剧
  • Safari

  • 对于每个浏览器都有不同的解决方案,我将感到满意。
    现在,我走了多远:

    Internet Explorer(添加双引号并替换为#和;)
    Content-Disposition: attachment; filename="weird %23 € = { } %3B filename.txt"
    

    Firefox(双引号似乎起作用。仅此而已):
    Content-Disposition: attachment; filename="weird # € = { } ; filename.txt"
    

    另一个可行的替代方案:
    Content-Disposition: attachment; filename*=UTF-8''weird%20%23%20%e2%82%ac%20%3D%20%7B%20%7D%20%3B%20filename.txt
    

    Chrome

    当仅使用双引号时,会出现以下问题:
  • =在文件名中消失
  • €将替换为-

  • 但这有效:
    Content-Disposition: attachment; filename*=UTF-8''weird%20%23%20%e2%82%ac%20%3D%20%7B%20%7D%20%3B%20filename.txt
    

    歌剧

    使用双引号或使用语法:filename * = UTF-8''...会产生以下问题:
  • 文件名中多个粘贴在一起的空格减少为一个
  • {和}消失:“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
    

    苹果浏览器
  • €将被看不见的字符替换(使用双引号)
    no solution that prevents that little problem
    

  • 来自上述其他线程的建议使用
    Content-Disposition: attachment; filename*=UTF-8''weird%20%23%20%80%20%3D%20%7B%20%7D%20%3B%20filename.txt
    

    没有为我工作。转义字符不会被翻译回,或者浏览器要使用我的cgi应用程序的名称保存到文件中。那是因为我的编码是错误的。我没有根据RFC 5987进行编码。但是Safari始终没有使用这种编码。因此,到目前为止,对于€字符而言,还没有解决方案。

    BTW:UTF-8转换器http://www.rishida.net/tools/conversion/

    在这些测试中,我使用了每个浏览器的最新版本:
  • Firefox 7
  • Internet Explorer 9
  • Chrome 15
  • Opera 11.5
  • Safari 5.1

  • PS:我尝试了键盘上的所有特殊字符。在此线程中,我仅使用那些造成麻烦的线程。

    编辑:

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

    完整的测试字符串:
    0 ! § $ % & ( ) = ` ´ { }    [ ] ² ³ @ € µ ^ ° ~ + ' # - _ . , ; ü ä ö ß 9.jpg
    

    编码的测试字符串:
    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
    

    使用此方法:
    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
    

    我得到以下结果:
  • Firefox可以使用
  • Chrome可以使用
  • IE:$%&()=`´{} []²³@€µ ^°〜+'#-_。 ,; üöß9.jpg(删除了前6个字符)。编辑2:这是由于浏览器的文件名长度限制。它开始从字符串的开头截断文件名。我并未对此进行深入研究,但看起来普通文件名的长度可能约为200个字符,并且具有许多转义序列的文件名甚至更多,但少于250个。但这没关系。
  • Opera:0! §$%&()=`´[]²³@€µ ^°〜+'#-_。 ,; üöß9.jpg(与以前一样缺少一些字符)。编辑2:我缩短了测试字符串,因为我怀疑Opera的文件名长度“有问题”,就像IE一样,它在那里也可以工作。
  • Safari无法使用该语法。那是异常(exception)。

  • 编辑2:

    到目前为止,状态是,文件名* = UTF-8''filname escape sequence”可以在除Safari之外的所有浏览器上使用。唯一可以被Safari替换的字符是€。我想我可以接受。您!

    编辑3:文件名长度

    我注意到一些文件名长度问题。
  • Internet Explorer:文件名长度可以为147个字符。如果字符串不包含转义序列,则为文件名的长度。如果是这样,文件名可能会有所不同。结果文件名短于147个字符。但这有所不同。我使用了2个转义序列,文件名缩短了5个字符,并且我使用了许多转义序列,文件名缩短了onyl 2个字符。我在这里找不到规则。
  • 其他浏览器似乎没有这个问题。如果文件系统可以处理文件,他们将保存文件。例如,我尝试使用250个字符,浏览器说我必须减少文件名(Chrome),否则他们自己将文件名缩短为220(Opera)或210(Firefox)字符。 Opera切断了文件结尾。 Safari尝试保存该长文件名,但最终没有保存它,而是在下载列表中将“-1”作为文件名写入。
  • 最佳答案

    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
    

    您得到的欧元字符编码错误;它的Unicode代码点不是%80,要解决此问题,它应该可以在除Safari之外的所有地方正常工作(正确的编码为%e2%82%ac)。

    测试案例位于:

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

    关于c++ - 内容处置文件名中的特殊字符,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7967079/

    相关文章:

    c++ - 使用虚函数代替 IF 语句更快?

    authentication - JitBit 帮助台 API

    c# - Content-Disposition header 中的 Unicode

    php - 如何确定压缩文件的内容长度?

    c++ - 使用基类的派生类中定义的类型

    C++/Qt enum - 我应该使用锁定来跨线程共享值吗?

    c++ - gnuplot: multimap 缩放

    javascript - 在什么情况下 websocket 关闭事件会告诉你 wasClean 是假的?

    C++ 更改 Opera 代理设置

    multithreading - Delphi:后台线程中的 TWebBrowser