diff --git a/.gitignore b/.gitignore index baff153..875e339 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,5 @@ sites/*/settings*.php # Ignore paths that contain user-generated content. sites/*/files sites/*/private + +sites/ diff --git a/includes/common.inc b/includes/common.inc index 34828e8..ba94fd6 100644 --- a/includes/common.inc +++ b/includes/common.inc @@ -990,9 +990,10 @@ function drupal_http_request($url, array $options = array()) { $response = preg_split("/\r\n|\n|\r/", $response); // Parse the response status line. - list($protocol, $code, $status_message) = explode(' ', trim(array_shift($response)), 3); - $result->protocol = $protocol; - $result->status_message = $status_message; + $response_status_array = _drupal_parse_response_status(trim(array_shift($response))); + $result->protocol = $response_status_array['http_version']; + $result->status_message = $response_status_array['reason_phrase']; + $code = $response_status_array['response_code']; $result->headers = array(); @@ -1083,13 +1084,45 @@ function drupal_http_request($url, array $options = array()) { } break; default: - $result->error = $status_message; + $result->error = $result->status_message; } return $result; } /** + * Split an HTTP response status line into components. + * + * Refactored out of drupal_http_request() so it can be unit tested. + * + * @link http://www.w3.org/Protocols/rfc2616/rfc2616-sec6.html Status line definition @endlink + * + * @param string $respone + * The response status line, e.g. 'HTTP/1.1 500 Internal Server Error' + * + * @return array + * Keyed array containing the component parts. If the response is malformed, + * all possible parts will be extracted. 'reason_phrase' could be empty. + * Possible keys: + * - 'http_version' + * - 'response_code' + * - 'reason_phrase' + */ +function _drupal_parse_response_status($response) { + $response_array = explode(' ', trim($response), 3); + // Set up empty values. + $result = array( + 'reason_phrase' => '', + ); + $result['http_version'] = $response_array[0]; + $result['response_code'] = $response_array[1]; + if (isset($response_array[2])) { + $result['reason_phrase'] = $response_array[2]; + } + return $result; +} + +/** * Helper function for determining hosts excluded from needing a proxy. * * @return diff --git a/modules/simpletest/tests/common.test b/modules/simpletest/tests/common.test index 44eecdc..936fdf5 100644 --- a/modules/simpletest/tests/common.test +++ b/modules/simpletest/tests/common.test @@ -1083,6 +1083,76 @@ class DrupalHTTPRequestTestCase extends DrupalWebTestCase { } /** + * Tests parsing of the HTTP response status line. + * + * @see _drupal_parse_response_status() + */ +class DrupalHTTPResponseStatusLineTest extends DrupalUnitTestCase { + public static function getInfo() { + return array( + 'name' => '_drupal_parse_response_status()', + 'description' => 'Perform unit tests on _drupal_parse_response_status()', + 'group' => 'System', + ); + } + + /** + * Tests parsing HTTP response status line. + */ + public function testStatusLine() { + // Grab the big array of test data from statusLineData(). + $data = $this->statusLineData(); + foreach($data as $test_case) { + $test_data = array_shift($test_case); + $expected = array_shift($test_case); + + $outcome = _drupal_parse_response_status($test_data); + + foreach(array_keys($expected) as $key) { + $this->assertIdentical($outcome[$key], $expected[$key]); + } + } + } + + /** + * Data provider for testStatusLine(). + * + * @return array + * Test data. + */ + protected function statusLineData() { + return array( + array( + 'HTTP/1.1 200 OK', + array( + 'http_version' => 'HTTP/1.1', + 'response_code' => '200', + 'reason_phrase' => 'OK', + ), + ), + // Data set with no reason phrase. + array( + 'HTTP/1.1 200', + array( + 'http_version' => 'HTTP/1.1', + 'response_code' => '200', + 'reason_phrase' => '', + ), + ), + // Arbitrary strings. + array( + 'version code multi word explanation', + array( + 'http_version' => 'version', + 'response_code' => 'code', + 'reason_phrase' => 'multi word explanation', + ), + ), + ); + } +} + +/** * Testing drupal_add_region_content and drupal_get_region_content. */ class DrupalSetContentTestCase extends DrupalWebTestCase {