From 8f8b0de93282ba4124da3b577ed5f96d8210ad18 Mon Sep 17 00:00:00 2001 From: Timo Tijhof Date: Fri, 20 Apr 2018 16:00:32 +0100 Subject: [PATCH] OutputPage: Factor out CdnCacheEpoch logic and cover with tests Bug: T178629 Change-Id: Ife7dd79677c2b5353317e06ac7ed521edd6193cc --- includes/OutputPage.php | 19 +++++++++-- tests/phpunit/includes/OutputPageTest.php | 41 +++++++++++++++++++++++ 2 files changed, 58 insertions(+), 2 deletions(-) diff --git a/includes/OutputPage.php b/includes/OutputPage.php index dd64413fd4..37527cf100 100644 --- a/includes/OutputPage.php +++ b/includes/OutputPage.php @@ -752,8 +752,10 @@ class OutputPage extends ContextSource { 'epoch' => $config->get( 'CacheEpoch' ) ]; if ( $config->get( 'UseSquid' ) ) { - // T46570: the core page itself may not change, but resources might - $modifiedTimes['sepoch'] = wfTimestamp( TS_MW, time() - $config->get( 'SquidMaxage' ) ); + $modifiedTimes['sepoch'] = wfTimestamp( TS_MW, $this->getCdnCacheEpoch( + time(), + $config->get( 'SquidMaxage' ) + ) ); } Hooks::run( 'OutputPageCheckLastModified', [ &$modifiedTimes, $this ] ); @@ -815,6 +817,19 @@ class OutputPage extends ContextSource { return true; } + /** + * @param int $reqTime Time of request (eg. now) + * @param int $maxAge Cache TTL in seconds + * @return int Timestamp + */ + private function getCdnCacheEpoch( $reqTime, $maxAge ) { + // Ensure Last-Modified is never more than (wgSquidMaxage) in the past, + // because even if the wiki page content hasn't changed since, static + // resources may have changed (skin HTML, interface messages, urls, etc.) + // and must roll-over in a timely manner (T46570) + return $reqTime - $maxAge; + } + /** * Override the last modified timestamp * diff --git a/tests/phpunit/includes/OutputPageTest.php b/tests/phpunit/includes/OutputPageTest.php index 81bbcd7ea4..0a657d886f 100644 --- a/tests/phpunit/includes/OutputPageTest.php +++ b/tests/phpunit/includes/OutputPageTest.php @@ -124,6 +124,47 @@ class OutputPageTest extends MediaWikiTestCase { ] ); } + public static function provideCdnCacheEpoch() { + $base = [ + 'pageTime' => '2011-04-01T12:00:00+00:00', + 'maxAge' => 24 * 3600, + ]; + return [ + 'after 1s' => [ $base + [ + 'reqTime' => '2011-04-01T12:00:01+00:00', + 'expect' => '2011-04-01T12:00:00+00:00', + ] ], + 'after 23h' => [ $base + [ + 'reqTime' => '2011-04-02T11:00:00+00:00', + 'expect' => '2011-04-01T12:00:00+00:00', + ] ], + 'after 24h and a bit' => [ $base + [ + 'reqTime' => '2011-04-02T12:34:56+00:00', + 'expect' => '2011-04-01T12:34:56+00:00', + ] ], + 'after a year' => [ $base + [ + 'reqTime' => '2012-05-06T00:12:07+00:00', + 'expect' => '2012-05-05T00:12:07+00:00', + ] ], + ]; + } + + /** + * @dataProvider provideCdnCacheEpoch + */ + public function testCdnCacheEpoch( $params ) { + $out = TestingAccessWrapper::newFromObject( $this->newInstance() ); + $reqTime = strtotime( $params['reqTime'] ); + $pageTime = strtotime( $params['pageTime'] ); + $actual = max( $pageTime, $out->getCdnCacheEpoch( $reqTime, $params['maxAge'] ) ); + + $this->assertEquals( + $params['expect'], + gmdate( DateTime::ATOM, $actual ), + 'cdn epoch' + ); + } + /** * Tests screen requests, without either query parameter set * @covers OutputPage::transformCssMedia -- 2.20.1