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() { |