Revert "Move NewPP limit report HTML comments to JS variables" and followups
[lhc/web/wiklou.git] / includes / OutputPage.php
index 48e6cc4..50629ba 100644 (file)
@@ -67,13 +67,6 @@ class OutputPage extends ContextSource {
         */
        public $mBodytext = '';
 
-       /**
-        * Holds the debug lines that will be output as comments in page source if
-        * $wgDebugComments is enabled. See also $wgShowDebug.
-        * @deprecated since 1.20; use MWDebug class instead.
-        */
-       public $mDebugtext = '';
-
        /** @var string Stores contents of "<title>" tag */
        private $mHTMLtitle = '';
 
@@ -302,9 +295,6 @@ class OutputPage extends ContextSource {
         */
        private $copyrightUrl;
 
-       /** @var array Profiling data */
-       private $limitReportData = [];
-
        /**
         * Constructor for OutputPage. This should not be called directly.
         * Instead a new RequestContext should be created and it will implicitly create
@@ -1221,8 +1211,8 @@ class OutputPage extends ContextSource {
        /**
         * Add new language links
         *
-        * @param array $newLinkArray Associative array mapping language code to the page
-        *                      name
+        * @param string[] $newLinkArray Array of interwiki-prefixed (non DB key) titles
+        *                               (e.g. 'fr:Test page')
         */
        public function addLanguageLinks( array $newLinkArray ) {
                $this->mLanguageLinks += $newLinkArray;
@@ -1231,8 +1221,8 @@ class OutputPage extends ContextSource {
        /**
         * Reset the language links and add new language links
         *
-        * @param array $newLinkArray Associative array mapping language code to the page
-        *                      name
+        * @param string[] $newLinkArray Array of interwiki-prefixed (non DB key) titles
+        *                               (e.g. 'fr:Test page')
         */
        public function setLanguageLinks( array $newLinkArray ) {
                $this->mLanguageLinks = $newLinkArray;
@@ -1241,7 +1231,7 @@ class OutputPage extends ContextSource {
        /**
         * Get the list of language links
         *
-        * @return array Array of Interwiki Prefixed (non DB key) Titles (e.g. 'fr:Test page')
+        * @return string[] Array of interwiki-prefixed (non DB key) titles (e.g. 'fr:Test page')
         */
        public function getLanguageLinks() {
                return $this->mLanguageLinks;
@@ -1265,7 +1255,7 @@ class OutputPage extends ContextSource {
                $lb->setArray( $arr );
 
                # Fetch existence plus the hiddencat property
-               $dbr = wfGetDB( DB_SLAVE );
+               $dbr = wfGetDB( DB_REPLICA );
                $fields = array_merge(
                        LinkCache::getSelectFields(),
                        [ 'page_namespace', 'page_title', 'pp_value' ]
@@ -1720,7 +1710,6 @@ class OutputPage extends ContextSource {
                $popts->setTidy( $oldTidy );
 
                $this->addParserOutput( $parserOutput );
-
        }
 
        /**
@@ -1783,14 +1772,11 @@ class OutputPage extends ContextSource {
                        }
                }
 
-               // Enable OOUI if requested via ParserOutput
+               // enable OOUI if requested via ParserOutput
                if ( $parserOutput->getEnableOOUI() ) {
                        $this->enableOOUI();
                }
 
-               // Include profiling data
-               $this->setLimitReportData( $parserOutput->getLimitReportData() );
-
                // Link flags are ignored for now, but may in the future be
                // used to mark individual language links.
                $linkFlags = [];
@@ -2203,22 +2189,26 @@ class OutputPage extends ContextSource {
                                        # We'll purge the proxy cache explicitly, but require end user agents
                                        # to revalidate against the proxy on each visit.
                                        # Surrogate-Control controls our CDN, Cache-Control downstream caches
-                                       wfDebug( __METHOD__ . ": proxy caching with ESI; {$this->mLastModified} **", 'private' );
+                                       wfDebug( __METHOD__ .
+                                               ": proxy caching with ESI; {$this->mLastModified} **", 'private' );
                                        # start with a shorter timeout for initial testing
                                        # header( 'Surrogate-Control: max-age=2678400+2678400, content="ESI/1.0"');
-                                       $response->header( 'Surrogate-Control: max-age=' . $config->get( 'SquidMaxage' )
-                                               . '+' . $this->mCdnMaxage . ', content="ESI/1.0"' );
+                                       $response->header(
+                                               "Surrogate-Control: max-age={$config->get( 'SquidMaxage' )}" .
+                                               "+{$this->mCdnMaxage}, content=\"ESI/1.0\""
+                                       );
                                        $response->header( 'Cache-Control: s-maxage=0, must-revalidate, max-age=0' );
                                } else {
                                        # We'll purge the proxy cache for anons explicitly, but require end user agents
                                        # to revalidate against the proxy on each visit.
                                        # IMPORTANT! The CDN needs to replace the Cache-Control header with
                                        # Cache-Control: s-maxage=0, must-revalidate, max-age=0
-                                       wfDebug( __METHOD__ . ": local proxy caching; {$this->mLastModified} **", 'private' );
+                                       wfDebug( __METHOD__ .
+                                               ": local proxy caching; {$this->mLastModified} **", 'private' );
                                        # start with a shorter timeout for initial testing
                                        # header( "Cache-Control: s-maxage=2678400, must-revalidate, max-age=0" );
-                                       $response->header( 'Cache-Control: s-maxage=' . $this->mCdnMaxage
-                                               . ', must-revalidate, max-age=0' );
+                                       $response->header( "Cache-Control: " .
+                                               "s-maxage={$this->mCdnMaxage}, must-revalidate, max-age=0" );
                                }
                        } else {
                                # We do want clients to cache if they can, but they *must* check for updates
@@ -2244,10 +2234,18 @@ class OutputPage extends ContextSource {
        /**
         * Finally, all the text has been munged and accumulated into
         * the object, let's actually output it:
+        *
+        * @param bool $return Set to true to get the result as a string rather than sending it
+        * @return string|null
+        * @throws Exception
+        * @throws FatalError
+        * @throws MWException
         */
-       public function output() {
+       public function output( $return = false ) {
+               global $wgContLang;
+
                if ( $this->mDoNothing ) {
-                       return;
+                       return $return ? '' : null;
                }
 
                $response = $this->getRequest()->response();
@@ -2283,7 +2281,7 @@ class OutputPage extends ContextSource {
                                }
                        }
 
-                       return;
+                       return $return ? '' : null;
                } elseif ( $this->mStatusCode ) {
                        $response->statusHeader( $this->mStatusCode );
                }
@@ -2292,7 +2290,7 @@ class OutputPage extends ContextSource {
                ob_start();
 
                $response->header( 'Content-type: ' . $config->get( 'MimeType' ) . '; charset=UTF-8' );
-               $response->header( 'Content-language: ' . $config->get( 'LanguageCode' ) );
+               $response->header( 'Content-language: ' . $wgContLang->getHtmlCode() );
 
                // Avoid Internet Explorer "compatibility view" in IE 8-10, so that
                // jQuery etc. can work correctly.
@@ -2333,7 +2331,6 @@ class OutputPage extends ContextSource {
                        // Hook that allows last minute changes to the output page, e.g.
                        // adding of CSS or Javascript by extensions.
                        Hooks::run( 'BeforePageDisplay', [ &$this, &$sk ] );
-                       $this->getSkin()->setupSkinUserCss( $this );
 
                        try {
                                $sk->outputPage();
@@ -2353,8 +2350,12 @@ class OutputPage extends ContextSource {
 
                $this->sendCacheControl();
 
-               ob_end_flush();
-
+               if ( $return ) {
+                       return ob_get_clean();
+               } else {
+                       ob_end_flush();
+                       return null;
+               }
        }
 
        /**
@@ -2384,7 +2385,7 @@ class OutputPage extends ContextSource {
         * Output a standard error page
         *
         * showErrorPage( 'titlemsg', 'pagetextmsg' );
-        * showErrorPage( 'titlemsg', 'pagetextmsg', array( 'param1', 'param2' ) );
+        * showErrorPage( 'titlemsg', 'pagetextmsg', [ 'param1', 'param2' ] );
         * showErrorPage( 'titlemsg', $messageObject );
         * showErrorPage( $titleMessageObject, $messageObject );
         *
@@ -2416,10 +2417,14 @@ class OutputPage extends ContextSource {
        /**
         * Output a standard permission error page
         *
-        * @param array $errors Error message keys
+        * @param array $errors Error message keys or [key, param...] arrays
         * @param string $action Action that was denied or null if unknown
         */
        public function showPermissionsErrorPage( array $errors, $action = null ) {
+               foreach ( $errors as $key => $error ) {
+                       $errors[$key] = (array)$error;
+               }
+
                // For some action (read, edit, create and upload), display a "login to do this action"
                // error if all of the following conditions are met:
                // 1. the user is not logged in
@@ -2566,7 +2571,7 @@ class OutputPage extends ContextSource {
        }
 
        /**
-        * Show a warning about slave lag
+        * Show a warning about replica DB lag
         *
         * If the lag is higher than $wgSlaveLagCritical seconds,
         * then the warning is a bit more obvious. If the lag is
@@ -2577,6 +2582,7 @@ class OutputPage extends ContextSource {
        public function showLagWarning( $lag ) {
                $config = $this->getConfig();
                if ( $lag >= $config->get( 'SlaveLagWarning' ) ) {
+                       $lag = floor( $lag ); // floor to avoid nano seconds to display
                        $message = $lag < $config->get( 'SlaveLagCritical' )
                                ? 'lag-warn-normal'
                                : 'lag-warn-high';
@@ -2704,26 +2710,32 @@ class OutputPage extends ContextSource {
                                'user.styles',
                                'user.cssprefs',
                        ] );
+                       $this->getSkin()->setupSkinUserCss( $this );
 
                        // Prepare exempt modules for buildExemptModules()
                        $exemptGroups = [ 'site' => [], 'noscript' => [], 'private' => [], 'user' => [] ];
                        $exemptStates = [];
-                       $moduleStyles = array_filter( $this->getModuleStyles( /*filter*/ true ),
+                       $moduleStyles = $this->getModuleStyles( /*filter*/ true );
+
+                       // Preload getTitleInfo for isKnownEmpty calls below and in ResourceLoaderClientHtml
+                       // Separate user-specific batch for improved cache-hit ratio.
+                       $userBatch = [ 'user.styles', 'user' ];
+                       $siteBatch = array_diff( $moduleStyles, $userBatch );
+                       $dbr = wfGetDB( DB_REPLICA );
+                       ResourceLoaderWikiModule::preloadTitleInfo( $context, $dbr, $siteBatch );
+                       ResourceLoaderWikiModule::preloadTitleInfo( $context, $dbr, $userBatch );
+
+                       // Filter out modules handled by buildExemptModules()
+                       $moduleStyles = array_filter( $moduleStyles,
                                function ( $name ) use ( $rl, $context, &$exemptGroups, &$exemptStates ) {
                                        $module = $rl->getModule( $name );
                                        if ( $module ) {
-                                               $group = $module->getGroup();
                                                if ( $name === 'user.styles' && $this->isUserCssPreview() ) {
                                                        $exemptStates[$name] = 'ready';
                                                        // Special case in buildExemptModules()
                                                        return false;
                                                }
-                                               if ( $name === 'site.styles' ) {
-                                                       // HACK: Technically, 'site.styles' isn't in a separate request group.
-                                                       // But, in order to ensure its styles are in the right position,
-                                                       // pretend it's in a group called 'site'.
-                                                       $group = 'site';
-                                               }
+                                               $group = $module->getGroup();
                                                if ( isset( $exemptGroups[$group] ) ) {
                                                        $exemptStates[$name] = 'ready';
                                                        if ( !$module->isKnownEmpty( $context ) ) {
@@ -2738,12 +2750,17 @@ class OutputPage extends ContextSource {
                        );
                        $this->rlExemptStyleModules = $exemptGroups;
 
-                       // Manually handled by getBottomScripts()
-                       $userModule = $rl->getModule( 'user' );
-                       $userState = $userModule->isKnownEmpty( $context ) && !$this->isUserJsPreview()
-                               ? 'ready'
-                               : 'loading';
-                       $this->rlUserModuleState = $exemptStates['user'] = $userState;
+                       $isUserModuleFiltered = !$this->filterModules( [ 'user' ] );
+                       // If this page filters out 'user', makeResourceLoaderLink will drop it.
+                       // Avoid indefinite "loading" state or untrue "ready" state (T145368).
+                       if ( !$isUserModuleFiltered ) {
+                               // Manually handled by getBottomScripts()
+                               $userModule = $rl->getModule( 'user' );
+                               $userState = $userModule->isKnownEmpty( $context ) && !$this->isUserJsPreview()
+                                       ? 'ready'
+                                       : 'loading';
+                               $this->rlUserModuleState = $exemptStates['user'] = $userState;
+                       }
 
                        $rlClient = new ResourceLoaderClientHtml( $context, $this->getTarget() );
                        $rlClient->setConfig( $this->getJSVars() );
@@ -2785,8 +2802,8 @@ class OutputPage extends ContextSource {
                        // The spec recommends defining XHTML5's charset using the XML declaration
                        // instead of meta.
                        // Our XML declaration is output by Html::htmlHeader.
-                       // http://www.whatwg.org/html/semantics.html#attr-meta-http-equiv-content-type
-                       // http://www.whatwg.org/html/semantics.html#charset
+                       // https://html.spec.whatwg.org/multipage/semantics.html#attr-meta-http-equiv-content-type
+                       // https://html.spec.whatwg.org/multipage/semantics.html#charset
                        $pieces[] = Html::element( 'meta', [ 'charset' => 'UTF-8' ] );
                }
 
@@ -2941,13 +2958,6 @@ class OutputPage extends ContextSource {
                        }
                }
 
-               $chunks[] = ResourceLoader::makeInlineScript(
-                       ResourceLoader::makeConfigSetScript(
-                               [ 'wgPageParseReport' => $this->limitReportData ],
-                               true
-                       )
-               );
-
                return self::combineWrappedStrings( $chunks );
        }
 
@@ -3064,8 +3074,8 @@ class OutputPage extends ContextSource {
                if ( $user->isLoggedIn() ) {
                        $vars['wgUserId'] = $user->getId();
                        $vars['wgUserEditCount'] = $user->getEditCount();
-                       $userReg = wfTimestampOrNull( TS_UNIX, $user->getRegistration() );
-                       $vars['wgUserRegistration'] = $userReg !== null ? ( $userReg * 1000 ) : null;
+                       $userReg = $user->getRegistration();
+                       $vars['wgUserRegistration'] = $userReg ? wfTimestamp( TS_UNIX, $userReg ) * 1000 : null;
                        // Get the revision ID of the oldest new message on the user's talk
                        // page. This can be used for constructing new message alerts on
                        // the client side.
@@ -3668,7 +3678,7 @@ class OutputPage extends ContextSource {
        public static function transformCssMedia( $media ) {
                global $wgRequest;
 
-               // http://www.w3.org/TR/css3-mediaqueries/#syntax
+               // https://www.w3.org/TR/css3-mediaqueries/#syntax
                $screenMediaQueryRegex = '/^(?:only\s+)?screen\b/i';
 
                // Switch in on-screen display for media testing
@@ -3849,12 +3859,4 @@ class OutputPage extends ContextSource {
                        'mediawiki.widgets.styles',
                ] );
        }
-
-       /**
-        * @param array $data Data from ParserOutput::getLimitReportData()
-        * @since 1.28
-        */
-       public function setLimitReportData( array $data ) {
-               $this->limitReportData = $data;
-       }
 }