Browse Source

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

RFC 7232 Compliance for yii\filters\HttpCache
tags/2.0.0-rc
Alexander Makarov 10 years ago
parent
commit
4a9cc31828
  1. 6
      docs/guide/caching-http.md
  2. 1
      framework/CHANGELOG.md
  3. 6
      framework/filters/HttpCache.php
  4. 70
      tests/unit/framework/filters/HttpCacheTest.php

6
docs/guide/caching-http.md

@ -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.
> 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.
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>

1
framework/CHANGELOG.md

@ -171,6 +171,7 @@ Yii Framework 2 Change Log
- Enh #4297: Added check for DOM extension to requirements (samdark)
- Enh #4317: Added `absoluteAuthTimeout` to yii\web\User (ivokund, nkovacs)
- 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 #4485: Added support for deferred validation in `ActiveForm` (Alex-Code)
- Enh #4520: Added sasl support to `yii\caching\MemCache` (xjflyttp)

6
framework/filters/HttpCache.php

@ -150,10 +150,10 @@ class HttpCache extends ActionFilter
*/
protected function validateCache($lastModified, $etag)
{
if ($lastModified !== null && (!isset($_SERVER['HTTP_IF_MODIFIED_SINCE']) || @strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE']) < $lastModified)) {
return false;
if($etag !== null && in_array($etag, Yii::$app->request->getEtags(), true)) {
return true;
} 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;
}
}

70
tests/unit/framework/filters/HttpCacheTest.php

@ -0,0 +1,70 @@
<?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);
}
}
Loading…
Cancel
Save