guzzle / psr7

PSR-7 HTTP message library
MIT License
7.88k stars 3 forks source link

Body resource cannot be detached when using `ServerRequest::fromGlobals()` #605

Open mrtus opened 6 months ago

mrtus commented 6 months ago

PHP version: 8.1

Library version: 2.6.2

Description When using ServerRequest::fromGlobals()->getBody()->detach() the returned resource has an empty content.

Looking into its internals the request body stream is wrapped with a CachingStream https://github.com/guzzle/psr7/blob/2.6/src/ServerRequest.php#L171

All of its methods are a bit of a wild-card to find out if they are working or not, looking at the implementation and after some testing, not all of them seem to & will behave as one would expect. e.g. ->getSize() does work, because the $this->remoteStream variable is called directly.

However since ->detach() is implemented through the StreamDecoratorTrait, the detach method is using the $this->stream property, which is seeded by the $target constructor argument of CachingStream.

How to reproduce

Since I think CachingStream is the cause of the problem, I'll limit the steps to that class only.

$httpFactory = new HttpFactory();

$body = $httpFactory->createStream('Hello world!');

$body = new CachingStream($body);

$resource = $body->detach();

$fstats = fstat($resource);
$contents = stream_get_contents($resource);

var_dump($body->getSize()); // Results in `int(11)`
var_dump($fstats['size']); // Results in `int(0)`
var_dump($contents); // Results in `string(0) ""`

Now, passing the body to the $target constructor property too, resolves the problem again, instead ->getSize() all of a sudden is broken.

$httpFactory = new HttpFactory();

$body = $httpFactory->createStream('Hello world!');

$body = new CachingStream($body, $body); // Note the `$target` being set here

$resource = $body->detach();

$fstats = fstat($resource);
$contents = stream_get_contents($resource);

var_dump($body->getSize()); // Results in `NULL`
var_dump($fstats['size']); // Results in `int(11)`
var_dump($contents); // Results in `string(11) "Hello world!"`

Do you require any other information from me?

Can you confirm this can be labeled as a bug?

What would be the proposed work-around?

Thank you.