Make WordPress Core

Changeset 10625


Ignore:
Timestamp:
02/22/2009 09:58:47 AM (16 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.