-
Notifications
You must be signed in to change notification settings - Fork 86
Very inefficient decoding of large chunked messages! #112
Changes from all commits
60cd011
f035be6
24d1a72
893aea3
167ed46
9f27a44
5e6c9c8
fd2c87d
78a5373
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,7 @@ | ||
<?php | ||
/** | ||
* @see https://github.com/zendframework/zend-http for the canonical source repository | ||
* @copyright Copyright (c) 2005-2017 Zend Technologies USA Inc. (http://www.zend.com) | ||
* @copyright Copyright (c) 2005-2018 Zend Technologies USA Inc. (http://www.zend.com) | ||
* @license https://github.com/zendframework/zend-http/blob/master/LICENSE.md New BSD License | ||
*/ | ||
|
||
|
@@ -179,6 +179,60 @@ public function testChunkedResponseCaseInsensitiveZF5438() | |
$this->assertEquals('c0cc9d44790fa2a58078059bab1902a9', md5($res->getContent())); | ||
} | ||
|
||
/** | ||
* @param int $chunksize the data size of the chunk to create | ||
* @return string a chunk of data for embedding inside a chunked response | ||
*/ | ||
private function makeChunk($chunksize) | ||
{ | ||
$chunkdata = str_repeat('W', $chunksize); | ||
return sprintf("%d\r\n%s\r\n", $chunksize, $chunkdata); | ||
} | ||
|
||
/** | ||
* @param Response $response | ||
* @return float the time that calling the getBody function took on the response | ||
*/ | ||
private function getTimeForGetBody(Response $response) | ||
{ | ||
$timeStart = microtime(true); | ||
$response->getBody(); | ||
return microtime(true) - $timeStart; | ||
} | ||
|
||
/** | ||
* @small | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What's There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Does the test fail with the previous code? (just asking, since can't try it on my machine atm) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. On my machine the test does not fail at all. Neither with php7 nor php 5.6 ... small will be removed. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @domoran I was asking if the test fails when removing the patch from the chunk decoding block. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, without the path the ratios are on my machine 2000-5000 under PHP7 and about 250 on PHP5.6 ... Test runs > 60 secs. I can increase the ratio here to make the test pass, but there must be some other problem. I would not expect a ratio much larger than 1, after all this is only one iteration more than before. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Alright, going up with those timings is not gonna help, so I suppose that a different approach needs to be taken. Could you poke me on Friday? I can probably work on it while traveling. |
||
*/ | ||
public function testChunkedResponsePerformance() | ||
{ | ||
$response = new Response(); | ||
|
||
$headers = file_get_contents(__DIR__ . '/_files/response_chunked_head'); | ||
$response->setHeaders(Headers::fromString($headers)); | ||
|
||
// avoid flakiness, repeat test | ||
$timings = []; | ||
for ($i = 0; $i < 4; $i++) { | ||
// get baseline for timing: 2000 x 1 Byte chunks | ||
$responseData = str_repeat($this->makeChunk(1), 2000); | ||
$response->setContent($responseData); | ||
$time1 = $this->getTimeForGetBody($response); | ||
|
||
// 'worst case' response, where 2000 1 Byte chunks are followed by a 10 MB Chunk | ||
$responseData2 = $responseData . $this->makeChunk(10000000); | ||
$response->setContent($responseData2); | ||
$time2 = $this->getTimeForGetBody($response); | ||
|
||
$timings[] = floor($time2 / $time1); | ||
} | ||
|
||
array_shift($timings); // do not measure first iteration | ||
|
||
// make sure that the worst case packet will have an equal timing as the baseline | ||
$errMsg = 'Chunked response is not parsing large packets efficiently! Timings:'; | ||
$this->assertLessThan(20, min($timings), $errMsg . print_r($timings, true)); | ||
} | ||
|
||
public function testLineBreaksCompatibility() | ||
{ | ||
$responseTestLf = $this->readResponse('response_lfonly'); | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
Date: Sun, 25 Jun 2006 19:55:19 GMT | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I would suggest moving this into the test method, via |
||
Server: Apache | ||
X-powered-by: PHP/5.1.4-pl3-gentoo | ||
Connection: close | ||
Transfer-encoding: chunked | ||
Content-type: text/html |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can be inlined