WP_HTTP: Improve WP_HTTP::chunkTransferDecode() to properly handle binary data and chunked responses which include data in the page that looks like a chunked response.

This also fixes a case where the gzip'd data would become corrupt after chunked decoding as \r\n was replaced with \n in the data stream. Fixes #23463 


git-svn-id: https://develop.svn.wordpress.org/trunk@25153 602fd350-edb4-49c9-b593-d223f7449a82
This commit is contained in:
Dion Hulse 2013-08-28 06:52:09 +00:00
parent 1d00e1d88a
commit 2785826961
1 changed files with 18 additions and 24 deletions

View File

@ -459,12 +459,10 @@ class WP_Http {
/**
* 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.
* Based off the HTTP http_encoding_dechunk function.
*
* @link http://tools.ietf.org/html/rfc2616#section-19.4.6 Process for chunked decoding.
*
* @todo Add support for footer chunked headers.
* @access public
* @since 2.7.0
* @static
@ -472,35 +470,31 @@ class WP_Http {
* @param string $body Body content
* @return string Chunked decoded body on success or raw body on failure.
*/
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) ) )
public static function chunkTransferDecode( $body ) {
// The body is not chunked encoded or is malformed.
if ( ! preg_match( '/^([0-9a-f]+)[^\r\n]*\r\n/i', trim( $body ) ) )
return $body;
$parsedBody = '';
//$parsedHeaders = array(); Unsupported
$parsed_body = '';
$body_original = $body; // We'll be altering $body, so need a backup in case of error
while ( true ) {
$hasChunk = (bool) preg_match( '/^([0-9a-f]+)(\s|\n)+/mi', $body, $match );
$has_chunk = (bool) preg_match( '/^([0-9a-f]+)[^\r\n]*\r\n/i', $body_copy, $match );
if ( ! $has_chunk || empty( $match[1] ) )
return $body_original;
if ( $hasChunk ) {
if ( empty( $match[1] ) )
return $body;
$length = hexdec( $match[1] );
$chunk_length = strlen( $match[0] );
$length = hexdec( $match[1] );
$chunkLength = strlen( $match[0] );
// Parse out the chunk of data
$parsed_body .= substr( $body, $chunk_length, $length );
$strBody = substr($body, $chunkLength, $length);
$parsedBody .= $strBody;
// Remove the chunk from the raw data
$body = substr( $body, $length + $chunk_length );
$body = ltrim(str_replace(array($match[0], $strBody), '', $body), "\n");
if ( "0" == trim($body) )
return $parsedBody; // Ignore footer headers.
} else {
return $body;
}
// End of document
if ( '0' === trim( $body ) )
return $parsed_body;
}
}