Extract server request marshalling to own class.
This commit is contained in:
parent
cd2e4448e2
commit
168867206e
|
|
@ -30,6 +30,7 @@
|
||||||
},
|
},
|
||||||
"autoload-dev": {
|
"autoload-dev": {
|
||||||
"psr-4": {
|
"psr-4": {
|
||||||
|
"WellRESTed\\": "test/tests/unit/",
|
||||||
"WellRESTed\\Test\\": "test/src/"
|
"WellRESTed\\Test\\": "test/src/"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,9 +4,7 @@ namespace WellRESTed\Message;
|
||||||
|
|
||||||
use InvalidArgumentException;
|
use InvalidArgumentException;
|
||||||
use Psr\Http\Message\ServerRequestInterface;
|
use Psr\Http\Message\ServerRequestInterface;
|
||||||
use Psr\Http\Message\StreamInterface;
|
|
||||||
use Psr\Http\Message\UploadedFileInterface;
|
use Psr\Http\Message\UploadedFileInterface;
|
||||||
use Psr\Http\Message\UriInterface;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Representation of an incoming, server-side HTTP request.
|
* Representation of an incoming, server-side HTTP request.
|
||||||
|
|
@ -53,22 +51,13 @@ class ServerRequest extends Request implements ServerRequestInterface
|
||||||
|
|
||||||
// ------------------------------------------------------------------------
|
// ------------------------------------------------------------------------
|
||||||
|
|
||||||
/**
|
public function __construct(array $serverParams = [])
|
||||||
* Creates a new, empty representation of a server-side HTTP request.
|
|
||||||
*
|
|
||||||
* To obtain a ServerRequest representing the request sent to the server
|
|
||||||
* instantiating the request, use the factory method
|
|
||||||
* ServerRequest::getServerRequest
|
|
||||||
*
|
|
||||||
* @see ServerRequest::getServerRequest
|
|
||||||
*/
|
|
||||||
public function __construct()
|
|
||||||
{
|
{
|
||||||
parent::__construct();
|
parent::__construct();
|
||||||
$this->attributes = [];
|
$this->serverParams = $serverParams;
|
||||||
$this->cookieParams = [];
|
$this->cookieParams = [];
|
||||||
$this->queryParams = [];
|
$this->queryParams = [];
|
||||||
$this->serverParams = [];
|
$this->attributes = [];
|
||||||
$this->uploadedFiles = [];
|
$this->uploadedFiles = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -339,189 +328,6 @@ class ServerRequest extends Request implements ServerRequestInterface
|
||||||
|
|
||||||
// ------------------------------------------------------------------------
|
// ------------------------------------------------------------------------
|
||||||
|
|
||||||
/**
|
|
||||||
* @param array $attributes
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
protected function readFromServerRequest(array $attributes = [])
|
|
||||||
{
|
|
||||||
$this->attributes = $attributes;
|
|
||||||
$this->serverParams = $_SERVER;
|
|
||||||
$this->cookieParams = $_COOKIE;
|
|
||||||
$this->readUploadedFiles($_FILES);
|
|
||||||
$this->queryParams = [];
|
|
||||||
$this->uri = $this->readUri();
|
|
||||||
if (isset($_SERVER['QUERY_STRING'])) {
|
|
||||||
parse_str($_SERVER['QUERY_STRING'], $this->queryParams);
|
|
||||||
}
|
|
||||||
if (isset($_SERVER['SERVER_PROTOCOL']) && $_SERVER['SERVER_PROTOCOL'] === 'HTTP/1.0') {
|
|
||||||
// The default is 1.1, so only update if 1.0
|
|
||||||
$this->protocolVersion = '1.0';
|
|
||||||
}
|
|
||||||
if (isset($_SERVER['REQUEST_METHOD'])) {
|
|
||||||
$this->method = $_SERVER['REQUEST_METHOD'];
|
|
||||||
}
|
|
||||||
$headers = $this->getServerRequestHeaders();
|
|
||||||
foreach ($headers as $key => $value) {
|
|
||||||
$this->headers[$key] = $value;
|
|
||||||
}
|
|
||||||
$this->body = $this->getStreamForBody();
|
|
||||||
|
|
||||||
$contentType = $this->getHeaderLine('Content-type');
|
|
||||||
if (strpos($contentType, 'application/x-www-form-urlencoded') !== false
|
|
||||||
|| strpos($contentType, 'multipart/form-data') !== false) {
|
|
||||||
$this->parsedBody = $_POST;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function readUploadedFiles(array $input): void
|
|
||||||
{
|
|
||||||
$uploadedFiles = [];
|
|
||||||
foreach ($input as $name => $value) {
|
|
||||||
$this->addUploadedFilesToBranch($uploadedFiles, $name, $value);
|
|
||||||
}
|
|
||||||
$this->uploadedFiles = $uploadedFiles;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function addUploadedFilesToBranch(
|
|
||||||
array &$branch,
|
|
||||||
string $name,
|
|
||||||
array $value
|
|
||||||
): void {
|
|
||||||
// Check for each of the expected keys.
|
|
||||||
if (isset($value['name'], $value['type'], $value['tmp_name'], $value['error'], $value['size'])) {
|
|
||||||
// This is a file. It may be a single file, or a list of files.
|
|
||||||
|
|
||||||
// Check if these items are arrays.
|
|
||||||
if (is_array($value['name'])
|
|
||||||
&& is_array($value['type'])
|
|
||||||
&& is_array($value['tmp_name'])
|
|
||||||
&& is_array($value['error'])
|
|
||||||
&& is_array($value['size'])
|
|
||||||
) {
|
|
||||||
// Each item is an array. This is a list of uploaded files.
|
|
||||||
$files = [];
|
|
||||||
$keys = array_keys($value['name']);
|
|
||||||
foreach ($keys as $key) {
|
|
||||||
$files[$key] = new UploadedFile(
|
|
||||||
$value['name'][$key],
|
|
||||||
$value['type'][$key],
|
|
||||||
$value['size'][$key],
|
|
||||||
$value['tmp_name'][$key],
|
|
||||||
$value['error'][$key]
|
|
||||||
);
|
|
||||||
}
|
|
||||||
$branch[$name] = $files;
|
|
||||||
} else {
|
|
||||||
// All expected keys are present and are not arrays. This is an uploaded file.
|
|
||||||
$uploadedFile = new UploadedFile(
|
|
||||||
$value['name'],
|
|
||||||
$value['type'],
|
|
||||||
$value['size'],
|
|
||||||
$value['tmp_name'],
|
|
||||||
$value['error']
|
|
||||||
);
|
|
||||||
$branch[$name] = $uploadedFile;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Add another branch
|
|
||||||
$nextBranch = [];
|
|
||||||
foreach ($value as $nextName => $nextValue) {
|
|
||||||
$this->addUploadedFilesToBranch($nextBranch, $nextName, $nextValue);
|
|
||||||
}
|
|
||||||
$branch[$name] = $nextBranch;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function readUri(): UriInterface
|
|
||||||
{
|
|
||||||
$uri = '';
|
|
||||||
|
|
||||||
$scheme = 'http';
|
|
||||||
if (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] && $_SERVER['HTTPS'] !== 'off') {
|
|
||||||
$scheme = 'https';
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isset($_SERVER['HTTP_HOST'])) {
|
|
||||||
$authority = $_SERVER['HTTP_HOST'];
|
|
||||||
$uri .= "$scheme://$authority";
|
|
||||||
}
|
|
||||||
|
|
||||||
// Path and query string
|
|
||||||
if (isset($_SERVER['REQUEST_URI'])) {
|
|
||||||
$uri .= $_SERVER['REQUEST_URI'];
|
|
||||||
}
|
|
||||||
|
|
||||||
return new Uri($uri);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return a reference to the singleton instance of the Request derived
|
|
||||||
* from the server's information about the request sent to the server.
|
|
||||||
*
|
|
||||||
* @param array $attributes Key-value pairs to add to the request.
|
|
||||||
* @return static
|
|
||||||
* @static
|
|
||||||
*/
|
|
||||||
public static function getServerRequest(array $attributes = [])
|
|
||||||
{
|
|
||||||
$request = new static();
|
|
||||||
$request->readFromServerRequest($attributes);
|
|
||||||
return $request;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return a stream representing the request's body.
|
|
||||||
*
|
|
||||||
* Override this method to use a specific StreamInterface implementation.
|
|
||||||
*
|
|
||||||
* @return StreamInterface
|
|
||||||
*/
|
|
||||||
protected function getStreamForBody()
|
|
||||||
{
|
|
||||||
$input = fopen('php://input', 'rb');
|
|
||||||
$temp = fopen('php://temp', 'wb+');
|
|
||||||
stream_copy_to_stream($input, $temp);
|
|
||||||
rewind($temp);
|
|
||||||
return new Stream($temp);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Read and return all request headers from the request issued to the server.
|
|
||||||
*
|
|
||||||
* @return array Associative array of headers
|
|
||||||
*/
|
|
||||||
protected function getServerRequestHeaders()
|
|
||||||
{
|
|
||||||
// http://www.php.net/manual/en/function.getallheaders.php#84262
|
|
||||||
$headers = [];
|
|
||||||
foreach ($_SERVER as $name => $value) {
|
|
||||||
if (substr($name, 0, 5) === 'HTTP_') {
|
|
||||||
$name = $this->normalizeHeaderName(substr($name, 5));
|
|
||||||
$headers[$name] = trim($value);
|
|
||||||
} elseif ($this->isContentHeader($name) && !empty(trim($value))) {
|
|
||||||
$name = $this->normalizeHeaderName($name);
|
|
||||||
$headers[$name] = trim($value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return $headers;
|
|
||||||
}
|
|
||||||
|
|
||||||
private function isContentHeader(string $name): bool
|
|
||||||
{
|
|
||||||
return $name === 'CONTENT_LENGTH' || $name === 'CONTENT_TYPE';
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param string $name
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
private function normalizeHeaderName($name)
|
|
||||||
{
|
|
||||||
$name = ucwords(strtolower(str_replace('_', ' ', $name)));
|
|
||||||
return str_replace(' ', '-', $name);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param array $root
|
* @param array $root
|
||||||
* @return bool
|
* @return bool
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,201 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace WellRESTed\Message;
|
||||||
|
|
||||||
|
use Psr\Http\Message\ServerRequestInterface;
|
||||||
|
use Psr\Http\Message\StreamInterface;
|
||||||
|
use Psr\Http\Message\UriInterface;
|
||||||
|
|
||||||
|
class ServerRequestMarshaller
|
||||||
|
{
|
||||||
|
public function getServerRequest(
|
||||||
|
?array $serverParams = null,
|
||||||
|
?array $cookieParams = null,
|
||||||
|
?array $queryParams = null,
|
||||||
|
?array $postParams = null,
|
||||||
|
?array $fileParams = null,
|
||||||
|
string $inputStream = 'php://input'
|
||||||
|
): ServerRequestInterface {
|
||||||
|
$serverParams = $serverParams ?? $_SERVER;
|
||||||
|
$cookieParams = $cookieParams ?? $_COOKIE;
|
||||||
|
$queryParams = $queryParams ?? self::parseQuery($serverParams);
|
||||||
|
$postParams = $postParams ?? $_POST;
|
||||||
|
$fileParams = $fileParams ?? $_FILES;
|
||||||
|
|
||||||
|
$request = new ServerRequest($serverParams);
|
||||||
|
|
||||||
|
$request = $request
|
||||||
|
->withProtocolVersion(self::parseProtocolVersion($serverParams))
|
||||||
|
->withMethod(self::parseMethod($serverParams))
|
||||||
|
->withBody(self::readBody($inputStream))
|
||||||
|
->withUri(self::readUri($serverParams))
|
||||||
|
->withUploadedFiles(self::readUploadedFiles($fileParams))
|
||||||
|
->withCookieParams($cookieParams)
|
||||||
|
->withQueryParams($queryParams);
|
||||||
|
|
||||||
|
$headers = self::parseHeaders($serverParams);
|
||||||
|
foreach ($headers as $name => $value) {
|
||||||
|
$request = $request->withAddedHeader($name, $value);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (self::isForm($request)) {
|
||||||
|
$request = $request->withParsedBody($postParams);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $request;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static function parseQuery(array $serverParams): array
|
||||||
|
{
|
||||||
|
$queryParams = [];
|
||||||
|
if (isset($serverParams['QUERY_STRING'])) {
|
||||||
|
parse_str($serverParams['QUERY_STRING'], $queryParams);
|
||||||
|
}
|
||||||
|
return $queryParams;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static function parseProtocolVersion(array $serverParams): string
|
||||||
|
{
|
||||||
|
if (isset($serverParams['SERVER_PROTOCOL'])
|
||||||
|
&& $serverParams['SERVER_PROTOCOL'] === 'HTTP/1.0') {
|
||||||
|
return '1.0';
|
||||||
|
}
|
||||||
|
return '1.1';
|
||||||
|
}
|
||||||
|
|
||||||
|
private static function parseHeaders(array $serverParams): array
|
||||||
|
{
|
||||||
|
// http://www.php.net/manual/en/function.getallheaders.php#84262
|
||||||
|
$headers = [];
|
||||||
|
foreach ($serverParams as $name => $value) {
|
||||||
|
if (substr($name, 0, 5) === 'HTTP_') {
|
||||||
|
$name = self::normalizeHeaderName(substr($name, 5));
|
||||||
|
$headers[$name] = trim($value);
|
||||||
|
} elseif (self::isContentHeader($name) && !empty(trim($value))) {
|
||||||
|
$name = self::normalizeHeaderName($name);
|
||||||
|
$headers[$name] = trim($value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $headers;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static function normalizeHeaderName(string $name): string
|
||||||
|
{
|
||||||
|
$name = ucwords(strtolower(str_replace('_', ' ', $name)));
|
||||||
|
return str_replace(' ', '-', $name);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static function isContentHeader(string $name): bool
|
||||||
|
{
|
||||||
|
return $name === 'CONTENT_LENGTH' || $name === 'CONTENT_TYPE';
|
||||||
|
}
|
||||||
|
|
||||||
|
private static function parseMethod(array $serverParams): string
|
||||||
|
{
|
||||||
|
return $serverParams['REQUEST_METHOD'] ?? 'GET';
|
||||||
|
}
|
||||||
|
|
||||||
|
private static function readBody(string $inputStream): StreamInterface
|
||||||
|
{
|
||||||
|
$input = fopen($inputStream, 'rb');
|
||||||
|
$temp = fopen('php://temp', 'wb+');
|
||||||
|
stream_copy_to_stream($input, $temp);
|
||||||
|
rewind($temp);
|
||||||
|
return new Stream($temp);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static function readUri(array $serverParams): UriInterface
|
||||||
|
{
|
||||||
|
$uri = '';
|
||||||
|
|
||||||
|
$scheme = 'http';
|
||||||
|
if (isset($serverParams['HTTPS']) && $serverParams['HTTPS'] && $serverParams['HTTPS'] !== 'off') {
|
||||||
|
$scheme = 'https';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($serverParams['HTTP_HOST'])) {
|
||||||
|
$authority = $serverParams['HTTP_HOST'];
|
||||||
|
$uri .= "$scheme://$authority";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Path and query string
|
||||||
|
if (isset($serverParams['REQUEST_URI'])) {
|
||||||
|
$uri .= $serverParams['REQUEST_URI'];
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Uri($uri);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static function isForm(ServerRequestInterface $request): bool
|
||||||
|
{
|
||||||
|
$contentType = $request->getHeaderLine('Content-type');
|
||||||
|
return (strpos($contentType, 'application/x-www-form-urlencoded') !== false)
|
||||||
|
|| (strpos($contentType, 'multipart/form-data') !== false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static function readUploadedFiles(array $input): array
|
||||||
|
{
|
||||||
|
$uploadedFiles = [];
|
||||||
|
foreach ($input as $name => $value) {
|
||||||
|
self::addUploadedFilesToBranch($uploadedFiles, $name, $value);
|
||||||
|
}
|
||||||
|
return $uploadedFiles;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static function addUploadedFilesToBranch(
|
||||||
|
array &$branch,
|
||||||
|
string $name,
|
||||||
|
array $value
|
||||||
|
): void {
|
||||||
|
if (self::isUploadedFile($value)) {
|
||||||
|
if (self::isUploadedFileList($value)) {
|
||||||
|
$files = [];
|
||||||
|
$keys = array_keys($value['name']);
|
||||||
|
foreach ($keys as $key) {
|
||||||
|
$files[$key] = new UploadedFile(
|
||||||
|
$value['name'][$key],
|
||||||
|
$value['type'][$key],
|
||||||
|
$value['size'][$key],
|
||||||
|
$value['tmp_name'][$key],
|
||||||
|
$value['error'][$key]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
$branch[$name] = $files;
|
||||||
|
} else {
|
||||||
|
// Single uploaded file
|
||||||
|
$uploadedFile = new UploadedFile(
|
||||||
|
$value['name'],
|
||||||
|
$value['type'],
|
||||||
|
$value['size'],
|
||||||
|
$value['tmp_name'],
|
||||||
|
$value['error']
|
||||||
|
);
|
||||||
|
$branch[$name] = $uploadedFile;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Add another branch
|
||||||
|
$nextBranch = [];
|
||||||
|
foreach ($value as $nextName => $nextValue) {
|
||||||
|
self::addUploadedFilesToBranch($nextBranch, $nextName, $nextValue);
|
||||||
|
}
|
||||||
|
$branch[$name] = $nextBranch;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static function isUploadedFile(array $value): bool
|
||||||
|
{
|
||||||
|
// Check for each of the expected keys. If all are present, this is a
|
||||||
|
// a file. It may be a single file, or a list of files.
|
||||||
|
return isset($value['name'], $value['type'], $value['tmp_name'], $value['error'], $value['size']);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static function isUploadedFileList(array $value): bool
|
||||||
|
{
|
||||||
|
// When each item is an array, this is a list of uploaded files.
|
||||||
|
return is_array($value['name'])
|
||||||
|
&& is_array($value['type'])
|
||||||
|
&& is_array($value['tmp_name'])
|
||||||
|
&& is_array($value['error'])
|
||||||
|
&& is_array($value['size']);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -7,7 +7,7 @@ use Psr\Http\Message\ServerRequestInterface;
|
||||||
use WellRESTed\Dispatching\Dispatcher;
|
use WellRESTed\Dispatching\Dispatcher;
|
||||||
use WellRESTed\Dispatching\DispatcherInterface;
|
use WellRESTed\Dispatching\DispatcherInterface;
|
||||||
use WellRESTed\Message\Response;
|
use WellRESTed\Message\Response;
|
||||||
use WellRESTed\Message\ServerRequest;
|
use WellRESTed\Message\ServerRequestMarshaller;
|
||||||
use WellRESTed\Routing\Router;
|
use WellRESTed\Routing\Router;
|
||||||
use WellRESTed\Transmission\Transmitter;
|
use WellRESTed\Transmission\Transmitter;
|
||||||
use WellRESTed\Transmission\TransmitterInterface;
|
use WellRESTed\Transmission\TransmitterInterface;
|
||||||
|
|
@ -163,7 +163,8 @@ class Server
|
||||||
private function getRequest(): ServerRequestInterface
|
private function getRequest(): ServerRequestInterface
|
||||||
{
|
{
|
||||||
if (!$this->request) {
|
if (!$this->request) {
|
||||||
$this->request = ServerRequest::getServerRequest();
|
$marshaller = new ServerRequestMarshaller();
|
||||||
|
return $marshaller->getServerRequest();
|
||||||
}
|
}
|
||||||
return $this->request;
|
return $this->request;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,381 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace WellRESTed\Message;
|
||||||
|
|
||||||
|
use Psr\Http\Message\UploadedFileInterface;
|
||||||
|
use Psr\Http\Message\UriInterface;
|
||||||
|
use WellRESTed\Test\TestCase;
|
||||||
|
|
||||||
|
/** @backupGlobals enabled */
|
||||||
|
class ServerRequestMarshallerTest extends TestCase
|
||||||
|
{
|
||||||
|
/** @var ServerRequestMarshaller */
|
||||||
|
private $marshaller;
|
||||||
|
|
||||||
|
protected function setUp(): void
|
||||||
|
{
|
||||||
|
parent::setUp();
|
||||||
|
|
||||||
|
$_SERVER = [
|
||||||
|
'HTTP_HOST' => 'localhost',
|
||||||
|
'HTTP_ACCEPT' => 'application/json',
|
||||||
|
'HTTP_CONTENT_TYPE' => 'application/x-www-form-urlencoded',
|
||||||
|
'QUERY_STRING' => 'cat=molly&kitten=aggie'
|
||||||
|
];
|
||||||
|
|
||||||
|
$_COOKIE = [
|
||||||
|
'dog' => 'Bear',
|
||||||
|
'hamster' => 'Dusty'
|
||||||
|
];
|
||||||
|
|
||||||
|
$this->marshaller = new ServerRequestMarshaller();
|
||||||
|
}
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------
|
||||||
|
// Psr\Http\Message\MessageInterface
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------
|
||||||
|
// Protocol Version
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dataProvider protocolVersionProvider
|
||||||
|
* @param $expectedProtocol
|
||||||
|
* @param $actualProtocol
|
||||||
|
*/
|
||||||
|
public function testProvidesProtocolVersion(string $expectedProtocol, ?string $actualProtocol): void
|
||||||
|
{
|
||||||
|
$_SERVER['SERVER_PROTOCOL'] = $actualProtocol;
|
||||||
|
$request = $this->marshaller->getServerRequest();
|
||||||
|
$this->assertEquals($expectedProtocol, $request->getProtocolVersion());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function protocolVersionProvider(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
['1.1', 'HTTP/1.1'],
|
||||||
|
['1.0', 'HTTP/1.0'],
|
||||||
|
['1.1', null],
|
||||||
|
['1.1', 'INVALID']
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------
|
||||||
|
// Headers
|
||||||
|
|
||||||
|
public function testProvidesHeadersFromHttpFields(): void
|
||||||
|
{
|
||||||
|
$_SERVER = [
|
||||||
|
'HTTP_ACCEPT' => 'application/json',
|
||||||
|
'HTTP_CONTENT_TYPE' => 'application/x-www-form-urlencoded'
|
||||||
|
];
|
||||||
|
$request = $this->marshaller->getServerRequest();
|
||||||
|
$this->assertEquals(['application/json'], $request->getHeader('Accept'));
|
||||||
|
$this->assertEquals(['application/x-www-form-urlencoded'], $request->getHeader('Content-type'));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testProvidesApacheContentHeaders(): void
|
||||||
|
{
|
||||||
|
$_SERVER = [
|
||||||
|
'CONTENT_LENGTH' => '1024',
|
||||||
|
'CONTENT_TYPE' => 'application/json'
|
||||||
|
];
|
||||||
|
$request = $this->marshaller->getServerRequest();
|
||||||
|
$this->assertEquals('1024', $request->getHeaderLine('Content-length'));
|
||||||
|
$this->assertEquals('application/json', $request->getHeaderLine('Content-type'));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testDoesNotProvideEmptyApacheContentHeaders(): void
|
||||||
|
{
|
||||||
|
$_SERVER = [
|
||||||
|
'CONTENT_LENGTH' => '',
|
||||||
|
'CONTENT_TYPE' => ' '
|
||||||
|
];
|
||||||
|
$request = $this->marshaller->getServerRequest();
|
||||||
|
$this->assertFalse($request->hasHeader('Content-length'));
|
||||||
|
$this->assertFalse($request->hasHeader('Content-type'));
|
||||||
|
}
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------
|
||||||
|
// Body
|
||||||
|
|
||||||
|
public function testProvidesBodyFromInputStream(): void
|
||||||
|
{
|
||||||
|
$tempFilePath = tempnam(sys_get_temp_dir(), 'test');
|
||||||
|
$content = 'Body content';
|
||||||
|
file_put_contents($tempFilePath, $content);
|
||||||
|
|
||||||
|
$request = $this->marshaller->getServerRequest(
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
$tempFilePath
|
||||||
|
);
|
||||||
|
unlink($tempFilePath);
|
||||||
|
|
||||||
|
$this->assertEquals($content, (string) $request->getBody());
|
||||||
|
}
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------
|
||||||
|
// Psr\Http\Message\RequestInterface
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
|
// Request Target
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dataProvider requestTargetProvider
|
||||||
|
* @param $expectedRequestTarget
|
||||||
|
* @param $actualRequestUri
|
||||||
|
*/
|
||||||
|
public function testProvidesRequestTarget(string $expectedRequestTarget, ?string $actualRequestUri): void
|
||||||
|
{
|
||||||
|
$_SERVER['REQUEST_URI'] = $actualRequestUri;
|
||||||
|
$request = $this->marshaller->getServerRequest();
|
||||||
|
$this->assertEquals($expectedRequestTarget, $request->getRequestTarget());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function requestTargetProvider(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
['/', '/'],
|
||||||
|
['/hello', '/hello'],
|
||||||
|
['/my/path.txt', '/my/path.txt'],
|
||||||
|
['/', null]
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
|
// Method
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dataProvider methodProvider
|
||||||
|
* @param $expectedMethod
|
||||||
|
* @param $serverMethod
|
||||||
|
*/
|
||||||
|
public function testProvidesMethod($expectedMethod, $serverMethod)
|
||||||
|
{
|
||||||
|
$_SERVER['REQUEST_METHOD'] = $serverMethod;
|
||||||
|
$request = $this->marshaller->getServerRequest();
|
||||||
|
$this->assertEquals($expectedMethod, $request->getMethod());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function methodProvider()
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
['GET', 'GET'],
|
||||||
|
['POST', 'POST'],
|
||||||
|
['DELETE', 'DELETE'],
|
||||||
|
['PUT', 'PUT'],
|
||||||
|
['OPTIONS', 'OPTIONS'],
|
||||||
|
['GET', null]
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
|
// URI
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dataProvider uriProvider
|
||||||
|
* @param UriInterface $expected
|
||||||
|
* @param array $serverParams
|
||||||
|
*/
|
||||||
|
public function testProvidesUri(UriInterface $expected, array $serverParams): void
|
||||||
|
{
|
||||||
|
$request = $this->marshaller->getServerRequest($serverParams);
|
||||||
|
$this->assertEquals($expected, $request->getUri());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function uriProvider()
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
[
|
||||||
|
new Uri('http://localhost/path'),
|
||||||
|
[
|
||||||
|
'HTTPS' => 'off',
|
||||||
|
'HTTP_HOST' => 'localhost',
|
||||||
|
'REQUEST_URI' => '/path',
|
||||||
|
'QUERY_STRING' => ''
|
||||||
|
]
|
||||||
|
],
|
||||||
|
[
|
||||||
|
new Uri('https://foo.com/path/to/stuff?cat=molly'),
|
||||||
|
[
|
||||||
|
'HTTPS' => '1',
|
||||||
|
'HTTP_HOST' => 'foo.com',
|
||||||
|
'REQUEST_URI' => '/path/to/stuff?cat=molly',
|
||||||
|
'QUERY_STRING' => 'cat=molly'
|
||||||
|
]
|
||||||
|
],
|
||||||
|
[
|
||||||
|
new Uri('http://foo.com:8080/path/to/stuff?cat=molly'),
|
||||||
|
[
|
||||||
|
'HTTP' => '1',
|
||||||
|
'HTTP_HOST' => 'foo.com:8080',
|
||||||
|
'REQUEST_URI' => '/path/to/stuff?cat=molly',
|
||||||
|
'QUERY_STRING' => 'cat=molly'
|
||||||
|
]
|
||||||
|
]
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------
|
||||||
|
// Psr\Http\Message\ServerRequestInterface
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------
|
||||||
|
// Server Params
|
||||||
|
|
||||||
|
public function testProvidesServerParams(): void
|
||||||
|
{
|
||||||
|
$request = $this->marshaller->getServerRequest();
|
||||||
|
$this->assertEquals($_SERVER, $request->getServerParams());
|
||||||
|
}
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
|
// Cookies
|
||||||
|
|
||||||
|
public function testProvidesCookieParams(): void
|
||||||
|
{
|
||||||
|
$request = $this->marshaller->getServerRequest();
|
||||||
|
$this->assertEquals($_COOKIE, $request->getCookieParams());
|
||||||
|
}
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
|
// Query
|
||||||
|
|
||||||
|
public function testProvidesQueryParams(): void
|
||||||
|
{
|
||||||
|
$request = $this->marshaller->getServerRequest();
|
||||||
|
$query = $request->getQueryParams();
|
||||||
|
$this->assertCount(2, $query);
|
||||||
|
$this->assertEquals('molly', $query['cat']);
|
||||||
|
$this->assertEquals('aggie', $query['kitten']);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
|
// Uploaded Files
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dataProvider uploadedFileProvider
|
||||||
|
* @param UploadedFileInterface $file
|
||||||
|
* @param array $path
|
||||||
|
*/
|
||||||
|
public function testGetServerRequestReadsUploadedFiles(UploadedFileInterface $file, array $path): void
|
||||||
|
{
|
||||||
|
$_FILES = [
|
||||||
|
'single' => [
|
||||||
|
'name' => 'single.txt',
|
||||||
|
'type' => 'text/plain',
|
||||||
|
'tmp_name' => '/tmp/php9hNlHe',
|
||||||
|
'error' => UPLOAD_ERR_OK,
|
||||||
|
'size' => 524
|
||||||
|
],
|
||||||
|
'nested' => [
|
||||||
|
'level2' => [
|
||||||
|
'name' => 'nested.json',
|
||||||
|
'type' => 'application/json',
|
||||||
|
'tmp_name' => '/tmp/phpadhjk',
|
||||||
|
'error' => UPLOAD_ERR_OK,
|
||||||
|
'size' => 1024
|
||||||
|
]
|
||||||
|
],
|
||||||
|
'nestedList' => [
|
||||||
|
'level2' => [
|
||||||
|
'name' => [
|
||||||
|
0 => 'nestedList0.jpg',
|
||||||
|
1 => 'nestedList1.jpg',
|
||||||
|
2 => ''
|
||||||
|
],
|
||||||
|
'type' => [
|
||||||
|
0 => 'image/jpeg',
|
||||||
|
1 => 'image/jpeg',
|
||||||
|
2 => ''
|
||||||
|
],
|
||||||
|
'tmp_name' => [
|
||||||
|
0 => '/tmp/phpjpg0',
|
||||||
|
1 => '/tmp/phpjpg1',
|
||||||
|
2 => ''
|
||||||
|
],
|
||||||
|
'error' => [
|
||||||
|
0 => UPLOAD_ERR_OK,
|
||||||
|
1 => UPLOAD_ERR_OK,
|
||||||
|
2 => UPLOAD_ERR_NO_FILE
|
||||||
|
],
|
||||||
|
'size' => [
|
||||||
|
0 => 256,
|
||||||
|
1 => 4096,
|
||||||
|
2 => 0
|
||||||
|
]
|
||||||
|
]
|
||||||
|
],
|
||||||
|
'nestedDictionary' => [
|
||||||
|
'level2' => [
|
||||||
|
'name' => [
|
||||||
|
'file0' => 'nestedDictionary0.jpg',
|
||||||
|
'file1' => 'nestedDictionary1.jpg'
|
||||||
|
],
|
||||||
|
'type' => [
|
||||||
|
'file0' => 'image/png',
|
||||||
|
'file1' => 'image/png'
|
||||||
|
],
|
||||||
|
'tmp_name' => [
|
||||||
|
'file0' => '/tmp/phppng0',
|
||||||
|
'file1' => '/tmp/phppng1'
|
||||||
|
],
|
||||||
|
'error' => [
|
||||||
|
'file0' => UPLOAD_ERR_OK,
|
||||||
|
'file1' => UPLOAD_ERR_OK
|
||||||
|
],
|
||||||
|
'size' => [
|
||||||
|
'file0' => 256,
|
||||||
|
'file1' => 4096
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
];
|
||||||
|
$request = $this->marshaller->getServerRequest();
|
||||||
|
$current = $request->getUploadedFiles();
|
||||||
|
foreach ($path as $item) {
|
||||||
|
$current = $current[$item];
|
||||||
|
}
|
||||||
|
$this->assertEquals($file, $current);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function uploadedFileProvider(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
[new UploadedFile('single.txt', 'text/plain', 524, '/tmp/php9hNlHe', UPLOAD_ERR_OK), ['single']],
|
||||||
|
[new UploadedFile('nested.json', 'application/json', 1024, '/tmp/phpadhjk', UPLOAD_ERR_OK), ['nested', 'level2']],
|
||||||
|
[new UploadedFile('nestedList0.jpg', 'image/jpeg', 256, '/tmp/phpjpg0', UPLOAD_ERR_OK), ['nestedList', 'level2', 0]],
|
||||||
|
[new UploadedFile('nestedList1.jpg', 'image/jpeg', 4096, '/tmp/phpjpg1', UPLOAD_ERR_OK), ['nestedList', 'level2', 1]],
|
||||||
|
[new UploadedFile('', '', 0, '', UPLOAD_ERR_NO_FILE), ['nestedList', 'level2', 2]],
|
||||||
|
[new UploadedFile('nestedDictionary0.jpg', 'image/png', 256, '/tmp/phppng0', UPLOAD_ERR_OK), ['nestedDictionary', 'level2', 'file0']],
|
||||||
|
[new UploadedFile('nestedDictionary1.jpg', 'image/png', 4096, '/tmp/phppngg1', UPLOAD_ERR_OK), ['nestedDictionary', 'level2', 'file1']]
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
|
// Parsed Body
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dataProvider formContentTypeProvider
|
||||||
|
* @param string $contentType
|
||||||
|
*/
|
||||||
|
public function testProvidesParsedBodyForForms(string $contentType): void
|
||||||
|
{
|
||||||
|
$_SERVER['HTTP_CONTENT_TYPE'] = $contentType;
|
||||||
|
$_POST = [
|
||||||
|
'dog' => 'Bear'
|
||||||
|
];
|
||||||
|
$request = $this->marshaller->getServerRequest();
|
||||||
|
$this->assertEquals('Bear', $request->getParsedBody()['dog']);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function formContentTypeProvider(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
['application/x-www-form-urlencoded'],
|
||||||
|
['multipart/form-data']
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,380 +1,12 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
namespace WellRESTed\Test\Unit\Message;
|
namespace WellRESTed\Message;
|
||||||
|
|
||||||
use InvalidArgumentException;
|
use InvalidArgumentException;
|
||||||
use WellRESTed\Message\NullStream;
|
|
||||||
use WellRESTed\Message\ServerRequest;
|
|
||||||
use WellRESTed\Message\UploadedFile;
|
|
||||||
use WellRESTed\Message\Uri;
|
|
||||||
use WellRESTed\Test\TestCase;
|
use WellRESTed\Test\TestCase;
|
||||||
|
|
||||||
class ServerRequestTest extends TestCase
|
class ServerRequestTest extends TestCase
|
||||||
{
|
{
|
||||||
// ------------------------------------------------------------------------
|
|
||||||
// Construction and Marshalling
|
|
||||||
|
|
||||||
/** @backupGlobals enabled */
|
|
||||||
public function testGetServerRequestReadsFromRequest()
|
|
||||||
{
|
|
||||||
$_SERVER = [
|
|
||||||
'HTTP_HOST' => 'localhost',
|
|
||||||
'HTTP_ACCEPT' => 'application/json',
|
|
||||||
'HTTP_CONTENT_TYPE' => 'application/x-www-form-urlencoded',
|
|
||||||
'QUERY_STRING' => 'guinea_pig=Claude&hamster=Fizzgig'
|
|
||||||
];
|
|
||||||
$_COOKIE = [
|
|
||||||
'cat' => 'Molly'
|
|
||||||
];
|
|
||||||
$_FILES = [];
|
|
||||||
$_POST = [
|
|
||||||
'dog' => 'Bear'
|
|
||||||
];
|
|
||||||
$attributes = ['guinea_pig' => 'Claude'];
|
|
||||||
$request = ServerRequest::getServerRequest($attributes);
|
|
||||||
$this->assertNotNull($request);
|
|
||||||
return $request;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------
|
|
||||||
// Marshalling Request Information
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @backupGlobals enabled
|
|
||||||
* @dataProvider protocolVersionProvider
|
|
||||||
*/
|
|
||||||
public function testGetServerRequestReadsProtocolVersion($expectedProtocol, $serverProtocol)
|
|
||||||
{
|
|
||||||
$_SERVER = [
|
|
||||||
'HTTP_HOST' => 'localhost',
|
|
||||||
'SERVER_PROTOCOL' => $serverProtocol,
|
|
||||||
'REQUEST_METHOD' => 'GET'
|
|
||||||
];
|
|
||||||
$request = ServerRequest::getServerRequest();
|
|
||||||
$this->assertEquals($expectedProtocol, $request->getProtocolVersion());
|
|
||||||
}
|
|
||||||
|
|
||||||
public function protocolVersionProvider()
|
|
||||||
{
|
|
||||||
return [
|
|
||||||
['1.1', 'HTTP/1.1'],
|
|
||||||
['1.0', 'HTTP/1.0'],
|
|
||||||
['1.1', null],
|
|
||||||
['1.1', 'INVALID']
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @backupGlobals enabled
|
|
||||||
* @dataProvider methodProvider
|
|
||||||
*/
|
|
||||||
public function testGetServerRequestReadsMethod($expectedMethod, $serverMethod)
|
|
||||||
{
|
|
||||||
$_SERVER = [
|
|
||||||
'HTTP_HOST' => 'localhost',
|
|
||||||
'REQUEST_METHOD' => $serverMethod
|
|
||||||
];
|
|
||||||
$request = ServerRequest::getServerRequest();
|
|
||||||
$this->assertEquals($expectedMethod, $request->getMethod());
|
|
||||||
}
|
|
||||||
|
|
||||||
public function methodProvider()
|
|
||||||
{
|
|
||||||
return [
|
|
||||||
['GET', 'GET'],
|
|
||||||
['POST', 'POST'],
|
|
||||||
['DELETE', 'DELETE'],
|
|
||||||
['PUT', 'PUT'],
|
|
||||||
['OPTIONS', 'OPTIONS'],
|
|
||||||
['GET', null]
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @backupGlobals enabled
|
|
||||||
* @dataProvider requestTargetProvider
|
|
||||||
*/
|
|
||||||
public function testGetServerRequestReadsRequestTargetFromRequest($expectedRequestTarget, $serverRequestUri)
|
|
||||||
{
|
|
||||||
$_SERVER = [
|
|
||||||
'HTTP_HOST' => 'localhost',
|
|
||||||
'REQUEST_URI' => $serverRequestUri
|
|
||||||
];
|
|
||||||
$request = ServerRequest::getServerRequest();
|
|
||||||
$this->assertEquals($expectedRequestTarget, $request->getRequestTarget());
|
|
||||||
}
|
|
||||||
|
|
||||||
public function requestTargetProvider()
|
|
||||||
{
|
|
||||||
return [
|
|
||||||
['/', '/'],
|
|
||||||
['/hello', '/hello'],
|
|
||||||
['/my/path.txt', '/my/path.txt'],
|
|
||||||
['/', null]
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @depends testGetServerRequestReadsFromRequest */
|
|
||||||
public function testGetServerRequestReadsHeaders($request)
|
|
||||||
{
|
|
||||||
/** @var ServerRequest $request */
|
|
||||||
$this->assertEquals(['application/json'], $request->getHeader('Accept'));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @backupGlobals enabled
|
|
||||||
*/
|
|
||||||
public function testGetServerRequestReadsContentHeaders()
|
|
||||||
{
|
|
||||||
$_SERVER = [
|
|
||||||
'CONTENT_LENGTH' => '1024',
|
|
||||||
'CONTENT_TYPE' => 'application/json'
|
|
||||||
];
|
|
||||||
$request = ServerRequest::getServerRequest();
|
|
||||||
$this->assertEquals('1024', $request->getHeaderLine('Content-length'));
|
|
||||||
$this->assertEquals('application/json', $request->getHeaderLine('Content-type'));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @backupGlobals enabled
|
|
||||||
*/
|
|
||||||
public function testGetServerRequestDoesNotReadEmptyContentHeaders()
|
|
||||||
{
|
|
||||||
$_SERVER = [
|
|
||||||
'CONTENT_LENGTH' => '',
|
|
||||||
'CONTENT_TYPE' => ' '
|
|
||||||
];
|
|
||||||
$request = ServerRequest::getServerRequest();
|
|
||||||
$this->assertFalse($request->hasHeader('Content-length'));
|
|
||||||
$this->assertFalse($request->hasHeader('Content-type'));
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testGetServerRequestReadsBody()
|
|
||||||
{
|
|
||||||
$body = new NullStream();
|
|
||||||
$request = $this->getMockBuilder('WellRESTed\Message\ServerRequest')
|
|
||||||
->setMethods(['getStreamForBody'])
|
|
||||||
->getMock();
|
|
||||||
$request->expects($this->any())
|
|
||||||
->method('getStreamForBody')
|
|
||||||
->will($this->returnValue($body));
|
|
||||||
|
|
||||||
$called = false;
|
|
||||||
$callReadFromServerRequest = function () use (&$called) {
|
|
||||||
$called = true;
|
|
||||||
$this->readFromServerRequest();
|
|
||||||
};
|
|
||||||
$callReadFromServerRequest = $callReadFromServerRequest->bindTo($request, $request);
|
|
||||||
$callReadFromServerRequest();
|
|
||||||
|
|
||||||
$this->assertSame($body, $request->getBody());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @backupGlobals enabled
|
|
||||||
* @dataProvider uriProvider
|
|
||||||
*/
|
|
||||||
public function testGetServerRequestReadsUri($expected, $server)
|
|
||||||
{
|
|
||||||
$_SERVER = $server;
|
|
||||||
$request = ServerRequest::getServerRequest();
|
|
||||||
$this->assertEquals($expected, $request->getUri());
|
|
||||||
}
|
|
||||||
|
|
||||||
public function uriProvider()
|
|
||||||
{
|
|
||||||
return [
|
|
||||||
[
|
|
||||||
new Uri('http://localhost/path'),
|
|
||||||
[
|
|
||||||
'HTTPS' => 'off',
|
|
||||||
'HTTP_HOST' => 'localhost',
|
|
||||||
'REQUEST_URI' => '/path',
|
|
||||||
'QUERY_STRING' => ''
|
|
||||||
]
|
|
||||||
],
|
|
||||||
[
|
|
||||||
new Uri('https://foo.com/path/to/stuff?cat=molly'),
|
|
||||||
[
|
|
||||||
'HTTPS' => '1',
|
|
||||||
'HTTP_HOST' => 'foo.com',
|
|
||||||
'REQUEST_URI' => '/path/to/stuff?cat=molly',
|
|
||||||
'QUERY_STRING' => 'cat=molly'
|
|
||||||
]
|
|
||||||
],
|
|
||||||
[
|
|
||||||
new Uri('http://foo.com:8080/path/to/stuff?cat=molly'),
|
|
||||||
[
|
|
||||||
'HTTP' => '1',
|
|
||||||
'HTTP_HOST' => 'foo.com:8080',
|
|
||||||
'REQUEST_URI' => '/path/to/stuff?cat=molly',
|
|
||||||
'QUERY_STRING' => 'cat=molly'
|
|
||||||
]
|
|
||||||
]
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------
|
|
||||||
// Marshalling ServerRequest Information
|
|
||||||
|
|
||||||
/** @depends testGetServerRequestReadsFromRequest */
|
|
||||||
public function testGetServerRequestReadsServerParams($request)
|
|
||||||
{
|
|
||||||
/** @var ServerRequest $request */
|
|
||||||
$this->assertEquals('localhost', $request->getServerParams()['HTTP_HOST']);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @depends testGetServerRequestReadsFromRequest */
|
|
||||||
public function testGetServerRequestReadsCookieParams($request)
|
|
||||||
{
|
|
||||||
/** @var ServerRequest $request */
|
|
||||||
$this->assertEquals('Molly', $request->getCookieParams()['cat']);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @depends testGetServerRequestReadsFromRequest */
|
|
||||||
public function testGetServerRequestReadsQueryParams($request)
|
|
||||||
{
|
|
||||||
/** @var ServerRequest $request */
|
|
||||||
$this->assertEquals('Claude', $request->getQueryParams()['guinea_pig']);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @backupGlobals enabled
|
|
||||||
* @dataProvider uploadedFileProvider
|
|
||||||
*/
|
|
||||||
public function testGetServerRequestReadsUploadedFiles($file, $path)
|
|
||||||
{
|
|
||||||
$_SERVER = [
|
|
||||||
'HTTP_HOST' => 'localhost',
|
|
||||||
'HTTP_ACCEPT' => 'application/json',
|
|
||||||
'HTTP_CONTENT_TYPE' => 'application/x-www-form-urlencoded'
|
|
||||||
];
|
|
||||||
$_FILES = [
|
|
||||||
'single' => [
|
|
||||||
'name' => 'single.txt',
|
|
||||||
'type' => 'text/plain',
|
|
||||||
'tmp_name' => '/tmp/php9hNlHe',
|
|
||||||
'error' => UPLOAD_ERR_OK,
|
|
||||||
'size' => 524
|
|
||||||
],
|
|
||||||
'nested' => [
|
|
||||||
'level2' => [
|
|
||||||
'name' => 'nested.json',
|
|
||||||
'type' => 'application/json',
|
|
||||||
'tmp_name' => '/tmp/phpadhjk',
|
|
||||||
'error' => UPLOAD_ERR_OK,
|
|
||||||
'size' => 1024
|
|
||||||
]
|
|
||||||
],
|
|
||||||
'nestedList' => [
|
|
||||||
'level2' => [
|
|
||||||
'name' => [
|
|
||||||
0 => 'nestedList0.jpg',
|
|
||||||
1 => 'nestedList1.jpg',
|
|
||||||
2 => ''
|
|
||||||
],
|
|
||||||
'type' => [
|
|
||||||
0 => 'image/jpeg',
|
|
||||||
1 => 'image/jpeg',
|
|
||||||
2 => ''
|
|
||||||
],
|
|
||||||
'tmp_name' => [
|
|
||||||
0 => '/tmp/phpjpg0',
|
|
||||||
1 => '/tmp/phpjpg1',
|
|
||||||
2 => ''
|
|
||||||
],
|
|
||||||
'error' => [
|
|
||||||
0 => UPLOAD_ERR_OK,
|
|
||||||
1 => UPLOAD_ERR_OK,
|
|
||||||
2 => UPLOAD_ERR_NO_FILE
|
|
||||||
],
|
|
||||||
'size' => [
|
|
||||||
0 => 256,
|
|
||||||
1 => 4096,
|
|
||||||
2 => 0
|
|
||||||
]
|
|
||||||
]
|
|
||||||
],
|
|
||||||
'nestedDictionary' => [
|
|
||||||
'level2' => [
|
|
||||||
'name' => [
|
|
||||||
'file0' => 'nestedDictionary0.jpg',
|
|
||||||
'file1' => 'nestedDictionary1.jpg'
|
|
||||||
],
|
|
||||||
'type' => [
|
|
||||||
'file0' => 'image/png',
|
|
||||||
'file1' => 'image/png'
|
|
||||||
],
|
|
||||||
'tmp_name' => [
|
|
||||||
'file0' => '/tmp/phppng0',
|
|
||||||
'file1' => '/tmp/phppng1'
|
|
||||||
],
|
|
||||||
'error' => [
|
|
||||||
'file0' => UPLOAD_ERR_OK,
|
|
||||||
'file1' => UPLOAD_ERR_OK
|
|
||||||
],
|
|
||||||
'size' => [
|
|
||||||
'file0' => 256,
|
|
||||||
'file1' => 4096
|
|
||||||
]
|
|
||||||
]
|
|
||||||
]
|
|
||||||
];
|
|
||||||
$request = ServerRequest::getServerRequest();
|
|
||||||
$current = $request->getUploadedFiles();
|
|
||||||
foreach ($path as $item) {
|
|
||||||
$current = $current[$item];
|
|
||||||
}
|
|
||||||
$this->assertEquals($file, $current);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function uploadedFileProvider()
|
|
||||||
{
|
|
||||||
return [
|
|
||||||
[new UploadedFile('single.txt', 'text/plain', 524, '/tmp/php9hNlHe', UPLOAD_ERR_OK), ['single']],
|
|
||||||
[new UploadedFile('nested.json', 'application/json', 1024, '/tmp/phpadhjk', UPLOAD_ERR_OK), ['nested', 'level2']],
|
|
||||||
[new UploadedFile('nestedList0.jpg', 'image/jpeg', 256, '/tmp/phpjpg0', UPLOAD_ERR_OK), ['nestedList', 'level2', 0]],
|
|
||||||
[new UploadedFile('nestedList1.jpg', 'image/jpeg', 4096, '/tmp/phpjpg1', UPLOAD_ERR_OK), ['nestedList', 'level2', 1]],
|
|
||||||
[new UploadedFile('', '', 0, '', UPLOAD_ERR_NO_FILE), ['nestedList', 'level2', 2]],
|
|
||||||
[new UploadedFile('nestedDictionary0.jpg', 'image/png', 256, '/tmp/phppng0', UPLOAD_ERR_OK), ['nestedDictionary', 'level2', 'file0']],
|
|
||||||
[new UploadedFile('nestedDictionary1.jpg', 'image/png', 4096, '/tmp/phppngg1', UPLOAD_ERR_OK), ['nestedDictionary', 'level2', 'file1']]
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @backupGlobals enabled
|
|
||||||
* @dataProvider formContentTypeProvider
|
|
||||||
*/
|
|
||||||
public function testGetServerRequestParsesFormBody($contentType)
|
|
||||||
{
|
|
||||||
$_SERVER = [
|
|
||||||
'HTTP_HOST' => 'localhost',
|
|
||||||
'HTTP_CONTENT_TYPE' => $contentType,
|
|
||||||
];
|
|
||||||
$_COOKIE = [];
|
|
||||||
$_FILES = [];
|
|
||||||
$_POST = [
|
|
||||||
'dog' => 'Bear'
|
|
||||||
];
|
|
||||||
$request = ServerRequest::getServerRequest();
|
|
||||||
$this->assertEquals('Bear', $request->getParsedBody()['dog']);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function formContentTypeProvider()
|
|
||||||
{
|
|
||||||
return [
|
|
||||||
['application/x-www-form-urlencoded'],
|
|
||||||
['multipart/form-data']
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @depends testGetServerRequestReadsFromRequest */
|
|
||||||
public function testGetServerRequestProvidesAttributesIfPassed($request)
|
|
||||||
{
|
|
||||||
/** @var ServerRequest $request */
|
|
||||||
$this->assertEquals('Claude', $request->getAttribute('guinea_pig'));
|
|
||||||
}
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------
|
// ------------------------------------------------------------------------
|
||||||
// Server Params
|
// Server Params
|
||||||
|
|
||||||
|
|
@ -393,14 +25,17 @@ class ServerRequestTest extends TestCase
|
||||||
$this->assertEquals([], $request->getCookieParams());
|
$this->assertEquals([], $request->getCookieParams());
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @depends testGetServerRequestReadsFromRequest */
|
public function testWithCookieParamsCreatesNewInstanceWithCookies()
|
||||||
public function testWithCookieParamsCreatesNewInstance($request1)
|
|
||||||
{
|
{
|
||||||
/** @var ServerRequest $request1 */
|
$cookies = [
|
||||||
$request2 = $request1->withCookieParams([
|
|
||||||
'cat' => 'Oscar'
|
'cat' => 'Oscar'
|
||||||
]);
|
];
|
||||||
$this->assertNotEquals($request1->getCookieParams()['cat'], $request2->getCookieParams()['cat']);
|
|
||||||
|
$request1 = new ServerRequest();
|
||||||
|
$request2 = $request1->withCookieParams($cookies);
|
||||||
|
|
||||||
|
$this->assertEquals($cookies, $request2->getCookieParams());
|
||||||
|
$this->assertNotSame($request2, $request1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------
|
// ------------------------------------------------------------------------
|
||||||
|
|
@ -412,14 +47,17 @@ class ServerRequestTest extends TestCase
|
||||||
$this->assertEquals([], $request->getQueryParams());
|
$this->assertEquals([], $request->getQueryParams());
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @depends testGetServerRequestReadsFromRequest */
|
public function testWithQueryParamsCreatesNewInstance()
|
||||||
public function testWithQueryParamsCreatesNewInstance($request1)
|
|
||||||
{
|
{
|
||||||
/** @var ServerRequest $request1 */
|
$query = [
|
||||||
$request2 = $request1->withQueryParams([
|
'cat' => 'Aggie'
|
||||||
'guinea_pig' => 'Clyde'
|
];
|
||||||
]);
|
|
||||||
$this->assertNotEquals($request1->getQueryParams()['guinea_pig'], $request2->getQueryParams()['guinea_pig']);
|
$request1 = new ServerRequest();
|
||||||
|
$request2 = $request1->withQueryParams($query);
|
||||||
|
|
||||||
|
$this->assertEquals($query, $request2->getQueryParams());
|
||||||
|
$this->assertNotSame($request2, $request1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------
|
// ------------------------------------------------------------------------
|
||||||
|
|
@ -431,19 +69,6 @@ class ServerRequestTest extends TestCase
|
||||||
$this->assertEquals([], $request->getUploadedFiles());
|
$this->assertEquals([], $request->getUploadedFiles());
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @backupGlobals enabled */
|
|
||||||
public function testGetUploadedFilesReturnsEmptyArrayWhenNoFilesAreUploaded()
|
|
||||||
{
|
|
||||||
$_SERVER = [
|
|
||||||
'HTTP_HOST' => 'localhost',
|
|
||||||
'HTTP_ACCEPT' => 'application/json',
|
|
||||||
'HTTP_CONTENT_TYPE' => 'application/x-www-form-urlencoded'
|
|
||||||
];
|
|
||||||
$_FILES = [];
|
|
||||||
$request = ServerRequest::getServerRequest();
|
|
||||||
$this->assertSame([], $request->getUploadedFiles());
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testWithUploadedFilesCreatesNewInstance()
|
public function testWithUploadedFilesCreatesNewInstance()
|
||||||
{
|
{
|
||||||
$uploadedFiles = [
|
$uploadedFiles = [
|
||||||
|
|
@ -566,18 +191,17 @@ class ServerRequestTest extends TestCase
|
||||||
$this->assertNull($request->getParsedBody());
|
$this->assertNull($request->getParsedBody());
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @depends testGetServerRequestReadsFromRequest */
|
public function testWithParsedBodyCreatesNewInstance()
|
||||||
public function testWithParsedBodyCreatesNewInstance($request1)
|
|
||||||
{
|
{
|
||||||
/** @var ServerRequest $request1 */
|
$body = [
|
||||||
$body1 = $request1->getParsedBody();
|
|
||||||
|
|
||||||
$request2 = $request1->withParsedBody([
|
|
||||||
'guinea_pig' => 'Clyde'
|
'guinea_pig' => 'Clyde'
|
||||||
]);
|
];
|
||||||
$body2 = $request2->getParsedBody();
|
|
||||||
|
|
||||||
$this->assertNotSame($body1, $body2);
|
$request1 = new ServerRequest();
|
||||||
|
$request2 = $request1->withParsedBody($body);
|
||||||
|
|
||||||
|
$this->assertEquals($body, $request2->getParsedBody());
|
||||||
|
$this->assertNotSame($request2, $request1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -1,19 +1,15 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
namespace WellRESTed\Test\Unit;
|
namespace WellRESTed;
|
||||||
|
|
||||||
use Prophecy\Argument;
|
use Prophecy\Argument;
|
||||||
use Prophecy\PhpUnit\ProphecyTrait;
|
use Prophecy\PhpUnit\ProphecyTrait;
|
||||||
use WellRESTed\Dispatching\DispatcherInterface;
|
use WellRESTed\Dispatching\DispatcherInterface;
|
||||||
use WellRESTed\Message\Response;
|
use WellRESTed\Message\Response;
|
||||||
use WellRESTed\Message\ServerRequest;
|
use WellRESTed\Message\ServerRequest;
|
||||||
use WellRESTed\Message\Stream;
|
|
||||||
use WellRESTed\Server;
|
|
||||||
use WellRESTed\Test\TestCase;
|
use WellRESTed\Test\TestCase;
|
||||||
use WellRESTed\Transmission\TransmitterInterface;
|
use WellRESTed\Transmission\TransmitterInterface;
|
||||||
|
|
||||||
require_once __DIR__ . '/../../src/HeaderStack.php';
|
|
||||||
|
|
||||||
class ServerTest extends TestCase
|
class ServerTest extends TestCase
|
||||||
{
|
{
|
||||||
use ProphecyTrait;
|
use ProphecyTrait;
|
||||||
|
|
@ -204,26 +200,4 @@ class ServerTest extends TestCase
|
||||||
$defaultResponse
|
$defaultResponse
|
||||||
)->shouldHaveBeenCalled();
|
)->shouldHaveBeenCalled();
|
||||||
}
|
}
|
||||||
|
|
||||||
// -------------------------------------------------------------------------
|
|
||||||
|
|
||||||
public function testCreatesStockTransmitterByDefault()
|
|
||||||
{
|
|
||||||
$content = 'Hello, world!';
|
|
||||||
|
|
||||||
$response = (new Response())
|
|
||||||
->withBody(new Stream($content));
|
|
||||||
|
|
||||||
$server = new Server();
|
|
||||||
$server->add(function () use ($response) {
|
|
||||||
return $response;
|
|
||||||
});
|
|
||||||
|
|
||||||
ob_start();
|
|
||||||
$server->respond();
|
|
||||||
$captured = ob_get_contents();
|
|
||||||
ob_end_clean();
|
|
||||||
|
|
||||||
$this->assertEquals($content, $captured);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue