Merge "selenium: invoke jobs to enforce eventual consistency"
[lhc/web/wiklou.git] / includes / parser / Parser.php
index 78265e8..dc2bb0c 100644 (file)
@@ -292,8 +292,8 @@ class Parser {
                        self::EXT_LINK_URL_CLASS . '*)\p{Zs}*([^\]\\x00-\\x08\\x0a-\\x1F\\x{FFFD}]*?)\]/Su';
                if ( isset( $conf['preprocessorClass'] ) ) {
                        $this->mPreprocessorClass = $conf['preprocessorClass'];
-               } elseif ( defined( 'HPHP_VERSION' ) ) {
-                       # Preprocessor_Hash is much faster than Preprocessor_DOM under HipHop
+               } elseif ( wfIsHHVM() ) {
+                       # Under HHVM Preprocessor_Hash is much faster than Preprocessor_DOM
                        $this->mPreprocessorClass = Preprocessor_Hash::class;
                } elseif ( extension_loaded( 'domxml' ) ) {
                        # PECL extension that conflicts with the core DOM extension (T15770)
@@ -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':
@@ -5750,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 );
                }