WikiPage: Truncate redirect fragments before inserting them into the DB
authorRoan Kattouw <roan.kattouw@gmail.com>
Thu, 25 Oct 2018 00:09:59 +0000 (17:09 -0700)
committerRoan Kattouw <roan.kattouw@gmail.com>
Thu, 25 Oct 2018 00:33:56 +0000 (17:33 -0700)
The rd_fragment field is 255 bytes wide, but there is no limit on how
long title fragments can be. We don't want to let the database silently
truncate the fragment for us, because that can result in invalid UTF-8.
Instead, truncate it before insertion in a UTF-8-aware way.

Bug: T207876
Change-Id: I12745f3f4c174eaced56d80f3661a71d0e5637e6

includes/page/WikiPage.php
tests/phpunit/includes/page/WikiPageDbTestBase.php

index 18797d9..d03d317 100644 (file)
@@ -1045,20 +1045,22 @@ class WikiPage implements Page, IDBAccessObject {
                $dbw->startAtomic( __METHOD__ );
 
                if ( !$oldLatest || $oldLatest == $this->lockAndGetLatest() ) {
+                       $contLang = MediaWikiServices::getInstance()->getContentLanguage();
+                       $truncatedFragment = $contLang->truncateForDatabase( $rt->getFragment(), 255 );
                        $dbw->upsert(
                                'redirect',
                                [
                                        'rd_from' => $this->getId(),
                                        'rd_namespace' => $rt->getNamespace(),
                                        'rd_title' => $rt->getDBkey(),
-                                       'rd_fragment' => $rt->getFragment(),
+                                       'rd_fragment' => $truncatedFragment,
                                        'rd_interwiki' => $rt->getInterwiki(),
                                ],
                                [ 'rd_from' ],
                                [
                                        'rd_namespace' => $rt->getNamespace(),
                                        'rd_title' => $rt->getDBkey(),
-                                       'rd_fragment' => $rt->getFragment(),
+                                       'rd_fragment' => $truncatedFragment,
                                        'rd_interwiki' => $rt->getInterwiki(),
                                ],
                                __METHOD__
index d9c92f5..fee4583 100644 (file)
@@ -816,6 +816,15 @@ abstract class WikiPageDbTestBase extends MediaWikiLangTestCase {
                                "#REDIRECT [[Media:hello_world]]",
                                "File:Hello world"
                        ],
+                       // Test fragments longer than 255 bytes (T207876)
+                       [
+                               'WikiPageTest_testGetRedirectTarget_4',
+                               CONTENT_MODEL_WIKITEXT,
+                               // phpcs:ignore Generic.Files.LineLength
+                               '#REDIRECT [[Foobar#🏴󠁮󠁬󠁦󠁲󠁿🏴󠁮󠁬󠁦󠁲󠁿🏴󠁮󠁬󠁦󠁲󠁿🏴󠁮󠁬󠁦󠁲󠁿🏴󠁮󠁬󠁦󠁲󠁿🏴󠁮󠁬󠁦󠁲󠁿🏴󠁮󠁬󠁦󠁲󠁿🏴󠁮󠁬󠁦󠁲󠁿🏴󠁮󠁬󠁦󠁲󠁿🏴󠁮󠁬󠁦󠁲󠁿🏴󠁮󠁬󠁦󠁲󠁿🏴󠁮󠁬󠁦󠁲󠁿🏴󠁮󠁬󠁦󠁲󠁿🏴󠁮󠁬󠁦󠁲󠁿🏴󠁮󠁬󠁦󠁲󠁿🏴󠁮󠁬󠁦󠁲󠁿🏴󠁮󠁬󠁦󠁲󠁿🏴󠁮󠁬󠁦󠁲󠁿🏴󠁮󠁬󠁦󠁲󠁿🏴󠁮󠁬󠁦󠁲󠁿🏴󠁮󠁬󠁦󠁲󠁿🏴󠁮󠁬󠁦󠁲󠁿]]',
+                               // phpcs:ignore Generic.Files.LineLength
+                               'Foobar#🏴󠁮󠁬󠁦󠁲󠁿🏴󠁮󠁬󠁦󠁲󠁿🏴󠁮󠁬󠁦󠁲󠁿🏴󠁮󠁬󠁦󠁲󠁿🏴󠁮󠁬󠁦󠁲󠁿🏴󠁮󠁬󠁦󠁲󠁿🏴󠁮󠁬󠁦󠁲󠁿🏴󠁮󠁬󠁦󠁲󠁿🏴󠁮󠁬󠁦󠁲󠁿🏴󠁮󠁬󠁦󠁲󠁿🏴󠁮󠁬...'
+                       ]
                ];
        }
 
@@ -836,7 +845,7 @@ abstract class WikiPageDbTestBase extends MediaWikiLangTestCase {
 
                # now, test the actual redirect
                $t = $page->getRedirectTarget();
-               $this->assertEquals( $target, is_null( $t ) ? null : $t->getPrefixedText() );
+               $this->assertEquals( $target, is_null( $t ) ? null : $t->getFullText() );
        }
 
        /**