简体   繁体   中英

Unicode in Content-Disposition header

I am using HttpContext object implemented in HttpHandler child to download a file, when I have non-ascii characters in file name it looks weird in IE whereas it looks fine in Firefox.

below is the code:-

       context.Response.ContentType = ".cs";
context.Response.AppendHeader("Content-Length", data.Length.ToString());
context.Response.AppendHeader("Content-Disposition", String.Format("attachment; filename={0}",filename));
        context.Response.OutputStream.Write(data, 0, data.Length);

context.Response.Flush();

when I supply 'ß' 'ä' 'ö' 'ü' 'ó' 'ß' 'ä' 'ö' 'ü' 'ó' in file name field it looks different than what I have in file name it looks fine in firefox. adding EncodingType and charset has been of no use.

In ie it is 'ß' 'ä' 'ö' 'ü' 'ó' 'ß' 'ä' 'ö' 'ü'_'ó' and in firefox it is 'ß' 'ä' 'ö' 'ü' 'ó' 'ß' 'ä' 'ö' 'ü' 'ó'.

Any Idea how this can be fixed?

I had similar problem. You have to use HttpUtility.UrlEncode or Server.UrlEncode to encode filename. Also I remember firefox didn't need it. Moreoverit ruined filename when it's url-encoded. My code:

// IE needs url encoding, FF doesn't support it, Google Chrome doesn't care
if (Request.Browser.IsBrowser ("IE"))
{
    fileName = Server.UrlEncode(fileName);
}

Response.Clear ();
Response.AddHeader ("content-disposition", String.Format ("attachment;filename=\"{0}\"", fileName));
Response.AddHeader ("Content-Length", data.Length.ToString (CultureInfo.InvariantCulture));
Response.ContentType = mimeType;
Response.BinaryWrite(data);

Edit

I have read specification more carefully. First of all RFC2183 states that:

Current [RFC 2045] grammar restricts parameter values (and hence Content-Disposition filenames) to US-ASCII.

But then I found references that [RFC 2045] is absolete and one must reference RFC 2231 , which states:

Asterisks ("*") are reused to provide the indicator that language and character set information is present and encoding is being used. A single quote ("'") is used to delimit the character set and language information at the beginning of the parameter value. Percent signs ("%") are used as the encoding flag, which agrees with RFC 2047.

Which means that you can use UrlEncode for non-ascii symbols, as long as you include the encoding as stated in the rfc . Here is an example:

string.Format("attachment; filename=\"{0}\"; filename*=UTF-8''{0}", Server.UrlEncode(fileName, Encoding.UTF8));

Note that filename is included in addition to filename* for backwards compatibility. You can also choose another encoding and modify the parameter accordingly, but UTF-8 covers everything.

HttpUtility.UrlPathEncode might be a better option. As URLEncode will replace spaces with '+' signs.

For me this solution is working on all major browsers:

Response.AppendHeader("Content-Disposition", string.Format("attachment; filename*=UTF-8''{0}", HttpUtility.UrlPathEncode(fileName).Replace(",", "%2C"));
var mime = MimeMapping.GetMimeMapping(fileName);
return File(fileName, mime);

Using ASP.NET MVC 3.

The Replace is necessary, because Chrome doesn't like Comma (,) in parameter values: http://www.gangarasa.com/lets-Do-GoodCode/tag/err_response_headers_multiple_content_disposition/

您可能需要阅读RFC 6266并查看http://greenbytes.de/tech/tc2231/上的测试。

For me this solved the problem:

var result = new HttpResponseMessage(HttpStatusCode.OK)
{
   Content = new ByteArrayContent(data)
};

result.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment")
{
    FileNameStar = "foo-ä-€.html"
};

When i look ad the repsonse in fiddler i can see the filename has automaticcaly been encoded using UTF-8:

Fiddler response example with encoded Content-Disposition filename using UTF-8

If we look at the value of the Content-Disposition header we can see it will be the same as @Johannes Geyer his answer. The only difference is that we didn't have to do the encoding ourselfs, the ContentDispositionHeaderValue class takes care of that.

I used the Testcases for the Content-Disposition header on: http://greenbytes.de/tech/tc2231/ as mentioned by Julian Reschke. Information about the ContentDispositionHeaderValue class can be found on MSDN.

For Asp.Net Core (version 2 as of this post) UrlPathEncode is deprecated, here's how to achieve the desired result:

System.Net.Mime.ContentDisposition cd = new System.Net.Mime.ContentDisposition
{
   FileName = Uri.EscapeUriString(fileName),
   Inline = true  // false = prompt the user for downloading;  true = browser to try to show the file inline
};

Response.Headers.Add("Content-Disposition", cd.ToString());

I`m using Uri.EscapeUriString for converts all characters to their hexadecimal representation, and string.Normalize for Unicode normalization form C. (tested in ASP.NET MVC5 framework 4.5)

    var contentDispositionHeader = new System.Net.Mime.ContentDisposition
    {
        Inline = false,
        FileName = Uri.EscapeUriString(Path.GetFileName(pathFile)).Normalize()
    };
    Response.Headers.Add("Content-Disposition", contentDispositionHeader.ToString());
    string mimeType = MimeMapping.GetMimeMapping(Server.MapPath(pathFile));
    return File(file, mimeType);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM