Index: includes/common.inc =================================================================== RCS file: /cvs/drupal/drupal/includes/common.inc,v retrieving revision 1.917 diff -u -9 -p -r1.917 common.inc --- includes/common.inc 3 Jun 2009 02:50:21 -0000 1.917 +++ includes/common.inc 6 Jun 2009 12:00:49 -0000 @@ -32,6 +32,12 @@ if (!defined('E_DEPRECATED')) { } /** + * Error code indicating that the request made by drupal_http_request() exceeded + * the specified timeout. + */ +define('HTTP_REQUEST_TIMEOUT', 1); + +/** * Set content for a specified region. * * @param $region @@ -436,11 +442,15 @@ function drupal_access_denied() { * @param $retry * An integer representing how many times to retry the request in case of a * redirect. + * @param $timeout + * A float representing the maximum number of seconds the function call may + * take. The default is 30 seconds. If a timeout occurs, the error code is set + * to the HTTP_REQUEST_TIMEOUT constant. * @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, $headers = array(), $method = 'GET', $data = NULL, $retry = 3, $timeout = 30) { global $db_prefix; $result = new stdClass(); @@ -460,17 +470,19 @@ function drupal_http_request($url, $head return $result; } + timer_start(__FUNCTION__); + switch ($uri['scheme']) { 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, $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, $timeout); break; default: $result->error = 'invalid schema '. $uri['scheme']; @@ -548,7 +560,16 @@ function drupal_http_request($url, $head // Fetch response. $response = ''; - while (!feof($fp) && $chunk = fread($fp, 1024)) { + while (!feof($fp)) { + // Calculate how much time is left of the original timeout value. + $time_left = $timeout - timer_read(__FUNCTION__) / 1000; + if ($time_left <= 0) { + $result->code = HTTP_REQUEST_TIMEOUT; + $result->error = 'request timed out'; + return $result; + } + stream_set_timeout($fp, floor($time_left), floor(1000000 * fmod($time_left, 1))); + $chunk = fread($fp, 1024); $response .= $chunk; } fclose($fp); @@ -594,8 +615,12 @@ function drupal_http_request($url, $head case 302: // Moved temporarily case 307: // Moved temporarily $location = $result->headers['Location']; - - if ($retry) { + $timeout -= timer_read(__FUNCTION__) / 1000; + if ($timeout <= 0) { + $result->code = HTTP_REQUEST_TIMEOUT; + $result->error = 'request timed out'; + } + elseif ($retry) { $result = drupal_http_request($result->headers['Location'], $headers, $method, $data, --$retry); $result->redirect_code = $result->code; }