Gracefully handle invalid chunks in HttpSocket

When invalid chunks are detected we should assume the server is
incorrect and handle the remaining content as a single large chunk.

Refs #5140
This commit is contained in:
mark_story 2014-11-16 23:34:34 -05:00
parent f570f931ce
commit 8cbf975943
2 changed files with 15 additions and 14 deletions

View file

@ -221,28 +221,29 @@ class HttpSocketResponse implements ArrayAccess {
$chunkLength = null; $chunkLength = null;
while ($chunkLength !== 0) { while ($chunkLength !== 0) {
if (!preg_match('/^([0-9a-f]+) *(?:;(.+)=(.+))?(?:\r\n|\n)/iU', $body, $match)) { if (!preg_match('/^([0-9a-f]+)[ ]*(?:;(.+)=(.+))?(?:\r\n|\n)/iU', $body, $match)) {
throw new SocketException(__d('cake_dev', 'HttpSocket::_decodeChunkedBody - Could not parse malformed chunk.')); // Handle remaining invalid data as one big chunk.
preg_match('/^(.*?)\r\n/', $body, $invalidMatch);
$length = isset($invalidMatch[1]) ? strlen($invalidMatch[1]) : 0;
$match = array(
0 => '',
1 => dechex($length)
);
} }
$chunkSize = 0; $chunkSize = 0;
$hexLength = 0; $hexLength = 0;
$chunkExtensionValue = '';
if (isset($match[0])) { if (isset($match[0])) {
$chunkSize = $match[0]; $chunkSize = $match[0];
} }
if (isset($match[1])) { if (isset($match[1])) {
$hexLength = $match[1]; $hexLength = $match[1];
} }
if (isset($match[3])) {
$chunkExtensionValue = $match[3];
}
$body = substr($body, strlen($chunkSize));
$chunkLength = hexdec($hexLength); $chunkLength = hexdec($hexLength);
$chunk = substr($body, 0, $chunkLength); $body = substr($body, strlen($chunkSize));
$decodedBody .= $chunk;
if ($chunkLength !== 0) { $decodedBody .= substr($body, 0, $chunkLength);
if ($chunkLength) {
$body = substr($body, $chunkLength + strlen("\r\n")); $body = substr($body, $chunkLength + strlen("\r\n"));
} }
} }

View file

@ -15,7 +15,6 @@
* @since CakePHP(tm) v 1.2.0.4206 * @since CakePHP(tm) v 1.2.0.4206
* @license http://www.opensource.org/licenses/mit-license.php MIT License * @license http://www.opensource.org/licenses/mit-license.php MIT License
*/ */
App::uses('HttpResponse', 'Network/Http'); App::uses('HttpResponse', 'Network/Http');
/** /**
@ -453,12 +452,13 @@ class HttpResponseTest extends CakeTestCase {
/** /**
* testDecodeChunkedBodyError method * testDecodeChunkedBodyError method
* *
* @expectedException SocketException
* @return void * @return void
*/ */
public function testDecodeChunkedBodyError() { public function testDecodeChunkedBodyError() {
$encoded = "19\r\nThis is a chunked message\r\nE\r\n\nThat is cool\n\r\n"; $encoded = "19\r\nThis is a chunked message\r\nE\r\n\nThat is cool\n\r\n";
$this->HttpResponse->decodeChunkedBody($encoded); $result = $this->HttpResponse->decodeChunkedBody($encoded);
$expected = "This is a chunked message\nThat is cool\n";
$this->assertEquals($expected, $result['body']);
} }
/** /**