httpd-38017

Version:

2.2.0

How it is diagnosed (reproduced or source analysis)?

Source analysis (we cannot reproduce it).

Symptom:

Apache cache refuse to serve any cached content, so every request needs to go to the back-end server even if the local cache had cached the object.

When apache is configured as “mod_cache + mod_disk_cache + mod_proxy + mod_proxy_ajp” as a reverse caching proxy. The backend server (tomcat) sets all the right http headers (Expires, Last-Modified) but apache refuses to serve cached content. The same problem also shows up with mod_mem_cache and/or mod_proxy_http

Root cause:

Inconsistency in storing & look-up of cache object: object storing is using the canonized name “_default_”, while during look-up it did not canonize, directly search using the actual name. This makes httpd thinks the content is not cached...

cache_storage.c

320: apr_status_t cache_generate_key_default(...) {

   ...

   /* Use the canonical name to improve cache hit rate, but only if this is

    * not a proxy request.

    */

-    if (!r->proxyreq) {

+    if (!r->proxyreq || (r->proxyreq == PROXYREQ_REVERSE)) {

// In the buggy run, ‘r->proxyreq == PROXYREQ_REVERSE’, so it was set to ‘_default_’.

       /* Use _default_ as the hostname if none present, as in mod_vhost */

       hostname =  ap_get_server_name(r);

       if (!hostname) {

           hostname = "_default_";

       }

   }

   else if(r->parsed_uri.hostname) {

       ...

   }

   else {

       /* We are a proxied request, with no hostname. Unlikely

        * to get very far - but just in case */

      /* default case of a switch, we should put a log message! */

       hostname = "_default_";

   }

   if (r->proxyreq && r->parsed_uri.scheme) {

       ... ...

   }

   else {

       scheme = "http";

   }

   if(r->proxyreq) {

          ...

       }

    ..

}

Is there Error Message?

No.

Can Errlog anticipate the Error?

Yes. Here, developers are using if.. else if .. else to implement: default-switch. The code logic:

-  if (!r->proxyreq) {

     … ..

   }

   else if(r->parsed_uri.hostname) {

       ...

   }

   else {

       /* We are a proxied request, with no hostname. Unlikely

        * to get very far - but just in case */

      /* default case of a switch, Errlog will put a log message! */

       hostname = "_default_";

   }

NOTE:

Squid bug 2678 is very similar to this one. Developers should pay attention to the inconsistency when canonizing file names during store/retrieve.