Ticket #4011: 4011.diff
File 4011.diff, 42.8 KB (added by , 16 years ago) |
---|
-
http.php
13 13 */ 14 14 15 15 /** 16 * Implementation for deflate and gzip transfer encodings.17 *18 * Includes RFC 1950, RFC 1951, and RFC 1952.19 *20 * @since unknown21 * @package WordPress22 * @subpackage HTTP23 */24 class WP_Http_Encoding {25 26 /**27 * Compress raw string using the deflate format.28 *29 * Supports the RFC 1951 standard.30 *31 * @since unknown32 *33 * @param string $raw String to compress.34 * @param int $level Optional, default is 9. Compression level, 9 is highest.35 * @param string $supports Optional, not used. When implemented it will choose the right compression based on what the server supports.36 * @return string|bool False on failure.37 */38 function compress( $raw, $level = 9, $supports = null ) {39 return gzdeflate( $raw, $level );40 }41 42 /**43 * Decompression of deflated string.44 *45 * Will attempt to decompress using the RFC 1950 standard, and if that fails46 * then the RFC 1951 standard deflate will be attempted. Finally, the RFC47 * 1952 standard gzip decode will be attempted. If all fail, then the48 * original compressed string will be returned.49 *50 * @since unknown51 *52 * @param string $compressed String to decompress.53 * @param int $length The optional length of the compressed data.54 * @return string|bool False on failure.55 */56 function decompress( $compressed, $length = null ) {57 $decompressed = gzinflate( $compressed );58 59 if( false !== $decompressed )60 return $decompressed;61 62 $decompressed = gzuncompress( $compressed );63 64 if( false !== $decompressed )65 return $decompressed;66 67 $decompressed = gzdecode( $compressed );68 69 if( false !== $decompressed )70 return $decompressed;71 72 return $compressed;73 }74 75 /**76 * What encoding types to accept and their priority values.77 *78 * @since unknown79 *80 * @return string Types of encoding to accept.81 */82 function accept_encoding() {83 $type = array();84 if( function_exists( 'gzinflate' ) )85 $type[] = 'deflate;q=1.0';86 87 if( function_exists( 'gzuncompress' ) )88 $type[] = 'compress;q=0.5';89 90 if( function_exists( 'gzdecode' ) )91 $type[] = 'gzip;q=0.5';92 93 return implode(', ', $type);94 }95 96 /**97 * What enconding the content used when it was compressed to send in the headers.98 *99 * @since unknown100 *101 * @return string Content-Encoding string to send in the header.102 */103 function content_encoding() {104 return 'deflate';105 }106 107 /**108 * Whether the content be decoded based on the headers.109 *110 * @since unknown111 *112 * @param array|string $headers All of the available headers.113 * @return bool114 */115 function should_decode($headers) {116 if( is_array( $headers ) ) {117 if( array_key_exists('content-encoding', $headers) && ! empty( $headers['content-encoding'] ) )118 return true;119 } else if( is_string( $headers ) ) {120 return ( stripos($headers, 'content-encoding:') !== false );121 }122 123 return false;124 }125 126 /**127 * Whether decompression and compression are supported by the PHP version.128 *129 * Each function is tested instead of checking for the zlib extension, to130 * ensure that the functions all exist in the PHP version and aren't131 * disabled.132 *133 * @since unknown134 *135 * @return bool136 */137 function is_available() {138 return ( function_exists('gzuncompress') || function_exists('gzdeflate') ||139 function_exists('gzinflate') );140 }141 }142 143 /**144 16 * WordPress HTTP Class for managing HTTP Transports and making HTTP requests. 145 17 * 146 * This class is called for the functionality of making HTTP requests and should 147 * replace Snoopy functionality, eventually. There is no available functionality 148 * to add HTTP transport implementations, since most of the HTTP transports are 149 * added and available for use. 18 * This class is called for the functionality of making HTTP requests and should replace Snoopy 19 * functionality, eventually. There is no available functionality to add HTTP transport 20 * implementations, since most of the HTTP transports are added and available for use. 150 21 * 151 * The exception is that cURL is not available as a transport and lacking an 152 * implementation. It will be added later and should be a patch on the WordPress 153 * Trac. 22 * The exception is that cURL is not available as a transport and lacking an implementation. It will 23 * be added later and should be a patch on the WordPress Trac. 154 24 * 155 * There are no properties, because none are needed and for performance reasons. 156 * Some of the functions are static and while they do have some overhead over157 * functions in PHP4, the purpose is maintainability. When PHP5 is finally the158 * requirement, it will be easy to add the static keyword to the code. It is not159 * as easy to convert a function to a method after enough code uses the oldway.25 * There are no properties, because none are needed and for performance reasons. Some of the 26 * functions are static and while they do have some overhead over functions in PHP4, the purpose is 27 * maintainability. When PHP5 is finally the requirement, it will be easy to add the static keyword 28 * to the code. It is not as easy to convert a function to a method after enough code uses the old 29 * way. 160 30 * 161 * Debugging includes several actions, which pass different variables for 162 * debugging the HTTP API. 31 * Debugging includes several actions, which pass different variables for debugging the HTTP API. 163 32 * 164 * <strong>http_transport_get_debug</strong> - gives working, nonblocking, and 165 * blocking transports. 33 * <strong>http_transport_get_debug</strong> - gives working, nonblocking, and blocking transports. 166 34 * 167 * <strong>http_transport_post_debug</strong> - gives working, nonblocking, and 168 * blocking transports. 35 * <strong>http_transport_post_debug</strong> - gives working, nonblocking, and blocking transports. 169 36 * 170 37 * @package WordPress 171 38 * @subpackage HTTP … … 228 95 static $working_transport, $blocking_transport, $nonblocking_transport; 229 96 230 97 if ( is_null($working_transport) ) { 231 if ( true === WP_Http_ExtHttp::test() && apply_filters('use_http_extension_transport', true)) {98 if ( true === WP_Http_ExtHttp::test() ) { 232 99 $working_transport['exthttp'] = new WP_Http_ExtHttp(); 233 100 $blocking_transport[] = &$working_transport['exthttp']; 234 } else if ( true === WP_Http_Curl::test() && apply_filters('use_curl_transport', true)) {101 } else if ( true === WP_Http_Curl::test() ) { 235 102 $working_transport['curl'] = new WP_Http_Curl(); 236 103 $blocking_transport[] = &$working_transport['curl']; 237 } else if ( true === WP_Http_Streams::test() && apply_filters('use_streams_transport', true)) {104 } else if ( true === WP_Http_Streams::test() ) { 238 105 $working_transport['streams'] = new WP_Http_Streams(); 239 106 $blocking_transport[] = &$working_transport['streams']; 240 } else if ( true === WP_Http_Fopen::test() && apply_filters('use_fopen_transport', true) &&( isset($args['ssl']) && !$args['ssl'] ) ) {107 } else if ( true === WP_Http_Fopen::test() && ( isset($args['ssl']) && !$args['ssl'] ) ) { 241 108 $working_transport['fopen'] = new WP_Http_Fopen(); 242 109 $blocking_transport[] = &$working_transport['fopen']; 243 } else if ( true === WP_Http_Fsockopen::test() && apply_filters('use_fsockopen_transport', true) &&( isset($args['ssl']) && !$args['ssl'] ) ) {110 } else if ( true === WP_Http_Fsockopen::test() && ( isset($args['ssl']) && !$args['ssl'] ) ) { 244 111 $working_transport['fsockopen'] = new WP_Http_Fsockopen(); 245 112 $blocking_transport[] = &$working_transport['fsockopen']; 246 113 } … … 279 146 static $working_transport, $blocking_transport, $nonblocking_transport; 280 147 281 148 if ( is_null($working_transport) ) { 282 if ( true === WP_Http_ExtHttp::test() && apply_filters('use_http_extension_transport', true)) {149 if ( true === WP_Http_ExtHttp::test() ) { 283 150 $working_transport['exthttp'] = new WP_Http_ExtHttp(); 284 151 $blocking_transport[] = &$working_transport['exthttp']; 285 } else if ( true === WP_Http_Curl::test() && apply_filters('use_curl_transport', true)) {152 } else if ( true === WP_Http_Curl::test() ) { 286 153 $working_transport['curl'] = new WP_Http_Curl(); 287 154 $blocking_transport[] = &$working_transport['curl']; 288 } else if ( true === WP_Http_Streams::test() && apply_filters('use_streams_transport', true)) {155 } else if ( true === WP_Http_Streams::test() ) { 289 156 $working_transport['streams'] = new WP_Http_Streams(); 290 157 $blocking_transport[] = &$working_transport['streams']; 291 } else if ( true === WP_Http_Fsockopen::test() && apply_filters('use_fsockopen_transport', true) &&( isset($args['ssl']) && !$args['ssl'] ) ) {158 } else if ( true === WP_Http_Fsockopen::test() && ( isset($args['ssl']) && !$args['ssl'] ) ) { 292 159 $working_transport['fsockopen'] = new WP_Http_Fsockopen(); 293 160 $blocking_transport[] = &$working_transport['fsockopen']; 294 161 } … … 311 178 /** 312 179 * Send a HTTP request to a URI. 313 180 * 314 * The body and headers are part of the arguments. The 'body' argument is 315 * for the body and will accept either a string or an array. The 'headers' 316 * argument should be an array, but a string is acceptable. If the 'body' 317 * argument is an array, then it will automatically be escaped using 318 * http_build_query(). 181 * The body and headers are part of the arguments. The 'body' argument is for the body and will 182 * accept either a string or an array. The 'headers' argument should be an array, but a string 183 * is acceptable. If the 'body' argument is an array, then it will automatically be escaped 184 * using http_build_query(). 319 185 * 320 * The only URI that are supported in the HTTP Transport implementation are 321 * the HTTP and HTTPS protocols. HTTP and HTTPS are assumed so the server 322 * might not know how to handle the send headers. Other protocols are 323 * unsupported and most likely will fail. 186 * The only URI that are supported in the HTTP Transport implementation are the HTTP and HTTPS 187 * protocols. HTTP and HTTPS are assumed so the server might not know how to handle the send 188 * headers. Other protocols are unsupported and most likely will fail. 324 189 * 325 * The defaults are 'method', 'timeout', 'redirection', 'httpversion', 326 * ' blocking' and 'user-agent'.190 * The defaults are 'method', 'timeout', 'redirection', 'httpversion', 'blocking' and 191 * 'user-agent'. 327 192 * 328 * Accepted 'method' values are 'GET', 'POST', and 'HEAD', some transports 329 * technically allow others, but should not be assumed. The 'timeout' is 330 * used to sent how long the connection should stay open before failing when 331 * no response. 'redirection' is used to track how many redirects were taken 332 * and used to sent the amount for other transports, but not all transports 193 * Accepted 'method' values are 'GET', 'POST', and 'HEAD', some transports technically allow 194 * others, but should not be assumed. The 'timeout' is used to sent how long the connection 195 * should stay open before failing when no response. 'redirection' is used to track how many 196 * redirects were taken and used to sent the amount for other transports, but not all transports 333 197 * accept setting that value. 334 198 * 335 * The 'httpversion' option is used to sent the HTTP version and accepted 336 * values are '1.0', and '1.1' and should be a string. Version 1.1 is not 337 * supported, because of chunk response. The 'user-agent' option is the 338 * user-agent and is used to replace the default user-agent, which is 199 * The 'httpversion' option is used to sent the HTTP version and accepted values are '1.0', and 200 * '1.1' and should be a string. Version 1.1 is not supported, because of chunk response. The 201 * 'user-agent' option is the user-agent and is used to replace the default user-agent, which is 339 202 * 'WordPress/WP_Version', where WP_Version is the value from $wp_version. 340 203 * 341 * 'blocking' is the default, which is used to tell the transport, whether 342 * it should halt PHP while it performs the request or continue regardless. 343 * Actually, that isn't entirely correct. Blocking mode really just means 344 * whether the fread should just pull what it can whenever it gets bytes or 345 * if it should wait until it has enough in the buffer to read or finishes 346 * reading the entire content. It doesn't actually always mean that PHP will 347 * continue going after making the request. 204 * 'blocking' is the default, which is used to tell the transport, whether it should halt PHP 205 * while it performs the request or continue regardless. Actually, that isn't entirely correct. 206 * Blocking mode really just means whether the fread should just pull what it can whenever it 207 * gets bytes or if it should wait until it has enough in the buffer to read or finishes reading 208 * the entire content. It doesn't actually always mean that PHP will continue going after making 209 * the request. 348 210 * 349 211 * @access public 350 212 * @since 2.7.0 … … 376 238 377 239 $arrURL = parse_url($url); 378 240 241 if ( $this->block_request( $url ) ) 242 return new WP_Error('http_request_failed', 'User has blocked requests through HTTP.'); 243 379 244 // Determine if this is a https call and pass that on to the transport functions 380 245 // so that we can blacklist the transports that do not support ssl verification 381 246 if ( $arrURL['scheme'] == 'https' || $arrURL['scheme'] == 'ssl' ) … … 400 265 $r['user-agent'] = $r['headers']['user-agent']; 401 266 unset($r['headers']['user-agent']); 402 267 } 403 268 404 269 // Construct Cookie: header if any cookies are set 405 270 WP_Http::buildCookieHeader( $r ); 406 271 … … 514 379 /** 515 380 * Transform header string into an array. 516 381 * 517 * If an array is given then it is assumed to be raw header data with 518 * numeric keys with the headers as the values. No headers must be passed 519 * that were already processed. 382 * If an array is given then it is assumed to be raw header data with numeric keys with the 383 * headers as the values. No headers must be passed that were already processed. 520 384 * 521 385 * @access public 522 386 * @static … … 561 425 562 426 return array('response' => $response, 'headers' => $newheaders, 'cookies' => $cookies); 563 427 } 564 428 565 429 /** 566 430 * Takes the arguments for a ::request() and checks for the cookie array. 567 * If it's found, then it's assumed to contain WP_Http_Cookie objects, which568 * are each parsed into strings and added to the Cookie: header (within the569 * arguments array). Edits the array by reference.570 431 * 432 * If it's found, then it's assumed to contain WP_Http_Cookie objects, which are each parsed 433 * into strings and added to the Cookie: header (within the arguments array). Edits the array by 434 * reference. 435 * 571 436 * @access public 437 * @version 2.8.0 572 438 * @static 573 439 * 574 440 * @param array $r Full array of args passed into ::request() … … 583 449 $r['headers']['cookie'] = $cookies_header; 584 450 } 585 451 } 586 452 587 453 /** 588 454 * Decodes chunk transfer-encoding, based off the HTTP 1.1 specification. 589 455 * 590 * Based off the HTTP http_encoding_dechunk function. Does not support 591 * UTF-8. Does not support returning footer headers. Shouldn't be too 592 * difficult to support it though. 456 * Based off the HTTP http_encoding_dechunk function. Does not support UTF-8. Does not support 457 * returning footer headers. Shouldn't be too difficult to support it though. 593 458 * 594 459 * @todo Add support for footer chunked headers. 595 460 * @access public … … 630 495 } 631 496 } 632 497 } 498 499 /** 500 * Block requests through the proxy. 501 * 502 * Those who are behind a proxy and want to prevent access to certain hosts may do so. This will 503 * prevent plugins from working and core functionality, if you don't include api.wordpress.org. 504 * 505 * You block external URL requests by defining WP_HTTP_BLOCK_EXTERNAL in your wp-config.php file 506 * and this will only allow localhost and your blog to make requests. The constant 507 * WP_ACCESSABLE_HOSTS will allow additional hosts to go through for requests. 508 * 509 * @since unknown 510 * @link http://core.trac.wordpress.org/ticket/8927 Allow preventing external requests. 511 * 512 * @param string $uri URI of url. 513 * @return bool True to block, false to allow. 514 */ 515 function block_request($uri) { 516 // We don't need to block requests, because nothing is blocked. 517 if ( ! defined('WP_HTTP_BLOCK_EXTERNAL') || ( defined('WP_HTTP_BLOCK_EXTERNAL') && WP_HTTP_BLOCK_EXTERNAL == false ) ) 518 return false; 519 520 // parse_url() only handles http, https type URLs, and will emit E_WARNING on failure. 521 // This will be displayed on blogs, which is not reasonable. 522 $check = @parse_url($uri); 523 524 /* Malformed URL, can not process, but this could mean ssl, so let through anyway. 525 * 526 * This isn't very security sound. There are instances where a hacker might attempt 527 * to bypass the proxy and this check. However, the reason for this behavior is that 528 * WordPress does not do any checking currently for non-proxy requests, so it is keeps with 529 * the default unsecure nature of the HTTP request. 530 */ 531 if ( $check === false ) 532 return false; 533 534 $home = parse_url( get_bloginfo('site_url') ); 535 536 if ( $uri == 'localhost' || $uri == $home['host'] ) 537 return false; 538 539 if ( defined('WP_ACCESSABLE_HOSTS') && is_array( WP_ACCESSABLE_HOSTS ) && in_array( $check['host'], WP_ACCESSABLE_HOSTS ) ) { 540 return false; 541 } 542 543 return true; 544 } 633 545 } 634 546 635 547 /** 636 548 * HTTP request method uses fsockopen function to retrieve the url. 637 549 * 638 * This would be the preferred method, but the fsockopen implementation has the 639 * most overhead of allthe HTTP transport implementations.550 * This would be the preferred method, but the fsockopen implementation has the most overhead of all 551 * the HTTP transport implementations. 640 552 * 641 553 * @package WordPress 642 554 * @subpackage HTTP … … 696 608 $arrURL['port'] = apply_filters('http_request_port', $arrURL['port']); 697 609 } 698 610 699 // There are issues with the HTTPS and SSL protocols that cause errors 700 // that can be safelyignored and should be ignored.611 // There are issues with the HTTPS and SSL protocols that cause errors that can be safely 612 // ignored and should be ignored. 701 613 if ( true === $secure_transport ) 702 614 $error_reporting = error_reporting(0); 703 615 … … 710 622 711 623 $endDelay = time(); 712 624 713 // If the delay is greater than the timeout then fsockopen should't be 714 // used, because it willcause a long delay.625 // If the delay is greater than the timeout then fsockopen should't be used, because it will 626 // cause a long delay. 715 627 $elapseDelay = ($endDelay-$startDelay) > $r['timeout']; 716 628 if ( true === $elapseDelay ) 717 629 add_option( 'disable_fsockopen', $endDelay, null, true ); … … 719 631 if ( false === $handle ) 720 632 return new WP_Error('http_request_failed', $iError . ': ' . $strError); 721 633 722 // WordPress supports PHP 4.3, which has this function. Removed sanity 723 // checking forperformance reasons.634 // WordPress supports PHP 4.3, which has this function. Removed sanity checking for 635 // performance reasons. 724 636 stream_set_timeout($handle, $r['timeout'] ); 725 637 726 638 $requestPath = $arrURL['path'] . ( isset($arrURL['query']) ? '?' . $arrURL['query'] : '' ); … … 798 710 if ( false !== ($option = get_option( 'disable_fsockopen' )) && time()-$option < 43200 ) // 12 hours 799 711 return false; 800 712 801 if ( function_exists( 'fsockopen' ) )713 if ( function_exists( 'fsockopen' ) && apply_filters('use_fsockopen_transport', true) ) 802 714 return true; 803 715 804 716 return false; … … 808 720 /** 809 721 * HTTP request method uses fopen function to retrieve the url. 810 722 * 811 * Requires PHP version greater than 4.3.0 for stream support. Does not allow 812 * for $context support, but should still be okay, to write the headers, before813 * getting the response. Also requires that'allow_url_fopen' to be enabled.723 * Requires PHP version greater than 4.3.0 for stream support. Does not allow for $context support, 724 * but should still be okay, to write the headers, before getting the response. Also requires that 725 * 'allow_url_fopen' to be enabled. 814 726 * 815 727 * @package WordPress 816 728 * @subpackage HTTP … … 820 732 /** 821 733 * Send a HTTP request to a URI using fopen(). 822 734 * 823 * This transport does not support sending of headers and body, therefore 824 * should not be used inthe instances, where there is a body and headers.735 * This transport does not support sending of headers and body, therefore should not be used in 736 * the instances, where there is a body and headers. 825 737 * 826 738 * Notes: Does not support non-blocking mode. Ignores 'redirection' option. 827 739 * … … 911 823 if ( ! function_exists('fopen') || (function_exists('ini_get') && true != ini_get('allow_url_fopen')) ) 912 824 return false; 913 825 914 return true;826 return apply_filters('use_fopen_transport', true); 915 827 } 916 828 } 917 829 918 830 /** 919 831 * HTTP request method uses Streams to retrieve the url. 920 832 * 921 * Requires PHP 5.0+ and uses fopen with stream context. Requires that 922 * 'allow_url_fopen' PHP settingto be enabled.833 * Requires PHP 5.0+ and uses fopen with stream context. Requires that 'allow_url_fopen' PHP setting 834 * to be enabled. 923 835 * 924 836 * Second preferred method for getting the URL, for PHP 5. 925 837 * … … 955 867 $r['user-agent'] = $r['headers']['user-agent']; 956 868 unset($r['headers']['user-agent']); 957 869 } 958 870 959 871 // Construct Cookie: header if any cookies are set 960 872 WP_Http::buildCookieHeader( $r ); 961 873 … … 984 896 'header' => $strHeaders, 985 897 'timeout' => $r['timeout'], 986 898 'ssl' => array( 987 988 989 899 'verify_peer' => apply_filters('https_ssl_verify', $r['sslverify']), 900 'verify_host' => apply_filters('https_ssl_verify', $r['sslverify']) 901 ) 990 902 ) 991 903 ); 992 904 905 $proxy = new WP_HTTP_Proxy(); 906 907 if ( $proxy->is_enabled() && $proxy->send_through_proxy( $url ) ) { 908 // WTF happens when the user stupidly puts http:// in the host? Bad things. Really, 909 // really bad things happen. Not exactly unleashing demons from hell, but you know. 910 // Just as bad probably. Actually, none of the other transports should work in that case 911 // so no sanitization is done. If there is, it should be done in the 912 // WP_HTTP_Proxy::host(). 913 // 914 // On second thought, why is it tcp protocol? Why not http? What if the proxy is http 915 // and not tcp? Even though, technically, http is tcp, but just a specialized form of 916 // tcp. Behavior is undefined, so it is probably good that not a lot of users will be 917 // affected by FUBAR behavior. 918 // 919 // Is it another WTF? that this multiline comment isn't using multiline comment syntax? 920 $arrContext['http']['proxy'] = 'tcp://'.$proxy->host().':'$proxy->port(); 921 922 // Yeah, this may or may not work. Good luck. 923 if ( $proxy->use_authentication() ) { 924 $arrContext['http']['header'] .= $proxy->authentication_header() . "\r\n"; 925 } 926 } 927 993 928 if ( ! is_null($r['body']) && ! empty($r['body'] ) ) 994 929 $arrContext['http']['content'] = $r['body']; 995 930 … … 1003 938 if ( ! $handle) 1004 939 return new WP_Error('http_request_failed', sprintf(__('Could not open handle for fopen() to %s'), $url)); 1005 940 1006 // WordPress supports PHP 4.3, which has this function. Removed sanity 1007 // checking forperformance reasons.941 // WordPress supports PHP 4.3, which has this function. Removed sanity checking for 942 // performance reasons. 1008 943 stream_set_timeout($handle, $r['timeout'] ); 1009 944 1010 945 if ( ! $r['blocking'] ) { … … 1049 984 if ( version_compare(PHP_VERSION, '5.0', '<') ) 1050 985 return false; 1051 986 1052 return true;987 return apply_filters('use_streams_transport', true); 1053 988 } 1054 989 } 1055 990 1056 991 /** 1057 992 * HTTP request method uses HTTP extension to retrieve the url. 1058 993 * 1059 * Requires the HTTP extension to be installed. This would be the preferred 1060 * transport since it can handle a lot of the problems that forces the others to 1061 * use the HTTP version 1.0. Even if PHP 5.2+ is being used, it doesn't mean 1062 * that the HTTP extension will be enabled. 994 * Requires the HTTP extension to be installed. This would be the preferred transport since it can 995 * handle a lot of the problems that forces the others to use the HTTP version 1.0. Even if PHP 5.2+ 996 * is being used, it doesn't mean that the HTTP extension will be enabled. 1063 997 * 1064 998 * @package WordPress 1065 999 * @subpackage HTTP … … 1095 1029 $r['user-agent'] = $r['headers']['user-agent']; 1096 1030 unset($r['headers']['user-agent']); 1097 1031 } 1098 1032 1099 1033 // Construct Cookie: header if any cookies are set 1100 1034 WP_Http::buildCookieHeader( $r ); 1101 1035 … … 1128 1062 ) 1129 1063 ); 1130 1064 1065 // The HTTP extensions offers really easy proxy support. 1066 $proxy = new WP_HTTP_Proxy(); 1067 1068 if ( $proxy->is_enabled() && $proxy->send_through_proxy( $url ) ) { 1069 $options['proxyhost'] = $proxy->host(); 1070 $options['proxyport'] = $proxy->port(); 1071 $options['proxytype'] = HTTP_PROXY_HTTP; 1072 1073 if ( $proxy->use_authentication() ) { 1074 $options['proxyauth'] = $proxy->authentication(); 1075 $options['proxyauthtype'] = HTTP_AUTH_BASIC; 1076 } 1077 } 1078 1131 1079 if ( !defined('WP_DEBUG') || ( defined('WP_DEBUG') && false === WP_DEBUG ) ) //Emits warning level notices for max redirects and timeouts 1132 1080 $strResponse = @http_request($r['method'], $url, $r['body'], $options, $info); 1133 1081 else 1134 1082 $strResponse = http_request($r['method'], $url, $r['body'], $options, $info); //Emits warning level notices for max redirects and timeouts 1135 1083 1136 if ( false === $strResponse || ! empty($info['error']) ) //Error may still be set, Response may return headers or partial document, and error contains a reason the request was aborted, eg, timeout expired or max-redirects reached 1084 // Error may still be set, Response may return headers or partial document, and error 1085 // contains a reason the request was aborted, eg, timeout expired or max-redirects reached. 1086 if ( false === $strResponse || ! empty($info['error']) ) 1137 1087 return new WP_Error('http_request_failed', $info['response_code'] . ': ' . $info['error']); 1138 1088 1139 1089 if ( ! $r['blocking'] ) … … 1168 1118 * @return boolean False means this class can not be used, true means it can. 1169 1119 */ 1170 1120 function test() { 1171 if ( function_exists('http_request') )1121 if ( function_exists('http_request') && apply_filters('use_http_extension_transport', true) ) 1172 1122 return true; 1173 1123 1174 1124 return false; … … 1185 1135 * @since 2.7 1186 1136 */ 1187 1137 class WP_Http_Curl { 1138 1188 1139 /** 1189 1140 * Send a HTTP request to a URI using cURL extension. 1190 1141 * … … 1212 1163 $r['user-agent'] = $r['headers']['user-agent']; 1213 1164 unset($r['headers']['user-agent']); 1214 1165 } 1215 1216 // Construct Cookie: header if any cookies are set 1166 1167 // Construct Cookie: header if any cookies are set. 1217 1168 WP_Http::buildCookieHeader( $r ); 1218 1169 1219 // cURL extension will sometimes fail when the timeout is less than 1 as 1220 // it may round downto 0, which gives it unlimited timeout.1170 // cURL extension will sometimes fail when the timeout is less than 1 as it may round down 1171 // to 0, which gives it unlimited timeout. 1221 1172 if ( $r['timeout'] > 0 && $r['timeout'] < 1 ) 1222 1173 $r['timeout'] = 1; 1223 1174 1224 1175 $handle = curl_init(); 1225 1176 1177 // cURL offers really easy proxy support. 1178 $proxy = new WP_HTTP_Proxy(); 1179 1180 if ( $proxy->is_enabled() && $proxy->send_through_proxy( $url ) ) { 1181 curl_setopt( $handle, CURLOPT_HTTPPROXYTUNNEL, true ); 1182 1183 $isPHP5 = version_compare(PHP_VERSION, '5.0.0', '>='); 1184 1185 if ( $isPHP5 ) { 1186 curl_setopt( $handle, CURLOPT_PROXYTYPE, CURLPROXY_HTTP ); 1187 curl_setopt( $handle, CURLOPT_PROXY, $proxy->host() ); 1188 curl_setopt( $handle, CURLOPT_PROXYPORT, $proxy->port() ); 1189 } else { 1190 curl_setopt( $handle, CURLOPT_PROXY, $proxy->host() .':'. $proxy->port() ); 1191 } 1192 1193 if ( $proxy->use_authentication() ) { 1194 if ( $isPHP5 ) 1195 curl_setopt( $handle, CURLOPT_PROXYAUTH, CURLAUTH_BASIC ); 1196 1197 curl_setopt( $handle, CURLOPT_PROXYUSERPWD, $proxy->authentication() ); 1198 } 1199 } 1200 1226 1201 curl_setopt( $handle, CURLOPT_URL, $url); 1227 1202 curl_setopt( $handle, CURLOPT_RETURNTRANSFER, true ); 1228 1203 curl_setopt( $handle, CURLOPT_SSL_VERIFYHOST, apply_filters('https_ssl_verify', $r['sslverify']) ); … … 1265 1240 else 1266 1241 curl_setopt( $handle, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1 ); 1267 1242 1268 // Cookies are not handled by the HTTP API currently. Allow for plugin 1269 // authors to handle it themselves... Although, it is somewhat pointless 1270 // without some reference. 1243 // Cookies are not handled by the HTTP API currently. Allow for plugin authors to handle it 1244 // themselves... Although, it is somewhat pointless without some reference. 1271 1245 do_action_ref_array( 'http_api_curl', array(&$handle) ); 1272 1246 1273 // We don't need to return the body, so don't. Just execute request 1274 // and return. 1247 // We don't need to return the body, so don't. Just execute request and return. 1275 1248 if ( ! $r['blocking'] ) { 1276 1249 curl_exec( $handle ); 1277 1250 curl_close( $handle ); … … 1320 1293 * @return boolean False means this class can not be used, true means it can. 1321 1294 */ 1322 1295 function test() { 1323 if ( function_exists('curl_init') && function_exists('curl_exec') )1296 if ( function_exists('curl_init') && function_exists('curl_exec') && apply_filters('use_curl_transport', true) ) 1324 1297 return true; 1325 1298 1326 1299 return false; 1327 1300 } 1328 1301 } 1329 1302 1303 /** 1304 * Adds Proxy support to the WordPress HTTP API. 1305 * 1306 * Proxy support is fringe enough that it isn't support in WordPress by default, meaning no plans 1307 * were made to implement it. Most WordPress users are not going to benefit with its support, but 1308 * enough people have made a stink out of the lack of it that it should be supported. 1309 * 1310 * There are caveats to proxy support. It requires that defines be made in the wp-config.php file to 1311 * enable proxy support. There are also a few filters that plugins can hook into for some of the 1312 * constants. 1313 * 1314 * The constants are as follows: 1315 * <ol> 1316 * <li>WP_PROXY_HOST - Enable proxy support and host for connecting.</li> 1317 * <li>WP_PROXY_PORT - Proxy port for connection. No default, must be defined.</li> 1318 * <li>WP_PROXY_USERNAME - Proxy username, if it requires authentication.</li> 1319 * <li>WP_PROXY_PASSWORD - Proxy password, if it requires authentication.</li> 1320 * <li>WP_PROXY_BYPASS_HOSTS - Will prevent the hosts in this list from going through the proxy. 1321 * You do not need to have localhost and the blog host in this list, because they will not be passed 1322 * through the proxy.</li> 1323 * </ol> 1324 * 1325 * An example can be as seen below. 1326 * <code> 1327 * define('WP_PROXY_HOST', '192.168.84.101'); 1328 * define('WP_PROXY_PORT', '8080'); 1329 * define('WP_PROXY_BYPASS_HOSTS', array('localhost', 'www.example.com')); 1330 * </code> 1331 * 1332 * @link http://core.trac.wordpress.org/ticket/4011 Proxy support ticket in WordPress. 1333 * @since unknown 1334 */ 1335 class WP_HTTP_Proxy { 1330 1336 1337 function WP_HTTP_Proxy() { 1338 $this->__construct(); 1339 } 1340 1341 function __construct() { 1342 1343 } 1344 1345 /** 1346 * Whether proxy connection should be used. 1347 * 1348 * @since unknown 1349 * @use WP_PROXY_HOST 1350 * @use WP_PROXY_PORT 1351 * 1352 * @return bool 1353 */ 1354 function is_enabled() { 1355 return ( defined('WP_PROXY_HOST') && defined('WP_PROXY_PORT') ); 1356 } 1357 1358 /** 1359 * Whether authentication should be used. 1360 * 1361 * @since unknown 1362 * @use WP_PROXY_USERNAME 1363 * @use WP_PROXY_PASSWORD 1364 * 1365 * @return bool 1366 */ 1367 function use_authentication() { 1368 return ( defined('WP_PROXY_USERNAME') && defined('WP_PROXY_PASSWORD') ); 1369 } 1370 1371 /** 1372 * Retrieve the host for the proxy server. 1373 * 1374 * @since unknown 1375 * 1376 * @return string 1377 */ 1378 function host() 1379 { 1380 if( defined('WP_PROXY_HOST') ) 1381 return WP_PROXY_HOST; 1382 1383 return ''; 1384 } 1385 1386 /** 1387 * Retrieve the port for the proxy server. 1388 * 1389 * @since unknown 1390 * 1391 * @return string 1392 */ 1393 function port() 1394 { 1395 if( defined('WP_PROXY_PORT') ) 1396 return WP_PROXY_PORT; 1397 1398 return ''; 1399 } 1400 1401 /** 1402 * Retrieve the username for proxy authentication. 1403 * 1404 * @since unknown 1405 * 1406 * @return string 1407 */ 1408 function username() 1409 { 1410 if( defined('WP_PROXY_USERNAME') ) 1411 return WP_PROXY_USERNAME; 1412 1413 return ''; 1414 } 1415 1416 /** 1417 * Retrieve the password for proxy authentication. 1418 * 1419 * @since unknown 1420 * 1421 * @return string 1422 */ 1423 function password() 1424 { 1425 if( defined('WP_PROXY_PASSWORD') ) 1426 return WP_PROXY_PASSWORD; 1427 1428 return ''; 1429 } 1430 1431 /** 1432 * Retrieve authentication string for proxy authentication. 1433 * 1434 * @since unknown 1435 * 1436 * @return string 1437 */ 1438 function authentication() { 1439 return $this->username() .':'. $this->password(); 1440 } 1441 1442 /** 1443 * Retrieve header string for proxy authentication. 1444 * 1445 * @since unknown 1446 * 1447 * @return string 1448 */ 1449 function authentication_header() { 1450 return 'Proxy-Authentication: Basic '. base64_encode( $this->authentication() ); 1451 } 1452 1453 /** 1454 * Whether URL should be sent through the proxy server. 1455 * 1456 * We want to keep localhost and the blog URL from being sent through the proxy server, because 1457 * some proxies can not handle this. We also have the constant available for defining other 1458 * hosts that won't be sent through the proxy. 1459 * 1460 * @uses WP_PROXY_BYPASS_HOSTS 1461 * @since unknown 1462 * 1463 * @param string $uri URI to check. 1464 * @return bool True, to send through the proxy and false if, the proxy should not be used. 1465 */ 1466 function send_through_proxy( $uri ) { 1467 // parse_url() only handles http, https type URLs, and will emit E_WARNING on failure. 1468 // This will be displayed on blogs, which is not reasonable. 1469 $check = @parse_url($uri); 1470 1471 // Malformed URL, can not process, but this could mean ssl, so let through anyway. 1472 if( $check === false ) 1473 return true; 1474 1475 $home = parse_url( get_bloginfo('site_url') ); 1476 1477 if ( $uri == 'localhost' || $uri == $home['host'] ) 1478 return false; 1479 1480 if ( defined('WP_PROXY_BYPASS_HOSTS') && is_array( WP_PROXY_BYPASS_HOSTS ) && in_array( $check['host'], WP_PROXY_BYPASS_HOSTS ) ) { 1481 return false; 1482 } 1483 1484 return true; 1485 } 1486 } 1487 1488 1331 1489 /** 1332 * Internal representation of a cookie.1490 * Internal representation of a single cookie. 1333 1491 * 1334 * Returned cookies are represented using this class, and when cookies are 1335 * set, if they are not already a WP_Http_Cookie() object, then they are turned 1336 * into one. 1492 * Returned cookies are represented using this class, and when cookies are set, if they are not 1493 * already a WP_Http_Cookie() object, then they are turned into one. 1337 1494 * 1495 * @todo The WordPress convention is to use underscores instead of camelCase for function and method 1496 * names. Need to switch to use underscores instead for the methods. 1497 * 1338 1498 * @package WordPress 1339 1499 * @subpackage HTTP 1500 * @since 2.8.0 1501 * @author Beau Lebens 1340 1502 */ 1341 1503 class WP_Http_Cookie { 1342 var $name, 1343 $value, 1344 $expires, 1345 $path, 1346 $domain; 1347 1504 1348 1505 /** 1349 * PHP4 style Constructor - Calls PHP5 Style Constructor 1506 * Cookie name. 1507 * 1508 * @since 2.8.0 1509 * @var string 1350 1510 */ 1511 var $name; 1512 1513 /** 1514 * Cookie value. 1515 * 1516 * @since 2.8.0 1517 * @var string 1518 */ 1519 var $value; 1520 1521 /** 1522 * When the cookie expires. 1523 * 1524 * @since 2.8.0 1525 * @var string 1526 */ 1527 var $expires; 1528 1529 /** 1530 * Cookie URL path. 1531 * 1532 * @since 2.8.0 1533 * @var string 1534 */ 1535 var $path; 1536 1537 /** 1538 * Cookie Domain. 1539 * 1540 * @since 2.8.0 1541 * @var string 1542 */ 1543 var $domain; 1544 1545 /** 1546 * PHP4 style Constructor - Calls PHP5 Style Constructor. 1547 * 1548 * @access public 1549 * @since 2.8.0 1550 * @param string|array $data Raw cookie data. 1551 */ 1351 1552 function WP_Http_Cookie( $data ) { 1352 return$this->__construct( $data );1553 $this->__construct( $data ); 1353 1554 } 1354 1555 1355 1556 /** 1356 1557 * Sets up this cookie object. 1357 1558 * 1559 * The parameter $data should be either an associative array containing the indices names below 1560 * or a header string detailing it. 1561 * 1562 * If it's an array, it should include the following elements: 1563 * <ol> 1564 * <li>Name</li> 1565 * <li>Value - should NOT be urlencoded already.</li> 1566 * <li>Expires - (optional) String or int (UNIX timestamp).</li> 1567 * <li>Path (optional)</li> 1568 * <li>Domain (optional)</li> 1569 * </ol> 1570 * 1358 1571 * @access public 1572 * @since 2.8.0 1359 1573 * 1360 * @param mixed $data Either an associative array describing the cookie, or a header-string detailing it. 1361 * If it's an array, it should include the following elements: 1362 * - name 1363 * - value [should NOT be urlencoded already] 1364 * - expires (optional) String or int (UNIX timestamp) 1365 * - path (optional) 1366 * - domain (optional) 1574 * @param string|array $data Raw cookie data. 1367 1575 */ 1368 1576 function __construct( $data ) { 1369 1577 if ( is_string( $data ) ) { 1370 1578 // Assume it's a header string direct from a previous request 1371 1579 $pairs = explode( ';', $data ); 1372 1580 1373 1581 // Special handling for first pair; name=value. Also be careful of "=" in value 1374 1582 $name = trim( substr( $pairs[0], 0, strpos( $pairs[0], '=' ) ) ); 1375 1583 $value = substr( $pairs[0], strpos( $pairs[0], '=' ) + 1 ); 1376 1584 $this->name = $name; 1377 1585 $this->value = urldecode( $value ); 1378 1586 array_shift( $pairs ); //Removes name=value from items. 1379 1587 1380 1588 // Set everything else as a property 1381 1589 foreach ( $pairs as $pair ) { 1382 1590 if ( empty($pair) ) //Handles the cookie ending in ; which results in a empty final pair 1383 1591 continue; 1592 1384 1593 list( $key, $val ) = explode( '=', $pair ); 1385 1594 $key = strtolower( trim( $key ) ); 1386 1595 if ( 'expires' == $key ) … … 1390 1599 } else { 1391 1600 if ( !isset( $data['name'] ) ) 1392 1601 return false; 1393 1602 1394 1603 // Set properties based directly on parameters 1395 1604 $this->name = $data['name']; 1396 1605 $this->value = isset( $data['value'] ) ? $data['value'] : ''; 1397 1606 $this->path = isset( $data['path'] ) ? $data['path'] : ''; 1398 1607 $this->domain = isset( $data['domain'] ) ? $data['domain'] : ''; 1608 1399 1609 if ( isset( $data['expires'] ) ) 1400 1610 $this->expires = is_int( $data['expires'] ) ? $data['expires'] : strtotime( $data['expires'] ); 1401 1611 else 1402 1612 $this->expires = null; 1403 1613 } 1404 1614 } 1405 1615 1406 1616 /** 1407 1617 * Confirms that it's OK to send this cookie to the URL checked against. 1408 1618 * 1409 1619 * Decision is based on RFC 2109/2965, so look there for details on validity. 1410 1620 * 1411 1621 * @access public 1622 * @since 2.8.0 1412 1623 * 1413 1624 * @param string $url URL you intend to send this cookie to 1414 1625 * @return boolean TRUE if allowed, FALSE otherwise. … … 1417 1628 // Expires - if expired then nothing else matters 1418 1629 if ( time() > $this->expires ) 1419 1630 return false; 1420 1631 1421 1632 // Get details on the URL we're thinking about sending to 1422 1633 $url = parse_url( $url ); 1423 1634 $url['port'] = isset( $url['port'] ) ? $url['port'] : 80; 1424 1635 $url['path'] = isset( $url['path'] ) ? $url['path'] : '/'; 1425 1426 1636 1637 // Values to use for comparison against the URL 1427 1638 $path = isset( $this->path ) ? $this->path : '/'; 1428 1639 $port = isset( $this->port ) ? $this->port : 80; 1429 1640 $domain = isset( $this->domain ) ? strtolower( $this->domain ) : strtolower( $url['host'] ); 1430 1641 if ( false === stripos( $domain, '.' ) ) 1431 1642 $domain .= '.local'; 1432 1643 1433 1644 // Host - very basic check that the request URL ends with the domain restriction (minus leading dot) 1434 1645 $domain = substr( $domain, 0, 1 ) == '.' ? substr( $domain, 1 ) : $domain; 1435 1646 if ( substr( $url['host'], -strlen( $domain ) ) != $domain ) 1436 1647 return false; 1437 1648 1438 1649 // Port - supports "port-lists" in the format: "80,8000,8080" 1439 1650 if ( !in_array( $url['port'], explode( ',', $port) ) ) 1440 1651 return false; 1441 1652 1442 1653 // Path - request path must start with path restriction 1443 1654 if ( substr( $url['path'], 0, strlen( $path ) ) != $path ) 1444 1655 return false; 1445 1656 1446 1657 return true; 1447 1658 } 1448 1659 1660 /** 1661 * Convert cookie name and value back to header string. 1662 * 1663 * @access public 1664 * @since 2.8.0 1665 * 1666 * @return string Header encoded cookie name and value. 1667 */ 1449 1668 function getHeaderValue() { 1450 1669 if ( empty( $this->name ) || empty( $this->value ) ) 1451 1670 return ''; 1452 1671 1453 1672 return $this->name . '=' . urlencode( $this->value ); 1454 1673 } 1455 1674 1675 /** 1676 * Retrieve cookie header for usage in the rest of the WordPress HTTP API. 1677 * 1678 * @access public 1679 * @since 2.8.0 1680 * 1681 * @return string 1682 */ 1456 1683 function getFullHeader() { 1457 1684 return 'Cookie: ' . $this->getHeaderValue(); 1458 1685 } 1459 1686 } 1460 1687 1461 1688 /** 1689 * Implementation for deflate and gzip transfer encodings. 1690 * 1691 * Includes RFC 1950, RFC 1951, and RFC 1952. 1692 * 1693 * @since 2.8 1694 * @package WordPress 1695 * @subpackage HTTP 1696 */ 1697 class WP_Http_Encoding { 1698 1699 /** 1700 * Compress raw string using the deflate format. 1701 * 1702 * Supports the RFC 1951 standard. 1703 * 1704 * @since 2.8 1705 * 1706 * @param string $raw String to compress. 1707 * @param int $level Optional, default is 9. Compression level, 9 is highest. 1708 * @param string $supports Optional, not used. When implemented it will choose the right compression based on what the server supports. 1709 * @return string|bool False on failure. 1710 */ 1711 function compress( $raw, $level = 9, $supports = null ) { 1712 return gzdeflate( $raw, $level ); 1713 } 1714 1715 /** 1716 * Decompression of deflated string. 1717 * 1718 * Will attempt to decompress using the RFC 1950 standard, and if that fails 1719 * then the RFC 1951 standard deflate will be attempted. Finally, the RFC 1720 * 1952 standard gzip decode will be attempted. If all fail, then the 1721 * original compressed string will be returned. 1722 * 1723 * @since 2.8 1724 * 1725 * @param string $compressed String to decompress. 1726 * @param int $length The optional length of the compressed data. 1727 * @return string|bool False on failure. 1728 */ 1729 function decompress( $compressed, $length = null ) { 1730 $decompressed = gzinflate( $compressed ); 1731 1732 if( false !== $decompressed ) 1733 return $decompressed; 1734 1735 $decompressed = gzuncompress( $compressed ); 1736 1737 if( false !== $decompressed ) 1738 return $decompressed; 1739 1740 $decompressed = gzdecode( $compressed ); 1741 1742 if( false !== $decompressed ) 1743 return $decompressed; 1744 1745 return $compressed; 1746 } 1747 1748 /** 1749 * What encoding types to accept and their priority values. 1750 * 1751 * @since 2.8 1752 * 1753 * @return string Types of encoding to accept. 1754 */ 1755 function accept_encoding() { 1756 $type = array(); 1757 if( function_exists( 'gzinflate' ) ) 1758 $type[] = 'deflate;q=1.0'; 1759 1760 if( function_exists( 'gzuncompress' ) ) 1761 $type[] = 'compress;q=0.5'; 1762 1763 if( function_exists( 'gzdecode' ) ) 1764 $type[] = 'gzip;q=0.5'; 1765 1766 return implode(', ', $type); 1767 } 1768 1769 /** 1770 * What enconding the content used when it was compressed to send in the headers. 1771 * 1772 * @since 2.8 1773 * 1774 * @return string Content-Encoding string to send in the header. 1775 */ 1776 function content_encoding() { 1777 return 'deflate'; 1778 } 1779 1780 /** 1781 * Whether the content be decoded based on the headers. 1782 * 1783 * @since 2.8 1784 * 1785 * @param array|string $headers All of the available headers. 1786 * @return bool 1787 */ 1788 function should_decode($headers) { 1789 if( is_array( $headers ) ) { 1790 if( array_key_exists('content-encoding', $headers) && ! empty( $headers['content-encoding'] ) ) 1791 return true; 1792 } else if( is_string( $headers ) ) { 1793 return ( stripos($headers, 'content-encoding:') !== false ); 1794 } 1795 1796 return false; 1797 } 1798 1799 /** 1800 * Whether decompression and compression are supported by the PHP version. 1801 * 1802 * Each function is tested instead of checking for the zlib extension, to 1803 * ensure that the functions all exist in the PHP version and aren't 1804 * disabled. 1805 * 1806 * @since 2.8 1807 * 1808 * @return bool 1809 */ 1810 function is_available() { 1811 return ( function_exists('gzuncompress') || function_exists('gzdeflate') || 1812 function_exists('gzinflate') ); 1813 } 1814 } 1815 1816 /** 1462 1817 * Returns the initialized WP_Http Object 1463 1818 * 1464 1819 * @since 2.7.0