diff --git a/framework/CHANGELOG.md b/framework/CHANGELOG.md index bf2d841413d..5f520732307 100644 --- a/framework/CHANGELOG.md +++ b/framework/CHANGELOG.md @@ -12,6 +12,8 @@ Yii Framework 2 Change Log - Bug #20453: Fix PHPStan/Psalm types in `yii\web\View` (max-s-lab) - Enh #20461: Add PHPStan/Psalm annotations for `yii\filters\auth\AuthInterface` (max-s-lab) - Bug #20459: Fix return type in `RequestParserInterface::parse` (max-s-lab) +- Enh #20477: Added Content-Encoding(aka gzip) support to request body (lucaswitch) + - Bug #20475: Fix `Formatter` class `asScientific()` method for PHP `8.5` `sprintf` precision change (`6` to `0`) (terabytesoftw) 2.0.53 June 27, 2025 diff --git a/framework/web/Request.php b/framework/web/Request.php index 7b9645d532d..c228c5f851b 100644 --- a/framework/web/Request.php +++ b/framework/web/Request.php @@ -307,6 +307,8 @@ class Request extends \yii\base\Request * @var HeaderCollection Collection of request headers. */ private $_headers; + /** @var boolean Enable automatically inflate post requests with gzip/deflate Content-Encoding headers */ + public $gzip = false; /** @@ -562,6 +564,24 @@ public function getIsFlash() private $_rawBody; + /** + * Inflate the raw body on needed. + * @return void + */ + private function tryInflateRawBody() + { + if ($this->gzip) { + $contentEncoding = $this->headers->get('Content-Encoding', '', true); + if ($contentEncoding === 'gzip' || $contentEncoding === 'x-gzip') { + // gzip (RFC 1952) + $this->_rawBody = gzdecode($this->_rawBody); + } elseif ($contentEncoding === 'deflate') { + // raw deflate (RFC 1951) + $this->_rawBody = gzinflate($this->_rawBody); + } + } + } + /** * Returns the raw HTTP request body. * @return string the request body @@ -570,8 +590,8 @@ public function getRawBody() { if ($this->_rawBody === null) { $this->_rawBody = file_get_contents('php://input'); + $this->tryInflateRawBody(); } - return $this->_rawBody; } diff --git a/tests/framework/web/RequestTest.php b/tests/framework/web/RequestTest.php index 932392e187d..0ab27a02376 100644 --- a/tests/framework/web/RequestTest.php +++ b/tests/framework/web/RequestTest.php @@ -7,6 +7,7 @@ namespace yiiunit\framework\web; +use ReflectionClass; use yii\web\Request; use yiiunit\TestCase; @@ -564,7 +565,7 @@ public function testGetScriptUrlWithEmptyServer() $_SERVER = []; $this->expectException(\yii\base\InvalidConfigException::class); - + $request->getScriptUrl(); } @@ -1410,4 +1411,45 @@ public function testForwardedNotTrusted() $this->assertSame('10.0.0.1', $request->userIP, 'User IP fail!'); $this->assertSame('http://yiiframework.com', $request->hostInfo, 'Host info fail!'); } + + public function testGzipGetRawBody() + { + $request = new Request(['gzip' => true]); + $reflection = new ReflectionClass($request); + $tryInflateRawBody = $reflection->getMethod('tryInflateRawBody'); + $rawBody = $reflection->getProperty('_rawBody'); + $rawBody->setAccessible(true); + $tryInflateRawBody->setAccessible(true); + + $testString = 'hello!'; + // Test gzip as described in RFC 1950, Content-Encoding: gzip or x-gzip + $request->headers->add('Content-encoding','gzip'); + $rawBody->setValue($request, gzencode($testString)); + $tryInflateRawBody->invoke($request); + $this->assertSame($testString, $rawBody->getValue($request), 'Could not deflate correctly'); + $request->headers->add('Content-encoding','x-gzip'); + $rawBody->setValue($request, gzencode($testString)); + $tryInflateRawBody->invoke($request); + $this->assertSame($testString, $rawBody->getValue($request), 'Could not deflate correctly'); + + // Test deflate as described in RFC 1951, Content-Encoding: deflate + $request = new Request(['gzip' => true]); + $request->headers->add('Content-encoding','deflate'); + $rawBody->setValue($request, gzdeflate($testString)); + $tryInflateRawBody->invoke($request); + $this->assertSame($testString, $rawBody->getValue($request), 'Could not deflate correctly'); + + // Test backwards compatibility + $request = new Request(['gzip' => false]); + $request->headers->add('Content-encoding','deflate'); + $rawBody->setValue($request, gzdeflate($testString)); + $tryInflateRawBody->invoke($request); + $this->assertSame(gzdeflate($testString), $rawBody->getValue($request), 'Gzip flag not working as expected'); + + $request = new Request(); + $request->headers->add('Content-encoding','deflate'); + $rawBody->setValue($request, gzdeflate($testString)); + $tryInflateRawBody->invoke($request); + $this->assertSame(gzdeflate($testString), $rawBody->getValue($request), 'Gzip flag not working as expected'); + } }