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 TitleFormatter;
18 use UIDGenerator;
20 use WebRequest;
22 
35  private const MAX_AGE_200 = 5;
36 
38  private $restClient;
39 
41  private $htmlResponse;
42 
50  public function __construct(
55  VirtualRESTServiceClient $virtualRESTServiceClient
56  ) {
58 
59  $this->restClient = $virtualRESTServiceClient;
60  }
61 
67  private function fetchHtmlFromRESTBase( LinkTarget $title ): array {
68  if ( $this->htmlResponse !== null ) {
69  return $this->htmlResponse;
70  }
71 
72  list( , $service ) = $this->restClient->getMountAndService( '/restbase/ ' );
73  if ( !$service ) {
74  try {
75  $restConfig = $this->config->get( 'VirtualRestConfig' );
76  if ( !isset( $restConfig['modules']['restbase'] ) ) {
77  throw new ConfigException(
78  __CLASS__ . " requires restbase module configured for VirtualRestConfig"
79  );
80  }
81  $this->restClient->mount( '/restbase/',
82  new RestbaseVirtualRESTService( $restConfig['modules']['restbase'] ) );
83  } catch ( Exception $e ) {
84  // This would usually be config exception, but let's fail on any exception
85  throw new LocalizedHttpException( MessageValue::new( 'rest-html-backend-error' ), 500 );
86  }
87  }
88 
89  $this->htmlResponse = $this->restClient->run( [
90  'method' => 'GET',
91  'url' => '/restbase/local/v1/page/html/' .
92  urlencode( $this->titleFormatter->getPrefixedDBkey( $title ) ) .
93  '?redirect=false'
94  ] );
95  return $this->htmlResponse;
96  }
97 
103  private function fetch200HtmlFromRESTBase( LinkTarget $title ): array {
104  $restbaseResp = $this->fetchHtmlFromRESTBase( $title );
105  if ( $restbaseResp['code'] !== 200 ) {
106  throw new LocalizedHttpException(
107  MessageValue::new( 'rest-html-backend-error' ),
108  $restbaseResp['code']
109  );
110  }
111  return $restbaseResp;
112  }
113 
117  private function constructHtmlUrl(): string {
118  $wr = new WebRequest();
119  $urlParts = wfParseUrl( $wr->getFullRequestURL() );
120  $currentPathParts = explode( '/', $urlParts['path'] );
121  $currentPathParts[ count( $currentPathParts ) - 1 ] = 'html';
122  $urlParts['path'] = implode( '/', $currentPathParts );
123  return Uri::fromParts( $urlParts );
124  }
125 
131  public function run( string $title ): Response {
132  $titleObj = $this->getTitle();
133  if ( !$titleObj || !$titleObj->getArticleID() ) {
134  throw new LocalizedHttpException(
135  MessageValue::new( 'rest-nonexistent-title' )->plaintextParams( $title ),
136  404
137  );
138  }
139 
140  if ( !$this->isAccessible( $titleObj ) ) {
141  throw new LocalizedHttpException(
142  MessageValue::new( 'rest-permission-denied-title' )->plaintextParams( $title ),
143  403
144  );
145  }
146 
147  $revision = $this->getLatestRevision();
148  if ( !$revision ) {
149  throw new LocalizedHttpException(
150  MessageValue::new( 'rest-no-revision' )->plaintextParams( $title ),
151  404
152  );
153  }
154 
155  $htmlType = $this->getHtmlType();
156  switch ( $htmlType ) {
157  case 'bare':
158  $body = $this->constructMetadata( $titleObj, $revision );
159  $body['html_url'] = $this->constructHtmlUrl();
160  $response = $this->getResponseFactory()->createJson( $body );
161  break;
162  case 'html':
163  $restbaseResp = $this->fetch200HtmlFromRESTBase( $titleObj );
164  $response = $this->getResponseFactory()->create();
165  $response->setHeader( 'Content-Type', $restbaseResp[ 'headers' ][ 'content-type' ] );
166  $response->setBody( new StringStream( $restbaseResp[ 'body' ] ) );
167  break;
168  case 'with_html':
169  $restbaseResp = $this->fetch200HtmlFromRESTBase( $titleObj );
170  $body = $this->constructMetadata( $titleObj, $revision );
171  $body['html'] = $restbaseResp['body'];
172  $response = $this->getResponseFactory()->createJson( $body );
173  break;
174  default:
175  throw new LogicException( "Unknown HTML type $htmlType" );
176  }
177 
178  $response->setHeader( 'Cache-Control', 'max-age=' . self::MAX_AGE_200 );
179  return $response;
180  }
181 
189  protected function getETag(): ?string {
190  $title = $this->getTitle();
191  if ( !$title || !$title->getArticleID() || !$this->isAccessible( $title ) ) {
192  return null;
193  }
194  if ( $this->getHtmlType() === 'bare' ) {
195  return '"' . $this->getLatestRevision()->getId() . '"';
196  }
197 
198  $restbaseRes = $this->fetch200HtmlFromRESTBase( $title );
199  return $restbaseRes['headers']['etag'] ?? null;
200  }
201 
206  protected function getLastModified(): ?string {
207  $title = $this->getTitle();
208  if ( !$title || !$title->getArticleID() || !$this->isAccessible( $title ) ) {
209  return null;
210  }
211 
212  if ( $this->getHtmlType() === 'bare' ) {
213  return $this->getLatestRevision()->getTimestamp();
214  }
215 
216  $restbaseRes = $this->fetch200HtmlFromRESTBase( $title );
217  $restbaseEtag = $restbaseRes['headers']['etag'] ?? null;
218  if ( !$restbaseEtag ) {
219  return null;
220  }
221 
222  $etagComponents = [];
223  if ( !preg_match( '/^(?:W\/)?"?[^"\/]+(?:\/([^"\/]+))"?$/',
224  $restbaseEtag, $etagComponents )
225  ) {
226  return null;
227  }
228 
229  return UIDGenerator::getTimestampFromUUIDv1( $etagComponents[1] ) ?: null;
230  }
231 
232  private function getHtmlType(): string {
233  return $this->getConfig()['format'];
234  }
235 }
MediaWiki\Rest\Handler\LatestPageContentHandler\$permissionManager
PermissionManager $permissionManager
Definition: LatestPageContentHandler.php:22
MediaWiki\Rest\Handler\PageHTMLHandler\__construct
__construct(Config $config, PermissionManager $permissionManager, RevisionLookup $revisionLookup, TitleFormatter $titleFormatter, VirtualRESTServiceClient $virtualRESTServiceClient)
Definition: PageHTMLHandler.php:50
MediaWiki\Rest\Handler
Definition: AbstractContributionHandler.php:3
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:206
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:35
MediaWiki\Rest\Handler\LatestPageContentHandler\$revisionLookup
RevisionLookup $revisionLookup
Definition: LatestPageContentHandler.php:25
MediaWiki\Rest\Handler\PageHTMLHandler\getETag
getETag()
Returns an ETag representing a page's source.
Definition: PageHTMLHandler.php:189
Config
Interface for configuration instances.
Definition: Config.php:30
MediaWiki\Rest\Handler\LatestPageContentHandler
Definition: LatestPageContentHandler.php:16
wfParseUrl
wfParseUrl( $url)
parse_url() work-alike, but non-broken.
Definition: GlobalFunctions.php:791
MediaWiki\Rest\Handler\PageHTMLHandler\run
run(string $title)
Definition: PageHTMLHandler.php:131
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:232
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:73
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:89
MediaWiki\Rest\Handler\LatestPageContentHandler\$titleFormatter
TitleFormatter $titleFormatter
Definition: LatestPageContentHandler.php:28
MediaWiki\Rest\Handler\LatestPageContentHandler\isAccessible
isAccessible( $titleObject)
Definition: LatestPageContentHandler.php:85
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\LatestPageContentHandler\$config
Config $config
Definition: LatestPageContentHandler.php:19
TitleFormatter
A title formatter service for MediaWiki.
Definition: TitleFormatter.php:34
MediaWiki\Rest\Handler\PageHTMLHandler\fetch200HtmlFromRESTBase
fetch200HtmlFromRESTBase(LinkTarget $title)
Definition: PageHTMLHandler.php:103
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:67
MediaWiki\Rest\Handler\PageHTMLHandler\constructHtmlUrl
constructHtmlUrl()
Definition: PageHTMLHandler.php:117
MediaWiki\Rest\Handler\LatestPageContentHandler\getTitle
getTitle()
Definition: LatestPageContentHandler.php:63
MediaWiki\Linker\LinkTarget
Definition: LinkTarget.php:26
MediaWiki\Rest\Handler\PageHTMLHandler\$restClient
VirtualRESTServiceClient $restClient
Definition: PageHTMLHandler.php:38
MediaWiki\Rest\Handler\PageHTMLHandler
Definition: PageHTMLHandler.php:34
MediaWiki\Rest\LocalizedHttpException
@newable
Definition: LocalizedHttpException.php:10
MediaWiki\Rest\Handler\PageHTMLHandler\$htmlResponse
array $htmlResponse
Definition: PageHTMLHandler.php:41
UIDGenerator\getTimestampFromUUIDv1
static getTimestampFromUUIDv1(string $uuid, int $format=TS_MW)
Get timestamp in a specified format from UUIDv1.
Definition: UIDGenerator.php:111