Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Introduce a reusable RequestBody and ensure Body::__toString() rewinds properly #1393

Merged
merged 3 commits into from Aug 2, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
8 changes: 6 additions & 2 deletions Slim/Http/Request.php
Expand Up @@ -155,12 +155,12 @@ public static function createFromEnvironment(Environment $environment)
$headers = Headers::createFromEnvironment($environment);
$cookies = Cookies::parseHeader($headers->get('Cookie', []));
$serverParams = $environment->all();
$body = new Body(fopen('php://input', 'r'));
$body = new RequestBody();
$uploadedFiles = UploadedFile::createFromEnvironment($environment);

$request = new static($method, $uri, $headers, $cookies, $serverParams, $body, $uploadedFiles);

if ($request->isPost() &&
if ($method === 'POST' &&
in_array($request->getMediaType(), ['application/x-www-form-urlencoded', 'multipart/form-data'])
) {
// parsed body must be $_POST
Expand Down Expand Up @@ -303,6 +303,10 @@ public function getMethod()
} elseif (is_array($body) && isset($body['_METHOD'])) {
$this->method = $this->filterMethod($body['_METHOD']);
}

if ($this->getBody()->eof()) {
$this->getBody()->rewind();
}
}
}

Expand Down
27 changes: 27 additions & 0 deletions Slim/Http/RequestBody.php
@@ -0,0 +1,27 @@
<?php
/**
* Slim Framework (http://slimframework.com)
*
* @link https://github.com/codeguy/Slim
* @copyright Copyright (c) 2011-2015 Josh Lockhart
* @license https://github.com/codeguy/Slim/blob/master/LICENSE (MIT License)
*/
namespace Slim\Http;

/**
* Provides a PSR-7 implementation of a reusable raw request body
*/
class RequestBody extends Body
{
/**
* Create a new RequestBody.
*/
public function __construct()
{
$stream = fopen('php://temp', 'w+');
stream_copy_to_stream(fopen('php://input', 'r'), $stream);
rewind($stream);

parent::__construct($stream);
}
}
11 changes: 10 additions & 1 deletion Slim/Http/Stream.php
Expand Up @@ -178,7 +178,16 @@ public function detach()
*/
public function __toString()
{
return $this->isAttached() ? (string)stream_get_contents($this->stream, -1, 0) : '';
if (!$this->isAttached()) {
return '';
}

try {
$this->rewind();
return $this->getContents();
} catch (RuntimeException $e) {
return '';
}
}

/**
Expand Down
31 changes: 16 additions & 15 deletions tests/AppTest.php
Expand Up @@ -11,6 +11,7 @@
use \Slim\Http\Environment;
use \Slim\Http\Uri;
use \Slim\Http\Body;
use \Slim\Http\RequestBody;
use \Slim\Http\Headers;
use \Slim\Http\Request;
use \Slim\Http\Response;
Expand Down Expand Up @@ -238,7 +239,7 @@ public function testInvokeReturnMethodNotAllowed()
$headers = Headers::createFromEnvironment($env);
$cookies = [];
$serverParams = $env->all();
$body = new Body(fopen('php://temp', 'r+'));
$body = new RequestBody();
$req = new Request('POST', $uri, $headers, $cookies, $serverParams, $body);
$res = new Response();

Expand Down Expand Up @@ -270,7 +271,7 @@ public function testInvokeWithMatchingRoute()
$headers = Headers::createFromEnvironment($env);
$cookies = [];
$serverParams = $env->all();
$body = new Body(fopen('php://temp', 'r+'));
$body = new RequestBody();
$req = new Request('GET', $uri, $headers, $cookies, $serverParams, $body);
$res = new Response();

Expand Down Expand Up @@ -298,7 +299,7 @@ public function testInvokeWithMatchingRouteWithSetArgument()
$headers = Headers::createFromEnvironment($env);
$cookies = [];
$serverParams = $env->all();
$body = new Body(fopen('php://temp', 'r+'));
$body = new RequestBody();
$req = new Request('GET', $uri, $headers, $cookies, $serverParams, $body);
$res = new Response();

Expand Down Expand Up @@ -326,7 +327,7 @@ public function testInvokeWithMatchingRouteWithSetArguments()
$headers = Headers::createFromEnvironment($env);
$cookies = [];
$serverParams = $env->all();
$body = new Body(fopen('php://temp', 'r+'));
$body = new RequestBody();
$req = new Request('GET', $uri, $headers, $cookies, $serverParams, $body);
$res = new Response();

Expand Down Expand Up @@ -354,7 +355,7 @@ public function testInvokeWithMatchingRouteWithNamedParameter()
$headers = Headers::createFromEnvironment($env);
$cookies = [];
$serverParams = $env->all();
$body = new Body(fopen('php://temp', 'r+'));
$body = new RequestBody();
$req = new Request('GET', $uri, $headers, $cookies, $serverParams, $body);
$res = new Response();

Expand Down Expand Up @@ -387,7 +388,7 @@ public function testInvokeWithMatchingRouteWithNamedParameterRequestResponseArgS
$headers = Headers::createFromEnvironment($env);
$cookies = [];
$serverParams = $env->all();
$body = new Body(fopen('php://temp', 'r+'));
$body = new RequestBody();
$req = new Request('GET', $uri, $headers, $cookies, $serverParams, $body);
$res = new Response();

Expand Down Expand Up @@ -415,7 +416,7 @@ public function testInvokeWithMatchingRouteWithNamedParameterOverwritesSetArgume
$headers = Headers::createFromEnvironment($env);
$cookies = [];
$serverParams = $env->all();
$body = new Body(fopen('php://temp', 'r+'));
$body = new RequestBody();
$req = new Request('GET', $uri, $headers, $cookies, $serverParams, $body);
$res = new Response();

Expand Down Expand Up @@ -445,7 +446,7 @@ public function testInvokeWithoutMatchingRoute()
$headers = Headers::createFromEnvironment($env);
$cookies = [];
$serverParams = $env->all();
$body = new Body(fopen('php://temp', 'r+'));
$body = new RequestBody();
$req = new Request('GET', $uri, $headers, $cookies, $serverParams, $body);
$res = new Response();

Expand All @@ -468,7 +469,7 @@ public function testInvokeWithPimpleCallable()
$headers = Headers::createFromEnvironment($env);
$cookies = [];
$serverParams = $env->all();
$body = new Body(fopen('php://temp', 'r+'));
$body = new RequestBody();
$req = new Request('GET', $uri, $headers, $cookies, $serverParams, $body);
$res = new Response();

Expand Down Expand Up @@ -505,7 +506,7 @@ public function testInvokeWithPimpleUndefinedCallable()
$headers = Headers::createFromEnvironment($env);
$cookies = [];
$serverParams = $env->all();
$body = new Body(fopen('php://temp', 'r+'));
$body = new RequestBody();
$req = new Request('GET', $uri, $headers, $cookies, $serverParams, $body);
$res = new Response();

Expand Down Expand Up @@ -537,7 +538,7 @@ public function testInvokeWithPimpleCallableViaMagicMethod()
$headers = Headers::createFromEnvironment($env);
$cookies = [];
$serverParams = $env->all();
$body = new Body(fopen('php://temp', 'r+'));
$body = new RequestBody();
$req = new Request('GET', $uri, $headers, $cookies, $serverParams, $body);
$res = new Response();

Expand Down Expand Up @@ -578,7 +579,7 @@ function handle($req, $res) {
$headers = Headers::createFromEnvironment($env);
$cookies = [];
$serverParams = $env->all();
$body = new Body(fopen('php://temp', 'r+'));
$body = new RequestBody();
$req = new Request('GET', $uri, $headers, $cookies, $serverParams, $body);
$res = new Response();

Expand All @@ -605,7 +606,7 @@ public function testCurrentRequestAttributesAreNotLostWhenAddingRouteArguments()
$headers = Headers::createFromEnvironment($env);
$cookies = [];
$serverParams = $env->all();
$body = new Body(fopen('php://temp', 'r+'));
$body = new RequestBody();
$req = new Request('GET', $uri, $headers, $cookies, $serverParams, $body);
$req = $req->withAttribute("one", 1);
$res = new Response();
Expand Down Expand Up @@ -638,7 +639,7 @@ public function testCurrentRequestAttributesAreNotLostWhenAddingRouteArgumentsRe
$headers = Headers::createFromEnvironment($env);
$cookies = [];
$serverParams = $env->all();
$body = new Body(fopen('php://temp', 'r+'));
$body = new RequestBody();
$req = new Request('GET', $uri, $headers, $cookies, $serverParams, $body);
$req = $req->withAttribute("one", 1);
$res = new Response();
Expand Down Expand Up @@ -717,7 +718,7 @@ public function testRespond()
$headers = Headers::createFromEnvironment($env);
$cookies = [];
$serverParams = $env->all();
$body = new Body(fopen('php://temp', 'r+'));
$body = new RequestBody();
$req = new Request('GET', $uri, $headers, $cookies, $serverParams, $body);
$res = new Response();

Expand Down
12 changes: 12 additions & 0 deletions tests/Http/BodyTest.php
Expand Up @@ -51,6 +51,10 @@ protected function tearDown()
* This method creates a new resource, and it seeds
* the resource with lorem ipsum text. The returned
* resource is readable, writable, and seekable.
*
* @param string $mode
*
* @return resource
*/
public function resourceFactory($mode = 'r+')
{
Expand Down Expand Up @@ -153,7 +157,15 @@ public function testToStringAttached()
$this->assertEquals($this->text, (string)$body);
}

public function testToStringAttachedRewindsFirst()
{
$this->stream = $this->resourceFactory();
$body = new \Slim\Http\Body($this->stream);

$this->assertEquals($this->text, (string)$body);
$this->assertEquals($this->text, (string)$body);
$this->assertEquals($this->text, (string)$body);
}

public function testToStringDetached()
{
Expand Down