Skip to content

Commit 7329329

Browse files
committed
bugfix: skip error parsing for 2xx responses on rejected promises
1 parent 20818be commit 7329329

3 files changed

Lines changed: 38 additions & 2 deletions

File tree

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
[
2+
{
3+
"type": "bugfix",
4+
"category": "",
5+
"description": "Fixed WrappedHttpHandler buffering the entire partial response body into memory when a 2xx response was attached to a rejected promise, which could exhaust memory on a transport failure during a large streamed download."
6+
}
7+
]

src/WrappedHttpHandler.php

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -168,8 +168,14 @@ private function parseError(
168168

169169
$serviceError = "AWS HTTP error:\n";
170170

171-
if (!isset($err['response'])) {
172-
$parts = ['response' => null];
171+
// A 2xx status on a rejected promise means the transport failed
172+
// mid-body after a success response was received; there is no error
173+
// document to parse, and parsing one would buffer the entire partial
174+
// body into memory.
175+
if (!isset($err['response'])
176+
|| $err['response']->getStatusCode() < 300
177+
) {
178+
$parts = ['response' => $err['response'] ?? null];
173179
$serviceError .= $err['exception']->getMessage();
174180
} else {
175181
try {

tests/WrappedHttpHandlerTest.php

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,29 @@ public function testCanRejectWithoutResponse()
9393
}
9494
}
9595

96+
public function testDoesNotParseErrorWhenRejectedWithSuccessResponse()
97+
{
98+
$e = new \Exception('cURL error 18: transfer closed with outstanding read data remaining');
99+
$cmd = new Command('foo');
100+
$req = new Request('GET', 'http://foo.com');
101+
$res = new Response(200, [], 'partial body');
102+
$handler = function () use ($e, $res) {
103+
return new RejectedPromise(['exception' => $e, 'response' => $res]);
104+
};
105+
$parser = $errorParser = [$this, 'fail'];
106+
$wrapped = new WrappedHttpHandler($handler, $parser, $errorParser);
107+
try {
108+
$wrapped($cmd, $req)->wait();
109+
$this->fail();
110+
} catch (AwsException $e) {
111+
$this->assertSame($cmd, $e->getCommand());
112+
$this->assertSame($req, $e->getRequest());
113+
$this->assertSame($res, $e->getResponse());
114+
$this->assertNull($e->getResult());
115+
$this->assertStringContainsString('cURL error 18', $e->getMessage());
116+
}
117+
}
118+
96119
#[DataProvider('responseAndParserProvider')]
97120
public function testCanRejectWithAndParseResponse(
98121
Response $res,

0 commit comments

Comments
 (0)