Make WordPress Core


Ignore:
Timestamp:
02/05/2009 09:59:37 PM (18 years ago)
Author:
ryan
Message:

Cookie support for HTTP API. Props beaulebens. fixes #9049 #9037 #8727

File:
1 edited

Legend:

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

    r10509 r10512  
    352352         * @param string $url URI resource.
    353353         * @param str|array $args Optional. Override the defaults.
    354          * @return boolean
     354         * @return array containing 'headers', 'body', 'response', 'cookies'
    355355         */
    356356        function request( $url, $args = array() ) {
     
    400400                        unset($r['headers']['user-agent']);
    401401                }
     402               
     403                // Construct Cookie: header if any cookies are set
     404                WP_Http::buildCookieHeader( $r );
    402405
    403406                if( WP_Http_Encoding::is_available() )
     
    425428                        do_action('http_api_debug', $transports, 'transports_list');
    426429
    427                 $response = array( 'headers' => array(), 'body' => '', 'response' => array('code', 'message') );
     430                $response = array( 'headers' => array(), 'body' => '', 'response' => array('code' => false, 'message' => false), 'cookies' => array() );
    428431                foreach( (array) $transports as $transport ) {
    429432                        $response = $transport->request($url, $r);
    430 
     433                       
    431434                        if( has_action('http_api_debug') )
    432435                                do_action( 'http_api_debug', $response, 'response', get_class($transport) );
     
    520523         *
    521524         * @param string|array $headers
    522          * @return array Processed string headers
     525         * @return array Processed string headers. If duplicate headers are encountered,
     526         *                                      Then a numbered array is returned as the value of that header-key.
    523527         */
    524528        function processHeaders($headers) {
     
    528532                $response = array('code' => 0, 'message' => '');
    529533
     534                $cookies = array();
    530535                $newheaders = array();
    531536                foreach ( $headers as $tempheader ) {
     
    542547                        list($key, $value) = explode(':', $tempheader, 2);
    543548
    544                         if ( ! empty($value) )
    545                                 $newheaders[strtolower($key)] = trim($value);
    546                 }
    547 
    548                 return array('response' => $response, 'headers' => $newheaders);
    549         }
    550 
     549                        if ( !empty( $value ) ) {
     550                                $key = strtolower( $key );
     551                                if ( isset( $newheaders[$key] ) ) {
     552                                        $newheaders[$key] = array( $newheaders[$key], trim( $value ) );
     553                                } else {
     554                                        $newheaders[$key] = trim( $value );
     555                                }
     556                                if ( 'set-cookie' == strtolower( $key ) )
     557                                        $cookies[] = new WP_Http_Cookie( $value );
     558                        }
     559                }
     560
     561                return array('response' => $response, 'headers' => $newheaders, 'cookies' => $cookies);
     562        }
     563       
     564        /**
     565         * Takes the arguments for a ::request() and checks for the cookie array.
     566         * If it's found, then it's assumed to contain WP_Http_Cookie objects, which
     567         * are each parsed into strings and added to the Cookie: header (within the
     568         * arguments array). Edits the array by reference.
     569         *
     570         * @access public
     571         * @static
     572         *
     573         * @param array $r Full array of args passed into ::request()
     574         */
     575        function buildCookieHeader( &$r ) {
     576                if ( count( $r['cookies'] ) ) {
     577                        $cookies_header = '';
     578                        foreach ( $r['cookies'] as $cookie ) {
     579                                $cookies_header .= $cookie->getHeaderValue() . '; ';
     580                        }
     581                        $cookies_header = substr( $cookies_header, 0, -2 );
     582                        $r['headers']['cookie'] = $cookies_header;
     583                }
     584        }
     585       
    551586        /**
    552587         * Decodes chunk transfer-encoding, based off the HTTP 1.1 specification.
     
    619654         * @param string $url URI resource.
    620655         * @param str|array $args Optional. Override the defaults.
    621          * @return array 'headers', 'body', and 'response' keys.
     656         * @return array 'headers', 'body', 'cookies' and 'response' keys.
    622657         */
    623658        function request($url, $args = array()) {
     
    638673                        unset($r['headers']['user-agent']);
    639674                }
     675
     676                // Construct Cookie: header if any cookies are set
     677                WP_Http::buildCookieHeader( $r );
    640678
    641679                $iError = null; // Store error number
     
    711749                if ( ! $r['blocking'] ) {
    712750                        fclose($handle);
    713                         return array( 'headers' => array(), 'body' => '', 'response' => array('code', 'message') );
     751                        return array( 'headers' => array(), 'body' => '', 'response' => array('code' => false, 'message' => false), 'cookies' => array() );
    714752                }
    715753
     
    746784                        $process['body'] = WP_Http_Encoding::decompress( $process['body'] );
    747785
    748                 return array('headers' => $arrHeaders['headers'], 'body' => $process['body'], 'response' => $arrHeaders['response']);
     786                return array('headers' => $arrHeaders['headers'], 'body' => $process['body'], 'response' => $arrHeaders['response'], 'cookies' => $arrHeaders['cookies']);
    749787        }
    750788
     
    794832         * @param string $url URI resource.
    795833         * @param str|array $args Optional. Override the defaults.
    796          * @return array 'headers', 'body', and 'response' keys.
     834         * @return array 'headers', 'body', 'cookies' and 'response' keys.
    797835         */
    798836        function request($url, $args = array()) {
     
    803841                        'redirection' => 5, 'httpversion' => '1.0',
    804842                        'blocking' => true,
    805                         'headers' => array(), 'body' => null
     843                        'headers' => array(), 'body' => null, 'cookies' => array()
    806844                );
    807845
     
    830868                if ( ! $r['blocking'] ) {
    831869                        fclose($handle);
    832                         return array( 'headers' => array(), 'body' => '', 'response' => array('code', 'message') );
     870                        return array( 'headers' => array(), 'body' => '', 'response' => array('code' => false, 'message' => false), 'cookies' => array() );
    833871                }
    834872
     
    859897                        $strResponse = WP_Http_Encoding::decompress( $strResponse );
    860898
    861                 return array('headers' => $processedHeaders['headers'], 'body' => $strResponse, 'response' => $processedHeaders['response']);
     899                return array('headers' => $processedHeaders['headers'], 'body' => $strResponse, 'response' => $processedHeaders['response'], 'cookies' => $processedHeaders['cookies']);
    862900        }
    863901
     
    898936         * @param string $url
    899937         * @param str|array $args Optional. Override the defaults.
    900          * @return array 'headers', 'body', and 'response' keys.
     938         * @return array 'headers', 'body', 'cookies' and 'response' keys.
    901939         */
    902940        function request($url, $args = array()) {
     
    905943                        'redirection' => 5, 'httpversion' => '1.0',
    906944                        'blocking' => true,
    907                         'headers' => array(), 'body' => null
     945                        'headers' => array(), 'body' => null, 'cookies' => array()
    908946                );
    909947
     
    917955                        unset($r['headers']['user-agent']);
    918956                }
     957               
     958                // Construct Cookie: header if any cookies are set
     959                WP_Http::buildCookieHeader( $r );
    919960
    920961                $arrURL = parse_url($url);
     
    9691010                        stream_set_blocking($handle, 0);
    9701011                        fclose($handle);
    971                         return array( 'headers' => array(), 'body' => '', 'response' => array('code', 'message') );
     1012                        return array( 'headers' => array(), 'body' => '', 'response' => array('code' => false, 'message' => false), 'cookies' => array() );
    9721013                }
    9731014
     
    9891030                        $strResponse = WP_Http_Encoding::decompress( $strResponse );
    9901031
    991                 return array('headers' => $processedHeaders['headers'], 'body' => $strResponse, 'response' => $processedHeaders['response']);
     1032                return array('headers' => $processedHeaders['headers'], 'body' => $strResponse, 'response' => $processedHeaders['response'], 'cookies' => $processedHeaders['cookies']);
    9921033        }
    9931034
     
    10351076         * @param string $url
    10361077         * @param str|array $args Optional. Override the defaults.
    1037          * @return array 'headers', 'body', and 'response' keys.
     1078         * @return array 'headers', 'body', 'cookies' and 'response' keys.
    10381079         */
    10391080        function request($url, $args = array()) {
     
    10421083                        'redirection' => 5, 'httpversion' => '1.0',
    10431084                        'blocking' => true,
    1044                         'headers' => array(), 'body' => null
     1085                        'headers' => array(), 'body' => null, 'cookies' => array()
    10451086                );
    10461087
     
    10541095                        unset($r['headers']['user-agent']);
    10551096                }
     1097               
     1098                // Construct Cookie: header if any cookies are set
     1099                WP_Http::buildCookieHeader( $r );
    10561100
    10571101                switch ( $r['method'] ) {
     
    10931137
    10941138                if ( ! $r['blocking'] )
    1095                         return array( 'headers' => array(), 'body' => '', 'response' => array('code', 'message') );
     1139                        return array( 'headers' => array(), 'body' => '', 'response' => array('code' => false, 'message' => false), 'cookies' => array() );
    10961140
    10971141                list($theHeaders, $theBody) = explode("\r\n\r\n", $strResponse, 2);
     
    11121156                $theResponse['message'] = get_status_header_desc($info['response_code']);
    11131157
    1114                 return array('headers' => $theHeaders['headers'], 'body' => $theBody, 'response' => $theResponse);
     1158                return array('headers' => $theHeaders['headers'], 'body' => $theBody, 'response' => $theResponse, 'cookies' => $theHeaders['cookies']);
    11151159        }
    11161160
     
    11491193         * @param string $url
    11501194         * @param str|array $args Optional. Override the defaults.
    1151          * @return array 'headers', 'body', and 'response' keys.
     1195         * @return array 'headers', 'body', 'cookies' and 'response' keys.
    11521196         */
    11531197        function request($url, $args = array()) {
     
    11561200                        'redirection' => 5, 'httpversion' => '1.0',
    11571201                        'blocking' => true,
    1158                         'headers' => array(), 'body' => null
     1202                        'headers' => array(), 'body' => null, 'cookies' => array()
    11591203                );
    11601204
     
    11681212                        unset($r['headers']['user-agent']);
    11691213                }
     1214               
     1215                // Construct Cookie: header if any cookies are set
     1216                WP_Http::buildCookieHeader( $r );
    11701217
    11711218                // cURL extension will sometimes fail when the timeout is less than 1 as
     
    12041251                        curl_setopt( $handle, CURLOPT_FOLLOWLOCATION, true );
    12051252
    1206                 if( ! is_null($r['headers']) )
    1207                         curl_setopt( $handle, CURLOPT_HTTPHEADER, $r['headers'] );
     1253                if ( !empty( $r['headers'] ) ) {
     1254                        // cURL expects full header strings in each element
     1255                        $headers = array();
     1256                        foreach ( $r['headers'] as $name => $value ) {
     1257                                $headers[] = "{$name}: $value";
     1258                        }
     1259                        curl_setopt( $handle, CURLOPT_HTTPHEADER, $headers );
     1260                }
    12081261
    12091262                if ( $r['httpversion'] == '1.0' )
     
    12171270                do_action_ref_array( 'http_api_curl', array(&$handle) );
    12181271
    1219                 // We don't need to return the body, so don't. Just execution request
     1272                // We don't need to return the body, so don't. Just execute request
    12201273                // and return.
    12211274                if ( ! $r['blocking'] ) {
    12221275                        curl_exec( $handle );
    12231276                        curl_close( $handle );
    1224                         return array( 'headers' => array(), 'body' => '', 'response' => array('code', 'message') );
     1277                        return array( 'headers' => array(), 'body' => '', 'response' => array('code' => false, 'message' => false), 'cookies' => array() );
    12251278                }
    12261279
     
    12421295                                return new WP_Error('http_request_failed', __('Too many redirects.'));
    12431296
    1244                         $theHeaders = array( 'headers' => array() );
     1297                        $theHeaders = array( 'headers' => array(), 'cookies' => array() );
    12451298                        $theBody = '';
    12461299                }
     
    12551308                        $theBody = WP_Http_Encoding::decompress( $theBody );
    12561309
    1257                 return array('headers' => $theHeaders['headers'], 'body' => $theBody, 'response' => $response);
     1310                return array('headers' => $theHeaders['headers'], 'body' => $theBody, 'response' => $response, 'cookies' => $theHeaders['cookies']);
    12581311        }
    12591312
     
    12741327}
    12751328
     1329
     1330/**
     1331 * Internal representation of a cookie.
     1332 *
     1333 * Returned cookies are represented using this class, and when cookies are
     1334 * set, if they are not already a WP_Http_Cookie() object, then they are turned
     1335 * into one.
     1336 *
     1337 * @package WordPress
     1338 * @subpackage HTTP
     1339 */
     1340class WP_Http_Cookie {
     1341        var $name,
     1342                $value,
     1343                $expires,
     1344                $path,
     1345                $domain;
     1346       
     1347        /**
     1348         * PHP4 style Constructor - Calls PHP5 Style Constructor
     1349         */
     1350        function WP_Http_Cookie( $data ) {
     1351                return $this->__construct( $data );
     1352        }
     1353       
     1354        /**
     1355         * Sets up this cookie object.
     1356         *
     1357         * @access public
     1358         *
     1359         * @param mixed $data Either an associative array describing the cookie, or a header-string detailing it.
     1360         *              If it's an array, it should include the following elements:
     1361         *                      - name
     1362         *                      - value [should NOT be urlencoded already]
     1363         *                      - expires (optional) String or int (UNIX timestamp)
     1364         *                      - path (optional)
     1365         *                      - domain (optional)
     1366         */
     1367        function __construct( $data ) {
     1368                if ( is_string( $data ) ) {
     1369                        // Assume it's a header string direct from a previous request
     1370                        $pairs = explode( ';', $data );
     1371                       
     1372                        // Special handling for first pair; name=value. Also be careful of "=" in value
     1373                        $name  = trim( substr( $pairs[0], 0, strpos( $pairs[0], '=' ) ) );
     1374                        $value = substr( $pairs[0], strpos( $pairs[0], '=' ) + 1 );
     1375                        $this->name  = $name;
     1376                        $this->value = urldecode( $value );
     1377                        array_shift( $pairs );
     1378                       
     1379                        // Set everything else as a property
     1380                        foreach ( $pairs as $pair ) {
     1381                                list( $key, $val ) = explode( '=', $pair );
     1382                                $key = strtolower( trim( $key ) );
     1383                                if ( 'expires' == $key )
     1384                                        $val = strtotime( $val );
     1385                                $this->$key = $val;
     1386                        }
     1387                } else {
     1388                        // Set properties based directly on parameters
     1389                        $this->name    = $data['name'];
     1390                        $this->value   = $data['value'];
     1391                        $this->expires = is_int( $data['expires'] ) ? $data['expires'] : strtotime( $data['expires'] );
     1392                        $this->path    = $data['path'];
     1393                        $this->domain  = $data['domain'];
     1394                }
     1395        }
     1396       
     1397        /**
     1398         * Confirms that it's OK to send this cookie to the URL checked against.
     1399         *
     1400         * Decision is based on RFC 2109/2965, so look there for details on validity.
     1401         *
     1402         * @access public
     1403         *
     1404         * @param string $url URL you intend to send this cookie to
     1405         * @return boolean TRUE if allowed, FALSE otherwise.
     1406         */
     1407        function test( $url ) {
     1408                // Expires - if expired then nothing else matters
     1409                if ( time() > $this->expires )
     1410                        return false;
     1411               
     1412                // Get details on the URL we're thinking about sending to
     1413                $url = parse_url( $url );
     1414                $url['port'] = isset( $url['port'] ) ? $url['port'] : 80;
     1415                $url['path'] = isset( $url['path'] ) ? $url['path'] : '/';
     1416               
     1417                 // Values to use for comparison against the URL
     1418                $path   = isset( $this->path )   ? $this->path   : '/';
     1419                $port   = isset( $this->port )   ? $this->port   : 80;
     1420                $domain = isset( $this->domain ) ? strtolower( $this->domain ) : strtolower( $url['host'] );
     1421                if ( false === stripos( $domain, '.' ) )
     1422                        $domain .= '.local';
     1423               
     1424                // Host - very basic check that the request URL ends with the domain restriction (minus leading dot)
     1425                $domain = substr( $domain, 0, 1 ) == '.' ? substr( $domain, 1 ) : $domain;
     1426                if ( substr( $url['host'], -strlen( $domain ) ) != $domain )
     1427                        return false;
     1428               
     1429                // Port - supports "port-lists" in the format: "80,8000,8080"
     1430                if ( !in_array( $url['port'], explode( ',', $port) ) )
     1431                        return false;
     1432               
     1433                // Path - request path must start with path restriction
     1434                if ( substr( $url['path'], 0, strlen( $path ) ) != $path )
     1435                        return false;
     1436               
     1437                return true;
     1438        }
     1439       
     1440        function getHeaderValue() {
     1441                if ( empty( $this->name ) || empty( $this->value ) )
     1442                        return '';
     1443               
     1444                return $this->name . '=' . urlencode( $this->value );
     1445        }
     1446       
     1447        function getFullHeader() {
     1448                return 'Cookie: ' . $this->getHeaderValue();
     1449        }
     1450}
     1451
    12761452/**
    12771453 * Returns the initialized WP_Http Object
     
    12971473 *
    12981474 * <code>
    1299  * $res = array( 'headers' => array(), 'response' => array('code', 'message') );
     1475 * $res = array( 'headers' => array(), 'response' => array('code' => int, 'message' => string) );
    13001476 * </code>
    13011477 *
Note: See TracChangeset for help on using the changeset viewer.