Fix Memcached key decode
authorMatthias Mullie <git@mullie.eu>
Mon, 28 Sep 2015 07:55:28 +0000 (09:55 +0200)
committerMatthias Mullie <git@mullie.eu>
Mon, 28 Sep 2015 17:37:53 +0000 (19:37 +0200)
Flow had a key: flowdb:flow_ref:wiki:by-source:v3:Parser\'s_"broken"_+_(page)_&_grill:testwiki:1:4.7
the '+' in there was not being encoded (it only does /[\x00-\x20\x25\x7f]+/)
but coming back, it was decoded into ' '.
getMulti() shows a key=>value array or results. Since key was different,
we couldn't find what we had requested.

Bug: T110326
Change-Id: Ia92edd73d0eb7fe0d35e38e7e7af8174fb85cbcc

includes/objectcache/MemcachedBagOStuff.php
tests/phpunit/includes/objectcache/BagOStuffTest.php

index e545aa5..7d12749 100644 (file)
@@ -168,7 +168,10 @@ class MemcachedBagOStuff extends BagOStuff {
         * @return string
         */
        public function decodeKey( $key ) {
-               return urldecode( $key );
+               // matches %00-%20, %25, %7F (=decoded alternatives for those encoded in encodeKey)
+               return preg_replace_callback( '/%([0-1][0-9]|20|25|7F)/i', function ( $match ) {
+                       return urldecode( $match[0] );
+               }, $key );
        }
 
        /**
index b684006..cde7ed6 100644 (file)
@@ -139,24 +139,28 @@ class BagOStuffTest extends MediaWikiTestCase {
                $value1 = array( 'this' => 'is', 'a' => 'test' );
                $value2 = array( 'this' => 'is', 'another' => 'test' );
                $value3 = array( 'testing a key that may be encoded when sent to cache backend' );
+               $value4 = array( 'another test where chars in key will be encoded' );
 
                $key1 = wfMemcKey( 'test1' );
                $key2 = wfMemcKey( 'test2' );
                $key3 = wfMemcKey( 'will-%-encode' ); // internally, MemcachedBagOStuffs will encode to will-%25-encode
+               $key4 = wfMemcKey( 'flowdb:flow_ref:wiki:by-source:v3:Parser\'s_"broken"_+_(page)_&_grill:testwiki:1:4.7' );
 
                $this->cache->add( $key1, $value1 );
                $this->cache->add( $key2, $value2 );
                $this->cache->add( $key3, $value3 );
+               $this->cache->add( $key4, $value4 );
 
                $this->assertEquals(
-                       array( $key1 => $value1, $key2 => $value2, $key3 => $value3 ),
-                       $this->cache->getMulti( array( $key1, $key2, $key3 ) )
+                       array( $key1 => $value1, $key2 => $value2, $key3 => $value3, $key4 => $value4 ),
+                       $this->cache->getMulti( array( $key1, $key2, $key3, $key4 ) )
                );
 
                // cleanup
                $this->cache->delete( $key1 );
                $this->cache->delete( $key2 );
                $this->cache->delete( $key3 );
+               $this->cache->delete( $key4 );
        }
 
        /**