diff --git a/composer.json b/composer.json index 735fb8e403e..89e0409c946 100644 --- a/composer.json +++ b/composer.json @@ -36,6 +36,7 @@ "php": ">=7.2.22", "psr/container": "1.0.0", "psr/log": "1.1.3", + "ralouphie/getallheaders": "3.0.3", "wikimedia/assert": "0.5.0", "wikimedia/at-ease": "2.0.0", "wikimedia/base-convert": "2.0.1", diff --git a/includes/Rest/RequestFromGlobals.php b/includes/Rest/RequestFromGlobals.php index e98db12c524..5d2f69484ec 100644 --- a/includes/Rest/RequestFromGlobals.php +++ b/includes/Rest/RequestFromGlobals.php @@ -54,22 +54,7 @@ class RequestFromGlobals extends RequestBase { } protected function initHeaders() { - if ( function_exists( 'apache_request_headers' ) ) { - $this->setHeaders( apache_request_headers() ); - } else { - $headers = []; - foreach ( $_SERVER as $name => $value ) { - if ( substr( $name, 0, 5 ) === 'HTTP_' ) { - $name = strtolower( str_replace( '_', '-', substr( $name, 5 ) ) ); - $headers[$name] = $value; - } elseif ( $name === 'CONTENT_LENGTH' ) { - $headers['content-length'] = $value; - } elseif ( $name === 'CONTENT_TYPE' ) { - $headers['content-type'] = $value; - } - } - $this->setHeaders( $headers ); - } + $this->setHeaders( getallheaders() ); } public function getBody() { diff --git a/includes/WebRequest.php b/includes/WebRequest.php index ecf355509ea..066b2239393 100644 --- a/includes/WebRequest.php +++ b/includes/WebRequest.php @@ -1089,21 +1089,7 @@ class WebRequest { return; } - $apacheHeaders = function_exists( 'apache_request_headers' ) ? apache_request_headers() : false; - if ( $apacheHeaders ) { - foreach ( $apacheHeaders as $tempName => $tempValue ) { - $this->headers[strtoupper( $tempName )] = $tempValue; - } - } else { - foreach ( $_SERVER as $name => $value ) { - if ( substr( $name, 0, 5 ) === 'HTTP_' ) { - $name = str_replace( '_', '-', substr( $name, 5 ) ); - $this->headers[$name] = $value; - } elseif ( $name === 'CONTENT_LENGTH' ) { - $this->headers['CONTENT-LENGTH'] = $value; - } - } - } + $this->headers = array_change_key_case( getallheaders(), CASE_UPPER ); } /** diff --git a/tests/phpunit/includes/Rest/RequestFromGlobalsTest.php b/tests/phpunit/includes/Rest/RequestFromGlobalsTest.php index 6be6128c51c..9a029ed5839 100644 --- a/tests/phpunit/includes/Rest/RequestFromGlobalsTest.php +++ b/tests/phpunit/includes/Rest/RequestFromGlobalsTest.php @@ -77,16 +77,26 @@ class RequestFromGlobalsTest extends MediaWikiTestCase { $this->setServerVars( [ 'HTTP_HOST' => '[::1]', 'CONTENT_LENGTH' => 6, - 'CONTENT_TYPE' => 'application/json' + 'CONTENT_TYPE' => 'application/json', + 'CONTENT_MD5' => 'rL0Y20zC+Fzt72VPzMSk2A==', ] ); $this->assertEquals( $this->reqFromGlobals->getHeaders(), [ - 'host' => [ '[::1]' ], - 'content-length' => [ 6 ], - 'content-type' => [ 'application/json' ] + 'Host' => [ '[::1]' ], + 'Content-Length' => [ 6 ], + 'Content-Type' => [ 'application/json' ], + 'Content-Md5' => [ 'rL0Y20zC+Fzt72VPzMSk2A==' ], ] ); } + public function testGetHeaderKeyIsCaseInsensitive() { + $cacheControl = 'private, must-revalidate, max-age=0'; + $this->setServerVars( [ 'HTTP_CACHE_CONTROL' => $cacheControl ] ); + + $this->assertSame( $this->reqFromGlobals->getHeader( 'Cache-Control' ), [ $cacheControl ] ); + $this->assertSame( $this->reqFromGlobals->getHeader( 'cache-control' ), [ $cacheControl ] ); + } + public function testGetBody() { $this->setServerVars( [ 'REQUEST_METHOD' => 'POST', diff --git a/tests/phpunit/includes/WebRequestTest.php b/tests/phpunit/includes/WebRequestTest.php index a0e89a18e97..50d5c25da18 100644 --- a/tests/phpunit/includes/WebRequestTest.php +++ b/tests/phpunit/includes/WebRequestTest.php @@ -644,6 +644,35 @@ class WebRequestTest extends MediaWikiTestCase { $this->assertSame( $request->getAcceptLang(), $expectedLanguages, $description ); } + /** + * @covers WebRequest::getHeader + */ + public function testGetHeaderCanYieldSpecialCgiHeaders() { + $contentType = 'application/json; charset=utf-8'; + $contentLength = '4711'; + $contentMd5 = 'rL0Y20zC+Fzt72VPzMSk2A=='; + $this->setServerVars( [ + 'HTTP_CONTENT_TYPE' => $contentType, + 'HTTP_CONTENT_LENGTH' => $contentLength, + 'HTTP_CONTENT_MD5' => $contentMd5, + ] ); + $request = new WebRequest(); + $this->assertSame( $request->getHeader( 'Content-Type' ), $contentType ); + $this->assertSame( $request->getHeader( 'Content-Length' ), $contentLength ); + $this->assertSame( $request->getHeader( 'Content-Md5' ), $contentMd5 ); + } + + /** + * @covers WebRequest::getHeader + */ + public function testGetHeaderKeyIsCaseInsensitive() { + $cacheControl = 'private, must-revalidate, max-age=0'; + $this->setServerVars( [ 'HTTP_CACHE_CONTROL' => $cacheControl ] ); + $request = new WebRequest(); + $this->assertSame( $request->getHeader( 'Cache-Control' ), $cacheControl ); + $this->assertSame( $request->getHeader( 'cache-control' ), $cacheControl ); + } + protected function setServerVars( $vars ) { // Don't remove vars which should be available in all SAPI. if ( !isset( $vars['REQUEST_TIME_FLOAT'] ) ) {