Use pool counter for generating large diffs to prevent DoS.
[lhc/web/wiklou.git] / includes / diff / DifferenceEngine.php
index 44e6a24..8985d51 100644 (file)
@@ -232,7 +232,7 @@ class DifferenceEngine extends ContextSource {
                        ->params( $this->getLanguage()->listToText( $missing ) )
                        ->numParams( count( $missing ) )
                        ->parseAsBlock();
-               $out->addHtml( $msg );
+               $out->addHTML( $msg );
        }
 
        public function showDiffPage( $diffOnly = false ) {
@@ -474,7 +474,7 @@ class DifferenceEngine extends ContextSource {
                        if ( !$linkInfo ) {
                                $this->mMarkPatrolledLink = '';
                        } else {
-                               $this->mMarkPatrolledLink = ' <span class="patrollink">[' . Linker::linkKnown(
+                               $this->mMarkPatrolledLink = ' <span class="patrollink" data-mw="interface">[' . Linker::linkKnown(
                                        $this->mNewPage,
                                        $this->msg( 'markaspatrolleddiff' )->escaped(),
                                        [],
@@ -715,7 +715,7 @@ class DifferenceEngine extends ContextSource {
                }
                // Short-circuit
                if ( $this->mOldRev === false || ( $this->mOldRev && $this->mNewRev
-                       && $this->mOldRev->getID() == $this->mNewRev->getID() )
+                       && $this->mOldRev->getId() == $this->mNewRev->getId() )
                ) {
                        return '';
                }
@@ -842,14 +842,36 @@ class DifferenceEngine extends ContextSource {
         * @return bool|string
         */
        public function generateTextDiffBody( $otext, $ntext ) {
-               $time = microtime( true );
+               $diff = function() use ( $otext, $ntext ) {
+                       $time = microtime( true );
 
-               $result = $this->textDiff( $otext, $ntext );
+                       $result = $this->textDiff( $otext, $ntext );
 
-               $time = microtime( true ) - $time;
-               $this->getStats()->timing( 'diff_time', $time * 1000 );
+                       $time = intval( ( microtime( true ) - $time ) * 1000 );
+                       $this->getStats()->timing( 'diff_time', $time );
+                       // Log requests slower than 99th percentile
+                       if ( $time > 100 && $this->mOldPage && $this->mNewPage ) {
+                               wfDebugLog( 'diff',
+                                       "$time ms diff: {$this->mOldid} -> {$this->mNewid} {$this->mNewPage}" );
+                       }
+
+                       return $result;
+               };
 
-               return $result;
+               $error = function( $status ) {
+                       throw new FatalError( $status->getWikiText() );
+               };
+
+               // Use PoolCounter if the diff looks like it can be expensive
+               if ( strlen( $otext ) + strlen( $ntext ) > 20000 ) {
+                       $work = new PoolCounterWorkViaCallback( 'diff',
+                               md5( $otext ) . md5( $ntext ),
+                               [ 'doWork' => $diff, 'error' => $error ]
+                       );
+                       return $work->execute();
+               }
+
+               return $diff();
        }
 
        /**
@@ -865,8 +887,8 @@ class DifferenceEngine extends ContextSource {
                $otext = str_replace( "\r\n", "\n", $otext );
                $ntext = str_replace( "\r\n", "\n", $ntext );
 
-               if ( $wgExternalDiffEngine == 'wikidiff' ) {
-                       wfDeprecated( 'wikidiff support', '1.27' );
+               if ( $wgExternalDiffEngine == 'wikidiff' || $wgExternalDiffEngine == 'wikidiff3' ) {
+                       wfDeprecated( "\$wgExternalDiffEngine = '{$wgExternalDiffEngine}'", '1.27' );
                        $wgExternalDiffEngine = false;
                }
 
@@ -879,7 +901,7 @@ class DifferenceEngine extends ContextSource {
 
                                return $text;
                        }
-               } elseif ( $wgExternalDiffEngine != 'wikidiff3' && $wgExternalDiffEngine !== false ) {
+               } elseif ( $wgExternalDiffEngine !== false ) {
                        # Diff via the shell
                        $tmpDir = wfTempDir();
                        $tempName1 = tempnam( $tmpDir, 'diff_' );
@@ -1055,12 +1077,12 @@ class DifferenceEngine extends ContextSource {
                $title = $rev->getTitle();
 
                $header = Linker::linkKnown( $title, $header, [],
-                       [ 'oldid' => $rev->getID() ] );
+                       [ 'oldid' => $rev->getId() ] );
 
                if ( $rev->userCan( Revision::DELETED_TEXT, $user ) ) {
                        $editQuery = [ 'action' => 'edit' ];
                        if ( !$rev->isCurrent() ) {
-                               $editQuery['oldid'] = $rev->getID();
+                               $editQuery['oldid'] = $rev->getId();
                        }
 
                        $key = $title->quickUserCan( 'edit', $user ) ? 'editold' : 'viewsourceold';
@@ -1147,19 +1169,6 @@ class DifferenceEngine extends ContextSource {
                return $header . $diff . "</table>";
        }
 
-       /**
-        * Use specified text instead of loading from the database
-        * @deprecated since 1.21, use setContent() instead.
-        */
-       public function setText( $oldText, $newText ) {
-               ContentHandler::deprecated( __METHOD__, "1.21" );
-
-               $oldContent = ContentHandler::makeContent( $oldText, $this->getTitle() );
-               $newContent = ContentHandler::makeContent( $newText, $this->getTitle() );
-
-               $this->setContent( $oldContent, $newContent );
-       }
-
        /**
         * Use specified text instead of loading from the database
         * @param Content $oldContent