browsers

Script-Generated Download Files

As we finish up the next release of Windows 10, my team is hard at work triaging incoming bugs. Here’s a pattern that has come up a few times this month:

Bug: I click download in Edge:

DownloadButtonbut I end up on an error page:

WompWompDataURI

Womp womp.

If you watch the network traffic, you’ll see that no request even hits the network in the failing case. But, if you carefully scroll that ugly error URL to see the middle, the source of the problem appears:

ms-appx-web://microsoft.microsoftedge/assets/errorpages/dnserror.html?ErrorStatus=0x80704006&NetworkStatusSupported=1#data:text/csv;charset=UTF-8, ID,Datetime,Type,Status,Note,From,To,Amount%20(total),Amount%20(fee),Funding%20Source,Destination%0D%0A

The error shows that Edge failed to navigate to a URL with the Data URI scheme.

Ever since we introduced support for DATA URLs a decade ago in Internet Explorer 8, they’ve been throttled with one major limitation: You cannot navigate to these URIs at the top level of the browser. Edge loosened things up so that Data URLs under 4096 characters can be used as the source of IFRAMEs, but the browser will not navigate to a data URL at the top level.

(Yes, this error page could use some love.)

Now, you might remember that last winter, Chrome took a change to forbid top-level navigation to data URIs (due to spoofing concerns), but that restriction contains one important exception: navigations that get turned into downloads (due to their MIME type being one other than something expected to render in the browser) are exempted. So this scenario sorta works in Chrome. (I say “sorta” because the authors of this site failed to specify a meaningful filename on the link, so the file downloads without the all-important .csv extension).

ChromeWorksSorta2

So, does IE/Edge’s restriction on Data URIs mean that webdevs cannot generate downloadable files dynamically in JavaScript in a way that works in all browsers?

No, of course not.

There are many alternative approaches, but one simple approach is to just use a blob URL, like so:

  var text2 = new Blob(["a,b,c,d"], { type: 'text/csv'});
  var down2 = document.createElement("a");
  down2.download = "simple.csv";
  down2.href = window.URL.createObjectURL(text2);
  document.body.appendChild(down2);
  down2.innerText="I have a download attribute. Click me";

When the link is clicked, the CSV file is downloaded with a proper filename.

 

-Eric

Standard

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s