HTTP API improvements. Implements chunked transfer decoding. Moves plugin update checker over to api. see #4779 props santosj.

git-svn-id: http://svn.automattic.com/wordpress/trunk@8630 1a063a9b-81f0-0310-95a4-ce76da25c4cd
This commit is contained in:
westi 2008-08-12 21:21:11 +00:00
parent f089ebcfe4
commit 88f521011a
3 changed files with 225 additions and 185 deletions

View File

@ -10,7 +10,7 @@ function plugins_api($action, $args = NULL) {
$res = apply_filters('plugins_api', false, $action, $args); //NOTE: Allows a plugin to completely override the builtin WordPress.org API. $res = apply_filters('plugins_api', false, $action, $args); //NOTE: Allows a plugin to completely override the builtin WordPress.org API.
if ( ! $res ) { if ( ! $res ) {
$request = wp_remote_post('http://api.wordpress.org/plugins/info/1.0/', array(), array(), array('action' => $action, 'request' => serialize($args)) ); $request = wp_remote_post('http://api.wordpress.org/plugins/info/1.0/', array( 'body' => array('action' => $action, 'request' => serialize($args))) );
$res = unserialize($request['body']); $res = unserialize($request['body']);
if ( ! $res ) if ( ! $res )
wp_die($request['body']); wp_die($request['body']);

View File

@ -137,6 +137,12 @@ class WP_Http {
/** /**
* Send a HTTP request to a URI. * Send a HTTP request to a URI.
* *
* The body and headers are part of the arguments. The 'body' argument is
* for the body and will accept either a string or an array. The 'headers'
* argument should be an array, but a string is acceptable. If the 'body'
* argument is an array, then it will automatically be escaped using
* http_build_query().
*
* The only URI that are supported in the HTTP Transport implementation are * The only URI that are supported in the HTTP Transport implementation are
* the HTTP and HTTPS protocols. HTTP and HTTPS are assumed so the server * the HTTP and HTTPS protocols. HTTP and HTTPS are assumed so the server
* might not know how to handle the send headers. Other protocols are * might not know how to handle the send headers. Other protocols are
@ -171,50 +177,54 @@ class WP_Http {
* *
* @param string $url URI resource. * @param string $url URI resource.
* @param str|array $args Optional. Override the defaults. * @param str|array $args Optional. Override the defaults.
* @param string|array $headers Optional. Either the header string or array of Header name and value pairs. Expects sanitized.
* @param string $body Optional. The body that should be sent. Will be automatically escaped and processed.
* @return boolean * @return boolean
*/ */
function request($url, $args = array(), $headers = null, $body = null) { function request( $url, $args = array() ) {
global $wp_version; global $wp_version;
$defaults = array( $defaults = array(
'method' => 'GET', 'timeout' => apply_filters('http_request_timeout', 3), 'method' => 'GET', 'timeout' => apply_filters('http_request_timeout', 3),
'redirection' => 5, 'httpversion' => '1.0', 'redirection' => 5, 'httpversion' => '1.0',
'user-agent' => apply_filters('http_headers_useragent', 'WordPress/' . $wp_version ), 'user-agent' => apply_filters('http_headers_useragent', 'WordPress/' . $wp_version ),
'blocking' => true 'blocking' => true,
'headers' => array(), 'body' => null
); );
$r = wp_parse_args( $args, $defaults ); $r = wp_parse_args( $args, $defaults );
if ( is_null($headers) ) if ( is_null( $r['headers'] ) )
$headers = array(); $r['headers'] = array();
if ( ! is_array($headers) ) { if ( ! is_array($r['headers']) ) {
$processedHeaders = WP_Http::processHeaders($headers); $processedHeaders = WP_Http::processHeaders($r['headers']);
$headers = $processedHeaders['headers']; $r['headers'] = $processedHeaders['headers'];
} }
if ( isset($headers['User-Agent']) ) { if ( isset($r['headers']['User-Agent']) ) {
$headers['user-agent'] = $headers['User-Agent']; $r['user-agent'] = $headers['User-Agent'];
unset($headers['User-Agent']); unset($r['headers']['User-Agent']);
} }
if ( ! isset($headers['user-agent']) ) if ( isset($r['headers']['user-agent']) ) {
$headers['user-agent'] = $r['user-agent']; $r['user-agent'] = $r['headers']['user-agent'];
unset($r['headers']['user-agent']);
}
if ( is_null($body) ) { if ( is_null($r['body']) ) {
$transports = WP_Http::_getTransport(); $transports = WP_Http::_getTransport();
} else { } else {
if ( is_array($body) || is_object($body) ) if ( is_array( $r['body'] ) || is_object( $r['body'] ) ) {
$body = http_build_query($body); $r['body'] = http_build_query($r['body']);
$r['headers']['Content-Type'] = 'application/x-www-form-urlencoded; charset=' . get_option('blog_charset');
$r['headers']['Content-Length'] = strlen($r['body']);
}
$transports = WP_Http::_postTransport(); $transports = WP_Http::_postTransport();
} }
$response = array( 'headers' => array(), 'body' => '', 'response' => array('code', 'message') ); $response = array( 'headers' => array(), 'body' => '', 'response' => array('code', 'message') );
foreach( (array) $transports as $transport ) { foreach( (array) $transports as $transport ) {
$response = $transport->request($url, $r, $headers, $body); $response = $transport->request($url, $r);
if( !is_wp_error($response) ) if( !is_wp_error($response) )
return $response; return $response;
@ -233,14 +243,12 @@ class WP_Http {
* *
* @param string $url URI resource. * @param string $url URI resource.
* @param str|array $args Optional. Override the defaults. * @param str|array $args Optional. Override the defaults.
* @param string|array $headers Optional. Either the header string or array of Header name and value pairs.
* @param string $body Optional. The body that should be sent. Expected to be already processed.
* @return boolean * @return boolean
*/ */
function post($url, $args = array(), $headers = null, $body = null) { function post($url, $args = array()) {
$defaults = array('method' => 'POST'); $defaults = array('method' => 'POST');
$r = wp_parse_args( $args, $defaults ); $r = wp_parse_args( $args, $defaults );
return $this->request($url, $r, $headers, $body); return $this->request($url, $r);
} }
/** /**
@ -253,14 +261,12 @@ class WP_Http {
* *
* @param string $url URI resource. * @param string $url URI resource.
* @param str|array $args Optional. Override the defaults. * @param str|array $args Optional. Override the defaults.
* @param string|array $headers Optional. Either the header string or array of Header name and value pairs.
* @param string $body Optional. The body that should be sent. Expected to be already processed.
* @return boolean * @return boolean
*/ */
function get($url, $args = array(), $headers = null, $body = null) { function get($url, $args = array()) {
$defaults = array('method' => 'GET'); $defaults = array('method' => 'GET');
$r = wp_parse_args( $args, $defaults ); $r = wp_parse_args( $args, $defaults );
return $this->request($url, $r, $headers, $body); return $this->request($url, $r);
} }
/** /**
@ -273,14 +279,12 @@ class WP_Http {
* *
* @param string $url URI resource. * @param string $url URI resource.
* @param str|array $args Optional. Override the defaults. * @param str|array $args Optional. Override the defaults.
* @param string|array $headers Optional. Either the header string or array of Header name and value pairs.
* @param string $body Optional. The body that should be sent. Expected to be already processed.
* @return boolean * @return boolean
*/ */
function head($url, $args = array(), $headers = null, $body = null) { function head($url, $args = array()) {
$defaults = array('method' => 'HEAD'); $defaults = array('method' => 'HEAD');
$r = wp_parse_args( $args, $defaults ); $r = wp_parse_args( $args, $defaults );
return $this->request($url, $r, $headers, $body); return $this->request($url, $r);
} }
/** /**
@ -298,40 +302,6 @@ class WP_Http {
return array('headers' => $theHeaders, 'body' => $theBody); return array('headers' => $theHeaders, 'body' => $theBody);
} }
/**
* Whether response code is in the 400 range.
*
* @access public
* @static
* @since 2.7
*
* @param array $response Array with code and message keys
* @return bool True if 40x Response, false if something else.
*/
function is400Response($response) {
if ( (int) substr($response, 0, 1) == 4 )
return true;
return false;
}
/**
* Whether the headers returned a redirect location.
*
* Actually just checks whether the location header exists.
*
* @access public
* @static
* @since 2.7
*
* @param array $headers Array with headers
* @return bool True if Location header is found.
*/
function isRedirect($headers) {
if ( isset($headers['location']) )
return true;
return false;
}
/** /**
* Transform header string into an array. * Transform header string into an array.
* *
@ -357,7 +327,6 @@ class WP_Http {
if ( empty($tempheader) ) if ( empty($tempheader) )
continue; continue;
if ( false === strpos($tempheader, ':') ) { if ( false === strpos($tempheader, ':') ) {
list( , $iResponseCode, $strResponseMsg) = explode(' ', $tempheader, 3); list( , $iResponseCode, $strResponseMsg) = explode(' ', $tempheader, 3);
$response['code'] = $iResponseCode; $response['code'] = $iResponseCode;
@ -373,6 +342,61 @@ class WP_Http {
return array('response' => $response, 'headers' => $newheaders); return array('response' => $response, 'headers' => $newheaders);
} }
/**
* Decodes chunk transfer-encoding, based off the HTTP 1.1 specification.
*
* Based off the HTTP http_encoding_dechunk function. Does not support
* UTF-8. Does not support returning footer headers. Shouldn't be too
* difficult to support it though.
*
* @todo Add support for footer chunked headers.
*
* @static
* @param string $body Body content
* @return bool|string|WP_Error False if not chunked encoded. WP_Error on failure. Chunked decoded body on success.
*/
function chunkTransferDecode($body) {
$body = str_replace(array("\r\n", "\r"), "\n", $body);
// The body is not chunked encoding or is malformed.
if ( ! preg_match( '/^[0-9a-f]+(\s|\n)+/mi', trim($body) ) )
return false;
$hex = '';
$dec = 0;
$parsedBody = '';
$parsedHeaders = array();
$done = false;
do {
$hasChunk = (bool) preg_match( '/^([0-9a-f]+)(\s|\n)+/mi', $body, $match );
if ( $hasChunk ) {
if ( empty($match[1]) ) {
return new WP_Error('http_chunked_decode', __('Does not appear to be chunked encoded or body is malformed.') );
}
$length = hexdec( $match[1] );
$chunkLength = strlen( $match[0] );
if( $body{$length+$chunkLength} == "\n" )
$length++;
$strBody = substr($body, strlen( $match[0] ), $length);
$parsedBody .= $strBody;
$body = str_replace(array($match[0], $strBody), '', $body);
if( "0" == $body ) {
$done = true;
return $parsedBody; // Ignore footer headers.
break;
}
} else {
return new WP_Error('http_chunked_decode', __('Does not appear to be chunked encoded or body is malformed.') );
}
} while ( false === $done );
}
} }
/** /**
@ -391,25 +415,32 @@ class WP_Http_Fsockopen {
* *
* Does not support non-blocking mode. * Does not support non-blocking mode.
* *
* @see WP_Http::retrieve For default options descriptions. * @see WP_Http::request For default options descriptions.
* *
* @since 2.7 * @since 2.7
* @access public * @access public
* @param string $url URI resource. * @param string $url URI resource.
* @param str|array $args Optional. Override the defaults. * @param str|array $args Optional. Override the defaults.
* @param string|array $headers Optional. Either the header string or array of Header name and value pairs. Expects sanitized.
* @param string $body Optional. The body that should be sent. Expected to be already processed.
* @return array 'headers', 'body', and 'response' keys. * @return array 'headers', 'body', and 'response' keys.
*/ */
function request($url, $args = array(), $headers = null, $body = null) { function request($url, $args = array()) {
$defaults = array( $defaults = array(
'method' => 'GET', 'timeout' => 3, 'method' => 'GET', 'timeout' => 3,
'redirection' => 5, 'httpversion' => '1.0', 'redirection' => 5, 'httpversion' => '1.0',
'blocking' => true 'blocking' => true,
'headers' => array(), 'body' => null
); );
$r = wp_parse_args( $args, $defaults ); $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']);
}
$iError = null; // Store error number $iError = null; // Store error number
$strError = null; // Store error string $strError = null; // Store error string
@ -445,22 +476,21 @@ class WP_Http_Fsockopen {
$strHeaders = ''; $strHeaders = '';
$strHeaders .= strtoupper($r['method']) . ' ' . $requestPath . ' HTTP/' . $r['httpversion'] . "\r\n"; $strHeaders .= strtoupper($r['method']) . ' ' . $requestPath . ' HTTP/' . $r['httpversion'] . "\r\n";
$strHeaders .= 'Host: ' . $arrURL['host'] . "\r\n"; $strHeaders .= 'Host: ' . $arrURL['host'] . "\r\n";
if ( ! is_null($body) ) {
$strHeaders .= 'Content-Type: application/x-www-form-urlencoded; charset=' . get_option('blog_charset') . "\r\n";
$strHeaders .= 'Content-Length: ' . strlen($body) . "\r\n";
}
if ( is_array($headers) ) { if( isset($r['user-agent']) )
foreach ( (array) $headers as $header => $headerValue ) $strHeaders .= 'User-agent: ' . $r['user-agent'] . "\r\n";
if ( is_array($r['headers']) ) {
foreach ( (array) $r['headers'] as $header => $headerValue )
$strHeaders .= $header . ': ' . $headerValue . "\r\n"; $strHeaders .= $header . ': ' . $headerValue . "\r\n";
} else { } else {
$strHeaders .= $headers; $strHeaders .= $r['headers'];
} }
$strHeaders .= "\r\n"; $strHeaders .= "\r\n";
if ( ! is_null($body) ) if ( ! is_null($r['body']) )
$strHeaders .= $body; $strHeaders .= $r['body'];
fwrite($handle, $strHeaders); fwrite($handle, $strHeaders);
@ -481,12 +511,14 @@ class WP_Http_Fsockopen {
$process = WP_Http::processResponse($strResponse); $process = WP_Http::processResponse($strResponse);
$arrHeaders = WP_Http::processHeaders($process['headers']); $arrHeaders = WP_Http::processHeaders($process['headers']);
if ( WP_Http::is400Response($arrHeaders['response']) ) if ( WP_Http_Fsockopen::is400Response($arrHeaders['response']['code']) )
return new WP_Error('http_request_failed', $arrHeaders['response']['code'] . ': ' . $arrHeaders['response']['message']); return new WP_Error('http_request_failed', $arrHeaders['response']['code'] . ': ' . $arrHeaders['response']['message']);
// If location is found, then assume redirect and redirect to location.
if ( isset($arrHeaders['headers']['location']) ) { if ( isset($arrHeaders['headers']['location']) ) {
if ( $r['redirection']-- > 0 ) if ( $r['redirection']-- > 0 ) {
return $this->request($arrHeaders['headers']['location'], $r, $headers, $body); return $this->request($arrHeaders['headers']['location'], $r);
}
else else
return new WP_Error('http_request_failed', __('Too many redirects.')); return new WP_Error('http_request_failed', __('Too many redirects.'));
} }
@ -507,6 +539,22 @@ class WP_Http_Fsockopen {
return false; return false;
} }
/**
* Whether response code is in the 400 range.
*
* @access public
* @static
* @since 2.7
*
* @param string $response Response code.
* @return bool True if 40x Response, false if something else.
*/
function is400Response($response) {
if ( is_numeric($response) && (int) substr($response, 0, 1) == 4 )
return true;
return false;
}
} }
/** /**
@ -536,17 +584,16 @@ class WP_Http_Fopen {
* *
* @param string $url URI resource. * @param string $url URI resource.
* @param str|array $args Optional. Override the defaults. * @param str|array $args Optional. Override the defaults.
* @param string|array $headers Optional. Either the header string or array of Header name and value pairs. Expects sanitized.
* @param string $body Optional. The body that should be sent. Expected to be already processed.
* @return array 'headers', 'body', and 'response' keys. * @return array 'headers', 'body', and 'response' keys.
*/ */
function request($url, $args = array(), $headers = null, $body = null) { function request($url, $args = array()) {
global $http_response_header; global $http_response_header;
$defaults = array( $defaults = array(
'method' => 'GET', 'timeout' => 3, 'method' => 'GET', 'timeout' => 3,
'redirection' => 5, 'httpversion' => '1.0', 'redirection' => 5, 'httpversion' => '1.0',
'blocking' => true 'blocking' => true,
'headers' => array(), 'body' => null
); );
$r = wp_parse_args( $args, $defaults ); $r = wp_parse_args( $args, $defaults );
@ -591,6 +638,9 @@ class WP_Http_Fopen {
$processedHeaders = WP_Http::processHeaders($theHeaders); $processedHeaders = WP_Http::processHeaders($theHeaders);
if ( ! empty( $strResponse ) && isset( $processedHeaders['headers']['transfer-encoding'] ) && 'chunked' == $processedHeaders['headers']['transfer-encoding'] )
$theBody = WP_Http::chunkTransferDecode($strResponse);
return array('headers' => $processedHeaders['headers'], 'body' => $strResponse, 'response' => $processedHeaders['response']); return array('headers' => $processedHeaders['headers'], 'body' => $strResponse, 'response' => $processedHeaders['response']);
} }
@ -629,27 +679,24 @@ class WP_Http_Streams {
* *
* @param string $url * @param string $url
* @param str|array $args Optional. Override the defaults. * @param str|array $args Optional. Override the defaults.
* @param string|array $headers Optional. Either the header string or array of Header name and value pairs. Expects sanitized.
* @param string $body Optional. The body that should be sent. Expected to be already processed.
* @return array 'headers', 'body', and 'response' keys. * @return array 'headers', 'body', and 'response' keys.
*/ */
function request($url, $args = array(), $headers = null, $body = null) { function request($url, $args = array()) {
$defaults = array( $defaults = array(
'method' => 'GET', 'timeout' => 3, 'method' => 'GET', 'timeout' => 3,
'redirection' => 5, 'httpversion' => '1.0', 'redirection' => 5, 'httpversion' => '1.0',
'blocking' => true 'blocking' => true,
'headers' => array(), 'body' => null
); );
$r = wp_parse_args( $args, $defaults ); $r = wp_parse_args( $args, $defaults );
if ( isset($headers['User-Agent']) ) { if ( isset($r['headers']['User-Agent']) ) {
$r['user-agent'] = $headers['User-Agent']; $r['user-agent'] = $r['headers']['User-Agent'];
unset($headers['User-Agent']); unset($r['headers']['User-Agent']);
} else if( isset($headers['user-agent']) ) { } else if( isset($r['headers']['user-agent']) ) {
$r['user-agent'] = $headers['user-agent']; $r['user-agent'] = $r['headers']['user-agent'];
unset($headers['user-agent']); unset($r['headers']['user-agent']);
} else {
$r['user-agent'] = apply_filters('http_headers_useragent', 'WordPress/' . $wp_version );
} }
$arrURL = parse_url($url); $arrURL = parse_url($url);
@ -660,19 +707,27 @@ class WP_Http_Streams {
if ( 'http' != $arrURL['scheme'] || 'https' != $arrURL['scheme'] ) if ( 'http' != $arrURL['scheme'] || 'https' != $arrURL['scheme'] )
$url = str_replace($arrURL['scheme'], 'http', $url); $url = str_replace($arrURL['scheme'], 'http', $url);
// Convert Header array to string.
$strHeaders = '';
if ( is_array( $r['headers'] ) )
foreach( $r['headers'] as $name => $value )
$strHeaders .= "{$name}: $value\r\n";
else if ( is_string( $r['headers'] ) )
$strHeaders = $r['headers'];
$arrContext = array('http' => $arrContext = array('http' =>
array( array(
'method' => strtoupper($r['method']), 'method' => strtoupper($r['method']),
'user-agent' => $r['user-agent'], 'user-agent' => $r['user-agent'],
'max_redirects' => $r['redirection'], 'max_redirects' => $r['redirection'],
'protocol_version' => (float) $r['httpversion'], 'protocol_version' => (float) $r['httpversion'],
'header' => $headers, 'header' => $strHeaders,
'timeout' => $r['timeout'] 'timeout' => $r['timeout']
) )
); );
if ( ! is_null($body) ) if ( ! is_null($r['body']) && ! empty($r['body'] ) )
$arrContext['http']['content'] = $body; $arrContext['http']['content'] = $r['body'];
$context = stream_context_create($arrContext); $context = stream_context_create($arrContext);
@ -695,6 +750,9 @@ class WP_Http_Streams {
$meta = stream_get_meta_data($handle); $meta = stream_get_meta_data($handle);
$processedHeaders = WP_Http::processHeaders($meta['wrapper_data']); $processedHeaders = WP_Http::processHeaders($meta['wrapper_data']);
if ( ! empty( $strResponse ) && isset( $processedHeaders['headers']['transfer-encoding'] ) && 'chunked' == $processedHeaders['headers']['transfer-encoding'] )
$theBody = WP_Http::chunkTransferDecode($strResponse);
fclose($handle); fclose($handle);
return array('headers' => $processedHeaders['headers'], 'body' => $strResponse, 'response' => $processedHeaders['response']); return array('headers' => $processedHeaders['headers'], 'body' => $strResponse, 'response' => $processedHeaders['response']);
@ -743,29 +801,24 @@ class WP_Http_ExtHTTP {
* *
* @param string $url * @param string $url
* @param str|array $args Optional. Override the defaults. * @param str|array $args Optional. Override the defaults.
* @param array $headers Optional. Either the header string or array of Header name and value pairs. Expects sanitized.
* @param string $body Optional. The body that should be sent. Expected to be already processed.
* @return array 'headers', 'body', and 'response' keys. * @return array 'headers', 'body', and 'response' keys.
*/ */
function request($url, $args = array(), $headers = null, $body = null) { function request($url, $args = array()) {
global $wp_version;
$defaults = array( $defaults = array(
'method' => 'GET', 'timeout' => 3, 'method' => 'GET', 'timeout' => 3,
'redirection' => 5, 'httpversion' => '1.0', 'redirection' => 5, 'httpversion' => '1.0',
'blocking' => true 'blocking' => true,
'headers' => array(), 'body' => null
); );
$r = wp_parse_args( $args, $defaults ); $r = wp_parse_args( $args, $defaults );
if ( isset($headers['User-Agent']) ) { if ( isset($r['headers']['User-Agent']) ) {
$r['user-agent'] = $headers['User-Agent']; $r['user-agent'] = $r['headers']['User-Agent'];
unset($headers['User-Agent']); unset($r['headers']['User-Agent']);
} else if( isset($headers['user-agent']) ) { } else if( isset($r['headers']['user-agent']) ) {
$r['user-agent'] = $headers['user-agent']; $r['user-agent'] = $r['headers']['user-agent'];
unset($headers['user-agent']); unset($r['headers']['user-agent']);
} else {
$r['user-agent'] = apply_filters('http_headers_useragent', 'WordPress/' . $wp_version );
} }
switch ( $r['method'] ) { switch ( $r['method'] ) {
@ -792,10 +845,10 @@ class WP_Http_ExtHTTP {
'connecttimeout' => $r['timeout'], 'connecttimeout' => $r['timeout'],
'redirect' => $r['redirection'], 'redirect' => $r['redirection'],
'useragent' => $r['user-agent'], 'useragent' => $r['user-agent'],
'headers' => $headers, 'headers' => $r['headers'],
); );
$strResponse = http_request($r['method'], $url, $body, $options, $info); $strResponse = http_request($r['method'], $url, $r['body'], $options, $info);
if ( false === $strResponse ) if ( false === $strResponse )
return new WP_Error('http_request_failed', $info['response_code'] . ': ' . $info['error']); return new WP_Error('http_request_failed', $info['response_code'] . ': ' . $info['error']);
@ -850,29 +903,24 @@ class WP_Http_Curl {
* *
* @param string $url * @param string $url
* @param str|array $args Optional. Override the defaults. * @param str|array $args Optional. Override the defaults.
* @param string|array $headers Optional. Either the header string or array of Header name and value pairs. Expects sanitized.
* @param string $body Optional. The body that should be sent. Expected to be already processed.
* @return array 'headers', 'body', and 'response' keys. * @return array 'headers', 'body', and 'response' keys.
*/ */
function request($url, $args = array(), $headers = null, $body = null) { function request($url, $args = array()) {
global $wp_version;
$defaults = array( $defaults = array(
'method' => 'GET', 'timeout' => 3, 'method' => 'GET', 'timeout' => 3,
'redirection' => 5, 'httpversion' => '1.0', 'redirection' => 5, 'httpversion' => '1.0',
'blocking' => true 'blocking' => true,
'headers' => array(), 'body' => null
); );
$r = wp_parse_args( $args, $defaults ); $r = wp_parse_args( $args, $defaults );
if ( isset($headers['User-Agent']) ) { if ( isset($r['headers']['User-Agent']) ) {
$r['user-agent'] = $headers['User-Agent']; $r['user-agent'] = $r['headers']['User-Agent'];
unset($headers['User-Agent']); unset($r['headers']['User-Agent']);
} else if( isset($headers['user-agent']) ) { } else if( isset($r['headers']['user-agent']) ) {
$r['user-agent'] = $headers['user-agent']; $r['user-agent'] = $r['headers']['user-agent'];
unset($headers['user-agent']); unset($r['headers']['user-agent']);
} else {
$r['user-agent'] = apply_filters('http_headers_useragent', 'WordPress/' . $wp_version );
} }
$handle = curl_init(); $handle = curl_init();
@ -896,8 +944,8 @@ class WP_Http_Curl {
if ( !ini_get('safe_mode') && !ini_get('open_basedir') ) if ( !ini_get('safe_mode') && !ini_get('open_basedir') )
curl_setopt( $handle, CURLOPT_FOLLOWLOCATION, true ); curl_setopt( $handle, CURLOPT_FOLLOWLOCATION, true );
if( ! is_null($headers) ) if( ! is_null($r['headers']) )
curl_setopt( $handle, CURLOPT_HTTPHEADER, $headers ); curl_setopt( $handle, CURLOPT_HTTPHEADER, $r['headers'] );
if ( $r['httpversion'] == '1.0' ) if ( $r['httpversion'] == '1.0' )
curl_setopt( $handle, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0 ); curl_setopt( $handle, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0 );
@ -915,6 +963,9 @@ class WP_Http_Curl {
list($theHeaders, $theBody) = explode("\r\n\r\n", $theResponse, 2); list($theHeaders, $theBody) = explode("\r\n\r\n", $theResponse, 2);
$theHeaders = WP_Http::processHeaders($theHeaders); $theHeaders = WP_Http::processHeaders($theHeaders);
if ( ! empty( $theBody ) && isset( $theHeaders['headers']['transfer-encoding'] ) && 'chunked' == $theHeaders['headers']['transfer-encoding'] )
$theBody = WP_Http::chunkTransferDecode($theBody);
$response = array(); $response = array();
$response['code'] = curl_getinfo( $handle, CURLINFO_HTTP_CODE ); $response['code'] = curl_getinfo( $handle, CURLINFO_HTTP_CODE );
$response['message'] = get_status_header_desc($response['code']); $response['message'] = get_status_header_desc($response['code']);
@ -986,14 +1037,11 @@ function &_wp_http_get_object() {
* *
* @param string $url Site URL to retrieve. * @param string $url Site URL to retrieve.
* @param array $args Optional. Override the defaults. * @param array $args Optional. Override the defaults.
* @param string|array $headers Optional. Either the header string or array of Header name and value pairs.
* @param string $body Optional. The body that should be sent. Expected to be already processed.
* @return string The body of the response * @return string The body of the response
*/ */
function wp_remote_request($url, $args = array(), $headers = null, $body = null) { function wp_remote_request($url, $args = array()) {
$objFetchSite = _wp_http_get_object(); $objFetchSite = _wp_http_get_object();
return $objFetchSite->request($url, $args);
return $objFetchSite->request($url, $args, $headers, $body);
} }
/** /**
@ -1005,14 +1053,12 @@ function wp_remote_request($url, $args = array(), $headers = null, $body = null)
* *
* @param string $url Site URL to retrieve. * @param string $url Site URL to retrieve.
* @param array $args Optional. Override the defaults. * @param array $args Optional. Override the defaults.
* @param string|array $headers Optional. Either the header string or array of Header name and value pairs.
* @param string $body Optional. The body that should be sent. Expected to be already processed.
* @return string The body of the response * @return string The body of the response
*/ */
function wp_remote_get($url, $args = array(), $headers = null, $body = null) { function wp_remote_get($url, $args = array()) {
$objFetchSite = _wp_http_get_object(); $objFetchSite = _wp_http_get_object();
return $objFetchSite->get($url, $args, $headers, $body); return $objFetchSite->get($url, $args);
} }
/** /**
@ -1024,14 +1070,11 @@ function wp_remote_get($url, $args = array(), $headers = null, $body = null) {
* *
* @param string $url Site URL to retrieve. * @param string $url Site URL to retrieve.
* @param array $args Optional. Override the defaults. * @param array $args Optional. Override the defaults.
* @param string|array $headers Optional. Either the header string or array of Header name and value pairs.
* @param string $body Optional. The body that should be sent. Expected to be already processed.
* @return string The body of the response * @return string The body of the response
*/ */
function wp_remote_post($url, $args = array(), $headers = null, $body = null) { function wp_remote_post($url, $args = array()) {
$objFetchSite = _wp_http_get_object(); $objFetchSite = _wp_http_get_object();
return $objFetchSite->post($url, $args);
return $objFetchSite->post($url, $args, $headers, $body);
} }
/** /**
@ -1043,14 +1086,11 @@ function wp_remote_post($url, $args = array(), $headers = null, $body = null) {
* *
* @param string $url Site URL to retrieve. * @param string $url Site URL to retrieve.
* @param array $args Optional. Override the defaults. * @param array $args Optional. Override the defaults.
* @param string|array $headers Optional. Either the header string or array of Header name and value pairs.
* @param string $body Optional. The body that should be sent. Expected to be already processed.
* @return string The body of the response * @return string The body of the response
*/ */
function wp_remote_head($url, $args = array(), $headers = null, $body = null) { function wp_remote_head($url, $args = array()) {
$objFetchSite = _wp_http_get_object(); $objFetchSite = _wp_http_get_object();
return $objFetchSite->head($url, $args);
return $objFetchSite->head($url, $args, $headers, $body);
} }
/** /**

View File

@ -1,17 +1,17 @@
<?php <?php
/** /**
* A simple set of functions to check our version 1.0 update service * A simple set of functions to check our version 1.0 update service.
* *
* @package WordPress * @package WordPress
* @since 2.3 * @since 2.3
*/ */
/** /**
* Check WordPress version against the newest version. * * Check WordPress version against the newest version.
*
* The WordPress version, PHP version, and Locale is sent. Checks against the * The WordPress version, PHP version, and Locale is sent. Checks against the
* WordPress server at api.wordpress.org server. Will only check if WordPress * WordPress server at api.wordpress.org server. Will only check if WordPress
* isn't installing. * isn't installing.
* *
* @package WordPress * @package WordPress
* @since 2.3 * @since 2.3
@ -41,20 +41,22 @@ function wp_version_check() {
$new_option->version_checked = $wp_version; $new_option->version_checked = $wp_version;
$url = "http://api.wordpress.org/core/version-check/1.2/?version=$wp_version&php=$php_version&locale=$locale"; $url = "http://api.wordpress.org/core/version-check/1.2/?version=$wp_version&php=$php_version&locale=$locale";
$options = array('timeout' => 3);
$headers = array( $options = array('timeout' => 3);
$options['headers'] = array(
'Content-Type' => 'application/x-www-form-urlencoded; charset=' . get_option('blog_charset'), 'Content-Type' => 'application/x-www-form-urlencoded; charset=' . get_option('blog_charset'),
'User-Agent' => 'WordPress/' . $wp_version . '; ' . get_bloginfo('url') 'User-Agent' => 'WordPress/' . $wp_version . '; ' . get_bloginfo('url')
); );
$response = wp_remote_request($url, $options, $headers); $response = wp_remote_request($url, $options);
if ( is_wp_error( $response ) )
return false;
if ( 200 != $response['response']['code'] ) if ( 200 != $response['response']['code'] )
return false; return false;
$body = $response['body']; $body = trim( $response['body'] );
$body = trim( $body );
$body = str_replace(array("\r\n", "\r"), "\n", $body); $body = str_replace(array("\r\n", "\r"), "\n", $body);
$returns = explode("\n", $body); $returns = explode("\n", $body);
@ -73,11 +75,12 @@ function wp_version_check() {
add_action( 'init', 'wp_version_check' ); add_action( 'init', 'wp_version_check' );
/** /**
* wp_update_plugins() - Check plugin versions against the latest versions hosted on WordPress.org. * Check plugin versions against the latest versions hosted on WordPress.org.
* *
* The WordPress version, PHP version, and Locale is sent along with a list of all plugins installed. * The WordPress version, PHP version, and Locale is sent along with a list of
* Checks against the WordPress server at api.wordpress.org. * all plugins installed. Checks against the WordPress server at
* Will only check if PHP has fsockopen enabled and WordPress isn't installing. * api.wordpress.org. Will only check if PHP has fsockopen enabled and WordPress
* isn't installing.
* *
* @package WordPress * @package WordPress
* @since 2.3 * @since 2.3
@ -88,7 +91,7 @@ add_action( 'init', 'wp_version_check' );
function wp_update_plugins() { function wp_update_plugins() {
global $wp_version; global $wp_version;
if ( !function_exists('fsockopen') || defined('WP_INSTALLING') ) if ( defined('WP_INSTALLING') )
return false; return false;
// If running blog-side, bail unless we've not checked in the last 12 hours // If running blog-side, bail unless we've not checked in the last 12 hours
@ -116,9 +119,11 @@ function wp_update_plugins() {
$plugin_changed = true; $plugin_changed = true;
} }
foreach ( (array) $current->response as $plugin_file => $update_details ) { if ( isset ( $current->response ) && is_array( $current->response ) ) {
if ( ! isset($plugins[ $plugin_file ]) ) { foreach ( $current->response as $plugin_file => $update_details ) {
$plugin_changed = true; if ( ! isset($plugins[ $plugin_file ]) ) {
$plugin_changed = true;
}
} }
} }
@ -129,27 +134,22 @@ function wp_update_plugins() {
$to_send->plugins = $plugins; $to_send->plugins = $plugins;
$to_send->active = $active; $to_send->active = $active;
$send = serialize( $to_send ); $send = serialize( $to_send );
$body = 'plugins=' . urlencode( $send );
$request = 'plugins=' . urlencode( $send ); $options = array('method' => 'POST', 'timeout' => 3, 'body' => $body);
$http_request = "POST /plugins/update-check/1.0/ HTTP/1.0\r\n"; $options['headers'] = array(
$http_request .= "Host: api.wordpress.org\r\n"; 'Content-Type' => 'application/x-www-form-urlencoded; charset=' . get_option('blog_charset'),
$http_request .= "Content-Type: application/x-www-form-urlencoded; charset=" . get_option('blog_charset') . "\r\n"; 'Content-Length' => strlen($body),
$http_request .= "Content-Length: " . strlen($request) . "\r\n"; 'User-Agent' => 'WordPress/' . $wp_version . '; ' . get_bloginfo('url')
$http_request .= 'User-Agent: WordPress/' . $wp_version . '; ' . get_bloginfo('url') . "\r\n"; );
$http_request .= "\r\n";
$http_request .= $request;
$response = ''; $raw_response = wp_remote_request('http://api.wordpress.org/plugins/update-check/1.0/', $options);
if( false != ( $fs = @fsockopen( 'api.wordpress.org', 80, $errno, $errstr, 3) ) && is_resource($fs) ) {
fwrite($fs, $http_request);
while ( !feof($fs) ) if( 200 != $raw_response['response']['code'] ) {
$response .= fgets($fs, 1160); // One TCP-IP packet return false;
fclose($fs);
$response = explode("\r\n\r\n", $response, 2);
} }
$response = unserialize( $response[1] ); $response = unserialize( $raw_response['body'] );
if ( $response ) if ( $response )
$new_option->response = $response; $new_option->response = $response;