diff --git a/src/Client.php b/src/Client.php index 631428b..5696ab3 100644 --- a/src/Client.php +++ b/src/Client.php @@ -278,6 +278,10 @@ private function addRequestBodyOptions(RequestInterface $request, array $options $body = $request->getBody(); $bodySize = $body->getSize(); if ($bodySize !== 0) { + if ($body->isSeekable()) { + $body->rewind(); + } + // Message has non empty body. if (null === $bodySize || $bodySize > 1024 * 1024) { // Avoid full loading large or unknown size body into memory diff --git a/tests/ClientTest.php b/tests/ClientTest.php index 584d625..6beed4e 100644 --- a/tests/ClientTest.php +++ b/tests/ClientTest.php @@ -1,6 +1,7 @@ getMockBuilder(Client::class)->disableOriginalConstructor() + ->setMethods(['__none__'])->getMock(); + + $bodyOptions = new \ReflectionMethod(Client::class, 'addRequestBodyOptions'); + $bodyOptions->setAccessible(true); + + $body = \GuzzleHttp\Psr7\stream_for('abcdef'); + $body->seek(3); + $request = new Request('http://foo.com', 'POST', $body); + $options = $bodyOptions->invoke($client, $request, []); + + static::assertEquals('abcdef', $options[CURLOPT_POSTFIELDS]); + } + + public function testRewindLargeStream() + { + $client = $this->getMockBuilder(Client::class)->disableOriginalConstructor() + ->setMethods(['__none__'])->getMock(); + + $bodyOptions = new \ReflectionMethod(Client::class, 'addRequestBodyOptions'); + $bodyOptions->setAccessible(true); + + $content = 'abcdef'; + while (strlen($content) < 1024*1024+100) { + $content .= '123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890'; + } + + $length = strlen($content); + $body = \GuzzleHttp\Psr7\stream_for($content); + $body->seek(40); + $request = new Request('http://foo.com', 'POST', $body); + $options = $bodyOptions->invoke($client, $request, []); + + static::assertTrue(false !== strstr($options[CURLOPT_READFUNCTION](null, null, $length), 'abcdef'), 'Steam was not rewinded'); + } + /** * Discovery should be used if no factory given. */