Browse Source

Change `RequestParserInterface::parse()` to accept whole `Request` instance (#14784)

`RequestParserInterface::parse()` signature changed to accept `Request` instance
tags/3.0.0-alpha1
Paul Klimov 7 years ago committed by GitHub
parent
commit
e703645b4d
  1. 1
      framework/CHANGELOG.md
  2. 2
      framework/UPGRADE.md
  3. 9
      framework/web/JsonParser.php
  4. 7
      framework/web/MultipartFormDataParser.php
  5. 17
      framework/web/Request.php
  6. 13
      framework/web/RequestParserInterface.php
  7. 50
      tests/framework/web/MultipartFormDataParserTest.php

1
framework/CHANGELOG.md

@ -16,6 +16,7 @@ Yii Framework 2 Change Log
- Enh #12938: Allow to pass additional parameters to `yii\base\View::renderDynamic()` (mikehaertl)
- Enh #13006: Added a `/` to the `yii\captcha\Captcha::$captchaAction` string to work correctly in a module also (boehsermoe)
- Removed methods marked as deprecated in 2.0.x (samdark)
- Chg #14784: Signature of `yii\web\RequestParserInterface::parse()` changed to accept `yii\web\Request` instance as a sole argument (klimov-paul)
- Chg #10771: Consistent behavior of `run()` method in all framework widgets. All return the result now for better extensibility (pkirill99, cebe)
- Chg #11397: Minimum required version of PHP is 7.1 now (samdark)
- Chg: Removed `yii\base\Object::className()` in favor of native PHP syntax `::class`, which does not trigger autoloading (cebe)

2
framework/UPGRADE.md

@ -110,6 +110,8 @@ Upgrade from Yii 2.0.x
with PHP. For details please refer to [guide on autoloading](https://github.com/yiisoft/yii2/blob/2.1/docs/guide/concept-autoloading.md),
[guide on customizing helpers](https://github.com/yiisoft/yii2/blob/2.1/docs/guide/helper-overview.md#customizing-helper-classes-)
and [guide on Working with Third-Party Code](https://github.com/yiisoft/yii2/blob/2.1/docs/guide/tutorial-yii-integration.md).
* The signature of `yii\web\RequestParserInterface::parse()` was changed. The method now accepts the `yii\web\Request` instance
as a sole argument. Make sure you declare and implement this method correctly, while creating your own request parser.
Upgrade from Yii 2.0.12

9
framework/web/JsonParser.php

@ -39,16 +39,13 @@ class JsonParser implements RequestParserInterface
/**
* Parses a HTTP request body.
* @param string $rawBody the raw HTTP request body.
* @param string $contentType the content type specified for the request body.
* @return array parameters parsed from the request body
* {@inheritdoc}
* @throws BadRequestHttpException if the body contains invalid json and [[throwException]] is `true`.
*/
public function parse($rawBody, $contentType)
public function parse($request)
{
try {
$parameters = Json::decode($rawBody, $this->asArray);
$parameters = Json::decode($request->getBody()->__toString(), $this->asArray);
return $parameters === null ? [] : $parameters;
} catch (InvalidArgumentException $e) {
if ($this->throwException) {

7
framework/web/MultipartFormDataParser.php

@ -123,9 +123,9 @@ class MultipartFormDataParser extends BaseObject implements RequestParserInterfa
}
/**
* @inheritdoc
* {@inheritdoc}
*/
public function parse($rawBody, $contentType)
public function parse($request)
{
if (!$this->force) {
if (!empty($_POST) || !empty($_FILES)) {
@ -136,6 +136,9 @@ class MultipartFormDataParser extends BaseObject implements RequestParserInterfa
$_FILES = [];
}
$contentType = $request->getContentType();
$rawBody = $request->getBody()->__toString();
if (empty($rawBody)) {
return [];
}

17
framework/web/Request.php

@ -16,6 +16,7 @@ use yii\di\Instance;
use yii\http\Cookie;
use yii\http\CookieCollection;
use yii\http\FileStream;
use yii\http\MemoryStream;
use yii\http\MessageTrait;
use yii\http\Uri;
@ -479,19 +480,13 @@ class Request extends \yii\base\Request implements RequestInterface
]);
}
private $_rawBody;
/**
* Returns the raw HTTP request body.
* @return string the request body
*/
public function getRawBody()
{
if ($this->_rawBody === null) {
$this->_rawBody = $this->getBody()->__toString();
}
return $this->_rawBody;
return $this->getBody()->__toString();
}
/**
@ -500,7 +495,9 @@ class Request extends \yii\base\Request implements RequestInterface
*/
public function setRawBody($rawBody)
{
$this->_rawBody = $rawBody;
$body = new MemoryStream();
$body->write($rawBody);
$this->setBody($body);
}
private $_bodyParams;
@ -539,13 +536,13 @@ class Request extends \yii\base\Request implements RequestInterface
if (!($parser instanceof RequestParserInterface)) {
throw new InvalidConfigException("The '$contentType' request parser is invalid. It must implement the yii\\web\\RequestParserInterface.");
}
$this->_bodyParams = $parser->parse($this->getRawBody(), $rawContentType);
$this->_bodyParams = $parser->parse($this);
} elseif (isset($this->parsers['*'])) {
$parser = Yii::createObject($this->parsers['*']);
if (!($parser instanceof RequestParserInterface)) {
throw new InvalidConfigException('The fallback request parser is invalid. It must implement the yii\\web\\RequestParserInterface.');
}
$this->_bodyParams = $parser->parse($this->getRawBody(), $rawContentType);
$this->_bodyParams = $parser->parse($this);
} elseif ($this->getMethod() === 'POST') {
// PHP has already parsed the body so we have all params in $_POST
$this->_bodyParams = $_POST;

13
framework/web/RequestParserInterface.php

@ -11,15 +11,18 @@ namespace yii\web;
* Interface for classes that parse the raw request body into a parameters array.
*
* @author Dan Schmidt <danschmidt5189@gmail.com>
* @author Paul Klimov <klimov.paul@gmail.com>
* @since 2.0
*/
interface RequestParserInterface
{
/**
* Parses a HTTP request body.
* @param string $rawBody the raw HTTP request body.
* @param string $contentType the content type specified for the request body.
* @return array parameters parsed from the request body
* Parses a given request instance determining its body parameters.
* This method MUST return the array of body parameters detected from [[$request]] data.
* However, this method MAY adjust the given [[Request]] instance directly for extra configuration.
* @param Request $request the HTTP request instance to be parsed.
* @return array parameters parsed from the request body.
* @throws BadRequestHttpException in case request body format is invalid.
*/
public function parse($rawBody, $contentType);
public function parse($request);
}

50
tests/framework/web/MultipartFormDataParserTest.php

@ -8,6 +8,7 @@
namespace yiiunit\framework\web;
use yii\web\MultipartFormDataParser;
use yii\web\Request;
use yiiunit\TestCase;
class MultipartFormDataParserTest extends TestCase
@ -24,7 +25,14 @@ class MultipartFormDataParserTest extends TestCase
$rawBody .= "\r\n--{$boundary}\nContent-Disposition: form-data; name=\"Item[file]\"; filename=\"item-file.txt\"\nContent-Type: text/plain\r\n\r\nitem file content";
$rawBody .= "\r\n--{$boundary}--";
$bodyParams = $parser->parse($rawBody, $contentType);
$request = new Request([
'rawBody' => $rawBody,
'headers' => [
'content-type' => [$contentType]
]
]);
$bodyParams = $parser->parse($request);
$expectedBodyParams = [
'title' => 'test-title',
@ -59,7 +67,13 @@ class MultipartFormDataParserTest extends TestCase
'name' => 'value',
];
$bodyParams = $parser->parse('should not matter', 'multipart/form-data; boundary=---12345');
$request = new Request([
'rawBody' => 'should not matter',
'headers' => [
'content-type' => ['multipart/form-data; boundary=---12345']
]
]);
$bodyParams = $parser->parse($request);
$this->assertEquals($_POST, $bodyParams);
$this->assertEquals([], $_FILES);
}
@ -82,7 +96,13 @@ class MultipartFormDataParserTest extends TestCase
$contentType = 'multipart/form-data; boundary=' . $boundary;
$rawBody = "--{$boundary}\nContent-Disposition: form-data; name=\"title\"\r\ntest-title--{$boundary}--";
$bodyParams = $parser->parse($rawBody, $contentType);
$request = new Request([
'rawBody' => $rawBody,
'headers' => [
'content-type' => [$contentType]
]
]);
$bodyParams = $parser->parse($request);
$this->assertEquals([], $bodyParams);
}
@ -101,7 +121,13 @@ class MultipartFormDataParserTest extends TestCase
$rawBody .= "--{$boundary}\nContent-Disposition: form-data; name=\"thirdFile\"; filename=\"third-file.txt\"\nContent-Type: text/plain\r\n\r\nthird file content";
$rawBody .= "--{$boundary}--";
$parser->parse($rawBody, $contentType);
$request = new Request([
'rawBody' => $rawBody,
'headers' => [
'content-type' => [$contentType]
]
]);
$parser->parse($request);
$this->assertCount(2, $_FILES);
}
@ -120,7 +146,13 @@ class MultipartFormDataParserTest extends TestCase
$rawBody .= "--{$boundary}\nContent-Disposition: form-data; name=\"thirdFile\"; filename=\"third-file.txt\"\nContent-Type: text/plain\r\n\r\nthird file with too long file content";
$rawBody .= "--{$boundary}--";
$parser->parse($rawBody, $contentType);
$request = new Request([
'rawBody' => $rawBody,
'headers' => [
'content-type' => [$contentType]
]
]);
$parser->parse($request);
$this->assertCount(3, $_FILES);
$this->assertEquals(UPLOAD_ERR_INI_SIZE, $_FILES['thirdFile']['error']);
}
@ -150,7 +182,13 @@ class MultipartFormDataParserTest extends TestCase
$rawBody .= "\r\n--{$boundary}\nContent-Disposition: form-data; name=\"someFile\"; filename=\"some-file.txt\"\nContent-Type: text/plain\r\n\r\nsome file content";
$rawBody .= "\r\n--{$boundary}--";
$bodyParams = $parser->parse($rawBody, $contentType);
$request = new Request([
'rawBody' => $rawBody,
'headers' => [
'content-type' => [$contentType]
]
]);
$bodyParams = $parser->parse($request);
$expectedBodyParams = [
'title' => 'test-title',

Loading…
Cancel
Save