Skip to content

Commit a44945a

Browse files
committed
bug symfony#10896 [HttpKernel] Fixed cache behavior when TTL has expired and a default "global" TTL is defined (alquerci, fabpot)
This PR was merged into the 2.3 branch. Discussion ---------- [HttpKernel] Fixed cache behavior when TTL has expired and a default "global" TTL is defined | Q | A | ------------- | --- | Bug fix? | yes | New feature? | no | BC breaks? | no | Deprecations? | no | Tests pass? | no | Fixed tickets | symfony#8232, symfony#10822, symfony#9919 | License | MIT From symfony#9919: "When the cache is stale the `validate` method `forward` the request to the backend. A new response will be created with or without TTL configuration. If the TTL was not set then the default one should be set like in the `fetch` method." This PR fixes this issue, the tests provided in symfony#9919 pass, and I've tweaked them to avoid the costly sleep calls. Commits ------- e3983e8 [HttpKernel] fixed default TTL not applied under certain conditions bc42dae Added test when TTL has expired
2 parents 46725c9 + e3983e8 commit a44945a

File tree

2 files changed

+107
-6
lines changed

2 files changed

+107
-6
lines changed

src/Symfony/Component/HttpKernel/HttpCache/HttpCache.php

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -428,12 +428,6 @@ protected function fetch(Request $request, $catch = false)
428428

429429
$response = $this->forward($subRequest, $catch);
430430

431-
if ($this->isPrivateRequest($request) && !$response->headers->hasCacheControlDirective('public')) {
432-
$response->setPrivate(true);
433-
} elseif ($this->options['default_ttl'] > 0 && null === $response->getTtl() && !$response->headers->getCacheControlDirective('must-revalidate')) {
434-
$response->setTtl($this->options['default_ttl']);
435-
}
436-
437431
if ($response->isCacheable()) {
438432
$this->store($request, $response);
439433
}
@@ -487,6 +481,12 @@ protected function forward(Request $request, $catch = false, Response $entry = n
487481

488482
$this->processResponseBody($request, $response);
489483

484+
if ($this->isPrivateRequest($request) && !$response->headers->hasCacheControlDirective('public')) {
485+
$response->setPrivate(true);
486+
} elseif ($this->options['default_ttl'] > 0 && null === $response->getTtl() && !$response->headers->getCacheControlDirective('must-revalidate')) {
487+
$response->setTtl($this->options['default_ttl']);
488+
}
489+
490490
return $response;
491491
}
492492

src/Symfony/Component/HttpKernel/Tests/HttpCache/HttpCacheTest.php

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -593,6 +593,107 @@ public function testAssignsDefaultTtlWhenResponseHasNoFreshnessInformation()
593593
$this->assertTraceContains('fresh');
594594
$this->assertTraceNotContains('store');
595595
$this->assertEquals('Hello World', $this->response->getContent());
596+
$this->assertRegExp('/s-maxage=10/', $this->response->headers->get('Cache-Control'));
597+
}
598+
599+
public function testAssignsDefaultTtlWhenResponseHasNoFreshnessInformationAndAfterTtlWasExpired()
600+
{
601+
$this->setNextResponse();
602+
603+
$this->cacheConfig['default_ttl'] = 2;
604+
$this->request('GET', '/');
605+
$this->assertHttpKernelIsCalled();
606+
$this->assertTraceContains('miss');
607+
$this->assertTraceContains('store');
608+
$this->assertEquals('Hello World', $this->response->getContent());
609+
$this->assertRegExp('/s-maxage=2/', $this->response->headers->get('Cache-Control'));
610+
611+
$this->request('GET', '/');
612+
$this->assertHttpKernelIsNotCalled();
613+
$this->assertEquals(200, $this->response->getStatusCode());
614+
$this->assertTraceContains('fresh');
615+
$this->assertTraceNotContains('store');
616+
$this->assertEquals('Hello World', $this->response->getContent());
617+
$this->assertRegExp('/s-maxage=2/', $this->response->headers->get('Cache-Control'));
618+
619+
// expires the cache
620+
$values = $this->getMetaStorageValues();
621+
$this->assertCount(1, $values);
622+
$tmp = unserialize($values[0]);
623+
$time = \DateTime::createFromFormat('U', time());
624+
$tmp[0][1]['date'] = \DateTime::createFromFormat('U', time() - 5)->format(DATE_RFC2822);
625+
$r = new \ReflectionObject($this->store);
626+
$m = $r->getMethod('save');
627+
$m->setAccessible(true);
628+
$m->invoke($this->store, 'md'.sha1('http://localhost/'), serialize($tmp));
629+
630+
$this->request('GET', '/');
631+
$this->assertHttpKernelIsCalled();
632+
$this->assertEquals(200, $this->response->getStatusCode());
633+
$this->assertTraceContains('stale');
634+
$this->assertTraceContains('invalid');
635+
$this->assertTraceContains('store');
636+
$this->assertEquals('Hello World', $this->response->getContent());
637+
$this->assertRegExp('/s-maxage=2/', $this->response->headers->get('Cache-Control'));
638+
639+
$this->setNextResponse();
640+
641+
$this->request('GET', '/');
642+
$this->assertHttpKernelIsNotCalled();
643+
$this->assertEquals(200, $this->response->getStatusCode());
644+
$this->assertTraceContains('fresh');
645+
$this->assertTraceNotContains('store');
646+
$this->assertEquals('Hello World', $this->response->getContent());
647+
$this->assertRegExp('/s-maxage=2/', $this->response->headers->get('Cache-Control'));
648+
}
649+
650+
public function testAssignsDefaultTtlWhenResponseHasNoFreshnessInformationAndAfterTtlWasExpiredWithStatus304()
651+
{
652+
$this->setNextResponse();
653+
654+
$this->cacheConfig['default_ttl'] = 2;
655+
$this->request('GET', '/');
656+
$this->assertHttpKernelIsCalled();
657+
$this->assertTraceContains('miss');
658+
$this->assertTraceContains('store');
659+
$this->assertEquals('Hello World', $this->response->getContent());
660+
$this->assertRegExp('/s-maxage=2/', $this->response->headers->get('Cache-Control'));
661+
662+
$this->request('GET', '/');
663+
$this->assertHttpKernelIsNotCalled();
664+
$this->assertEquals(200, $this->response->getStatusCode());
665+
$this->assertTraceContains('fresh');
666+
$this->assertTraceNotContains('store');
667+
$this->assertEquals('Hello World', $this->response->getContent());
668+
669+
// expires the cache
670+
$values = $this->getMetaStorageValues();
671+
$this->assertCount(1, $values);
672+
$tmp = unserialize($values[0]);
673+
$time = \DateTime::createFromFormat('U', time());
674+
$tmp[0][1]['date'] = \DateTime::createFromFormat('U', time() - 5)->format(DATE_RFC2822);
675+
$r = new \ReflectionObject($this->store);
676+
$m = $r->getMethod('save');
677+
$m->setAccessible(true);
678+
$m->invoke($this->store, 'md'.sha1('http://localhost/'), serialize($tmp));
679+
680+
$this->request('GET', '/');
681+
$this->assertHttpKernelIsCalled();
682+
$this->assertEquals(200, $this->response->getStatusCode());
683+
$this->assertTraceContains('stale');
684+
$this->assertTraceContains('valid');
685+
$this->assertTraceContains('store');
686+
$this->assertTraceNotContains('miss');
687+
$this->assertEquals('Hello World', $this->response->getContent());
688+
$this->assertRegExp('/s-maxage=2/', $this->response->headers->get('Cache-Control'));
689+
690+
$this->request('GET', '/');
691+
$this->assertHttpKernelIsNotCalled();
692+
$this->assertEquals(200, $this->response->getStatusCode());
693+
$this->assertTraceContains('fresh');
694+
$this->assertTraceNotContains('store');
695+
$this->assertEquals('Hello World', $this->response->getContent());
696+
$this->assertRegExp('/s-maxage=2/', $this->response->headers->get('Cache-Control'));
596697
}
597698

598699
public function testDoesNotAssignDefaultTtlWhenResponseHasMustRevalidateDirective()

0 commit comments

Comments
 (0)