181 lines
5.1 KiB
PHP
181 lines
5.1 KiB
PHP
<?php
|
|
/**
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License along
|
|
* with this program; if not, write to the Free Software Foundation, Inc.,
|
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
* http://www.gnu.org/copyleft/gpl.html
|
|
*
|
|
* @file
|
|
*/
|
|
|
|
use MediaWiki\MediaWikiServices;
|
|
use Wikimedia\Http\HttpAcceptNegotiator;
|
|
use Wikimedia\Http\HttpAcceptParser;
|
|
|
|
/**
|
|
* Request handler implementing a data interface for mediawiki pages.
|
|
*
|
|
* @author Daniel Kinzler
|
|
* @author Amir Sarabadanai
|
|
*/
|
|
class PageDataRequestHandler {
|
|
|
|
/**
|
|
* Checks whether the request is complete, i.e. whether it contains all information needed
|
|
* to reply with page data.
|
|
*
|
|
* This does not check whether the request is valid and will actually produce a successful
|
|
* response.
|
|
*
|
|
* @param string|null $subPage
|
|
* @param WebRequest $request
|
|
*
|
|
* @return bool
|
|
*/
|
|
public function canHandleRequest( $subPage, WebRequest $request ) {
|
|
if ( $subPage === '' || $subPage === null ) {
|
|
return $request->getText( 'target' ) !== '';
|
|
}
|
|
|
|
$parts = explode( '/', $subPage, 2 );
|
|
$slot = $parts[0];
|
|
$title = $parts[1] ?? '';
|
|
return ( $slot === 'main' || $slot === '' ) && $title !== '';
|
|
}
|
|
|
|
/**
|
|
* Main method for handling requests.
|
|
*
|
|
* @param string|null $subPage
|
|
* @param WebRequest $request The request parameters. Known parameters are:
|
|
* - title: the page title
|
|
* - format: the format
|
|
* - oldid|revision: the revision ID
|
|
* @param OutputPage $output
|
|
*
|
|
* @note Instead of an output page, a WebResponse could be sufficient, but
|
|
* redirect logic is currently implemented in OutputPage.
|
|
*
|
|
* @throws HttpError
|
|
*/
|
|
public function handleRequest( $subPage, WebRequest $request, OutputPage $output ) {
|
|
// No matter what: The response is always public
|
|
$output->getRequest()->response()->header( 'Access-Control-Allow-Origin: *' );
|
|
|
|
if ( !$this->canHandleRequest( $subPage, $request ) ) {
|
|
throw new HttpError( 400, wfMessage( 'pagedata-bad-title', $subPage ) );
|
|
}
|
|
|
|
$revision = 0;
|
|
|
|
if ( $subPage !== '' ) {
|
|
$parts = explode( '/', $subPage, 2 );
|
|
$title = $parts[1] ?? '';
|
|
} else {
|
|
$title = $request->getText( 'target' );
|
|
}
|
|
|
|
$revision = $request->getInt( 'oldid', $revision );
|
|
$revision = $request->getInt( 'revision', $revision );
|
|
|
|
if ( $title === null || $title === '' ) {
|
|
// TODO: different error message?
|
|
throw new HttpError( 400, wfMessage( 'pagedata-bad-title', $title ) );
|
|
}
|
|
|
|
try {
|
|
$title = Title::newFromTextThrow( $title );
|
|
} catch ( MalformedTitleException $ex ) {
|
|
throw new HttpError( 400, wfMessage( 'pagedata-bad-title', $title ) );
|
|
}
|
|
|
|
$this->httpContentNegotiation( $request, $output, $title, $revision );
|
|
}
|
|
|
|
/**
|
|
* Applies HTTP content negotiation.
|
|
* If the negotiation is successful, this method will set the appropriate redirect
|
|
* in the OutputPage object and return. Otherwise, an HttpError is thrown.
|
|
*
|
|
* @param WebRequest $request
|
|
* @param OutputPage $output
|
|
* @param Title $title
|
|
* @param int $revision The desired revision
|
|
*
|
|
* @throws HttpError
|
|
*/
|
|
public function httpContentNegotiation(
|
|
WebRequest $request,
|
|
OutputPage $output,
|
|
Title $title,
|
|
$revision = 0
|
|
) {
|
|
$mimeTypes = MediaWikiServices::getInstance()
|
|
->getContentHandlerFactory()
|
|
->getContentHandler( $title->getContentModel() )
|
|
->getSupportedFormats();
|
|
|
|
$acceptHeader = $request->getHeader( 'Accept' );
|
|
if ( $acceptHeader !== false ) {
|
|
$parser = new HttpAcceptParser();
|
|
$accept = $parser->parseWeights( $acceptHeader );
|
|
} else {
|
|
// anything goes
|
|
$accept = [
|
|
'*' => 0.1 // just to make extra sure
|
|
];
|
|
// prefer the default
|
|
$accept[$mimeTypes[0]] = 1;
|
|
}
|
|
|
|
$negotiator = new HttpAcceptNegotiator( $mimeTypes );
|
|
$format = $negotiator->getBestSupportedKey( $accept );
|
|
|
|
if ( $format === null ) {
|
|
$format = isset( $accept['text/html'] ) ? 'text/html' : null;
|
|
}
|
|
|
|
if ( $format === null ) {
|
|
$msg = wfMessage( 'pagedata-not-acceptable', implode( ', ', $mimeTypes ) );
|
|
throw new HttpError( 406, $msg );
|
|
}
|
|
|
|
$url = $this->getDocUrl( $title, $format, $revision );
|
|
$output->redirect( $url, 303 );
|
|
}
|
|
|
|
/**
|
|
* Returns a url representing the given title.
|
|
*
|
|
* @param Title $title
|
|
* @param string|null $format The (normalized) format name, or ''
|
|
* @param int $revision
|
|
* @return string
|
|
*/
|
|
private function getDocUrl( Title $title, $format = '', $revision = 0 ) {
|
|
$params = [];
|
|
|
|
if ( $revision > 0 ) {
|
|
$params['oldid'] = $revision;
|
|
}
|
|
|
|
if ( $format === 'text/html' ) {
|
|
return $title->getFullURL( $params );
|
|
}
|
|
|
|
$params[ 'action' ] = 'raw';
|
|
|
|
return $title->getFullURL( $params );
|
|
}
|
|
|
|
}
|