# Replacing cache-control headers

**URL:** <https://www.ruby-forum.com/t/replacing-cache-control-headers/184993>\
**Category:** NGINX\
**Created:** [March 11, 2010, 4:17pm UTC](https://www.ruby-forum.com/t/replacing-cache-control-headers/184993 "2010-03-11T16:17:54Z")\
**Posts on this page:** 3\
**Page:** 1

<div class="post-metadata">

**Author:** ![rmac217](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/r/bc8723/32.png) [@rmac217](https://www.ruby-forum.com/u/rmac217)\
**Post date:** [March 11, 2010, 4:17pm UTC](https://www.ruby-forum.com/t/replacing-cache-control-headers/184993/1 "2010-03-11T16:17:54Z")

</div>

I’m trying to add Cache-Control headers to an ill-behaved backend  
application (that I don’t control). For many requests, the backend  
sets Cache-Control headers with an empty value (an RFC violation, I  
know, and a bug report has been filed, but resolution is likely going  
to take months from the vendor). Nginx 0.7.62 using default Ubuntu  
package from Karmic.

I need to avoid using the “more Headers” module if at all possible for  
administrative reasons (standard packages are much easier to deal with  
administratively and make life much easier during audits).

So, I am trying to use proxy\_hide\_header and variables to  
conditionally set the header. The problem is that using  
$upstream\_http\_cache\_control in a “set” or “if” statement always seems  
to evaluate to the empty string. However, I can add a customer header  
which shows the value passed from the upstream correctly if is not  
empty.

Here is the relevant portion of my config (I have tried many variants  
of positive and negative logic, without success):

```
    location / {
    proxy_pass http://backend;
    proxy_set_header Host $host;
    proxy_read_timeout 900;
    proxy_redirect default;
    proxy_hide_header Pragma;
    proxy_hide_header Cache-Control;

    set $mycc $upstream_http_cache_control;
    if ($mycc = "") {
            set $mycc "no-cache";
            }

    add_header "Cache-Control" $mycc;
    add_header "X-Upstream-Cache-Control" 

```

$upstream\_http\_cache\_control;  
add\_header “X-Upstream-Expires” $upstream\_http\_expires;  
}

With this configuration, I always get “Cache-Control: no-cache”  
headers, even when “X-Upstream-Cache-Control” shows that the upstream  
did pass a non-empty Cache-Control header. An Example response:  
HTTP/1.1 200 OK  
Server: nginx/0.7.62  
Date: Thu, 11 Mar 2010 15:10:36 GMT  
Content-Type: application/x-javascript  
Connection: keep-alive  
Content-Length: 10134  
Last-Modified: Sun, 24 Jan 2010 12:05:44 GMT  
Accept-Ranges: bytes  
ETag: “166958eed9cca1:0”  
Cache-Control: no-cache  
X-Upstream-Cache-Control: max-age=900

## Is there any way do do this using default nginx modules?

RPM

---

<div class="post-metadata">

**Author:** ![rmac217](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/r/bc8723/32.png) [@rmac217](https://www.ruby-forum.com/u/rmac217)\
**Post date:** [March 11, 2010, 4:48pm UTC](https://www.ruby-forum.com/t/replacing-cache-control-headers/184993/2 "2010-03-11T16:48:21Z")

</div>

Hello!

On Thu, Mar 11, 2010 at 09:17:03AM -0600, Ryan M. wrote:

> ```
> location / {
> }
> 
> ```

As rewrite module directives (“if”, “set”) are executed during  
rewrite phase of request processing it will always see empty value  
of $upstream\_http\_cache\_control variable (it’s not yet available  
as no headers got from upstream yet).

> ```
> add_header "Cache-Control" $mycc;
> add_header "X-Upstream-Cache-Control" $upstream_http_cache_control;
> add_header "X-Upstream-Expires" $upstream_http_expires;
> }
> 
> ```
> 
> With this configuration, I always get “Cache-Control: no-cache”  
> headers, even when “X-Upstream-Cache-Control” shows that the upstream  
> did pass a non-empty Cache-Control header. An Example response:

This is expected behaviour.

[…]

> Is there any way do do this using default nginx modules?

You may try to do this with embedded perl, specifically perl\_set.  
Something like this should work:

```
perl_set $mycc 'sub {
    return shift->variable("upstream_http_cache_control") || 

```

“no-cache”;  
}';

Maxim D.

---

<div class="post-metadata">

**Author:** ![rmac217](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/r/bc8723/32.png) [@rmac217](https://www.ruby-forum.com/u/rmac217)\
**Post date:** [March 12, 2010, 5:16am UTC](https://www.ruby-forum.com/t/replacing-cache-control-headers/184993/3 "2010-03-12T05:16:36Z")

</div>

On Thu, Mar 11, 2010 at 9:47 AM, Maxim D. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid)  
wrote:

> This is expected behaviour.

Thank you for the explanation. It is easy to forget that nginx has a  
declarative configuration language, not imperative. Sort of (order  
does seem to matter in some cases).

> > Is there any way do do this using default nginx modules?
> 
> You may try to do this with embedded perl, specifically perl\_set.  
> Something like this should work:
> 
> Â Â perl\_set Â $mycc Â ‘sub {  
> Â Â Â Â return shift-\>variable(“upstream\_http\_cache\_control”) || “no-cache”;  
> Â Â }’;

Very interesting. The English-language wiki says that this module is  
still experimental, which makes me leery of introducing it to a  
high-volume site (over 600 requests/sec at times). Is that information  
outdated? I cannot seem to find a Russian-language equivalent to that  
page, either on [nginx.org](http://nginx.org) or [sysoev.ru](http://sysoev.ru). Would the Perl module  
drastically slow things down?

Based on your first notes above about the execution order of rewrite  
directives, I was able to come up with a workaround, using a separate  
location. Since I know the URLs that set improper headers on the  
back-end have a specific set of substrings, I was just able to make a  
regex-based location for that ("location ~\* ) which does the  
proxy\_hide\_header cobined with add\_header, while the previous  
“location /” just passes the back-end’s caching headers uinmodified.  
This should work as long as we don’t run across too many more URL  
patterns that need “adjusting”. Again I am a bit worried about  
performance with this regex solution, but we are entering into a load  
test cycle soon.

–  
RPM
