if ( $token == '' || $token != $params['token'] ) {
$this->dieUsage( 'Incorrect watchlist token provided -- please set a correct token in Special:Preferences', 'bad_wltoken' );
}
- } elseif ( !$wgUser->isLoggedIn() ) {
- $this->dieUsage( 'You must be logged-in to have a watchlist', 'notloggedin' );
} else {
+ // User not determined by URL, so don't cache
+ $this->getMain()->setVaryCookie();
+ if ( !$wgUser->isLoggedIn() ) {
+ $this->dieUsage( 'You must be logged-in to have a watchlist', 'notloggedin' );
+ }
$user = $wgUser;
}
return $user;
public function execute() {
global $wgUser;
+ $this->getMain()->setCachePrivate();
$oldName = $wgUser->getName();
$wgUser->logout();
private $mPrinter, $mModules, $mModuleNames, $mFormats, $mFormatNames;
private $mResult, $mAction, $mShowVersions, $mEnableWrite, $mRequest;
- private $mInternalMode, $mSquidMaxage, $mModule;
+ private $mInternalMode, $mSquidMaxage, $mModule, $mVaryCookie;
private $mCacheControl = array( 'must-revalidate' => true );
$this->mSquidMaxage = - 1; // flag for executeActionWithErrorHandling()
$this->mCommit = false;
+ $this->mVaryCookie = false;
}
/**
's-maxage' => $maxage
) );
}
+
+ /**
+ * Make sure Cache-Control: private is set. Use this when the output of a request
+ * is for the current recipient only and should not be cached in any shared cache.
+ */
+ public function setCachePrivate() {
+ $this->setCacheControl( array( 'private' => true ) );
+ }
/**
* Set directives (key/value pairs) for the Cache-Control header.
public function setCacheControl( $directives ) {
$this->mCacheControl = $directives + $this->mCacheControl;
}
+
+ /**
+ * Make sure Vary: Cookie and friends are set. Use this when the output of a request
+ * may be cached for anons but may not be cached for logged-in users.
+ *
+ * WARNING: This function must be called CONSISTENTLY for a given URL. This means that a
+ * given URL must either always or never call this function; if it sometimes does and
+ * sometimes doesn't, stuff will break.
+ */
+ public function setVaryCookie() {
+ $this->mVaryCookie = true;
+ }
+
+ /**
+ * Actually output the Vary: Cookie header and its friends, if flagged with setVaryCookie().
+ * Outputs the appropriate X-Vary-Options header and Cache-Control: private if needed.
+ */
+ private function outputVaryCookieHeader() {
+ global $wgUseXVO, $wgOut;
+ if ( $this->mVaryCookie ) {
+ header( 'Vary: Cookie' );
+ if ( $wgUseXVO ) {
+ header( $wgOut->getXVO() );
+ if ( $wgOut->hasCacheVaryCookies() ) {
+ $this->setCacheControl( array( 'private' => true ) );
+ }
+ }
+ }
+ }
/**
* Create an instance of an output formatter by its name
// Error results should not be cached
$this->setCacheMaxAge( 0 );
+ $this->setCachePrivate();
$headerStr = 'MediaWiki-API-Error: ' . $errCode;
if ( $e->getCode() === 0 ) {
$this->mPrinter->safeProfileOut();
$this->printResult( true );
}
+
+ // If this wiki is private, don't cache anything ever
+ if ( in_array( 'read', User::getGroupPermissions( array( '*' ) ), true ) ) {
+ $this->setCachePrivate();
+ }
// If nobody called setCacheMaxAge(), use the (s)maxage parameters
if ( !isset( $this->mCacheControl['s-maxage'] ) ) {
}
header( "Cache-Control: $ccHeader" );
+ $this->outputVaryCookieHeader();
if ( $this->mPrinter->getIsHtml() && !$this->mPrinter->isDisabled() ) {
echo wfReportTime();
*/
protected function checkExecutePermissions( $module ) {
global $wgUser, $wgGroupPermissions;
- if ( $module->isReadMode() && !$wgGroupPermissions['*']['read'] && !$wgUser->isAllowed( 'read' ) )
+ if ( $module->isReadMode() && !in_array( 'read', User::getGroupPermissions( array( '*' ) ), true ) &&
+ !$wgUser->isAllowed( 'read' ) )
{
$this->dieUsageMsg( array( 'readrequired' ) );
}
$p_result = false;
$pcache = ParserCache::singleton();
if ( $wgEnableParserCache ) {
- $p_result = $pcache->get( $articleObj, $wgUser );
+ $p_result = $pcache->get( $articleObj, $popts );
}
if ( !$p_result ) {
$p_result = $wgParser->parse( $articleObj->getContent(), $titleObj, $popts );
if ( $params['pst'] || $params['onlypst'] ) {
$text = $wgParser->preSaveTransform( $text, $titleObj, $wgUser, $popts );
+ $this->getMain()->setVaryCookie();
}
if ( $params['onlypst'] ) {
// Build a result and bail out
* Patrols the article or provides the reason the patrol failed.
*/
public function execute() {
+ $this->getMain()->setCachePrivate();
$params = $this->extractRequestParams();
if ( !isset( $params['rcid'] ) ) {
*/
public function execute() {
global $wgUser;
+ $this->getMain()->setCachePrivate();
$params = $this->extractRequestParams();
if ( !$wgUser->isAllowed( 'purge' ) ) {
$this->dieUsageMsg( array( 'cantpurge' ) );
if ( !is_null( $params['lang'] ) && $params['lang'] != $wgLang->getCode() ) {
$oldLang = $wgLang; // Keep $wgLang for restore later
$wgLang = Language::factory( $params['lang'] );
+ } else if ( is_null( $params['lang'] ) ) {
+ // Language not determined by URL but by user preferences, so don't cache
+ $this->getMain()->setVaryCookie();
}
$prop = array_flip( (array)$params['prop'] );
'ipb_auto' => 0
) );
}
+
+ // Make sure private data (deleted blocks) isn't cached
+ $this->getMain()->setVaryCookie();
if ( !$wgUser->isAllowed( 'hideuser' ) ) {
$this->addWhereFld( 'ipb_deleted', 0 );
}
public function execute() {
global $wgUser;
+ $this->getMain()->setVaryCookie();
// Before doing anything at all, let's check permissions
if ( !$wgUser->isAllowed( 'deletedhistory' ) ) {
$this->dieUsage( 'You don\'t have permission to view deleted revision information', 'permissiondenied' );
public function execute() {
global $wgUser;
+ $this->getMain()->setVaryCookie();
// Before doing anything at all, let's check permissions
if ( !$wgUser->isAllowed( 'deletedhistory' ) ) {
$this->dieUsage( 'You don\'t have permission to view deleted file information', 'permissiondenied' );
}
if ( $this->fld_watched ) {
+ $this->getMain()->setVaryCookie();
$this->getWatchedInfo();
}
}
if ( !is_null( $this->params['token'] ) ) {
+ // Don't cache tokens
+ $this->getMain()->setCachePrivate();
+
$tokenFunctions = $this->getTokenFunctions();
$pageInfo['starttimestamp'] = wfTimestamp( TS_ISO_8601, time() );
foreach ( $this->params['token'] as $t ) {
}
/**
- * Get information about watched status and put it in $watched
+ * Get information about watched status and put it in $this->watched
*/
private function getWatchedInfo() {
global $wgUser;
// Check permissions
global $wgUser;
- if ( ( isset( $show['patrolled'] ) || isset( $show['!patrolled'] ) ) && !$wgUser->useRCPatrol() && !$wgUser->useNPPatrol() )
- {
- $this->dieUsage( 'You need the patrol right to request the patrolled flag', 'permissiondenied' );
+ if ( isset( $show['patrolled'] ) || isset( $show['!patrolled'] ) ) {
+ $this->getMain()->setVaryCookie();
+ if ( !$wgUser->useRCPatrol() && !$wgUser->useNPPatrol() ) {
+ $this->dieUsage( 'You need the patrol right to request the patrolled flag', 'permissiondenied' );
+ }
}
/* Add additional conditions to query depending upon parameters. */
}
if ( !is_null( $this->token ) ) {
+ // Don't cache tokens
+ $this->getMain()->setCachePrivate();
+
$tokenFunctions = $this->getTokenFunctions();
foreach ( $this->token as $t ) {
$val = call_user_func( $tokenFunctions[$t], $row->rc_cur_id,
}
if ( !is_null( $this->token ) ) {
+ // Don't cache tokens
+ $this->getMain()->setCachePrivate();
+
$tokenFunctions = $this->getTokenFunctions();
foreach ( $this->token as $t ) {
$val = call_user_func( $tokenFunctions[$t], $title->getArticleID(), $title, $revision );
);
}
+ // Make sure private data (deleted revisions) isn't cached
+ $this->getMain()->setVaryCookie();
if ( !$wgUser->isAllowed( 'hideuser' ) ) {
$this->addWhere( $this->getDB()->bitAnd( 'rev_deleted', Revision::DELETED_USER ) . ' = 0' );
}
$this->fld_patrolled )
{
global $wgUser;
+ // Don't cache private data
+ $this->getMain()->setVaryCookie();
if ( !$wgUser->useRCPatrol() && !$wgUser->useNPPatrol() ) {
$this->dieUsage( 'You need the patrol right to request the patrolled flag', 'permissiondenied' );
}
+
// Use a redundant join condition on both
// timestamp and ID so we can use the timestamp
// index
}
public function execute() {
+ $this->getMain()->setCachePrivate();
$params = $this->extractRequestParams();
$result = $this->getResult();
$r = array();
}
if ( !is_null( $params['token'] ) ) {
+ // Don't cache tokens
+ $this->getMain()->setCachePrivate();
+
$tokenFunctions = $this->getTokenFunctions();
foreach ( $params['token'] as $t ) {
$val = call_user_func( $tokenFunctions[$t], $user );
$this->fld_notificationtimestamp = isset( $prop['notificationtimestamp'] );
if ( $this->fld_patrol ) {
+ $this->getMain()->setVaryCookie();
if ( !$user->useRCPatrol() && !$user->useNPPatrol() ) {
$this->dieUsage( 'patrol property is not available', 'patrol' );
}
}
// Check permissions. FIXME: should this check $user instead of $wgUser?
- if ( ( isset( $show['patrolled'] ) || isset( $show['!patrolled'] ) ) && !$wgUser->useRCPatrol() && !$wgUser->useNPPatrol() )
- {
- $this->dieUsage( 'You need the patrol right to request the patrolled flag', 'permissiondenied' );
+ if ( isset( $show['patrolled'] ) || isset( $show['!patrolled'] ) ) {
+ $this->getMain()->setVaryCookie();
+ if ( !$wgUser->useRCPatrol() && !$wgUser->useNPPatrol() ) {
+ $this->dieUsage( 'You need the patrol right to request the patrolled flag', 'permissiondenied' );
+ }
}
/* Add additional conditions to query depending upon parameters. */
public function execute() {
global $wgUser;
+ $this->getMain()->setCachePrivate();
if ( !$wgUser->isLoggedIn() ) {
$this->dieUsage( 'You must be logged-in to have a watchlist', 'notloggedin' );
}