Skip to content

Commit

Permalink
Merge pull request #2 from rayward/4.2-bc
Browse files Browse the repository at this point in the history
Add body as a callback support to 4.2.4.
  • Loading branch information
rayward authored May 8, 2018
2 parents acccec4 + ce733bb commit 4d008c2
Show file tree
Hide file tree
Showing 6 changed files with 107 additions and 14 deletions.
4 changes: 2 additions & 2 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,11 @@
"ext-mbstring" : "*",
"ext-ctype" : "*",
"sabre/event" : ">=1.0.0,<4.0.0",
"sabre/uri" : "~1.0"
"sabre/uri" : "^1.0.1"
},
"require-dev" : {
"phpunit/phpunit" : "~4.3",
"sabre/cs" : "~0.0.1"
"sabre/cs" : "~0.0.8"
},
"suggest" : {
"ext-curl" : " to make http requests with the Client class"
Expand Down
31 changes: 25 additions & 6 deletions lib/Message.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,9 @@ abstract class Message implements MessageInterface {
/**
* Request body
*
* This should be a stream resource
* This should be a stream resource, string or a callback writing the body to php://output
*
* @var resource
* @var resource|string|callable
*/
protected $body;

Expand Down Expand Up @@ -47,6 +47,9 @@ abstract class Message implements MessageInterface {
function getBodyAsStream() {

$body = $this->getBody();
if (is_callable($body)) {
$body = $this->captureCallbackOutput($body);
}
if (is_string($body) || is_null($body)) {
$stream = fopen('php://temp', 'r+');
fwrite($stream, $body);
Expand Down Expand Up @@ -74,6 +77,9 @@ function getBodyAsString() {
if (is_null($body)) {
return '';
}
if (is_callable($body)) {
return $this->captureCallbackOutput($body);
}
$contentLength = $this->getHeader('Content-Length');
if (is_int($contentLength) || ctype_digit($contentLength)) {
return stream_get_contents($body, $contentLength);
Expand All @@ -85,9 +91,9 @@ function getBodyAsString() {
/**
* Returns the message body, as it's internal representation.
*
* This could be either a string or a stream.
* This could be either a string, a stream or a callback writing the body to php://output.
*
* @return resource|string
* @return resource|string|callable
*/
function getBody() {

Expand All @@ -96,9 +102,9 @@ function getBody() {
}

/**
* Replaces the body resource with a new stream or string.
* Replaces the body resource with a new stream, string or a callback writing the body to php://output.
*
* @param resource|string $body
* @param resource|string|callable $body
*/
function setBody($body) {

Expand Down Expand Up @@ -311,4 +317,17 @@ function getHttpVersion() {
return $this->httpVersion;

}

/**
* Runs given callback and captures data sent to php://output stream.
*
* @param callable $callback
* @return string
*/
private function captureCallbackOutput($callback)
{
ob_start();
$callback();
return ob_get_clean();
}
}
6 changes: 3 additions & 3 deletions lib/MessageInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -35,16 +35,16 @@ function getBodyAsString();
/**
* Returns the message body, as it's internal representation.
*
* This could be either a string or a stream.
* This could be either a string, a stream or a callback writing the body to php://output
*
* @return resource|string
* @return resource|string|callable
*/
function getBody();

/**
* Updates the body resource with a new stream.
*
* @param resource|string $body
* @param resource|string|callable $body
* @return void
*/
function setBody($body);
Expand Down
5 changes: 5 additions & 0 deletions lib/Sapi.php
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,11 @@ static function sendResponse(ResponseInterface $response) {
$body = $response->getBody();
if (is_null($body)) return;

if (is_callable($body)) {
$body();
return;
}

$contentLength = $response->getHeader('Content-Length');
if ($contentLength !== null) {
$output = fopen('php://output', 'wb');
Expand Down
54 changes: 51 additions & 3 deletions tests/HTTP/MessageTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -42,13 +42,50 @@ function testStringBody() {

}

function testCallbackBodyAsString() {

$body = $this->createCallback('foo');

$message = new MessageMock();
$message->setBody($body);

$string = $message->getBodyAsString();

$this->assertSame('foo', $string);

}

function testCallbackBodyAsStream() {

$body = $this->createCallback('foo');

$message = new MessageMock();
$message->setBody($body);

$stream = $message->getBodyAsStream();

$this->assertSame('foo', stream_get_contents($stream));

}

function testGetBodyWhenCallback() {

$callback = $this->createCallback('foo');

$message = new MessageMock();
$message->setBody($callback);

$this->assertSame($callback, $message->getBody());

}

/**
* It's possible that streams contains more data than the Content-Length.
*
* The request object should make sure to never emit more than
* Content-Length, if Content-Length is set.
*
* This is in particular useful when respoding to range requests with
* This is in particular useful when responding to range requests with
* streams that represent files on the filesystem, as it's possible to just
* seek the stream to a certain point, set the content-length and let the
* request object do the rest.
Expand Down Expand Up @@ -208,11 +245,11 @@ function testMultipleHeaders() {
$message->addHeader('A', '2');

$this->assertEquals(
"1,2",
'1,2',
$message->getHeader('A')
);
$this->assertEquals(
"1,2",
'1,2',
$message->getHeader('a')
);

Expand Down Expand Up @@ -241,6 +278,17 @@ function testHasHeaders() {

}

/**
* @param string $content
* @return \Closure Returns a callback printing $content to php://output stream
*/
private function createCallback($content)
{
return function() use ($content) {
echo $content;
};
}

}

class MessageMock extends Message { }
21 changes: 21 additions & 0 deletions tests/HTTP/SapiTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -164,4 +164,25 @@ function testSendLimitedByContentLengthStream() {

}

/**
* @runInSeparateProcess
* @depends testSend
*/
function testSendWorksWithCallbackAsBody() {
$response = new Response(200, [], function() {
$fd = fopen('php://output', 'r+');
fwrite($fd, 'foo');
fclose($fd);
});

ob_start();

Sapi::sendResponse($response);

$result = ob_get_clean();

$this->assertEquals('foo', $result);

}

}

0 comments on commit 4d008c2

Please sign in to comment.