257
265
$arrURL = @parse_url( $url );
259
if ( empty( $url ) || empty( $arrURL['scheme'] ) )
267
if ( empty( $url ) || empty( $arrURL['scheme'] ) ) {
260
268
return new WP_Error('http_request_failed', __('A valid URL was not provided.'));
262
if ( $this->block_request( $url ) )
271
if ( $this->block_request( $url ) ) {
263
272
return new WP_Error( 'http_request_failed', __( 'User has blocked requests through HTTP.' ) );
266
* Determine if this is a https call and pass that on to the transport functions
267
* so that we can blacklist the transports that do not support ssl verification
269
$r['ssl'] = $arrURL['scheme'] == 'https' || $arrURL['scheme'] == 'ssl';
271
// Determine if this request is to OUR install of WordPress.
272
$homeURL = parse_url( get_bloginfo( 'url' ) );
273
$r['local'] = 'localhost' == $arrURL['host'] || ( isset( $homeURL['host'] ) && $homeURL['host'] == $arrURL['host'] );
277
* If we are streaming to a file but no filename was given drop it in the WP temp dir
278
* and pick its name using the basename of the $url.
280
if ( $r['stream'] && empty( $r['filename'] ) ) {
281
$r['filename'] = get_temp_dir() . wp_unique_filename( get_temp_dir(), basename( $url ) );
285
* Force some settings if we are streaming to a file and check for existence and perms
286
* of destination directory.
275
// If we are streaming to a file but no filename was given drop it in the WP temp dir
276
// and pick its name using the basename of the $url
288
277
if ( $r['stream'] ) {
278
if ( empty( $r['filename'] ) ) {
279
$r['filename'] = get_temp_dir() . basename( $url );
282
// Force some settings if we are streaming to a file and check for existence and perms of destination directory
289
283
$r['blocking'] = true;
290
if ( ! wp_is_writable( dirname( $r['filename'] ) ) )
284
if ( ! wp_is_writable( dirname( $r['filename'] ) ) ) {
291
285
return new WP_Error( 'http_request_failed', __( 'Destination directory for file streaming does not exist or is not writable.' ) );
294
if ( is_null( $r['headers'] ) )
289
if ( is_null( $r['headers'] ) ) {
295
290
$r['headers'] = array();
293
// WP allows passing in headers as a string, weirdly.
297
294
if ( ! is_array( $r['headers'] ) ) {
298
$processedHeaders = self::processHeaders( $r['headers'], $url );
295
$processedHeaders = WP_Http::processHeaders( $r['headers'] );
299
296
$r['headers'] = $processedHeaders['headers'];
302
if ( isset( $r['headers']['User-Agent'] ) ) {
303
$r['user-agent'] = $r['headers']['User-Agent'];
304
unset( $r['headers']['User-Agent'] );
307
if ( isset( $r['headers']['user-agent'] ) ) {
308
$r['user-agent'] = $r['headers']['user-agent'];
309
unset( $r['headers']['user-agent'] );
312
if ( '1.1' == $r['httpversion'] && !isset( $r['headers']['connection'] ) ) {
313
$r['headers']['connection'] = 'close';
316
// Construct Cookie: header if any cookies are set.
317
self::buildCookieHeader( $r );
319
// Avoid issues where mbstring.func_overload is enabled.
320
mbstring_binary_safe_encoding();
322
if ( ! isset( $r['headers']['Accept-Encoding'] ) ) {
323
if ( $encoding = WP_Http_Encoding::accept_encoding( $url, $r ) )
324
$r['headers']['Accept-Encoding'] = $encoding;
327
if ( ( ! is_null( $r['body'] ) && '' != $r['body'] ) || 'POST' == $r['method'] || 'PUT' == $r['method'] ) {
328
if ( is_array( $r['body'] ) || is_object( $r['body'] ) ) {
329
$r['body'] = http_build_query( $r['body'], null, '&' );
331
if ( ! isset( $r['headers']['Content-Type'] ) )
332
$r['headers']['Content-Type'] = 'application/x-www-form-urlencoded; charset=' . get_option( 'blog_charset' );
335
if ( '' === $r['body'] )
338
if ( ! isset( $r['headers']['Content-Length'] ) && ! isset( $r['headers']['content-length'] ) )
339
$r['headers']['Content-Length'] = strlen( $r['body'] );
342
$response = $this->_dispatch_request( $url, $r );
344
reset_mbstring_encoding();
346
if ( is_wp_error( $response ) )
349
// Append cookies that were used in this request to the response
300
$headers = $r['headers'];
302
$type = $r['method'];
304
'timeout' => $r['timeout'],
305
'useragent' => $r['user-agent'],
306
'blocking' => $r['blocking'],
307
'hooks' => new Requests_Hooks(),
310
// Ensure redirects follow browser behaviour.
311
$options['hooks']->register( 'requests.before_redirect', array( get_class(), 'browser_redirect_compatibility' ) );
313
if ( $r['stream'] ) {
314
$options['filename'] = $r['filename'];
316
if ( empty( $r['redirection'] ) ) {
317
$options['follow_redirects'] = false;
319
$options['redirects'] = $r['redirection'];
322
// Use byte limit, if we can
323
if ( isset( $r['limit_response_size'] ) ) {
324
$options['max_bytes'] = $r['limit_response_size'];
327
// If we've got cookies, use and convert them to Requests_Cookie.
350
328
if ( ! empty( $r['cookies'] ) ) {
351
$cookies_set = wp_list_pluck( $response['cookies'], 'name' );
352
foreach ( $r['cookies'] as $cookie ) {
353
if ( ! in_array( $cookie->name, $cookies_set ) && $cookie->test( $url ) ) {
354
$response['cookies'][] = $cookie;
329
$options['cookies'] = WP_Http::normalize_cookies( $r['cookies'] );
332
// SSL certificate handling
333
if ( ! $r['sslverify'] ) {
334
$options['verify'] = false;
336
$options['verify'] = $r['sslcertificates'];
339
// All non-GET/HEAD requests should put the arguments in the form body.
340
if ( 'HEAD' !== $type && 'GET' !== $type ) {
341
$options['data_format'] = 'body';
345
* Filters whether SSL should be verified for non-local requests.
349
* @param bool $ssl_verify Whether to verify the SSL connection. Default true.
351
$options['verify'] = apply_filters( 'https_ssl_verify', $options['verify'] );
353
// Check for proxies.
354
$proxy = new WP_HTTP_Proxy();
355
if ( $proxy->is_enabled() && $proxy->send_through_proxy( $url ) ) {
356
$options['proxy'] = new Requests_Proxy_HTTP( $proxy->host() . ':' . $proxy->port() );
358
if ( $proxy->use_authentication() ) {
359
$options['proxy']->use_authentication = true;
360
$options['proxy']->user = $proxy->username();
361
$options['proxy']->pass = $proxy->password();
366
$requests_response = Requests::request( $url, $headers, $data, $type, $options );
368
// Convert the response into an array
369
$http_response = new WP_HTTP_Requests_Response( $requests_response, $r['filename'] );
370
$response = $http_response->to_array();
372
// Add the original object to the array.
373
$response['http_response'] = $http_response;
375
catch ( Requests_Exception $e ) {
376
$response = new WP_Error( 'http_request_failed', $e->getMessage() );
380
* Fires after an HTTP API response is received and before the response is returned.
384
* @param array|WP_Error $response HTTP response or WP_Error object.
385
* @param string $context Context under which the hook is fired.
386
* @param string $class HTTP transport used.
387
* @param array $args HTTP request arguments.
388
* @param string $url The request URL.
390
do_action( 'http_api_debug', $response, 'response', 'Requests', $r, $url );
391
if ( is_wp_error( $response ) ) {
395
if ( ! $r['blocking'] ) {
397
'headers' => array(),
403
'cookies' => array(),
404
'http_response' => null,
409
* Filters the HTTP API response immediately before the response is returned.
413
* @param array $response HTTP response.
414
* @param array $r HTTP request arguments.
415
* @param string $url The request URL.
417
return apply_filters( 'http_response', $response, $r, $url );
421
* Normalizes cookies for using in Requests.
427
* @param array $cookies List of cookies to send with the request.
428
* @return Requests_Cookie_Jar Cookie holder object.
430
public static function normalize_cookies( $cookies ) {
431
$cookie_jar = new Requests_Cookie_Jar();
433
foreach ( $cookies as $name => $value ) {
434
if ( $value instanceof WP_Http_Cookie ) {
435
$cookie_jar[ $value->name ] = new Requests_Cookie( $value->name, $value->value, $value->get_attributes() );
436
} elseif ( is_string( $value ) ) {
437
$cookie_jar[ $name ] = new Requests_Cookie( $name, $value );
445
* Match redirect behaviour to browser handling.
447
* Changes 302 redirects from POST to GET to match browser handling. Per
448
* RFC 7231, user agents can deviate from the strict reading of the
449
* specification for compatibility purposes.
455
* @param string $location URL to redirect to.
456
* @param array $headers Headers for the redirect.
457
* @param array $options Redirect request options.
458
* @param Requests_Response $original Response object.
460
public static function browser_redirect_compatibility( $location, $headers, $data, &$options, $original ) {
462
if ( $original->status_code === 302 ) {
463
$options['type'] = Requests::GET;