wp/wp-includes/class-http.php
changeset 16 a86126ab1dd4
parent 9 177826044cd9
child 18 be944660c56a
equal deleted inserted replaced
15:3d4e9c994f10 16:a86126ab1dd4
     6  * @subpackage HTTP
     6  * @subpackage HTTP
     7  * @since 2.7.0
     7  * @since 2.7.0
     8  */
     8  */
     9 
     9 
    10 if ( ! class_exists( 'Requests' ) ) {
    10 if ( ! class_exists( 'Requests' ) ) {
    11 	require( ABSPATH . WPINC . '/class-requests.php' );
    11 	require ABSPATH . WPINC . '/class-requests.php';
    12 
    12 
    13 	Requests::register_autoloader();
    13 	Requests::register_autoloader();
    14 	Requests::set_certificate_path( ABSPATH . WPINC . '/certificates/ca-bundle.crt' );
    14 	Requests::set_certificate_path( ABSPATH . WPINC . '/certificates/ca-bundle.crt' );
    15 }
    15 }
    16 
    16 
   107 	 *
   107 	 *
   108 	 *     @type string       $method              Request method. Accepts 'GET', 'POST', 'HEAD', 'PUT', 'DELETE',
   108 	 *     @type string       $method              Request method. Accepts 'GET', 'POST', 'HEAD', 'PUT', 'DELETE',
   109 	 *                                             'TRACE', 'OPTIONS', or 'PATCH'.
   109 	 *                                             'TRACE', 'OPTIONS', or 'PATCH'.
   110 	 *                                             Some transports technically allow others, but should not be
   110 	 *                                             Some transports technically allow others, but should not be
   111 	 *                                             assumed. Default 'GET'.
   111 	 *                                             assumed. Default 'GET'.
   112 	 *     @type int          $timeout             How long the connection should stay open in seconds. Default 5.
   112 	 *     @type float        $timeout             How long the connection should stay open in seconds. Default 5.
   113 	 *     @type int          $redirection         Number of allowed redirects. Not supported by all transports
   113 	 *     @type int          $redirection         Number of allowed redirects. Not supported by all transports
   114 	 *                                             Default 5.
   114 	 *                                             Default 5.
   115 	 *     @type string       $httpversion         Version of the HTTP protocol to use. Accepts '1.0' and '1.1'.
   115 	 *     @type string       $httpversion         Version of the HTTP protocol to use. Accepts '1.0' and '1.1'.
   116 	 *                                             Default '1.0'.
   116 	 *                                             Default '1.0'.
   117 	 *     @type string       $user-agent          User-agent value sent.
   117 	 *     @type string       $user-agent          User-agent value sent.
   131 	 *                                             Default false.
   131 	 *                                             Default false.
   132 	 *     @type bool         $decompress          Whether to decompress a compressed response. If set to false and
   132 	 *     @type bool         $decompress          Whether to decompress a compressed response. If set to false and
   133 	 *                                             compressed content is returned in the response anyway, it will
   133 	 *                                             compressed content is returned in the response anyway, it will
   134 	 *                                             need to be separately decompressed. Default true.
   134 	 *                                             need to be separately decompressed. Default true.
   135 	 *     @type bool         $sslverify           Whether to verify SSL for the request. Default true.
   135 	 *     @type bool         $sslverify           Whether to verify SSL for the request. Default true.
   136 	 *     @type string       sslcertificates      Absolute path to an SSL certificate .crt file.
   136 	 *     @type string       $sslcertificates     Absolute path to an SSL certificate .crt file.
   137 	 *                                             Default ABSPATH . WPINC . '/certificates/ca-bundle.crt'.
   137 	 *                                             Default ABSPATH . WPINC . '/certificates/ca-bundle.crt'.
   138 	 *     @type bool         $stream              Whether to stream to a file. If set to true and no filename was
   138 	 *     @type bool         $stream              Whether to stream to a file. If set to true and no filename was
   139 	 *                                             given, it will be droped it in the WP temp dir and its name will
   139 	 *                                             given, it will be droped it in the WP temp dir and its name will
   140 	 *                                             be set using the basename of the URL. Default false.
   140 	 *                                             be set using the basename of the URL. Default false.
   141 	 *     @type string       $filename            Filename of the file to write to when streaming. $stream must be
   141 	 *     @type string       $filename            Filename of the file to write to when streaming. $stream must be
   153 			 * Filters the timeout value for an HTTP request.
   153 			 * Filters the timeout value for an HTTP request.
   154 			 *
   154 			 *
   155 			 * @since 2.7.0
   155 			 * @since 2.7.0
   156 			 * @since 5.1.0 The `$url` parameter was added.
   156 			 * @since 5.1.0 The `$url` parameter was added.
   157 			 *
   157 			 *
   158 			 * @param int    $timeout_value Time in seconds until a request times out. Default 5.
   158 			 * @param float  $timeout_value Time in seconds until a request times out. Default 5.
   159 			 * @param string $url           The request URL.
   159 			 * @param string $url           The request URL.
   160 			 */
   160 			 */
   161 			'timeout'             => apply_filters( 'http_request_timeout', 5, $url ),
   161 			'timeout'             => apply_filters( 'http_request_timeout', 5, $url ),
   162 			/**
   162 			/**
   163 			 * Filters the number of redirects allowed during an HTTP request.
   163 			 * Filters the number of redirects allowed during an HTTP request.
   213 		);
   213 		);
   214 
   214 
   215 		// Pre-parse for the HEAD checks.
   215 		// Pre-parse for the HEAD checks.
   216 		$args = wp_parse_args( $args );
   216 		$args = wp_parse_args( $args );
   217 
   217 
   218 		// By default, Head requests do not cause redirections.
   218 		// By default, HEAD requests do not cause redirections.
   219 		if ( isset( $args['method'] ) && 'HEAD' == $args['method'] ) {
   219 		if ( isset( $args['method'] ) && 'HEAD' === $args['method'] ) {
   220 			$defaults['redirection'] = 0;
   220 			$defaults['redirection'] = 0;
   221 		}
   221 		}
   222 
   222 
   223 		$r = wp_parse_args( $args, $defaults );
   223 		$parsed_args = wp_parse_args( $args, $defaults );
   224 		/**
   224 		/**
   225 		 * Filters the arguments used in an HTTP request.
   225 		 * Filters the arguments used in an HTTP request.
   226 		 *
   226 		 *
   227 		 * @since 2.7.0
   227 		 * @since 2.7.0
   228 		 *
   228 		 *
   229 		 * @param array  $r   An array of HTTP request arguments.
   229 		 * @param array  $parsed_args An array of HTTP request arguments.
   230 		 * @param string $url The request URL.
   230 		 * @param string $url         The request URL.
   231 		 */
   231 		 */
   232 		$r = apply_filters( 'http_request_args', $r, $url );
   232 		$parsed_args = apply_filters( 'http_request_args', $parsed_args, $url );
   233 
   233 
   234 		// The transports decrement this, store a copy of the original value for loop purposes.
   234 		// The transports decrement this, store a copy of the original value for loop purposes.
   235 		if ( ! isset( $r['_redirection'] ) ) {
   235 		if ( ! isset( $parsed_args['_redirection'] ) ) {
   236 			$r['_redirection'] = $r['redirection'];
   236 			$parsed_args['_redirection'] = $parsed_args['redirection'];
   237 		}
   237 		}
   238 
   238 
   239 		/**
   239 		/**
   240 		 * Filters whether to preempt an HTTP request's return value.
   240 		 * Filters the preemptive return value of an HTTP request.
   241 		 *
   241 		 *
   242 		 * Returning a non-false value from the filter will short-circuit the HTTP request and return
   242 		 * Returning a non-false value from the filter will short-circuit the HTTP request and return
   243 		 * early with that value. A filter should return either:
   243 		 * early with that value. A filter should return one of:
   244 		 *
   244 		 *
   245 		 *  - An array containing 'headers', 'body', 'response', 'cookies', and 'filename' elements
   245 		 *  - An array containing 'headers', 'body', 'response', 'cookies', and 'filename' elements
   246 		 *  - A WP_Error instance
   246 		 *  - A WP_Error instance
   247 		 *  - boolean false (to avoid short-circuiting the response)
   247 		 *  - boolean false to avoid short-circuiting the response
   248 		 *
   248 		 *
   249 		 * Returning any other value may result in unexpected behaviour.
   249 		 * Returning any other value may result in unexpected behaviour.
   250 		 *
   250 		 *
   251 		 * @since 2.9.0
   251 		 * @since 2.9.0
   252 		 *
   252 		 *
   253 		 * @param false|array|WP_Error $preempt Whether to preempt an HTTP request's return value. Default false.
   253 		 * @param false|array|WP_Error $preempt     A preemptive return value of an HTTP request. Default false.
   254 		 * @param array               $r        HTTP request arguments.
   254 		 * @param array                $parsed_args HTTP request arguments.
   255 		 * @param string              $url      The request URL.
   255 		 * @param string               $url         The request URL.
   256 		 */
   256 		 */
   257 		$pre = apply_filters( 'pre_http_request', false, $r, $url );
   257 		$pre = apply_filters( 'pre_http_request', false, $parsed_args, $url );
   258 
   258 
   259 		if ( false !== $pre ) {
   259 		if ( false !== $pre ) {
   260 			return $pre;
   260 			return $pre;
   261 		}
   261 		}
   262 
   262 
   263 		if ( function_exists( 'wp_kses_bad_protocol' ) ) {
   263 		if ( function_exists( 'wp_kses_bad_protocol' ) ) {
   264 			if ( $r['reject_unsafe_urls'] ) {
   264 			if ( $parsed_args['reject_unsafe_urls'] ) {
   265 				$url = wp_http_validate_url( $url );
   265 				$url = wp_http_validate_url( $url );
   266 			}
   266 			}
   267 			if ( $url ) {
   267 			if ( $url ) {
   268 				$url = wp_kses_bad_protocol( $url, array( 'http', 'https', 'ssl' ) );
   268 				$url = wp_kses_bad_protocol( $url, array( 'http', 'https', 'ssl' ) );
   269 			}
   269 			}
   270 		}
   270 		}
   271 
   271 
   272 		$arrURL = @parse_url( $url );
   272 		$arrURL = parse_url( $url );
   273 
   273 
   274 		if ( empty( $url ) || empty( $arrURL['scheme'] ) ) {
   274 		if ( empty( $url ) || empty( $arrURL['scheme'] ) ) {
   275 			return new WP_Error( 'http_request_failed', __( 'A valid URL was not provided.' ) );
   275 			$response = new WP_Error( 'http_request_failed', __( 'A valid URL was not provided.' ) );
       
   276 			/** This action is documented in wp-includes/class-http.php */
       
   277 			do_action( 'http_api_debug', $response, 'response', 'Requests', $parsed_args, $url );
       
   278 			return $response;
   276 		}
   279 		}
   277 
   280 
   278 		if ( $this->block_request( $url ) ) {
   281 		if ( $this->block_request( $url ) ) {
   279 			return new WP_Error( 'http_request_failed', __( 'User has blocked requests through HTTP.' ) );
   282 			$response = new WP_Error( 'http_request_not_executed', __( 'User has blocked requests through HTTP.' ) );
       
   283 			/** This action is documented in wp-includes/class-http.php */
       
   284 			do_action( 'http_api_debug', $response, 'response', 'Requests', $parsed_args, $url );
       
   285 			return $response;
   280 		}
   286 		}
   281 
   287 
   282 		// If we are streaming to a file but no filename was given drop it in the WP temp dir
   288 		// If we are streaming to a file but no filename was given drop it in the WP temp dir
   283 		// and pick its name using the basename of the $url
   289 		// and pick its name using the basename of the $url.
   284 		if ( $r['stream'] ) {
   290 		if ( $parsed_args['stream'] ) {
   285 			if ( empty( $r['filename'] ) ) {
   291 			if ( empty( $parsed_args['filename'] ) ) {
   286 				$r['filename'] = get_temp_dir() . basename( $url );
   292 				$parsed_args['filename'] = get_temp_dir() . basename( $url );
   287 			}
   293 			}
   288 
   294 
   289 			// Force some settings if we are streaming to a file and check for existence and perms of destination directory
   295 			// Force some settings if we are streaming to a file and check for existence
   290 			$r['blocking'] = true;
   296 			// and perms of destination directory.
   291 			if ( ! wp_is_writable( dirname( $r['filename'] ) ) ) {
   297 			$parsed_args['blocking'] = true;
   292 				return new WP_Error( 'http_request_failed', __( 'Destination directory for file streaming does not exist or is not writable.' ) );
   298 			if ( ! wp_is_writable( dirname( $parsed_args['filename'] ) ) ) {
   293 			}
   299 				$response = new WP_Error( 'http_request_failed', __( 'Destination directory for file streaming does not exist or is not writable.' ) );
   294 		}
   300 				/** This action is documented in wp-includes/class-http.php */
   295 
   301 				do_action( 'http_api_debug', $response, 'response', 'Requests', $parsed_args, $url );
   296 		if ( is_null( $r['headers'] ) ) {
   302 				return $response;
   297 			$r['headers'] = array();
   303 			}
       
   304 		}
       
   305 
       
   306 		if ( is_null( $parsed_args['headers'] ) ) {
       
   307 			$parsed_args['headers'] = array();
   298 		}
   308 		}
   299 
   309 
   300 		// WP allows passing in headers as a string, weirdly.
   310 		// WP allows passing in headers as a string, weirdly.
   301 		if ( ! is_array( $r['headers'] ) ) {
   311 		if ( ! is_array( $parsed_args['headers'] ) ) {
   302 			$processedHeaders = WP_Http::processHeaders( $r['headers'] );
   312 			$processedHeaders       = WP_Http::processHeaders( $parsed_args['headers'] );
   303 			$r['headers']     = $processedHeaders['headers'];
   313 			$parsed_args['headers'] = $processedHeaders['headers'];
   304 		}
   314 		}
   305 
   315 
   306 		// Setup arguments
   316 		// Setup arguments.
   307 		$headers = $r['headers'];
   317 		$headers = $parsed_args['headers'];
   308 		$data    = $r['body'];
   318 		$data    = $parsed_args['body'];
   309 		$type    = $r['method'];
   319 		$type    = $parsed_args['method'];
   310 		$options = array(
   320 		$options = array(
   311 			'timeout'   => $r['timeout'],
   321 			'timeout'   => $parsed_args['timeout'],
   312 			'useragent' => $r['user-agent'],
   322 			'useragent' => $parsed_args['user-agent'],
   313 			'blocking'  => $r['blocking'],
   323 			'blocking'  => $parsed_args['blocking'],
   314 			'hooks'     => new WP_HTTP_Requests_Hooks( $url, $r ),
   324 			'hooks'     => new WP_HTTP_Requests_Hooks( $url, $parsed_args ),
   315 		);
   325 		);
   316 
   326 
   317 		// Ensure redirects follow browser behaviour.
   327 		// Ensure redirects follow browser behaviour.
   318 		$options['hooks']->register( 'requests.before_redirect', array( get_class(), 'browser_redirect_compatibility' ) );
   328 		$options['hooks']->register( 'requests.before_redirect', array( get_class(), 'browser_redirect_compatibility' ) );
   319 
   329 
   320 		// Validate redirected URLs.
   330 		// Validate redirected URLs.
   321 		if ( function_exists( 'wp_kses_bad_protocol' ) && $r['reject_unsafe_urls'] ) {
   331 		if ( function_exists( 'wp_kses_bad_protocol' ) && $parsed_args['reject_unsafe_urls'] ) {
   322 			$options['hooks']->register( 'requests.before_redirect', array( get_class(), 'validate_redirects' ) );
   332 			$options['hooks']->register( 'requests.before_redirect', array( get_class(), 'validate_redirects' ) );
   323 		}
   333 		}
   324 
   334 
   325 		if ( $r['stream'] ) {
   335 		if ( $parsed_args['stream'] ) {
   326 			$options['filename'] = $r['filename'];
   336 			$options['filename'] = $parsed_args['filename'];
   327 		}
   337 		}
   328 		if ( empty( $r['redirection'] ) ) {
   338 		if ( empty( $parsed_args['redirection'] ) ) {
   329 			$options['follow_redirects'] = false;
   339 			$options['follow_redirects'] = false;
   330 		} else {
   340 		} else {
   331 			$options['redirects'] = $r['redirection'];
   341 			$options['redirects'] = $parsed_args['redirection'];
   332 		}
   342 		}
   333 
   343 
   334 		// Use byte limit, if we can
   344 		// Use byte limit, if we can.
   335 		if ( isset( $r['limit_response_size'] ) ) {
   345 		if ( isset( $parsed_args['limit_response_size'] ) ) {
   336 			$options['max_bytes'] = $r['limit_response_size'];
   346 			$options['max_bytes'] = $parsed_args['limit_response_size'];
   337 		}
   347 		}
   338 
   348 
   339 		// If we've got cookies, use and convert them to Requests_Cookie.
   349 		// If we've got cookies, use and convert them to Requests_Cookie.
   340 		if ( ! empty( $r['cookies'] ) ) {
   350 		if ( ! empty( $parsed_args['cookies'] ) ) {
   341 			$options['cookies'] = WP_Http::normalize_cookies( $r['cookies'] );
   351 			$options['cookies'] = WP_Http::normalize_cookies( $parsed_args['cookies'] );
   342 		}
   352 		}
   343 
   353 
   344 		// SSL certificate handling
   354 		// SSL certificate handling.
   345 		if ( ! $r['sslverify'] ) {
   355 		if ( ! $parsed_args['sslverify'] ) {
   346 			$options['verify']     = false;
   356 			$options['verify']     = false;
   347 			$options['verifyname'] = false;
   357 			$options['verifyname'] = false;
   348 		} else {
   358 		} else {
   349 			$options['verify'] = $r['sslcertificates'];
   359 			$options['verify'] = $parsed_args['sslcertificates'];
   350 		}
   360 		}
   351 
   361 
   352 		// All non-GET/HEAD requests should put the arguments in the form body.
   362 		// All non-GET/HEAD requests should put the arguments in the form body.
   353 		if ( 'HEAD' !== $type && 'GET' !== $type ) {
   363 		if ( 'HEAD' !== $type && 'GET' !== $type ) {
   354 			$options['data_format'] = 'body';
   364 			$options['data_format'] = 'body';
   375 				$options['proxy']->user               = $proxy->username();
   385 				$options['proxy']->user               = $proxy->username();
   376 				$options['proxy']->pass               = $proxy->password();
   386 				$options['proxy']->pass               = $proxy->password();
   377 			}
   387 			}
   378 		}
   388 		}
   379 
   389 
   380 		// Avoid issues where mbstring.func_overload is enabled
   390 		// Avoid issues where mbstring.func_overload is enabled.
   381 		mbstring_binary_safe_encoding();
   391 		mbstring_binary_safe_encoding();
   382 
   392 
   383 		try {
   393 		try {
   384 			$requests_response = Requests::request( $url, $headers, $data, $type, $options );
   394 			$requests_response = Requests::request( $url, $headers, $data, $type, $options );
   385 
   395 
   386 			// Convert the response into an array
   396 			// Convert the response into an array.
   387 			$http_response = new WP_HTTP_Requests_Response( $requests_response, $r['filename'] );
   397 			$http_response = new WP_HTTP_Requests_Response( $requests_response, $parsed_args['filename'] );
   388 			$response      = $http_response->to_array();
   398 			$response      = $http_response->to_array();
   389 
   399 
   390 			// Add the original object to the array.
   400 			// Add the original object to the array.
   391 			$response['http_response'] = $http_response;
   401 			$response['http_response'] = $http_response;
   392 		} catch ( Requests_Exception $e ) {
   402 		} catch ( Requests_Exception $e ) {
   398 		/**
   408 		/**
   399 		 * Fires after an HTTP API response is received and before the response is returned.
   409 		 * Fires after an HTTP API response is received and before the response is returned.
   400 		 *
   410 		 *
   401 		 * @since 2.8.0
   411 		 * @since 2.8.0
   402 		 *
   412 		 *
   403 		 * @param array|WP_Error $response HTTP response or WP_Error object.
   413 		 * @param array|WP_Error $response    HTTP response or WP_Error object.
   404 		 * @param string         $context  Context under which the hook is fired.
   414 		 * @param string         $context     Context under which the hook is fired.
   405 		 * @param string         $class    HTTP transport used.
   415 		 * @param string         $class       HTTP transport used.
   406 		 * @param array          $r        HTTP request arguments.
   416 		 * @param array          $parsed_args HTTP request arguments.
   407 		 * @param string         $url      The request URL.
   417 		 * @param string         $url         The request URL.
   408 		 */
   418 		 */
   409 		do_action( 'http_api_debug', $response, 'response', 'Requests', $r, $url );
   419 		do_action( 'http_api_debug', $response, 'response', 'Requests', $parsed_args, $url );
   410 		if ( is_wp_error( $response ) ) {
   420 		if ( is_wp_error( $response ) ) {
   411 			return $response;
   421 			return $response;
   412 		}
   422 		}
   413 
   423 
   414 		if ( ! $r['blocking'] ) {
   424 		if ( ! $parsed_args['blocking'] ) {
   415 			return array(
   425 			return array(
   416 				'headers'       => array(),
   426 				'headers'       => array(),
   417 				'body'          => '',
   427 				'body'          => '',
   418 				'response'      => array(
   428 				'response'      => array(
   419 					'code'    => false,
   429 					'code'    => false,
   427 		/**
   437 		/**
   428 		 * Filters the HTTP API response immediately before the response is returned.
   438 		 * Filters the HTTP API response immediately before the response is returned.
   429 		 *
   439 		 *
   430 		 * @since 2.9.0
   440 		 * @since 2.9.0
   431 		 *
   441 		 *
   432 		 * @param array  $response HTTP response.
   442 		 * @param array  $response    HTTP response.
   433 		 * @param array  $r        HTTP request arguments.
   443 		 * @param array  $parsed_args HTTP request arguments.
   434 		 * @param string $url      The request URL.
   444 		 * @param string $url         The request URL.
   435 		 */
   445 		 */
   436 		return apply_filters( 'http_response', $response, $r, $url );
   446 		return apply_filters( 'http_response', $response, $parsed_args, $url );
   437 	}
   447 	}
   438 
   448 
   439 	/**
   449 	/**
   440 	 * Normalizes cookies for using in Requests.
   450 	 * Normalizes cookies for using in Requests.
   441 	 *
   451 	 *
   472 	 * @param string|array      $data     Body to send with the request.
   482 	 * @param string|array      $data     Body to send with the request.
   473 	 * @param array             $options  Redirect request options.
   483 	 * @param array             $options  Redirect request options.
   474 	 * @param Requests_Response $original Response object.
   484 	 * @param Requests_Response $original Response object.
   475 	 */
   485 	 */
   476 	public static function browser_redirect_compatibility( $location, $headers, $data, &$options, $original ) {
   486 	public static function browser_redirect_compatibility( $location, $headers, $data, &$options, $original ) {
   477 		// Browser compat
   487 		// Browser compatibility.
   478 		if ( $original->status_code === 302 ) {
   488 		if ( 302 === $original->status_code ) {
   479 			$options['type'] = Requests::GET;
   489 			$options['type'] = Requests::GET;
   480 		}
   490 		}
   481 	}
   491 	}
   482 
   492 
   483 	/**
   493 	/**
   484 	 * Validate redirected URLs.
   494 	 * Validate redirected URLs.
   485 	 *
   495 	 *
   486 	 * @since 4.7.5
   496 	 * @since 4.7.5
   487 	 *
   497 	 *
   488 	 * @throws Requests_Exception On unsuccessful URL validation
   498 	 * @throws Requests_Exception On unsuccessful URL validation.
   489 	 * @param string $location URL to redirect to.
   499 	 * @param string $location URL to redirect to.
   490 	 */
   500 	 */
   491 	public static function validate_redirects( $location ) {
   501 	public static function validate_redirects( $location ) {
   492 		if ( ! wp_http_validate_url( $location ) ) {
   502 		if ( ! wp_http_validate_url( $location ) ) {
   493 			throw new Requests_Exception( __( 'A valid URL was not provided.' ), 'wp_http.redirect_failed_validation' );
   503 			throw new Requests_Exception( __( 'A valid URL was not provided.' ), 'wp_http.redirect_failed_validation' );
   497 	/**
   507 	/**
   498 	 * Tests which transports are capable of supporting the request.
   508 	 * Tests which transports are capable of supporting the request.
   499 	 *
   509 	 *
   500 	 * @since 3.2.0
   510 	 * @since 3.2.0
   501 	 *
   511 	 *
   502 	 * @param array $args Request arguments
   512 	 * @param array  $args Request arguments.
   503 	 * @param string $url URL to Request
   513 	 * @param string $url  URL to request.
   504 	 *
   514 	 * @return string|false Class name for the first transport that claims to support the request.
   505 	 * @return string|false Class name for the first transport that claims to support the request. False if no transport claims to support the request.
   515 	 *                      False if no transport claims to support the request.
   506 	 */
   516 	 */
   507 	public function _get_first_available_transport( $args, $url = null ) {
   517 	public function _get_first_available_transport( $args, $url = null ) {
   508 		$transports = array( 'curl', 'streams' );
   518 		$transports = array( 'curl', 'streams' );
   509 
   519 
   510 		/**
   520 		/**
   511 		 * Filters which HTTP transports are available and in what order.
   521 		 * Filters which HTTP transports are available and in what order.
   512 		 *
   522 		 *
   513 		 * @since 3.7.0
   523 		 * @since 3.7.0
   514 		 *
   524 		 *
   515 		 * @param array  $transports Array of HTTP transports to check. Default array contains
   525 		 * @param string[] $transports Array of HTTP transports to check. Default array contains
   516 		 *                           'curl', and 'streams', in that order.
   526 		 *                             'curl' and 'streams', in that order.
   517 		 * @param array  $args       HTTP request arguments.
   527 		 * @param array    $args       HTTP request arguments.
   518 		 * @param string $url        The URL to request.
   528 		 * @param string   $url        The URL to request.
   519 		 */
   529 		 */
   520 		$request_order = apply_filters( 'http_api_transports', $transports, $args, $url );
   530 		$request_order = apply_filters( 'http_api_transports', $transports, $args, $url );
   521 
   531 
   522 		// Loop over each transport on each HTTP request looking for one which will serve this request's needs.
   532 		// Loop over each transport on each HTTP request looking for one which will serve this request's needs.
   523 		foreach ( $request_order as $transport ) {
   533 		foreach ( $request_order as $transport ) {
   524 			if ( in_array( $transport, $transports ) ) {
   534 			if ( in_array( $transport, $transports, true ) ) {
   525 				$transport = ucfirst( $transport );
   535 				$transport = ucfirst( $transport );
   526 			}
   536 			}
   527 			$class = 'WP_Http_' . $transport;
   537 			$class = 'WP_Http_' . $transport;
   528 
   538 
   529 			// Check to see if this transport is a possibility, calls the transport statically.
   539 			// Check to see if this transport is a possibility, calls the transport statically.
   547 	 *
   557 	 *
   548 	 * @since 3.2.0
   558 	 * @since 3.2.0
   549 	 * @deprecated 5.1.0 Use WP_Http::request()
   559 	 * @deprecated 5.1.0 Use WP_Http::request()
   550 	 * @see WP_Http::request()
   560 	 * @see WP_Http::request()
   551 	 *
   561 	 *
   552 	 * @param string $url URL to Request
   562 	 * @param string $url  URL to request.
   553 	 * @param array $args Request arguments
   563 	 * @param array  $args Request arguments.
   554 	 * @return array|WP_Error Array containing 'headers', 'body', 'response', 'cookies', 'filename'. A WP_Error instance upon error
   564 	 * @return array|WP_Error Array containing 'headers', 'body', 'response', 'cookies', 'filename'.
       
   565 	 *                        A WP_Error instance upon error.
   555 	 */
   566 	 */
   556 	private function _dispatch_request( $url, $args ) {
   567 	private function _dispatch_request( $url, $args ) {
   557 		static $transports = array();
   568 		static $transports = array();
   558 
   569 
   559 		$class = $this->_get_first_available_transport( $args, $url );
   570 		$class = $this->_get_first_available_transport( $args, $url );
   586 	 *
   597 	 *
   587 	 * @since 2.7.0
   598 	 * @since 2.7.0
   588 	 *
   599 	 *
   589 	 * @param string       $url  The request URL.
   600 	 * @param string       $url  The request URL.
   590 	 * @param string|array $args Optional. Override the defaults.
   601 	 * @param string|array $args Optional. Override the defaults.
   591 	 * @return array|WP_Error Array containing 'headers', 'body', 'response', 'cookies', 'filename'. A WP_Error instance upon error
   602 	 * @return array|WP_Error Array containing 'headers', 'body', 'response', 'cookies', 'filename'.
       
   603 	 *                        A WP_Error instance upon error.
   592 	 */
   604 	 */
   593 	public function post( $url, $args = array() ) {
   605 	public function post( $url, $args = array() ) {
   594 		$defaults = array( 'method' => 'POST' );
   606 		$defaults    = array( 'method' => 'POST' );
   595 		$r        = wp_parse_args( $args, $defaults );
   607 		$parsed_args = wp_parse_args( $args, $defaults );
   596 		return $this->request( $url, $r );
   608 		return $this->request( $url, $parsed_args );
   597 	}
   609 	}
   598 
   610 
   599 	/**
   611 	/**
   600 	 * Uses the GET HTTP method.
   612 	 * Uses the GET HTTP method.
   601 	 *
   613 	 *
   602 	 * Used for sending data that is expected to be in the body.
   614 	 * Used for sending data that is expected to be in the body.
   603 	 *
   615 	 *
   604 	 * @since 2.7.0
   616 	 * @since 2.7.0
   605 	 *
   617 	 *
   606 	 * @param string $url The request URL.
   618 	 * @param string       $url  The request URL.
   607 	 * @param string|array $args Optional. Override the defaults.
   619 	 * @param string|array $args Optional. Override the defaults.
   608 	 * @return array|WP_Error Array containing 'headers', 'body', 'response', 'cookies', 'filename'. A WP_Error instance upon error
   620 	 * @return array|WP_Error Array containing 'headers', 'body', 'response', 'cookies', 'filename'.
       
   621 	 *                        A WP_Error instance upon error.
   609 	 */
   622 	 */
   610 	public function get( $url, $args = array() ) {
   623 	public function get( $url, $args = array() ) {
   611 		$defaults = array( 'method' => 'GET' );
   624 		$defaults    = array( 'method' => 'GET' );
   612 		$r        = wp_parse_args( $args, $defaults );
   625 		$parsed_args = wp_parse_args( $args, $defaults );
   613 		return $this->request( $url, $r );
   626 		return $this->request( $url, $parsed_args );
   614 	}
   627 	}
   615 
   628 
   616 	/**
   629 	/**
   617 	 * Uses the HEAD HTTP method.
   630 	 * Uses the HEAD HTTP method.
   618 	 *
   631 	 *
   619 	 * Used for sending data that is expected to be in the body.
   632 	 * Used for sending data that is expected to be in the body.
   620 	 *
   633 	 *
   621 	 * @since 2.7.0
   634 	 * @since 2.7.0
   622 	 *
   635 	 *
   623 	 * @param string $url The request URL.
   636 	 * @param string       $url  The request URL.
   624 	 * @param string|array $args Optional. Override the defaults.
   637 	 * @param string|array $args Optional. Override the defaults.
   625 	 * @return array|WP_Error Array containing 'headers', 'body', 'response', 'cookies', 'filename'. A WP_Error instance upon error
   638 	 * @return array|WP_Error Array containing 'headers', 'body', 'response', 'cookies', 'filename'.
       
   639 	 *                        A WP_Error instance upon error.
   626 	 */
   640 	 */
   627 	public function head( $url, $args = array() ) {
   641 	public function head( $url, $args = array() ) {
   628 		$defaults = array( 'method' => 'HEAD' );
   642 		$defaults    = array( 'method' => 'HEAD' );
   629 		$r        = wp_parse_args( $args, $defaults );
   643 		$parsed_args = wp_parse_args( $args, $defaults );
   630 		return $this->request( $url, $r );
   644 		return $this->request( $url, $parsed_args );
   631 	}
   645 	}
   632 
   646 
   633 	/**
   647 	/**
   634 	 * Parses the responses and splits the parts into headers and body.
   648 	 * Parses the responses and splits the parts into headers and body.
   635 	 *
   649 	 *
   636 	 * @since 2.7.0
   650 	 * @since 2.7.0
   637 	 *
   651 	 *
   638 	 * @param string $strResponse The full response string
   652 	 * @param string $strResponse The full response string.
   639 	 * @return array Array with 'headers' and 'body' keys.
   653 	 * @return array {
   640 	 */
   654 	 *     Array with response headers and body.
   641 	public static function processResponse( $strResponse ) {
   655 	 *
       
   656 	 *     @type string $headers HTTP response headers.
       
   657 	 *     @type string $body    HTTP response body.
       
   658 	 * }
       
   659 	 */
       
   660 	public static function processResponse( $strResponse ) { // phpcs:ignore WordPress.NamingConventions.ValidFunctionName.MethodNameInvalid
   642 		$res = explode( "\r\n\r\n", $strResponse, 2 );
   661 		$res = explode( "\r\n\r\n", $strResponse, 2 );
   643 
   662 
   644 		return array(
   663 		return array(
   645 			'headers' => $res[0],
   664 			'headers' => $res[0],
   646 			'body'    => isset( $res[1] ) ? $res[1] : '',
   665 			'body'    => isset( $res[1] ) ? $res[1] : '',
   647 		);
   666 		);
   648 	}
   667 	}
   649 
   668 
   650 	/**
   669 	/**
   651 	 * Transform header string into an array.
   670 	 * Transforms header string into an array.
   652 	 *
       
   653 	 * If an array is given then it is assumed to be raw header data with numeric keys with the
       
   654 	 * headers as the values. No headers must be passed that were already processed.
       
   655 	 *
   671 	 *
   656 	 * @since 2.7.0
   672 	 * @since 2.7.0
   657 	 *
   673 	 *
   658 	 * @param string|array $headers
   674 	 * @param string|array $headers The original headers. If a string is passed, it will be converted
   659 	 * @param string $url The URL that was requested
   675 	 *                              to an array. If an array is passed, then it is assumed to be
   660 	 * @return array Processed string headers. If duplicate headers are encountered,
   676 	 *                              raw header data with numeric keys with the headers as the values.
   661 	 *                  Then a numbered array is returned as the value of that header-key.
   677 	 *                              No headers must be passed that were already processed.
   662 	 */
   678 	 * @param string       $url     Optional. The URL that was requested. Default empty.
   663 	public static function processHeaders( $headers, $url = '' ) {
   679 	 * @return array {
       
   680 	 *     Processed string headers. If duplicate headers are encountered,
       
   681 	 *     then a numbered array is returned as the value of that header-key.
       
   682 	 *
       
   683 	 *     @type array            $response {
       
   684 	 *          @type int    $code    The response status code. Default 0.
       
   685 	 *          @type string $message The response message. Default empty.
       
   686 	 *     }
       
   687 	 *     @type array            $newheaders The processed header data as a multidimensional array.
       
   688 	 *     @type WP_Http_Cookie[] $cookies    If the original headers contain the 'Set-Cookie' key,
       
   689 	 *                                        an array containing `WP_Http_Cookie` objects is returned.
       
   690 	 * }
       
   691 	 */
       
   692 	public static function processHeaders( $headers, $url = '' ) { // phpcs:ignore WordPress.NamingConventions.ValidFunctionName.MethodNameInvalid
   664 		// Split headers, one per array element.
   693 		// Split headers, one per array element.
   665 		if ( is_string( $headers ) ) {
   694 		if ( is_string( $headers ) ) {
   666 			// Tolerate line terminator: CRLF = LF (RFC 2616 19.3).
   695 			// Tolerate line terminator: CRLF = LF (RFC 2616 19.3).
   667 			$headers = str_replace( "\r\n", "\n", $headers );
   696 			$headers = str_replace( "\r\n", "\n", $headers );
   668 			/*
   697 			/*
   715 				}
   744 				}
   716 				$newheaders[ $key ][] = $value;
   745 				$newheaders[ $key ][] = $value;
   717 			} else {
   746 			} else {
   718 				$newheaders[ $key ] = $value;
   747 				$newheaders[ $key ] = $value;
   719 			}
   748 			}
   720 			if ( 'set-cookie' == $key ) {
   749 			if ( 'set-cookie' === $key ) {
   721 				$cookies[] = new WP_Http_Cookie( $value, $url );
   750 				$cookies[] = new WP_Http_Cookie( $value, $url );
   722 			}
   751 			}
   723 		}
   752 		}
   724 
   753 
   725 		// Cast the Response Code to an int
   754 		// Cast the Response Code to an int.
   726 		$response['code'] = intval( $response['code'] );
   755 		$response['code'] = intval( $response['code'] );
   727 
   756 
   728 		return array(
   757 		return array(
   729 			'response' => $response,
   758 			'response' => $response,
   730 			'headers'  => $newheaders,
   759 			'headers'  => $newheaders,
   741 	 *
   770 	 *
   742 	 * @since 2.8.0
   771 	 * @since 2.8.0
   743 	 *
   772 	 *
   744 	 * @param array $r Full array of args passed into ::request()
   773 	 * @param array $r Full array of args passed into ::request()
   745 	 */
   774 	 */
   746 	public static function buildCookieHeader( &$r ) {
   775 	public static function buildCookieHeader( &$r ) { // phpcs:ignore WordPress.NamingConventions.ValidFunctionName.MethodNameInvalid
   747 		if ( ! empty( $r['cookies'] ) ) {
   776 		if ( ! empty( $r['cookies'] ) ) {
   748 			// Upgrade any name => value cookie pairs to WP_HTTP_Cookie instances.
   777 			// Upgrade any name => value cookie pairs to WP_HTTP_Cookie instances.
   749 			foreach ( $r['cookies'] as $name => $value ) {
   778 			foreach ( $r['cookies'] as $name => $value ) {
   750 				if ( ! is_object( $value ) ) {
   779 				if ( ! is_object( $value ) ) {
   751 					$r['cookies'][ $name ] = new WP_Http_Cookie(
   780 					$r['cookies'][ $name ] = new WP_Http_Cookie(
   774 	 *
   803 	 *
   775 	 * @link https://tools.ietf.org/html/rfc2616#section-19.4.6 Process for chunked decoding.
   804 	 * @link https://tools.ietf.org/html/rfc2616#section-19.4.6 Process for chunked decoding.
   776 	 *
   805 	 *
   777 	 * @since 2.7.0
   806 	 * @since 2.7.0
   778 	 *
   807 	 *
   779 	 * @param string $body Body content
   808 	 * @param string $body Body content.
   780 	 * @return string Chunked decoded body on success or raw body on failure.
   809 	 * @return string Chunked decoded body on success or raw body on failure.
   781 	 */
   810 	 */
   782 	public static function chunkTransferDecode( $body ) {
   811 	public static function chunkTransferDecode( $body ) { // phpcs:ignore WordPress.NamingConventions.ValidFunctionName.MethodNameInvalid
   783 		// The body is not chunked encoded or is malformed.
   812 		// The body is not chunked encoded or is malformed.
   784 		if ( ! preg_match( '/^([0-9a-f]+)[^\r\n]*\r\n/i', trim( $body ) ) ) {
   813 		if ( ! preg_match( '/^([0-9a-f]+)[^\r\n]*\r\n/i', trim( $body ) ) ) {
   785 			return $body;
   814 			return $body;
   786 		}
   815 		}
   787 
   816 
   811 			}
   840 			}
   812 		}
   841 		}
   813 	}
   842 	}
   814 
   843 
   815 	/**
   844 	/**
   816 	 * Block requests through the proxy.
   845 	 * Determines whether an HTTP API request to the given URL should be blocked.
   817 	 *
   846 	 *
   818 	 * Those who are behind a proxy and want to prevent access to certain hosts may do so. This will
   847 	 * Those who are behind a proxy and want to prevent access to certain hosts may do so. This will
   819 	 * prevent plugins from working and core functionality, if you don't include api.wordpress.org.
   848 	 * prevent plugins from working and core functionality, if you don't include `api.wordpress.org`.
   820 	 *
   849 	 *
   821 	 * You block external URL requests by defining WP_HTTP_BLOCK_EXTERNAL as true in your wp-config.php
   850 	 * You block external URL requests by defining `WP_HTTP_BLOCK_EXTERNAL` as true in your `wp-config.php`
   822 	 * file and this will only allow localhost and your site to make requests. The constant
   851 	 * file and this will only allow localhost and your site to make requests. The constant
   823 	 * WP_ACCESSIBLE_HOSTS will allow additional hosts to go through for requests. The format of the
   852 	 * `WP_ACCESSIBLE_HOSTS` will allow additional hosts to go through for requests. The format of the
   824 	 * WP_ACCESSIBLE_HOSTS constant is a comma separated list of hostnames to allow, wildcard domains
   853 	 * `WP_ACCESSIBLE_HOSTS` constant is a comma separated list of hostnames to allow, wildcard domains
   825 	 * are supported, eg *.wordpress.org will allow for all subdomains of wordpress.org to be contacted.
   854 	 * are supported, eg `*.wordpress.org` will allow for all subdomains of `wordpress.org` to be contacted.
   826 	 *
   855 	 *
   827 	 * @since 2.8.0
   856 	 * @since 2.8.0
       
   857 	 *
   828 	 * @link https://core.trac.wordpress.org/ticket/8927 Allow preventing external requests.
   858 	 * @link https://core.trac.wordpress.org/ticket/8927 Allow preventing external requests.
   829 	 * @link https://core.trac.wordpress.org/ticket/14636 Allow wildcard domains in WP_ACCESSIBLE_HOSTS
   859 	 * @link https://core.trac.wordpress.org/ticket/14636 Allow wildcard domains in WP_ACCESSIBLE_HOSTS
   830 	 *
       
   831 	 * @staticvar array|null $accessible_hosts
       
   832 	 * @staticvar array      $wildcard_regex
       
   833 	 *
   860 	 *
   834 	 * @param string $uri URI of url.
   861 	 * @param string $uri URI of url.
   835 	 * @return bool True to block, false to allow.
   862 	 * @return bool True to block, false to allow.
   836 	 */
   863 	 */
   837 	public function block_request( $uri ) {
   864 	public function block_request( $uri ) {
   846 		}
   873 		}
   847 
   874 
   848 		$home = parse_url( get_option( 'siteurl' ) );
   875 		$home = parse_url( get_option( 'siteurl' ) );
   849 
   876 
   850 		// Don't block requests back to ourselves by default.
   877 		// Don't block requests back to ourselves by default.
   851 		if ( 'localhost' == $check['host'] || ( isset( $home['host'] ) && $home['host'] == $check['host'] ) ) {
   878 		if ( 'localhost' === $check['host'] || ( isset( $home['host'] ) && $home['host'] == $check['host'] ) ) {
   852 			/**
   879 			/**
   853 			 * Filters whether to block local requests through the proxy.
   880 			 * Filters whether to block local HTTP API requests.
       
   881 			 *
       
   882 			 * A local request is one to `localhost` or to the same host as the site itself.
   854 			 *
   883 			 *
   855 			 * @since 2.8.0
   884 			 * @since 2.8.0
   856 			 *
   885 			 *
   857 			 * @param bool $block Whether to block local requests through proxy.
   886 			 * @param bool $block Whether to block local requests. Default false.
   858 			 *                    Default false.
       
   859 			 */
   887 			 */
   860 			return apply_filters( 'block_local_requests', false );
   888 			return apply_filters( 'block_local_requests', false );
   861 		}
   889 		}
   862 
   890 
   863 		if ( ! defined( 'WP_ACCESSIBLE_HOSTS' ) ) {
   891 		if ( ! defined( 'WP_ACCESSIBLE_HOSTS' ) ) {
   879 		}
   907 		}
   880 
   908 
   881 		if ( ! empty( $wildcard_regex ) ) {
   909 		if ( ! empty( $wildcard_regex ) ) {
   882 			return ! preg_match( $wildcard_regex, $check['host'] );
   910 			return ! preg_match( $wildcard_regex, $check['host'] );
   883 		} else {
   911 		} else {
   884 			return ! in_array( $check['host'], $accessible_hosts ); //Inverse logic, If it's in the array, then we can't access it.
   912 			return ! in_array( $check['host'], $accessible_hosts, true ); // Inverse logic, if it's in the array, then don't block it.
   885 		}
   913 		}
   886 
   914 
   887 	}
   915 	}
   888 
   916 
   889 	/**
   917 	/**
   906 	 *
   934 	 *
   907 	 * If an Absolute URL is provided, no processing of that URL is done.
   935 	 * If an Absolute URL is provided, no processing of that URL is done.
   908 	 *
   936 	 *
   909 	 * @since 3.4.0
   937 	 * @since 3.4.0
   910 	 *
   938 	 *
   911 	 * @param string $maybe_relative_path The URL which might be relative
   939 	 * @param string $maybe_relative_path The URL which might be relative.
   912 	 * @param string $url                 The URL which $maybe_relative_path is relative to
   940 	 * @param string $url                 The URL which $maybe_relative_path is relative to.
   913 	 * @return string An Absolute URL, in a failure condition where the URL cannot be parsed, the relative URL will be returned.
   941 	 * @return string An Absolute URL, in a failure condition where the URL cannot be parsed, the relative URL will be returned.
   914 	 */
   942 	 */
   915 	public static function make_absolute_url( $maybe_relative_path, $url ) {
   943 	public static function make_absolute_url( $maybe_relative_path, $url ) {
   916 		if ( empty( $url ) ) {
   944 		if ( empty( $url ) ) {
   917 			return $maybe_relative_path;
   945 			return $maybe_relative_path;
   918 		}
   946 		}
   919 
   947 
   920 		if ( ! $url_parts = wp_parse_url( $url ) ) {
   948 		$url_parts = wp_parse_url( $url );
       
   949 		if ( ! $url_parts ) {
   921 			return $maybe_relative_path;
   950 			return $maybe_relative_path;
   922 		}
   951 		}
   923 
   952 
   924 		if ( ! $relative_url_parts = wp_parse_url( $maybe_relative_path ) ) {
   953 		$relative_url_parts = wp_parse_url( $maybe_relative_path );
       
   954 		if ( ! $relative_url_parts ) {
   925 			return $maybe_relative_path;
   955 			return $maybe_relative_path;
   926 		}
   956 		}
   927 
   957 
   928 		// Check for a scheme on the 'relative' url
   958 		// Check for a scheme on the 'relative' URL.
   929 		if ( ! empty( $relative_url_parts['scheme'] ) ) {
   959 		if ( ! empty( $relative_url_parts['scheme'] ) ) {
   930 			return $maybe_relative_path;
   960 			return $maybe_relative_path;
   931 		}
   961 		}
   932 
   962 
   933 		$absolute_path = $url_parts['scheme'] . '://';
   963 		$absolute_path = $url_parts['scheme'] . '://';
   934 
   964 
   935 		// Schemeless URL's will make it this far, so we check for a host in the relative url and convert it to a protocol-url
   965 		// Schemeless URLs will make it this far, so we check for a host in the relative URL
       
   966 		// and convert it to a protocol-URL.
   936 		if ( isset( $relative_url_parts['host'] ) ) {
   967 		if ( isset( $relative_url_parts['host'] ) ) {
   937 			$absolute_path .= $relative_url_parts['host'];
   968 			$absolute_path .= $relative_url_parts['host'];
   938 			if ( isset( $relative_url_parts['port'] ) ) {
   969 			if ( isset( $relative_url_parts['port'] ) ) {
   939 				$absolute_path .= ':' . $relative_url_parts['port'];
   970 				$absolute_path .= ':' . $relative_url_parts['port'];
   940 			}
   971 			}
   943 			if ( isset( $url_parts['port'] ) ) {
   974 			if ( isset( $url_parts['port'] ) ) {
   944 				$absolute_path .= ':' . $url_parts['port'];
   975 				$absolute_path .= ':' . $url_parts['port'];
   945 			}
   976 			}
   946 		}
   977 		}
   947 
   978 
   948 		// Start off with the Absolute URL path.
   979 		// Start off with the absolute URL path.
   949 		$path = ! empty( $url_parts['path'] ) ? $url_parts['path'] : '/';
   980 		$path = ! empty( $url_parts['path'] ) ? $url_parts['path'] : '/';
   950 
   981 
   951 		// If it's a root-relative path, then great.
   982 		// If it's a root-relative path, then great.
   952 		if ( ! empty( $relative_url_parts['path'] ) && '/' == $relative_url_parts['path'][0] ) {
   983 		if ( ! empty( $relative_url_parts['path'] ) && '/' === $relative_url_parts['path'][0] ) {
   953 			$path = $relative_url_parts['path'];
   984 			$path = $relative_url_parts['path'];
   954 
   985 
   955 			// Else it's a relative path.
   986 			// Else it's a relative path.
   956 		} elseif ( ! empty( $relative_url_parts['path'] ) ) {
   987 		} elseif ( ! empty( $relative_url_parts['path'] ) ) {
   957 			// Strip off any file components from the absolute path.
   988 			// Strip off any file components from the absolute path.
   967 
   998 
   968 			// Strip any final leading ../ from the path.
   999 			// Strip any final leading ../ from the path.
   969 			$path = preg_replace( '!^/(\.\./)+!', '', $path );
  1000 			$path = preg_replace( '!^/(\.\./)+!', '', $path );
   970 		}
  1001 		}
   971 
  1002 
   972 		// Add the Query string.
  1003 		// Add the query string.
   973 		if ( ! empty( $relative_url_parts['query'] ) ) {
  1004 		if ( ! empty( $relative_url_parts['query'] ) ) {
   974 			$path .= '?' . $relative_url_parts['query'];
  1005 			$path .= '?' . $relative_url_parts['query'];
   975 		}
  1006 		}
   976 
  1007 
   977 		return $absolute_path . '/' . ltrim( $path, '/' );
  1008 		return $absolute_path . '/' . ltrim( $path, '/' );
   978 	}
  1009 	}
   979 
  1010 
   980 	/**
  1011 	/**
   981 	 * Handles HTTP Redirects and follows them if appropriate.
  1012 	 * Handles an HTTP redirect and follows it if appropriate.
   982 	 *
  1013 	 *
   983 	 * @since 3.7.0
  1014 	 * @since 3.7.0
   984 	 *
  1015 	 *
   985 	 * @param string $url The URL which was requested.
  1016 	 * @param string $url      The URL which was requested.
   986 	 * @param array $args The Arguments which were used to make the request.
  1017 	 * @param array  $args     The arguments which were used to make the request.
   987 	 * @param array $response The Response of the HTTP request.
  1018 	 * @param array  $response The response of the HTTP request.
   988 	 * @return false|object False if no redirect is present, a WP_HTTP or WP_Error result otherwise.
  1019 	 * @return array|false|WP_Error An HTTP API response array if the redirect is successfully followed,
       
  1020 	 *                              false if no redirect is present, or a WP_Error object if there's an error.
   989 	 */
  1021 	 */
   990 	public static function handle_redirects( $url, $args, $response ) {
  1022 	public static function handle_redirects( $url, $args, $response ) {
   991 		// If no redirects are present, or, redirects were not requested, perform no action.
  1023 		// If no redirects are present, or, redirects were not requested, perform no action.
   992 		if ( ! isset( $response['headers']['location'] ) || 0 === $args['_redirection'] ) {
  1024 		if ( ! isset( $response['headers']['location'] ) || 0 === $args['_redirection'] ) {
   993 			return false;
  1025 			return false;
  1011 		}
  1043 		}
  1012 
  1044 
  1013 		$redirect_location = WP_Http::make_absolute_url( $redirect_location, $url );
  1045 		$redirect_location = WP_Http::make_absolute_url( $redirect_location, $url );
  1014 
  1046 
  1015 		// POST requests should not POST to a redirected location.
  1047 		// POST requests should not POST to a redirected location.
  1016 		if ( 'POST' == $args['method'] ) {
  1048 		if ( 'POST' === $args['method'] ) {
  1017 			if ( in_array( $response['response']['code'], array( 302, 303 ) ) ) {
  1049 			if ( in_array( $response['response']['code'], array( 302, 303 ), true ) ) {
  1018 				$args['method'] = 'GET';
  1050 				$args['method'] = 'GET';
  1019 			}
  1051 			}
  1020 		}
  1052 		}
  1021 
  1053 
  1022 		// Include valid cookies in the redirect process.
  1054 		// Include valid cookies in the redirect process.
  1037 	 * This function also detects the type of the IP address, returning either
  1069 	 * This function also detects the type of the IP address, returning either
  1038 	 * '4' or '6' to represent a IPv4 and IPv6 address respectively.
  1070 	 * '4' or '6' to represent a IPv4 and IPv6 address respectively.
  1039 	 * This does not verify if the IP is a valid IP, only that it appears to be
  1071 	 * This does not verify if the IP is a valid IP, only that it appears to be
  1040 	 * an IP address.
  1072 	 * an IP address.
  1041 	 *
  1073 	 *
  1042 	 * @link http://home.deds.nl/~aeron/regex/ for IPv6 regex
  1074 	 * @link http://home.deds.nl/~aeron/regex/ for IPv6 regex.
  1043 	 *
  1075 	 *
  1044 	 * @since 3.7.0
  1076 	 * @since 3.7.0
  1045 	 *
  1077 	 *
  1046 	 * @param string $maybe_ip A suspected IP address
  1078 	 * @param string $maybe_ip A suspected IP address.
  1047 	 * @return integer|bool Upon success, '4' or '6' to represent a IPv4 or IPv6 address, false upon failure
  1079 	 * @return integer|bool Upon success, '4' or '6' to represent a IPv4 or IPv6 address, false upon failure
  1048 	 */
  1080 	 */
  1049 	public static function is_ip_address( $maybe_ip ) {
  1081 	public static function is_ip_address( $maybe_ip ) {
  1050 		if ( preg_match( '/^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/', $maybe_ip ) ) {
  1082 		if ( preg_match( '/^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/', $maybe_ip ) ) {
  1051 			return 4;
  1083 			return 4;