Saturday, October 1, 2011

Force downloading through dynamic Content-Disposition

The Problem

I wanted to make it to images on my personal site could be downloaded easily. But I also want them to be normally visible in the browser. I decided to solve this with a query string parameter so:
http://epii.info/anime/2011/Fanime/Ace%20Attorney%20-%20Trucy%20Wright%208.jpg
will load the image (of Trucy from Ace Attorney), and
http://epii.info/anime/2011/Fanime/Ace%20Attorney%20-%20Trucy%20Wright%208.jpg?dl
will give the user the option to download it.

Basically I want to conditionally apply a Content-Disposition: attachment header to essentially static files, depending on the query-string.

The Solution

I found a close, but non-working example at Experts Exchange. I revised that into this:
RewriteCond %{QUERY_STRING} ^dl
RewriteRule ^((.*/)*([^/]+jpg))$ - [E=dlfilename:$3,E=fullpath:$1]
Header onsuccess set Content-Disposition "attachment;filename=\"%{dlfilename}e\"" env=dlfilename
Header onsuccess set Content-Location "/%{fullpath}e" env=dlfilename
Header onsuccess set Link "</%{fullpath}e>; rel=\"canonical\"" env=dlfilename

which is placed in an Apache 2.2 .htaccess file in the shared-hosting webserver's root.
It assumes mod_rewrite is installed and turned on (via RewriteEngine on), as well as mod_headers

Breakdown

RewriteCond %{QUERY_STRING} ^dl
The RewriteRule now only applies if the query string starts with "dl"

RewriteRule ^((.*/)*([^/]+jpg))$ - [E=dlfilename:$3,E=fullpath:$1]
This doesn't rewrite anything, but rather assigns two Apache environment variables if the file ends in jpg (and the previous RewriteCond passed). dlfilename is set with just the file name, not the full path. fullpath contains the full path (relative to .htaccess) to the requested file.

Header onsuccess set Content-Disposition "attachment;filename=\"%{dlfilename}e\"" env=dlfilename
If the dlfilename environment variable has been set, this sets the Content-Type to suggest the user saves the file, and sets the filename to the file's name. (could be problematic as implemented here if your file names contain quotes.)

Header onsuccess set Content-Location "/%{fullpath}e" env=dlfilename
This sets the Content-Location to offer a canonical location of the file. The idea is to improve image SEO by telling the search engine they aren't different. Google says they ignore this header due to it being popularly misconfigured. Just in case anyone does use it though, it's there.

Header onsuccess set Link "</%{fullpath}e>; rel=\"canonical\"" env=dlfilename
More SEO. This is Google's suggested alternative to Content-Location, though they say it only applied to Web Search for now. So if you're using images like me, this may not help you any. But if you're using PDFs, it probably will.

No comments:

Post a Comment