ソースを参照

Fixing a couple bugs in CakeResponse::checkNotModified() and implementing conditional rendering in
RequestHandlerComponent

Jose Lorenzo Rodriguez 14 年 前
コミット
979f7a28b5

+ 19 - 1
lib/Cake/Controller/Component/RequestHandlerComponent.php

@@ -95,7 +95,8 @@ class RequestHandlerComponent extends Component {
  * @param array $settings Array of settings.
  */
 	public function __construct(ComponentCollection $collection, $settings = array()) {
-		parent::__construct($collection, $settings);
+		$default = array('checkHttpCache' => true);
+		parent::__construct($collection, $settings + $default);
 		$this->addInputType('xml', array(array($this, 'convertXml')));
 
 		$Controller = $collection->getController();
@@ -241,6 +242,23 @@ class RequestHandlerComponent extends Component {
 	}
 
 /**
+ * Checks if the response can be considered different according to the request
+ * headers, and the caching response headers. If it was not modified, then the
+ * render process is skipped. And the client will get a blank response with a
+ * "304 Not Modified" header.
+ *
+ * @params Controller $controller
+ * @return boolean false if the render process should be aborted
+ **/
+	public function beforeRender($controller) {
+		$shouldCheck = $this->settings['checkHttpCache'];
+		if ($shouldCheck && $this->response->checkNotModified($this->request)) {
+			$this->response->send();
+			return false;
+		}
+	}
+
+/**
  * Returns true if the current HTTP request is Ajax, false otherwise
  *
  * @return boolean True if call is Ajax

+ 5 - 1
lib/Cake/Network/CakeResponse.php

@@ -1034,7 +1034,11 @@ class CakeResponse {
 		if ($modifiedSince) {
 			$timeMatches = strtotime($this->modified()) == strtotime($modifiedSince);
 		}
-		$notModified = (!isset($etagMatches) || $etagMatches) && (!isset($timeMatches) || $timeMatches);
+		$checks = compact('etagMatches', 'timeMatches');
+		if (empty($checks)) {
+			return false;
+		}
+		$notModified = !in_array(false, $checks, true);
 		if ($notModified) {
 			$this->notModified();
 		}

+ 55 - 0
lib/Cake/Test/Case/Controller/Component/RequestHandlerComponentTest.php

@@ -824,4 +824,59 @@ class RequestHandlerComponentTest extends CakeTestCase {
 		$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');
+		$this->assertFalse($RequestHandler->beforeRender($this->Controller));
+	}
+
+/**
+ * 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->assertFalse($RequestHandler->beforeRender($this->Controller));
+	}
+
+/**
+ * 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->assertFalse($RequestHandler->beforeRender($this->Controller));
+	}
+
+/**
+ * Test checkNotModified method
+ *
+ * @return void
+ **/
+	public function testCheckNotModifiedNoInfo() {
+		$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->assertNull($RequestHandler->beforeRender($this->Controller));
+	}
 }