Commit 45dbbc39 by Qiang Xue

Additional fix to #4728.

parent 109da0b7
......@@ -107,12 +107,10 @@ Expensive ETag generation may defeat the purpose of using `HttpCache` and introd
since they need to be re-evaluated on every request. Try to find a simple expression that invalidates
the cache if the page content has been modified.
> Note: In compliance to [RFC 7232, section 2.4](http://tools.ietf.org/html/rfc7232#section-2.4),
> Note: In compliance to [RFC 7232](http://tools.ietf.org/html/rfc7232#section-2.4),
`HttpCache` will send out both `ETag` and `Last-Modified` headers if they are both configured.
However, in order to satisfy [section 3.3](http://tools.ietf.org/html/rfc7232#section-3.3) the
`If-None-Match` client header will always take precedence over `If-Modified-Since` during validation; meaning
latter one is going to be ignored if a `If-None-Match` header is present in the request.
And if the client sends both of the `If-None-Match` header and the `If-Modified-Since` header, only the former
will be respected.
## `Cache-Control` Header <a name="cache-control"></a>
......
......@@ -130,7 +130,6 @@ class HttpCache extends ActionFilter
if ($this->validateCache($lastModified, $etag)) {
$response->setStatusCode(304);
return false;
}
......@@ -150,10 +149,14 @@ class HttpCache extends ActionFilter
*/
protected function validateCache($lastModified, $etag)
{
if($etag !== null && in_array($etag, Yii::$app->request->getEtags(), true)) {
return true;
if (isset($_SERVER['HTTP_IF_NONE_MATCH'])) {
// HTTP_IF_NONE_MATCH takes precedence over HTTP_IF_MODIFIED_SINCE
// http://tools.ietf.org/html/rfc7232#section-3.3
return $etag === null || in_array($etag, Yii::$app->request->getEtags(), true);
} elseif (isset($_SERVER['HTTP_IF_MODIFIED_SINCE'])) {
return $lastModified === null || @strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE']) >= $lastModified;
} else {
return $lastModified !== null && isset($_SERVER['HTTP_IF_MODIFIED_SINCE']) && @strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE']) >= $lastModified;
return $etag === null && $lastModified === null;
}
}
......
......@@ -37,7 +37,10 @@ class HttpCacheTest extends \yiiunit\TestCase
$method = new \ReflectionMethod($httpCache, 'validateCache');
$method->setAccessible(true);
$this->assertFalse($method->invoke($httpCache, null, null));
unset($_SERVER['HTTP_IF_MODIFIED_SINCE'], $_SERVER['HTTP_IF_NONE_MATCH']);
$this->assertTrue($method->invoke($httpCache, null, null));
$this->assertFalse($method->invoke($httpCache, 0, null));
$this->assertFalse($method->invoke($httpCache, 0, '"foo"'));
$_SERVER['HTTP_IF_MODIFIED_SINCE'] = 'Thu, 01 Jan 1970 00:00:00 GMT';
$this->assertTrue($method->invoke($httpCache, 0, null));
......@@ -45,8 +48,10 @@ class HttpCacheTest extends \yiiunit\TestCase
$_SERVER['HTTP_IF_NONE_MATCH'] = '"foo"';
$this->assertTrue($method->invoke($httpCache, 0, '"foo"'));
$this->assertFalse($method->invoke($httpCache, 0, '"foos"'));
$this->assertTrue($method->invoke($httpCache, 1, '"foo"'));
$this->assertFalse($method->invoke($httpCache, null, null));
$this->assertFalse($method->invoke($httpCache, 1, '"foos"'));
$this->assertTrue($method->invoke($httpCache, null, null));
}
/**
......@@ -67,4 +72,4 @@ class HttpCacheTest extends \yiiunit\TestCase
$this->assertStringStartsWith('"', $etag);
$this->assertStringEndsWith('"', $etag);
}
}
\ No newline at end of file
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment