WordPress.org

Make WordPress Core

Ticket #8927: 8927.diff

File 8927.diff, 16.2 KB (added by jacobsantos, 5 years ago)

Has HTTP API cleanup and adds capability to block requests through use of constants.

  • http.php

     
    228228                static $working_transport, $blocking_transport, $nonblocking_transport; 
    229229 
    230230                if ( is_null($working_transport) ) { 
    231                         if ( true === WP_Http_ExtHttp::test() && apply_filters('use_http_extension_transport', true) ) { 
     231                        if ( true === WP_Http_ExtHttp::test() ) { 
    232232                                $working_transport['exthttp'] = new WP_Http_ExtHttp(); 
    233233                                $blocking_transport[] = &$working_transport['exthttp']; 
    234                         } else if ( true === WP_Http_Curl::test() && apply_filters('use_curl_transport', true) ) { 
     234                        } else if ( true === WP_Http_Curl::test() ) { 
    235235                                $working_transport['curl'] = new WP_Http_Curl(); 
    236236                                $blocking_transport[] = &$working_transport['curl']; 
    237                         } else if ( true === WP_Http_Streams::test() && apply_filters('use_streams_transport', true) ) { 
     237                        } else if ( true === WP_Http_Streams::test() ) { 
    238238                                $working_transport['streams'] = new WP_Http_Streams(); 
    239239                                $blocking_transport[] = &$working_transport['streams']; 
    240                         } else if ( true === WP_Http_Fopen::test() && apply_filters('use_fopen_transport', true) && ( isset($args['ssl']) && !$args['ssl'] ) ) { 
     240                        } else if ( true === WP_Http_Fopen::test() && ( isset($args['ssl']) && !$args['ssl'] ) ) { 
    241241                                $working_transport['fopen'] = new WP_Http_Fopen(); 
    242242                                $blocking_transport[] = &$working_transport['fopen']; 
    243                         } else if ( true === WP_Http_Fsockopen::test() && apply_filters('use_fsockopen_transport', true) && ( isset($args['ssl']) && !$args['ssl'] ) ) { 
     243                        } else if ( true === WP_Http_Fsockopen::test() && ( isset($args['ssl']) && !$args['ssl'] ) ) { 
    244244                                $working_transport['fsockopen'] = new WP_Http_Fsockopen(); 
    245245                                $blocking_transport[] = &$working_transport['fsockopen']; 
    246246                        } 
     
    279279                static $working_transport, $blocking_transport, $nonblocking_transport; 
    280280 
    281281                if ( is_null($working_transport) ) { 
    282                         if ( true === WP_Http_ExtHttp::test() && apply_filters('use_http_extension_transport', true) ) { 
     282                        if ( true === WP_Http_ExtHttp::test() ) { 
    283283                                $working_transport['exthttp'] = new WP_Http_ExtHttp(); 
    284284                                $blocking_transport[] = &$working_transport['exthttp']; 
    285                         } else if ( true === WP_Http_Curl::test() && apply_filters('use_curl_transport', true) ) { 
     285                        } else if ( true === WP_Http_Curl::test() ) { 
    286286                                $working_transport['curl'] = new WP_Http_Curl(); 
    287287                                $blocking_transport[] = &$working_transport['curl']; 
    288                         } else if ( true === WP_Http_Streams::test() && apply_filters('use_streams_transport', true) ) { 
     288                        } else if ( true === WP_Http_Streams::test() ) { 
    289289                                $working_transport['streams'] = new WP_Http_Streams(); 
    290290                                $blocking_transport[] = &$working_transport['streams']; 
    291                         } else if ( true === WP_Http_Fsockopen::test() && apply_filters('use_fsockopen_transport', true) && ( isset($args['ssl']) && !$args['ssl'] ) ) { 
     291                        } else if ( true === WP_Http_Fsockopen::test() && ( isset($args['ssl']) && !$args['ssl'] ) ) { 
    292292                                $working_transport['fsockopen'] = new WP_Http_Fsockopen(); 
    293293                                $blocking_transport[] = &$working_transport['fsockopen']; 
    294294                        } 
     
    376376 
    377377                $arrURL = parse_url($url); 
    378378 
     379                if ( $this->block_request( $url ) ) 
     380                        return new WP_Error('http_request_failed', 'User has blocked requests through HTTP.'); 
     381 
    379382                // Determine if this is a https call and pass that on to the transport functions 
    380383                // so that we can blacklist the transports that do not support ssl verification 
    381384                if ( $arrURL['scheme'] == 'https' || $arrURL['scheme'] == 'ssl' ) 
     
    400403                        $r['user-agent'] = $r['headers']['user-agent']; 
    401404                        unset($r['headers']['user-agent']); 
    402405                } 
    403                  
     406 
    404407                // Construct Cookie: header if any cookies are set 
    405408                WP_Http::buildCookieHeader( $r ); 
    406409 
     
    514517        /** 
    515518         * Transform header string into an array. 
    516519         * 
    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. 
     520         * If an array is given then it is assumed to be raw header data with numeric keys with the 
     521         * headers as the values. No headers must be passed that were already processed. 
    520522         * 
    521523         * @access public 
    522524         * @static 
     
    564566         
    565567        /** 
    566568         * 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, which 
    568          * are each parsed into strings and added to the Cookie: header (within the 
    569          * arguments array). Edits the array by reference. 
    570569         * 
     570         * If it's found, then it's assumed to contain WP_Http_Cookie objects, which are each parsed 
     571         * into strings and added to the Cookie: header (within the arguments array). Edits the array by 
     572         * reference. 
     573         * 
    571574         * @access public 
     575         * @version 2.8.0 
    572576         * @static 
    573577         * 
    574578         * @param array $r Full array of args passed into ::request() 
     
    583587                        $r['headers']['cookie'] = $cookies_header; 
    584588                } 
    585589        } 
    586          
     590 
    587591        /** 
    588592         * Decodes chunk transfer-encoding, based off the HTTP 1.1 specification. 
    589593         * 
     
    630634                        } 
    631635                } 
    632636        } 
     637 
     638        /** 
     639         * Block requests through the proxy. 
     640         * 
     641         * Those who are behind a proxy and want to prevent access to certain hosts may do so. This will 
     642         * prevent plugins from working and core functionality, if you don't include api.wordpress.org. 
     643         * 
     644         * You block external URL requests by defining WP_HTTP_BLOCK_EXTERNAL in your wp-config.php file 
     645         * and this will only allow localhost and your blog to make requests. The constant 
     646         * WP_ACCESSABLE_HOSTS will allow additional hosts to go through for requests. 
     647         * 
     648         * @since unknown 
     649         * @link http://core.trac.wordpress.org/ticket/8927 Allow preventing external requests. 
     650         * 
     651         * @param string $uri URI of url. 
     652         * @return bool True to block, false to allow. 
     653         */ 
     654        function block_request($uri) { 
     655                // We don't need to block requests, because nothing is blocked. 
     656                if ( ! defined('WP_HTTP_BLOCK_EXTERNAL') || ( defined('WP_HTTP_BLOCK_EXTERNAL') && WP_HTTP_BLOCK_EXTERNAL == false ) ) 
     657                        return false; 
     658 
     659                // parse_url() only handles http, https type URLs, and will emit E_WARNING on failure. 
     660                // This will be displayed on blogs, which is not reasonable. 
     661                $check = @parse_url($uri); 
     662 
     663                /* Malformed URL, can not process, but this could mean ssl, so let through anyway. 
     664                 * 
     665                 * This isn't very security sound. There are instances where a hacker might attempt 
     666                 * to bypass the proxy and this check. However, the reason for this behavior is that 
     667                 * WordPress does not do any checking currently for non-proxy requests, so it is keeps with 
     668                 * the default unsecure nature of the HTTP request. 
     669                 */ 
     670                if ( $check === false ) 
     671                        return false; 
     672 
     673                $home = parse_url( get_bloginfo('site_url') ); 
     674 
     675                if ( $uri == 'localhost' || $uri == $home['host'] ) 
     676                        return false; 
     677 
     678                if ( defined('WP_ACCESSABLE_HOSTS') && is_array( WP_ACCESSABLE_HOSTS ) && in_array( $check['host'], WP_ACCESSABLE_HOSTS ) ) { 
     679                                return false; 
     680                } 
     681 
     682                return true; 
     683        } 
    633684} 
    634685 
    635686/** 
     
    798849                if ( false !== ($option = get_option( 'disable_fsockopen' )) && time()-$option < 43200 ) // 12 hours 
    799850                        return false; 
    800851 
    801                 if ( function_exists( 'fsockopen' ) ) 
     852                if ( function_exists( 'fsockopen' ) && apply_filters('use_fsockopen_transport', true) ) 
    802853                        return true; 
    803854 
    804855                return false; 
     
    911962                if ( ! function_exists('fopen') || (function_exists('ini_get') && true != ini_get('allow_url_fopen')) ) 
    912963                        return false; 
    913964 
    914                 return true; 
     965                return apply_filters('use_fopen_transport', true); 
    915966        } 
    916967} 
    917968 
     
    9551006                        $r['user-agent'] = $r['headers']['user-agent']; 
    9561007                        unset($r['headers']['user-agent']); 
    9571008                } 
    958                  
     1009 
    9591010                // Construct Cookie: header if any cookies are set 
    9601011                WP_Http::buildCookieHeader( $r ); 
    9611012 
     
    9841035                                'header' => $strHeaders, 
    9851036                                'timeout' => $r['timeout'], 
    9861037                                'ssl' => array( 
    987                                         'verify_peer' => apply_filters('https_ssl_verify', $r['sslverify']), 
    988                                         'verify_host' => apply_filters('https_ssl_verify', $r['sslverify']) 
    989                                 ) 
     1038                                                'verify_peer' => apply_filters('https_ssl_verify', $r['sslverify']), 
     1039                                                'verify_host' => apply_filters('https_ssl_verify', $r['sslverify']) 
     1040                                ) 
    9901041                        ) 
    9911042                ); 
    9921043 
     
    10491100                if ( version_compare(PHP_VERSION, '5.0', '<') ) 
    10501101                        return false; 
    10511102 
    1052                 return true; 
     1103                return apply_filters('use_streams_transport', true); 
    10531104        } 
    10541105} 
    10551106 
     
    10991150                // Construct Cookie: header if any cookies are set 
    11001151                WP_Http::buildCookieHeader( $r ); 
    11011152 
     1153                // Construct Cookie: header if any cookies are set 
     1154                WP_Http::buildCookieHeader( $r ); 
     1155 
    11021156                switch ( $r['method'] ) { 
    11031157                        case 'POST': 
    11041158                                $r['method'] = HTTP_METH_POST; 
     
    11331187                else 
    11341188                        $strResponse = http_request($r['method'], $url, $r['body'], $options, $info); //Emits warning level notices for max redirects and timeouts 
    11351189 
    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 
     1190                // Error may still be set, Response may return headers or partial document, and error 
     1191                // contains a reason the request was aborted, eg, timeout expired or max-redirects reached. 
     1192                if ( false === $strResponse || ! empty($info['error']) ) 
    11371193                        return new WP_Error('http_request_failed', $info['response_code'] . ': ' . $info['error']); 
    11381194 
    11391195                if ( ! $r['blocking'] ) 
     
    11681224         * @return boolean False means this class can not be used, true means it can. 
    11691225         */ 
    11701226        function test() { 
    1171                 if ( function_exists('http_request') ) 
     1227                if ( function_exists('http_request') && apply_filters('use_http_extension_transport', true) ) 
    11721228                        return true; 
    11731229 
    11741230                return false; 
     
    11851241 * @since 2.7 
    11861242 */ 
    11871243class WP_Http_Curl { 
     1244 
    11881245        /** 
    11891246         * Send a HTTP request to a URI using cURL extension. 
    11901247         * 
     
    12121269                        $r['user-agent'] = $r['headers']['user-agent']; 
    12131270                        unset($r['headers']['user-agent']); 
    12141271                } 
    1215                  
     1272 
    12161273                // Construct Cookie: header if any cookies are set 
    12171274                WP_Http::buildCookieHeader( $r ); 
    12181275 
     
    13201377         * @return boolean False means this class can not be used, true means it can. 
    13211378         */ 
    13221379        function test() { 
    1323                 if ( function_exists('curl_init') && function_exists('curl_exec') ) 
     1380                if ( function_exists('curl_init') && function_exists('curl_exec') && apply_filters('use_curl_transport', true) ) 
    13241381                        return true; 
    13251382 
    13261383                return false; 
     
    13291386 
    13301387 
    13311388/** 
    1332  * Internal representation of a cookie. 
     1389 * Internal representation of a single cookie. 
    13331390 * 
    13341391 * Returned cookies are represented using this class, and when cookies are 
    13351392 * set, if they are not already a WP_Http_Cookie() object, then they are turned 
    13361393 * into one. 
    13371394 * 
     1395 * @todo The WordPress convention is to use underscores instead of camelCase for function and method 
     1396 * names. Need to switch to use underscores instead for the methods. 
     1397 * 
    13381398 * @package WordPress 
    13391399 * @subpackage HTTP 
     1400 * @since 2.8.0 
     1401 * @author Beau Lebens 
    13401402 */ 
    13411403class WP_Http_Cookie { 
    1342         var $name, 
    1343                 $value, 
    1344                 $expires, 
    1345                 $path, 
    1346                 $domain; 
    1347          
     1404 
    13481405        /** 
    1349          * PHP4 style Constructor - Calls PHP5 Style Constructor 
     1406         * Cookie name. 
     1407         * 
     1408         * @since 2.8.0 
     1409         * @var string 
    13501410         */ 
     1411        var $name; 
     1412 
     1413        /** 
     1414         * Cookie value. 
     1415         * 
     1416         * @since 2.8.0 
     1417         * @var string 
     1418         */ 
     1419        var $value; 
     1420 
     1421        /** 
     1422         * When the cookie expires. 
     1423         * 
     1424         * @since 2.8.0 
     1425         * @var string 
     1426         */ 
     1427        var $expires; 
     1428 
     1429        /** 
     1430         * Cookie URL path. 
     1431         * 
     1432         * @since 2.8.0 
     1433         * @var string 
     1434         */ 
     1435        var $path; 
     1436 
     1437        /** 
     1438         * Cookie Domain. 
     1439         * 
     1440         * @since 2.8.0 
     1441         * @var string 
     1442         */ 
     1443        var $domain; 
     1444 
     1445        /** 
     1446         * PHP4 style Constructor - Calls PHP5 Style Constructor. 
     1447         * 
     1448         * @access public 
     1449         * @since 2.8.0 
     1450         * @param string|array $data Raw cookie data. 
     1451         */ 
    13511452        function WP_Http_Cookie( $data ) { 
    1352                 return $this->__construct( $data ); 
     1453                $this->__construct( $data ); 
    13531454        } 
    1354          
     1455 
    13551456        /** 
    13561457         * Sets up this cookie object. 
    13571458         * 
     1459         * The parameter $data should be either an associative array containing the indices names below 
     1460         * or a header string detailing it. 
     1461         * 
     1462         * If it's an array, it should include the following elements: 
     1463         * <ol> 
     1464         * <li>Name</li> 
     1465         * <li>Value - should NOT be urlencoded already.</li> 
     1466         * <li>Expires - (optional) String or int (UNIX timestamp).</li> 
     1467         * <li>Path (optional)</li> 
     1468         * <li>Domain (optional)</li> 
     1469         * </ol> 
     1470         * 
    13581471         * @access public 
     1472         * @since 2.8.0 
    13591473         * 
    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) 
     1474         * @param string|array $data Raw cookie data. 
    13671475         */ 
    13681476        function __construct( $data ) { 
    13691477                if ( is_string( $data ) ) { 
    13701478                        // Assume it's a header string direct from a previous request 
    13711479                        $pairs = explode( ';', $data ); 
    1372                          
     1480 
    13731481                        // Special handling for first pair; name=value. Also be careful of "=" in value 
    13741482                        $name  = trim( substr( $pairs[0], 0, strpos( $pairs[0], '=' ) ) ); 
    13751483                        $value = substr( $pairs[0], strpos( $pairs[0], '=' ) + 1 ); 
    13761484                        $this->name  = $name; 
    13771485                        $this->value = urldecode( $value ); 
    13781486                        array_shift( $pairs ); //Removes name=value from items. 
    1379                          
     1487 
    13801488                        // Set everything else as a property 
    13811489                        foreach ( $pairs as $pair ) { 
    13821490                                if ( empty($pair) ) //Handles the cookie ending in ; which results in a empty final pair 
    13831491                                        continue; 
     1492 
    13841493                                list( $key, $val ) = explode( '=', $pair ); 
    13851494                                $key = strtolower( trim( $key ) ); 
    13861495                                if ( 'expires' == $key ) 
     
    13901499                } else { 
    13911500                        if ( !isset( $data['name'] ) ) 
    13921501                                return false; 
    1393                          
     1502 
    13941503                        // Set properties based directly on parameters 
    13951504                        $this->name   = $data['name']; 
    13961505                        $this->value  = isset( $data['value'] ) ? $data['value'] : ''; 
    13971506                        $this->path   = isset( $data['path'] ) ? $data['path'] : ''; 
    13981507                        $this->domain = isset( $data['domain'] ) ? $data['domain'] : ''; 
     1508 
    13991509                        if ( isset( $data['expires'] ) ) 
    14001510                                $this->expires = is_int( $data['expires'] ) ? $data['expires'] : strtotime( $data['expires'] ); 
    14011511                        else 
    14021512                                $this->expires = null; 
    14031513                } 
    14041514        } 
    1405          
     1515 
    14061516        /** 
    14071517         * Confirms that it's OK to send this cookie to the URL checked against. 
    14081518         *  
    14091519         * Decision is based on RFC 2109/2965, so look there for details on validity. 
    14101520         * 
    14111521         * @access public 
     1522         * @since 2.8.0 
    14121523         * 
    14131524         * @param string $url URL you intend to send this cookie to 
    14141525         * @return boolean TRUE if allowed, FALSE otherwise. 
     
    14171528                // Expires - if expired then nothing else matters 
    14181529                if ( time() > $this->expires ) 
    14191530                        return false; 
    1420                  
     1531 
    14211532                // Get details on the URL we're thinking about sending to 
    14221533                $url = parse_url( $url ); 
    14231534                $url['port'] = isset( $url['port'] ) ? $url['port'] : 80; 
    14241535                $url['path'] = isset( $url['path'] ) ? $url['path'] : '/'; 
    1425                  
    1426                  // Values to use for comparison against the URL 
     1536 
     1537                // Values to use for comparison against the URL 
    14271538                $path   = isset( $this->path )   ? $this->path   : '/'; 
    14281539                $port   = isset( $this->port )   ? $this->port   : 80; 
    14291540                $domain = isset( $this->domain ) ? strtolower( $this->domain ) : strtolower( $url['host'] ); 
    14301541                if ( false === stripos( $domain, '.' ) ) 
    14311542                        $domain .= '.local'; 
    1432                  
     1543 
    14331544                // Host - very basic check that the request URL ends with the domain restriction (minus leading dot) 
    14341545                $domain = substr( $domain, 0, 1 ) == '.' ? substr( $domain, 1 ) : $domain; 
    14351546                if ( substr( $url['host'], -strlen( $domain ) ) != $domain ) 
    14361547                        return false; 
    1437                  
     1548 
    14381549                // Port - supports "port-lists" in the format: "80,8000,8080" 
    14391550                if ( !in_array( $url['port'], explode( ',', $port) ) ) 
    14401551                        return false; 
    1441                  
     1552 
    14421553                // Path - request path must start with path restriction 
    14431554                if ( substr( $url['path'], 0, strlen( $path ) ) != $path ) 
    14441555                        return false; 
    1445                  
     1556 
    14461557                return true; 
    14471558        } 
    1448          
     1559 
     1560        /** 
     1561         * Convert cookie name and value back to header string. 
     1562         * 
     1563         * @access public 
     1564         * @since 2.8.0 
     1565         * 
     1566         * @return string Header encoded cookie name and value. 
     1567         */ 
    14491568        function getHeaderValue() { 
    14501569                if ( empty( $this->name ) || empty( $this->value ) ) 
    14511570                        return ''; 
    14521571                 
    14531572                return $this->name . '=' . urlencode( $this->value ); 
    14541573        } 
    1455          
     1574 
     1575        /** 
     1576         * Retrieve cookie header for usage in the rest of the WordPress HTTP API. 
     1577         * 
     1578         * @access public 
     1579         * @since 2.8.0 
     1580         * 
     1581         * @return string 
     1582         */ 
    14561583        function getFullHeader() { 
    14571584                return 'Cookie: ' . $this->getHeaderValue(); 
    14581585        }