summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--includes/common.inc46
1 files changed, 38 insertions, 8 deletions
diff --git a/includes/common.inc b/includes/common.inc
index e7515f5..58fe6ae 100644
--- a/includes/common.inc
+++ b/includes/common.inc
@@ -31,6 +31,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
@@ -435,11 +441,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, protocol,
* status message, 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.0) {
global $db_prefix;
$result = new stdClass();
@@ -459,18 +469,20 @@ function drupal_http_request($url, $headers = array(), $method = 'GET', $data =
return $result;
}
+ timer_start(__FUNCTION__);
+
switch ($uri['scheme']) {
case 'http':
case 'feed':
$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'];
@@ -544,11 +556,25 @@ function drupal_http_request($url, $headers = array(), $method = 'GET', $data =
$result->request = $request;
- fwrite($fp, $request);
+ // Calculate how much time is left of the original timeout value.
+ $time_left = $timeout - timer_read(__FUNCTION__) / 1000;
+ if ($time_left > 0) {
+ stream_set_timeout($fp, floor($time_left), floor(1000000 * fmod($time_left, 1)));
+ fwrite($fp, $request);
+ }
// 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);
@@ -597,9 +623,13 @@ function drupal_http_request($url, $headers = array(), $method = 'GET', $data =
case 302: // Moved temporarily
case 307: // Moved temporarily
$location = $result->headers['Location'];
-
- if ($retry) {
- $result = drupal_http_request($result->headers['Location'], $headers, $method, $data, --$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, $timeout);
$result->redirect_code = $result->code;
}
$result->redirect_url = $location;