diff --git a/includes/Rest/EntryPoint.php b/includes/Rest/EntryPoint.php index d5924f06c10..795999a55ca 100644 --- a/includes/Rest/EntryPoint.php +++ b/includes/Rest/EntryPoint.php @@ -6,8 +6,16 @@ use ExtensionRegistry; use MediaWiki\MediaWikiServices; use RequestContext; use Title; +use WebResponse; class EntryPoint { + /** @var RequestInterface */ + private $request; + /** @var WebResponse */ + private $webResponse; + /** @var Router */ + private $router; + public static function main() { // URL safety checks global $wgRequest; @@ -21,8 +29,8 @@ class EntryPoint { RequestContext::getMain()->setTitle( $wgTitle ); $services = MediaWikiServices::getInstance(); - $conf = $services->getMainConfig(); + $request = new RequestFromGlobals( [ 'cookiePrefix' => $conf->get( 'CookiePrefix' ) ] ); @@ -36,20 +44,35 @@ class EntryPoint { new ResponseFactory ); - $response = $router->execute( $request ); + $entryPoint = new self( + $request, + $wgRequest->response(), + $router ); + $entryPoint->execute(); + } - $webResponse = $wgRequest->response(); - $webResponse->header( + public function __construct( RequestInterface $request, WebResponse $webResponse, + Router $router + ) { + $this->request = $request; + $this->webResponse = $webResponse; + $this->router = $router; + } + + public function execute() { + $response = $this->router->execute( $this->request ); + + $this->webResponse->header( 'HTTP/' . $response->getProtocolVersion() . ' ' . $response->getStatusCode() . ' ' . $response->getReasonPhrase() ); foreach ( $response->getRawHeaderLines() as $line ) { - $webResponse->header( $line ); + $this->webResponse->header( $line ); } foreach ( $response->getCookies() as $cookie ) { - $webResponse->setCookie( + $this->webResponse->setCookie( $cookie['name'], $cookie['value'], $cookie['expiry'], diff --git a/tests/phpunit/includes/Rest/EntryPointTest.php b/tests/phpunit/includes/Rest/EntryPointTest.php new file mode 100644 index 00000000000..4f87a70b4fe --- /dev/null +++ b/tests/phpunit/includes/Rest/EntryPointTest.php @@ -0,0 +1,90 @@ +getMockBuilder( WebResponse::class ) + ->setMethods( [ 'header' ] ) + ->getMock(); + } + + public static function mockHandlerHeader() { + return new class extends Handler { + public function execute() { + $response = $this->getResponseFactory()->create(); + $response->setHeader( 'Foo', 'Bar' ); + return $response; + } + }; + } + + public function testHeader() { + $webResponse = $this->createWebResponse(); + $webResponse->expects( $this->any() ) + ->method( 'header' ) + ->withConsecutive( + [ 'HTTP/1.1 200 OK', true, null ], + [ 'Foo: Bar', true, null ] + ); + + $entryPoint = new EntryPoint( + new RequestData( [ 'uri' => new Uri( '/rest/mock/EntryPoint/header' ) ] ), + $webResponse, + $this->createRouter() ); + $entryPoint->execute(); + $this->assertTrue( true ); + } + + public static function mockHandlerBodyRewind() { + return new class extends Handler { + public function execute() { + $response = $this->getResponseFactory()->create(); + $stream = new Stream( fopen( 'php://memory', 'w+' ) ); + $stream->write( 'hello' ); + $response->setBody( $stream ); + return $response; + } + }; + } + + /** + * Make sure EntryPoint rewinds a seekable body stream before reading. + */ + public function testBodyRewind() { + $entryPoint = new EntryPoint( + new RequestData( [ 'uri' => new Uri( '/rest/mock/EntryPoint/bodyRewind' ) ] ), + $this->createWebResponse(), + $this->createRouter() ); + ob_start(); + $entryPoint->execute(); + $this->assertSame( 'hello', ob_get_clean() ); + } + +} diff --git a/tests/phpunit/includes/Rest/Handler/HelloHandlerTest.php b/tests/phpunit/includes/Rest/Handler/HelloHandlerTest.php index 9719f9ea67d..afbaafb7573 100644 --- a/tests/phpunit/includes/Rest/Handler/HelloHandlerTest.php +++ b/tests/phpunit/includes/Rest/Handler/HelloHandlerTest.php @@ -49,7 +49,7 @@ class HelloHandlerTest extends MediaWikiTestCase { /** @dataProvider provideTestViaRouter */ public function testViaRouter( $requestInfo, $responseInfo ) { $router = new Router( - [ __DIR__ . '/testRoutes.json' ], + [ __DIR__ . '/../testRoutes.json' ], [], '/rest', new EmptyBagOStuff(), diff --git a/tests/phpunit/includes/Rest/Handler/testRoutes.json b/tests/phpunit/includes/Rest/Handler/testRoutes.json deleted file mode 100644 index 6b440f77593..00000000000 --- a/tests/phpunit/includes/Rest/Handler/testRoutes.json +++ /dev/null @@ -1,6 +0,0 @@ -[ - { - "path": "/user/{name}/hello", - "class": "MediaWiki\\Rest\\Handler\\HelloHandler" - } -] diff --git a/tests/phpunit/includes/Rest/testRoutes.json b/tests/phpunit/includes/Rest/testRoutes.json new file mode 100644 index 00000000000..7e43bb0c5df --- /dev/null +++ b/tests/phpunit/includes/Rest/testRoutes.json @@ -0,0 +1,14 @@ +[ + { + "path": "/user/{name}/hello", + "class": "MediaWiki\\Rest\\Handler\\HelloHandler" + }, + { + "path": "/mock/EntryPoint/header", + "factory": "MediaWiki\\Tests\\Rest\\EntryPointTest::mockHandlerHeader" + }, + { + "path": "/mock/EntryPoint/bodyRewind", + "factory": "MediaWiki\\Tests\\Rest\\EntryPointTest::mockHandlerBodyRewind" + } +]