WordPress.org

Make WordPress Core

Ticket #16236: 16236.12.diff

File 16236.12.diff, 14.9 KB (added by sivel, 7 years ago)

Now that we are using CURLOPT_HEADERFUNCTION, use that for all header processing in cURL

  • wp-includes/class-http.php

     
    227227                        'body' => null,
    228228                        'compress' => false,
    229229                        'decompress' => true,
    230                         'sslverify' => true
     230                        'sslverify' => true,
     231                        'stream' => false,
     232                        'filename' => null
    231233                );
    232234
    233235                $r = wp_parse_args( $args, $defaults );
     
    255257                $r['local'] = $homeURL['host'] == $arrURL['host'] || 'localhost' == $arrURL['host'];
    256258                unset( $homeURL );
    257259
     260                // If we are streaming to a file but no filename was given drop it in the WP temp dir
     261                // and pick it's name using the basename of the $url
     262                if ( $r['stream']  && ! $r['filename'] )
     263                        $r['filename'] = get_temp_dir() . basename( $url );
     264
     265                // Force some settings if we are streaming to a file and check for existence and perms of destination directory
     266                if ( $r['stream'] ) {
     267                        $r['blocking'] = true;
     268                        if ( ! is_writable( dirname( $r['filename'] ) ) )
     269                                return new WP_Error( 'http_request_failed', __( 'Destination directory for file streaming does not exist or is not writable.' ) );
     270                }
     271
    258272                if ( is_null( $r['headers'] ) )
    259273                        $r['headers'] = array();
    260274
     
    748762                }
    749763
    750764                $strResponse = '';
    751                 while ( ! feof($handle) )
    752                         $strResponse .= fread($handle, 4096);
     765                $bodyStarted = false;
    753766
    754                 fclose($handle);
     767                // If streaming to a file setup the file handle
     768                if ( $r['stream'] ) {
     769                        if ( ! WP_DEBUG )
     770                                $stream_handle = @fopen( $r['filename'], 'w+' );
     771                        else
     772                                $stream_handle = fopen( $r['filename'], 'w+' );
     773                        if ( ! $stream_handle )
     774                                return new WP_Error( 'http_request_failed', sprintf( __( 'Could not open handle for fopen() to %s' ), $r['filename'] ) );
     775                }
    755776
     777                while ( ! feof($handle) ) {
     778                        if ( $r['stream'] ) {
     779                                $block = fread( $handle, 4096 );
     780                                if ( $bodyStarted ) {
     781                                        fwrite( $stream_handle, $block );
     782                                } else {
     783                                        $strResponse .= $block;
     784                                        if ( strpos( $strResponse, "\r\n\r\n" ) ) {
     785                                                $process = WP_Http::processResponse( $strResponse );
     786                                                $bodyStarted = true;
     787                                                fwrite( $stream_handle, $process['body'] );
     788                                                unset( $strResponse );
     789                                                $process['body'] = '';
     790                                        }
     791                                }
     792                        } else {
     793                                $strResponse .= fread( $handle, 4096 );
     794                        }
     795                }
     796
     797                fclose( $handle );
     798
    756799                if ( true === $secure_transport )
    757800                        error_reporting($error_reporting);
    758801
    759                 $process = WP_Http::processResponse($strResponse);
    760                 $arrHeaders = WP_Http::processHeaders($process['headers']);
     802                if ( $r['stream'] ) {
     803                        fclose( $stream_handle );
     804                        $arrHeaders = WP_Http::processHeaders( $process['headers'] );
     805                } else {
     806                        $process = WP_Http::processResponse( $strResponse );
     807                        $arrHeaders = WP_Http::processHeaders( $process['headers'] );
     808                        unset( $strResponse );
     809                }
    761810
    762811                // Is the response code within the 400 range?
    763812                if ( (int) $arrHeaders['response']['code'] >= 400 && (int) $arrHeaders['response']['code'] < 500 )
     
    779828                if ( true === $r['decompress'] && true === WP_Http_Encoding::should_decode($arrHeaders['headers']) )
    780829                        $process['body'] = WP_Http_Encoding::decompress( $process['body'] );
    781830
    782                 return array('headers' => $arrHeaders['headers'], 'body' => $process['body'], 'response' => $arrHeaders['response'], 'cookies' => $arrHeaders['cookies']);
     831                return array( 'headers' => $arrHeaders['headers'], 'body' => $process['body'], 'response' => $arrHeaders['response'], 'cookies' => $arrHeaders['cookies'], 'filename' => $r['filename'] );
    783832        }
    784833
    785834        /**
     
    10751124                        return array( 'headers' => array(), 'body' => '', 'response' => array('code' => false, 'message' => false), 'cookies' => array() );
    10761125                }
    10771126
    1078                 $strResponse = stream_get_contents($handle);
    1079                 $meta = stream_get_meta_data($handle);
     1127                if ( $r['stream'] ) {
     1128                        if ( ! WP_DEBUG )
     1129                                $stream_handle = @fopen( $r['filename'], 'w+' );
     1130                        else
     1131                                $stream_handle = fopen( $r['filename'], 'w+' );
     1132                        if ( ! $stream_handle )
     1133                                return new WP_Error( 'http_request_failed', sprintf( __( 'Could not open handle for fopen() to %s' ), $r['filename'] ) );
     1134                        stream_copy_to_stream( $handle, $stream_handle );
     1135                        fclose( $stream_handle );
     1136                        $strResponse = '';
     1137                } else {
     1138                        $strResponse = stream_get_contents( $handle );
     1139                }
    10801140
    1081                 fclose($handle);
     1141                $meta = stream_get_meta_data( $handle );
    10821142
     1143                fclose( $handle );
     1144
    10831145                $processedHeaders = array();
    10841146                if ( isset( $meta['wrapper_data']['headers'] ) )
    10851147                        $processedHeaders = WP_Http::processHeaders($meta['wrapper_data']['headers']);
     
    10921154                if ( true === $r['decompress'] && true === WP_Http_Encoding::should_decode($processedHeaders['headers']) )
    10931155                        $strResponse = WP_Http_Encoding::decompress( $strResponse );
    10941156
    1095                 return array('headers' => $processedHeaders['headers'], 'body' => $strResponse, 'response' => $processedHeaders['response'], 'cookies' => $processedHeaders['cookies']);
     1157                return array( 'headers' => $processedHeaders['headers'], 'body' => $strResponse, 'response' => $processedHeaders['response'], 'cookies' => $processedHeaders['cookies'], 'filename' => $r['filename'] );
    10961158        }
    10971159
    10981160        /**
     
    12601322                if ( true === $r['decompress'] && true === WP_Http_Encoding::should_decode($theHeaders['headers']) )
    12611323                        $theBody = http_inflate( $theBody );
    12621324
     1325                if ( $r['stream'] ) {
     1326                        if ( !WP_DEBUG )
     1327                                $stream_handle = @fopen( $r['filename'], 'w+' );
     1328                        else
     1329                                $stream_handle = fopen( $r['filename'], 'w+' );
     1330
     1331                        if ( ! $stream_handle )
     1332                                return new WP_Error( 'http_request_failed', sprintf( __( 'Could not open handle for fopen() to %s' ), $r['filename'] ) );
     1333
     1334                        fwrite( $stream_handle, $theBody );
     1335                        fclose( $stream_handle );
     1336                        $theBody = '';
     1337                }
     1338
    12631339                $theResponse = array();
    12641340                $theResponse['code'] = $info['response_code'];
    12651341                $theResponse['message'] = get_status_header_desc($info['response_code']);
    12661342
    1267                 return array('headers' => $theHeaders['headers'], 'body' => $theBody, 'response' => $theResponse, 'cookies' => $theHeaders['cookies']);
     1343                return array( 'headers' => $theHeaders['headers'], 'body' => $theBody, 'response' => $theResponse, 'cookies' => $theHeaders['cookies'], 'filename' => $r['filename'] );
    12681344        }
    12691345
    12701346        /**
     
    12751351         *
    12761352         * @return boolean False means this class can not be used, true means it can.
    12771353         */
    1278         function test($args = array()) {
    1279                 return apply_filters('use_http_extension_transport', function_exists('http_request'), $args );
     1354        function test( $args = array() ) {
     1355                $use = true;
     1356
     1357                if ( ! function_exists( 'http_request' ) )
     1358                        $use = false;
     1359
     1360                return apply_filters( 'use_http_extension_transport', $use, $args );
    12801361        }
    12811362}
    12821363
     
    12921373class WP_Http_Curl {
    12931374
    12941375        /**
     1376         * Temporary header storage for use with streaming to a file.
     1377         *
     1378         * @since 3.2.0
     1379         * @access private
     1380         * @var string
     1381         */
     1382        private $headers;
     1383
     1384        /**
    12951385         * Send a HTTP request to a URI using cURL extension.
    12961386         *
    12971387         * @access public
     
    13831473                }
    13841474
    13851475                if ( true === $r['blocking'] )
    1386                         curl_setopt( $handle, CURLOPT_HEADER, true );
    1387                 else
    1388                         curl_setopt( $handle, CURLOPT_HEADER, false );
     1476                        curl_setopt( $handle, CURLOPT_HEADERFUNCTION, array( &$this, 'stream_headers' ) );
    13891477
     1478                curl_setopt( $handle, CURLOPT_HEADER, false );
     1479
     1480                // If streaming to a file open a file handle, and setup our callback for grabbing the headers
     1481                if ( $r['stream'] ) {
     1482                        if ( ! WP_DEBUG )
     1483                                $stream_handle = @fopen( $r['filename'], 'w+' );
     1484                        else
     1485                                $stream_handle = fopen( $r['filename'], 'w+' );
     1486                        if ( ! $stream_handle )
     1487                                return new WP_Error( 'http_request_failed', sprintf( __( 'Could not open handle for fopen() to %s' ), $r['filename'] ) );
     1488                        curl_setopt( $handle, CURLOPT_FILE, $stream_handle );
     1489                }
     1490
    13901491                // The option doesn't work with safe mode or when open_basedir is set.
    13911492                // Disable HEAD when making HEAD requests.
    13921493                if ( !ini_get('safe_mode') && !ini_get('open_basedir') && 'HEAD' != $r['method'] )
     
    14191520
    14201521                $theResponse = curl_exec( $handle );
    14211522
    1422                 if ( !empty($theResponse) ) {
    1423                         $headerLength = curl_getinfo($handle, CURLINFO_HEADER_SIZE);
    1424                         $theHeaders = trim( substr($theResponse, 0, $headerLength) );
    1425                         if ( strlen($theResponse) > $headerLength )
    1426                                 $theBody = substr( $theResponse, $headerLength );
     1523                if ( ! empty( $theResponse ) ) {
     1524                        if ( true === $r['stream'] )
     1525                                $theBody = '';
    14271526                        else
    1428                                 $theBody = '';
    1429                         if ( false !== strpos($theHeaders, "\r\n\r\n") ) {
    1430                                 $headerParts = explode("\r\n\r\n", $theHeaders);
    1431                                 $theHeaders = $headerParts[ count($headerParts) -1 ];
    1432                         }
    1433                         $theHeaders = WP_Http::processHeaders($theHeaders);
     1527                                $theBody = $theResponse;
     1528                        $theHeaders = WP_Http::processHeaders( $this->headers );
     1529                        unset( $this->headers );
    14341530                } else {
    1435                         if ( $curl_error = curl_error($handle) )
    1436                                 return new WP_Error('http_request_failed', $curl_error);
    1437                         if ( in_array( curl_getinfo( $handle, CURLINFO_HTTP_CODE ), array(301, 302) ) )
    1438                                 return new WP_Error('http_request_failed', __('Too many redirects.'));
     1531                        if ( $curl_error = curl_error( $handle ) )
     1532                                return new WP_Error( 'http_request_failed', $curl_error );
     1533                        if ( in_array( curl_getinfo( $handle, CURLINFO_HTTP_CODE ), array( 301, 302 ) ) )
     1534                                return new WP_Error( 'http_request_failed', __( 'Too many redirects.' ) );
    14391535
    14401536                        $theHeaders = array( 'headers' => array(), 'cookies' => array() );
    14411537                        $theBody = '';
     
    14471543
    14481544                curl_close( $handle );
    14491545
     1546                if ( $r['stream'] )
     1547                        fclose( $stream_handle );
     1548
    14501549                // See #11305 - When running under safe mode, redirection is disabled above. Handle it manually.
    14511550                if ( !empty($theHeaders['headers']['location']) && (ini_get('safe_mode') || ini_get('open_basedir')) ) {
    14521551                        if ( $r['redirection']-- > 0 ) {
     
    14591558                if ( true === $r['decompress'] && true === WP_Http_Encoding::should_decode($theHeaders['headers']) )
    14601559                        $theBody = WP_Http_Encoding::decompress( $theBody );
    14611560
    1462                 return array('headers' => $theHeaders['headers'], 'body' => $theBody, 'response' => $response, 'cookies' => $theHeaders['cookies']);
     1561                return array( 'headers' => $theHeaders['headers'], 'body' => $theBody, 'response' => $response, 'cookies' => $theHeaders['cookies'], 'filename' => $r['filename'] );
    14631562        }
    14641563
    14651564        /**
     1565         * Grab the headers of the cURL request when steraming to a file
     1566         *
     1567         * Each header is sent individually to this callback, so we append to the $header property for temporary storage
     1568         *
     1569         * @since 3.2.0
     1570         * @access private
     1571         * @return int
     1572         */
     1573        private function stream_headers( $handle, $headers ) {
     1574                $this->headers .= $headers;
     1575                return strlen( $headers );
     1576        }
     1577
     1578        /**
    14661579         * Whether this class can be used for retrieving an URL.
    14671580         *
    14681581         * @static
     
    14701583         *
    14711584         * @return boolean False means this class can not be used, true means it can.
    14721585         */
    1473         function test($args = array()) {
     1586        function test( $args = array() ) {
    14741587                if ( function_exists('curl_init') && function_exists('curl_exec') )
    14751588                        return apply_filters('use_curl_transport', true, $args);
    14761589
  • wp-includes/functions.php

     
    21112111}
    21122112
    21132113/**
     2114 * Determines a writable directory for temporary files.
     2115 * Function's preference is to WP_CONTENT_DIR followed by the return value of <code>sys_get_temp_dir()</code>, before finally defaulting to /tmp/
     2116 *
     2117 * In the event that this function does not find a writable location, It may be overridden by the <code>WP_TEMP_DIR</code> constant in your <code>wp-config.php</code> file.
     2118 *
     2119 * @since 2.5.0
     2120 *
     2121 * @return string Writable temporary directory
     2122 */
     2123function get_temp_dir() {
     2124        static $temp;
     2125        if ( defined('WP_TEMP_DIR') )
     2126                return trailingslashit(WP_TEMP_DIR);
     2127
     2128        if ( $temp )
     2129                return trailingslashit($temp);
     2130
     2131        $temp = WP_CONTENT_DIR . '/';
     2132        if ( is_dir($temp) && @is_writable($temp) )
     2133                return $temp;
     2134
     2135        if  ( function_exists('sys_get_temp_dir') ) {
     2136                $temp = sys_get_temp_dir();
     2137                if ( @is_writable($temp) )
     2138                        return trailingslashit($temp);
     2139        }
     2140
     2141        $temp = ini_get('upload_tmp_dir');
     2142        if ( is_dir($temp) && @is_writable($temp) )
     2143                return trailingslashit($temp);
     2144
     2145        $temp = '/tmp/';
     2146        return $temp;
     2147}
     2148
     2149/**
    21142150 * Get an array containing the current upload directory's path and url.
    21152151 *
    21162152 * Checks the 'upload_path' option, which should be from the web root folder,
  • wp-admin/includes/file.php

     
    153153}
    154154
    155155/**
    156  * Determines a writable directory for temporary files.
    157  * Function's preference is to WP_CONTENT_DIR followed by the return value of <code>sys_get_temp_dir()</code>, before finally defaulting to /tmp/
    158  *
    159  * In the event that this function does not find a writable location, It may be overridden by the <code>WP_TEMP_DIR</code> constant in your <code>wp-config.php</code> file.
    160  *
    161  * @since 2.5.0
    162  *
    163  * @return string Writable temporary directory
    164  */
    165 function get_temp_dir() {
    166         static $temp;
    167         if ( defined('WP_TEMP_DIR') )
    168                 return trailingslashit(WP_TEMP_DIR);
    169 
    170         if ( $temp )
    171                 return trailingslashit($temp);
    172 
    173         $temp = WP_CONTENT_DIR . '/';
    174         if ( is_dir($temp) && @is_writable($temp) )
    175                 return $temp;
    176 
    177         if  ( function_exists('sys_get_temp_dir') ) {
    178                 $temp = sys_get_temp_dir();
    179                 if ( @is_writable($temp) )
    180                         return trailingslashit($temp);
    181         }
    182 
    183         $temp = ini_get('upload_tmp_dir');
    184         if ( is_dir($temp) && @is_writable($temp) )
    185                 return trailingslashit($temp);
    186 
    187         $temp = '/tmp/';
    188         return $temp;
    189 }
    190 
    191 /**
    192156 * Returns a filename of a Temporary unique file.
    193157 * Please note that the calling function must unlink() this itself.
    194158 *
     
    513477function download_url( $url, $timeout = 300 ) {
    514478        //WARNING: The file is not automatically deleted, The script must unlink() the file.
    515479        if ( ! $url )
    516                 return new WP_Error('http_no_url', __('Invalid URL Provided.'));
     480                return new WP_Error( 'http_no_url', __( 'Invalid URL Provided.' ) );
    517481
    518         $tmpfname = wp_tempnam($url);
     482        $tmpfname = wp_tempnam( $url );
    519483        if ( ! $tmpfname )
    520                 return new WP_Error('http_no_file', __('Could not create Temporary file.'));
     484                return new WP_Error( 'http_no_file', __( 'Could not create Temporary file.' ) );
    521485
    522         $handle = @fopen($tmpfname, 'wb');
    523         if ( ! $handle )
    524                 return new WP_Error('http_no_file', __('Could not create Temporary file.'));
     486        $response = wp_remote_get( $url, array( 'timeout' => $timeout, 'stream' => true, 'filename' => $tmpfname ) );
    525487
    526         $response = wp_remote_get($url, array('timeout' => $timeout));
    527 
    528         if ( is_wp_error($response) ) {
    529                 fclose($handle);
    530                 unlink($tmpfname);
     488        if ( is_wp_error( $response ) ) {
     489                unlink( $tmpfname );
    531490                return $response;
    532491        }
    533492
    534493        if ( $response['response']['code'] != '200' ){
    535                 fclose($handle);
    536                 unlink($tmpfname);
    537                 return new WP_Error('http_404', trim($response['response']['message']));
     494                unlink( $tmpfname );
     495                return new WP_Error( 'http_404', trim( $response['response']['message'] ) );
    538496        }
    539497
    540         fwrite($handle, $response['body']);
    541         fclose($handle);
    542 
    543498        return $tmpfname;
    544499}
    545500