- Patch #330582 by Darren Oh, c960657 et al: better API for retrieving HTTP headers and working with HTTP headers in tests.
parent
71a22f1c1f
commit
99afbc53a7
|
@ -27,6 +27,13 @@ class DrupalWebTestCase {
|
||||||
*/
|
*/
|
||||||
protected $curlHandle;
|
protected $curlHandle;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The headers of the page currently loaded in the internal browser.
|
||||||
|
*
|
||||||
|
* @var Array
|
||||||
|
*/
|
||||||
|
protected $headers;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The content of the page currently loaded in the internal browser.
|
* The content of the page currently loaded in the internal browser.
|
||||||
*
|
*
|
||||||
|
@ -923,6 +930,7 @@ class DrupalWebTestCase {
|
||||||
$this->curlInitialize();
|
$this->curlInitialize();
|
||||||
$url = empty($curl_options[CURLOPT_URL]) ? curl_getinfo($this->curlHandle, CURLINFO_EFFECTIVE_URL) : $curl_options[CURLOPT_URL];
|
$url = empty($curl_options[CURLOPT_URL]) ? curl_getinfo($this->curlHandle, CURLINFO_EFFECTIVE_URL) : $curl_options[CURLOPT_URL];
|
||||||
curl_setopt_array($this->curlHandle, $this->additionalCurlOptions + $curl_options);
|
curl_setopt_array($this->curlHandle, $this->additionalCurlOptions + $curl_options);
|
||||||
|
$this->headers = array();
|
||||||
$this->drupalSetContent(curl_exec($this->curlHandle), curl_getinfo($this->curlHandle, CURLINFO_EFFECTIVE_URL));
|
$this->drupalSetContent(curl_exec($this->curlHandle), curl_getinfo($this->curlHandle, CURLINFO_EFFECTIVE_URL));
|
||||||
$this->assertTrue($this->content !== FALSE, t('!method to !url, response is !length bytes.', array('!method' => !empty($curl_options[CURLOPT_NOBODY]) ? 'HEAD' : (empty($curl_options[CURLOPT_POSTFIELDS]) ? 'GET' : 'POST'), '!url' => $url, '!length' => strlen($this->content))), t('Browser'));
|
$this->assertTrue($this->content !== FALSE, t('!method to !url, response is !length bytes.', array('!method' => !empty($curl_options[CURLOPT_NOBODY]) ? 'HEAD' : (empty($curl_options[CURLOPT_POSTFIELDS]) ? 'GET' : 'POST'), '!url' => $url, '!length' => strlen($this->content))), t('Browser'));
|
||||||
return $this->drupalGetContent();
|
return $this->drupalGetContent();
|
||||||
|
@ -939,6 +947,7 @@ class DrupalWebTestCase {
|
||||||
* An header.
|
* An header.
|
||||||
*/
|
*/
|
||||||
protected function curlHeaderCallback($curlHandler, $header) {
|
protected function curlHeaderCallback($curlHandler, $header) {
|
||||||
|
$this->headers[] = $header;
|
||||||
// Errors are being sent via X-Drupal-Assertion-* headers,
|
// Errors are being sent via X-Drupal-Assertion-* headers,
|
||||||
// generated by _drupal_log_error() in the exact form required
|
// generated by _drupal_log_error() in the exact form required
|
||||||
// by DrupalWebTestCase::error().
|
// by DrupalWebTestCase::error().
|
||||||
|
@ -1001,7 +1010,7 @@ class DrupalWebTestCase {
|
||||||
// We re-using a CURL connection here. If that connection still has certain
|
// 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
|
// options set, it might change the GET into a POST. Make sure we clear out
|
||||||
// previous options.
|
// previous options.
|
||||||
$out = $this->curlExec(array(CURLOPT_HTTPGET => TRUE, CURLOPT_URL => url($path, $options), CURLOPT_HEADER => FALSE, CURLOPT_NOBODY => FALSE));
|
$out = $this->curlExec(array(CURLOPT_HTTPGET => TRUE, CURLOPT_URL => url($path, $options), CURLOPT_NOBODY => FALSE));
|
||||||
$this->refreshVariables(); // Ensure that any changes to variables in the other thread are picked up.
|
$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).
|
// Replace original page output with new output from redirected page(s).
|
||||||
|
@ -1083,7 +1092,7 @@ class DrupalWebTestCase {
|
||||||
}
|
}
|
||||||
$post = implode('&', $post);
|
$post = implode('&', $post);
|
||||||
}
|
}
|
||||||
$out = $this->curlExec(array(CURLOPT_URL => $action, CURLOPT_POST => TRUE, CURLOPT_POSTFIELDS => $post, CURLOPT_HEADER => FALSE));
|
$out = $this->curlExec(array(CURLOPT_URL => $action, CURLOPT_POST => TRUE, CURLOPT_POSTFIELDS => $post));
|
||||||
// Ensure that any changes to variables in the other thread are picked up.
|
// Ensure that any changes to variables in the other thread are picked up.
|
||||||
$this->refreshVariables();
|
$this->refreshVariables();
|
||||||
|
|
||||||
|
@ -1137,7 +1146,7 @@ class DrupalWebTestCase {
|
||||||
*/
|
*/
|
||||||
protected function drupalHead($path, Array $options = array()) {
|
protected function drupalHead($path, Array $options = array()) {
|
||||||
$options['absolute'] = TRUE;
|
$options['absolute'] = TRUE;
|
||||||
$out = $this->curlExec(array(CURLOPT_HEADER => TRUE, CURLOPT_NOBODY => TRUE, CURLOPT_URL => url($path, $options)));
|
$out = $this->curlExec(array(CURLOPT_NOBODY => TRUE, CURLOPT_URL => url($path, $options)));
|
||||||
$this->refreshVariables(); // Ensure that any changes to variables in the other thread are picked up.
|
$this->refreshVariables(); // Ensure that any changes to variables in the other thread are picked up.
|
||||||
return $out;
|
return $out;
|
||||||
}
|
}
|
||||||
|
@ -1420,6 +1429,92 @@ class DrupalWebTestCase {
|
||||||
return $this->url;
|
return $this->url;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the HTTP response headers of the requested page. Normally we are only
|
||||||
|
* interested in the headers returned by the last request. However, if a page
|
||||||
|
* is redirected or HTTP authentication is in use, multiple requests will be
|
||||||
|
* required to retrieve the page. Headers from all requests may be requested
|
||||||
|
* by passing TRUE to this function.
|
||||||
|
*
|
||||||
|
* @param $all_requests
|
||||||
|
* Boolean value specifying whether to return headers from all requests
|
||||||
|
* instead of just the last request. Defaults to FALSE.
|
||||||
|
* @return
|
||||||
|
* A name/value array if headers from only the last request are requested.
|
||||||
|
* If headers from all requests are requested, an array of name/value
|
||||||
|
* arrays, one for each request.
|
||||||
|
*
|
||||||
|
* The pseudonym ":status" is used for the HTTP status line.
|
||||||
|
*
|
||||||
|
* Values for duplicate headers are stored as a single comma-separated list.
|
||||||
|
*/
|
||||||
|
protected function drupalGetHeaders($all_requests = FALSE) {
|
||||||
|
$request = 0;
|
||||||
|
$headers = array($request => array());
|
||||||
|
foreach ($this->headers as $header) {
|
||||||
|
$header = trim($header);
|
||||||
|
if ($header === '') {
|
||||||
|
$request++;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (strpos($header, 'HTTP/') === 0) {
|
||||||
|
$name = ':status';
|
||||||
|
$value = $header;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
list($name, $value) = explode(':', $header, 2);
|
||||||
|
$name = strtolower($name);
|
||||||
|
}
|
||||||
|
if (isset($headers[$request][$name])) {
|
||||||
|
$headers[$request][$name] .= ',' . trim($value);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$headers[$request][$name] = trim($value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!$all_requests) {
|
||||||
|
$headers = array_pop($headers);
|
||||||
|
}
|
||||||
|
return $headers;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the value of an HTTP response header. If multiple requests were
|
||||||
|
* required to retrieve the page, only the headers from the last request will
|
||||||
|
* be checked by default. However, if TRUE is passed as the second argument,
|
||||||
|
* all requests will be processed from last to first until the header is
|
||||||
|
* found.
|
||||||
|
*
|
||||||
|
* @param $name
|
||||||
|
* The name of the header to retrieve. Names are case-insensitive (see RFC
|
||||||
|
* 2616 section 4.2).
|
||||||
|
* @param $all_requests
|
||||||
|
* Boolean value specifying whether to check all requests if the header is
|
||||||
|
* not found in the last request. Defaults to FALSE.
|
||||||
|
* @return
|
||||||
|
* The HTTP header value or FALSE if not found.
|
||||||
|
*/
|
||||||
|
protected function drupalGetHeader($name, $all_requests = FALSE) {
|
||||||
|
$name = strtolower($name);
|
||||||
|
$header = FALSE;
|
||||||
|
if ($all_requests) {
|
||||||
|
foreach (array_reverse($this->drupalGetHeaders(TRUE)) as $headers) {
|
||||||
|
if (isset($headers[$name])) {
|
||||||
|
$header = $headers[$name];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$headers = $this->drupalGetHeaders();
|
||||||
|
if (isset($headers[$name])) {
|
||||||
|
$header = $headers[$name];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $header;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the current raw HTML of requested page.
|
* Gets the current raw HTML of requested page.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -44,6 +44,7 @@ class SimpleTestTestCase extends DrupalWebTestCase {
|
||||||
global $conf;
|
global $conf;
|
||||||
if (!$this->inCURL()) {
|
if (!$this->inCURL()) {
|
||||||
$this->drupalGet('node');
|
$this->drupalGet('node');
|
||||||
|
$this->assertTrue($this->drupalGetHeader('Date'), t('An HTTP header was received.'));
|
||||||
$this->assertTitle(variable_get('site_name', 'Drupal'), t('Site title matches.'));
|
$this->assertTitle(variable_get('site_name', 'Drupal'), t('Site title matches.'));
|
||||||
// Make sure that we are locked out of the installer when prefixing
|
// Make sure that we are locked out of the installer when prefixing
|
||||||
// using the user-agent header. This is an important security check.
|
// using the user-agent header. This is an important security check.
|
||||||
|
@ -51,6 +52,15 @@ class SimpleTestTestCase extends DrupalWebTestCase {
|
||||||
|
|
||||||
$this->drupalGet($base_url . '/install.php', array('external' => TRUE));
|
$this->drupalGet($base_url . '/install.php', array('external' => TRUE));
|
||||||
$this->assertResponse(403, 'Cannot access install.php with a "simpletest" user-agent header.');
|
$this->assertResponse(403, 'Cannot access install.php with a "simpletest" user-agent header.');
|
||||||
|
|
||||||
|
$this->drupalLogin($this->drupalCreateUser());
|
||||||
|
$headers = $this->drupalGetHeaders(TRUE);
|
||||||
|
$this->assertEqual(count($headers), 2, t('There was one intermediate request.'));
|
||||||
|
$this->assertTrue(strpos($headers[0][':status'], '302') !== FALSE, t('Intermediate response code was 302.'));
|
||||||
|
$this->assertFalse(empty($headers[0]['location']), t('Intermediate request contained a Location header.'));
|
||||||
|
$this->assertEqual($this->getUrl(), $headers[0]['location'], t('HTTP redirect was followed'));
|
||||||
|
$this->assertFalse($this->drupalGetHeader('Location'), t('Headers from intermediate request were reset.'));
|
||||||
|
$this->assertResponse(200, t('Response code from intermediate request was reset.'));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -104,7 +104,7 @@ class BootstrapPageCacheTestCase extends DrupalWebTestCase {
|
||||||
$this->drupalGet($base_url);
|
$this->drupalGet($base_url);
|
||||||
|
|
||||||
$this->drupalHead($base_url);
|
$this->drupalHead($base_url);
|
||||||
$this->assertText('ETag: ', t('Verify presence of ETag header indicating that page caching is enabled.'));
|
$this->assertTrue($this->drupalGetHeader('ETag') !== FALSE, t('Verify presence of ETag header indicating that page caching is enabled.'));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,8 +7,6 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
class SessionTestCase extends DrupalWebTestCase {
|
class SessionTestCase extends DrupalWebTestCase {
|
||||||
protected $saved_cookie;
|
|
||||||
|
|
||||||
function getInfo() {
|
function getInfo() {
|
||||||
return array(
|
return array(
|
||||||
'name' => t('Session tests'),
|
'name' => t('Session tests'),
|
||||||
|
@ -21,18 +19,6 @@ class SessionTestCase extends DrupalWebTestCase {
|
||||||
parent::setUp('session_test');
|
parent::setUp('session_test');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Implementation of curlHeaderCallback().
|
|
||||||
*/
|
|
||||||
protected function curlHeaderCallback($ch, $header) {
|
|
||||||
// Look for a Set-Cookie header.
|
|
||||||
if (preg_match('/^Set-Cookie.+$/i', $header, $matches)) {
|
|
||||||
$this->saved_cookie = $header;
|
|
||||||
}
|
|
||||||
|
|
||||||
return parent::curlHeaderCallback($ch, $header);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests for drupal_save_session() and drupal_session_regenerate().
|
* Tests for drupal_save_session() and drupal_session_regenerate().
|
||||||
*/
|
*/
|
||||||
|
@ -49,7 +35,7 @@ class SessionTestCase extends DrupalWebTestCase {
|
||||||
$this->sessionReset($user->uid);
|
$this->sessionReset($user->uid);
|
||||||
// Make sure the session cookie is set as HttpOnly.
|
// Make sure the session cookie is set as HttpOnly.
|
||||||
$this->drupalLogin($user);
|
$this->drupalLogin($user);
|
||||||
$this->assertTrue(preg_match('/HttpOnly/i', $this->saved_cookie), t('Session cookie is set as HttpOnly.'));
|
$this->assertTrue(preg_match('/HttpOnly/i', $this->drupalGetHeader('Set-Cookie', TRUE)), t('Session cookie is set as HttpOnly.'));
|
||||||
$this->drupalLogout();
|
$this->drupalLogout();
|
||||||
// Verify that the session is regenerated if a module calls exit
|
// Verify that the session is regenerated if a module calls exit
|
||||||
// in hook_user_login().
|
// in hook_user_login().
|
||||||
|
|
Loading…
Reference in New Issue