Prettify MessageCache::loadFromDB()-small query
[lhc/web/wiklou.git] / includes / cache / MessageCache.php
index 4facc20..c992112 100644 (file)
@@ -23,6 +23,7 @@
 use MediaWiki\MediaWikiServices;
 use Wikimedia\ScopedCallback;
 use MediaWiki\Logger\LoggerFactory;
+use Wikimedia\Rdbms\Database;
 
 /**
  * MediaWiki message cache structure version.
@@ -191,11 +192,22 @@ class MessageCache {
                                // either.
                                $po = ParserOptions::newFromAnon();
                                $po->setEditSection( false );
+                               $po->setAllowUnsafeRawHtml( false );
+                               $po->setWrapOutputClass( false );
                                return $po;
                        }
 
                        $this->mParserOptions = new ParserOptions;
                        $this->mParserOptions->setEditSection( false );
+                       // Messages may take parameters that could come
+                       // from malicious sources. As a precaution, disable
+                       // the <html> parser tag when parsing messages.
+                       $this->mParserOptions->setAllowUnsafeRawHtml( false );
+                       // Wrapping messages in an extra <div> is probably not expected. If
+                       // they're outside the content area they probably shouldn't be
+                       // targeted by CSS that's targeting the parser output, and if
+                       // they're inside they already are from the outer div.
+                       $this->mParserOptions->setWrapOutputClass( false );
                }
 
                return $this->mParserOptions;
@@ -480,7 +492,8 @@ class MessageCache {
                } else {
                        # Effectively disallows use of '/' character in NS_MEDIAWIKI for uses
                        # other than language code.
-                       $conds[] = 'page_title NOT' . $dbr->buildLike( $dbr->anyString(), '/', $dbr->anyString() );
+                       $conds[] = 'page_title NOT' .
+                               $dbr->buildLike( $dbr->anyString(), '/', $dbr->anyString() );
                }
 
                # Conditions to fetch oversized pages to ignore them
@@ -502,15 +515,18 @@ class MessageCache {
 
                # Conditions to load the remaining pages with their contents
                $smallConds = $conds;
-               $smallConds[] = 'page_latest=rev_id';
-               $smallConds[] = 'rev_text_id=old_id';
                $smallConds[] = 'page_len <= ' . intval( $wgMaxMsgCacheEntrySize );
 
                $res = $dbr->select(
                        [ 'page', 'revision', 'text' ],
-                       [ 'page_title', 'old_text', 'old_flags' ],
+                       [ 'page_title', 'old_id', 'old_text', 'old_flags' ],
                        $smallConds,
-                       __METHOD__ . "($code)-small"
+                       __METHOD__ . "($code)-small",
+                       [],
+                       [
+                               'revision' => [ 'JOIN', 'page_latest=rev_id' ],
+                               'text' => [ 'JOIN', 'rev_text_id=old_id' ],
+                       ]
                );
 
                foreach ( $res as $row ) {
@@ -546,7 +562,7 @@ class MessageCache {
        /**
         * Updates cache as necessary when message page is changed
         *
-        * @param string $title Message cache key with initial uppercase letter.
+        * @param string $title Message cache key with initial uppercase letter
         * @param string|bool $text New contents of the page (false if deleted)
         */
        public function replace( $title, $text ) {
@@ -591,9 +607,8 @@ class MessageCache {
                                $page->loadPageData( $page::READ_LATEST );
                                $text = $this->getMessageTextFromContent( $page->getContent() );
                                // Check if an individual cache key should exist and update cache accordingly
-                               $titleKey = $this->wanCache->makeKey(
-                                       'messages-big', $this->mCache[$code]['HASH'], $title );
                                if ( is_string( $text ) && strlen( $text ) > $wgMaxMsgCacheEntrySize ) {
+                                       $titleKey = $this->bigMessageCacheKey( $this->mCache[$code]['HASH'], $title );
                                        $this->wanCache->set( $titleKey, ' ' . $text, $this->mExpiry );
                                }
                                // Mark this cache as definitely being "latest" (non-volatile) so
@@ -962,8 +977,8 @@ class MessageCache {
         * some callers require this behavior. LanguageConverter::parseCachedTable()
         * and self::get() are some examples in core.
         *
-        * @param string $title Message cache key with initial uppercase letter.
-        * @param string $code Code denoting the language to try.
+        * @param string $title Message cache key with initial uppercase letter
+        * @param string $code Code denoting the language to try
         * @return string|bool The message, or false if it does not exist or on error
         */
        public function getMsgFromNamespace( $title, $code ) {
@@ -990,8 +1005,8 @@ class MessageCache {
                        return false;
                }
 
-               // Try the individual message cache
-               $titleKey = $this->wanCache->makeKey( 'messages-big', $this->mCache[$code]['HASH'], $title );
+               // Individual message cache key
+               $titleKey = $this->bigMessageCacheKey( $this->mCache[$code]['HASH'], $title );
 
                if ( $this->mCacheVolatile[$code] ) {
                        $entry = false;
@@ -1000,6 +1015,7 @@ class MessageCache {
                                __METHOD__ . ': loading volatile key \'{titleKey}\'',
                                [ 'titleKey' => $titleKey, 'code' => $code ] );
                } else {
+                       // Try the individual message cache
                        $entry = $this->wanCache->get( $titleKey );
                }
 
@@ -1052,7 +1068,8 @@ class MessageCache {
                        $message = false; // negative caching
                }
 
-               if ( $message === false ) { // negative caching
+               if ( $message === false ) {
+                       // Negative caching in case a "too big" message is no longer available (deleted)
                        $this->mCache[$code][$title] = '!NONEXISTENT';
                        $this->wanCache->set( $titleKey, '!NONEXISTENT', $this->mExpiry, $cacheOpts );
                }
@@ -1296,4 +1313,13 @@ class MessageCache {
 
                return $msgText;
        }
+
+       /**
+        * @param string $hash Hash for this version of the entire key/value overrides map
+        * @param string $title Message cache key with initial uppercase letter
+        * @return string
+        */
+       private function bigMessageCacheKey( $hash, $title ) {
+               return $this->wanCache->makeKey( 'messages-big', $hash, $title );
+       }
 }