apache.htaccessmod-headers

In Apache .htaccess, set Header set Content-disposition, how to pass the filename from QUERY_STRING value


In Apache .htaccess, I have below block to force download.

<If "%{QUERY_STRING} =~ /fileName=/">
  ForceType application/octet-stream
  Header set "Content-disposition" "attachment; filename=download.doc"
</If>

This works fine. Now I need to make the filename be the value of query string key "fileName".

I know how to do this in Nginx. Below is the code.

if ($arg_fileName) {
    set $fname $arg_fileName;
    add_header Content-Disposition 'attachment; filename="$fname"';
}

How to do this in Apache .htaccess?


Solution

  • You could do something like this with the help of mod_rewrite:

    RewriteEngine On
    
    # Save value of fileName URL param in environment variable FILENAME
    RewriteCond %{QUERY_STRING} (?:^|&)fileName=([^&]+)
    RewriteRule ^ - [E=FILENAME:%1]
    
    # Conditionally set header only if FILENAME is set and use this in the header itself
    Header set "Content-Disposition" "attachment; filename=\"%{FILENAME}e\"" env=FILENAME
    

    ([^&]+) - Note, however, that you might want to restrict the regex used to match the fileName parameter value, since not everything is necessarily permitted in the filename argument of the HTTP response header. This can vary by browser and modern browsers do support more. Note also that the value grabbed from the QUERY_STRING is already URL-encoded. So, maybe something like ([\w.-]+) would be sufficient instead to match just a-z, A-Z, 0-9, _, . and -?

    The env=FILENAME argument results in the header only being set when the FILENAME env var exists, so this negates the need for the <If> expression.

    ForceType application/octet-stream
    

    This isn't strictly necessary to trigger a download, it is the Content-Disposition: attachment header that does this in any remotely modern browser. In fact, it is not necessarily recommended to send the application/octet-stream mime-type for all responses. You should be sending the correct Content-Type header for the resource being sent.