diff --git includes/common.inc includes/common.inc index 0f67417..866a94d 100644 --- includes/common.inc +++ includes/common.inc @@ -741,6 +741,8 @@ function drupal_access_denied() { * 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. + * - context + * A context resource created with stream_context_create(). * @return * An object which can have one or more of the following parameters: * - request @@ -794,20 +796,24 @@ function drupal_http_request($url, array $options = array()) { 'data' => NULL, 'max_redirects' => 3, 'timeout' => 30, + 'context' => NULL, ); switch ($uri['scheme']) { case 'http': case 'feed': + $transport = 'tcp://'; $port = isset($uri['port']) ? $uri['port'] : 80; - $host = $uri['host'] . ($port != 80 ? ':' . $port : ''); - $fp = @fsockopen($uri['host'], $port, $errno, $errstr, $options['timeout']); + // RFC 2616: "non-standard ports MUST, default ports MAY be included". + // We don't add the standard port to prevent from breaking rewrite rules + // checking the host that do not take into account the port number. + $options['headers']['Host'] = $uri['host'] . ($port != 80 ? ':' . $port : ''); break; case 'https': // Note: Only works when PHP is compiled with OpenSSL support. + $transport = 'ssl://'; $port = isset($uri['port']) ? $uri['port'] : 443; - $host = $uri['host'] . ($port != 443 ? ':' . $port : ''); - $fp = @fsockopen('ssl://' . $uri['host'], $port, $errno, $errstr, $options['timeout']); + $options['headers']['Host'] = $uri['host'] . ($port != 443 ? ':' . $port : ''); break; default: $result->error = 'invalid schema ' . $uri['scheme']; @@ -815,12 +821,20 @@ function drupal_http_request($url, array $options = array()) { return $result; } + if (empty($options['context'])) { + $fp = @stream_socket_client($transport . $uri['host'], $port, $errno, $errstr, $options['timeout']); + } + else { + // Create a stream with context. Allows verification of a SSL certificate. + $fp = @stream_socket_client($transport . $uri['host'], $port, $errno, $errstr, $options['timeout'], STREAM_CLIENT_CONNECT, $options['context']); + } + // Make sure the socket opened properly. if (!$fp) { // When a network error occurs, we use a negative number so it does not // clash with the HTTP status codes. $result->code = -$errno; - $result->error = trim($errstr); + $result->error = trim($errstr) ? trim($errstr) : t('Error opening socket @socket', array('@socket' => $transport . $uri['host'] . ':' . $port)); // Mark that this request failed. This will trigger a check of the web // server's ability to make outgoing HTTP requests the next time that @@ -842,11 +856,6 @@ function drupal_http_request($url, array $options = array()) { 'User-Agent' => 'Drupal (+http://drupal.org/)', ); - // RFC 2616: "non-standard ports MUST, default ports MAY be included". - // We don't add the standard port to prevent from breaking rewrite rules - // checking the host that do not take into account the port number. - $options['headers']['Host'] = $host; - // Only add Content-Length if we actually have any content or if it is a POST // or PUT request. Some non-standard servers get confused by Content-Length in // at least HEAD/GET requests, and Squid always requires Content-Length in @@ -877,8 +886,12 @@ function drupal_http_request($url, array $options = array()) { } $request .= "\r\n" . $options['data']; $result->request = $request; - - fwrite($fp, $request); + // Calculate how much time is left of the original timeout value. + $timeout = $options['timeout'] - timer_read(__FUNCTION__) / 1000; + if ($timeout > 0) { + stream_set_timeout($fp, floor($timeout), floor(1000000 * fmod($timeout, 1))); + fwrite($fp, $request); + } // Fetch response. Due to PHP bugs like http://bugs.php.net/bug.php?id=43782 // and http://bugs.php.net/bug.php?id=46049 we can't rely on feof(), but