Make WordPress Core

Changeset 10625


Ignore:
Timestamp:
02/22/2009 09:58:47 AM (18 years ago)
Author:
westi
Message:

Add support for blocking all outbound HTTP requests. Improve HTTP Api phpdoc. Tidy up the poetry. Fixes #8927 props jacobsantos.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/wp-includes/http.php

    r10565 r10625  
    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'];
    … …  
    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'];
    … …  
    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
    … …  
    401404                        unset($r['headers']['user-agent']);
    402405                }
    403                
     406
    404407                // Construct Cookie: header if any cookies are set
    405408                WP_Http::buildCookieHeader( $r );
    … …  
    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
    … …  
    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.
    570          *
    571          * @access public
     569         *
     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         *
     574         * @access public
     575         * @version 2.8.0
    572576         * @static
    573577         *
    … …  
    584588                }
    585589        }
    586        
     590
    587591        /**
    588592         * Decodes chunk transfer-encoding, based off the HTTP 1.1 specification.
    … …  
    630634                        }
    631635                }
     636        }
     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                // Don't block requests back to ourselves by default
     676                if ( $uri == 'localhost' || $uri == $home['host'] )
     677                        return apply_filters('block_local_requests', false);
     678
     679                if ( defined('WP_ACCESSABLE_HOSTS') && is_array( WP_ACCESSABLE_HOSTS ) && in_array( $check['host'], WP_ACCESSABLE_HOSTS ) ) {
     680                                return false;
     681                }
     682
     683                return true;
    632684        }
    633685}
    … …  
    800852
    801853                if ( function_exists( 'fsockopen' ) )
    802                         return true;
     854                        return apply_filters('use_fsockopen_transport', true);
    803855
    804856                return false;
    … …  
    912964                        return false;
    913965
    914                 return true;
     966                return apply_filters('use_fopen_transport', true);
    915967        }
    916968}
    … …  
    9561008                        unset($r['headers']['user-agent']);
    9571009                }
    958                
     1010
    9591011                // Construct Cookie: header if any cookies are set
    9601012                WP_Http::buildCookieHeader( $r );
    … …  
    9851037                                'timeout' => $r['timeout'],
    9861038                                'ssl' => array(
    987                                         'verify_peer' => apply_filters('https_ssl_verify', $r['sslverify']),
    988                                         'verify_host' => apply_filters('https_ssl_verify', $r['sslverify'])
    989                                 )
     1039                                                'verify_peer' => apply_filters('https_ssl_verify', $r['sslverify']),
     1040                                                'verify_host' => apply_filters('https_ssl_verify', $r['sslverify'])
     1041                                )
    9901042                        )
    9911043                );
    … …  
    10501102                        return false;
    10511103
    1052                 return true;
     1104                return apply_filters('use_streams_transport', true);
    10531105        }
    10541106}
    … …  
    11341186                        $strResponse = http_request($r['method'], $url, $r['body'], $options, $info); //Emits warning level notices for max redirects and timeouts
    11351187
    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
     1188                // Error may still be set, Response may return headers or partial document, and error
     1189                // contains a reason the request was aborted, eg, timeout expired or max-redirects reached.
     1190                if ( false === $strResponse || ! empty($info['error']) )
    11371191                        return new WP_Error('http_request_failed', $info['response_code'] . ': ' . $info['error']);
    11381192
    … …  
    11701224        function test() {
    11711225                if ( function_exists('http_request') )
    1172                         return true;
     1226                        return apply_filters('use_http_extension_transport', true);
    11731227
    11741228                return false;
    … …  
    11861240 */
    11871241class WP_Http_Curl {
     1242
    11881243        /**
    11891244         * Send a HTTP request to a URI using cURL extension.
    … …  
    12131268                        unset($r['headers']['user-agent']);
    12141269                }
    1215                
     1270
    12161271                // Construct Cookie: header if any cookies are set
    12171272                WP_Http::buildCookieHeader( $r );
    … …  
    13221377        function test() {
    13231378                if ( function_exists('curl_init') && function_exists('curl_exec') )
    1324                         return true;
     1379                        return  apply_filters('use_curl_transport', true);
    13251380
    13261381                return false;
    … …  
    13301385
    13311386/**
    1332  * Internal representation of a cookie.
     1387 * Internal representation of a single cookie.
    13331388 *
    13341389 * Returned cookies are represented using this class, and when cookies are
    … …  
    13361391 * into one.
    13371392 *
     1393 * @todo The WordPress convention is to use underscores instead of camelCase for function and method
     1394 * names. Need to switch to use underscores instead for the methods.
     1395 *
    13381396 * @package WordPress
    13391397 * @subpackage HTTP
     1398 * @since 2.8.0
     1399 * @author Beau Lebens
    13401400 */
    13411401class WP_Http_Cookie {
    1342         var $name,
    1343                 $value,
    1344                 $expires,
    1345                 $path,
    1346                 $domain;
    1347        
    1348         /**
    1349          * PHP4 style Constructor - Calls PHP5 Style Constructor
     1402
     1403        /**
     1404         * Cookie name.
     1405         *
     1406         * @since 2.8.0
     1407         * @var string
     1408         */
     1409        var $name;
     1410
     1411        /**
     1412         * Cookie value.
     1413         *
     1414         * @since 2.8.0
     1415         * @var string
     1416         */
     1417        var $value;
     1418
     1419        /**
     1420         * When the cookie expires.
     1421         *
     1422         * @since 2.8.0
     1423         * @var string
     1424         */
     1425        var $expires;
     1426
     1427        /**
     1428         * Cookie URL path.
     1429         *
     1430         * @since 2.8.0
     1431         * @var string
     1432         */
     1433        var $path;
     1434
     1435        /**
     1436         * Cookie Domain.
     1437         *
     1438         * @since 2.8.0
     1439         * @var string
     1440         */
     1441        var $domain;
     1442
     1443        /**
     1444         * PHP4 style Constructor - Calls PHP5 Style Constructor.
     1445         *
     1446         * @access public
     1447         * @since 2.8.0
     1448         * @param string|array $data Raw cookie data.
    13501449         */
    13511450        function WP_Http_Cookie( $data ) {
    1352                 return $this->__construct( $data );
    1353         }
    1354        
     1451                $this->__construct( $data );
     1452        }
     1453
    13551454        /**
    13561455         * Sets up this cookie object.
    13571456         *
    1358          * @access public
    1359          *
    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)
     1457         * The parameter $data should be either an associative array containing the indices names below
     1458         * or a header string detailing it.
     1459         *
     1460         * If it's an array, it should include the following elements:
     1461         * <ol>
     1462         * <li>Name</li>
     1463         * <li>Value - should NOT be urlencoded already.</li>
     1464         * <li>Expires - (optional) String or int (UNIX timestamp).</li>
     1465         * <li>Path (optional)</li>
     1466         * <li>Domain (optional)</li>
     1467         * </ol>
     1468         *
     1469         * @access public
     1470         * @since 2.8.0
     1471         *
     1472         * @param string|array $data Raw cookie data.
    13671473         */
    13681474        function __construct( $data ) {
    … …  
    13701476                        // Assume it's a header string direct from a previous request
    13711477                        $pairs = explode( ';', $data );
    1372                        
     1478
    13731479                        // Special handling for first pair; name=value. Also be careful of "=" in value
    13741480                        $name  = trim( substr( $pairs[0], 0, strpos( $pairs[0], '=' ) ) );
    … …  
    13771483                        $this->value = urldecode( $value );
    13781484                        array_shift( $pairs ); //Removes name=value from items.
    1379                        
     1485
    13801486                        // Set everything else as a property
    13811487                        foreach ( $pairs as $pair ) {
    13821488                                if ( empty($pair) ) //Handles the cookie ending in ; which results in a empty final pair
    13831489                                        continue;
     1490
    13841491                                list( $key, $val ) = explode( '=', $pair );
    13851492                                $key = strtolower( trim( $key ) );
    … …  
    13911498                        if ( !isset( $data['name'] ) )
    13921499                                return false;
    1393                        
     1500
    13941501                        // Set properties based directly on parameters
    13951502                        $this->name   = $data['name'];
    … …  
    13971504                        $this->path   = isset( $data['path'] ) ? $data['path'] : '';
    13981505                        $this->domain = isset( $data['domain'] ) ? $data['domain'] : '';
     1506
    13991507                        if ( isset( $data['expires'] ) )
    14001508                                $this->expires = is_int( $data['expires'] ) ? $data['expires'] : strtotime( $data['expires'] );
    … …  
    14031511                }
    14041512        }
    1405        
     1513
    14061514        /**
    14071515         * Confirms that it's OK to send this cookie to the URL checked against.
    … …  
    14101518         *
    14111519         * @access public
     1520         * @since 2.8.0
    14121521         *
    14131522         * @param string $url URL you intend to send this cookie to
    … …  
    14181527                if ( time() > $this->expires )
    14191528                        return false;
    1420                
     1529
    14211530                // Get details on the URL we're thinking about sending to
    14221531                $url = parse_url( $url );
    14231532                $url['port'] = isset( $url['port'] ) ? $url['port'] : 80;
    14241533                $url['path'] = isset( $url['path'] ) ? $url['path'] : '/';
    1425                
    1426                  // Values to use for comparison against the URL
     1534
     1535                // Values to use for comparison against the URL
    14271536                $path   = isset( $this->path )   ? $this->path   : '/';
    14281537                $port   = isset( $this->port )   ? $this->port   : 80;
    … …  
    14301539                if ( false === stripos( $domain, '.' ) )
    14311540                        $domain .= '.local';
    1432                
     1541
    14331542                // Host - very basic check that the request URL ends with the domain restriction (minus leading dot)
    14341543                $domain = substr( $domain, 0, 1 ) == '.' ? substr( $domain, 1 ) : $domain;
    14351544                if ( substr( $url['host'], -strlen( $domain ) ) != $domain )
    14361545                        return false;
    1437                
     1546
    14381547                // Port - supports "port-lists" in the format: "80,8000,8080"
    14391548                if ( !in_array( $url['port'], explode( ',', $port) ) )
    14401549                        return false;
    1441                
     1550
    14421551                // Path - request path must start with path restriction
    14431552                if ( substr( $url['path'], 0, strlen( $path ) ) != $path )
    14441553                        return false;
    1445                
     1554
    14461555                return true;
    14471556        }
    1448        
     1557
     1558        /**
     1559         * Convert cookie name and value back to header string.
     1560         *
     1561         * @access public
     1562         * @since 2.8.0
     1563         *
     1564         * @return string Header encoded cookie name and value.
     1565         */
    14491566        function getHeaderValue() {
    14501567                if ( empty( $this->name ) || empty( $this->value ) )
    … …  
    14531570                return $this->name . '=' . urlencode( $this->value );
    14541571        }
    1455        
     1572
     1573        /**
     1574         * Retrieve cookie header for usage in the rest of the WordPress HTTP API.
     1575         *
     1576         * @access public
     1577         * @since 2.8.0
     1578         *
     1579         * @return string
     1580         */
    14561581        function getFullHeader() {
    14571582                return 'Cookie: ' . $this->getHeaderValue();
Note: See TracChangeset for help on using the changeset viewer.