MediaWiki  master
PageHTMLHandler.php
Go to the documentation of this file.
1 <?php
2 
3 namespace MediaWiki\Rest\Handler;
4 
5 use Config;
7 use Exception;
8 use GuzzleHttp\Psr7\Uri;
9 use LogicException;
17 use TitleFactory;
18 use TitleFormatter;
19 use UIDGenerator;
21 use WebRequest;
23 
36  private const MAX_AGE_200 = 5;
37 
39  private $restClient;
40 
42  private $htmlResponse;
43 
52  public function __construct(
58  VirtualRESTServiceClient $virtualRESTServiceClient
59  ) {
60  parent::__construct(
61  $config,
66  );
67 
68  $this->restClient = $virtualRESTServiceClient;
69  }
70 
76  private function fetchHtmlFromRESTBase( LinkTarget $title ): array {
77  if ( $this->htmlResponse !== null ) {
78  return $this->htmlResponse;
79  }
80 
81  list( , $service ) = $this->restClient->getMountAndService( '/restbase/ ' );
82  if ( !$service ) {
83  try {
84  $restConfig = $this->config->get( 'VirtualRestConfig' );
85  if ( !isset( $restConfig['modules']['restbase'] ) ) {
86  throw new ConfigException(
87  __CLASS__ . " requires restbase module configured for VirtualRestConfig"
88  );
89  }
90  $this->restClient->mount( '/restbase/',
91  new RestbaseVirtualRESTService( $restConfig['modules']['restbase'] ) );
92  } catch ( Exception $e ) {
93  // This would usually be config exception, but let's fail on any exception
94  throw new LocalizedHttpException( MessageValue::new( 'rest-html-backend-error' ), 500 );
95  }
96  }
97 
98  $this->htmlResponse = $this->restClient->run( [
99  'method' => 'GET',
100  'url' => '/restbase/local/v1/page/html/' .
101  urlencode( $this->titleFormatter->getPrefixedDBkey( $title ) ) .
102  '?redirect=false'
103  ] );
104  return $this->htmlResponse;
105  }
106 
112  private function fetch200HtmlFromRESTBase( LinkTarget $title ): array {
113  $restbaseResp = $this->fetchHtmlFromRESTBase( $title );
114  if ( $restbaseResp['code'] !== 200 ) {
115  throw new LocalizedHttpException(
116  MessageValue::new( 'rest-html-backend-error' ),
117  $restbaseResp['code']
118  );
119  }
120  return $restbaseResp;
121  }
122 
126  private function constructHtmlUrl(): string {
127  $wr = new WebRequest();
128  $urlParts = wfParseUrl( $wr->getFullRequestURL() );
129  $currentPathParts = explode( '/', $urlParts['path'] );
130  $currentPathParts[ count( $currentPathParts ) - 1 ] = 'html';
131  $urlParts['path'] = implode( '/', $currentPathParts );
132  return Uri::fromParts( $urlParts );
133  }
134 
140  public function run( string $title ): Response {
141  $titleObj = $this->getTitle();
142  if ( !$titleObj || !$titleObj->getArticleID() ) {
143  throw new LocalizedHttpException(
144  MessageValue::new( 'rest-nonexistent-title' )->plaintextParams( $title ),
145  404
146  );
147  }
148 
149  if ( !$this->isAccessible( $titleObj ) ) {
150  throw new LocalizedHttpException(
151  MessageValue::new( 'rest-permission-denied-title' )->plaintextParams( $title ),
152  403
153  );
154  }
155 
156  $revision = $this->getLatestRevision();
157  if ( !$revision ) {
158  throw new LocalizedHttpException(
159  MessageValue::new( 'rest-no-revision' )->plaintextParams( $title ),
160  404
161  );
162  }
163 
164  $htmlType = $this->getHtmlType();
165  switch ( $htmlType ) {
166  case 'bare':
167  $body = $this->constructMetadata( $titleObj, $revision );
168  $body['html_url'] = $this->constructHtmlUrl();
169  $response = $this->getResponseFactory()->createJson( $body );
170  break;
171  case 'html':
172  $restbaseResp = $this->fetch200HtmlFromRESTBase( $titleObj );
173  $response = $this->getResponseFactory()->create();
174  $response->setHeader( 'Content-Type', $restbaseResp[ 'headers' ][ 'content-type' ] );
175  $response->setBody( new StringStream( $restbaseResp[ 'body' ] ) );
176  break;
177  case 'with_html':
178  $restbaseResp = $this->fetch200HtmlFromRESTBase( $titleObj );
179  $body = $this->constructMetadata( $titleObj, $revision );
180  $body['html'] = $restbaseResp['body'];
181  $response = $this->getResponseFactory()->createJson( $body );
182  break;
183  default:
184  throw new LogicException( "Unknown HTML type $htmlType" );
185  }
186 
187  $response->setHeader( 'Cache-Control', 'max-age=' . self::MAX_AGE_200 );
188  return $response;
189  }
190 
198  protected function getETag(): ?string {
199  $title = $this->getTitle();
200  if ( !$title || !$title->getArticleID() || !$this->isAccessible( $title ) ) {
201  return null;
202  }
203  if ( $this->getHtmlType() === 'bare' ) {
204  return '"' . $this->getLatestRevision()->getId() . '"';
205  }
206 
207  $restbaseRes = $this->fetch200HtmlFromRESTBase( $title );
208  return $restbaseRes['headers']['etag'] ?? null;
209  }
210 
215  protected function getLastModified(): ?string {
216  $title = $this->getTitle();
217  if ( !$title || !$title->getArticleID() || !$this->isAccessible( $title ) ) {
218  return null;
219  }
220 
221  if ( $this->getHtmlType() === 'bare' ) {
222  return $this->getLatestRevision()->getTimestamp();
223  }
224 
225  $restbaseRes = $this->fetch200HtmlFromRESTBase( $title );
226  $restbaseEtag = $restbaseRes['headers']['etag'] ?? null;
227  if ( !$restbaseEtag ) {
228  return null;
229  }
230 
231  $etagComponents = [];
232  if ( !preg_match( '/^(?:W\/)?"?[^"\/]+(?:\/([^"\/]+))"?$/',
233  $restbaseEtag, $etagComponents )
234  ) {
235  return null;
236  }
237 
238  return UIDGenerator::getTimestampFromUUIDv1( $etagComponents[1] ) ?: null;
239  }
240 
241  private function getHtmlType(): string {
242  return $this->getConfig()['format'];
243  }
244 }
MediaWiki\Rest\Handler\LatestPageContentHandler\$permissionManager
PermissionManager $permissionManager
Definition: LatestPageContentHandler.php:23
MediaWiki\Rest\Handler
Definition: AbstractContributionHandler.php:3
MediaWiki\Rest\Handler\LatestPageContentHandler\$titleFactory
TitleFactory $titleFactory
Definition: LatestPageContentHandler.php:41
MediaWiki\Rest\Handler\getResponseFactory
getResponseFactory()
Get the ResponseFactory which can be used to generate Response objects.
Definition: Handler.php:151
MediaWiki\Rest\StringStream
A stream class which uses a string as the underlying storage.
Definition: StringStream.php:16
MediaWiki\Rest\Handler\PageHTMLHandler\getLastModified
getLastModified()
Definition: PageHTMLHandler.php:215
UIDGenerator
Class for getting statistically unique IDs.
Definition: UIDGenerator.php:31
Revision\RevisionLookup
Service for looking up page revisions.
Definition: RevisionLookup.php:38
Wikimedia\Message\MessageValue
Value object representing a message for i18n.
Definition: MessageValue.php:16
MediaWiki\Rest\Handler\PageHTMLHandler\MAX_AGE_200
const MAX_AGE_200
Definition: PageHTMLHandler.php:36
MediaWiki\Rest\Handler\LatestPageContentHandler\$revisionLookup
RevisionLookup $revisionLookup
Definition: LatestPageContentHandler.php:26
MediaWiki\Rest\Handler\PageHTMLHandler\getETag
getETag()
Returns an ETag representing a page's source.
Definition: PageHTMLHandler.php:198
Config
Interface for configuration instances.
Definition: Config.php:30
MediaWiki\Rest\Handler\LatestPageContentHandler
Definition: LatestPageContentHandler.php:17
wfParseUrl
wfParseUrl( $url)
parse_url() work-alike, but non-broken.
Definition: GlobalFunctions.php:792
MediaWiki\Rest\Handler\PageHTMLHandler\run
run(string $title)
Definition: PageHTMLHandler.php:140
VirtualRESTServiceClient
Virtual HTTP service client loosely styled after a Virtual File System.
Definition: VirtualRESTServiceClient.php:45
MediaWiki\Rest\Handler\PageHTMLHandler\getHtmlType
getHtmlType()
Definition: PageHTMLHandler.php:241
MediaWiki\Rest\Response
Definition: Response.php:8
ConfigException
Exceptions for config failures.
Definition: ConfigException.php:29
$title
$title
Definition: testCompression.php:38
MediaWiki\Rest\Handler\getConfig
getConfig()
Get the configuration array for the current route.
Definition: Handler.php:140
MediaWiki\Rest\Handler\LatestPageContentHandler\getLatestRevision
getLatestRevision()
Definition: LatestPageContentHandler.php:81
MediaWiki\Permissions\PermissionManager
A service class for checking permissions To obtain an instance, use MediaWikiServices::getInstance()-...
Definition: PermissionManager.php:49
MediaWiki\Rest\Handler\LatestPageContentHandler\constructMetadata
constructMetadata(Title $titleObject, RevisionRecord $revision)
Definition: LatestPageContentHandler.php:97
MediaWiki\Rest\Handler\LatestPageContentHandler\$titleFormatter
TitleFormatter $titleFormatter
Definition: LatestPageContentHandler.php:29
MediaWiki\Rest\Handler\LatestPageContentHandler\isAccessible
isAccessible( $titleObject)
Definition: LatestPageContentHandler.php:93
WebRequest
The WebRequest class encapsulates getting at data passed in the URL or via a POSTed form stripping il...
Definition: WebRequest.php:42
MediaWiki\Rest\Handler\PageHTMLHandler\__construct
__construct(Config $config, PermissionManager $permissionManager, RevisionLookup $revisionLookup, TitleFormatter $titleFormatter, TitleFactory $titleFactory, VirtualRESTServiceClient $virtualRESTServiceClient)
Definition: PageHTMLHandler.php:52
MediaWiki\Rest\Handler\LatestPageContentHandler\$config
Config $config
Definition: LatestPageContentHandler.php:20
TitleFormatter
A title formatter service for MediaWiki.
Definition: TitleFormatter.php:34
MediaWiki\Rest\Handler\PageHTMLHandler\fetch200HtmlFromRESTBase
fetch200HtmlFromRESTBase(LinkTarget $title)
Definition: PageHTMLHandler.php:112
TitleFactory
Creates Title objects.
Definition: TitleFactory.php:33
Wikimedia\Message\MessageValue\new
static new( $key, $params=[])
Static constructor for easier chaining of ->params() methods.
Definition: MessageValue.php:42
RestbaseVirtualRESTService
Virtual HTTP service client for RESTBase.
Definition: RestbaseVirtualRESTService.php:25
MediaWiki\Rest\Handler\PageHTMLHandler\fetchHtmlFromRESTBase
fetchHtmlFromRESTBase(LinkTarget $title)
Definition: PageHTMLHandler.php:76
MediaWiki\Rest\Handler\PageHTMLHandler\constructHtmlUrl
constructHtmlUrl()
Definition: PageHTMLHandler.php:126
MediaWiki\Rest\Handler\LatestPageContentHandler\getTitle
getTitle()
Definition: LatestPageContentHandler.php:70
MediaWiki\Linker\LinkTarget
Definition: LinkTarget.php:26
MediaWiki\Rest\Handler\PageHTMLHandler\$restClient
VirtualRESTServiceClient $restClient
Definition: PageHTMLHandler.php:39
MediaWiki\Rest\Handler\PageHTMLHandler
Definition: PageHTMLHandler.php:35
MediaWiki\Rest\LocalizedHttpException
@newable
Definition: LocalizedHttpException.php:10
MediaWiki\Rest\Handler\PageHTMLHandler\$htmlResponse
array $htmlResponse
Definition: PageHTMLHandler.php:42
UIDGenerator\getTimestampFromUUIDv1
static getTimestampFromUUIDv1(string $uuid, int $format=TS_MW)
Get timestamp in a specified format from UUIDv1.
Definition: UIDGenerator.php:111