/** * Handles HTTP Redirects and follows them if appropriate. * * @since 3.7.0 * * @static * * @param string $url The URL which was requested. * @param array $args The Arguments which were used to make the request. * @param array $response The Response of the HTTP request. * @return false|object False if no redirect is present, a WP_HTTP or WP_Error result otherwise. */ public static function handle_redirects($url, $args, $response) { // If no redirects are present, or, redirects were not requested, perform no action. if (!isset($response['headers']['location']) || 0 === $args['_redirection']) { return false; } // Only perform redirections on redirection http codes. if ($response['response']['code'] > 399 || $response['response']['code'] < 300) { return false; } // Don't redirect if we've run out of redirects. if ($args['redirection']-- <= 0) { return new WP_Error('http_request_failed', __('Too many redirects.')); } $redirect_location = $response['headers']['location']; // If there were multiple Location headers, use the last header specified. if (is_array($redirect_location)) { $redirect_location = array_pop($redirect_location); } $redirect_location = WP_Http::make_absolute_url($redirect_location, $url); // POST requests should not POST to a redirected location. if ('POST' == $args['method']) { if (in_array($response['response']['code'], array(302, 303))) { $args['method'] = 'GET'; } } // Include valid cookies in the redirect process. if (!empty($response['cookies'])) { foreach ($response['cookies'] as $cookie) { if ($cookie->test($redirect_location)) { $args['cookies'][] = $cookie; } } } return wp_remote_request($redirect_location, $args); }
/** * Send a HTTP request to a URI using cURL extension. * * @access public * @since 2.7.0 * * @param string $url The request URL. * @param string|array $args Optional. Override the defaults. * @return array|WP_Error Array containing 'headers', 'body', 'response', 'cookies', 'filename'. A WP_Error instance upon error */ public function request($url, $args = array()) { $defaults = array('method' => 'GET', 'timeout' => 5, 'redirection' => 5, 'httpversion' => '1.0', 'blocking' => true, 'headers' => array(), 'body' => null, 'cookies' => array()); $r = wp_parse_args($args, $defaults); if (isset($r['headers']['User-Agent'])) { $r['user-agent'] = $r['headers']['User-Agent']; unset($r['headers']['User-Agent']); } elseif (isset($r['headers']['user-agent'])) { $r['user-agent'] = $r['headers']['user-agent']; unset($r['headers']['user-agent']); } // Construct Cookie: header if any cookies are set. WP_Http::buildCookieHeader($r); $handle = curl_init(); // cURL offers really easy proxy support. $proxy = new WP_HTTP_Proxy(); if ($proxy->is_enabled() && $proxy->send_through_proxy($url)) { curl_setopt($handle, CURLOPT_PROXYTYPE, CURLPROXY_HTTP); curl_setopt($handle, CURLOPT_PROXY, $proxy->host()); curl_setopt($handle, CURLOPT_PROXYPORT, $proxy->port()); if ($proxy->use_authentication()) { curl_setopt($handle, CURLOPT_PROXYAUTH, CURLAUTH_ANY); curl_setopt($handle, CURLOPT_PROXYUSERPWD, $proxy->authentication()); } } $is_local = isset($r['local']) && $r['local']; $ssl_verify = isset($r['sslverify']) && $r['sslverify']; if ($is_local) { /** This filter is documented in wp-includes/class-wp-http-streams.php */ $ssl_verify = apply_filters('https_local_ssl_verify', $ssl_verify); } elseif (!$is_local) { /** This filter is documented in wp-includes/class-wp-http-streams.php */ $ssl_verify = apply_filters('https_ssl_verify', $ssl_verify); } /* * CURLOPT_TIMEOUT and CURLOPT_CONNECTTIMEOUT expect integers. Have to use ceil since. * a value of 0 will allow an unlimited timeout. */ $timeout = (int) ceil($r['timeout']); curl_setopt($handle, CURLOPT_CONNECTTIMEOUT, $timeout); curl_setopt($handle, CURLOPT_TIMEOUT, $timeout); curl_setopt($handle, CURLOPT_URL, $url); curl_setopt($handle, CURLOPT_RETURNTRANSFER, true); curl_setopt($handle, CURLOPT_SSL_VERIFYHOST, $ssl_verify === true ? 2 : false); curl_setopt($handle, CURLOPT_SSL_VERIFYPEER, $ssl_verify); if ($ssl_verify) { curl_setopt($handle, CURLOPT_CAINFO, $r['sslcertificates']); } curl_setopt($handle, CURLOPT_USERAGENT, $r['user-agent']); /* * The option doesn't work with safe mode or when open_basedir is set, and there's * a bug #17490 with redirected POST requests, so handle redirections outside Curl. */ curl_setopt($handle, CURLOPT_FOLLOWLOCATION, false); if (defined('CURLOPT_PROTOCOLS')) { // PHP 5.2.10 / cURL 7.19.4 curl_setopt($handle, CURLOPT_PROTOCOLS, CURLPROTO_HTTP | CURLPROTO_HTTPS); } switch ($r['method']) { case 'HEAD': curl_setopt($handle, CURLOPT_NOBODY, true); break; case 'POST': curl_setopt($handle, CURLOPT_POST, true); curl_setopt($handle, CURLOPT_POSTFIELDS, $r['body']); break; case 'PUT': curl_setopt($handle, CURLOPT_CUSTOMREQUEST, 'PUT'); curl_setopt($handle, CURLOPT_POSTFIELDS, $r['body']); break; default: curl_setopt($handle, CURLOPT_CUSTOMREQUEST, $r['method']); if (!is_null($r['body'])) { curl_setopt($handle, CURLOPT_POSTFIELDS, $r['body']); } break; } if (true === $r['blocking']) { curl_setopt($handle, CURLOPT_HEADERFUNCTION, array($this, 'stream_headers')); curl_setopt($handle, CURLOPT_WRITEFUNCTION, array($this, 'stream_body')); } curl_setopt($handle, CURLOPT_HEADER, false); if (isset($r['limit_response_size'])) { $this->max_body_length = intval($r['limit_response_size']); } else { $this->max_body_length = false; } // If streaming to a file open a file handle, and setup our curl streaming handler. if ($r['stream']) { if (!WP_DEBUG) { $this->stream_handle = @fopen($r['filename'], 'w+'); } else { $this->stream_handle = fopen($r['filename'], 'w+'); } if (!$this->stream_handle) { return new WP_Error('http_request_failed', sprintf(__('Could not open handle for fopen() to %s'), $r['filename'])); } } else { $this->stream_handle = false; } if (!empty($r['headers'])) { // cURL expects full header strings in each element. $headers = array(); foreach ($r['headers'] as $name => $value) { $headers[] = "{$name}: {$value}"; } curl_setopt($handle, CURLOPT_HTTPHEADER, $headers); } if ($r['httpversion'] == '1.0') { curl_setopt($handle, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0); } else { curl_setopt($handle, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1); } /** * Fires before the cURL request is executed. * * Cookies are not currently handled by the HTTP API. This action allows * plugins to handle cookies themselves. * * @since 2.8.0 * * @param resource &$handle The cURL handle returned by curl_init(). * @param array $r The HTTP request arguments. * @param string $url The request URL. */ do_action_ref_array('http_api_curl', array(&$handle, $r, $url)); // We don't need to return the body, so don't. Just execute request and return. if (!$r['blocking']) { curl_exec($handle); if ($curl_error = curl_error($handle)) { curl_close($handle); return new WP_Error('http_request_failed', $curl_error); } if (in_array(curl_getinfo($handle, CURLINFO_HTTP_CODE), array(301, 302))) { curl_close($handle); return new WP_Error('http_request_failed', __('Too many redirects.')); } curl_close($handle); return array('headers' => array(), 'body' => '', 'response' => array('code' => false, 'message' => false), 'cookies' => array()); } curl_exec($handle); $theHeaders = WP_Http::processHeaders($this->headers, $url); $theBody = $this->body; $bytes_written_total = $this->bytes_written_total; $this->headers = ''; $this->body = ''; $this->bytes_written_total = 0; $curl_error = curl_errno($handle); // If an error occurred, or, no response. if ($curl_error || 0 == strlen($theBody) && empty($theHeaders['headers'])) { if (CURLE_WRITE_ERROR == $curl_error) { if (!$this->max_body_length || $this->max_body_length != $bytes_written_total) { if ($r['stream']) { curl_close($handle); fclose($this->stream_handle); return new WP_Error('http_request_failed', __('Failed to write request to temporary file.')); } else { curl_close($handle); return new WP_Error('http_request_failed', curl_error($handle)); } } } else { if ($curl_error = curl_error($handle)) { curl_close($handle); return new WP_Error('http_request_failed', $curl_error); } } if (in_array(curl_getinfo($handle, CURLINFO_HTTP_CODE), array(301, 302))) { curl_close($handle); return new WP_Error('http_request_failed', __('Too many redirects.')); } } curl_close($handle); if ($r['stream']) { fclose($this->stream_handle); } $response = array('headers' => $theHeaders['headers'], 'body' => null, 'response' => $theHeaders['response'], 'cookies' => $theHeaders['cookies'], 'filename' => $r['filename']); // Handle redirects. if (false !== ($redirect_response = WP_HTTP::handle_redirects($url, $r, $response))) { return $redirect_response; } if (true === $r['decompress'] && true === WP_Http_Encoding::should_decode($theHeaders['headers'])) { $theBody = WP_Http_Encoding::decompress($theBody); } $response['body'] = $theBody; return $response; }