wp/wp-includes/class-wp-http.php
changeset 21 48c4eec2b7e6
parent 19 3d72ae0968f4
child 22 8c2e4d02f4ef
equal deleted inserted replaced
20:7b1b88e27a20 21:48c4eec2b7e6
     5  * @package WordPress
     5  * @package WordPress
     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( 'WpOrg\Requests\Autoload' ) ) {
    11 	require ABSPATH . WPINC . '/class-requests.php';
    11 	require ABSPATH . WPINC . '/Requests/src/Autoload.php';
    12 
    12 
    13 	Requests::register_autoloader();
    13 	WpOrg\Requests\Autoload::register();
    14 	Requests::set_certificate_path( ABSPATH . WPINC . '/certificates/ca-bundle.crt' );
    14 	WpOrg\Requests\Requests::set_certificate_path( ABSPATH . WPINC . '/certificates/ca-bundle.crt' );
    15 }
    15 }
    16 
    16 
    17 /**
    17 /**
    18  * Core class used for managing HTTP transports and making HTTP requests.
    18  * Core class used for managing HTTP transports and making HTTP requests.
    19  *
    19  *
    23  *
    23  *
    24  * Debugging includes several actions, which pass different variables for debugging the HTTP API.
    24  * Debugging includes several actions, which pass different variables for debugging the HTTP API.
    25  *
    25  *
    26  * @since 2.7.0
    26  * @since 2.7.0
    27  */
    27  */
       
    28 #[AllowDynamicProperties]
    28 class WP_Http {
    29 class WP_Http {
    29 
    30 
    30 	// Aliases for HTTP response codes.
    31 	// Aliases for HTTP response codes.
    31 	const HTTP_CONTINUE       = 100;
    32 	const HTTP_CONTINUE       = 100;
    32 	const SWITCHING_PROTOCOLS = 101;
    33 	const SWITCHING_PROTOCOLS = 101;
    74 	const IM_A_TEAPOT                     = 418;
    75 	const IM_A_TEAPOT                     = 418;
    75 	const MISDIRECTED_REQUEST             = 421;
    76 	const MISDIRECTED_REQUEST             = 421;
    76 	const UNPROCESSABLE_ENTITY            = 422;
    77 	const UNPROCESSABLE_ENTITY            = 422;
    77 	const LOCKED                          = 423;
    78 	const LOCKED                          = 423;
    78 	const FAILED_DEPENDENCY               = 424;
    79 	const FAILED_DEPENDENCY               = 424;
       
    80 	const TOO_EARLY                       = 425;
    79 	const UPGRADE_REQUIRED                = 426;
    81 	const UPGRADE_REQUIRED                = 426;
    80 	const PRECONDITION_REQUIRED           = 428;
    82 	const PRECONDITION_REQUIRED           = 428;
    81 	const TOO_MANY_REQUESTS               = 429;
    83 	const TOO_MANY_REQUESTS               = 429;
    82 	const REQUEST_HEADER_FIELDS_TOO_LARGE = 431;
    84 	const REQUEST_HEADER_FIELDS_TOO_LARGE = 431;
    83 	const UNAVAILABLE_FOR_LEGAL_REASONS   = 451;
    85 	const UNAVAILABLE_FOR_LEGAL_REASONS   = 451;
   244 		 *
   246 		 *
   245 		 *  - An array containing 'headers', 'body', 'response', 'cookies', and 'filename' elements
   247 		 *  - An array containing 'headers', 'body', 'response', 'cookies', and 'filename' elements
   246 		 *  - A WP_Error instance
   248 		 *  - A WP_Error instance
   247 		 *  - boolean false to avoid short-circuiting the response
   249 		 *  - boolean false to avoid short-circuiting the response
   248 		 *
   250 		 *
   249 		 * Returning any other value may result in unexpected behaviour.
   251 		 * Returning any other value may result in unexpected behavior.
   250 		 *
   252 		 *
   251 		 * @since 2.9.0
   253 		 * @since 2.9.0
   252 		 *
   254 		 *
   253 		 * @param false|array|WP_Error $preempt     A preemptive return value of an HTTP request. Default false.
   255 		 * @param false|array|WP_Error $response    A preemptive return value of an HTTP request. Default false.
   254 		 * @param array                $parsed_args HTTP request arguments.
   256 		 * @param array                $parsed_args HTTP request arguments.
   255 		 * @param string               $url         The request URL.
   257 		 * @param string               $url         The request URL.
   256 		 */
   258 		 */
   257 		$pre = apply_filters( 'pre_http_request', false, $parsed_args, $url );
   259 		$pre = apply_filters( 'pre_http_request', false, $parsed_args, $url );
   258 
   260 
   272 		$parsed_url = parse_url( $url );
   274 		$parsed_url = parse_url( $url );
   273 
   275 
   274 		if ( empty( $url ) || empty( $parsed_url['scheme'] ) ) {
   276 		if ( empty( $url ) || empty( $parsed_url['scheme'] ) ) {
   275 			$response = new WP_Error( 'http_request_failed', __( 'A valid URL was not provided.' ) );
   277 			$response = new WP_Error( 'http_request_failed', __( 'A valid URL was not provided.' ) );
   276 			/** This action is documented in wp-includes/class-wp-http.php */
   278 			/** This action is documented in wp-includes/class-wp-http.php */
   277 			do_action( 'http_api_debug', $response, 'response', 'Requests', $parsed_args, $url );
   279 			do_action( 'http_api_debug', $response, 'response', 'WpOrg\Requests\Requests', $parsed_args, $url );
   278 			return $response;
   280 			return $response;
   279 		}
   281 		}
   280 
   282 
   281 		if ( $this->block_request( $url ) ) {
   283 		if ( $this->block_request( $url ) ) {
   282 			$response = new WP_Error( 'http_request_not_executed', __( 'User has blocked requests through HTTP.' ) );
   284 			$response = new WP_Error( 'http_request_not_executed', __( 'User has blocked requests through HTTP.' ) );
   283 			/** This action is documented in wp-includes/class-wp-http.php */
   285 			/** This action is documented in wp-includes/class-wp-http.php */
   284 			do_action( 'http_api_debug', $response, 'response', 'Requests', $parsed_args, $url );
   286 			do_action( 'http_api_debug', $response, 'response', 'WpOrg\Requests\Requests', $parsed_args, $url );
   285 			return $response;
   287 			return $response;
   286 		}
   288 		}
   287 
   289 
   288 		// If we are streaming to a file but no filename was given drop it in the WP temp dir
   290 		// If we are streaming to a file but no filename was given drop it in the WP temp dir
   289 		// and pick its name using the basename of the $url.
   291 		// and pick its name using the basename of the $url.
   296 			// and perms of destination directory.
   298 			// and perms of destination directory.
   297 			$parsed_args['blocking'] = true;
   299 			$parsed_args['blocking'] = true;
   298 			if ( ! wp_is_writable( dirname( $parsed_args['filename'] ) ) ) {
   300 			if ( ! wp_is_writable( dirname( $parsed_args['filename'] ) ) ) {
   299 				$response = new WP_Error( 'http_request_failed', __( 'Destination directory for file streaming does not exist or is not writable.' ) );
   301 				$response = new WP_Error( 'http_request_failed', __( 'Destination directory for file streaming does not exist or is not writable.' ) );
   300 				/** This action is documented in wp-includes/class-wp-http.php */
   302 				/** This action is documented in wp-includes/class-wp-http.php */
   301 				do_action( 'http_api_debug', $response, 'response', 'Requests', $parsed_args, $url );
   303 				do_action( 'http_api_debug', $response, 'response', 'WpOrg\Requests\Requests', $parsed_args, $url );
   302 				return $response;
   304 				return $response;
   303 			}
   305 			}
   304 		}
   306 		}
   305 
   307 
   306 		if ( is_null( $parsed_args['headers'] ) ) {
   308 		if ( is_null( $parsed_args['headers'] ) ) {
   322 			'useragent' => $parsed_args['user-agent'],
   324 			'useragent' => $parsed_args['user-agent'],
   323 			'blocking'  => $parsed_args['blocking'],
   325 			'blocking'  => $parsed_args['blocking'],
   324 			'hooks'     => new WP_HTTP_Requests_Hooks( $url, $parsed_args ),
   326 			'hooks'     => new WP_HTTP_Requests_Hooks( $url, $parsed_args ),
   325 		);
   327 		);
   326 
   328 
   327 		// Ensure redirects follow browser behaviour.
   329 		// Ensure redirects follow browser behavior.
   328 		$options['hooks']->register( 'requests.before_redirect', array( get_class(), 'browser_redirect_compatibility' ) );
   330 		$options['hooks']->register( 'requests.before_redirect', array( static::class, 'browser_redirect_compatibility' ) );
   329 
   331 
   330 		// Validate redirected URLs.
   332 		// Validate redirected URLs.
   331 		if ( function_exists( 'wp_kses_bad_protocol' ) && $parsed_args['reject_unsafe_urls'] ) {
   333 		if ( function_exists( 'wp_kses_bad_protocol' ) && $parsed_args['reject_unsafe_urls'] ) {
   332 			$options['hooks']->register( 'requests.before_redirect', array( get_class(), 'validate_redirects' ) );
   334 			$options['hooks']->register( 'requests.before_redirect', array( static::class, 'validate_redirects' ) );
   333 		}
   335 		}
   334 
   336 
   335 		if ( $parsed_args['stream'] ) {
   337 		if ( $parsed_args['stream'] ) {
   336 			$options['filename'] = $parsed_args['filename'];
   338 			$options['filename'] = $parsed_args['filename'];
   337 		}
   339 		}
   344 		// Use byte limit, if we can.
   346 		// Use byte limit, if we can.
   345 		if ( isset( $parsed_args['limit_response_size'] ) ) {
   347 		if ( isset( $parsed_args['limit_response_size'] ) ) {
   346 			$options['max_bytes'] = $parsed_args['limit_response_size'];
   348 			$options['max_bytes'] = $parsed_args['limit_response_size'];
   347 		}
   349 		}
   348 
   350 
   349 		// If we've got cookies, use and convert them to Requests_Cookie.
   351 		// If we've got cookies, use and convert them to WpOrg\Requests\Cookie.
   350 		if ( ! empty( $parsed_args['cookies'] ) ) {
   352 		if ( ! empty( $parsed_args['cookies'] ) ) {
   351 			$options['cookies'] = WP_Http::normalize_cookies( $parsed_args['cookies'] );
   353 			$options['cookies'] = WP_Http::normalize_cookies( $parsed_args['cookies'] );
   352 		}
   354 		}
   353 
   355 
   354 		// SSL certificate handling.
   356 		// SSL certificate handling.
   368 		 * Filters whether SSL should be verified for non-local requests.
   370 		 * Filters whether SSL should be verified for non-local requests.
   369 		 *
   371 		 *
   370 		 * @since 2.8.0
   372 		 * @since 2.8.0
   371 		 * @since 5.1.0 The `$url` parameter was added.
   373 		 * @since 5.1.0 The `$url` parameter was added.
   372 		 *
   374 		 *
   373 		 * @param bool   $ssl_verify Whether to verify the SSL connection. Default true.
   375 		 * @param bool|string $ssl_verify Boolean to control whether to verify the SSL connection
   374 		 * @param string $url        The request URL.
   376 		 *                                or path to an SSL certificate.
       
   377 		 * @param string      $url        The request URL.
   375 		 */
   378 		 */
   376 		$options['verify'] = apply_filters( 'https_ssl_verify', $options['verify'], $url );
   379 		$options['verify'] = apply_filters( 'https_ssl_verify', $options['verify'], $url );
   377 
   380 
   378 		// Check for proxies.
   381 		// Check for proxies.
   379 		$proxy = new WP_HTTP_Proxy();
   382 		$proxy = new WP_HTTP_Proxy();
   380 		if ( $proxy->is_enabled() && $proxy->send_through_proxy( $url ) ) {
   383 		if ( $proxy->is_enabled() && $proxy->send_through_proxy( $url ) ) {
   381 			$options['proxy'] = new Requests_Proxy_HTTP( $proxy->host() . ':' . $proxy->port() );
   384 			$options['proxy'] = new WpOrg\Requests\Proxy\Http( $proxy->host() . ':' . $proxy->port() );
   382 
   385 
   383 			if ( $proxy->use_authentication() ) {
   386 			if ( $proxy->use_authentication() ) {
   384 				$options['proxy']->use_authentication = true;
   387 				$options['proxy']->use_authentication = true;
   385 				$options['proxy']->user               = $proxy->username();
   388 				$options['proxy']->user               = $proxy->username();
   386 				$options['proxy']->pass               = $proxy->password();
   389 				$options['proxy']->pass               = $proxy->password();
   389 
   392 
   390 		// Avoid issues where mbstring.func_overload is enabled.
   393 		// Avoid issues where mbstring.func_overload is enabled.
   391 		mbstring_binary_safe_encoding();
   394 		mbstring_binary_safe_encoding();
   392 
   395 
   393 		try {
   396 		try {
   394 			$requests_response = Requests::request( $url, $headers, $data, $type, $options );
   397 			$requests_response = WpOrg\Requests\Requests::request( $url, $headers, $data, $type, $options );
   395 
   398 
   396 			// Convert the response into an array.
   399 			// Convert the response into an array.
   397 			$http_response = new WP_HTTP_Requests_Response( $requests_response, $parsed_args['filename'] );
   400 			$http_response = new WP_HTTP_Requests_Response( $requests_response, $parsed_args['filename'] );
   398 			$response      = $http_response->to_array();
   401 			$response      = $http_response->to_array();
   399 
   402 
   400 			// Add the original object to the array.
   403 			// Add the original object to the array.
   401 			$response['http_response'] = $http_response;
   404 			$response['http_response'] = $http_response;
   402 		} catch ( Requests_Exception $e ) {
   405 		} catch ( WpOrg\Requests\Exception $e ) {
   403 			$response = new WP_Error( 'http_request_failed', $e->getMessage() );
   406 			$response = new WP_Error( 'http_request_failed', $e->getMessage() );
   404 		}
   407 		}
   405 
   408 
   406 		reset_mbstring_encoding();
   409 		reset_mbstring_encoding();
   407 
   410 
   414 		 * @param string         $context     Context under which the hook is fired.
   417 		 * @param string         $context     Context under which the hook is fired.
   415 		 * @param string         $class       HTTP transport used.
   418 		 * @param string         $class       HTTP transport used.
   416 		 * @param array          $parsed_args HTTP request arguments.
   419 		 * @param array          $parsed_args HTTP request arguments.
   417 		 * @param string         $url         The request URL.
   420 		 * @param string         $url         The request URL.
   418 		 */
   421 		 */
   419 		do_action( 'http_api_debug', $response, 'response', 'Requests', $parsed_args, $url );
   422 		do_action( 'http_api_debug', $response, 'response', 'WpOrg\Requests\Requests', $parsed_args, $url );
   420 		if ( is_wp_error( $response ) ) {
   423 		if ( is_wp_error( $response ) ) {
   421 			return $response;
   424 			return $response;
   422 		}
   425 		}
   423 
   426 
   424 		if ( ! $parsed_args['blocking'] ) {
   427 		if ( ! $parsed_args['blocking'] ) {
   450 	 * Normalizes cookies for using in Requests.
   453 	 * Normalizes cookies for using in Requests.
   451 	 *
   454 	 *
   452 	 * @since 4.6.0
   455 	 * @since 4.6.0
   453 	 *
   456 	 *
   454 	 * @param array $cookies Array of cookies to send with the request.
   457 	 * @param array $cookies Array of cookies to send with the request.
   455 	 * @return Requests_Cookie_Jar Cookie holder object.
   458 	 * @return WpOrg\Requests\Cookie\Jar Cookie holder object.
   456 	 */
   459 	 */
   457 	public static function normalize_cookies( $cookies ) {
   460 	public static function normalize_cookies( $cookies ) {
   458 		$cookie_jar = new Requests_Cookie_Jar();
   461 		$cookie_jar = new WpOrg\Requests\Cookie\Jar();
   459 
   462 
   460 		foreach ( $cookies as $name => $value ) {
   463 		foreach ( $cookies as $name => $value ) {
   461 			if ( $value instanceof WP_Http_Cookie ) {
   464 			if ( $value instanceof WP_Http_Cookie ) {
   462 				$attributes                 = array_filter(
   465 				$attributes                 = array_filter(
   463 					$value->get_attributes(),
   466 					$value->get_attributes(),
   464 					static function( $attr ) {
   467 					static function ( $attr ) {
   465 						return null !== $attr;
   468 						return null !== $attr;
   466 					}
   469 					}
   467 				);
   470 				);
   468 				$cookie_jar[ $value->name ] = new Requests_Cookie( $value->name, $value->value, $attributes, array( 'host-only' => $value->host_only ) );
   471 				$cookie_jar[ $value->name ] = new WpOrg\Requests\Cookie( (string) $value->name, $value->value, $attributes, array( 'host-only' => $value->host_only ) );
   469 			} elseif ( is_scalar( $value ) ) {
   472 			} elseif ( is_scalar( $value ) ) {
   470 				$cookie_jar[ $name ] = new Requests_Cookie( $name, $value );
   473 				$cookie_jar[ $name ] = new WpOrg\Requests\Cookie( (string) $name, (string) $value );
   471 			}
   474 			}
   472 		}
   475 		}
   473 
   476 
   474 		return $cookie_jar;
   477 		return $cookie_jar;
   475 	}
   478 	}
   476 
   479 
   477 	/**
   480 	/**
   478 	 * Match redirect behaviour to browser handling.
   481 	 * Match redirect behavior to browser handling.
   479 	 *
   482 	 *
   480 	 * Changes 302 redirects from POST to GET to match browser handling. Per
   483 	 * Changes 302 redirects from POST to GET to match browser handling. Per
   481 	 * RFC 7231, user agents can deviate from the strict reading of the
   484 	 * RFC 7231, user agents can deviate from the strict reading of the
   482 	 * specification for compatibility purposes.
   485 	 * specification for compatibility purposes.
   483 	 *
   486 	 *
   484 	 * @since 4.6.0
   487 	 * @since 4.6.0
   485 	 *
   488 	 *
   486 	 * @param string            $location URL to redirect to.
   489 	 * @param string                  $location URL to redirect to.
   487 	 * @param array             $headers  Headers for the redirect.
   490 	 * @param array                   $headers  Headers for the redirect.
   488 	 * @param string|array      $data     Body to send with the request.
   491 	 * @param string|array            $data     Body to send with the request.
   489 	 * @param array             $options  Redirect request options.
   492 	 * @param array                   $options  Redirect request options.
   490 	 * @param Requests_Response $original Response object.
   493 	 * @param WpOrg\Requests\Response $original Response object.
   491 	 */
   494 	 */
   492 	public static function browser_redirect_compatibility( $location, $headers, $data, &$options, $original ) {
   495 	public static function browser_redirect_compatibility( $location, $headers, $data, &$options, $original ) {
   493 		// Browser compatibility.
   496 		// Browser compatibility.
   494 		if ( 302 === $original->status_code ) {
   497 		if ( 302 === $original->status_code ) {
   495 			$options['type'] = Requests::GET;
   498 			$options['type'] = WpOrg\Requests\Requests::GET;
   496 		}
   499 		}
   497 	}
   500 	}
   498 
   501 
   499 	/**
   502 	/**
   500 	 * Validate redirected URLs.
   503 	 * Validate redirected URLs.
   501 	 *
   504 	 *
   502 	 * @since 4.7.5
   505 	 * @since 4.7.5
   503 	 *
   506 	 *
   504 	 * @throws Requests_Exception On unsuccessful URL validation.
   507 	 * @throws WpOrg\Requests\Exception On unsuccessful URL validation.
   505 	 * @param string $location URL to redirect to.
   508 	 * @param string $location URL to redirect to.
   506 	 */
   509 	 */
   507 	public static function validate_redirects( $location ) {
   510 	public static function validate_redirects( $location ) {
   508 		if ( ! wp_http_validate_url( $location ) ) {
   511 		if ( ! wp_http_validate_url( $location ) ) {
   509 			throw new Requests_Exception( __( 'A valid URL was not provided.' ), 'wp_http.redirect_failed_validation' );
   512 			throw new WpOrg\Requests\Exception( __( 'A valid URL was not provided.' ), 'wp_http.redirect_failed_validation' );
   510 		}
   513 		}
   511 	}
   514 	}
   512 
   515 
   513 	/**
   516 	/**
   514 	 * Tests which transports are capable of supporting the request.
   517 	 * Tests which transports are capable of supporting the request.
   515 	 *
   518 	 *
   516 	 * @since 3.2.0
   519 	 * @since 3.2.0
       
   520 	 * @deprecated 6.4.0 Use WpOrg\Requests\Requests::get_transport_class()
       
   521 	 * @see WpOrg\Requests\Requests::get_transport_class()
   517 	 *
   522 	 *
   518 	 * @param array  $args Request arguments.
   523 	 * @param array  $args Request arguments.
   519 	 * @param string $url  URL to request.
   524 	 * @param string $url  URL to request.
   520 	 * @return string|false Class name for the first transport that claims to support the request.
   525 	 * @return string|false Class name for the first transport that claims to support the request.
   521 	 *                      False if no transport claims to support the request.
   526 	 *                      False if no transport claims to support the request.
   525 
   530 
   526 		/**
   531 		/**
   527 		 * Filters which HTTP transports are available and in what order.
   532 		 * Filters which HTTP transports are available and in what order.
   528 		 *
   533 		 *
   529 		 * @since 3.7.0
   534 		 * @since 3.7.0
       
   535 		 * @deprecated 6.4.0 Use WpOrg\Requests\Requests::get_transport_class()
   530 		 *
   536 		 *
   531 		 * @param string[] $transports Array of HTTP transports to check. Default array contains
   537 		 * @param string[] $transports Array of HTTP transports to check. Default array contains
   532 		 *                             'curl' and 'streams', in that order.
   538 		 *                             'curl' and 'streams', in that order.
   533 		 * @param array    $args       HTTP request arguments.
   539 		 * @param array    $args       HTTP request arguments.
   534 		 * @param string   $url        The URL to request.
   540 		 * @param string   $url        The URL to request.
   535 		 */
   541 		 */
   536 		$request_order = apply_filters( 'http_api_transports', $transports, $args, $url );
   542 		$request_order = apply_filters_deprecated( 'http_api_transports', array( $transports, $args, $url ), '6.4.0' );
   537 
   543 
   538 		// Loop over each transport on each HTTP request looking for one which will serve this request's needs.
   544 		// Loop over each transport on each HTTP request looking for one which will serve this request's needs.
   539 		foreach ( $request_order as $transport ) {
   545 		foreach ( $request_order as $transport ) {
   540 			if ( in_array( $transport, $transports, true ) ) {
   546 			if ( in_array( $transport, $transports, true ) ) {
   541 				$transport = ucfirst( $transport );
   547 				$transport = ucfirst( $transport );
   578 			return new WP_Error( 'http_failure', __( 'There are no HTTP transports available which can complete the requested request.' ) );
   584 			return new WP_Error( 'http_failure', __( 'There are no HTTP transports available which can complete the requested request.' ) );
   579 		}
   585 		}
   580 
   586 
   581 		// Transport claims to support request, instantiate it and give it a whirl.
   587 		// Transport claims to support request, instantiate it and give it a whirl.
   582 		if ( empty( $transports[ $class ] ) ) {
   588 		if ( empty( $transports[ $class ] ) ) {
   583 			$transports[ $class ] = new $class;
   589 			$transports[ $class ] = new $class();
   584 		}
   590 		}
   585 
   591 
   586 		$response = $transports[ $class ]->request( $url, $args );
   592 		$response = $transports[ $class ]->request( $url, $args );
   587 
   593 
   588 		/** This action is documented in wp-includes/class-wp-http.php */
   594 		/** This action is documented in wp-includes/class-wp-http.php */
   604 	 * @since 2.7.0
   610 	 * @since 2.7.0
   605 	 *
   611 	 *
   606 	 * @param string       $url  The request URL.
   612 	 * @param string       $url  The request URL.
   607 	 * @param string|array $args Optional. Override the defaults.
   613 	 * @param string|array $args Optional. Override the defaults.
   608 	 * @return array|WP_Error Array containing 'headers', 'body', 'response', 'cookies', 'filename'.
   614 	 * @return array|WP_Error Array containing 'headers', 'body', 'response', 'cookies', 'filename'.
   609 	 *                        A WP_Error instance upon error.
   615 	 *                        A WP_Error instance upon error. See WP_Http::response() for details.
   610 	 */
   616 	 */
   611 	public function post( $url, $args = array() ) {
   617 	public function post( $url, $args = array() ) {
   612 		$defaults    = array( 'method' => 'POST' );
   618 		$defaults    = array( 'method' => 'POST' );
   613 		$parsed_args = wp_parse_args( $args, $defaults );
   619 		$parsed_args = wp_parse_args( $args, $defaults );
   614 		return $this->request( $url, $parsed_args );
   620 		return $this->request( $url, $parsed_args );
   622 	 * @since 2.7.0
   628 	 * @since 2.7.0
   623 	 *
   629 	 *
   624 	 * @param string       $url  The request URL.
   630 	 * @param string       $url  The request URL.
   625 	 * @param string|array $args Optional. Override the defaults.
   631 	 * @param string|array $args Optional. Override the defaults.
   626 	 * @return array|WP_Error Array containing 'headers', 'body', 'response', 'cookies', 'filename'.
   632 	 * @return array|WP_Error Array containing 'headers', 'body', 'response', 'cookies', 'filename'.
   627 	 *                        A WP_Error instance upon error.
   633 	 *                        A WP_Error instance upon error. See WP_Http::response() for details.
   628 	 */
   634 	 */
   629 	public function get( $url, $args = array() ) {
   635 	public function get( $url, $args = array() ) {
   630 		$defaults    = array( 'method' => 'GET' );
   636 		$defaults    = array( 'method' => 'GET' );
   631 		$parsed_args = wp_parse_args( $args, $defaults );
   637 		$parsed_args = wp_parse_args( $args, $defaults );
   632 		return $this->request( $url, $parsed_args );
   638 		return $this->request( $url, $parsed_args );
   640 	 * @since 2.7.0
   646 	 * @since 2.7.0
   641 	 *
   647 	 *
   642 	 * @param string       $url  The request URL.
   648 	 * @param string       $url  The request URL.
   643 	 * @param string|array $args Optional. Override the defaults.
   649 	 * @param string|array $args Optional. Override the defaults.
   644 	 * @return array|WP_Error Array containing 'headers', 'body', 'response', 'cookies', 'filename'.
   650 	 * @return array|WP_Error Array containing 'headers', 'body', 'response', 'cookies', 'filename'.
   645 	 *                        A WP_Error instance upon error.
   651 	 *                        A WP_Error instance upon error. See WP_Http::response() for details.
   646 	 */
   652 	 */
   647 	public function head( $url, $args = array() ) {
   653 	public function head( $url, $args = array() ) {
   648 		$defaults    = array( 'method' => 'HEAD' );
   654 		$defaults    = array( 'method' => 'HEAD' );
   649 		$parsed_args = wp_parse_args( $args, $defaults );
   655 		$parsed_args = wp_parse_args( $args, $defaults );
   650 		return $this->request( $url, $parsed_args );
   656 		return $this->request( $url, $parsed_args );
   685 	 * @return array {
   691 	 * @return array {
   686 	 *     Processed string headers. If duplicate headers are encountered,
   692 	 *     Processed string headers. If duplicate headers are encountered,
   687 	 *     then a numbered array is returned as the value of that header-key.
   693 	 *     then a numbered array is returned as the value of that header-key.
   688 	 *
   694 	 *
   689 	 *     @type array            $response {
   695 	 *     @type array            $response {
   690 	 *          @type int    $code    The response status code. Default 0.
   696 	 *         @type int    $code    The response status code. Default 0.
   691 	 *          @type string $message The response message. Default empty.
   697 	 *         @type string $message The response message. Default empty.
   692 	 *     }
   698 	 *     }
   693 	 *     @type array            $newheaders The processed header data as a multidimensional array.
   699 	 *     @type array            $newheaders The processed header data as a multidimensional array.
   694 	 *     @type WP_Http_Cookie[] $cookies    If the original headers contain the 'Set-Cookie' key,
   700 	 *     @type WP_Http_Cookie[] $cookies    If the original headers contain the 'Set-Cookie' key,
   695 	 *                                        an array containing `WP_Http_Cookie` objects is returned.
   701 	 *                                        an array containing `WP_Http_Cookie` objects is returned.
   696 	 * }
   702 	 * }
   717 		/*
   723 		/*
   718 		 * If a redirection has taken place, The headers for each page request may have been passed.
   724 		 * If a redirection has taken place, The headers for each page request may have been passed.
   719 		 * In this case, determine the final HTTP header and parse from there.
   725 		 * In this case, determine the final HTTP header and parse from there.
   720 		 */
   726 		 */
   721 		for ( $i = count( $headers ) - 1; $i >= 0; $i-- ) {
   727 		for ( $i = count( $headers ) - 1; $i >= 0; $i-- ) {
   722 			if ( ! empty( $headers[ $i ] ) && false === strpos( $headers[ $i ], ':' ) ) {
   728 			if ( ! empty( $headers[ $i ] ) && ! str_contains( $headers[ $i ], ':' ) ) {
   723 				$headers = array_splice( $headers, $i );
   729 				$headers = array_splice( $headers, $i );
   724 				break;
   730 				break;
   725 			}
   731 			}
   726 		}
   732 		}
   727 
   733 
   730 		foreach ( (array) $headers as $tempheader ) {
   736 		foreach ( (array) $headers as $tempheader ) {
   731 			if ( empty( $tempheader ) ) {
   737 			if ( empty( $tempheader ) ) {
   732 				continue;
   738 				continue;
   733 			}
   739 			}
   734 
   740 
   735 			if ( false === strpos( $tempheader, ':' ) ) {
   741 			if ( ! str_contains( $tempheader, ':' ) ) {
   736 				$stack   = explode( ' ', $tempheader, 3 );
   742 				$stack   = explode( ' ', $tempheader, 3 );
   737 				$stack[] = '';
   743 				$stack[] = '';
   738 				list( , $response['code'], $response['message']) = $stack;
   744 				list( , $response['code'], $response['message']) = $stack;
   739 				continue;
   745 				continue;
   740 			}
   746 			}
   901 		static $accessible_hosts = null;
   907 		static $accessible_hosts = null;
   902 		static $wildcard_regex   = array();
   908 		static $wildcard_regex   = array();
   903 		if ( null === $accessible_hosts ) {
   909 		if ( null === $accessible_hosts ) {
   904 			$accessible_hosts = preg_split( '|,\s*|', WP_ACCESSIBLE_HOSTS );
   910 			$accessible_hosts = preg_split( '|,\s*|', WP_ACCESSIBLE_HOSTS );
   905 
   911 
   906 			if ( false !== strpos( WP_ACCESSIBLE_HOSTS, '*' ) ) {
   912 			if ( str_contains( WP_ACCESSIBLE_HOSTS, '*' ) ) {
   907 				$wildcard_regex = array();
   913 				$wildcard_regex = array();
   908 				foreach ( $accessible_hosts as $host ) {
   914 				foreach ( $accessible_hosts as $host ) {
   909 					$wildcard_regex[] = str_replace( '\*', '.+', preg_quote( $host, '/' ) );
   915 					$wildcard_regex[] = str_replace( '\*', '.+', preg_quote( $host, '/' ) );
   910 				}
   916 				}
   911 				$wildcard_regex = '/^(' . implode( '|', $wildcard_regex ) . ')$/i';
   917 				$wildcard_regex = '/^(' . implode( '|', $wildcard_regex ) . ')$/i';
   915 		if ( ! empty( $wildcard_regex ) ) {
   921 		if ( ! empty( $wildcard_regex ) ) {
   916 			return ! preg_match( $wildcard_regex, $check['host'] );
   922 			return ! preg_match( $wildcard_regex, $check['host'] );
   917 		} else {
   923 		} else {
   918 			return ! in_array( $check['host'], $accessible_hosts, true ); // Inverse logic, if it's in the array, then don't block it.
   924 			return ! in_array( $check['host'], $accessible_hosts, true ); // Inverse logic, if it's in the array, then don't block it.
   919 		}
   925 		}
   920 
       
   921 	}
   926 	}
   922 
   927 
   923 	/**
   928 	/**
   924 	 * Used as a wrapper for PHP's parse_url() function that handles edgecases in < PHP 5.4.7.
   929 	 * Used as a wrapper for PHP's parse_url() function that handles edgecases in < PHP 5.4.7.
   925 	 *
   930 	 *
  1009 		// Add the query string.
  1014 		// Add the query string.
  1010 		if ( ! empty( $relative_url_parts['query'] ) ) {
  1015 		if ( ! empty( $relative_url_parts['query'] ) ) {
  1011 			$path .= '?' . $relative_url_parts['query'];
  1016 			$path .= '?' . $relative_url_parts['query'];
  1012 		}
  1017 		}
  1013 
  1018 
       
  1019 		// Add the fragment.
       
  1020 		if ( ! empty( $relative_url_parts['fragment'] ) ) {
       
  1021 			$path .= '#' . $relative_url_parts['fragment'];
       
  1022 		}
       
  1023 
  1014 		return $absolute_path . '/' . ltrim( $path, '/' );
  1024 		return $absolute_path . '/' . ltrim( $path, '/' );
  1015 	}
  1025 	}
  1016 
  1026 
  1017 	/**
  1027 	/**
  1018 	 * Handles an HTTP redirect and follows it if appropriate.
  1028 	 * Handles an HTTP redirect and follows it if appropriate.
  1071 
  1081 
  1072 	/**
  1082 	/**
  1073 	 * Determines if a specified string represents an IP address or not.
  1083 	 * Determines if a specified string represents an IP address or not.
  1074 	 *
  1084 	 *
  1075 	 * This function also detects the type of the IP address, returning either
  1085 	 * This function also detects the type of the IP address, returning either
  1076 	 * '4' or '6' to represent a IPv4 and IPv6 address respectively.
  1086 	 * '4' or '6' to represent an IPv4 and IPv6 address respectively.
  1077 	 * This does not verify if the IP is a valid IP, only that it appears to be
  1087 	 * This does not verify if the IP is a valid IP, only that it appears to be
  1078 	 * an IP address.
  1088 	 * an IP address.
  1079 	 *
  1089 	 *
  1080 	 * @link http://home.deds.nl/~aeron/regex/ for IPv6 regex.
  1090 	 * @link http://home.deds.nl/~aeron/regex/ for IPv6 regex.
  1081 	 *
  1091 	 *
  1082 	 * @since 3.7.0
  1092 	 * @since 3.7.0
  1083 	 *
  1093 	 *
  1084 	 * @param string $maybe_ip A suspected IP address.
  1094 	 * @param string $maybe_ip A suspected IP address.
  1085 	 * @return int|false Upon success, '4' or '6' to represent a IPv4 or IPv6 address, false upon failure
  1095 	 * @return int|false Upon success, '4' or '6' to represent an IPv4 or IPv6 address, false upon failure.
  1086 	 */
  1096 	 */
  1087 	public static function is_ip_address( $maybe_ip ) {
  1097 	public static function is_ip_address( $maybe_ip ) {
  1088 		if ( preg_match( '/^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/', $maybe_ip ) ) {
  1098 		if ( preg_match( '/^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/', $maybe_ip ) ) {
  1089 			return 4;
  1099 			return 4;
  1090 		}
  1100 		}
  1091 
  1101 
  1092 		if ( false !== strpos( $maybe_ip, ':' ) && preg_match( '/^(((?=.*(::))(?!.*\3.+\3))\3?|([\dA-F]{1,4}(\3|:\b|$)|\2))(?4){5}((?4){2}|(((2[0-4]|1\d|[1-9])?\d|25[0-5])\.?\b){4})$/i', trim( $maybe_ip, ' []' ) ) ) {
  1102 		if ( str_contains( $maybe_ip, ':' ) && preg_match( '/^(((?=.*(::))(?!.*\3.+\3))\3?|([\dA-F]{1,4}(\3|:\b|$)|\2))(?4){5}((?4){2}|(((2[0-4]|1\d|[1-9])?\d|25[0-5])\.?\b){4})$/i', trim( $maybe_ip, ' []' ) ) ) {
  1093 			return 6;
  1103 			return 6;
  1094 		}
  1104 		}
  1095 
  1105 
  1096 		return false;
  1106 		return false;
  1097 	}
  1107 	}
  1098 
       
  1099 }
  1108 }