aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--includes/Rest/Handler/Helper/PageContentHelper.php16
-rw-r--r--includes/Rest/Handler/PageHTMLHandler.php7
-rw-r--r--tests/api-testing/REST/content.v1/Page.js10
-rw-r--r--tests/phpunit/integration/includes/Rest/Handler/Helper/PageContentHelperTest.php22
-rw-r--r--tests/phpunit/integration/includes/Rest/Handler/PageHTMLHandlerTest.php37
5 files changed, 85 insertions, 7 deletions
diff --git a/includes/Rest/Handler/Helper/PageContentHelper.php b/includes/Rest/Handler/Helper/PageContentHelper.php
index b9e3d7d164ef..7437de25c70e 100644
--- a/includes/Rest/Handler/Helper/PageContentHelper.php
+++ b/includes/Rest/Handler/Helper/PageContentHelper.php
@@ -334,13 +334,27 @@ class PageContentHelper {
],
'redirect' => [
Handler::PARAM_SOURCE => 'query',
- ParamValidator::PARAM_TYPE => [ 'no' ],
+ ParamValidator::PARAM_TYPE => 'boolean',
ParamValidator::PARAM_REQUIRED => false,
+ ParamValidator::PARAM_DEFAULT => true,
]
];
}
/**
+ * Whether the handler is allowed to follow redirects, according to the
+ * request parameters.
+ *
+ * Handlers that can follow wiki redirects can use this to give clients
+ * control over the redirect handling behavior.
+ *
+ * @return bool
+ */
+ public function getRedirectsAllowed(): bool {
+ return $this->parameters['redirect'] ?? true;
+ }
+
+ /**
* Sets the 'Cache-Control' header no more then provided $expiry.
* @param ResponseInterface $response
* @param int|null $expiry
diff --git a/includes/Rest/Handler/PageHTMLHandler.php b/includes/Rest/Handler/PageHTMLHandler.php
index 1e3ad4541634..bed9d9a1504b 100644
--- a/includes/Rest/Handler/PageHTMLHandler.php
+++ b/includes/Rest/Handler/PageHTMLHandler.php
@@ -77,13 +77,8 @@ class PageHTMLHandler extends SimpleHandler {
public function run(): Response {
$this->contentHelper->checkAccessPermission();
$page = $this->contentHelper->getPageIdentity();
- $params = $this->getRequest()->getQueryParams();
- if ( array_key_exists( 'redirect', $params ) ) {
- $followWikiRedirects = $params['redirect'] !== 'no';
- } else {
- $followWikiRedirects = true;
- }
+ $followWikiRedirects = $this->contentHelper->getRedirectsAllowed();
// The call to $this->contentHelper->getPage() should not return null if
// $this->contentHelper->checkAccess() did not throw.
diff --git a/tests/api-testing/REST/content.v1/Page.js b/tests/api-testing/REST/content.v1/Page.js
index 49a103fff2f0..58b82ab9304d 100644
--- a/tests/api-testing/REST/content.v1/Page.js
+++ b/tests/api-testing/REST/content.v1/Page.js
@@ -251,6 +251,16 @@ describe( 'Page Source', () => {
assert.match( headers[ 'content-type' ], /^text\/html/ );
} );
+ it( 'Bypass wiki redirects with query param redirect=false', async () => {
+ const redirectPageDbkey = utils.dbkey( redirectPage );
+ const { status, text, headers } = await client.get(
+ `/page/${ redirectPageDbkey }/html`,
+ { redirect: 'false' }
+ );
+ assert.deepEqual( status, 200, text );
+ assert.match( headers[ 'content-type' ], /^text\/html/ );
+ } );
+
it( 'Bypass variant redirects with query param redirect=no', async () => {
const agepayDbkey = utils.dbkey( agepay );
const { status, headers } = await client.get(
diff --git a/tests/phpunit/integration/includes/Rest/Handler/Helper/PageContentHelperTest.php b/tests/phpunit/integration/includes/Rest/Handler/Helper/PageContentHelperTest.php
index 2f095a95ba08..e840e72dadcb 100644
--- a/tests/phpunit/integration/includes/Rest/Handler/Helper/PageContentHelperTest.php
+++ b/tests/phpunit/integration/includes/Rest/Handler/Helper/PageContentHelperTest.php
@@ -296,6 +296,28 @@ class PageContentHelperTest extends MediaWikiIntegrationTestCase {
$helper->checkAccess();
}
+ public static function provideRedirectsAllowed() {
+ yield [ [], true ];
+ yield [ [ 'redirect' => true ], true ];
+ yield [ [ 'redirect' => false ], false ];
+ }
+
+ /**
+ * @dataProvider provideRedirectsAllowed
+ */
+ public function testRedirectsAllowed( array $params, bool $allowRedirect ) {
+ $page = $this->getNonexistingTestPage(
+ Title::makeTitle( NS_MEDIAWIKI, 'Logouttext' )
+ );
+ $title = $page->getTitle();
+ $helper = $this->newHelper(
+ $params + [ 'title' => $title->getPrefixedDBkey() ],
+ $this->mockAnonUltimateAuthority()
+ );
+
+ $this->assertSame( $allowRedirect, $helper->getRedirectsAllowed() );
+ }
+
public function testParameterSettings() {
$helper = $this->newHelper();
$settings = $helper->getParamSettings();
diff --git a/tests/phpunit/integration/includes/Rest/Handler/PageHTMLHandlerTest.php b/tests/phpunit/integration/includes/Rest/Handler/PageHTMLHandlerTest.php
index 4d5c20b25e60..1223778fe8c4 100644
--- a/tests/phpunit/integration/includes/Rest/Handler/PageHTMLHandlerTest.php
+++ b/tests/phpunit/integration/includes/Rest/Handler/PageHTMLHandlerTest.php
@@ -7,6 +7,7 @@ use MediaWiki\Deferred\DeferredUpdates;
use MediaWiki\Hook\ParserLogLinterDataHook;
use MediaWiki\MainConfigNames;
use MediaWiki\Rest\Handler\PageHTMLHandler;
+use MediaWiki\Rest\HttpException;
use MediaWiki\Rest\LocalizedHttpException;
use MediaWiki\Rest\RequestData;
use MediaWiki\Title\Title;
@@ -162,6 +163,42 @@ class PageHTMLHandlerTest extends MediaWikiIntegrationTestCase {
$this->assertStringContainsString( self::HTML, $htmlResponse );
}
+ public static function provideWikiRedirect() {
+ yield 'follow wiki redirects per default' => [ [], 307 ];
+ yield 'bad redirect param' => [ [ 'redirect' => 'wrong' ], 400 ];
+ yield 'redirect=no' => [ [ 'redirect' => 'no' ], 200 ];
+ yield 'redirect=false' => [ [ 'redirect' => 'false' ], 200 ];
+ yield 'redirect=true' => [ [ 'redirect' => 'true' ], 307 ];
+ }
+
+ /**
+ * @dataProvider provideWikiRedirect
+ */
+ public function testWikiRedirect( $params, $expectedStatus ) {
+ $redirect = $this->getExistingTestPage( 'HtmlEndpointTestPage/redirect' );
+ $page = $this->getExistingTestPage( 'HtmlEndpointTestPage/target' );
+
+ $this->editPage( $redirect, "#REDIRECT [[{$page->getTitle()->getPrefixedDBkey()}]]" );
+
+ $request = new RequestData(
+ [
+ 'pathParams' => [ 'title' => $redirect->getTitle()->getPrefixedText() ],
+ 'queryParams' => $params
+ ]
+ );
+
+ try {
+ $handler = $this->newHandler();
+ $response = $this->executeHandler( $handler, $request, [
+ 'format' => 'html'
+ ] );
+
+ $this->assertSame( $expectedStatus, $response->getStatusCode() );
+ } catch ( HttpException $ex ) {
+ $this->assertSame( $expectedStatus, $ex->getCode() );
+ }
+ }
+
public function testExecuteHtmlOnlyForSystemMessagePage() {
$title = Title::newFromText( 'MediaWiki:Logouttext/de' );
$page = $this->getNonexistingTestPage( $title );