Skip to content

Commit af736b7

Browse files
Merge branch '4.4' into 5.4
* 4.4: [HttpClient] fix 303 after PUT and sending chunked requests
2 parents 2341c4b + 4e7fe5e commit af736b7

File tree

4 files changed

+30
-3
lines changed

4 files changed

+30
-3
lines changed

HttpClientTrait.php

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,8 +101,13 @@ private static function prepareRequest(?string $method, ?string $url, array $opt
101101

102102
if (\is_string($options['body'])
103103
&& (string) \strlen($options['body']) !== substr($h = $options['normalized_headers']['content-length'][0] ?? '', 16)
104-
&& ('' !== $h || ('' !== $options['body'] && !isset($options['normalized_headers']['transfer-encoding'])))
104+
&& ('' !== $h || '' !== $options['body'])
105105
) {
106+
if (isset($options['normalized_headers']['transfer-encoding'])) {
107+
unset($options['normalized_headers']['transfer-encoding']);
108+
$options['body'] = self::dechunk($options['body']);
109+
}
110+
106111
$options['normalized_headers']['content-length'] = [substr_replace($h ?: 'Content-Length: ', \strlen($options['body']), 16)];
107112
}
108113
}
@@ -365,6 +370,22 @@ private static function normalizeBody($body)
365370
return $body;
366371
}
367372

373+
private static function dechunk(string $body): string
374+
{
375+
$h = fopen('php://temp', 'w+');
376+
stream_filter_append($h, 'dechunk', \STREAM_FILTER_WRITE);
377+
fwrite($h, $body);
378+
$body = stream_get_contents($h, -1, 0);
379+
rewind($h);
380+
ftruncate($h, 0);
381+
382+
if (fwrite($h, '-') && '' !== stream_get_contents($h, -1, 0)) {
383+
throw new TransportException('Request body has broken chunked encoding.');
384+
}
385+
386+
return $body;
387+
}
388+
368389
/**
369390
* @param string|string[] $fingerprint
370391
*

NativeHttpClient.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,11 @@ public function request(string $method, string $url, array $options = []): Respo
8686

8787
$options['body'] = self::getBodyAsString($options['body']);
8888

89+
if (isset($options['normalized_headers']['transfer-encoding'])) {
90+
unset($options['normalized_headers']['transfer-encoding']);
91+
$options['headers'] = array_merge(...array_values($options['normalized_headers']));
92+
$options['body'] = self::dechunk($options['body']);
93+
}
8994
if ('' === $options['body'] && $hasBody && !$hasContentLength) {
9095
$options['headers'][] = 'Content-Length: 0';
9196
}

Response/CurlResponse.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -409,6 +409,7 @@ private static function parseHeaderLine($ch, string $data, array &$info, array &
409409
} elseif (303 === $info['http_code'] || ('POST' === $info['http_method'] && \in_array($info['http_code'], [301, 302], true))) {
410410
$info['http_method'] = 'HEAD' === $info['http_method'] ? 'HEAD' : 'GET';
411411
curl_setopt($ch, \CURLOPT_POSTFIELDS, '');
412+
curl_setopt($ch, \CURLOPT_CUSTOMREQUEST, $info['http_method']);
412413
}
413414
}
414415

Tests/MockHttpClientTest.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -217,12 +217,12 @@ public function testFixContentLength()
217217
$this->assertSame(['Content-Length: 7'], $requestOptions['normalized_headers']['content-length']);
218218

219219
$response = $client->request('POST', 'http://localhost:8057/post', [
220-
'body' => 'abc=def',
220+
'body' => "8\r\nSymfony \r\n5\r\nis aw\r\n6\r\nesome!\r\n0\r\n\r\n",
221221
'headers' => ['Transfer-Encoding: chunked'],
222222
]);
223223

224224
$requestOptions = $response->getRequestOptions();
225-
$this->assertFalse(isset($requestOptions['normalized_headers']['content-length']));
225+
$this->assertSame(['Content-Length: 19'], $requestOptions['normalized_headers']['content-length']);
226226

227227
$response = $client->request('POST', 'http://localhost:8057/post', [
228228
'body' => '',

0 commit comments

Comments
 (0)