### Eclipse Workspace Patch 1.0
#P wordpress-trunk
Index: wp-includes/class-http.php
===================================================================
--- wp-includes/class-http.php	(revision 17565)
+++ wp-includes/class-http.php	(working copy)
@@ -13,6 +13,50 @@
  */
 
 /**
+ * HTTP Transport base class
+ * 
+ * @since 3.2
+ */
+abstract class WP_Http_TransportConcrete extends WP_Http {
+	abstract protected static function test( array $args = array(), $url = null );
+	abstract protected function _request( $url, array $args );
+	/**
+	 * Send a HTTP request to a URI.
+	 *
+	 * @see WP_Http::request For default options descriptions.
+	 *
+	 * @since 2.7
+	 * @access public
+	 * @param string $url URI resource.
+	 * @param str|array $args Optional. Override the defaults.
+	 * @return array 'headers', 'body', 'cookies' and 'response' keys.
+	 */
+	public function request( $url, $args = array() ) {
+		$defaults = array(
+			'method' => 'GET', 'timeout' => 5,
+			'redirection' => 5, 'httpversion' => '1.0',
+			'blocking' => true,
+			'headers' => array(), 'cookies' => array(), 'body' => null
+		);
+
+		$args = wp_parse_args( $args, $defaults );
+
+		if ( isset($args['headers']['User-Agent']) ) {
+			$args['user-agent'] = $args['headers']['User-Agent'];
+			unset($args['headers']['User-Agent']);
+		} else if ( isset($r['headers']['user-agent']) ) {
+			$args['user-agent'] = $args['headers']['user-agent'];
+			unset($args['headers']['user-agent']);
+		}
+
+		// Construct Cookie: header if any cookies are set
+		WP_Http::buildCookieHeader( $args );
+		
+		return $this->_request( $url, $args );
+	}
+}
+
+/**
  * WordPress HTTP Class for managing HTTP Transports and making HTTP requests.
  *
  * This class is called for the functionality of making HTTP requests and replaces Snoopy
@@ -36,6 +80,12 @@
  * @since 2.7.0
  */
 class WP_Http {
+	/**
+	 * local store of WP_Http_* Transport Objects, keyed with their Transport name.
+	 *
+	 * @var array
+	 */
+	private static $_transports = array();
 
 	/**
 	 * Send a HTTP request to a URI.
@@ -102,7 +152,6 @@
 			'filename' => null
 		);
 
-		
 		// Pre-parse for the HEAD checks.
 		$args = wp_parse_args( $args );
 
@@ -110,7 +159,7 @@
 		if ( isset($args['method']) && 'HEAD' == $args['method'] )
 			$defaults['redirection'] = 0;
 
-		$r = wp_parse_args( $args, $defaults );
+		$r = array_merge( $defaults, $args );
 		$r = apply_filters( 'http_request_args', $r, $url );
 
 		// Certain classes decrement this, store a copy of the original value for loop purposes.
@@ -124,7 +173,7 @@
 		$arrURL = parse_url( $url );
 
 		if ( empty( $url ) || empty( $arrURL['scheme'] ) )
-			return new WP_Error('http_request_failed', __('A valid URL was not provided.'));
+			return new WP_Error('http_request_failed', __( 'Invalid URL.' ));
 
 		if ( $this->block_request( $url ) )
 			return new WP_Error( 'http_request_failed', __( 'User has blocked requests through HTTP.' ) );
@@ -158,14 +207,12 @@
 			$r['headers'] = $processedHeaders['headers'];
 		}
 
-		if ( isset( $r['headers']['User-Agent'] ) ) {
+		if ( isset($r['headers']['User-Agent']) ) {
 			$r['user-agent'] = $r['headers']['User-Agent'];
-			unset( $r['headers']['User-Agent'] );
-		}
-
-		if ( isset( $r['headers']['user-agent'] ) ) {
+			unset($r['headers']['User-Agent']);
+		} else if ( isset($r['headers']['user-agent']) ) {
 			$r['user-agent'] = $r['headers']['user-agent'];
-			unset( $r['headers']['user-agent'] );
+			unset($r['headers']['user-agent']);
 		}
 
 		// Construct Cookie: header if any cookies are set
@@ -196,6 +243,23 @@
 	}
 
 	/**
+	 * get transport object specified by name
+	 *
+	 * Works as a multi-singleton registry on self::$transports
+	 *
+	 * @param string $transport name
+	 * @return Object
+	 */
+	private function _transport_object( $transport ) {
+		$class = "WP_HTTP_{$transport}";
+
+		if ( empty( self::$_transports[ $transport ] ) )
+			self::$_transports[ $transport ] = new $class;
+
+		return self::$_transports[ $transport ];
+	}
+
+	/**
 	 * Dispatches a HTTP request to a supporting transport.
 	 *
 	 * Tests each transport in order to find a transport which matches the request arguements.
@@ -218,30 +282,20 @@
 	 * @return array|object Array containing 'headers', 'body', 'response', 'cookies'. A WP_Error instance upon error
 	 */
 	private function _dispatch_request($url, $args) {
-		static $transports = null;
-		if ( is_null($transports) )
-			$transports = array();
+		// default transports order
+		$request_order = $args['blocking'] ?
+							array( 'exthttp', 'curl', 'streams', 'fsockopen' ): // blocking order
+							array( 'curl', 'streams', 'fsockopen', 'exthttp' ); // non-blocking order
 
-		$request_order = isset($r['blocking']) && !$r['blocking'] ?
-							array('curl', 'streams', 'fsockopen', 'exthttp') : // non-blocking order
-							array('exthttp', 'curl', 'streams', 'fsockopen'); // blocking order
+		$request_order = apply_filters( 'http_get_transports', $request_order, $url, $args );
 
-		// Loop over each transport on each HTTP request looking for one which will serve this requests needs
-		foreach ( $request_order as $transport ) {
-			$class = 'WP_HTTP_' . $transport;
+		// retrieve the transport from all transports and request
+		if ( $transport = $this->_test_transports( $request_order, $url, $args ) ) {
+			// Transport claims to support request, give it a whirl.
+			$response = $this->_transport_object( $transport )->request( $url, $args );
 
-			// Check to see if this transport is a possibility, calls the transport statically
-			if ( ! call_user_func( array($class, 'test'), $args, $url) )
-				continue;
+			do_action( 'http_api_debug', $response, 'response', "WP_Http_{$transport}" );
 
-			// Transport claims to support request, Instantate it and give it a whirl.
-			if ( empty( $transports[ $transport ] ) )
-				$transports[ $transport ] = new $class;
-
-			$response = $transports[ $transport ]->request( $url, $args );
-
-			do_action( 'http_api_debug', $response, 'response', $class );
-
 			if ( is_wp_error( $response ) )
 				return $response;
 
@@ -250,8 +304,45 @@
 
 		return new WP_Error('http_failure', __('There are no HTTP transports available which can complete the requested request.') );
 	}
+	
+	/**
+	 * Test if one of the transports is available
+	 * 
+	 * Returns on first match.
+	 * 
+	 * @param array $transports list of transports to test against
+	 * @param string $url
+	 * @param array $args
+	 * @return string name of the transport, empty string if non could be found
+	 */
+	private function _test_transports( array $transports, $url, array $args ) {
+		foreach( $transports as $transport ) {
+			if ( $this->test_transport( $transport, $args, $url ) )
+				return $transport;
+		}
+		return '';
+	}
 
 	/**
+	 * test if a named transport is available
+	 * 
+	 * @param string $transport name of the transport
+	 * @param array $args Optional. Arguments for the transport to be tested against.
+	 * @param string $url Optional. Url for the transport to be tested against.
+	 * @return boolean Whether or not the transport can be used.
+	 */
+	public function test_transport( $transport, array $args = array() , $url = null ) {
+		$result = call_user_func( "WP_HTTP_{$transport}::test", $args, $url );
+		return apply_filters( "use_{$transport}_transport", $result, $args, $url );
+	}
+	
+	private function _request_by_method( $method, $url, $args ) {
+		$defaults = array( 'method' => $method );
+		$r = wp_parse_args( $args, $defaults );
+		return $this->request( $url, $r );
+	}
+
+	/**
 	 * Uses the POST HTTP method.
 	 *
 	 * Used for sending data that is expected to be in the body.
@@ -264,9 +355,7 @@
 	 * @return array|object Array containing 'headers', 'body', 'response', 'cookies'. A WP_Error instance upon error
 	 */
 	function post($url, $args = array()) {
-		$defaults = array('method' => 'POST');
-		$r = wp_parse_args( $args, $defaults );
-		return $this->request($url, $r);
+		return $this->_request_by_method( 'POST', $url, $args );
 	}
 
 	/**
@@ -282,9 +371,7 @@
 	 * @return array|object Array containing 'headers', 'body', 'response', 'cookies'. A WP_Error instance upon error
 	 */
 	function get($url, $args = array()) {
-		$defaults = array('method' => 'GET');
-		$r = wp_parse_args( $args, $defaults );
-		return $this->request($url, $r);
+		return $this->_request_by_method( 'GET', $url, $args );
 	}
 
 	/**
@@ -300,9 +387,7 @@
 	 * @return array|object Array containing 'headers', 'body', 'response', 'cookies'. A WP_Error instance upon error
 	 */
 	function head($url, $args = array()) {
-		$defaults = array('method' => 'HEAD');
-		$r = wp_parse_args( $args, $defaults );
-		return $this->request($url, $r);
+		return $this->_request_by_method( 'POST', $url, $args );
 	}
 
 	/**
@@ -317,8 +402,9 @@
 	 */
 	function processResponse($strResponse) {
 		$res = explode("\r\n\r\n", $strResponse, 2);
+		$res[] = '';
 
-		return array('headers' => isset($res[0]) ? $res[0] : array(), 'body' => isset($res[1]) ? $res[1] : '');
+		return array( 'headers' => $res[0], 'body' => $res[1] );
 	}
 
 	/**
@@ -537,41 +623,19 @@
  * @subpackage HTTP
  * @since 2.7.0
  */
-class WP_Http_Fsockopen {
+class WP_Http_Fsockopen extends WP_Http_TransportConcrete {
 	/**
 	 * Send a HTTP request to a URI using fsockopen().
 	 *
-	 * Does not support non-blocking mode.
-	 *
-	 * @see WP_Http::request For default options descriptions.
-	 *
-	 * @since 2.7
-	 * @access public
+	 * @since 2.7 through request()
+	 * @access public through request()
 	 * @param string $url URI resource.
-	 * @param str|array $args Optional. Override the defaults.
+	 * @param array $args Optional.
 	 * @return array 'headers', 'body', 'cookies' and 'response' keys.
 	 */
-	function request($url, $args = array()) {
-		$defaults = array(
-			'method' => 'GET', 'timeout' => 5,
-			'redirection' => 5, 'httpversion' => '1.0',
-			'blocking' => true,
-			'headers' => array(), 'body' => null, 'cookies' => array()
-		);
+	protected function _request($url, array $args = array()) {
+		$r = $args; # alias parameter @todo rename
 
-		$r = wp_parse_args( $args, $defaults );
-
-		if ( isset($r['headers']['User-Agent']) ) {
-			$r['user-agent'] = $r['headers']['User-Agent'];
-			unset($r['headers']['User-Agent']);
-		} else if ( isset($r['headers']['user-agent']) ) {
-			$r['user-agent'] = $r['headers']['user-agent'];
-			unset($r['headers']['user-agent']);
-		}
-
-		// Construct Cookie: header if any cookies are set
-		WP_Http::buildCookieHeader( $r );
-
 		$iError = null; // Store error number
 		$strError = null; // Store error string
 
@@ -718,7 +782,7 @@
 		$arrHeaders = WP_Http::processHeaders( $process['headers'] );
 
 		// Is the response code within the 400 range?
-		if ( (int) $arrHeaders['response']['code'] >= 400 && (int) $arrHeaders['response']['code'] < 500 )
+		if ( 4 === (int) ($arrHeaders['response']['code'] / 100) )
 			return new WP_Error('http_request_failed', $arrHeaders['response']['code'] . ': ' . $arrHeaders['response']['message']);
 
 		// If location is found, then assume redirect and redirect to location.
@@ -747,7 +811,7 @@
 	 * @static
 	 * @return boolean False means this class can not be used, true means it can.
 	 */
-	function test( $args = array() ) {
+	protected static function test( array $args = array(), $url = null ) {
 		if ( false !== ($option = get_option( 'disable_fsockopen' )) && time()-$option < 43200 ) // 12 hours
 			return false;
 
@@ -760,7 +824,7 @@
 		else
 			$use = false;
 
-		return apply_filters('use_fsockopen_transport', $use, $args);
+		return $use;
 	}
 }
 
@@ -776,7 +840,7 @@
  * @subpackage HTTP
  * @since 2.7.0
  */
-class WP_Http_Streams {
+class WP_Http_Streams extends WP_Http_TransportConcrete {
 	/**
 	 * Send a HTTP request to a URI using streams with fopen().
 	 *
@@ -787,27 +851,9 @@
 	 * @param str|array $args Optional. Override the defaults.
 	 * @return array 'headers', 'body', 'cookies' and 'response' keys.
 	 */
-	function request($url, $args = array()) {
-		$defaults = array(
-			'method' => 'GET', 'timeout' => 5,
-			'redirection' => 5, 'httpversion' => '1.0',
-			'blocking' => true,
-			'headers' => array(), 'body' => null, 'cookies' => array()
-		);
+	protected function _request($url, array $args = array()) {
+		$r = $args; # alias parameter @todo rename
 
-		$r = wp_parse_args( $args, $defaults );
-
-		if ( isset($r['headers']['User-Agent']) ) {
-			$r['user-agent'] = $r['headers']['User-Agent'];
-			unset($r['headers']['User-Agent']);
-		} else if ( isset($r['headers']['user-agent']) ) {
-			$r['user-agent'] = $r['headers']['user-agent'];
-			unset($r['headers']['user-agent']);
-		}
-
-		// Construct Cookie: header if any cookies are set
-		WP_Http::buildCookieHeader( $r );
-
 		$arrURL = parse_url($url);
 
 		if ( false === $arrURL )
@@ -931,11 +977,8 @@
 	 *
 	 * @return boolean False means this class can not be used, true means it can.
 	 */
-	function test($args = array()) {
-		if ( ! function_exists('fopen') || (function_exists('ini_get') && true != ini_get('allow_url_fopen')) )
-			return false;
-
-		return apply_filters('use_streams_transport', true, $args);
+	static protected function test( array $args = array(), $url = null ) {
+		return !( ! function_exists('fopen') || (function_exists('ini_get') && true != ini_get('allow_url_fopen')) );
 	}
 }
 
@@ -950,7 +993,7 @@
  * @subpackage HTTP
  * @since 2.7.0
  */
-class WP_Http_ExtHttp {
+class WP_Http_ExtHttp extends WP_Http_TransportConcrete {
 	/**
 	 * Send a HTTP request to a URI using HTTP extension.
 	 *
@@ -963,27 +1006,9 @@
 	 * @param str|array $args Optional. Override the defaults.
 	 * @return array 'headers', 'body', 'cookies' and 'response' keys.
 	 */
-	function request($url, $args = array()) {
-		$defaults = array(
-			'method' => 'GET', 'timeout' => 5,
-			'redirection' => 5, 'httpversion' => '1.0',
-			'blocking' => true,
-			'headers' => array(), 'body' => null, 'cookies' => array()
-		);
+	function _request($url, array $args = array()) {
+		$r = $args; # alias parameter @todo rename
 
-		$r = wp_parse_args( $args, $defaults );
-
-		if ( isset($r['headers']['User-Agent']) ) {
-			$r['user-agent'] = $r['headers']['User-Agent'];
-			unset($r['headers']['User-Agent']);
-		} else if ( isset($r['headers']['user-agent']) ) {
-			$r['user-agent'] = $r['headers']['user-agent'];
-			unset($r['headers']['user-agent']);
-		}
-
-		// Construct Cookie: header if any cookies are set
-		WP_Http::buildCookieHeader( $r );
-
 		switch ( $r['method'] ) {
 			case 'POST':
 				$r['method'] = HTTP_METH_POST;
@@ -1098,8 +1123,8 @@
 	 *
 	 * @return boolean False means this class can not be used, true means it can.
 	 */
-	function test($args = array()) {
-		return apply_filters('use_http_extension_transport', function_exists('http_request'), $args );
+	protected static function test(array $args = array(), $url = null) {
+		return function_exists('http_request');
 	}
 }
 
@@ -1112,7 +1137,7 @@
  * @subpackage HTTP
  * @since 2.7
  */
-class WP_Http_Curl {
+class WP_Http_Curl extends WP_Http_TransportConcrete {
 
 	/**
 	 * Temporary header storage for use with streaming to a file.
@@ -1133,27 +1158,9 @@
 	 * @param str|array $args Optional. Override the defaults.
 	 * @return array 'headers', 'body', 'cookies' and 'response' keys.
 	 */
-	function request($url, $args = array()) {
-		$defaults = array(
-			'method' => 'GET', 'timeout' => 5,
-			'redirection' => 5, 'httpversion' => '1.0',
-			'blocking' => true,
-			'headers' => array(), 'body' => null, 'cookies' => array()
-		);
+	function _request($url, array $args = array()) {
+		$r = $args; # alias parameter @todo rename
 
-		$r = wp_parse_args( $args, $defaults );
-
-		if ( isset($r['headers']['User-Agent']) ) {
-			$r['user-agent'] = $r['headers']['User-Agent'];
-			unset($r['headers']['User-Agent']);
-		} else if ( isset($r['headers']['user-agent']) ) {
-			$r['user-agent'] = $r['headers']['user-agent'];
-			unset($r['headers']['user-agent']);
-		}
-
-		// Construct Cookie: header if any cookies are set.
-		WP_Http::buildCookieHeader( $r );
-
 		$handle = curl_init();
 
 		// cURL offers really easy proxy support.
@@ -1314,11 +1321,8 @@
 	 *
 	 * @return boolean False means this class can not be used, true means it can.
 	 */
-	function test($args = array()) {
-		if ( function_exists('curl_init') && function_exists('curl_exec') )
-			return apply_filters('use_curl_transport', true, $args);
-
-		return false;
+	protected static function test(array $args = array(), $url = null) {
+		return function_exists('curl_init') && function_exists('curl_exec');
 	}
 }
 
Index: wp-includes/http.php
===================================================================
--- wp-includes/http.php	(revision 17565)
+++ wp-includes/http.php	(working copy)
@@ -19,13 +19,9 @@
  *
  * @return WP_Http HTTP Transport object.
  */
-function &_wp_http_get_object() {
+function _wp_http_get_object() {
 	static $http;
-
-	if ( is_null($http) )
-		$http = new WP_Http();
-
-	return $http;
+	return $http ? $http : $http = new WP_Http();
 }
 
 /**
@@ -56,8 +52,7 @@
  * @return WP_Error|array The response or WP_Error on failure.
  */
 function wp_remote_request($url, $args = array()) {
-	$objFetchSite = _wp_http_get_object();
-	return $objFetchSite->request($url, $args);
+	return _wp_http_get_object()->request($url, $args);
 }
 
 /**
@@ -72,8 +67,7 @@
  * @return WP_Error|array The response or WP_Error on failure.
  */
 function wp_remote_get($url, $args = array()) {
-	$objFetchSite = _wp_http_get_object();
-	return $objFetchSite->get($url, $args);
+	return _wp_http_get_object()->get($url, $args);
 }
 
 /**
@@ -88,8 +82,7 @@
  * @return WP_Error|array The response or WP_Error on failure.
  */
 function wp_remote_post($url, $args = array()) {
-	$objFetchSite = _wp_http_get_object();
-	return $objFetchSite->post($url, $args);
+	return _wp_http_get_object()->post($url, $args);
 }
 
 /**
@@ -104,8 +97,7 @@
  * @return WP_Error|array The response or WP_Error on failure.
  */
 function wp_remote_head($url, $args = array()) {
-	$objFetchSite = _wp_http_get_object();
-	return $objFetchSite->head($url, $args);
+	return _wp_http_get_object()->head($url, $args);
 }
 
 /**
@@ -116,7 +108,7 @@
  * @param array $response HTTP response.
  * @return array The headers of the response. Empty array if incorrect parameter given.
  */
-function wp_remote_retrieve_headers(&$response) {
+function wp_remote_retrieve_headers($response) {
 	if ( is_wp_error($response) || ! isset($response['headers']) || ! is_array($response['headers']))
 		return array();
 
@@ -132,7 +124,7 @@
  * @param string $header Header name to retrieve value from.
  * @return string The header value. Empty string on if incorrect parameter given, or if the header doesnt exist.
  */
-function wp_remote_retrieve_header(&$response, $header) {
+function wp_remote_retrieve_header($response, $header) {
 	if ( is_wp_error($response) || ! isset($response['headers']) || ! is_array($response['headers']))
 		return '';
 
@@ -152,7 +144,7 @@
  * @param array $response HTTP response.
  * @return string the response code. Empty string on incorrect parameter given.
  */
-function wp_remote_retrieve_response_code(&$response) {
+function wp_remote_retrieve_response_code($response) {
 	if ( is_wp_error($response) || ! isset($response['response']) || ! is_array($response['response']))
 		return '';
 
@@ -169,7 +161,7 @@
  * @param array $response HTTP response.
  * @return string The response message. Empty string on incorrect parameter given.
  */
-function wp_remote_retrieve_response_message(&$response) {
+function wp_remote_retrieve_response_message($response) {
 	if ( is_wp_error($response) || ! isset($response['response']) || ! is_array($response['response']))
 		return '';
 
@@ -184,7 +176,7 @@
  * @param array $response HTTP response.
  * @return string The body of the response. Empty string if no body or incorrect parameter given.
  */
-function wp_remote_retrieve_body(&$response) {
+function wp_remote_retrieve_body($response) {
 	if ( is_wp_error($response) || ! isset($response['body']) )
 		return '';
 
