| 233 | | $r = wp_parse_args( $args, $defaults ); |
| 234 | | $r = apply_filters( 'http_request_args', $r, $url ); |
| 235 | | |
| 236 | | // Allow plugins to short-circuit the request |
| 237 | | $pre = apply_filters( 'pre_http_request', false, $r, $url ); |
| 238 | | if ( false !== $pre ) |
| 239 | | return $pre; |
| 240 | | |
| 241 | | $arrURL = parse_url($url); |
| 242 | | |
| 243 | | if ( empty( $url ) || empty($url['scheme'] ) ) |
| 244 | | return new WP_Error('http_request_failed', __('A valid URL was not provided.')); |
| 245 | | |
| 246 | | if ( $this->block_request( $url ) ) |
| 247 | | return new WP_Error('http_request_failed', __('User has blocked requests through HTTP.')); |
| 248 | | |
| 249 | | // Determine if this is a https call and pass that on to the transport functions |
| 250 | | // so that we can blacklist the transports that do not support ssl verification |
| 251 | | $r['ssl'] = $arrURL['scheme'] == 'https' || $arrURL['scheme'] == 'ssl'; |
| 252 | | |
| 253 | | // Determine if this request is to OUR install of WordPress |
| 254 | | $homeURL = parse_url( get_bloginfo('url') ); |
| 255 | | $r['local'] = $homeURL['host'] == $arrURL['host'] || 'localhost' == $arrURL['host']; |
| 256 | | unset($homeURL); |
| 257 | | |
| 258 | | if ( is_null( $r['headers'] ) ) |
| 259 | | $r['headers'] = array(); |
| 260 | | |
| 261 | | if ( ! is_array($r['headers']) ) { |
| 262 | | $processedHeaders = WP_Http::processHeaders($r['headers']); |
| 263 | | $r['headers'] = $processedHeaders['headers']; |
| 264 | | } |
| 265 | | |
| 266 | | if ( isset($r['headers']['User-Agent']) ) { |
| 267 | | $r['user-agent'] = $r['headers']['User-Agent']; |
| 268 | | unset($r['headers']['User-Agent']); |
| 269 | | } |
| 270 | | |
| 271 | | if ( isset($r['headers']['user-agent']) ) { |
| 272 | | $r['user-agent'] = $r['headers']['user-agent']; |
| 273 | | unset($r['headers']['user-agent']); |
| 274 | | } |
| 275 | | |
| 276 | | // Construct Cookie: header if any cookies are set |
| 277 | | WP_Http::buildCookieHeader( $r ); |
| 278 | | |
| 279 | | if ( WP_Http_Encoding::is_available() ) |
| 280 | | $r['headers']['Accept-Encoding'] = WP_Http_Encoding::accept_encoding(); |
| 281 | | |
| 282 | | if ( empty($r['body']) ) { |
| 283 | | // Some servers fail when sending content without the content-length header being set. |
| 284 | | // Also, to fix another bug, we only send when doing POST and PUT and the content-length |
| 285 | | // header isn't already set. |
| 286 | | if( ($r['method'] == 'POST' || $r['method'] == 'PUT') && ! isset($r['headers']['Content-Length']) ) |
| 287 | | $r['headers']['Content-Length'] = 0; |
| 288 | | |
| 289 | | // The method is ambiguous, because we aren't talking about HTTP methods, the "get" in |
| 290 | | // this case is simply that we aren't sending any bodies and to get the transports that |
| 291 | | // don't support sending bodies along with those which do. |
| 292 | | $transports = WP_Http::_getTransport($r); |
| 293 | | } else { |
| 294 | | if ( is_array( $r['body'] ) || is_object( $r['body'] ) ) { |
| 295 | | if ( ! version_compare(phpversion(), '5.1.2', '>=') ) |
| 296 | | $r['body'] = _http_build_query($r['body'], null, '&'); |
| 297 | | else |
| 298 | | $r['body'] = http_build_query($r['body'], null, '&'); |
| 299 | | $r['headers']['Content-Type'] = 'application/x-www-form-urlencoded; charset=' . get_option('blog_charset'); |
| 300 | | $r['headers']['Content-Length'] = strlen($r['body']); |
| 301 | | } |
| 302 | | |
| 303 | | if ( ! isset( $r['headers']['Content-Length'] ) && ! isset( $r['headers']['content-length'] ) ) |
| 304 | | $r['headers']['Content-Length'] = strlen($r['body']); |
| 305 | | |
| 306 | | // The method is ambiguous, because we aren't talking about HTTP methods, the "post" in |
| 307 | | // this case is simply that we are sending HTTP body and to get the transports that do |
| 308 | | // support sending the body. Not all do, depending on the limitations of the PHP core |
| 309 | | // limitations. |
| 310 | | $transports = WP_Http::_postTransport($r); |
| 311 | | } |
| 312 | | |
| | 432 | $config = new WP_Http_Config($uri); |
| | 433 | return $config->block_request(); |
| | 434 | } |
| | 435 | } |
| | 436 | |
| | 437 | /** |
| | 438 | * Consolidates the argument processing for all of the transports and main WP_Http class. |
| | 439 | * |
| | 440 | * Since the beginning the argument processing was handled in both {@link WP_Http::request()} and in |
| | 441 | * the individual transports. As more arguments and features were added, it became that |
| | 442 | * {@link WP_Http::request()} was getting all of the support and the rest of the transports were |
| | 443 | * becoming stagnate with argument processing. |
| | 444 | * |
| | 445 | * The individual transports appear to be used more individually, which would cause problems with |
| | 446 | * argument processing or require duplication of {@link WP_Http::request()} code. |
| | 447 | * |
| | 448 | * @since {unknown} |
| | 449 | * @package WordPress |
| | 450 | * @subpackage HTTP |
| | 451 | */ |
| | 452 | class WP_Http_Config { |
| | 453 | |
| | 454 | /** |
| | 455 | * The request URL. |
| | 456 | * |
| | 457 | * @since {unknown} |
| | 458 | * @var string |
| | 459 | */ |
| | 460 | var $uri = ''; |
| | 461 | |
| | 462 | /** |
| | 463 | * Processed arguments cache. |
| | 464 | * |
| | 465 | * @since {unknown} |
| | 466 | * @var array |
| | 467 | */ |
| | 468 | var $args = array(); |
| | 469 | |
| | 470 | /** |
| | 471 | * PHP4 constructor calls PHP5 constructor. |
| | 472 | * |
| | 473 | * @since {unknown} |
| | 474 | * |
| | 475 | * @param String $uri Request URI. |
| | 476 | */ |
| | 477 | function WP_Http_Config( $uri = '' ) { |
| | 478 | $this->__construct($uri); |
| | 479 | } |
| | 480 | |
| | 481 | /** |
| | 482 | * PHP5 constructor - Initialize class properties. |
| | 483 | * |
| | 484 | * @since {unknown} |
| | 485 | * |
| | 486 | * @param String $uri Request URI. |
| | 487 | */ |
| | 488 | function __construct( $uri = '' ) { |
| | 489 | $this->uri = $uri; |
| | 490 | } |
| | 491 | |
| | 492 | /** |
| | 493 | * Process arguments for sending requests. |
| | 494 | * |
| | 495 | * The 'body' argument is for the body and will accept either a string or an array. If the |
| | 496 | * 'body' argument is an array, then it will automatically be escaped using http_build_query(). |
| | 497 | * The 'content-type' header will automatically be set as well as 'content-length' to the size |
| | 498 | * of the body, if the 'body' argument is an array. |
| | 499 | * |
| | 500 | * The 'headers' argument should be an array, but a string will be accepted and then converted |
| | 501 | * to an array. The recommendation for headers to be an array is for optimization purposes. The |
| | 502 | * header array should have the header (or field) name as the array key (or indicies) and the |
| | 503 | * header value as the array value. |
| | 504 | * |
| | 505 | * The defaults are 'method', 'timeout', 'redirection', 'httpversion', 'blocking' and |
| | 506 | * 'user-agent'. |
| | 507 | * |
| | 508 | * Accepted 'method' values are 'GET', 'POST', and 'HEAD', some transports technically allow |
| | 509 | * others, but should not be assumed. The 'timeout' is used to sent how long the connection |
| | 510 | * should stay open before failing when no response. 'redirection' is used to track how many |
| | 511 | * redirects were taken and used to sent the amount for other transports, but not all transports |
| | 512 | * accept setting that value. |
| | 513 | * |
| | 514 | * The 'httpversion' option is used to sent the HTTP version and accepted values are '1.0', and |
| | 515 | * '1.1' and should be a string. Version 1.1 is supported, since chunked responses are |
| | 516 | * supported. The 'user-agent' option is the user-agent and is used to replace the default |
| | 517 | * user-agent, which is 'WordPress/WP_Version', where WP_Version is the value from $wp_version. |
| | 518 | * |
| | 519 | * 'blocking' is the default, which is used to tell the transport, whether it should halt PHP |
| | 520 | * while it performs the request or continue regardless. Actually, that isn't entirely correct. |
| | 521 | * Blocking mode really just means whether the fread should just pull what it can whenever it |
| | 522 | * gets bytes or if it should wait until it has enough in the buffer to read or finishes reading |
| | 523 | * the entire content. It doesn't actually always mean that PHP will continue going after making |
| | 524 | * the request. |
| | 525 | * |
| | 526 | * @access public |
| | 527 | * @since {unknown} |
| | 528 | * |
| | 529 | * @param str|array $args Optional. Override the defaults. |
| | 530 | * @return array Transports for either sending body or for get requests. |
| | 531 | */ |
| | 532 | function process( $args = array() ) { |
| | 533 | global $wp_version; |
| | 534 | |
| | 535 | $defaults = array( |
| | 536 | 'method' => 'GET', |
| | 537 | 'timeout' => apply_filters( 'http_request_timeout', 5), |
| | 538 | 'redirection' => apply_filters( 'http_request_redirection_count', 5), |
| | 539 | 'httpversion' => apply_filters( 'http_request_version', '1.0'), |
| | 540 | 'user-agent' => apply_filters( 'http_headers_useragent', 'WordPress/' . $wp_version . '; ' . get_bloginfo( 'url' ) ), |
| | 541 | 'blocking' => true, |
| | 542 | 'headers' => array(), |
| | 543 | 'cookies' => array(), |
| | 544 | 'body' => null, |
| | 545 | 'compress' => false, |
| | 546 | 'decompress' => true, |
| | 547 | 'sslverify' => true |
| | 548 | ); |
| | 549 | |
| | 550 | $r = wp_parse_args( $args, $defaults ); |
| | 551 | $r = apply_filters( 'http_request_args', $r, $this->uri ); |
| | 552 | |
| | 553 | // Allow plugins to short-circuit the request |
| | 554 | $pre = apply_filters( 'pre_http_request', false, $r, $this->uri ); |
| | 555 | if ( false !== $pre ) |
| | 556 | return $pre; |
| | 557 | |
| | 558 | $arrURL = parse_url($this->uri); |
| | 559 | |
| | 560 | if ( empty( $arrURL ) || empty($arrURL['scheme'] ) ) |
| | 561 | return new WP_Error('http_request_failed', __('A valid URL was not provided.')); |
| | 562 | |
| | 563 | if ( $this->block_request() ) |
| | 564 | return new WP_Error('http_request_failed', __('User has blocked requests through HTTP.')); |
| | 565 | |
| | 566 | // Determine if this is a https call and pass that on to the transport functions |
| | 567 | // so that we can blacklist the transports that do not support ssl verification |
| | 568 | $r['ssl'] = $arrURL['scheme'] == 'https' || $arrURL['scheme'] == 'ssl'; |
| | 569 | |
| | 570 | // Determine if this request is to OUR install of WordPress |
| | 571 | $homeURL = parse_url( get_bloginfo('url') ); |
| | 572 | $r['local'] = $homeURL['host'] == $arrURL['host'] || 'localhost' == $arrURL['host']; |
| | 573 | unset($homeURL); |
| | 574 | |
| | 575 | if ( is_null( $r['headers'] ) ) |
| | 576 | $r['headers'] = array(); |
| | 577 | |
| | 578 | // Convert string to an array, if needed. |
| | 579 | if ( ! is_array($r['headers']) ) { |
| | 580 | $processedHeaders = WP_Http::processHeaders($r['headers']); |
| | 581 | $r['headers'] = $processedHeaders['headers']; |
| | 582 | } |
| | 583 | |
| | 584 | // Change all headers to lowercase to standardize header checks. |
| | 585 | // RFC 1945 section 4.2 states that "Field names are case-insensitive." |
| | 586 | $r['headers'] = array_change_key_case($r['headers']); |
| | 587 | |
| | 588 | // Most transports do not support setting user-agent by header value alone. Therefore, |
| | 589 | // to prevent possible problems, we change it to an argument |
| | 590 | if ( isset($r['headers']['user-agent']) ) { |
| | 591 | $r['user-agent'] = $r['headers']['user-agent']; |
| | 592 | unset($r['headers']['user-agent']); |
| | 593 | } |
| | 594 | |
| | 595 | // Construct Cookie: header if any cookies are set |
| | 596 | WP_Http::buildCookieHeader( $r ); |
| | 597 | |
| | 598 | if ( WP_Http_Encoding::is_available() ) |
| | 599 | $r['headers']['accept-encoding'] = WP_Http_Encoding::accept_encoding(); |
| | 600 | |
| | 601 | if ( empty($r['body']) ) { |
| | 602 | // Some servers fail when sending content without the content-length header being set. |
| | 603 | // Also, to fix another bug, we only send when doing POST and PUT and the content-length |
| | 604 | // header isn't already set. |
| | 605 | if( ($r['method'] == 'POST' || $r['method'] == 'PUT') && ! isset($r['headers']['content-length']) ) |
| | 606 | $r['headers']['content-length'] = 0; |
| | 607 | } else { |
| | 608 | if ( is_array( $r['body'] ) || is_object( $r['body'] ) ) { |
| | 609 | if ( ! version_compare(phpversion(), '5.1.2', '>=') ) |
| | 610 | $r['body'] = _http_build_query($r['body'], null, '&'); |
| | 611 | else |
| | 612 | $r['body'] = http_build_query($r['body'], null, '&'); |
| | 613 | $r['headers']['content-type'] = 'application/x-www-form-urlencoded; charset=' . get_option('blog_charset'); |
| | 614 | $r['headers']['content-length'] = strlen($r['body']); |
| | 615 | } |
| | 616 | |
| | 617 | if ( ! isset( $r['headers']['content-length'] ) && ! isset( $r['headers']['content-length'] ) ) |
| | 618 | $r['headers']['content-length'] = strlen($r['body']); |
| | 619 | } |
| | 620 | |
| | 621 | $r['processed'] = true; |
| | 622 | |
| | 623 | $this->args = $r; |
| | 624 | } |
| | 625 | |
| | 626 | /** |
| | 627 | * Retrieve transports based on whether body is sent with the request. |
| | 628 | * |
| | 629 | * There used to be a note in the methods used that they both are ambiguous. The note was given |
| | 630 | * to prevent future coders from incorrectly assuming that the 'get' in |
| | 631 | * {@link WP_Http::_getTransport()} was for HTTP GET method requests and that the 'post' in |
| | 632 | * {@link WP_Http::_postTransport()} was for HTTP POST method requests. This is not the case, |
| | 633 | * the two methods were created because there is a transport for PHP4 that does not support |
| | 634 | * sending the request body and must be ignored for those requests. |
| | 635 | * |
| | 636 | * The above note are part of the methods, but the note was duplicated for clarity sake to |
| | 637 | * prevent questions on why they are that way. |
| | 638 | * |
| | 639 | * @since {unknown} |
| | 640 | * |
| | 641 | * @return array Transports for sending requests. |
| | 642 | */ |
| | 643 | function get_transports() { |
| | 644 | return ( empty($this->args['body']) ) ? WP_Http::_getTransport($r) : WP_Http::_postTransport($r); |
| | 645 | } |
| | 646 | |
| | 647 | /** |
| | 648 | * Retrieve processed arguments. |
| | 649 | * |
| | 650 | * The {@link WP_Http_Config::process()} needs to be called first or this method will only |
| | 651 | * return an empty array. |
| | 652 | * |
| | 653 | * @since {unknown} |
| | 654 | * |
| | 655 | * @return array Processed Arguments for requests. |
| | 656 | */ |
| | 657 | function get_arguments() { |
| | 658 | return $this->args; |
| | 659 | } |
| | 660 | |
| | 661 | /** |
| | 662 | * Block requests through the proxy. |
| | 663 | * |
| | 664 | * Those who are behind a proxy and want to prevent access to certain hosts may do so. This will |
| | 665 | * prevent plugins from working and core functionality, if you don't include api.wordpress.org. |
| | 666 | * |
| | 667 | * You block external URL requests by defining WP_HTTP_BLOCK_EXTERNAL as true in your wp-config.php |
| | 668 | * file and this will only allow localhost and your blog to make requests. The constant |
| | 669 | * WP_ACCESSIBLE_HOSTS will allow additional hosts to go through for requests. The format of the |
| | 670 | * WP_ACCESSIBLE_HOSTS constant is a comma separated list of hostnames to allow. |
| | 671 | * |
| | 672 | * @since 2.8.0 |
| | 673 | * @link http://core.trac.wordpress.org/ticket/8927 Allow preventing external requests. |
| | 674 | * |
| | 675 | * @param string $uri URI of url. |
| | 676 | * @return bool True to block, false to allow. |
| | 677 | */ |
| | 678 | function block_request() { |