Nginx X-Accel-Redirect stripping Content-Encoding header

I have Nginx setup to allow requests to be served with the
X-Accel-Redirect
header. This works fine for images, but I’m trying to get it to work for
Javascript files that are already gzip’ed on the disk.

It appears Nginx is stripping off the ‘Content-Encoding: gzip’ header.
This
makes the browser not unzip the content when it receives it, which
obviously
makes it not work.

Is it possible to make Nginx preserve the Content-Encoding header to
allow
pre-gzipped content through X-Accel-Redirect? Or is there another way to
allow this work?

The headers seen are:

With Accel = doesn’t work

Accept-Ranges:bytes
Cache-Control:max-age=1209600, s-maxage=120960
Connection:keep-alive
Content-Length:125499
Content-Type:application/javascript
Date:Fri, 28 Jun 2013 09:52:33 GMT
ETag:“51c8efa3-1ea3b”
Expires:Fri, 12 Jul 2013 09:52:33 GMT
Last-Modified:Tue, 25 Jun 2013 01:17:23 GMT
Server:nginx/1.4.1

No accel = works

Cache-Control:max-age=1209600, s-maxage=120960
Connection:keep-alive
Content-Encoding:gzip
Content-Length:125499
Content-Type:application/javascript
Date:Fri, 28 Jun 2013 09:53:04 GMT
Expires:Fri, 12 Jul 2013 09:53:04 GMT
HTTP1/0 200 Ok:
Pragma:cache
Server:nginx/1.4.1
X-Powered-By:PHP/5.4.9

In case it’s relevant, the code that is serving the content is:

public static function  proxyFile($fileNameToServe, $mimeType, 
$alreadyGzip
= false){
        $seconds_to_cache = 3600 * 24 * 7 * 2;



        if ($alreadyGzip) {
            header('Content-Encoding: gzip');
            $filesize = filesize($fileNameToServe);
            header('Content-Length: '.$filesize);
        }

        if(defined('X-ACCEL-REDIRECT') == true &&
constant('X-ACCEL-REDIRECT') == true){
            $filenameToProxy = str_replace(PATH_TO_ROOT."var/cache",
'/protected_files', $fileNameToServe );
            sendProxyHeaders($mimeType, $seconds_to_cache);
            header("X-Accel-Redirect: ".$filenameToProxy);
            exit(0);
        }
        else{
            sendProxyHeaders($mimeType, $seconds_to_cache);
            $fileHandle = fopen($fileNameToServe, 'r');

            if($fileHandle == false){
                throw new \Exception("Failed to open file 
[$fileNameToServe]
for serving.");
            }

            while (!feof($fileHandle)) {
                $contents = fread($fileHandle, 8192);
                echo $contents;
            }

            fclose($fileHandle);
        }

        exit(0);
    }

    function  sendProxyHeaders($mimeType, $seconds_to_cache,
$secondsForCDNToCache = false){
      $currentTimeStamp = gmdate("D, d M Y H:i:s", time()) . " GMT";
      $timeStamp = gmdate("D, d M Y H:i:s", time() + $seconds_to_cache) 
. "
GMT";

      if($secondsForCDNToCache === false){
        $secondsForCDNToCache = intval($seconds_to_cache / 10);
      }

      header("HTTP1/0 200 Ok");
      header("Content-Type: $mimeType");
      header("Date: $currentTimeStamp");
      header("Expires: $timeStamp");
      header("Pragma: cache");

      //max-age = browser max age
      //s-maxage = intermediate (cache e.g. CDN)
      header("Cache-Control: max-age=$seconds_to_cache,
s-maxage=$secondsForCDNToCache");
    }

Posted at Nginx Forum:
http://forum.nginx.org/read.php?2,240406,240406#msg-240406

Hello!

On Fri, Jun 28, 2013 at 06:21:08AM -0400, Danack wrote:

allow this work?
Any headers from the original response (the one with X-Accel-Redirect)
might be preserved using the $upstream_http_* variables. Something
like this should work:

location /files/ {
    internal;
    add_header Content-Encoding $upstream_http_content_encoding;
}

This might not work well with nginx gzip filter though.

Better solution might be to just return X-Accel-Redirect to an
unrompressed file, and use gzip_static to serve precompressed
files if they are available and supported by a client, see
http://nginx.org/r/gzip_static.


Maxim D.
http://nginx.org/en/donation.html

Something like this should work:

location /files/ {
    internal;
    add_header Content-Encoding $upstream_http_content_encoding;
}

Thanks yep that worked.

This might not work well with nginx gzip filter though.

And yes, I had to turn gzip off for the internal location used for
x-accel-redirect, otherwise it was setting the Content-Encoding header
twice.

Better solution might be to just return X-Accel-Redirect to an
uncompressed file, and use gzip_static to serve precompressed
files if they are available and supported by a client, see
http://nginx.org/r/gzip_static.

Thanks for the tip.

cheers
Dan

Posted at Nginx Forum:
http://forum.nginx.org/read.php?2,240406,240410#msg-240410