Firefox Reports Source File Could Not Be Read

We work on a rather large project that interacts with files stored in the Rackspace Cloud. Users often need to click links to view files saved within orders, and normally this works fine.

Starting today, Firefox only (not Chrome or IE) starting throwing errors like the following for a certain type of file download link:

/tmp/ph5nhgdfgty.part could not be saved, because the source file could not be read.

Try again later, or contact the server administrator.

What was odd was that other files (stored in a different table) downloaded fine. So I first compared the code of the two different functions that prompt the different file downloads, thinking that maybe the one that was failing used a bad header or something. The headers were exactly the same, however.

I then Googled it and found several links like the following, none of which helped me.

Source file could not be read – MozillaZine Knowledge Base
Unable to save or download files – MozillaZine Knowledge Base

I then found this link and I tried the various config changes that were suggested, again, all to no avail.

The following comment caught my eye, however.

This is an old error message relating to corrupted downloads (http://kb.mozillazine.org/Source_file_could_not_be_read), but has become more prevalent in Firefox 33.

To make a long story short… before, if the server sent a response that was smaller than the stated size, the discrepancy was ignored and the download was treated as okay. Starting in Firefox 33, a file smaller than the stated size is treated as corrupted.

I am using Firefox 47.0.1, so I looked at my code and it was doing the following:

// prompt the download
header(‘Content-Description: File Transfer’);
header(‘Content-Type: ‘ . $row[‘file_type’]);
header(‘Content-Disposition: attachment; filename=”‘ . $row[‘file_name’] . ‘”‘);
header(‘Content-Transfer-Encoding: binary’);
header(‘Expires: 0’);
header(‘Cache-Control: post-check=0, pre-check=0, max_age=1’);
header(‘Pragma: public’);
header(‘Content-Length: ‘ . $row[‘size’]);
ob_clean();
flush();

echo $content;

This data is pulled from a MySQL database, and when the file is originally copied to the cloud, we store the file size returned from the cloud and store it in a column for that record in the database. So I changed that code to do the following instead:

header(‘Content-Length: ‘ . strlen($content));

Voila! The download worked, as expected. I asked the client to test, as well, because I had also changed several Firefox configuration options trying to determine the issue (e.g. about:config) and it worked, as expected, for them, as well, without making any configuration changes.

Maybe this will save someone some grief down-the-road!