Home > Net >  Response Header with UTF-8 Attachment Filename With Apostrophe Downloads with wrong filename in Chro
Response Header with UTF-8 Attachment Filename With Apostrophe Downloads with wrong filename in Chro

Time:12-13

There seems to be an issue where both Chrome and Edge download a file with the incorrect filename when they receive a header with a UTF-8 filename containing an apostrophe. For example, calling this URL: https://localhost:44328/Home/GetDocument?id=2

Which returns this Response Header:

content-disposition: attachment; filename*=UTF-8''Supplier's Notes.txt

Will download a file named "Supplier's Notes.txt" in Firefox but will download a file named "GetDocument.htm" in both Chrome and Edge.

Is this a known browser issue? Is there any way to address this?

Here is some sample MVC code you can use to reproduce the issue:

HomeController.cs

using DownloadNameWithApostrophe.Models;
using System.Text;
using System.Web.Mvc;

namespace DownloadNameWithApostrophe.Controllers
{
    public class HomeController : Controller
    {
        public ActionResult Index()
        {
            return View(new SampleViewModel());
        }

        public void GetDocument(int id)
        {
            if (!SampleViewModel.SampleData.ContainsKey(id))
            {
                return;
            }

            var attachmentString = "filename*=UTF-8''"   SampleViewModel.SampleData[id];
            this.HttpContext.Response.Clear();
            this.HttpContext.Response.AddHeader("Content-Disposition", "attachment; "   attachmentString);
            this.HttpContext.Response.AddHeader("Contenty-type", "application/octet-stream");

            var bytes = Encoding.ASCII.GetBytes("Hello World");            
            this.HttpContext.Response.OutputStream.Write(bytes, 0, bytes.Length);

            this.HttpContext.Response.Flush();
            this.HttpContext.Response.End();
        }       
    }
}

SampleViewModel.cs

using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;

namespace DownloadNameWithApostrophe.Models
{
    public class SampleViewModel
    {
        public static Dictionary<int, string> SampleData
        {
            get
            {
                var downloads = new Dictionary<int, string>();
                downloads.Add(1, "Initial Estimate.txt");
                downloads.Add(2, "Supplier's Notes.txt");
                return downloads;
            }
        }

        [Display(Name = "Available Downloads")]
        public Dictionary<int, string> Downloads { get; set; }

        public SampleViewModel()
        {
            Downloads = SampleData;
        }
        
    }
}

Index.cshtml

@model DownloadNameWithApostrophe.Models.SampleViewModel
@{
    Layout = null;
}

<div >
    <div >
        <h2>Getting started</h2>
        @Html.LabelFor(m => m.Downloads)
        @foreach (var download in Model.Downloads)
        {
            <br />
           <a href="@Url.RouteUrl(new {action="GetDocument", controller="Home"})[email protected]">@download.Value</a>
        }
    </div>
</div>

CodePudding user response:

That's because Chromium implements RFC 3986, in which ' is a reserved character which must be percent-encoded.

You can use Uri.EscapeDataString() to escape the string:

var attachmentString = "filename*=UTF-8''"   Uri.EscapeDataString(SampleViewModel.SampleData[id]);

Then the file name will be "Supplier's Notes.txt" in Chrome and Edge.

  • Related