Index: wp-includes/class-http.php
===================================================================
--- wp-includes/class-http.php	(revision 23403)
+++ wp-includes/class-http.php	(working copy)
@@ -95,7 +95,8 @@
 			'decompress' => true,
 			'sslverify' => true,
 			'stream' => false,
-			'filename' => null
+			'filename' => null,
+			'first-x-bytes' => null,
 		);
 
 		// Pre-parse for the HEAD checks.
@@ -166,7 +167,7 @@
 		// Construct Cookie: header if any cookies are set
 		WP_Http::buildCookieHeader( $r );
 
-		if ( WP_Http_Encoding::is_available() )
+		if ( WP_Http_Encoding::is_available( $r ) )
 			$r['headers']['Accept-Encoding'] = WP_Http_Encoding::accept_encoding();
 
 		if ( ( ! is_null( $r['body'] ) && '' != $r['body'] ) || 'POST' == $r['method'] || 'PUT' == $r['method'] ) {
@@ -731,6 +732,10 @@
 
 		$strResponse = '';
 		$bodyStarted = false;
+		$keep_reading = true;
+		$block_size = 4096;
+		if ( isset( $r['first-x-bytes'] ) )
+			$block_size = min( $block_size, $r['first-x-bytes'] );
 
 		// If streaming to a file setup the file handle
 		if ( $r['stream'] ) {
@@ -741,30 +746,45 @@
 			if ( ! $stream_handle )
 				return new WP_Error( 'http_request_failed', sprintf( __( 'Could not open handle for fopen() to %s' ), $r['filename'] ) );
 
-			while ( ! feof($handle) ) {
-				$block = fread( $handle, 4096 );
-				if ( $bodyStarted ) {
-					fwrite( $stream_handle, $block );
-				} else {
+			$bytes_written = 0;
+			while ( ! feof($handle) && $keep_reading ) {
+				$block = fread( $handle, $block_size );
+				if ( ! $bodyStarted ) {
 					$strResponse .= $block;
 					if ( strpos( $strResponse, "\r\n\r\n" ) ) {
 						$process = WP_Http::processResponse( $strResponse );
 						$bodyStarted = true;
-						fwrite( $stream_handle, $process['body'] );
+						$block = $process['body'];
 						unset( $strResponse );
 						$process['body'] = '';
 					}
 				}
+				
+				if ( isset( $r['first-x-bytes'] ) && ( $bytes_written + strlen( $block ) ) > $r['first-x-bytes'] ) {
+					$block = substr( $block, 0, ( $r['first-x-bytes'] - $bytes_written ) );
+				}
+				$bytes_written += fwrite( $stream_handle, $block );				
+				
+				$keep_reading = !isset( $r['first-x-bytes'] ) || $bytes_written < $r['first-x-bytes'];
 			}
 
 			fclose( $stream_handle );
 
 		} else {
-			while ( ! feof($handle) )
-				$strResponse .= fread( $handle, 4096 );
+			$header_length = 0;
+			while ( ! feof( $handle ) && $keep_reading ) {
+				$block = fread( $handle, $block_size );
+				$strResponse .= $block;
+				if ( ! $bodyStarted && strpos( $strResponse, "\r\n\r\n" ) ) {
+					$header_length = strpos( $strResponse, "\r\n\r\n" ) + 4;
+					$bodyStarted = true;
+				}
+				$keep_reading = ( ! $bodyStarted || !isset( $r['first-x-bytes'] ) || strlen( $strResponse ) < ( $header_length + $r['first-x-bytes'] ) );
+			}
 
 			$process = WP_Http::processResponse( $strResponse );
 			unset( $strResponse );
+
 		}
 
 		fclose( $handle );
@@ -790,6 +810,9 @@
 		if ( true === $r['decompress'] && true === WP_Http_Encoding::should_decode($arrHeaders['headers']) )
 			$process['body'] = WP_Http_Encoding::decompress( $process['body'] );
 
+		if ( isset( $r['first-x-bytes'] ) && strlen( $process['body'] ) > $r['first-x-bytes'] )
+			$process['body'] = substr( $process['body'], 0, $r['first-x-bytes'] );
+
 		return array( 'headers' => $arrHeaders['headers'], 'body' => $process['body'], 'response' => $arrHeaders['response'], 'cookies' => $arrHeaders['cookies'], 'filename' => $r['filename'] );
 	}
 
@@ -933,6 +956,7 @@
 			return array( 'headers' => array(), 'body' => '', 'response' => array('code' => false, 'message' => false), 'cookies' => array() );
 		}
 
+		$max_bytes = isset( $r['first-x-bytes'] ) ? intval( $r['first-x-bytes'] ) : -1;
 		if ( $r['stream'] ) {
 			if ( ! WP_DEBUG )
 				$stream_handle = @fopen( $r['filename'], 'w+' );
@@ -942,12 +966,12 @@
 			if ( ! $stream_handle )
 				return new WP_Error( 'http_request_failed', sprintf( __( 'Could not open handle for fopen() to %s' ), $r['filename'] ) );
 
-			stream_copy_to_stream( $handle, $stream_handle );
+			stream_copy_to_stream( $handle, $stream_handle, $max_bytes );
 
 			fclose( $stream_handle );
 			$strResponse = '';
 		} else {
-			$strResponse = stream_get_contents( $handle );
+			$strResponse = stream_get_contents( $handle, $max_bytes );
 		}
 
 		$meta = stream_get_meta_data( $handle );
@@ -1011,7 +1035,7 @@
 class WP_Http_Curl {
 
 	/**
-	 * Temporary header storage for use with streaming to a file.
+	 * Temporary header storage for during requests.
 	 *
 	 * @since 3.2.0
 	 * @access private
@@ -1020,6 +1044,33 @@
 	private $headers = '';
 
 	/**
+	 * Temporary body storage for during requests.
+	 *
+	 * @since 3.6.0
+	 * @access private
+	 * @var string
+	 */
+	private $body = '';
+
+	/**
+	 * The maximum amount of data to recieve from the remote server
+	 *
+	 * @since 3.6.0
+	 * @access private
+	 * @var int
+	 */
+	private $max_body_length = false;
+
+	/**
+	 * The file resource used for streaming to file.
+	 *
+	 * @since 3.6.0
+	 * @access private
+	 * @var resource
+	 */
+	private $stream_handle = false;
+
+	/**
 	 * Send a HTTP request to a URI using cURL extension.
 	 *
 	 * @access public
@@ -1108,20 +1159,24 @@
 				break;
 		}
 
-		if ( true === $r['blocking'] )
+		if ( true === $r['blocking'] ) {
 			curl_setopt( $handle, CURLOPT_HEADERFUNCTION, array( $this, 'stream_headers' ) );
+			curl_setopt( $handle, CURLOPT_WRITEFUNCTION, array( $this, 'stream_body' ) );
+		}
 
 		curl_setopt( $handle, CURLOPT_HEADER, false );
 
+		if ( isset( $r['first-x-bytes'] ) )
+			$this->max_body_length = intval( $r['first-x-bytes'] );
+
 		// If streaming to a file open a file handle, and setup our curl streaming handler
 		if ( $r['stream'] ) {
 			if ( ! WP_DEBUG )
-				$stream_handle = @fopen( $r['filename'], 'w+' );
+				$this->stream_handle = @fopen( $r['filename'], 'w+' );
 			else
-				$stream_handle = fopen( $r['filename'], 'w+' );
-			if ( ! $stream_handle )
+				$this->stream_handle = fopen( $r['filename'], 'w+' );
+			if ( ! $this->stream_handle )
 				return new WP_Error( 'http_request_failed', sprintf( __( 'Could not open handle for fopen() to %s' ), $r['filename'] ) );
-			curl_setopt( $handle, CURLOPT_FILE, $stream_handle );
 		}
 
 		if ( !empty( $r['headers'] ) ) {
@@ -1150,22 +1205,20 @@
 		}
 
 		$theResponse = curl_exec( $handle );
-		$theBody = '';
 		$theHeaders = WP_Http::processHeaders( $this->headers );
+		$theBody = $this->body;
 
-		if ( strlen($theResponse) > 0 && ! is_bool( $theResponse ) ) // is_bool: when using $args['stream'], curl_exec will return (bool)true
-			$theBody = $theResponse;
+		$this->headers = '';
+		$this->body = '';
 
 		// If no response
-		if ( 0 == strlen( $theResponse ) && empty( $theHeaders['headers'] ) ) {
+		if ( 0 == strlen( $theBody ) && empty( $theHeaders['headers'] ) ) {
 			if ( $curl_error = curl_error( $handle ) )
 				return new WP_Error( 'http_request_failed', $curl_error );
 			if ( in_array( curl_getinfo( $handle, CURLINFO_HTTP_CODE ), array( 301, 302 ) ) )
 				return new WP_Error( 'http_request_failed', __( 'Too many redirects.' ) );
 		}
 
-		$this->headers = '';
-
 		$response = array();
 		$response['code'] = curl_getinfo( $handle, CURLINFO_HTTP_CODE );
 		$response['message'] = get_status_header_desc($response['code']);
@@ -1173,7 +1226,7 @@
 		curl_close( $handle );
 
 		if ( $r['stream'] )
-			fclose( $stream_handle );
+			fclose( $this->stream_handle );
 
 		// See #11305 - When running under safe mode, redirection is disabled above. Handle it manually.
 		if ( ! empty( $theHeaders['headers']['location'] ) && 0 !== $r['_redirection'] ) { // _redirection: The requested number of redirections
@@ -1205,6 +1258,28 @@
 	}
 
 	/**
+	 * Grab the body of the cURL request
+	 *
+	 * The contents of the document are passed in chunks, so we append to the $body property for temporary storage.
+	 * Returning a length shorter than the length of $data passed in will cause cURL to abort the request as "completed"
+	 *
+	 * @since 3.6.0
+	 * @access private
+	 * @return int
+	 */
+	private function stream_body( $handle, $data ) {
+		if ( $this->max_body_length && ( strlen( $this->body ) + strlen( $data ) ) > $this->max_body_length )
+			$data = substr( $data, 0, ( $this->max_body_length - strlen( $this->body ) ) );
+
+		if ( $this->stream_handle )
+			fwrite( $this->stream_handle, $data );
+		else
+			$this->body .= $data;
+
+		return strlen( $data );
+	}
+
+	/**
 	 * Whether this class can be used for retrieving an URL.
 	 *
 	 * @static
@@ -1785,7 +1860,11 @@
 	 *
 	 * @return bool
 	 */
-	public static function is_available() {
+	public static function is_available( $args ) {
+		// If only partial content is being requested, we won't be able to decompress it
+		if ( isset( $args['first-x-bytes'] ) )
+			return false;
+
 		return ( function_exists('gzuncompress') || function_exists('gzdeflate') || function_exists('gzinflate') );
 	}
 }
