Index: includes/common.inc =================================================================== RCS file: /cvs/drupal/drupal/includes/common.inc,v retrieving revision 1.782 diff -u -p -r1.782 common.inc --- includes/common.inc 12 Aug 2008 08:36:38 -0000 1.782 +++ includes/common.inc 12 Aug 2008 21:46:45 -0000 @@ -400,22 +400,36 @@ function drupal_access_denied() { * * @param $url * A string containing a fully qualified URI. - * @param $headers - * An array containing an HTTP header => value pair. - * @param $method - * A string defining the HTTP request to use. - * @param $data - * A string containing data to include in the request. - * @param $retry - * An integer representing how many times to retry the request in case of a - * redirect. + * @param $options + * An associative array of options, with the following keys: + * - 'headers' + * An array containing an HTTP header => value pair. + * - 'method' (default 'GET') + * A string defining the HTTP request to use. + * - 'data' + * A string containing data to include in the request. + * - 'retry' (default 3) + * An integer representing how many times to retry the request + * in case of a redirect. + * - 'timeout' (default 20) + * The number of seconds before the timeout of the request. * @return * An object containing the HTTP request headers, response code, headers, * data and redirect status. */ -function drupal_http_request($url, $headers = array(), $method = 'GET', $data = NULL, $retry = 3) { +function drupal_http_request($url, $options = array()) { global $db_prefix; static $self_test = FALSE; + + // Merge in defaults. + $options += array( + 'headers' => array(), + 'method' => 'GET', + 'data' => NULL, + 'retry' => 3, + 'timeout' => 20, + ); + $result = new stdClass(); // Try to clear the drupal_http_request_fails variable if it's set. We // can't tie this call to any error because there is no surefire way to @@ -450,13 +464,13 @@ function drupal_http_request($url, $head case 'http': $port = isset($uri['port']) ? $uri['port'] : 80; $host = $uri['host'] . ($port != 80 ? ':' . $port : ''); - $fp = @fsockopen($uri['host'], $port, $errno, $errstr, 15); + $fp = @fsockopen($uri['host'], $port, $errno, $errstr, $options['timeout']); break; case 'https': // Note: Only works for PHP 4.3 compiled with OpenSSL. $port = isset($uri['port']) ? $uri['port'] : 443; $host = $uri['host'] . ($port != 443 ? ':' . $port : ''); - $fp = @fsockopen('ssl://' . $uri['host'], $port, $errno, $errstr, 20); + $fp = @fsockopen('ssl://' . $uri['host'], $port, $errno, $errstr, $options['timeout']); break; default: $result->error = 'invalid schema ' . $uri['scheme']; @@ -485,7 +499,7 @@ function drupal_http_request($url, $head // host that do not take into account the port number. 'Host' => "Host: $host", 'User-Agent' => 'User-Agent: Drupal (+http://drupal.org/)', - 'Content-Length' => 'Content-Length: ' . strlen($data) + 'Content-Length' => 'Content-Length: ' . strlen($options['data']) ); // If the server url has a user then attempt to use basic authentication @@ -500,21 +514,24 @@ function drupal_http_request($url, $head // same time won't interfere with each other as they would if the database // prefix were stored statically in a file or database variable. if (preg_match("/^simpletest\d+/", $db_prefix)) { - $headers['User-Agent'] = $db_prefix; + $options['headers']['User-Agent'] = $db_prefix; } - foreach ($headers as $header => $value) { + foreach ($options['headers'] as $header => $value) { $defaults[$header] = $header . ': ' . $value; } - $request = $method . ' ' . $path . " HTTP/1.0\r\n"; + $request = $options['method'] . ' ' . $path . " HTTP/1.0\r\n"; $request .= implode("\r\n", $defaults); $request .= "\r\n\r\n"; - if ($data) { - $request .= $data . "\r\n"; + if ($options['data']) { + $request .= $options['data'] . "\r\n"; } $result->request = $request; + // Set a timeout on the stream + stream_set_timeout($fp, $options['timeout']); + fwrite($fp, $request); // Fetch response. @@ -522,6 +539,14 @@ function drupal_http_request($url, $head while (!feof($fp) && $chunk = fread($fp, 1024)) { $response .= $chunk; } + + // Determine whether the response timed out during read + $response_metadata = stream_get_meta_data($fp); + if (array_key_exists('timed_out', $response_metadata) && $response_metadata['timed_out']) { + $result->error = 'Connection timed out while reading response'; + return $result; + } + fclose($fp); // Parse response. @@ -566,8 +591,9 @@ function drupal_http_request($url, $head case 307: // Moved temporarily $location = $result->headers['Location']; - if ($retry) { - $result = drupal_http_request($result->headers['Location'], $headers, $method, $data, --$retry); + if ($options['retry']) { + $options['retry']--; + $result = drupal_http_request($result->headers['Location'], $options); $result->redirect_code = $result->code; } $result->redirect_url = $location; Index: includes/xmlrpc.inc =================================================================== RCS file: /cvs/drupal/drupal/includes/xmlrpc.inc,v retrieving revision 1.52 diff -u -p -r1.52 xmlrpc.inc --- includes/xmlrpc.inc 8 Aug 2008 20:00:09 -0000 1.52 +++ includes/xmlrpc.inc 12 Aug 2008 21:46:46 -0000 @@ -443,7 +443,7 @@ function _xmlrpc() { $method = array_shift($args); } $xmlrpc_request = xmlrpc_request($method, $args); - $result = drupal_http_request($url, array("Content-Type" => "text/xml"), 'POST', $xmlrpc_request->xml); + $result = drupal_http_request($url, array('headers' => array("Content-Type" => "text/xml"), 'method' => 'POST', 'data' => $xmlrpc_request->xml)); if ($result->code != 200) { xmlrpc_error($result->code, $result->error); return FALSE; Index: modules/aggregator/aggregator.module =================================================================== RCS file: /cvs/drupal/drupal/modules/aggregator/aggregator.module,v retrieving revision 1.388 diff -u -p -r1.388 aggregator.module --- modules/aggregator/aggregator.module 12 Aug 2008 10:42:41 -0000 1.388 +++ modules/aggregator/aggregator.module 12 Aug 2008 21:46:47 -0000 @@ -588,7 +588,7 @@ function aggregator_refresh($feed) { } // Request feed. - $result = drupal_http_request($feed['url'], $headers); + $result = drupal_http_request($feed['url'], array('headers' => $headers)); // Process HTTP response code. switch ($result->code) { Index: modules/openid/openid.module =================================================================== RCS file: /cvs/drupal/drupal/modules/openid/openid.module,v retrieving revision 1.27 diff -u -p -r1.27 openid.module --- modules/openid/openid.module 24 Jul 2008 16:25:18 -0000 1.27 +++ modules/openid/openid.module 12 Aug 2008 21:46:48 -0000 @@ -272,7 +272,7 @@ function openid_discovery($claimed_id) { if ($url['scheme'] == 'http' || $url['scheme'] == 'https') { // For regular URLs, try Yadis resolution first, then HTML-based discovery $headers = array('Accept' => 'application/xrds+xml'); - $result = drupal_http_request($xrds_url, $headers); + $result = drupal_http_request($xrds_url, array('headers' => $headers)); if (!isset($result->error)) { if (isset($result->headers['Content-Type']) && preg_match("/application\/xrds\+xml/", $result->headers['Content-Type'])) { @@ -290,7 +290,7 @@ function openid_discovery($claimed_id) { } if (!empty($xrds_url)) { $headers = array('Accept' => 'application/xrds+xml'); - $xrds_result = drupal_http_request($xrds_url, $headers); + $xrds_result = drupal_http_request($xrds_url, array('headers' => $headers)); if (!isset($xrds_result->error)) { $services = xrds_parse($xrds_result->data); } @@ -348,7 +348,7 @@ function openid_association($op_endpoint $assoc_request = openid_association_request($public); $assoc_message = _openid_encode_message(_openid_create_message($assoc_request)); $assoc_headers = array('Content-Type' => 'application/x-www-form-urlencoded; charset=utf-8'); - $assoc_result = drupal_http_request($op_endpoint, $assoc_headers, 'POST', $assoc_message); + $assoc_result = drupal_http_request($op_endpoint, array('headers' => $assoc_headers, 'method' => 'POST', 'data' => $assoc_message)); if (isset($assoc_result->error)) { module_invoke('system', 'check_http_request'); return FALSE; @@ -510,7 +510,7 @@ function openid_verify_assertion($op_end $request['openid.mode'] = 'check_authentication'; $message = _openid_create_message($request); $headers = array('Content-Type' => 'application/x-www-form-urlencoded; charset=utf-8'); - $result = drupal_http_request($op_endpoint, $headers, 'POST', _openid_encode_message($message)); + $result = drupal_http_request($op_endpoint, array('headers' => $headers, 'method' => 'POST', 'data' => _openid_encode_message($message))); if (!isset($result->error)) { $response = _openid_parse_message($result->data); if (strtolower(trim($response['is_valid'])) == 'true') {