We ran into this as well. It's a bug in W3 Total Cache. I'm hoping the authors read this, else I'll try to get to them more directly.
We had this occurring on our brand-new wordpress install too. Turns out that W3TC caches HEAD and GET and serves them equally. So if a HEAD request for a URL is sent, it will be cached, and the next time a GET for that same resource is received it will return the cached HEAD response, which means you'll get a "Content-Length: 2" and a \r\n for your content, nothing else.
Here's a patch that will simply not cache HEAD at all:
diff --git wp-content/plugins/w3-total-cache/lib/W3/PgCache.php wp-content/plugins/w3-total-cache/lib/W3/PgCache.php
index aec6e61..44d0f61 100644
--- wp-content/plugins/w3-total-cache/lib/W3/PgCache.php
+++ wp-content/plugins/w3-total-cache/lib/W3/PgCache.php
@@ -493,20 +493,26 @@ class W3_PgCache {
/**
* Skip if posting
*/
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
$this->cache_reject_reason = 'Requested method is POST';
return false;
}
+ if ($_SERVER['REQUEST_METHOD'] == 'HEAD') {
+ $this->cache_reject_reason = 'Requested method is HEAD';
+
+ return false;
+ }
+
/**
* Skip if there is query in the request uri
*/
if (!$this->_config->get_boolean('pgcache.cache.query') && strstr($this->_request_uri, '?') !== false) {
$this->cache_reject_reason = 'Requested URI contains query';
return false;
}
/**
This is a large hammer that simply prevents any HEAD requests from being generated, so you never cache that 'blank' page. It does mean that you essentially have a heavy response generated each time for HEADs, so if caching is critical for your server load this is vulnerable to potential DoS.
A better solution when a HEAD request is made would be to generate the page as if a GET were requested and cache both the HEAD and GET responses independently and serve the appropriate one. I have not investigated the W3 Total Cache code enough to implement this.
I hope my change above, or the improved one I described, can make it into a updated version of the plugin. Please ping me if there are any questions.
Here's how to reproduce this:
- clear cache
- curl -I http://www.example.com/page/
- You'll see just headers, as appropriate
- curl http://www.example.com/page/
- You'll see just headers, which is wrong for a GET.