Skip to content

Commit

Permalink
Add support for streamed response
Browse files Browse the repository at this point in the history
  • Loading branch information
danizord authored and nicolas-grekas committed Mar 11, 2019
1 parent aebc14b commit 7cc1605
Show file tree
Hide file tree
Showing 3 changed files with 61 additions and 8 deletions.
52 changes: 46 additions & 6 deletions Factory/HttpFoundationFactory.php
Expand Up @@ -13,13 +13,15 @@

use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Message\StreamInterface;
use Psr\Http\Message\UploadedFileInterface;
use Psr\Http\Message\UriInterface;
use Symfony\Bridge\PsrHttpMessage\HttpFoundationFactoryInterface;
use Symfony\Component\HttpFoundation\Cookie;
use Symfony\Component\HttpFoundation\File\UploadedFile;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\StreamedResponse;

/**
* {@inheritdoc}
Expand All @@ -28,6 +30,16 @@
*/
class HttpFoundationFactory implements HttpFoundationFactoryInterface
{
/**
* @var int The maximum output buffering size for each iteration when sending the response
*/
private $responseBufferMaxLength;

public function __construct(int $responseBufferMaxLength = 16372)
{
$this->responseBufferMaxLength = $responseBufferMaxLength;
}

/**
* {@inheritdoc}
*/
Expand Down Expand Up @@ -138,16 +150,25 @@ protected function getTemporaryPath()
/**
* {@inheritdoc}
*/
public function createResponse(ResponseInterface $psrResponse)
public function createResponse(ResponseInterface $psrResponse, bool $streamed = false)
{
$cookies = $psrResponse->getHeader('Set-Cookie');
$psrResponse = $psrResponse->withHeader('Set-Cookie', []);

$response = new Response(
$psrResponse->getBody()->__toString(),
$psrResponse->getStatusCode(),
$psrResponse->getHeaders()
);
if ($streamed) {
$response = new StreamedResponse(
$this->createStreamedResponseCallback($psrResponse->getBody()),
$psrResponse->getStatusCode(),
$psrResponse->getHeaders()
);
} else {
$response = new Response(
$psrResponse->getBody()->__toString(),
$psrResponse->getStatusCode(),
$psrResponse->getHeaders()
);
}

$response->setProtocolVersion($psrResponse->getProtocolVersion());

foreach ($cookies as $cookie) {
Expand Down Expand Up @@ -237,4 +258,23 @@ private function createCookie($cookie)
isset($samesite) ? $samesite : null
);
}

private function createStreamedResponseCallback(StreamInterface $body): callable
{
return function () use ($body) {
if ($body->isSeekable()) {
$body->rewind();
}

if (!$body->isReadable()) {
echo $body;

return;
}

while (!$body->eof()) {
echo $body->read($this->responseBufferMaxLength);
}
};
}
}
9 changes: 9 additions & 0 deletions Tests/Factory/HttpFoundationFactoryTest.php
Expand Up @@ -237,5 +237,14 @@ public function testCreateResponse()

$this->assertEquals('The response body', $symfonyResponse->getContent());
$this->assertEquals(200, $symfonyResponse->getStatusCode());

$symfonyResponse = $this->factory->createResponse($response, true);

ob_start();
$symfonyResponse->sendContent();
$sentContent = ob_get_clean();

$this->assertEquals('The response body', $sentContent);
$this->assertEquals(200, $symfonyResponse->getStatusCode());
}
}
8 changes: 6 additions & 2 deletions Tests/Fixtures/Stream.php
Expand Up @@ -19,6 +19,7 @@
class Stream implements StreamInterface
{
private $stringContent;
private $eof = true;

public function __construct($stringContent = '')
{
Expand Down Expand Up @@ -49,12 +50,12 @@ public function tell()

public function eof()
{
return true;
return $this->eof;
}

public function isSeekable()
{
return false;
return true;
}

public function seek($offset, $whence = SEEK_SET)
Expand All @@ -63,6 +64,7 @@ public function seek($offset, $whence = SEEK_SET)

public function rewind()
{
$this->eof = false;
}

public function isWritable()
Expand All @@ -81,6 +83,8 @@ public function isReadable()

public function read($length)
{
$this->eof = true;

return $this->stringContent;
}

Expand Down

0 comments on commit 7cc1605

Please sign in to comment.