Merge "Decline to cache preprocessor items larger than 1 Mb"
authorjenkins-bot <jenkins-bot@gerrit.wikimedia.org>
Thu, 3 Sep 2015 04:52:02 +0000 (04:52 +0000)
committerGerrit Code Review <gerrit@wikimedia.org>
Thu, 3 Sep 2015 04:52:02 +0000 (04:52 +0000)
RELEASE-NOTES-1.26
includes/Setup.php
includes/cache/MessageCache.php
tests/phpunit/includes/libs/IEUrlExtensionTest.php

index 6dcf919..ddf6f7d 100644 (file)
@@ -83,6 +83,8 @@ production.
 * (T53283) load.php sometimes sends 304 response without full headers
 * (T65198) Talk page tabs now have a "rel=discussion" attribute
 * (T98841) {{msgnw:}} now preserves comments even when subst: is not used.
+* (T104142) $wgEmergencyContact and $wgPasswordSender now use their default
+  value if set to an empty string.
 
 === Action API changes in 1.26 ===
 * New-style continuation is now the default for action=continue. Clients may
index 6abef44..479ce8c 100644 (file)
@@ -522,11 +522,11 @@ unset( $serverParts );
 
 // Set defaults for configuration variables
 // that are derived from the server name by default
-if ( $wgEmergencyContact === false ) {
+// Note: $wgEmergencyContact and $wgPasswordSender may be false or empty string (T104142)
+if ( !$wgEmergencyContact ) {
        $wgEmergencyContact = 'wikiadmin@' . $wgServerName;
 }
-
-if ( $wgPasswordSender === false ) {
+if ( !$wgPasswordSender ) {
        $wgPasswordSender = 'apache@' . $wgServerName;
 }
 
index a894038..69f4c63 100644 (file)
@@ -526,26 +526,26 @@ class MessageCache {
 
                list( $msg, $code ) = $this->figureMessage( $title );
                if ( strpos( $title, '/' ) !== false && $code === $wgLanguageCode ) {
-                       # Content language overrides do not use the /<code> suffix
+                       // Content language overrides do not use the /<code> suffix
                        return;
                }
 
-               # Note that if the cache is volatile, load() may trigger a DB fetch.
-               # In that case we reenter/reuse the existing cache key lock to avoid
-               # a self-deadlock. This is safe as no reads happen *directly* in this
-               # method between getReentrantScopedLock() and load() below. There is
-               # no risk of data "changing under our feet" for replace().
+               // Note that if the cache is volatile, load() may trigger a DB fetch.
+               // In that case we reenter/reuse the existing cache key lock to avoid
+               // a self-deadlock. This is safe as no reads happen *directly* in this
+               // method between getReentrantScopedLock() and load() below. There is
+               // no risk of data "changing under our feet" for replace().
                $cacheKey = wfMemcKey( 'messages', $code );
                $scopedLock = $this->getReentrantScopedLock( $cacheKey );
                $this->load( $code, self::FOR_UPDATE );
 
                $titleKey = wfMemcKey( 'messages', 'individual', $title );
                if ( $text === false ) {
-                       # Article was deleted
+                       // Article was deleted
                        $this->mCache[$code][$title] = '!NONEXISTENT';
                        $this->wanCache->delete( $titleKey );
                } elseif ( strlen( $text ) > $wgMaxMsgCacheEntrySize ) {
-                       # Check for size
+                       // Check for size
                        $this->mCache[$code][$title] = '!TOO BIG';
                        $this->wanCache->set( $titleKey, ' ' . $text, $this->mExpiry );
                } else {
@@ -553,12 +553,17 @@ class MessageCache {
                        $this->wanCache->delete( $titleKey );
                }
 
+               // Mark this cache as definitely "latest" (non-volatile) so
+               // load() calls do try to refresh the cache with slave data
+               $this->mCache[$code]['LATEST'] = time();
+
+               // Update caches if the lock was acquired
                if ( $scopedLock ) {
-                       # Update caches
                        $this->saveToCaches( $this->mCache[$code], 'all', $code );
                }
 
                ScopedCallback::consume( $scopedLock );
+               // Relay the purge to APC and other DCs
                $this->wanCache->touchCheckKey( wfMemcKey( 'messages', $code ) );
 
                // Also delete cached sidebar... just in case it is affected
@@ -610,7 +615,7 @@ class MessageCache {
         * @param string|bool $code Language code (default: false)
         * @return bool
         */
-       protected function saveToCaches( $cache, $dest, $code = false ) {
+       protected function saveToCaches( array $cache, $dest, $code = false ) {
                if ( $dest === 'all' ) {
                        $cacheKey = wfMemcKey( 'messages', $code );
                        $success = $this->mMemc->set( $cacheKey, $cache );
@@ -618,16 +623,14 @@ class MessageCache {
                        $success = true;
                }
 
-               $this->setValidationHash( $code, $cache['HASH'] );
-
-               # Save to local cache
+               $this->setValidationHash( $code, $cache );
                $this->saveToLocalCache( $code, $cache );
 
                return $success;
        }
 
        /**
-        * Get the md5 used to validate the local disk cache
+        * Get the md5 used to validate the local APC cache
         *
         * @param string $code
         * @return array (hash or false, bool expiry/volatility status)
@@ -635,25 +638,41 @@ class MessageCache {
        protected function getValidationHash( $code ) {
                $curTTL = null;
                $value = $this->wanCache->get(
-                       wfMemcKey( 'messages', $code, 'hash' ),
+                       wfMemcKey( 'messages', $code, 'hash', 'v1' ),
                        $curTTL,
                        array( wfMemcKey( 'messages', $code ) )
                );
-               $expired = ( $curTTL === null || $curTTL < 0 );
 
-               return array( $value, $expired );
+               if ( !$value ) {
+                       // No hash found at all; cache must regenerate to be safe
+                       $expired = true;
+               } elseif ( ( time() - $value['latest'] ) < WANObjectCache::HOLDOFF_TTL ) {
+                       // Cache was recently updated via replace() and should be up-to-date
+                       $expired = false;
+               } else {
+                       // See if the "check" key was bumped after the hash was generated
+                       $expired = ( $curTTL < 0 );
+               }
+
+               return array( $value['hash'], $expired );
        }
 
        /**
         * Set the md5 used to validate the local disk cache
         *
+        * If $cache has a 'LATEST' UNIX timestamp key, then the hash will not
+        * be treated as "volatile" by getValidationHash() for the next few seconds
+        *
         * @param string $code
-        * @param string $hash
+        * @param array $cache Cached messages with a version
         */
-       protected function setValidationHash( $code, $hash ) {
+       protected function setValidationHash( $code, array $cache ) {
                $this->wanCache->set(
-                       wfMemcKey( 'messages', $code, 'hash' ),
-                       $hash,
+                       wfMemcKey( 'messages', $code, 'hash', 'v1' ),
+                       array(
+                               'hash' => $cache['HASH'],
+                               'latest' => isset( $cache['LATEST'] ) ? $cache['LATEST'] : 0
+                       ),
                        WANObjectCache::TTL_NONE
                );
        }
index e96953e..57668e5 100644 (file)
@@ -170,4 +170,37 @@ class IEUrlExtensionTest extends PHPUnit_Framework_TestCase {
                        'Two dots'
                );
        }
+
+       /**
+        * @covers IEUrlExtension::findIE6Extension
+        */
+       public function testScriptQuery() {
+               $this->assertEquals(
+                       'php',
+                       IEUrlExtension::findIE6Extension( 'example.php?foo=a&bar=b' ),
+                       'Script with query'
+               );
+       }
+
+       /**
+        * @covers IEUrlExtension::findIE6Extension
+        */
+       public function testEscapedScriptQuery() {
+               $this->assertEquals(
+                       '',
+                       IEUrlExtension::findIE6Extension( 'example%2Ephp?foo=a&bar=b' ),
+                       'Script with urlencoded dot and query'
+               );
+       }
+
+       /**
+        * @covers IEUrlExtension::findIE6Extension
+        */
+       public function testEscapedScriptQueryDot() {
+               $this->assertEquals(
+                       'y',
+                       IEUrlExtension::findIE6Extension( 'example%2Ephp?foo=a.x&bar=b.y' ),
+                       'Script with urlencoded dot and query with dot'
+               );
+       }
 }