*/
use MediaWiki\Logger\LoggerFactory;
+use MediaWiki\Session\SessionManager;
use WrappedString\WrappedString;
/**
/** @var string */
private $mPageTitleActionText = '';
- /** @var array */
- private $mParseWarnings = array();
-
/** @var int Cache stuff. Looks like mEnableClientCache */
protected $mCdnMaxage = 0;
/** @var int Upper limit on mCdnMaxage */
$clientHeader = $this->getRequest()->getHeader( 'If-Modified-Since' );
if ( $clientHeader === false ) {
- wfDebug( __METHOD__ . ": client did not send If-Modified-Since header\n", 'log' );
+ wfDebug( __METHOD__ . ": client did not send If-Modified-Since header", 'private' );
return false;
}
}
wfDebug( __METHOD__ . ": client sent If-Modified-Since: " .
- wfTimestamp( TS_ISO_8601, $clientHeaderTime ) . "\n", 'log' );
+ wfTimestamp( TS_ISO_8601, $clientHeaderTime ), 'private' );
wfDebug( __METHOD__ . ": effective Last-Modified: " .
- wfTimestamp( TS_ISO_8601, $maxModified ) . "\n", 'log' );
+ wfTimestamp( TS_ISO_8601, $maxModified ), 'private' );
if ( $clientHeaderTime < $maxModified ) {
- wfDebug( __METHOD__ . ": STALE, $info\n", 'log' );
+ wfDebug( __METHOD__ . ": STALE, $info", 'private' );
return false;
}
# Not modified
# Give a 304 Not Modified response code and disable body output
- wfDebug( __METHOD__ . ": NOT MODIFIED, $info\n", 'log' );
+ wfDebug( __METHOD__ . ": NOT MODIFIED, $info", 'private' );
ini_set( 'zlib.output_compression', 0 );
$this->getRequest()->response()->statusHeader( 304 );
$this->sendCacheControl();
$this->mNewSectionLink = $parserOutput->getNewSection();
$this->mHideNewSectionLink = $parserOutput->getHideNewSection();
- $this->mParseWarnings = $parserOutput->getWarnings();
if ( !$parserOutput->isCacheable() ) {
$this->enableClientCache( false );
}
if ( $cookies === null ) {
$config = $this->getConfig();
$cookies = array_merge(
+ SessionManager::singleton()->getVaryCookies(),
array(
- $config->get( 'CookiePrefix' ) . 'Token',
- $config->get( 'CookiePrefix' ) . 'LoggedOut',
- "forceHTTPS",
- session_name()
+ 'forceHTTPS',
),
$config->get( 'CacheVaryCookies' )
);
* @return string
*/
public function getVaryHeader() {
+ foreach ( SessionManager::singleton()->getVaryHeaders() as $header => $options ) {
+ $this->addVaryHeader( $header, $options );
+ }
return 'Vary: ' . join( ', ', array_keys( $this->mVaryHeader ) );
}
}
$this->addVaryHeader( 'Cookie', $cookiesOption );
+ foreach ( SessionManager::singleton()->getVaryHeaders() as $header => $options ) {
+ $this->addVaryHeader( $header, $options );
+ }
+
$headers = array();
foreach ( $this->mVaryHeader as $header => $option ) {
$newheader = $header;
if ( $this->mEnableClientCache ) {
if (
- $config->get( 'UseSquid' ) && session_id() == '' && !$this->isPrintable() &&
- $this->mCdnMaxage != 0 && !$this->haveCacheVaryCookies()
+ $config->get( 'UseSquid' ) && !SessionManager::getGlobalSession()->isPersistent() &&
+ !$this->isPrintable() && $this->mCdnMaxage != 0 && !$this->haveCacheVaryCookies()
) {
if ( $config->get( 'UseESI' ) ) {
# 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} **\n", 'log' );
+ 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' )
# 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} **\n", 'log' );
+ 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
} else {
# We do want clients to cache if they can, but they *must* check for updates
# on revisiting the page.
- wfDebug( __METHOD__ . ": private caching; {$this->mLastModified} **\n", 'log' );
+ wfDebug( __METHOD__ . ": private caching; {$this->mLastModified} **", 'private' );
$response->header( 'Expires: ' . gmdate( 'D, d M Y H:i:s', 0 ) . ' GMT' );
$response->header( "Cache-Control: private, must-revalidate, max-age=0" );
}
$response->header( "Last-Modified: {$this->mLastModified}" );
}
} else {
- wfDebug( __METHOD__ . ": no caching **\n", 'log' );
+ wfDebug( __METHOD__ . ": no caching **", 'private' );
# In general, the absence of a last modified header should be enough to prevent
# the client from using its cache. We send a few other things just to make sure.
print $ins;
}
- /**
- * Produce a "user is blocked" page.
- * @deprecated since 1.18
- */
- function blockedPage() {
- wfDeprecated( __METHOD__, '1.18' );
- throw new UserBlockedError( $this->getUser()->mBlock );
- }
-
/**
* Prepare this object to display an error page; disable caching and
* indexing, clear the current text and redirect, set the page's title
$this->returnToMain();
}
- /**
- * Display an error page noting that a given permission bit is required.
- * @deprecated since 1.18, just throw the exception directly
- * @param string $permission Key required
- * @throws PermissionsError
- */
- public function permissionRequired( $permission ) {
- wfDeprecated( __METHOD__, '1.18' );
- throw new PermissionsError( $permission );
- }
-
/**
* Format a list of error messages
*
# Feeds
if ( $config->get( 'Feed' ) ) {
+ $feedLinks = array();
+
foreach ( $this->getSyndicationLinks() as $format => $link ) {
# Use the page name for the title. In principle, this could
# lead to issues with having the same name for different feeds
# corresponding to the same page, but we can't avoid that at
# this low a level.
- $tags[] = $this->feedLink(
+ $feedLinks[] = $this->feedLink(
$format,
$link,
# Used messages: 'page-rss-feed' and 'page-atom-feed' (for an easier grep)
if ( $config->get( 'OverrideSiteFeed' ) ) {
foreach ( $config->get( 'OverrideSiteFeed' ) as $type => $feedUrl ) {
// Note, this->feedLink escapes the url.
- $tags[] = $this->feedLink(
+ $feedLinks[] = $this->feedLink(
$type,
$feedUrl,
$this->msg( "site-{$type}-feed", $sitename )->text()
} elseif ( !$this->getTitle()->isSpecial( 'Recentchanges' ) ) {
$rctitle = SpecialPage::getTitleFor( 'Recentchanges' );
foreach ( $config->get( 'AdvertisedFeedTypes' ) as $format ) {
- $tags[] = $this->feedLink(
+ $feedLinks[] = $this->feedLink(
$format,
$rctitle->getLocalURL( array( 'feed' => $format ) ),
# For grep: 'site-rss-feed', 'site-atom-feed'
);
}
}
+
+ # Allow extensions to change the list pf feeds. This hook is primarily for changing,
+ # manipulating or removing existing feed tags. If you want to add new feeds, you should
+ # use OutputPage::addFeedLink() instead.
+ Hooks::run( 'AfterBuildFeedLinks', array( &$feedLinks ) );
+
+ $tags += $feedLinks;
}
# Canonical URL
return $link;
}
+ /**
+ * Transform path to web-accessible static resource.
+ *
+ * This is used to add a validation hash as query string.
+ * This aids various behaviors:
+ *
+ * - Put long Cache-Control max-age headers on responses for improved
+ * cache performance.
+ * - Get the correct version of a file as expected by the current page.
+ * - Instantly get the updated version of a file after deployment.
+ *
+ * Avoid using this for urls included in HTML as otherwise clients may get different
+ * versions of a resource when navigating the site depending on when the page was cached.
+ * If changes to the url propagate, this is not a problem (e.g. if the url is in
+ * an external stylesheet).
+ *
+ * @since 1.27
+ * @param Config $config
+ * @param string $path Path-absolute URL to file (from document root, must start with "/")
+ * @return string URL
+ */
+ public static function transformResourcePath( Config $config, $path ) {
+ global $IP;
+ $remotePath = $config->get( 'ResourceBasePath' );
+ if ( strpos( $path, $remotePath ) !== 0 ) {
+ // Path is outside wgResourceBasePath, ignore.
+ return $path;
+ }
+ $path = RelPath\getRelativePath( $path, $remotePath );
+ return self::transformFilePath( $remotePath, $IP, $path );
+ }
+
+ /**
+ * Utility method for transformResourceFilePath().
+ *
+ * Caller is responsible for ensuring the file exists. Emits a PHP warning otherwise.
+ *
+ * @since 1.27
+ * @param string $remotePath URL path that points to $localPath
+ * @param string $localPath File directory exposed at $remotePath
+ * @param string $file Path to target file relative to $localPath
+ * @return string URL
+ */
+ public static function transformFilePath( $remotePath, $localPath, $file ) {
+ $hash = md5_file( "$localPath/$file" );
+ if ( $hash === false ) {
+ wfLogWarning( __METHOD__ . ": Failed to hash $localPath/$file" );
+ $hash = '';
+ }
+ return "$remotePath/$file?" . substr( $hash, 0, 5 );
+ }
+
/**
* Transform "media" attribute based on request parameters
*
$this->addWikiText( $s );
}
- /**
- * Include jQuery core. Use this to avoid loading it multiple times
- * before we get a usable script loader.
- *
- * @param array $modules List of jQuery modules which should be loaded
- * @return array The list of modules which were not loaded.
- * @since 1.16
- * @deprecated since 1.17
- */
- public function includeJQuery( array $modules = array() ) {
- wfDeprecated( __METHOD__, '1.17' );
- return array();
- }
-
/**
* Enables/disables TOC, doesn't override __NOTOC__
* @param bool $flag
$this->getLanguage()->getDir()
);
$this->addModuleStyles( array(
- 'oojs-ui.styles',
+ 'oojs-ui-core.styles',
'oojs-ui.styles.icons',
'oojs-ui.styles.indicators',
'oojs-ui.styles.textures',