WordPress.org

Make WordPress Core

Ticket #9049: http-cookie-support-2.diff

File http-cookie-support-2.diff, 16.9 KB (added by beaulebens, 7 years ago)

Changed WP_Http_Fopen() so that it silently ignores cookies, as per other headers (since it can't send request headers)

  • http.php

     
    348348         * 
    349349         * @param string $url URI resource. 
    350350         * @param str|array $args Optional. Override the defaults. 
    351          * @return boolean 
     351         * @return array containing 'headers', 'body', 'response', 'cookies' 
    352352         */ 
    353353        function request( $url, $args = array() ) { 
    354354                global $wp_version; 
     
    386386                        $r['user-agent'] = $r['headers']['user-agent']; 
    387387                        unset($r['headers']['user-agent']); 
    388388                } 
     389                 
     390                // Construct Cookie: header if any cookies are set 
     391                WP_Http::buildCookieHeader( $r ); 
    389392 
    390393                if( WP_Http_Encoding::is_available() ) 
    391394                        $r['headers']['Accept-Encoding'] = WP_Http_Encoding::accept_encoding(); 
     
    411414                if( has_action('http_api_debug') ) 
    412415                        do_action('http_api_debug', $transports, 'transports_list'); 
    413416 
    414                 $response = array( 'headers' => array(), 'body' => '', 'response' => array('code', 'message') ); 
     417                $response = array( 'headers' => array(), 'body' => '', 'response' => array('code' => false, 'message' => false), 'cookies' => array() ); 
    415418                foreach( (array) $transports as $transport ) { 
    416419                        $response = $transport->request($url, $r); 
    417  
     420                         
    418421                        if( has_action('http_api_debug') ) 
    419422                                do_action( 'http_api_debug', $response, 'response', get_class($transport) ); 
    420423 
     
    506509         * @since 2.7.0 
    507510         * 
    508511         * @param string|array $headers 
    509          * @return array Processed string headers 
     512         * @return array Processed string headers. If duplicate headers are encountered, 
     513         *                                      Then a numbered array is returned as the value of that header-key. 
    510514         */ 
    511515        function processHeaders($headers) { 
    512516                if ( is_string($headers) ) 
     
    514518 
    515519                $response = array('code' => 0, 'message' => ''); 
    516520 
     521                $cookies = array(); 
    517522                $newheaders = array(); 
    518523                foreach ( $headers as $tempheader ) { 
    519524                        if ( empty($tempheader) ) 
     
    528533 
    529534                        list($key, $value) = explode(':', $tempheader, 2); 
    530535 
    531                         if ( ! empty($value) ) 
    532                                 $newheaders[strtolower($key)] = trim($value); 
     536                        if ( !empty( $value ) ) { 
     537                                $key = strtolower( $key ); 
     538                                if ( isset( $newheaders[$key] ) ) { 
     539                                        $newheaders[$key] = array( $newheaders[$key], trim( $value ) ); 
     540                                } else { 
     541                                        $newheaders[$key] = trim( $value ); 
     542                                } 
     543                                if ( 'set-cookie' == strtolower( $key ) ) 
     544                                        $cookies[] = new WP_Http_Cookie( $value ); 
     545                        } 
    533546                } 
    534547 
    535                 return array('response' => $response, 'headers' => $newheaders); 
     548                return array('response' => $response, 'headers' => $newheaders, 'cookies' => $cookies); 
    536549        } 
    537  
     550         
    538551        /** 
     552         * Takes the arguments for a ::request() and checks for the cookie array. 
     553         * If it's found, then it's assumed to contain WP_Http_Cookie objects, which 
     554         * are each parsed into strings and added to the Cookie: header (within the 
     555         * arguments array). Edits the array by reference. 
     556         * 
     557         * @access public 
     558         * @static 
     559         * 
     560         * @param array $r Full array of args passed into ::request() 
     561         */ 
     562        function buildCookieHeader( &$r ) { 
     563                if ( count( $r['cookies'] ) ) { 
     564                        $cookies_header = ''; 
     565                        foreach ( $r['cookies'] as $cookie ) { 
     566                                $cookies_header .= $cookie->getHeaderValue() . '; '; 
     567                        } 
     568                        $cookies_header = substr( $cookies_header, 0, -2 ); 
     569                        $r['headers']['cookie'] = $cookies_header; 
     570                } 
     571        } 
     572         
     573        /** 
    539574         * Decodes chunk transfer-encoding, based off the HTTP 1.1 specification. 
    540575         * 
    541576         * Based off the HTTP http_encoding_dechunk function. Does not support 
     
    605640         * @access public 
    606641         * @param string $url URI resource. 
    607642         * @param str|array $args Optional. Override the defaults. 
    608          * @return array 'headers', 'body', and 'response' keys. 
     643         * @return array 'headers', 'body', 'cookies' and 'response' keys. 
    609644         */ 
    610645        function request($url, $args = array()) { 
    611646                $defaults = array( 
     
    625660                        unset($r['headers']['user-agent']); 
    626661                } 
    627662 
     663                // Construct Cookie: header if any cookies are set 
     664                WP_Http::buildCookieHeader( $r ); 
     665 
    628666                $iError = null; // Store error number 
    629667                $strError = null; // Store error string 
    630668 
     
    697735 
    698736                if ( ! $r['blocking'] ) { 
    699737                        fclose($handle); 
    700                         return array( 'headers' => array(), 'body' => '', 'response' => array('code', 'message') ); 
     738                        return array( 'headers' => array(), 'body' => '', 'response' => array('code' => false, 'message' => false), 'cookies' => array() ); 
    701739                } 
    702740 
    703741                $strResponse = ''; 
     
    732770                if ( true === $r['decompress'] && true === WP_Http_Encoding::should_decode($arrHeaders) ) 
    733771                        $process['body'] = WP_Http_Encoding::decompress( $process['body'] ); 
    734772 
    735                 return array('headers' => $arrHeaders['headers'], 'body' => $process['body'], 'response' => $arrHeaders['response']); 
     773                return array('headers' => $arrHeaders['headers'], 'body' => $process['body'], 'response' => $arrHeaders['response'], 'cookies' => $arrHeaders['cookies']); 
    736774        } 
    737775 
    738776        /** 
     
    780818         * 
    781819         * @param string $url URI resource. 
    782820         * @param str|array $args Optional. Override the defaults. 
    783          * @return array 'headers', 'body', and 'response' keys. 
     821         * @return array 'headers', 'body', 'cookies' and 'response' keys. 
    784822         */ 
    785823        function request($url, $args = array()) { 
    786824                global $http_response_header; 
     
    789827                        'method' => 'GET', 'timeout' => 5, 
    790828                        'redirection' => 5, 'httpversion' => '1.0', 
    791829                        'blocking' => true, 
    792                         'headers' => array(), 'body' => null 
     830                        'headers' => array(), 'body' => null, 'cookies' => array() 
    793831                ); 
    794832 
    795833                $r = wp_parse_args( $args, $defaults ); 
     
    816854 
    817855                if ( ! $r['blocking'] ) { 
    818856                        fclose($handle); 
    819                         return array( 'headers' => array(), 'body' => '', 'response' => array('code', 'message') ); 
     857                        return array( 'headers' => array(), 'body' => '', 'response' => array('code' => false, 'message' => false), 'cookies' => array() ); 
    820858                } 
    821859 
    822860                $strResponse = ''; 
     
    845883                if ( true === $r['decompress'] && true === WP_Http_Encoding::should_decode($processedHeaders) ) 
    846884                        $strResponse = WP_Http_Encoding::decompress( $strResponse ); 
    847885 
    848                 return array('headers' => $processedHeaders['headers'], 'body' => $strResponse, 'response' => $processedHeaders['response']); 
     886                return array('headers' => $processedHeaders['headers'], 'body' => $strResponse, 'response' => $processedHeaders['response'], 'cookies' => $processedHeaders['cookies']); 
    849887        } 
    850888 
    851889        /** 
     
    884922         * 
    885923         * @param string $url 
    886924         * @param str|array $args Optional. Override the defaults. 
    887          * @return array 'headers', 'body', and 'response' keys. 
     925         * @return array 'headers', 'body', 'cookies' and 'response' keys. 
    888926         */ 
    889927        function request($url, $args = array()) { 
    890928                $defaults = array( 
    891929                        'method' => 'GET', 'timeout' => 5, 
    892930                        'redirection' => 5, 'httpversion' => '1.0', 
    893931                        'blocking' => true, 
    894                         'headers' => array(), 'body' => null 
     932                        'headers' => array(), 'body' => null, 'cookies' => array() 
    895933                ); 
    896934 
    897935                $r = wp_parse_args( $args, $defaults ); 
     
    903941                        $r['user-agent'] = $r['headers']['user-agent']; 
    904942                        unset($r['headers']['user-agent']); 
    905943                } 
     944                 
     945                // Construct Cookie: header if any cookies are set 
     946                WP_Http::buildCookieHeader( $r ); 
    906947 
    907948                $arrURL = parse_url($url); 
    908949 
     
    951992                if ( ! $r['blocking'] ) { 
    952993                        stream_set_blocking($handle, 0); 
    953994                        fclose($handle); 
    954                         return array( 'headers' => array(), 'body' => '', 'response' => array('code', 'message') ); 
     995                        return array( 'headers' => array(), 'body' => '', 'response' => array('code' => false, 'message' => false), 'cookies' => array() ); 
    955996                } 
    956997 
    957998                $strResponse = stream_get_contents($handle); 
     
    9711012                if ( true === $r['decompress'] && true === WP_Http_Encoding::should_decode($processedHeaders) ) 
    9721013                        $strResponse = WP_Http_Encoding::decompress( $strResponse ); 
    9731014 
    974                 return array('headers' => $processedHeaders['headers'], 'body' => $strResponse, 'response' => $processedHeaders['response']); 
     1015                return array('headers' => $processedHeaders['headers'], 'body' => $strResponse, 'response' => $processedHeaders['response'], 'cookies' => $processedHeaders['cookies']); 
    9751016        } 
    9761017 
    9771018        /** 
     
    10171058         * 
    10181059         * @param string $url 
    10191060         * @param str|array $args Optional. Override the defaults. 
    1020          * @return array 'headers', 'body', and 'response' keys. 
     1061         * @return array 'headers', 'body', 'cookies' and 'response' keys. 
    10211062         */ 
    10221063        function request($url, $args = array()) { 
    10231064                $defaults = array( 
    10241065                        'method' => 'GET', 'timeout' => 5, 
    10251066                        'redirection' => 5, 'httpversion' => '1.0', 
    10261067                        'blocking' => true, 
    1027                         'headers' => array(), 'body' => null 
     1068                        'headers' => array(), 'body' => null, 'cookies' => array() 
    10281069                ); 
    10291070 
    10301071                $r = wp_parse_args( $args, $defaults ); 
     
    10361077                        $r['user-agent'] = $r['headers']['user-agent']; 
    10371078                        unset($r['headers']['user-agent']); 
    10381079                } 
     1080                 
     1081                // Construct Cookie: header if any cookies are set 
     1082                WP_Http::buildCookieHeader( $r ); 
    10391083 
    10401084                switch ( $r['method'] ) { 
    10411085                        case 'POST': 
     
    10711115                        return new WP_Error('http_request_failed', $info['response_code'] . ': ' . $info['error']); 
    10721116 
    10731117                if ( ! $r['blocking'] ) 
    1074                         return array( 'headers' => array(), 'body' => '', 'response' => array('code', 'message') ); 
     1118                        return array( 'headers' => array(), 'body' => '', 'response' => array('code' => false, 'message' => false), 'cookies' => array() ); 
    10751119 
    10761120                list($theHeaders, $theBody) = explode("\r\n\r\n", $strResponse, 2); 
    10771121                $theHeaders = WP_Http::processHeaders($theHeaders); 
     
    10901134                $theResponse['code'] = $info['response_code']; 
    10911135                $theResponse['message'] = get_status_header_desc($info['response_code']); 
    10921136 
    1093                 return array('headers' => $theHeaders['headers'], 'body' => $theBody, 'response' => $theResponse); 
     1137                return array('headers' => $theHeaders['headers'], 'body' => $theBody, 'response' => $theResponse, 'cookies' => $theHeaders['cookies']); 
    10941138        } 
    10951139 
    10961140        /** 
     
    11271171         * 
    11281172         * @param string $url 
    11291173         * @param str|array $args Optional. Override the defaults. 
    1130          * @return array 'headers', 'body', and 'response' keys. 
     1174         * @return array 'headers', 'body', 'cookies' and 'response' keys. 
    11311175         */ 
    11321176        function request($url, $args = array()) { 
    11331177                $defaults = array( 
    11341178                        'method' => 'GET', 'timeout' => 5, 
    11351179                        'redirection' => 5, 'httpversion' => '1.0', 
    11361180                        'blocking' => true, 
    1137                         'headers' => array(), 'body' => null 
     1181                        'headers' => array(), 'body' => null, 'cookies' => array() 
    11381182                ); 
    11391183 
    11401184                $r = wp_parse_args( $args, $defaults ); 
     
    11461190                        $r['user-agent'] = $r['headers']['user-agent']; 
    11471191                        unset($r['headers']['user-agent']); 
    11481192                } 
     1193                 
     1194                // Construct Cookie: header if any cookies are set 
     1195                WP_Http::buildCookieHeader( $r ); 
    11491196 
    11501197                // cURL extension will sometimes fail when the timeout is less than 1 as 
    11511198                // it may round down to 0, which gives it unlimited timeout. 
     
    11541201 
    11551202                $handle = curl_init(); 
    11561203                curl_setopt( $handle, CURLOPT_URL, $url); 
    1157  
     1204                 
    11581205                // The cURL extension requires that the option be set for the HEAD to 
    11591206                // work properly. 
    11601207                if ( 'HEAD' === $r['method'] ) { 
     
    11791226                if ( !ini_get('safe_mode') && !ini_get('open_basedir') ) 
    11801227                        curl_setopt( $handle, CURLOPT_FOLLOWLOCATION, true ); 
    11811228 
    1182                 if( ! is_null($r['headers']) ) 
    1183                         curl_setopt( $handle, CURLOPT_HTTPHEADER, $r['headers'] ); 
     1229                if ( !empty( $r['headers'] ) ) { 
     1230                        // cURL expects full header strings in each element 
     1231                        $headers = array(); 
     1232                        foreach ( $r['headers'] as $name => $value ) { 
     1233                                $headers[] = "{$name}: $value"; 
     1234                        } 
     1235                        curl_setopt( $handle, CURLOPT_HTTPHEADER, $headers ); 
     1236                } 
    11841237 
    11851238                if ( $r['httpversion'] == '1.0' ) 
    11861239                        curl_setopt( $handle, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0 ); 
     
    11921245                // without some reference. 
    11931246                do_action_ref_array( 'http_api_curl', array(&$handle) ); 
    11941247 
    1195                 // We don't need to return the body, so don't. Just execution request 
     1248                // We don't need to return the body, so don't. Just execute request 
    11961249                // and return. 
    11971250                if ( ! $r['blocking'] ) { 
    11981251                        curl_exec( $handle ); 
    11991252                        curl_close( $handle ); 
    1200                         return array( 'headers' => array(), 'body' => '', 'response' => array('code', 'message') ); 
     1253                        return array( 'headers' => array(), 'body' => '', 'response' => array('code' => false, 'message' => false), 'cookies' => array() ); 
    12011254                } 
    12021255 
    12031256                $theResponse = curl_exec( $handle ); 
     
    12171270                        if ( in_array( curl_getinfo( $handle, CURLINFO_HTTP_CODE ), array(301, 302) ) ) 
    12181271                                return new WP_Error('http_request_failed', __('Too many redirects.')); 
    12191272 
    1220                         $theHeaders = array( 'headers' => array() ); 
     1273                        $theHeaders = array( 'headers' => array(), 'cookies' => array() ); 
    12211274                        $theBody = ''; 
    12221275                } 
    12231276 
     
    12301283                if ( true === $r['decompress'] && true === WP_Http_Encoding::should_decode($theHeaders) ) 
    12311284                        $theBody = WP_Http_Encoding::decompress( $theBody ); 
    12321285 
    1233                 return array('headers' => $theHeaders['headers'], 'body' => $theBody, 'response' => $response); 
     1286                return array('headers' => $theHeaders['headers'], 'body' => $theBody, 'response' => $response, 'cookies' => $theHeaders['cookies']); 
    12341287        } 
    12351288 
    12361289        /** 
     
    12491302        } 
    12501303} 
    12511304 
     1305 
    12521306/** 
     1307 * Internal representation of a cookie. 
     1308 * 
     1309 * Returned cookies are represented using this class, and when cookies are 
     1310 * set, if they are not already a WP_Http_Cookie() object, then they are turned 
     1311 * into one. 
     1312 * 
     1313 * @package WordPress 
     1314 * @subpackage HTTP 
     1315 */ 
     1316class WP_Http_Cookie { 
     1317        var $name, 
     1318                $value, 
     1319                $expires, 
     1320                $path, 
     1321                $domain; 
     1322         
     1323        /** 
     1324         * PHP4 style Constructor - Calls PHP5 Style Constructor 
     1325         */ 
     1326        function WP_Http_Cookie( $data ) { 
     1327                return $this->__construct( $data ); 
     1328        } 
     1329         
     1330        /** 
     1331         * Sets up this cookie object. 
     1332         * 
     1333         * @access public 
     1334         * 
     1335         * @param mixed $data Either an associative array describing the cookie, or a header-string detailing it. 
     1336         *              If it's an array, it should include the following elements: 
     1337         *                      - name 
     1338         *                      - value [should NOT be urlencoded already] 
     1339         *                      - expires (optional) String or int (UNIX timestamp) 
     1340         *                      - path (optional) 
     1341         *                      - domain (optional) 
     1342         */ 
     1343        function __construct( $data ) { 
     1344                if ( is_string( $data ) ) { 
     1345                        // Assume it's a header string direct from a previous request 
     1346                        $pairs = explode( ';', $data ); 
     1347                         
     1348                        // Special handling for first pair; name=value. Also be careful of "=" in value 
     1349                        $name  = trim( substr( $pairs[0], 0, strpos( $pairs[0], '=' ) ) ); 
     1350                        $value = substr( $pairs[0], strpos( $pairs[0], '=' ) + 1 ); 
     1351                        $this->name  = $name; 
     1352                        $this->value = urldecode( $value ); 
     1353                        array_shift( $pairs ); 
     1354                         
     1355                        // Set everything else as a property 
     1356                        foreach ( $pairs as $pair ) { 
     1357                                list( $key, $val ) = explode( '=', $pair ); 
     1358                                $key = strtolower( trim( $key ) ); 
     1359                                if ( 'expires' == $key ) 
     1360                                        $val = strtotime( $val ); 
     1361                                $this->$key = $val; 
     1362                        } 
     1363                } else { 
     1364                        // Set properties based directly on parameters 
     1365                        $this->name    = $data['name']; 
     1366                        $this->value   = $data['value']; 
     1367                        $this->expires = is_int( $data['expires'] ) ? $data['expires'] : strtotime( $data['expires'] ); 
     1368                        $this->path    = $data['path']; 
     1369                        $this->domain  = $data['domain']; 
     1370                } 
     1371        } 
     1372         
     1373        /** 
     1374         * Confirms that it's OK to send this cookie to the URL checked against. 
     1375         *  
     1376         * Decision is based on RFC 2109/2965, so look there for details on validity. 
     1377         * 
     1378         * @access public 
     1379         * 
     1380         * @param string $url URL you intend to send this cookie to 
     1381         * @return boolean TRUE if allowed, FALSE otherwise. 
     1382         */ 
     1383        function test( $url ) { 
     1384                // Expires - if expired then nothing else matters 
     1385                if ( time() > $this->expires ) 
     1386                        return false; 
     1387                 
     1388                // Get details on the URL we're thinking about sending to 
     1389                $url = parse_url( $url ); 
     1390                $url['port'] = isset( $url['port'] ) ? $url['port'] : 80; 
     1391                $url['path'] = isset( $url['path'] ) ? $url['path'] : '/'; 
     1392                 
     1393                 // Values to use for comparison against the URL 
     1394                $path   = isset( $this->path )   ? $this->path   : '/'; 
     1395                $port   = isset( $this->port )   ? $this->port   : 80; 
     1396                $domain = isset( $this->domain ) ? strtolower( $this->domain ) : strtolower( $url['host'] ); 
     1397                if ( false === stripos( $domain, '.' ) ) 
     1398                        $domain .= '.local'; 
     1399                 
     1400                // Host - very basic check that the request URL ends with the domain restriction (minus leading dot) 
     1401                $domain = substr( $domain, 0, 1 ) == '.' ? substr( $domain, 1 ) : $domain; 
     1402                if ( substr( $url['host'], -strlen( $domain ) ) != $domain ) 
     1403                        return false; 
     1404                 
     1405                // Port - supports "port-lists" in the format: "80,8000,8080" 
     1406                if ( !in_array( $url['port'], explode( ',', $port) ) ) 
     1407                        return false; 
     1408                 
     1409                // Path - request path must start with path restriction 
     1410                if ( substr( $url['path'], 0, strlen( $path ) ) != $path ) 
     1411                        return false; 
     1412                 
     1413                return true; 
     1414        } 
     1415         
     1416        function getHeaderValue() { 
     1417                if ( empty( $this->name ) || empty( $this->value ) ) 
     1418                        return ''; 
     1419                 
     1420                return $this->name . '=' . urlencode( $this->value ); 
     1421        } 
     1422         
     1423        function getFullHeader() { 
     1424                return 'Cookie: ' . $this->getHeaderValue(); 
     1425        } 
     1426} 
     1427 
     1428/** 
    12531429 * Returns the initialized WP_Http Object 
    12541430 * 
    12551431 * @since 2.7.0 
     
    12721448 * The array structure is a little complex. 
    12731449 * 
    12741450 * <code> 
    1275  * $res = array( 'headers' => array(), 'response' => array('code', 'message') ); 
     1451 * $res = array( 'headers' => array(), 'response' => array('code' => int, 'message' => string) ); 
    12761452 * </code> 
    12771453 * 
    12781454 * All of the headers in $res['headers'] are with the name as the key and the