diff --git a/wp-includes/class-http.php b/wp-includes/class-http.php index d7ec428f85..541ae56c71 100644 --- a/wp-includes/class-http.php +++ b/wp-includes/class-http.php @@ -593,6 +593,40 @@ class WP_Http { return $absolute_path . '/' . ltrim( $path, '/' ); } + + /** + * Handles HTTP Redirects and follows them if appropriate. + * + * @since 3.7 + * + * @param $url The URL which was requested + * @param $args The Arguements which were used to make the request + * @param $response The Response of the HTTP request + * @return false|object False if no redirect is present, a WP_HTTP or WP_Error result otherwise + */ + 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 = WP_HTTP::make_absolute_url( $response['headers']['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'; + } + + return wp_remote_request( $redirect_location, $args ); + } } /** @@ -804,14 +838,17 @@ class WP_Http_Fsockopen { $arrHeaders = WP_Http::processHeaders( $process['headers'] ); - // If location is found, then assume redirect and redirect to location. - if ( isset($arrHeaders['headers']['location']) && 0 !== $r['_redirection'] ) { - if ( $r['redirection']-- > 0 ) { - return wp_remote_request( WP_HTTP::make_absolute_url( $arrHeaders['headers']['location'], $url ), $r); - } else { - return new WP_Error('http_request_failed', __('Too many redirects.')); - } - } + $response = array( + 'headers' => $arrHeaders['headers'], + 'body' => null, // Not yet processed + 'response' => $arrHeaders['response'], + 'cookies' => $arrHeaders['cookies'], + 'filename' => $r['filename'] + ); + + // Handle redirects + if ( false !== ( $redirect_response = WP_HTTP::handle_redirects( $url, $r, $response ) ) ) + return $redirect_response; // If the body was chunk encoded, then decode it. if ( ! empty( $process['body'] ) && isset( $arrHeaders['headers']['transfer-encoding'] ) && 'chunked' == $arrHeaders['headers']['transfer-encoding'] ) @@ -823,7 +860,9 @@ class WP_Http_Fsockopen { if ( isset( $r['limit_response_size'] ) && strlen( $process['body'] ) > $r['limit_response_size'] ) $process['body'] = substr( $process['body'], 0, $r['limit_response_size'] ); - return array( 'headers' => $arrHeaders['headers'], 'body' => $process['body'], 'response' => $arrHeaders['response'], 'cookies' => $arrHeaders['cookies'], 'filename' => $r['filename'] ); + $response['body'] = $process['body']; + + return $response; } /** @@ -995,13 +1034,17 @@ class WP_Http_Streams { else $processedHeaders = WP_Http::processHeaders($meta['wrapper_data']); - if ( ! empty( $processedHeaders['headers']['location'] ) && 0 !== $r['_redirection'] ) { // _redirection: The requested number of redirections - if ( $r['redirection']-- > 0 ) { - return wp_remote_request( WP_HTTP::make_absolute_url( $processedHeaders['headers']['location'], $url ), $r ); - } else { - return new WP_Error( 'http_request_failed', __( 'Too many redirects.' ) ); - } - } + $response = array( + 'headers' => $processedHeaders['headers'], + 'body' => null, + 'response' => $processedHeaders['response'], + 'cookies' => $processedHeaders['cookies'], + 'filename' => $r['filename'] + ); + + // Handle redirects + if ( false !== ( $redirect_response = WP_HTTP::handle_redirects( $url, $r, $response ) ) ) + return $redirect_response; if ( ! empty( $strResponse ) && isset( $processedHeaders['headers']['transfer-encoding'] ) && 'chunked' == $processedHeaders['headers']['transfer-encoding'] ) $strResponse = WP_Http::chunkTransferDecode($strResponse); @@ -1009,7 +1052,9 @@ class WP_Http_Streams { if ( true === $r['decompress'] && true === WP_Http_Encoding::should_decode($processedHeaders['headers']) ) $strResponse = WP_Http_Encoding::decompress( $strResponse ); - return array( 'headers' => $processedHeaders['headers'], 'body' => $strResponse, 'response' => $processedHeaders['response'], 'cookies' => $processedHeaders['cookies'], 'filename' => $r['filename'] ); + $response['body'] = $strResponse; + + return $response; } /** @@ -1262,19 +1307,24 @@ class WP_Http_Curl { if ( $r['stream'] ) fclose( $this->stream_handle ); - // See #11305 - When running under safe mode, redirection is disabled above. Handle it manually. - if ( ! empty( $theHeaders['headers']['location'] ) && 0 !== $r['_redirection'] ) { // _redirection: The requested number of redirections - if ( $r['redirection']-- > 0 ) { - return wp_remote_request( WP_HTTP::make_absolute_url( $theHeaders['headers']['location'], $url ), $r ); - } else { - return new WP_Error( 'http_request_failed', __( 'Too many redirects.' ) ); - } - } + $response = array( + 'headers' => $theHeaders['headers'], + 'body' => null, + 'response' => $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 ); - return array( 'headers' => $theHeaders['headers'], 'body' => $theBody, 'response' => $response, 'cookies' => $theHeaders['cookies'], 'filename' => $r['filename'] ); + $response['body'] = $theBody; + + return $response; } /**