Skip to content

Commit

Permalink
Validate ServerRequest body type
Browse files Browse the repository at this point in the history
  • Loading branch information
clue committed Jul 9, 2020
1 parent dc5a481 commit 898be44
Show file tree
Hide file tree
Showing 3 changed files with 129 additions and 17 deletions.
2 changes: 1 addition & 1 deletion src/Io/RequestHeaderParser.php
Original file line number Diff line number Diff line change
Expand Up @@ -224,7 +224,7 @@ public function parseRequest($headers, $remoteSocketUri, $localSocketUri)
$start['method'],
$uri,
$fields,
null,
'',
$start['version'],
$serverParams
);
Expand Down
45 changes: 29 additions & 16 deletions src/Message/ServerRequest.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Message\StreamInterface;
use Psr\Http\Message\UriInterface;
use React\Http\Io\HttpBodyStream;
use React\Stream\ReadableStreamInterface;
use RingCentral\Psr7\Request;

/**
Expand Down Expand Up @@ -38,25 +40,40 @@ class ServerRequest extends Request implements ServerRequestInterface
private $parsedBody;

/**
* @param null|string $method HTTP method for the request.
* @param null|string|UriInterface $uri URI for the request.
* @param array $headers Headers for the message.
* @param string|resource|StreamInterface $body Message body.
* @param string $protocolVersion HTTP protocol version.
* @param array $serverParams server-side parameters
*
* @throws \InvalidArgumentException for an invalid URI
* @param string $method HTTP method for the request.
* @param string|UriInterface $url URL for the request.
* @param array<string,string|string[]> $headers Headers for the message.
* @param string|ReadableStreamInterface|StreamInterface $body Message body.
* @param string $version HTTP protocol version.
* @param array<string,string> $serverParams server-side parameters
* @throws \InvalidArgumentException for an invalid URL or body
*/
public function __construct(
$method,
$uri,
$url,
array $headers = array(),
$body = null,
$protocolVersion = '1.1',
$body = '',
$version = '1.1',
$serverParams = array()
) {
$stream = null;
if ($body instanceof ReadableStreamInterface && !$body instanceof StreamInterface) {
$stream = $body;
$body = null;
} elseif (!\is_string($body) && !$body instanceof StreamInterface) {
throw new \InvalidArgumentException('Invalid server request body given');
}

$this->serverParams = $serverParams;
parent::__construct($method, $uri, $headers, $body, $protocolVersion);
parent::__construct($method, $url, $headers, $body, $version);

if ($stream !== null) {
$size = (int) $this->getHeaderLine('Content-Length');
if (\strtolower($this->getHeaderLine('Transfer-Encoding')) === 'chunked') {
$size = null;
}
$this->stream = new HttpBodyStream($stream, $size);
}

$query = $this->getUri()->getQuery();
if ($query !== '') {
Expand Down Expand Up @@ -158,10 +175,6 @@ public function withoutAttribute($name)
*/
private function parseCookie($cookie)
{
if ($cookie === '') {
return array();
}

$cookieArray = \explode(';', $cookie);
$result = array();

Expand Down
99 changes: 99 additions & 0 deletions tests/Message/ServerRequestTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@

namespace React\Tests\Http\Message;

use React\Http\Io\HttpBodyStream;
use React\Http\Message\ServerRequest;
use React\Stream\ThroughStream;
use React\Tests\Http\TestCase;

class ServerRequestTest extends TestCase
Expand Down Expand Up @@ -263,4 +265,101 @@ public function testCookieWithoutSpaceAfterSeparatorWillBeAccepted()
$cookies = $this->request->getCookieParams();
$this->assertEquals(array('hello' => 'world', 'react' => 'php'), $cookies);
}

public function testConstructWithStringRequestBodyReturnsStringBodyWithAutomaticSize()
{
$request = new ServerRequest(
'GET',
'http://localhost',
array(),
'foo'
);

$body = $request->getBody();
$this->assertSame(3, $body->getSize());
$this->assertEquals('foo', (string) $body);
}

public function testConstructWithHttpBodyStreamReturnsBodyAsIs()
{
$request = new ServerRequest(
'GET',
'http://localhost',
array(),
$body = new HttpBodyStream(new ThroughStream(), 100)
);

$this->assertSame($body, $request->getBody());
}

public function testConstructWithStreamingRequestBodyReturnsBodyWhichImplementsReadableStreamInterfaceWithSizeZeroDefault()
{
$request = new ServerRequest(
'GET',
'http://localhost',
array(),
new ThroughStream()
);

$body = $request->getBody();
$this->assertInstanceOf('Psr\Http\Message\StreamInterface', $body);
$this->assertInstanceOf('React\Stream\ReadableStreamInterface', $body);
$this->assertSame(0, $body->getSize());
}

public function testConstructWithStreamingRequestBodyReturnsBodyWithSizeFromContentLengthHeader()
{
$request = new ServerRequest(
'GET',
'http://localhost',
array(
'Content-Length' => 100
),
new ThroughStream()
);

$body = $request->getBody();
$this->assertInstanceOf('Psr\Http\Message\StreamInterface', $body);
$this->assertInstanceOf('React\Stream\ReadableStreamInterface', $body);
$this->assertSame(100, $body->getSize());
}

public function testConstructWithStreamingRequestBodyReturnsBodyWithSizeUnknownForTransferEncodingChunked()
{
$request = new ServerRequest(
'GET',
'http://localhost',
array(
'Transfer-Encoding' => 'Chunked'
),
new ThroughStream()
);

$body = $request->getBody();
$this->assertInstanceOf('Psr\Http\Message\StreamInterface', $body);
$this->assertInstanceOf('React\Stream\ReadableStreamInterface', $body);
$this->assertNull($body->getSize());
}

public function testConstructWithFloatRequestBodyThrows()
{
$this->setExpectedException('InvalidArgumentException');
new ServerRequest(
'GET',
'http://localhost',
array(),
1.0
);
}

public function testConstructWithResourceRequestBodyThrows()
{
$this->setExpectedException('InvalidArgumentException');
new ServerRequest(
'GET',
'http://localhost',
array(),
tmpfile()
);
}
}

0 comments on commit 898be44

Please sign in to comment.