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 Legacy:

DownloadButton…but 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...n%0D%0A

The error shows that Edge Legacy 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 Legacy 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. The new Chromium-based Edge does not have this limitation.

(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 Legacy’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);
down2.addEventListener("onclick", function(){ if (navigator.msSaveOrOpenBlob) {navigator.msSaveOrOpenBlob(text2,"simple.csv"); return false;}});
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.

See this GitHub thread for a fuller discussion.

-Eric

PS: Even in the new Chromium-based Edge, downloads sourced from blob: or data: may not be handled properly by browser policies that call for special handling of files from specified sites. See https://crbug.com/1169904, for details.

Published by ericlaw

Impatient optimist. Dad. Author/speaker. Created Fiddler & SlickRun. PM @ Microsoft 2001-2012, and 2018-, working on Office, IE, and Edge. Now a GPM for Microsoft Defender. My words are my own, I do not speak for any other entity.

2 thoughts on “Script-Generated Download Files

    1. You’ll need to be a lot more specific than “It doesn’t work.” Please provide a link to a jsFiddle or demo page.

Leave a comment