Implementing RequestHandler::checkNotModified() as a helper for HTTP caching

This commit is contained in:
Jose Lorenzo Rodriguez 2012-01-13 01:36:31 -04:30
parent 8e979cc83e
commit dffe84cfbc
2 changed files with 134 additions and 0 deletions

View file

@ -704,4 +704,33 @@ class RequestHandlerComponent extends Component {
}
$this->_inputTypeMap[$type] = $handler;
}
/**
* Checks whether a response has not been modified according to the 'If-None-Match'
* (Etags) and 'If-Modified-Since' (last modification date) request
* headers headers. If the response is detected to be not modified, it
* is marked as so accordingly so the client can be informed of that.
*
* In order to mark a response as not modified, you need to set at least
* the Last-Modified response header or a response etag to be compared
* with the request itself
*
* @return boolean whether the response was marked as not modified or
* not
**/
public function checkNotModified() {
$etags = preg_split('/\s*,\s*/', $this->request->header('If-None-Match'), null, PREG_SPLIT_NO_EMPTY);
$modifiedSince = $this->request->header('If-Modified-Since');
if ($responseTag = $this->response->etag()) {
$etagMatches = in_array('*', $etags) || in_array($responseTag, $etags);
}
if ($modifiedSince) {
$timeMatches = strtotime($this->response->modified()) == strtotime($modifiedSince);
}
$notModified = (!isset($etagMatches) || $etagMatches) && (!isset($timeMatches) || $timeMatches);
if ($notModified) {
$this->response->notModified();
}
return $notModified;
}
}

View file

@ -823,4 +823,109 @@ class RequestHandlerComponentTest extends CakeTestCase {
public function testAddInputTypeException() {
$this->RequestHandler->addInputType('csv', array('I am not callable'));
}
/**
* Test checkNotModified method
*
* @return void
**/
public function testCheckNotModifiedByEtagStar() {
$_SERVER['HTTP_IF_NONE_MATCH'] = '*';
$RequestHandler = $this->getMock('RequestHandlerComponent', array('_stop'), array(&$this->Controller->Components));
$RequestHandler->response = $this->getMock('CakeResponse', array('notModified'));
$RequestHandler->response->etag('something');
$RequestHandler->response->expects($this->once())->method('notModified');
$RequestHandler->checkNotModified();
}
/**
* Test checkNotModified method
*
* @return void
**/
public function testCheckNotModifiedByEtagExact() {
$_SERVER['HTTP_IF_NONE_MATCH'] = 'W/"something", "other"';
$RequestHandler = $this->getMock('RequestHandlerComponent', array('_stop'), array(&$this->Controller->Components));
$RequestHandler->response = $this->getMock('CakeResponse', array('notModified'));
$RequestHandler->response->etag('something', true);
$RequestHandler->response->expects($this->once())->method('notModified');
$this->assertTrue($RequestHandler->checkNotModified());
}
/**
* Test checkNotModified method
*
* @return void
**/
public function testCheckNotModifiedByEtagAndTime() {
$_SERVER['HTTP_IF_NONE_MATCH'] = 'W/"something", "other"';
$_SERVER['HTTP_IF_MODIFIED_SINCE'] = '2012-01-01 00:00:00';
$RequestHandler = $this->getMock('RequestHandlerComponent', array('_stop'), array(&$this->Controller->Components));
$RequestHandler->response = $this->getMock('CakeResponse', array('notModified'));
$RequestHandler->response->etag('something', true);
$RequestHandler->response->modified('2012-01-01 00:00:00');
$RequestHandler->response->expects($this->once())->method('notModified');
$this->assertTrue($RequestHandler->checkNotModified());
}
/**
* Test checkNotModified method
*
* @return void
**/
public function testCheckNotModifiedByEtagAndTimeMismatch() {
$_SERVER['HTTP_IF_NONE_MATCH'] = 'W/"something", "other"';
$_SERVER['HTTP_IF_MODIFIED_SINCE'] = '2012-01-01 00:00:00';
$RequestHandler = $this->getMock('RequestHandlerComponent', array('_stop'), array(&$this->Controller->Components));
$RequestHandler->response = $this->getMock('CakeResponse', array('notModified'));
$RequestHandler->response->etag('something', true);
$RequestHandler->response->modified('2012-01-01 00:00:01');
$RequestHandler->response->expects($this->never())->method('notModified');
$this->assertFalse($RequestHandler->checkNotModified());
}
/**
* Test checkNotModified method
*
* @return void
**/
public function testCheckNotModifiedByEtagMismatch() {
$_SERVER['HTTP_IF_NONE_MATCH'] = 'W/"something-else", "other"';
$_SERVER['HTTP_IF_MODIFIED_SINCE'] = '2012-01-01 00:00:00';
$RequestHandler = $this->getMock('RequestHandlerComponent', array('_stop'), array(&$this->Controller->Components));
$RequestHandler->response = $this->getMock('CakeResponse', array('notModified'));
$RequestHandler->response->etag('something', true);
$RequestHandler->response->modified('2012-01-01 00:00:00');
$RequestHandler->response->expects($this->never())->method('notModified');
$this->assertFalse($RequestHandler->checkNotModified());
}
/**
* Test checkNotModified method
*
* @return void
**/
public function testCheckNotModifiedByTime() {
$_SERVER['HTTP_IF_MODIFIED_SINCE'] = '2012-01-01 00:00:00';
$RequestHandler = $this->getMock('RequestHandlerComponent', array('_stop'), array(&$this->Controller->Components));
$RequestHandler->response = $this->getMock('CakeResponse', array('notModified'));
$RequestHandler->response->modified('2012-01-01 00:00:00');
$RequestHandler->response->expects($this->once())->method('notModified');
$this->assertTrue($RequestHandler->checkNotModified());
}
/**
* Test checkNotModified method
*
* @return void
**/
public function testCheckNotModifiedNoHints() {
$_SERVER['HTTP_IF_NONE_MATCH'] = 'W/"something", "other"';
$_SERVER['HTTP_IF_MODIFIED_SINCE'] = '2012-01-01 00:00:00';
$RequestHandler = $this->getMock('RequestHandlerComponent', array('_stop'), array(&$this->Controller->Components));
$RequestHandler->response = $this->getMock('CakeResponse', array('notModified'));
$RequestHandler->response->expects($this->never())->method('notModified');
$this->assertFalse($RequestHandler->checkNotModified());
}
}