Index: wp-admin/includes/file.php
===================================================================
--- wp-admin/includes/file.php	(revision 17549)
+++ wp-admin/includes/file.php	(working copy)
@@ -153,42 +153,6 @@
 }
 
 /**
- * Determines a writable directory for temporary files.
- * 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/
- *
- * 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.
- *
- * @since 2.5.0
- *
- * @return string Writable temporary directory
- */
-function get_temp_dir() {
-	static $temp;
-	if ( defined('WP_TEMP_DIR') )
-		return trailingslashit(WP_TEMP_DIR);
-
-	if ( $temp )
-		return trailingslashit($temp);
-
-	$temp = WP_CONTENT_DIR . '/';
-	if ( is_dir($temp) && @is_writable($temp) )
-		return $temp;
-
-	if  ( function_exists('sys_get_temp_dir') ) {
-		$temp = sys_get_temp_dir();
-		if ( @is_writable($temp) )
-			return trailingslashit($temp);
-	}
-
-	$temp = ini_get('upload_tmp_dir');
-	if ( is_dir($temp) && @is_writable($temp) )
-		return trailingslashit($temp);
-
-	$temp = '/tmp/';
-	return $temp;
-}
-
-/**
  * Returns a filename of a Temporary unique file.
  * Please note that the calling function must unlink() this itself.
  *
@@ -513,33 +477,24 @@
 function download_url( $url, $timeout = 300 ) {
 	//WARNING: The file is not automatically deleted, The script must unlink() the file.
 	if ( ! $url )
-		return new WP_Error('http_no_url', __('Invalid URL Provided.'));
+		return new WP_Error( 'http_no_url', __( 'Invalid URL Provided.' ) );
 
-	$tmpfname = wp_tempnam($url);
+	$tmpfname = wp_tempnam( $url );
 	if ( ! $tmpfname )
-		return new WP_Error('http_no_file', __('Could not create Temporary file.'));
+		return new WP_Error( 'http_no_file', __( 'Could not create Temporary file.' ) );
 
-	$handle = @fopen($tmpfname, 'wb');
-	if ( ! $handle )
-		return new WP_Error('http_no_file', __('Could not create Temporary file.'));
+	$response = wp_remote_get( $url, array( 'timeout' => $timeout, 'stream' => true, 'filename' => $tmpfname ) );
 
-	$response = wp_remote_get($url, array('timeout' => $timeout));
-
-	if ( is_wp_error($response) ) {
-		fclose($handle);
-		unlink($tmpfname);
+	if ( is_wp_error( $response ) ) {
+		unlink( $tmpfname );
 		return $response;
 	}
 
 	if ( $response['response']['code'] != '200' ){
-		fclose($handle);
-		unlink($tmpfname);
-		return new WP_Error('http_404', trim($response['response']['message']));
+		unlink( $tmpfname );
+		return new WP_Error( 'http_404', trim( $response['response']['message'] ) );
 	}
 
-	fwrite($handle, $response['body']);
-	fclose($handle);
-
 	return $tmpfname;
 }
 
Index: wp-includes/class-http.php
===================================================================
--- wp-includes/class-http.php	(revision 17551)
+++ wp-includes/class-http.php	(working copy)
@@ -97,7 +97,9 @@
 			'body' => null,
 			'compress' => false,
 			'decompress' => true,
-			'sslverify' => true
+			'sslverify' => true,
+			'stream' => false,
+			'filename' => null
 		);
 
 		
@@ -136,6 +138,18 @@
 		$r['local'] = $homeURL['host'] == $arrURL['host'] || 'localhost' == $arrURL['host'];
 		unset( $homeURL );
 
+		// If we are streaming to a file but no filename was given drop it in the WP temp dir
+		// and pick it's name using the basename of the $url
+		if ( $r['stream']  && empty( $r['filename'] ) )
+			$r['filename'] = get_temp_dir() . basename( $url );
+
+		// Force some settings if we are streaming to a file and check for existence and perms of destination directory
+		if ( $r['stream'] ) {
+			$r['blocking'] = true;
+			if ( ! is_writable( dirname( $r['filename'] ) ) )
+				return new WP_Error( 'http_request_failed', __( 'Destination directory for file streaming does not exist or is not writable.' ) );
+		}
+
 		if ( is_null( $r['headers'] ) )
 			$r['headers'] = array();
 
@@ -659,16 +673,52 @@
 		}
 
 		$strResponse = '';
-		while ( ! feof($handle) )
-			$strResponse .= fread($handle, 4096);
+		$bodyStarted = false;
 
-		fclose($handle);
+		// If streaming to a file setup the file handle
+		if ( $r['stream'] ) {
+			if ( ! WP_DEBUG )
+				$stream_handle = @fopen( $r['filename'], 'w+' );
+			else
+				$stream_handle = fopen( $r['filename'], 'w+' );
+			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 {
+					$strResponse .= $block;
+					if ( strpos( $strResponse, "\r\n\r\n" ) ) {
+						$process = WP_Http::processResponse( $strResponse );
+						$bodyStarted = true;
+						fwrite( $stream_handle, $process['body'] );
+						unset( $strResponse );
+						$process['body'] = '';
+					}
+				}
+			}
+
+			fclose( $stream_handle );
+
+		} else { 
+			while ( ! feof($handle) )
+				$strResponse .= fread( $handle, 4096 );
+		}
+
+		fclose( $handle );
+
 		if ( true === $secure_transport )
 			error_reporting($error_reporting);
 
-		$process = WP_Http::processResponse($strResponse);
-		$arrHeaders = WP_Http::processHeaders($process['headers']);
+		if ( $r['stream'] ) {
+			$arrHeaders = WP_Http::processHeaders( $process['headers'] );
+		} else {
+			$process = WP_Http::processResponse( $strResponse );
+			$arrHeaders = WP_Http::processHeaders( $process['headers'] );
+			unset( $strResponse );
+		}
 
 		// Is the response code within the 400 range?
 		if ( (int) $arrHeaders['response']['code'] >= 400 && (int) $arrHeaders['response']['code'] < 500 )
@@ -690,7 +740,7 @@
 		if ( true === $r['decompress'] && true === WP_Http_Encoding::should_decode($arrHeaders['headers']) )
 			$process['body'] = WP_Http_Encoding::decompress( $process['body'] );
 
-		return array('headers' => $arrHeaders['headers'], 'body' => $process['body'], 'response' => $arrHeaders['response'], 'cookies' => $arrHeaders['cookies']);
+		return array( 'headers' => $arrHeaders['headers'], 'body' => $process['body'], 'response' => $arrHeaders['response'], 'cookies' => $arrHeaders['cookies'], 'filename' => $r['filename'] );
 	}
 
 	/**
@@ -834,11 +884,24 @@
 			return array( 'headers' => array(), 'body' => '', 'response' => array('code' => false, 'message' => false), 'cookies' => array() );
 		}
 
-		$strResponse = stream_get_contents($handle);
-		$meta = stream_get_meta_data($handle);
+		if ( $r['stream'] ) {
+			if ( ! WP_DEBUG )
+				$stream_handle = @fopen( $r['filename'], 'w+' );
+			else
+				$stream_handle = fopen( $r['filename'], 'w+' );
+			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 );
+			fclose( $stream_handle );
+			$strResponse = '';
+		} else {
+			$strResponse = stream_get_contents( $handle );
+		}
 
-		fclose($handle);
+		$meta = stream_get_meta_data( $handle );
 
+		fclose( $handle );
+
 		$processedHeaders = array();
 		if ( isset( $meta['wrapper_data']['headers'] ) )
 			$processedHeaders = WP_Http::processHeaders($meta['wrapper_data']['headers']);
@@ -856,7 +919,7 @@
 		if ( true === $r['decompress'] && true === WP_Http_Encoding::should_decode($processedHeaders['headers']) )
 			$strResponse = WP_Http_Encoding::decompress( $strResponse );
 
-		return array('headers' => $processedHeaders['headers'], 'body' => $strResponse, 'response' => $processedHeaders['response'], 'cookies' => $processedHeaders['cookies']);
+		return array( 'headers' => $processedHeaders['headers'], 'body' => $strResponse, 'response' => $processedHeaders['response'], 'cookies' => $processedHeaders['cookies'], 'filename' => $r['filename'] );
 	}
 
 	/**
@@ -1006,11 +1069,25 @@
 		if ( true === $r['decompress'] && true === WP_Http_Encoding::should_decode($theHeaders['headers']) )
 			$theBody = http_inflate( $theBody );
 
+		if ( $r['stream'] ) {
+			if ( !WP_DEBUG )
+				$stream_handle = @fopen( $r['filename'], 'w+' );
+			else
+				$stream_handle = fopen( $r['filename'], 'w+' );
+
+			if ( ! $stream_handle )
+				return new WP_Error( 'http_request_failed', sprintf( __( 'Could not open handle for fopen() to %s' ), $r['filename'] ) );
+
+			fwrite( $stream_handle, $theBody );
+			fclose( $stream_handle );
+			$theBody = '';
+		}
+
 		$theResponse = array();
 		$theResponse['code'] = $info['response_code'];
 		$theResponse['message'] = get_status_header_desc($info['response_code']);
 
-		return array('headers' => $theHeaders['headers'], 'body' => $theBody, 'response' => $theResponse, 'cookies' => $theHeaders['cookies']);
+		return array( 'headers' => $theHeaders['headers'], 'body' => $theBody, 'response' => $theResponse, 'cookies' => $theHeaders['cookies'], 'filename' => $r['filename'] );
 	}
 
 	/**
@@ -1038,6 +1115,15 @@
 class WP_Http_Curl {
 
 	/**
+	 * Temporary header storage for use with streaming to a file.
+	 *
+	 * @since 3.2.0
+	 * @access private
+	 * @var string
+	 */
+	private $headers;
+
+	/**
 	 * Send a HTTP request to a URI using cURL extension.
 	 *
 	 * @access public
@@ -1121,10 +1207,21 @@
 		}
 
 		if ( true === $r['blocking'] )
-			curl_setopt( $handle, CURLOPT_HEADER, true );
-		else
-			curl_setopt( $handle, CURLOPT_HEADER, false );
+			curl_setopt( $handle, CURLOPT_HEADERFUNCTION, array( &$this, 'stream_headers' ) );
 
+		curl_setopt( $handle, CURLOPT_HEADER, false );
+
+		// 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+' );
+			else
+				$stream_handle = fopen( $r['filename'], 'w+' );
+			if ( ! $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 );
+		}
+
 		// The option doesn't work with safe mode or when open_basedir is set.
 		if ( !ini_get('safe_mode') && !ini_get('open_basedir') && 0 !== $r['_redirection'] )
 			curl_setopt( $handle, CURLOPT_FOLLOWLOCATION, true );
@@ -1155,35 +1252,31 @@
 		}
 
 		$theResponse = curl_exec( $handle );
+		$theBody = '';
+		$theHeaders = WP_Http::processHeaders( $this->headers );
 
-		if ( !empty($theResponse) ) {
-			$headerLength = curl_getinfo($handle, CURLINFO_HEADER_SIZE);
-			$theHeaders = trim( substr($theResponse, 0, $headerLength) );
-			if ( strlen($theResponse) > $headerLength )
-				$theBody = substr( $theResponse, $headerLength );
-			else
-				$theBody = '';
-			if ( false !== strpos($theHeaders, "\r\n\r\n") ) {
-				$headerParts = explode("\r\n\r\n", $theHeaders);
-				$theHeaders = $headerParts[ count($headerParts) -1 ];
-			}
-			$theHeaders = WP_Http::processHeaders($theHeaders);
-		} else {
+		if ( !empty($theResponse) )
+			$theBody = $theResponse;
+
+		// If no response, and It's not a HEAD request with valid headers returned
+		if ( empty($theResponse) && 'HEAD' != $args['method'] && !empty($this->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.'));
-
-			$theHeaders = array( 'headers' => array(), 'cookies' => array() );
-			$theBody = '';
 		}
 
+		unset( $this->headers );
+
 		$response = array();
 		$response['code'] = curl_getinfo( $handle, CURLINFO_HTTP_CODE );
 		$response['message'] = get_status_header_desc($response['code']);
 
 		curl_close( $handle );
 
+		if ( $r['stream'] )
+			fclose( $stream_handle );
+
 		// See #11305 - When running under safe mode, redirection is disabled above. Handle it manually.
 		if ( !empty($theHeaders['headers']['location']) && (ini_get('safe_mode') || ini_get('open_basedir')) && 0 !== $r['_redirection'] ) {
 			if ( $r['redirection']-- > 0 ) {
@@ -1196,10 +1289,24 @@
 		if ( true === $r['decompress'] && true === WP_Http_Encoding::should_decode($theHeaders['headers']) )
 			$theBody = WP_Http_Encoding::decompress( $theBody );
 
-		return array('headers' => $theHeaders['headers'], 'body' => $theBody, 'response' => $response, 'cookies' => $theHeaders['cookies']);
+		return array( 'headers' => $theHeaders['headers'], 'body' => $theBody, 'response' => $response, 'cookies' => $theHeaders['cookies'], 'filename' => $r['filename'] );
 	}
 
 	/**
+	 * Grab the headers of the cURL request
+	 *
+	 * Each header is sent individually to this callback, so we append to the $header property for temporary storage
+	 *
+	 * @since 3.2.0
+	 * @access private
+	 * @return int
+	 */
+	private function stream_headers( $handle, $headers ) {
+		$this->headers .= $headers;
+		return strlen( $headers );
+	}
+
+	/**
 	 * Whether this class can be used for retrieving an URL.
 	 *
 	 * @static
Index: wp-includes/functions.php
===================================================================
--- wp-includes/functions.php	(revision 17549)
+++ wp-includes/functions.php	(working copy)
@@ -2111,6 +2111,42 @@
 }
 
 /**
+ * Determines a writable directory for temporary files.
+ * 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/
+ *
+ * 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.
+ *
+ * @since 2.5.0
+ *
+ * @return string Writable temporary directory
+ */
+function get_temp_dir() {
+	static $temp;
+	if ( defined('WP_TEMP_DIR') )
+		return trailingslashit(WP_TEMP_DIR);
+
+	if ( $temp )
+		return trailingslashit($temp);
+
+	$temp = WP_CONTENT_DIR . '/';
+	if ( is_dir($temp) && @is_writable($temp) )
+		return $temp;
+
+	if  ( function_exists('sys_get_temp_dir') ) {
+		$temp = sys_get_temp_dir();
+		if ( @is_writable($temp) )
+			return trailingslashit($temp);
+	}
+
+	$temp = ini_get('upload_tmp_dir');
+	if ( is_dir($temp) && @is_writable($temp) )
+		return trailingslashit($temp);
+
+	$temp = '/tmp/';
+	return $temp;
+}
+
+/**
  * Get an array containing the current upload directory's path and url.
  *
  * Checks the 'upload_path' option, which should be from the web root folder,
@@ -3091,10 +3127,12 @@
  * @param int|string $field A field from the object to place instead of the entire object
  * @return array
  */
-function wp_list_pluck( $list, $field ) {
-	foreach ( $list as $key => $value ) {
+function wp_list_pluck( $_list, $field ) {
+	$list = array();
+	foreach ( $_list as $key => $value ) {
 		$value = (array) $value;
-		$list[ $key ] = $value[ $field ];
+		if ( isset($value[ $field ]) )
+			$list[ $key ] = $value[ $field ];
 	}
 
 	return $list;
