Created
February 22, 2012 15:56
-
-
Save nfreear/1885672 to your computer and use it in GitHub Desktop.
Drupal 6.24+ OU proxy fix: drupal_http_request() function, lines 452-644 / nfreear / IET-at-OU
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| function drupal_http_request($url, $headers = array(), $method = 'GET', $data = NULL, $retry = 3, $timeout = 30.0) { | |
| global $db_prefix; | |
| $result = new stdClass(); | |
| // Parse the URL and make sure we can handle the schema. | |
| $uri = parse_url($url); | |
| if ($uri == FALSE) { | |
| $result->error = 'unable to parse URL'; | |
| $result->code = -1001; | |
| return $result; | |
| } | |
| if (!isset($uri['scheme'])) { | |
| $result->error = 'missing schema'; | |
| $result->code = -1002; | |
| 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); | |
| // LGH Patch to make Drupal work with OU Proxy - see http://www.drupal.org/node/7881 | |
| $fp = @fsockopen("wwwcache.open.ac.uk", "80", $errno, $errstr, 15); | |
| 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, $timeout); | |
| break; | |
| default: | |
| $result->error = 'invalid schema '. $uri['scheme']; | |
| $result->code = -1003; | |
| return $result; | |
| } | |
| // 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); | |
| // 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 | |
| // requirements checking is performed. | |
| // @see system_requirements() | |
| variable_set('drupal_http_request_fails', TRUE); | |
| return $result; | |
| } | |
| // Construct the path to act on. | |
| $path = isset($uri['path']) ? $uri['path'] : '/'; | |
| if (isset($uri['query'])) { | |
| $path .= '?'. $uri['query']; | |
| } | |
| // Create HTTP request. | |
| $defaults = array( | |
| // RFC 2616: "non-standard ports MUST, default ports MAY be included". | |
| // We don't add the port to prevent from breaking rewrite rules checking the | |
| // host that do not take into account the port number. | |
| 'Host' => "Host: $host", | |
| 'User-Agent' => 'User-Agent: Drupal (+http://drupal.org/)', | |
| 'Connection' => 'Connection: close', // ISPOTCHANGE RG 16/08/11 added to allow HTTP/1.1 to be used with the new OU proxy | |
| ); | |
| // 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 | |
| // POST/PUT requests. | |
| $content_length = strlen($data); | |
| if ($content_length > 0 || $method == 'POST' || $method == 'PUT') { | |
| $defaults['Content-Length'] = 'Content-Length: '. $content_length; | |
| } | |
| // If the server url has a user then attempt to use basic authentication | |
| if (isset($uri['user'])) { | |
| $defaults['Authorization'] = 'Authorization: Basic '. base64_encode($uri['user'] . (!empty($uri['pass']) ? ":". $uri['pass'] : '')); | |
| } | |
| // If the database prefix is being used by SimpleTest to run the tests in a copied | |
| // database then set the user-agent header to the database prefix so that any | |
| // calls to other Drupal pages will run the SimpleTest prefixed database. The | |
| // user-agent is used to ensure that multiple testing sessions running at the | |
| // 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 (is_string($db_prefix) && preg_match("/^simpletest\d+$/", $db_prefix, $matches)) { | |
| $defaults['User-Agent'] = 'User-Agent: ' . $matches[0]; | |
| } | |
| foreach ($headers as $header => $value) { | |
| $defaults[$header] = $header .': '. $value; | |
| } | |
| // LGH Patch to make Drupal work with OU proxy - see http://www.drupal.org/node.7881 | |
| // $request = $method .' '. $path ." HTTP/1.0\r\n"; | |
| $request = $method.' '.$uri['scheme']."://".$uri['host'].$path." HTTP/1.1\r\n"; | |
| $request .= implode("\r\n", $defaults); | |
| $request .= "\r\n\r\n"; | |
| $request .= $data; | |
| $result->request = $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)) { | |
| // 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); | |
| // Parse response. | |
| list($split, $result->data) = explode("\r\n\r\n", $response, 2); | |
| $split = preg_split("/\r\n|\n|\r/", $split); | |
| list($protocol, $code, $status_message) = explode(' ', trim(array_shift($split)), 3); | |
| $result->protocol = $protocol; | |
| $result->status_message = $status_message; | |
| $result->headers = array(); | |
| // Parse headers. | |
| while ($line = trim(array_shift($split))) { | |
| list($header, $value) = explode(':', $line, 2); | |
| if (isset($result->headers[$header]) && $header == 'Set-Cookie') { | |
| // RFC 2109: the Set-Cookie response header comprises the token Set- | |
| // Cookie:, followed by a comma-separated list of one or more cookies. | |
| $result->headers[$header] .= ','. trim($value); | |
| } | |
| else { | |
| $result->headers[$header] = trim($value); | |
| } | |
| } | |
| $responses = array( | |
| 100 => 'Continue', 101 => 'Switching Protocols', | |
| 200 => 'OK', 201 => 'Created', 202 => 'Accepted', 203 => 'Non-Authoritative Information', 204 => 'No Content', 205 => 'Reset Content', 206 => 'Partial Content', | |
| 300 => 'Multiple Choices', 301 => 'Moved Permanently', 302 => 'Found', 303 => 'See Other', 304 => 'Not Modified', 305 => 'Use Proxy', 307 => 'Temporary Redirect', | |
| 400 => 'Bad Request', 401 => 'Unauthorized', 402 => 'Payment Required', 403 => 'Forbidden', 404 => 'Not Found', 405 => 'Method Not Allowed', 406 => 'Not Acceptable', 407 => 'Proxy Authentication Required', 408 => 'Request Time-out', 409 => 'Conflict', 410 => 'Gone', 411 => 'Length Required', 412 => 'Precondition Failed', 413 => 'Request Entity Too Large', 414 => 'Request-URI Too Large', 415 => 'Unsupported Media Type', 416 => 'Requested range not satisfiable', 417 => 'Expectation Failed', | |
| 500 => 'Internal Server Error', 501 => 'Not Implemented', 502 => 'Bad Gateway', 503 => 'Service Unavailable', 504 => 'Gateway Time-out', 505 => 'HTTP Version not supported' | |
| ); | |
| // RFC 2616 states that all unknown HTTP codes must be treated the same as the | |
| // base code in their class. | |
| if (!isset($responses[$code])) { | |
| $code = floor($code / 100) * 100; | |
| } | |
| switch ($code) { | |
| case 200: // OK | |
| case 304: // Not modified | |
| break; | |
| case 301: // Moved permanently | |
| case 302: // Moved temporarily | |
| case 307: // Moved temporarily | |
| $location = $result->headers['Location']; | |
| $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; | |
| break; | |
| default: | |
| $result->error = $status_message; | |
| } | |
| $result->code = $code; | |
| return $result; | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment