WordPress.org

Make WordPress Core

Ticket #23472: 23472.diff

File 23472.diff, 8.8 KB (added by dd32, 5 years ago)
  • wp-includes/class-http.php

     
    9595                        'decompress' => true,
    9696                        'sslverify' => true,
    9797                        'stream' => false,
    98                         'filename' => null
     98                        'filename' => null,
     99                        'first-x-bytes' => null,
    99100                );
    100101
    101102                // Pre-parse for the HEAD checks.
     
    166167                // Construct Cookie: header if any cookies are set
    167168                WP_Http::buildCookieHeader( $r );
    168169
    169                 if ( WP_Http_Encoding::is_available() )
     170                if ( WP_Http_Encoding::is_available( $r ) )
    170171                        $r['headers']['Accept-Encoding'] = WP_Http_Encoding::accept_encoding();
    171172
    172173                if ( ( ! is_null( $r['body'] ) && '' != $r['body'] ) || 'POST' == $r['method'] || 'PUT' == $r['method'] ) {
     
    731732
    732733                $strResponse = '';
    733734                $bodyStarted = false;
     735                $keep_reading = true;
     736                $block_size = 4096;
     737                if ( isset( $r['first-x-bytes'] ) )
     738                        $block_size = min( $block_size, $r['first-x-bytes'] );
    734739
    735740                // If streaming to a file setup the file handle
    736741                if ( $r['stream'] ) {
     
    741746                        if ( ! $stream_handle )
    742747                                return new WP_Error( 'http_request_failed', sprintf( __( 'Could not open handle for fopen() to %s' ), $r['filename'] ) );
    743748
    744                         while ( ! feof($handle) ) {
    745                                 $block = fread( $handle, 4096 );
    746                                 if ( $bodyStarted ) {
    747                                         fwrite( $stream_handle, $block );
    748                                 } else {
     749                        $bytes_written = 0;
     750                        while ( ! feof($handle) && $keep_reading ) {
     751                                $block = fread( $handle, $block_size );
     752                                if ( ! $bodyStarted ) {
    749753                                        $strResponse .= $block;
    750754                                        if ( strpos( $strResponse, "\r\n\r\n" ) ) {
    751755                                                $process = WP_Http::processResponse( $strResponse );
    752756                                                $bodyStarted = true;
    753                                                 fwrite( $stream_handle, $process['body'] );
     757                                                $block = $process['body'];
    754758                                                unset( $strResponse );
    755759                                                $process['body'] = '';
    756760                                        }
    757761                                }
     762                               
     763                                if ( isset( $r['first-x-bytes'] ) && ( $bytes_written + strlen( $block ) ) > $r['first-x-bytes'] ) {
     764                                        $block = substr( $block, 0, ( $r['first-x-bytes'] - $bytes_written ) );
     765                                }
     766                                $bytes_written += fwrite( $stream_handle, $block );                             
     767                               
     768                                $keep_reading = !isset( $r['first-x-bytes'] ) || $bytes_written < $r['first-x-bytes'];
    758769                        }
    759770
    760771                        fclose( $stream_handle );
    761772
    762773                } else {
    763                         while ( ! feof($handle) )
    764                                 $strResponse .= fread( $handle, 4096 );
     774                        $header_length = 0;
     775                        while ( ! feof( $handle ) && $keep_reading ) {
     776                                $block = fread( $handle, $block_size );
     777                                $strResponse .= $block;
     778                                if ( ! $bodyStarted && strpos( $strResponse, "\r\n\r\n" ) ) {
     779                                        $header_length = strpos( $strResponse, "\r\n\r\n" ) + 4;
     780                                        $bodyStarted = true;
     781                                }
     782                                $keep_reading = ( ! $bodyStarted || !isset( $r['first-x-bytes'] ) || strlen( $strResponse ) < ( $header_length + $r['first-x-bytes'] ) );
     783                        }
    765784
    766785                        $process = WP_Http::processResponse( $strResponse );
    767786                        unset( $strResponse );
     787
    768788                }
    769789
    770790                fclose( $handle );
     
    790810                if ( true === $r['decompress'] && true === WP_Http_Encoding::should_decode($arrHeaders['headers']) )
    791811                        $process['body'] = WP_Http_Encoding::decompress( $process['body'] );
    792812
     813                if ( isset( $r['first-x-bytes'] ) && strlen( $process['body'] ) > $r['first-x-bytes'] )
     814                        $process['body'] = substr( $process['body'], 0, $r['first-x-bytes'] );
     815
    793816                return array( 'headers' => $arrHeaders['headers'], 'body' => $process['body'], 'response' => $arrHeaders['response'], 'cookies' => $arrHeaders['cookies'], 'filename' => $r['filename'] );
    794817        }
    795818
     
    933956                        return array( 'headers' => array(), 'body' => '', 'response' => array('code' => false, 'message' => false), 'cookies' => array() );
    934957                }
    935958
     959                $max_bytes = isset( $r['first-x-bytes'] ) ? intval( $r['first-x-bytes'] ) : -1;
    936960                if ( $r['stream'] ) {
    937961                        if ( ! WP_DEBUG )
    938962                                $stream_handle = @fopen( $r['filename'], 'w+' );
     
    942966                        if ( ! $stream_handle )
    943967                                return new WP_Error( 'http_request_failed', sprintf( __( 'Could not open handle for fopen() to %s' ), $r['filename'] ) );
    944968
    945                         stream_copy_to_stream( $handle, $stream_handle );
     969                        stream_copy_to_stream( $handle, $stream_handle, $max_bytes );
    946970
    947971                        fclose( $stream_handle );
    948972                        $strResponse = '';
    949973                } else {
    950                         $strResponse = stream_get_contents( $handle );
     974                        $strResponse = stream_get_contents( $handle, $max_bytes );
    951975                }
    952976
    953977                $meta = stream_get_meta_data( $handle );
     
    10111035class WP_Http_Curl {
    10121036
    10131037        /**
    1014          * Temporary header storage for use with streaming to a file.
     1038         * Temporary header storage for during requests.
    10151039         *
    10161040         * @since 3.2.0
    10171041         * @access private
     
    10201044        private $headers = '';
    10211045
    10221046        /**
     1047         * Temporary body storage for during requests.
     1048         *
     1049         * @since 3.6.0
     1050         * @access private
     1051         * @var string
     1052         */
     1053        private $body = '';
     1054
     1055        /**
     1056         * The maximum amount of data to recieve from the remote server
     1057         *
     1058         * @since 3.6.0
     1059         * @access private
     1060         * @var int
     1061         */
     1062        private $max_body_length = false;
     1063
     1064        /**
     1065         * The file resource used for streaming to file.
     1066         *
     1067         * @since 3.6.0
     1068         * @access private
     1069         * @var resource
     1070         */
     1071        private $stream_handle = false;
     1072
     1073        /**
    10231074         * Send a HTTP request to a URI using cURL extension.
    10241075         *
    10251076         * @access public
     
    11081159                                break;
    11091160                }
    11101161
    1111                 if ( true === $r['blocking'] )
     1162                if ( true === $r['blocking'] ) {
    11121163                        curl_setopt( $handle, CURLOPT_HEADERFUNCTION, array( $this, 'stream_headers' ) );
     1164                        curl_setopt( $handle, CURLOPT_WRITEFUNCTION, array( $this, 'stream_body' ) );
     1165                }
    11131166
    11141167                curl_setopt( $handle, CURLOPT_HEADER, false );
    11151168
     1169                if ( isset( $r['first-x-bytes'] ) )
     1170                        $this->max_body_length = intval( $r['first-x-bytes'] );
     1171
    11161172                // If streaming to a file open a file handle, and setup our curl streaming handler
    11171173                if ( $r['stream'] ) {
    11181174                        if ( ! WP_DEBUG )
    1119                                 $stream_handle = @fopen( $r['filename'], 'w+' );
     1175                                $this->stream_handle = @fopen( $r['filename'], 'w+' );
    11201176                        else
    1121                                 $stream_handle = fopen( $r['filename'], 'w+' );
    1122                         if ( ! $stream_handle )
     1177                                $this->stream_handle = fopen( $r['filename'], 'w+' );
     1178                        if ( ! $this->stream_handle )
    11231179                                return new WP_Error( 'http_request_failed', sprintf( __( 'Could not open handle for fopen() to %s' ), $r['filename'] ) );
    1124                         curl_setopt( $handle, CURLOPT_FILE, $stream_handle );
    11251180                }
    11261181
    11271182                if ( !empty( $r['headers'] ) ) {
     
    11501205                }
    11511206
    11521207                $theResponse = curl_exec( $handle );
    1153                 $theBody = '';
    11541208                $theHeaders = WP_Http::processHeaders( $this->headers );
     1209                $theBody = $this->body;
    11551210
    1156                 if ( strlen($theResponse) > 0 && ! is_bool( $theResponse ) ) // is_bool: when using $args['stream'], curl_exec will return (bool)true
    1157                         $theBody = $theResponse;
     1211                $this->headers = '';
     1212                $this->body = '';
    11581213
    11591214                // If no response
    1160                 if ( 0 == strlen( $theResponse ) && empty( $theHeaders['headers'] ) ) {
     1215                if ( 0 == strlen( $theBody ) && empty( $theHeaders['headers'] ) ) {
    11611216                        if ( $curl_error = curl_error( $handle ) )
    11621217                                return new WP_Error( 'http_request_failed', $curl_error );
    11631218                        if ( in_array( curl_getinfo( $handle, CURLINFO_HTTP_CODE ), array( 301, 302 ) ) )
    11641219                                return new WP_Error( 'http_request_failed', __( 'Too many redirects.' ) );
    11651220                }
    11661221
    1167                 $this->headers = '';
    1168 
    11691222                $response = array();
    11701223                $response['code'] = curl_getinfo( $handle, CURLINFO_HTTP_CODE );
    11711224                $response['message'] = get_status_header_desc($response['code']);
     
    11731226                curl_close( $handle );
    11741227
    11751228                if ( $r['stream'] )
    1176                         fclose( $stream_handle );
     1229                        fclose( $this->stream_handle );
    11771230
    11781231                // See #11305 - When running under safe mode, redirection is disabled above. Handle it manually.
    11791232                if ( ! empty( $theHeaders['headers']['location'] ) && 0 !== $r['_redirection'] ) { // _redirection: The requested number of redirections
     
    12051258        }
    12061259
    12071260        /**
     1261         * Grab the body of the cURL request
     1262         *
     1263         * The contents of the document are passed in chunks, so we append to the $body property for temporary storage.
     1264         * Returning a length shorter than the length of $data passed in will cause cURL to abort the request as "completed"
     1265         *
     1266         * @since 3.6.0
     1267         * @access private
     1268         * @return int
     1269         */
     1270        private function stream_body( $handle, $data ) {
     1271                if ( $this->max_body_length && ( strlen( $this->body ) + strlen( $data ) ) > $this->max_body_length )
     1272                        $data = substr( $data, 0, ( $this->max_body_length - strlen( $this->body ) ) );
     1273
     1274                if ( $this->stream_handle )
     1275                        fwrite( $this->stream_handle, $data );
     1276                else
     1277                        $this->body .= $data;
     1278
     1279                return strlen( $data );
     1280        }
     1281
     1282        /**
    12081283         * Whether this class can be used for retrieving an URL.
    12091284         *
    12101285         * @static
     
    17851860         *
    17861861         * @return bool
    17871862         */
    1788         public static function is_available() {
     1863        public static function is_available( $args ) {
     1864                // If only partial content is being requested, we won't be able to decompress it
     1865                if ( isset( $args['first-x-bytes'] ) )
     1866                        return false;
     1867
    17891868                return ( function_exists('gzuncompress') || function_exists('gzdeflate') || function_exists('gzinflate') );
    17901869        }
    17911870}