Skip to content

Commit bb12b3c

Browse files
committed
[#566] Cover CurlAdapter gzip response parsing
1 parent 3b27e78 commit bb12b3c

3 files changed

Lines changed: 33 additions & 7 deletions

File tree

src/HttpClient/Adapters/CurlAdapter.php

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -417,29 +417,30 @@ private function parseResponse(string $rawResponse)
417417
{
418418
$response = $rawResponse;
419419
$contentType = $this->responseHeaders['Content-Type'] ?? null;
420+
$contentEncoding = $this->responseHeaders['Content-Encoding'] ?? null;
421+
422+
if (is_string($contentEncoding) && strtolower($contentEncoding) === 'gzip') {
423+
$decoded = gzdecode($rawResponse);
424+
$response = $decoded !== false ? $decoded : $response;
425+
}
420426

421427
if (is_string($contentType) && preg_match('/\bjson\b/i', $contentType) === 1) {
422-
$decoded = json_decode($rawResponse);
428+
$decoded = json_decode($response);
423429
return json_last_error() === JSON_ERROR_NONE ? $decoded : $response;
424430
}
425431

426432
if (is_string($contentType) && preg_match('/\bxml\b/i', $contentType) === 1) {
427433
$previousUseInternalErrors = libxml_use_internal_errors(true);
428434

429435
try {
430-
$xml = simplexml_load_string($rawResponse);
436+
$xml = simplexml_load_string($response);
431437
} finally {
432438
libxml_use_internal_errors($previousUseInternalErrors);
433439
}
434440

435441
return $xml !== false ? $xml : $response;
436442
}
437443

438-
if (($this->responseHeaders['Content-Encoding'] ?? null) === 'gzip') {
439-
$decoded = gzdecode($rawResponse);
440-
return $decoded !== false ? $decoded : $response;
441-
}
442-
443444
return $response;
444445
}
445446
}

tests/Unit/HttpClient/Adapters/CurlAdapterTest.php

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,19 @@ public function testCurlAdapterDecodesGzipResponse(): void
164164
$this->assertSame('compressed response', $response);
165165
}
166166

167+
public function testCurlAdapterParsesGzippedJsonResponse(): void
168+
{
169+
$adapter = new CurlAdapter();
170+
$headers = $this->invokePrivateMethod($adapter, 'parseResponseHeaders', [
171+
"HTTP/1.1 200 OK\r\nContent-Type: application/json\r\nContent-Encoding: GZip\r\n\r\n",
172+
]);
173+
$this->setPrivateProperty($adapter, 'responseHeaders', $headers);
174+
175+
$response = $this->invokePrivateMethod($adapter, 'parseResponse', [gzencode('{"ok":true}')]);
176+
177+
$this->assertTrue($response->ok);
178+
}
179+
167180
public function testCurlAdapterPassesZeroInfoOptionToNativeCurl(): void
168181
{
169182
$adapter = new CurlAdapter();

tests/Unit/HttpClient/HttpClientTest.php

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ public function testHttpClientGetSetData(): void
5959
public function testHttpClientIsMultiRequest(): void
6060
{
6161
$curl = Mockery::mock(Curl::class);
62+
$curl->shouldReceive('setUrl')->with('https://example.com')->once();
6263

6364
$multi = Mockery::mock(MultiCurl::class);
6465

@@ -107,6 +108,8 @@ public function testHttpClientEnsureSingleRequestThrowsOnMulti(): void
107108
public function testHttpClientSingleRequestResponseFlow(): void
108109
{
109110
$curl = Mockery::mock(Curl::class);
111+
$curl->shouldReceive('setUrl')->with('https://example.com')->once();
112+
$curl->shouldReceive('setOpt')->with(CURLOPT_CUSTOMREQUEST, 'GET')->once();
110113
$curl->shouldReceive('exec')->once();
111114
$curl->shouldReceive('isError')->andReturn(false);
112115
$curl->shouldReceive('getId')->andReturn(0);
@@ -129,6 +132,10 @@ public function testHttpClientSingleRequestResponseFlow(): void
129132
public function testHttpClientPostRequestWithData(): void
130133
{
131134
$curl = Mockery::mock(Curl::class);
135+
$curl->shouldReceive('setUrl')->with('https://example.com')->once();
136+
$curl->shouldReceive('setOpt')->with(CURLOPT_CUSTOMREQUEST, 'POST')->once();
137+
$curl->shouldReceive('buildPostData')->with(['x' => 1])->once()->andReturn('x=1');
138+
$curl->shouldReceive('setOpt')->with(CURLOPT_POSTFIELDS, 'x=1')->once();
132139
$curl->shouldReceive('exec')->once();
133140
$curl->shouldReceive('isError')->andReturn(false);
134141
$curl->shouldReceive('getId')->andReturn(0);
@@ -148,6 +155,8 @@ public function testHttpClientPostRequestWithData(): void
148155
public function testHttpClientSingleRequestError(): void
149156
{
150157
$curl = Mockery::mock(Curl::class);
158+
$curl->shouldReceive('setUrl')->with('https://bad.local')->once();
159+
$curl->shouldReceive('setOpt')->with(CURLOPT_CUSTOMREQUEST, 'GET')->once();
151160
$curl->shouldReceive('exec')->once();
152161
$curl->shouldReceive('isError')->andReturn(true);
153162
$curl->shouldReceive('getId')->andReturn(0);
@@ -266,6 +275,8 @@ public function testHttpClientCreateAsyncMultiRequestRegistersCallbacks(): void
266275
public function testHttpClientInfoAndUrl(): void
267276
{
268277
$curl = Mockery::mock(Curl::class);
278+
$curl->shouldReceive('setUrl')->with('https://example.com')->once();
279+
$curl->shouldReceive('setOpt')->with(CURLOPT_CUSTOMREQUEST, 'GET')->once();
269280
$curl->shouldReceive('exec')->once();
270281
$curl->shouldReceive('isError')->andReturn(false);
271282
$curl->shouldReceive('getId')->andReturn(0);
@@ -288,6 +299,7 @@ public function testHttpClientInfoAndUrl(): void
288299
public function testHttpClientPassesZeroInfoOption(): void
289300
{
290301
$curl = Mockery::mock(Curl::class);
302+
$curl->shouldReceive('setUrl')->with('https://example.com')->once();
291303
$curl->shouldReceive('getInfo')->with(0)->once()->andReturn('zero');
292304

293305
$this->httpClient->createRequest('https://example.com', $curl);

0 commit comments

Comments
 (0)