X-Git-Url: http://git.cyclocoop.org/?a=blobdiff_plain;f=includes%2Fparser%2FParser.php;h=7d5a362b3811f2d1b25623c0807e315779dcd838;hb=465954aa23cec76ca47e51a58ff342f46fbbdcab;hp=6bee1692c42ca797b40cf27ec081c6cae7de2fd2;hpb=15f6eff90c305d405fe4331c8a8dc8caa842e5b3;p=lhc%2Fweb%2Fwiklou.git diff --git a/includes/parser/Parser.php b/includes/parser/Parser.php index 6bee1692c4..7d5a362b38 100644 --- a/includes/parser/Parser.php +++ b/includes/parser/Parser.php @@ -425,12 +425,14 @@ class Parser { * Do not call this function recursively. * * @param string $text Text we want to parse + * @param-taint $text escapes_htmlnoent * @param Title $title * @param ParserOptions $options * @param bool $linestart * @param bool $clearState * @param int|null $revid Number to pass in {{REVISIONID}} * @return ParserOutput A ParserOutput + * @return-taint escaped */ public function parse( $text, Title $title, ParserOptions $options, @@ -517,7 +519,7 @@ class Parser { # with CSS (T37247) $class = $this->mOptions->getWrapOutputClass(); if ( $class !== false && !$this->mOptions->getInterfaceMessage() ) { - $text = Html::rawElement( 'div', [ 'class' => $class ], $text ); + $this->mOutput->addWrapperDivClass( $class ); } $this->mOutput->setText( $text ); @@ -671,8 +673,10 @@ class Parser { * $text are not expanded * * @param string $text Text extension wants to have parsed + * @param-taint $text escapes_htmlnoent * @param bool|PPFrame $frame The frame to use for expanding any template variables * @return string UNSAFE half-parsed HTML + * @return-taint escaped */ public function recursiveTagParse( $text, $frame = false ) { // Avoid PHP 7.1 warning from passing $this by reference @@ -697,8 +701,10 @@ class Parser { * @since 1.25 * * @param string $text Text extension wants to have parsed + * @param-taint $text escapes_htmlnoent * @param bool|PPFrame $frame The frame to use for expanding any template variables * @return string Fully parsed HTML + * @return-taint escaped */ public function recursiveTagParseFully( $text, $frame = false ) { $text = $this->recursiveTagParse( $text, $frame ); @@ -1313,6 +1319,7 @@ class Parser { * @private * * @param string $text The text to parse + * @param-taint $text escapes_html * @param bool $isMain Whether this is being called from the main parse() function * @param PPFrame|bool $frame A pre-processor frame * @@ -2692,9 +2699,19 @@ class Parser { $this->mOutput->setFlag( 'vary-revision-id' ); wfDebug( __METHOD__ . ": {{REVISIONID}} used, setting vary-revision-id...\n" ); $value = $this->mRevisionId; - if ( !$value && $this->mOptions->getSpeculativeRevIdCallback() ) { - $value = call_user_func( $this->mOptions->getSpeculativeRevIdCallback() ); - $this->mOutput->setSpeculativeRevIdUsed( $value ); + + if ( !$value ) { + $rev = $this->getRevisionObject(); + if ( $rev ) { + $value = $rev->getId(); + } + } + + if ( !$value ) { + $value = $this->mOptions->getSpeculativeRevId(); + if ( $value ) { + $this->mOutput->setSpeculativeRevIdUsed( $value ); + } } break; case 'revisionday': @@ -3783,57 +3800,68 @@ class Parser { * Transclude an interwiki link. * * @param Title $title - * @param string $action + * @param string $action Usually one of (raw, render) * * @return string */ public function interwikiTransclude( $title, $action ) { - global $wgEnableScaryTranscluding; + global $wgEnableScaryTranscluding, $wgTranscludeCacheExpiry; if ( !$wgEnableScaryTranscluding ) { return wfMessage( 'scarytranscludedisabled' )->inContentLanguage()->text(); } $url = $title->getFullURL( [ 'action' => $action ] ); - - if ( strlen( $url ) > 255 ) { + if ( strlen( $url ) > 1024 ) { return wfMessage( 'scarytranscludetoolong' )->inContentLanguage()->text(); } - return $this->fetchScaryTemplateMaybeFromCache( $url ); - } - /** - * @param string $url - * @return mixed|string - */ - public function fetchScaryTemplateMaybeFromCache( $url ) { - global $wgTranscludeCacheExpiry; - $dbr = wfGetDB( DB_REPLICA ); - $tsCond = $dbr->timestamp( time() - $wgTranscludeCacheExpiry ); - $obj = $dbr->selectRow( 'transcache', [ 'tc_time', 'tc_contents' ], - [ 'tc_url' => $url, "tc_time >= " . $dbr->addQuotes( $tsCond ) ] ); - if ( $obj ) { - return $obj->tc_contents; - } - - $req = MWHttpRequest::factory( $url, [], __METHOD__ ); - $status = $req->execute(); // Status object - if ( $status->isOK() ) { - $text = $req->getContent(); - } elseif ( $req->getStatus() != 200 ) { + $wikiId = $title->getTransWikiID(); // remote wiki ID or false + + $fname = __METHOD__; + $cache = MediaWikiServices::getInstance()->getMainWANObjectCache(); + + $data = $cache->getWithSetCallback( + $cache->makeGlobalKey( + 'interwiki-transclude', + ( $wikiId !== false ) ? $wikiId : 'external', + sha1( $url ) + ), + $wgTranscludeCacheExpiry, + function ( $oldValue, &$ttl ) use ( $url, $fname, $cache ) { + $req = MWHttpRequest::factory( $url, [], $fname ); + + $status = $req->execute(); // Status object + if ( !$status->isOK() ) { + $ttl = $cache::TTL_UNCACHEABLE; + } elseif ( $req->getResponseHeader( 'X-Database-Lagged' ) !== null ) { + $ttl = min( $cache::TTL_LAGGED, $ttl ); + } + + return [ + 'text' => $status->isOK() ? $req->getContent() : null, + 'code' => $req->getStatus() + ]; + }, + [ + 'checkKeys' => ( $wikiId !== false ) + ? [ $cache->makeGlobalKey( 'interwiki-page', $wikiId, $title->getDBkey() ) ] + : [], + 'pcGroup' => 'interwiki-transclude:5', + 'pcTTL' => $cache::TTL_PROC_LONG + ] + ); + + if ( is_string( $data['text'] ) ) { + $text = $data['text']; + } elseif ( $data['code'] != 200 ) { // Though we failed to fetch the content, this status is useless. - return wfMessage( 'scarytranscludefailed-httpstatus' ) - ->params( $url, $req->getStatus() /* HTTP status */ )->inContentLanguage()->text(); + $text = wfMessage( 'scarytranscludefailed-httpstatus' ) + ->params( $url, $data['code'] )->inContentLanguage()->text(); } else { - return wfMessage( 'scarytranscludefailed', $url )->inContentLanguage()->text(); + $text = wfMessage( 'scarytranscludefailed', $url )->inContentLanguage()->text(); } - $dbw = wfGetDB( DB_MASTER ); - $dbw->replace( 'transcache', [ 'tc_url' ], [ - 'tc_url' => $url, - 'tc_time' => $dbw->timestamp( time() ), - 'tc_contents' => $text - ] ); return $text; } @@ -5739,18 +5767,31 @@ class Parser { if ( !is_null( $this->mRevisionObject ) ) { return $this->mRevisionObject; } - if ( is_null( $this->mRevisionId ) ) { - return null; - } + // NOTE: try to get the RevisionObject even if mRevisionId is null. + // This is useful when parsing revision that has not yet been saved. + // However, if we get back a saved revision even though we are in + // preview mode, we'll have to ignore it, see below. + // NOTE: This callback may be used to inject an OLD revision that was + // already loaded, so "current" is a bit of a misnomer. We can't just + // skip it if mRevisionId is set. $rev = call_user_func( $this->mOptions->getCurrentRevisionCallback(), $this->getTitle(), $this ); - # If the parse is for a new revision, then the callback should have - # already been set to force the object and should match mRevisionId. - # If not, try to fetch by mRevisionId for sanity. - if ( $rev && $rev->getId() != $this->mRevisionId ) { + if ( $this->mRevisionId === null && $rev && $rev->getId() ) { + // We are in preview mode (mRevisionId is null), and the current revision callback + // returned an existing revision. Ignore it and return null, it's probably the page's + // current revision, which is not what we want here. Note that we do want to call the + // callback to allow the unsaved revision to be injected here, e.g. for + // self-transclusion previews. + return null; + } + + // If the parse is for a new revision, then the callback should have + // already been set to force the object and should match mRevisionId. + // If not, try to fetch by mRevisionId for sanity. + if ( $this->mRevisionId && $rev && $rev->getId() != $this->mRevisionId ) { $rev = Revision::newFromId( $this->mRevisionId ); }