Commit 4a9cc318 by Alexander Makarov

Merge pull request #4728 from DaSourcerer/4372-httpcache-rfc7232-compliance

RFC 7232 Compliance for yii\filters\HttpCache
parents 90c6a476 528e12f4
...@@ -108,9 +108,11 @@ since they need to be re-evaluated on every request. Try to find a simple expres ...@@ -108,9 +108,11 @@ since they need to be re-evaluated on every request. Try to find a simple expres
the cache if the page content has been modified. the cache if the page content has been modified.
> Note: In compliant to [RFC 2616, section 13.3.4](http://tools.ietf.org/html/rfc2616#section-13.3.4), > Note: In compliance to [RFC 7232, section 2.4](http://tools.ietf.org/html/rfc7232#section-2.4),
`HttpCache` will send out both `ETag` and `Last-Modified` headers if they are both configured. `HttpCache` will send out both `ETag` and `Last-Modified` headers if they are both configured.
Consequently, both will be used for cache validation if sent by the client. 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.
## `Cache-Control` Header <a name="cache-control"></a> ## `Cache-Control` Header <a name="cache-control"></a>
......
...@@ -171,6 +171,7 @@ Yii Framework 2 Change Log ...@@ -171,6 +171,7 @@ Yii Framework 2 Change Log
- Enh #4297: Added check for DOM extension to requirements (samdark) - Enh #4297: Added check for DOM extension to requirements (samdark)
- Enh #4317: Added `absoluteAuthTimeout` to yii\web\User (ivokund, nkovacs) - Enh #4317: Added `absoluteAuthTimeout` to yii\web\User (ivokund, nkovacs)
- Enh #4360: Added client validation support for file validator (Skysplit) - Enh #4360: Added client validation support for file validator (Skysplit)
- Enh #4372: `yii\filters\HttpCache` failed to comply to RFC 7232
- Enh #4436: Added callback functions to AJAX-based form validation (thiagotalma) - Enh #4436: Added callback functions to AJAX-based form validation (thiagotalma)
- Enh #4485: Added support for deferred validation in `ActiveForm` (Alex-Code) - Enh #4485: Added support for deferred validation in `ActiveForm` (Alex-Code)
- Enh #4520: Added sasl support to `yii\caching\MemCache` (xjflyttp) - Enh #4520: Added sasl support to `yii\caching\MemCache` (xjflyttp)
......
...@@ -150,10 +150,10 @@ class HttpCache extends ActionFilter ...@@ -150,10 +150,10 @@ class HttpCache extends ActionFilter
*/ */
protected function validateCache($lastModified, $etag) protected function validateCache($lastModified, $etag)
{ {
if ($lastModified !== null && (!isset($_SERVER['HTTP_IF_MODIFIED_SINCE']) || @strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE']) < $lastModified)) { if($etag !== null && in_array($etag, Yii::$app->request->getEtags(), true)) {
return false; return true;
} else { } else {
return $etag === null || in_array($etag, Yii::$app->request->getEtags(), true); return $lastModified !== null && isset($_SERVER['HTTP_IF_MODIFIED_SINCE']) && @strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE']) >= $lastModified;
} }
} }
......
<?php
namespace yiiunit\framework\filters;
use Yii;
use yii\filters\HttpCache;
/**
* @group filters
*/
class HttpCacheTest extends \yiiunit\TestCase
{
protected function setUp()
{
parent::setUp();
$_SERVER['SCRIPT_FILENAME'] = "/index.php";
$_SERVER['SCRIPT_NAME'] = "/index.php";
$this->mockWebApplication();
}
public function testDisabled()
{
$httpCache = new HttpCache;
$this->assertTrue($httpCache->beforeAction(null));
$httpCache->enabled=false;
$this->assertTrue($httpCache->beforeAction(null));
}
/**
* @covers yii\filters\HttpCache::validateCache
*/
public function testValidateCache()
{
$httpCache = new HttpCache;
$method = new \ReflectionMethod($httpCache, 'validateCache');
$method->setAccessible(true);
$this->assertFalse($method->invoke($httpCache, null, null));
$_SERVER['HTTP_IF_MODIFIED_SINCE'] = 'Thu, 01 Jan 1970 00:00:00 GMT';
$this->assertTrue($method->invoke($httpCache, 0, null));
$this->assertFalse($method->invoke($httpCache, 1, null));
$_SERVER['HTTP_IF_NONE_MATCH'] = '"foo"';
$this->assertTrue($method->invoke($httpCache, 0, '"foo"'));
$this->assertTrue($method->invoke($httpCache, 1, '"foo"'));
$this->assertFalse($method->invoke($httpCache, null, null));
}
/**
* @covers yii\filters\HttpCache::generateEtag
*/
public function testGenerateEtag()
{
$httpCache = new HttpCache;
$httpCache->etagSeed = function($action, $params) {
return '';
};
$httpCache->beforeAction(null);
$response = Yii::$app->getResponse();
$this->assertTrue($response->getHeaders()->offsetExists('ETag'));
$etag = $response->getHeaders()->get('ETag');
$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