diff options
-rw-r--r-- | includes/bootstrap.inc | 13 | ||||
-rw-r--r-- | modules/simpletest/drupal_web_test_case.php | 21 | ||||
-rw-r--r-- | modules/simpletest/tests/bootstrap.test | 37 |
3 files changed, 52 insertions, 19 deletions
diff --git a/includes/bootstrap.inc b/includes/bootstrap.inc index 59fb3f039..1f3db1aa3 100644 --- a/includes/bootstrap.inc +++ b/includes/bootstrap.inc @@ -730,17 +730,16 @@ function drupal_page_header() { * */ function drupal_page_cache_header($cache) { - // Set default values: - $last_modified = gmdate('D, d M Y H:i:s', $cache->created) . ' GMT'; - $etag = '"' . md5($last_modified) . '"'; + // Create entity tag based on cache update time. + $etag = '"' . md5($cache->created) . '"'; - // See if the client has provided the required HTTP headers: - $if_modified_since = isset($_SERVER['HTTP_IF_MODIFIED_SINCE']) ? stripslashes($_SERVER['HTTP_IF_MODIFIED_SINCE']) : FALSE; + // See if the client has provided the required HTTP headers. + $if_modified_since = isset($_SERVER['HTTP_IF_MODIFIED_SINCE']) ? strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE']) : FALSE; $if_none_match = isset($_SERVER['HTTP_IF_NONE_MATCH']) ? stripslashes($_SERVER['HTTP_IF_NONE_MATCH']) : FALSE; if ($if_modified_since && $if_none_match && $if_none_match == $etag // etag must match - && $if_modified_since == $last_modified) { // if-modified-since must match + && $if_modified_since == $cache->created) { // if-modified-since must match header($_SERVER['SERVER_PROTOCOL'] . ' 304 Not Modified'); // All 304 responses must send an etag if the 200 response for the same object contained an etag header("Etag: $etag"); @@ -748,7 +747,7 @@ function drupal_page_cache_header($cache) { } // Send appropriate response: - header("Last-Modified: $last_modified"); + header("Last-Modified: " . gmdate(DATE_RFC1123, $cache->created)); header("ETag: $etag"); // The following headers force validation of cache: diff --git a/modules/simpletest/drupal_web_test_case.php b/modules/simpletest/drupal_web_test_case.php index 6ebf9d8df..b0f2e9f40 100644 --- a/modules/simpletest/drupal_web_test_case.php +++ b/modules/simpletest/drupal_web_test_case.php @@ -1001,16 +1001,19 @@ class DrupalWebTestCase { * Drupal path or URL to load into internal browser * @param $options * Options to be forwarded to url(). + * @param $headers + * An array containing additional HTTP request headers, each formatted as + * "name: value". * @return * The retrieved HTML string, also available as $this->drupalGetContent() */ - protected function drupalGet($path, $options = array()) { + protected function drupalGet($path, Array $options = array(), Array $headers = array()) { $options['absolute'] = TRUE; // We re-using a CURL connection here. If that connection still has certain // options set, it might change the GET into a POST. Make sure we clear out // previous options. - $out = $this->curlExec(array(CURLOPT_HTTPGET => TRUE, CURLOPT_URL => url($path, $options), CURLOPT_NOBODY => FALSE)); + $out = $this->curlExec(array(CURLOPT_HTTPGET => TRUE, CURLOPT_URL => url($path, $options), CURLOPT_NOBODY => FALSE, CURLOPT_HTTPHEADER => $headers)); $this->refreshVariables(); // Ensure that any changes to variables in the other thread are picked up. // Replace original page output with new output from redirected page(s). @@ -1051,8 +1054,11 @@ class DrupalWebTestCase { * Value of the submit button. * @param $options * Options to be forwarded to url(). + * @param $headers + * An array containing additional HTTP request headers, each formatted as + * "name: value". */ - protected function drupalPost($path, $edit, $submit, $options = array()) { + protected function drupalPost($path, $edit, $submit, Array $options = array(), Array $headers = array()) { $submit_matches = FALSE; if (isset($path)) { $html = $this->drupalGet($path, $options); @@ -1092,7 +1098,7 @@ class DrupalWebTestCase { } $post = implode('&', $post); } - $out = $this->curlExec(array(CURLOPT_URL => $action, CURLOPT_POST => TRUE, CURLOPT_POSTFIELDS => $post)); + $out = $this->curlExec(array(CURLOPT_URL => $action, CURLOPT_POST => TRUE, CURLOPT_POSTFIELDS => $post, CURLOPT_HTTPHEADER => $headers)); // Ensure that any changes to variables in the other thread are picked up. $this->refreshVariables(); @@ -1141,12 +1147,15 @@ class DrupalWebTestCase { * Drupal path or URL to load into internal browser * @param $options * Options to be forwarded to url(). + * @param $headers + * An array containing additional HTTP request headers, each formatted as + * "name: value". * @return * The retrieved headers, also available as $this->drupalGetContent() */ - protected function drupalHead($path, Array $options = array()) { + protected function drupalHead($path, Array $options = array(), Array $headers = array()) { $options['absolute'] = TRUE; - $out = $this->curlExec(array(CURLOPT_NOBODY => TRUE, CURLOPT_URL => url($path, $options))); + $out = $this->curlExec(array(CURLOPT_NOBODY => TRUE, CURLOPT_URL => url($path, $options), CURLOPT_HTTPHEADER => $headers)); $this->refreshVariables(); // Ensure that any changes to variables in the other thread are picked up. return $out; } diff --git a/modules/simpletest/tests/bootstrap.test b/modules/simpletest/tests/bootstrap.test index ec5a598d8..29191eeaf 100644 --- a/modules/simpletest/tests/bootstrap.test +++ b/modules/simpletest/tests/bootstrap.test @@ -89,7 +89,7 @@ class BootstrapPageCacheTestCase extends DrupalWebTestCase { function getInfo() { return array( 'name' => t('Page cache test'), - 'description' => t('Enable the page cache, submit a HEAD request and examine headers.'), + 'description' => t('Enable the page cache and test it with conditional HTTP requests.'), 'group' => t('Bootstrap') ); } @@ -98,13 +98,38 @@ class BootstrapPageCacheTestCase extends DrupalWebTestCase { * Enable cache and examine HTTP headers. */ function testPageCache() { - global $base_url; - variable_set('cache', 1); + variable_set('cache', CACHE_NORMAL); + // Fill the cache. - $this->drupalGet($base_url); + $this->drupalGet(''); + + $this->drupalHead(''); + $etag = $this->drupalGetHeader('ETag'); + $this->assertTrue($etag, t('An ETag header was sent, indicating that page was cached.')); + $last_modified = $this->drupalGetHeader('Last-Modified'); + + $this->drupalGet('', array(), array('If-Modified-Since: ' . $last_modified, 'If-None-Match: ' . $etag)); + $this->assertResponse(304, t('Conditional request returned 304 Not Modified.')); + + $this->drupalGet('', array(), array('If-Modified-Since: ' . gmdate(DATE_RFC822, strtotime($last_modified)), 'If-None-Match: ' . $etag)); + $this->assertResponse(304, t('Conditional request with obsolete If-Modified-Since date returned 304 Not Modified.')); + + $this->drupalGet('', array(), array('If-Modified-Since: ' . gmdate(DATE_RFC850, strtotime($last_modified)), 'If-None-Match: ' . $etag)); + $this->assertResponse(304, t('Conditional request with obsolete If-Modified-Since date returned 304 Not Modified.')); + + $this->drupalGet('', array(), array('If-Modified-Since: ' . $last_modified)); + $this->assertResponse(200, t('Conditional request without If-None-Match returned 200 OK.')); + $this->assertTrue($this->drupalGetHeader('ETag'), t('An ETag header was sent, indicating that page was cached.')); + + $this->drupalGet('', array(), array('If-Modified-Since: ' . gmdate(DATE_RFC1123, strtotime($last_modified) + 1), 'If-None-Match: ' . $etag)); + $this->assertResponse(200, t('Conditional request with new a If-Modified-Since date newer than Last-Modified returned 200 OK.')); + $this->assertTrue($this->drupalGetHeader('ETag'), t('An ETag header was sent, indicating that page was cached.')); - $this->drupalHead($base_url); - $this->assertTrue($this->drupalGetHeader('ETag') !== FALSE, t('Verify presence of ETag header indicating that page caching is enabled.')); + $user = $this->drupalCreateUser(); + $this->drupalLogin($user); + $this->drupalGet('', array(), array('If-Modified-Since: ' . $last_modified, 'If-None-Match: ' . $etag)); + $this->assertResponse(200, t('Conditional request returned 200 OK for authenticated user.')); + $this->assertFalse($this->drupalGetHeader('ETag'), t('An ETag header was not sent, indicating that page was not cached.')); } } |