diff --git a/src/Symfony/Component/HttpClient/CurlHttpClient.php b/src/Symfony/Component/HttpClient/CurlHttpClient.php index 67a6c1dddd5d8..ba3191c37c340 100644 --- a/src/Symfony/Component/HttpClient/CurlHttpClient.php +++ b/src/Symfony/Component/HttpClient/CurlHttpClient.php @@ -236,6 +236,10 @@ public function request(string $method, string $url, array $options = []): Respo } if (!\is_string($body)) { + if (isset($options['auth_ntlm'])) { + $curlopts[\CURLOPT_FORBID_REUSE] = true; // Reusing NTLM connections requires seeking capability, which only string bodies support + } + if (\is_resource($body)) { $curlopts[\CURLOPT_INFILE] = $body; } else { diff --git a/src/Symfony/Component/HttpClient/HttplugClient.php b/src/Symfony/Component/HttpClient/HttplugClient.php index 8e1dc1c4cb9e3..dad01dcc89c8e 100644 --- a/src/Symfony/Component/HttpClient/HttplugClient.php +++ b/src/Symfony/Component/HttpClient/HttplugClient.php @@ -224,23 +224,44 @@ private function sendPsr7Request(RequestInterface $request, ?bool $buffer = null { try { $body = $request->getBody(); + $headers = $request->getHeaders(); - if ($body->isSeekable()) { - try { - $body->seek(0); - } catch (\RuntimeException) { - // ignore - } + $size = $request->getHeader('content-length')[0] ?? -1; + if (0 > $size && 0 < $size = $body->getSize() ?? -1) { + $headers['Content-Length'] = [$size]; } - $headers = $request->getHeaders(); - if (!$request->hasHeader('content-length') && 0 <= $size = $body->getSize() ?? -1) { - $headers['Content-Length'] = [$size]; + if (0 === $size) { + $body = ''; + } elseif (0 < $size && $size < 1 << 21) { + if ($body->isSeekable()) { + try { + $body->seek(0); + } catch (\RuntimeException) { + // ignore + } + } + + $body = $body->getContents(); + } else { + $body = static function (int $size) use ($body) { + if ($body->isSeekable()) { + try { + $body->seek(0); + } catch (\RuntimeException) { + // ignore + } + } + + while (!$body->eof()) { + yield $body->read($size); + } + }; } $options = [ 'headers' => $headers, - 'body' => static fn (int $size) => $body->read($size), + 'body' => $body, 'buffer' => $buffer, ]; diff --git a/src/Symfony/Component/HttpClient/Psr18Client.php b/src/Symfony/Component/HttpClient/Psr18Client.php index a2a19236e8f67..5ab4a8d3ce41d 100644 --- a/src/Symfony/Component/HttpClient/Psr18Client.php +++ b/src/Symfony/Component/HttpClient/Psr18Client.php @@ -88,23 +88,44 @@ public function sendRequest(RequestInterface $request): ResponseInterface { try { $body = $request->getBody(); + $headers = $request->getHeaders(); - if ($body->isSeekable()) { - try { - $body->seek(0); - } catch (\RuntimeException) { - // ignore - } + $size = $request->getHeader('content-length')[0] ?? -1; + if (0 > $size && 0 < $size = $body->getSize() ?? -1) { + $headers['Content-Length'] = [$size]; } - $headers = $request->getHeaders(); - if (!$request->hasHeader('content-length') && 0 <= $size = $body->getSize() ?? -1) { - $headers['Content-Length'] = [$size]; + if (0 === $size) { + $body = ''; + } elseif (0 < $size && $size < 1 << 21) { + if ($body->isSeekable()) { + try { + $body->seek(0); + } catch (\RuntimeException) { + // ignore + } + } + + $body = $body->getContents(); + } else { + $body = static function (int $size) use ($body) { + if ($body->isSeekable()) { + try { + $body->seek(0); + } catch (\RuntimeException) { + // ignore + } + } + + while (!$body->eof()) { + yield $body->read($size); + } + }; } $options = [ 'headers' => $headers, - 'body' => static fn (int $size) => $body->read($size), + 'body' => $body, ]; if ('1.0' === $request->getProtocolVersion()) {