r69932 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r69931‎ | r69932 | r69933 >
Date:08:03, 26 July 2010
Author:tstarling
Status:ok
Tags:
Comment:
* MFT r69776, and followups r69784, r69928, r69931, and superseded base revisions r69339, r69347, r69350, r69369, r69379: API cache header fix.
* MFT r69784, r69928: updating extensions for the above core change.
* Updated release notes. Bug number left out since I want to wait until closer to the release before I report it.
Modified paths:
  • /branches/REL1_16/extensions/CentralAuth/ApiQueryGlobalUserInfo.php (modified) (history)
  • /branches/REL1_16/extensions/FlaggedRevs/api (modified) (history)
  • /branches/REL1_16/extensions/FlaggedRevs/api/ApiFlagConfig.php (modified) (history)
  • /branches/REL1_16/extensions/FlaggedRevs/api/ApiQueryFlagged.php (modified) (history)
  • /branches/REL1_16/extensions/FlaggedRevs/api/ApiQueryOldreviewedpages.php (modified) (history)
  • /branches/REL1_16/extensions/FlaggedRevs/api/ApiQueryReviewedpages.php (modified) (history)
  • /branches/REL1_16/extensions/FlaggedRevs/api/ApiQueryUnreviewedpages.php (modified) (history)
  • /branches/REL1_16/extensions/GlobalBlocking/ApiQueryGlobalBlocks.php (modified) (history)
  • /branches/REL1_16/extensions/LiquidThreads/api/ApiQueryLQTThreads.php (modified) (history)
  • /branches/REL1_16/phase3/RELEASE-NOTES (modified) (history)
  • /branches/REL1_16/phase3/includes/api (modified) (history)
  • /branches/REL1_16/phase3/includes/api/ApiExpandTemplates.php (modified) (history)
  • /branches/REL1_16/phase3/includes/api/ApiMain.php (modified) (history)
  • /branches/REL1_16/phase3/includes/api/ApiOpenSearch.php (modified) (history)
  • /branches/REL1_16/phase3/includes/api/ApiParse.php (modified) (history)
  • /branches/REL1_16/phase3/includes/api/ApiQuery.php (modified) (history)
  • /branches/REL1_16/phase3/includes/api/ApiQueryAllCategories.php (modified) (history)
  • /branches/REL1_16/phase3/includes/api/ApiQueryAllLinks.php (modified) (history)
  • /branches/REL1_16/phase3/includes/api/ApiQueryAllUsers.php (modified) (history)
  • /branches/REL1_16/phase3/includes/api/ApiQueryAllimages.php (modified) (history)
  • /branches/REL1_16/phase3/includes/api/ApiQueryAllmessages.php (modified) (history)
  • /branches/REL1_16/phase3/includes/api/ApiQueryAllpages.php (modified) (history)
  • /branches/REL1_16/phase3/includes/api/ApiQueryBacklinks.php (modified) (history)
  • /branches/REL1_16/phase3/includes/api/ApiQueryBase.php (modified) (history)
  • /branches/REL1_16/phase3/includes/api/ApiQueryCategories.php (modified) (history)
  • /branches/REL1_16/phase3/includes/api/ApiQueryCategoryInfo.php (modified) (history)
  • /branches/REL1_16/phase3/includes/api/ApiQueryCategoryMembers.php (modified) (history)
  • /branches/REL1_16/phase3/includes/api/ApiQueryDuplicateFiles.php (modified) (history)
  • /branches/REL1_16/phase3/includes/api/ApiQueryExtLinksUsage.php (modified) (history)
  • /branches/REL1_16/phase3/includes/api/ApiQueryExternalLinks.php (modified) (history)
  • /branches/REL1_16/phase3/includes/api/ApiQueryImageInfo.php (modified) (history)
  • /branches/REL1_16/phase3/includes/api/ApiQueryImages.php (modified) (history)
  • /branches/REL1_16/phase3/includes/api/ApiQueryInfo.php (modified) (history)
  • /branches/REL1_16/phase3/includes/api/ApiQueryLangLinks.php (modified) (history)
  • /branches/REL1_16/phase3/includes/api/ApiQueryLinks.php (modified) (history)
  • /branches/REL1_16/phase3/includes/api/ApiQueryLogEvents.php (modified) (history)
  • /branches/REL1_16/phase3/includes/api/ApiQueryProtectedTitles.php (modified) (history)
  • /branches/REL1_16/phase3/includes/api/ApiQueryRandom.php (modified) (history)
  • /branches/REL1_16/phase3/includes/api/ApiQueryRecentChanges.php (modified) (history)
  • /branches/REL1_16/phase3/includes/api/ApiQueryRevisions.php (modified) (history)
  • /branches/REL1_16/phase3/includes/api/ApiQuerySearch.php (modified) (history)
  • /branches/REL1_16/phase3/includes/api/ApiQuerySiteinfo.php (modified) (history)
  • /branches/REL1_16/phase3/includes/api/ApiQueryTags.php (modified) (history)
  • /branches/REL1_16/phase3/includes/api/ApiQueryUserContributions.php (modified) (history)
  • /branches/REL1_16/phase3/includes/api/ApiQueryUsers.php (modified) (history)
  • /branches/REL1_16/phase3/includes/api/ApiQueryWatchlist.php (modified) (history)

Diff [purge]

Index: branches/REL1_16/extensions/CentralAuth/ApiQueryGlobalUserInfo.php
@@ -110,6 +110,16 @@
111111 }
112112 }
113113
 114+ public function getCacheMode( $params ) {
 115+ if ( !is_null( $params['user'] ) ) {
 116+ // URL determines user, public caching is fine
 117+ return 'public';
 118+ } else {
 119+ // Code will fall back to $wgUser, don't cache
 120+ return 'private';
 121+ }
 122+ }
 123+
114124 public function getAllowedParams() {
115125 return array(
116126 'user' => null,
Property changes on: branches/REL1_16/extensions/CentralAuth/ApiQueryGlobalUserInfo.php
___________________________________________________________________
Added: svn:mergeinfo
117127 Merged /trunk/extensions/CentralAuth/ApiQueryGlobalUserInfo.php:r62827,69784
Index: branches/REL1_16/extensions/FlaggedRevs/api/ApiFlagConfig.php
@@ -29,6 +29,7 @@
3030 class ApiFlagConfig extends ApiBase {
3131
3232 public function execute() {
 33+ $this->getMain()->setCacheMode( 'public' );
3334 global $wgFlaggedRevTags;
3435 $data = array();
3536 foreach( $wgFlaggedRevTags as $tag => $params ) {
Property changes on: branches/REL1_16/extensions/FlaggedRevs/api/ApiFlagConfig.php
___________________________________________________________________
Added: svn:mergeinfo
3637 Merged /trunk/extensions/FlaggedRevs/api/ApiFlagConfig.php:r69784,69928
Index: branches/REL1_16/extensions/FlaggedRevs/api/ApiQueryFlagged.php
@@ -59,6 +59,10 @@
6060 $db->freeResult( $res );
6161 }
6262
 63+ public function getCacheMode( $params ) {
 64+ return 'public';
 65+ }
 66+
6367 public function getAllowedParams() {
6468 return array();
6569 }
Index: branches/REL1_16/extensions/FlaggedRevs/api/ApiQueryOldreviewedpages.php
@@ -146,6 +146,15 @@
147147 }
148148 }
149149
 150+ public function getCacheMode( $params ) {
 151+ if ( $params['filterwatched'] == 'watched' ) {
 152+ // Private data
 153+ return 'private';
 154+ } else {
 155+ return 'public';
 156+ }
 157+ }
 158+
150159 public function getAllowedParams() {
151160 $namespaces = FlaggedRevs::getReviewNamespaces();
152161 return array (
Property changes on: branches/REL1_16/extensions/FlaggedRevs/api/ApiQueryOldreviewedpages.php
___________________________________________________________________
Added: svn:mergeinfo
153162 Merged /trunk/extensions/FlaggedRevs/api/ApiQueryOldreviewedpages.php:r69784,69928
Index: branches/REL1_16/extensions/FlaggedRevs/api/ApiQueryReviewedpages.php
@@ -119,6 +119,10 @@
120120 }
121121 }
122122
 123+ public function getCacheMode( $params ) {
 124+ return 'public';
 125+ }
 126+
123127 public function getAllowedParams() {
124128 $namespaces = FlaggedRevs::getReviewNamespaces();
125129 return array (
Index: branches/REL1_16/extensions/FlaggedRevs/api/ApiQueryUnreviewedpages.php
@@ -114,6 +114,10 @@
115115 }
116116 }
117117
 118+ public function getCacheMode( $params ) {
 119+ return 'public';
 120+ }
 121+
118122 public function getAllowedParams() {
119123 $namespaces = FlaggedRevs::getReviewNamespaces();
120124 return array (
Property changes on: branches/REL1_16/extensions/FlaggedRevs/api
___________________________________________________________________
Added: svn:mergeinfo
121125 Merged /trunk/extensions/FlaggedRevs/api:r69784
Index: branches/REL1_16/extensions/GlobalBlocking/ApiQueryGlobalBlocks.php
@@ -138,6 +138,10 @@
139139 $result->addValue('query', $this->getModuleName(), $data);
140140 }
141141
 142+ public function getCacheMode($params) {
 143+ return 'public';
 144+ }
 145+
142146 public function getAllowedParams() {
143147 return array (
144148 'start' => array(
Property changes on: branches/REL1_16/extensions/GlobalBlocking/ApiQueryGlobalBlocks.php
___________________________________________________________________
Added: svn:mergeinfo
145149 Merged /trunk/extensions/GlobalBlocking/ApiQueryGlobalBlocks.php:r69784
Index: branches/REL1_16/extensions/LiquidThreads/api/ApiQueryLQTThreads.php
@@ -244,6 +244,15 @@
245245 }
246246 }
247247
 248+ public function getCacheMode( $params ) {
 249+ if ( $params['render'] ) {
 250+ // Rendering uses $wgUser
 251+ return 'anon-public-user-private';
 252+ } else {
 253+ return 'public';
 254+ }
 255+ }
 256+
248257 public function getAllowedParams() {
249258 return array (
250259 'startid' => array(
Property changes on: branches/REL1_16/extensions/LiquidThreads/api/ApiQueryLQTThreads.php
___________________________________________________________________
Added: svn:mergeinfo
251260 Merged /trunk/extensions/LiquidThreads/api/ApiQueryLQTThreads.php:r57390,69784
Index: branches/REL1_16/phase3/RELEASE-NOTES
@@ -1,10 +1,10 @@
22 = MediaWiki release notes =
33
4 -== MediaWiki 1.16 beta 3 ==
 4+== MediaWiki 1.16.0 ==
55
6 -2010-05-28
 6+2010-07-26
77
8 -This is a pre-release beta of the MediaWiki 1.16 branch.
 8+This is a stable release of the MediaWiki 1.16 branch.
99
1010 === Summary of selected changes in 1.16 ===
1111
@@ -61,6 +61,9 @@
6262 Special:Upload after following a red link to a file.
6363 * In SQLite full-text search feature: fixed "move page" feature, was non-
6464 functional.
 65+* (bug xxxxx) Fixed Cache-Control headers sent from API modules, to protect
 66+ user privacy in the case where an attacker can access the wiki through the
 67+ same HTTP proxy as a logged-in user.
6568
6669 == Changes since 1.16 beta 2 ==
6770
Index: branches/REL1_16/phase3/includes/api/ApiQueryLangLinks.php
@@ -93,6 +93,10 @@
9494 $db->freeResult( $res );
9595 }
9696
 97+ public function getCacheMode( $params ) {
 98+ return 'public';
 99+ }
 100+
97101 public function getAllowedParams() {
98102 return array(
99103 'limit' => array(
@@ -133,4 +137,4 @@
134138 public function getVersion() {
135139 return __CLASS__ . ': $Id$';
136140 }
137 -}
\ No newline at end of file
 141+}
Index: branches/REL1_16/phase3/includes/api/ApiQueryCategories.php
@@ -43,6 +43,10 @@
4444 $this->run();
4545 }
4646
 47+ public function getCacheMode( $params ) {
 48+ return 'public';
 49+ }
 50+
4751 public function executeGenerator( $resultPageSet ) {
4852 $this->run( $resultPageSet );
4953 }
Index: branches/REL1_16/phase3/includes/api/ApiQueryCategoryInfo.php
@@ -99,6 +99,10 @@
100100 $db->freeResult( $res );
101101 }
102102
 103+ public function getCacheMode( $params ) {
 104+ return 'public';
 105+ }
 106+
103107 public function getAllowedParams() {
104108 return array (
105109 'continue' => null,
@@ -122,4 +126,4 @@
123127 public function getVersion() {
124128 return __CLASS__ . ': $Id$';
125129 }
126 -}
\ No newline at end of file
 130+}
Index: branches/REL1_16/phase3/includes/api/ApiQueryDuplicateFiles.php
@@ -43,6 +43,10 @@
4444 $this->run();
4545 }
4646
 47+ public function getCacheMode( $params ) {
 48+ return 'public';
 49+ }
 50+
4751 public function executeGenerator( $resultPageSet ) {
4852 $this->run( $resultPageSet );
4953 }
Index: branches/REL1_16/phase3/includes/api/ApiQueryImageInfo.php
@@ -244,6 +244,10 @@
245245 return $retval;
246246 }
247247
 248+ public function getCacheMode( $params ) {
 249+ return 'public';
 250+ }
 251+
248252 private function getContinueStr( $img )
249253 {
250254 return $img->getOriginalTitle()->getText() .
Index: branches/REL1_16/phase3/includes/api/ApiOpenSearch.php
@@ -56,7 +56,7 @@
5757 // Open search results may be stored for a very long
5858 // time
5959 $this->getMain()->setCacheMaxAge( $wgSearchSuggestCacheExpiry );
60 - $this->getMain()->setCacheControl( array( 'must-revalidate' => false ) );
 60+ $this->getMain()->setCacheMode( 'public' );
6161
6262 $srchres = PrefixSearch::titleSearch( $search, $limit,
6363 $namespaces );
Index: branches/REL1_16/phase3/includes/api/ApiQueryWatchlist.php
@@ -154,7 +154,7 @@
155155 $this->dieUsageMsg( array( 'show' ) );
156156 }
157157
158 - // Check permissions. FIXME: should this check $user instead of $wgUser?
 158+ // Check permissions.
159159 if ( ( isset( $show['patrolled'] ) || isset( $show['!patrolled'] ) ) && !$wgUser->useRCPatrol() && !$wgUser->useNPPatrol() )
160160 $this->dieUsage( "You need the patrol right to request the patrolled flag", 'permissiondenied' );
161161
Index: branches/REL1_16/phase3/includes/api/ApiQueryImages.php
@@ -122,6 +122,10 @@
123123 $db->freeResult( $res );
124124 }
125125
 126+ public function getCacheMode( $params ) {
 127+ return 'public';
 128+ }
 129+
126130 public function getAllowedParams() {
127131 return array(
128132 'limit' => array(
@@ -164,4 +168,4 @@
165169 public function getVersion() {
166170 return __CLASS__ . ': $Id$';
167171 }
168 -}
\ No newline at end of file
 172+}
Index: branches/REL1_16/phase3/includes/api/ApiQuery.php
@@ -206,9 +206,15 @@
207207 $this->InstantiateModules( $modules, 'list', $this->mQueryListModules );
208208 $this->InstantiateModules( $modules, 'meta', $this->mQueryMetaModules );
209209
 210+ $cacheMode = 'public';
 211+
210212 // If given, execute generator to substitute user supplied data with generated data.
211213 if ( isset ( $this->params['generator'] ) ) {
212 - $this->executeGeneratorModule( $this->params['generator'], $modules );
 214+ $generator = $this->newGenerator( $this->params['generator'] );
 215+ $params = $generator->extractRequestParams();
 216+ $cacheMode = $this->mergeCacheMode( $cacheMode,
 217+ $generator->getCacheMode( $params ) );
 218+ $this->executeGeneratorModule( $generator, $modules );
213219 } else {
214220 // Append custom fields and populate page/revision information
215221 $this->addCustomFldsToPageSet( $modules, $this->mPageSet );
@@ -220,14 +226,38 @@
221227
222228 // Execute all requested modules.
223229 foreach ( $modules as $module ) {
 230+ $params = $module->extractRequestParams();
 231+ $cacheMode = $this->mergeCacheMode(
 232+ $cacheMode, $module->getCacheMode( $params ) );
224233 $module->profileIn();
225234 $module->execute();
226235 wfRunHooks( 'APIQueryAfterExecute', array( &$module ) );
227236 $module->profileOut();
228237 }
 238+
 239+ // Set the cache mode
 240+ $this->getMain()->setCacheMode( $cacheMode );
229241 }
230242
231243 /**
 244+ * Update a cache mode string, applying the cache mode of a new module to it.
 245+ * The cache mode may increase in the level of privacy, but public modules
 246+ * added to private data do not decrease the level of privacy.
 247+ */
 248+ protected function mergeCacheMode( $cacheMode, $modCacheMode ) {
 249+ if ( $modCacheMode === 'anon-public-user-private' ) {
 250+ if ( $cacheMode !== 'private' ) {
 251+ $cacheMode = 'anon-public-user-private';
 252+ }
 253+ } elseif ( $modCacheMode === 'public' ) {
 254+ // do nothing, if it's public already it will stay public
 255+ } else { // private
 256+ $cacheMode = 'private';
 257+ }
 258+ return $cacheMode;
 259+ }
 260+
 261+ /**
232262 * Query modules may optimize data requests through the $this->getPageSet() object
233263 * by adding extra fields from the page table.
234264 * This function will gather all the extra request fields from the modules.
@@ -401,12 +431,9 @@
402432 }
403433
404434 /**
405 - * For generator mode, execute generator, and use its output as new
406 - * ApiPageSet
407 - * @param $generatorName string Module name
408 - * @param $modules array of module objects
 435+ * Create a generator object of the given type and return it
409436 */
410 - protected function executeGeneratorModule( $generatorName, $modules ) {
 437+ public function newGenerator( $generatorName ) {
411438
412439 // Find class that implements requested generator
413440 if ( isset ( $this->mQueryListModules[$generatorName] ) ) {
@@ -424,9 +451,20 @@
425452 $generator = new $className ( $this, $generatorName );
426453 if ( !$generator instanceof ApiQueryGeneratorBase )
427454 $this->dieUsage( "Module $generatorName cannot be used as a generator", "badgenerator" );
428 -
429455 $generator->setGeneratorMode();
 456+ return $generator;
 457+ }
430458
 459+ /**
 460+ * For generator mode, execute generator, and use its output as new
 461+ * ApiPageSet
 462+ * @param $generatorName string Module name
 463+ * @param $modules array of module objects
 464+ */
 465+ protected function executeGeneratorModule( $generator, $modules ) {
 466+ // Generator results
 467+ $resultPageSet = new ApiPageSet( $this, $this->redirects, $this->convertTitles );
 468+
431469 // Add any additional fields modules may need
432470 $generator->requestExtraData( $this->mPageSet );
433471 $this->addCustomFldsToPageSet( $modules, $resultPageSet );
Index: branches/REL1_16/phase3/includes/api/ApiQueryRandom.php
@@ -121,6 +121,10 @@
122122 return $vals;
123123 }
124124
 125+ public function getCacheMode( $params ) {
 126+ return 'public';
 127+ }
 128+
125129 public function getAllowedParams() {
126130 return array (
127131 'namespace' => array(
@@ -161,4 +165,4 @@
162166 public function getVersion() {
163167 return __CLASS__ . ': $Id: ApiQueryRandom.php overlordq$';
164168 }
165 -}
\ No newline at end of file
 169+}
Index: branches/REL1_16/phase3/includes/api/ApiQueryRevisions.php
@@ -464,6 +464,17 @@
465465 return $vals;
466466 }
467467
 468+ public function getCacheMode( $params ) {
 469+ if ( isset( $params['token'] ) ) {
 470+ return 'private';
 471+ }
 472+ if ( !is_null( $params['prop'] ) && in_array( 'parsedcomment', $params['prop'] ) ) {
 473+ // formatComment() calls wfMsg() among other things
 474+ return 'anon-public-user-private';
 475+ }
 476+ return 'public';
 477+ }
 478+
468479 public function getAllowedParams() {
469480 return array (
470481 'prop' => array (
Index: branches/REL1_16/phase3/includes/api/ApiQueryExternalLinks.php
@@ -83,6 +83,10 @@
8484 $db->freeResult( $res );
8585 }
8686
 87+ public function getCacheMode( $params ) {
 88+ return 'public';
 89+ }
 90+
8791 public function getAllowedParams() {
8892 return array(
8993 'limit' => array(
@@ -117,4 +121,4 @@
118122 public function getVersion() {
119123 return __CLASS__ . ': $Id$';
120124 }
121 -}
\ No newline at end of file
 125+}
Index: branches/REL1_16/phase3/includes/api/ApiQueryCategoryMembers.php
@@ -43,6 +43,10 @@
4444 $this->run();
4545 }
4646
 47+ public function getCacheMode( $params ) {
 48+ return 'public';
 49+ }
 50+
4751 public function executeGenerator( $resultPageSet ) {
4852 $this->run( $resultPageSet );
4953 }
Index: branches/REL1_16/phase3/includes/api/ApiQueryAllmessages.php
@@ -120,6 +120,19 @@
121121 $result->setIndexedTagName_internal( array( 'query', $this->getModuleName() ), 'message' );
122122 }
123123
 124+ public function getCacheMode( $params ) {
 125+ if ( is_null( $params['lang'] ) ) {
 126+ // Language not specified, will be fetched from preferences
 127+ return 'anon-public-user-private';
 128+ } elseif ( $params['enableparser'] ) {
 129+ // User-specific parser options will be used
 130+ return 'anon-public-user-private';
 131+ } else {
 132+ // OK to cache
 133+ return 'public';
 134+ }
 135+ }
 136+
124137 public function getAllowedParams() {
125138 return array (
126139 'messages' => array (
Index: branches/REL1_16/phase3/includes/api/ApiQueryUserContributions.php
@@ -338,6 +338,12 @@
339339 wfTimestamp( TS_ISO_8601, $row->rev_timestamp );
340340 }
341341
 342+ public function getCacheMode( $params ) {
 343+ // This module provides access to deleted revisions and patrol flags if
 344+ // the requester is logged in
 345+ return 'anon-public-user-private';
 346+ }
 347+
342348 public function getAllowedParams() {
343349 return array (
344350 'limit' => array (
Index: branches/REL1_16/phase3/includes/api/ApiQueryUsers.php
@@ -207,6 +207,14 @@
208208 return $this->getResult()->setIndexedTagName_internal( array( 'query', $this->getModuleName() ), 'user' );
209209 }
210210
 211+ public function getCacheMode( $params ) {
 212+ if ( isset( $params['token'] ) ) {
 213+ return 'private';
 214+ } else {
 215+ return 'public';
 216+ }
 217+ }
 218+
211219 public function getAllowedParams() {
212220 return array (
213221 'prop' => array (
Index: branches/REL1_16/phase3/includes/api/ApiExpandTemplates.php
@@ -42,6 +42,9 @@
4343 }
4444
4545 public function execute() {
 46+ // Cache may vary on $wgUser because ParserOptions gets data from it
 47+ $this->getMain()->setCacheMode( 'anon-public-user-private' );
 48+
4649 // Get parameters
4750 $params = $this->extractRequestParams();
4851
Index: branches/REL1_16/phase3/includes/api/ApiQueryRecentChanges.php
@@ -422,6 +422,24 @@
423423 }
424424 }
425425
 426+ public function getCacheMode( $params ) {
 427+ if ( isset( $params['show'] ) ) {
 428+ foreach ( $params['show'] as $show ) {
 429+ if ( $show === 'patrolled' || $show === '!patrolled' ) {
 430+ return 'private';
 431+ }
 432+ }
 433+ }
 434+ if ( isset( $params['token'] ) ) {
 435+ return 'private';
 436+ }
 437+ if ( !is_null( $params['prop'] ) && in_array( 'parsedcomment', $params['prop'] ) ) {
 438+ // formatComment() calls wfMsg() among other things
 439+ return 'anon-public-user-private';
 440+ }
 441+ return 'public';
 442+ }
 443+
426444 public function getAllowedParams() {
427445 return array (
428446 'start' => array (
Index: branches/REL1_16/phase3/includes/api/ApiQueryAllCategories.php
@@ -44,6 +44,10 @@
4545 $this->run();
4646 }
4747
 48+ public function getCacheMode( $params ) {
 49+ return 'public';
 50+ }
 51+
4852 public function executeGenerator( $resultPageSet ) {
4953 $this->run( $resultPageSet );
5054 }
@@ -177,4 +181,4 @@
178182 public function getVersion() {
179183 return __CLASS__ . ': $Id$';
180184 }
181 -}
\ No newline at end of file
 185+}
Index: branches/REL1_16/phase3/includes/api/ApiQueryProtectedTitles.php
@@ -126,6 +126,15 @@
127127 $resultPageSet->populateFromTitles( $titles );
128128 }
129129
 130+ public function getCacheMode( $params ) {
 131+ if ( !is_null( $params['prop'] ) && in_array( 'parsedcomment', $params['prop'] ) ) {
 132+ // formatComment() calls wfMsg() among other things
 133+ return 'anon-public-user-private';
 134+ } else {
 135+ return 'public';
 136+ }
 137+ }
 138+
130139 public function getAllowedParams() {
131140 global $wgRestrictionLevels;
132141 return array (
@@ -197,4 +206,4 @@
198207 public function getVersion() {
199208 return __CLASS__ . ': $Id$';
200209 }
201 -}
\ No newline at end of file
 210+}
Index: branches/REL1_16/phase3/includes/api/ApiQueryLinks.php
@@ -64,6 +64,10 @@
6565 $this->run();
6666 }
6767
 68+ public function getCacheMode( $params ) {
 69+ return 'public';
 70+ }
 71+
6872 public function executeGenerator( $resultPageSet ) {
6973 $this->run( $resultPageSet );
7074 }
@@ -206,4 +210,4 @@
207211 public function getVersion() {
208212 return __CLASS__ . ': $Id$';
209213 }
210 -}
\ No newline at end of file
 214+}
Index: branches/REL1_16/phase3/includes/api/ApiQueryExtLinksUsage.php
@@ -41,6 +41,10 @@
4242 $this->run();
4343 }
4444
 45+ public function getCacheMode( $params ) {
 46+ return 'public';
 47+ }
 48+
4549 public function executeGenerator( $resultPageSet ) {
4650 $this->run( $resultPageSet );
4751 }
@@ -218,4 +222,4 @@
219223 public function getVersion() {
220224 return __CLASS__ . ': $Id$';
221225 }
222 -}
\ No newline at end of file
 226+}
Index: branches/REL1_16/phase3/includes/api/ApiQueryAllUsers.php
@@ -189,6 +189,10 @@
190190 $result->setIndexedTagName_internal( array( 'query', $this->getModuleName() ), 'u' );
191191 }
192192
 193+ public function getCacheMode( $params ) {
 194+ return 'public';
 195+ }
 196+
193197 public function getAllowedParams() {
194198 return array (
195199 'from' => null,
@@ -242,4 +246,4 @@
243247 public function getVersion() {
244248 return __CLASS__ . ': $Id$';
245249 }
246 -}
\ No newline at end of file
 250+}
Property changes on: branches/REL1_16/phase3/includes/api/ApiQueryAllUsers.php
___________________________________________________________________
Modified: svn:mergeinfo
247251 Merged /trunk/phase3/includes/api/ApiQueryAllUsers.php:r69339,69347,69350,69369,69379,69776,69931
Index: branches/REL1_16/phase3/includes/api/ApiQueryInfo.php
@@ -522,7 +522,7 @@
523523 }
524524
525525 /**
526 - * Get information about watched status and put it in $watched
 526+ * Get information about watched status and put it in $this->watched
527527 */
528528 private function getWatchedInfo()
529529 {
@@ -553,6 +553,27 @@
554554 }
555555 }
556556
 557+ public function getCacheMode( $params ) {
 558+ $publicProps = array(
 559+ 'protection',
 560+ 'talkid',
 561+ 'subjectid',
 562+ 'url',
 563+ 'preload',
 564+ );
 565+ if ( !is_null( $params['prop'] ) ) {
 566+ foreach ( $params['prop'] as $prop ) {
 567+ if ( !in_array( $prop, $publicProps ) ) {
 568+ return 'private';
 569+ }
 570+ }
 571+ }
 572+ if ( !is_null( $params['token'] ) ) {
 573+ return 'private';
 574+ }
 575+ return 'public';
 576+ }
 577+
557578 public function getAllowedParams() {
558579 return array (
559580 'prop' => array (
@@ -561,11 +582,13 @@
562583 ApiBase :: PARAM_TYPE => array (
563584 'protection',
564585 'talkid',
565 - 'watched',
 586+ 'watched', # private
566587 'subjectid',
567588 'url',
568 - 'readable',
 589+ 'readable', # private
569590 'preload'
 591+ // If you add more properties here, please consider whether they
 592+ // need to be added to getCacheMode()
570593 ) ),
571594 'token' => array (
572595 ApiBase :: PARAM_DFLT => null,
Index: branches/REL1_16/phase3/includes/api/ApiQueryTags.php
@@ -129,6 +129,10 @@
130130 return true;
131131 }
132132
 133+ public function getCacheMode( $params ) {
 134+ return 'public';
 135+ }
 136+
133137 public function getAllowedParams() {
134138 return array (
135139 'continue' => array(
Index: branches/REL1_16/phase3/includes/api/ApiMain.php
@@ -126,7 +126,8 @@
127127 private $mResult, $mAction, $mShowVersions, $mEnableWrite, $mRequest;
128128 private $mInternalMode, $mSquidMaxage, $mModule;
129129
130 - private $mCacheControl = array( 'must-revalidate' => true );
 130+ private $mCacheMode = 'private';
 131+ private $mCacheControl = array();
131132
132133 /**
133134 * Constructs an instance of ApiMain that utilizes the module and format specified by $request.
@@ -223,13 +224,83 @@
224225 }
225226
226227 /**
 228+ * Set the type of caching headers which will be sent.
 229+ *
 230+ * @param $mode One of:
 231+ * - 'public': Cache this object in public caches, if the maxage or smaxage
 232+ * parameter is set, or if setCacheMaxAge() was called. If a maximum age is
 233+ * not provided by any of these means, the object will be private.
 234+ * - 'private': Cache this object only in private client-side caches.
 235+ * - 'anon-public-user-private': Make this object cacheable for logged-out
 236+ * users, but private for logged-in users. IMPORTANT: If this is set, it must be
 237+ * set consistently for a given URL, it cannot be set differently depending on
 238+ * things like the contents of the database, or whether the user is logged in.
 239+ *
 240+ * If the wiki does not allow anonymous users to read it, the mode set here
 241+ * will be ignored, and private caching headers will always be sent. In other words,
 242+ * the "public" mode is equivalent to saying that the data sent is as public as a page
 243+ * view.
 244+ *
 245+ * For user-dependent data, the private mode should generally be used. The
 246+ * anon-public-user-private mode should only be used where there is a particularly
 247+ * good performance reason for caching the anonymous response, but where the
 248+ * response to logged-in users may differ, or may contain private data.
 249+ *
 250+ * If this function is never called, then the default will be the private mode.
 251+ */
 252+ public function setCacheMode( $mode ) {
 253+ if ( !in_array( $mode, array( 'private', 'public', 'anon-public-user-private' ) ) ) {
 254+ wfDebug( __METHOD__.": unrecognised cache mode \"$mode\"\n" );
 255+ // Ignore for forwards-compatibility
 256+ return;
 257+ }
 258+
 259+ if ( !in_array( 'read', User::getGroupPermissions( array( '*' ) ), true ) ) {
 260+ // Private wiki, only private headers
 261+ if ( $mode !== 'private' ) {
 262+ wfDebug( __METHOD__.": ignoring request for $mode cache mode, private wiki\n" );
 263+ return;
 264+ }
 265+ }
 266+
 267+ wfDebug( __METHOD__.": setting cache mode $mode\n" );
 268+ $this->mCacheMode = $mode;
 269+ }
 270+
 271+ /**
 272+ * @deprecated Private caching is now the default, so there is usually no
 273+ * need to call this function. If there is a need, you can use
 274+ * $this->setCacheMode('private')
 275+ */
 276+ public function setCachePrivate() {
 277+ $this->setCacheMode( 'private' );
 278+ }
 279+
 280+ /**
227281 * Set directives (key/value pairs) for the Cache-Control header.
228282 * Boolean values will be formatted as such, by including or omitting
229283 * without an equals sign.
 284+ *
 285+ * Cache control values set here will only be used if the cache mode is not
 286+ * private, see setCacheMode().
230287 */
231288 public function setCacheControl( $directives ) {
232289 $this->mCacheControl = $directives + $this->mCacheControl;
233290 }
 291+
 292+ /**
 293+ * Make sure Vary: Cookie and friends are set. Use this when the output of a request
 294+ * may be cached for anons but may not be cached for logged-in users.
 295+ *
 296+ * WARNING: This function must be called CONSISTENTLY for a given URL. This means that a
 297+ * given URL must either always or never call this function; if it sometimes does and
 298+ * sometimes doesn't, stuff will break.
 299+ *
 300+ * @deprecated Use setCacheMode( 'anon-public-user-private' )
 301+ */
 302+ public function setVaryCookie() {
 303+ $this->setCacheMode( 'anon-public-user-private' );
 304+ }
234305
235306 /**
236307 * Create an instance of an output formatter by its name
@@ -280,7 +351,7 @@
281352 $errCode = $this->substituteResultWithError( $e );
282353
283354 // Error results should not be cached
284 - $this->setCacheMaxAge( 0 );
 355+ $this->setCacheMode( 'private' );
285356
286357 $headerStr = 'MediaWiki-API-Error: ' . $errCode;
287358 if ( $e->getCode() === 0 )
@@ -296,6 +367,48 @@
297368 $this->printResult( true );
298369 }
299370
 371+ // Send cache headers after any code which might generate an error, to
 372+ // avoid sending public cache headers for errors.
 373+ $this->sendCacheHeaders();
 374+
 375+ if ( $this->mPrinter->getIsHtml() && !$this->mPrinter->isDisabled() ) {
 376+ echo wfReportTime();
 377+ }
 378+
 379+ ob_end_flush();
 380+ }
 381+
 382+ protected function sendCacheHeaders() {
 383+ if ( $this->mCacheMode == 'private' ) {
 384+ header( 'Cache-Control: private' );
 385+ return;
 386+ }
 387+
 388+ if ( $this->mCacheMode == 'anon-public-user-private' ) {
 389+ global $wgUseXVO, $wgOut;
 390+ header( 'Vary: Accept-Encoding, Cookie' );
 391+ if ( $wgUseXVO ) {
 392+ header( $wgOut->getXVO() );
 393+ if ( $wgOut->haveCacheVaryCookies() ) {
 394+ // Logged in, mark this request private
 395+ header( 'Cache-Control: private' );
 396+ return;
 397+ }
 398+ // Logged out, send normal public headers below
 399+ } elseif ( session_id() != '' ) {
 400+ // Logged in or otherwise has session (e.g. anonymous users who have edited)
 401+ // Mark request private
 402+ header( 'Cache-Control: private' );
 403+ return;
 404+ } // else no XVO and anonymous, send public headers below
 405+ } else /* if public */ {
 406+ // Give a debugging message if the user object is unstubbed on a public request
 407+ global $wgUser;
 408+ if ( !( $wgUser instanceof StubUser ) ) {
 409+ wfDebug( __METHOD__." \$wgUser is unstubbed on a public request!\n" );
 410+ }
 411+ }
 412+
300413 // If nobody called setCacheMaxAge(), use the (s)maxage parameters
301414 if ( !isset( $this->mCacheControl['s-maxage'] ) ) {
302415 $this->mCacheControl['s-maxage'] = $this->getParameter( 'smaxage' );
@@ -304,12 +417,21 @@
305418 $this->mCacheControl['max-age'] = $this->getParameter( 'maxage' );
306419 }
307420
308 - // Set the cache expiration at the last moment, as any errors may change the expiration.
309 - // if $this->mSquidMaxage == 0, the expiry time is set to the first second of unix epoch
310 - $exp = min( $this->mCacheControl['s-maxage'], $this->mCacheControl['max-age'] );
311 - $expires = ( $exp == 0 ? 1 : time() + $exp );
312 - header( 'Expires: ' . wfTimestamp( TS_RFC2822, $expires ) );
 421+ if ( !$this->mCacheControl['s-maxage'] && !$this->mCacheControl['max-age'] ) {
 422+ // Public cache not requested
 423+ // Sending a Vary header in this case is harmless, and protects us
 424+ // against conditional calls of setCacheMaxAge().
 425+ header( 'Cache-Control: private' );
 426+ return;
 427+ }
313428
 429+ $this->mCacheControl['public'] = true;
 430+
 431+ // Send an Expires header
 432+ $maxAge = min( $this->mCacheControl['s-maxage'], $this->mCacheControl['max-age'] );
 433+ $expiryUnixTime = ( $maxAge == 0 ? 1 : time() + $maxAge );
 434+ header( 'Expires: ' . wfTimestamp( TS_RFC2822, $expiryUnixTime ) );
 435+
314436 // Construct the Cache-Control header
315437 $ccHeader = '';
316438 $separator = '';
@@ -326,11 +448,6 @@
327449 }
328450
329451 header( "Cache-Control: $ccHeader" );
330 -
331 - if ( $this->mPrinter->getIsHtml() )
332 - echo wfReportTime();
333 -
334 - ob_end_flush();
335452 }
336453
337454 /**
@@ -446,7 +563,7 @@
447564 }
448565
449566 global $wgUser, $wgGroupPermissions;
450 - if ( $module->isReadMode() && !$wgGroupPermissions['*']['read'] && !$wgUser->isAllowed( 'read' ) )
 567+ if ( $module->isReadMode() && !in_array( 'read', User::getGroupPermissions( array( '*' ) ), true ) && !$wgUser->isAllowed( 'read' ) )
451568 $this->dieUsageMsg( array( 'readrequired' ) );
452569 if ( $module->isWriteMode() ) {
453570 if ( !$this->mEnableWrite )
Index: branches/REL1_16/phase3/includes/api/ApiQueryBacklinks.php
@@ -92,6 +92,10 @@
9393 $this->run();
9494 }
9595
 96+ public function getCacheMode( $params ) {
 97+ return 'public';
 98+ }
 99+
96100 public function executeGenerator( $resultPageSet ) {
97101 $this->run( $resultPageSet );
98102 }
Index: branches/REL1_16/phase3/includes/api/ApiQuerySearch.php
@@ -155,6 +155,10 @@
156156 }
157157 }
158158
 159+ public function getCacheMode( $params ) {
 160+ return 'public';
 161+ }
 162+
159163 public function getAllowedParams() {
160164 return array (
161165 'search' => null,
Index: branches/REL1_16/phase3/includes/api/ApiQueryAllLinks.php
@@ -43,6 +43,10 @@
4444 $this->run();
4545 }
4646
 47+ public function getCacheMode( $params ) {
 48+ return 'public';
 49+ }
 50+
4751 public function executeGenerator( $resultPageSet ) {
4852 $this->run( $resultPageSet );
4953 }
@@ -207,4 +211,4 @@
208212 public function getVersion() {
209213 return __CLASS__ . ': $Id$';
210214 }
211 -}
\ No newline at end of file
 215+}
Index: branches/REL1_16/phase3/includes/api/ApiQuerySiteinfo.php
@@ -421,6 +421,9 @@
422422 return $this->getResult()->addValue( 'query', $property, $data );
423423 }
424424
 425+ public function getCacheMode( $params ) {
 426+ return 'public';
 427+ }
425428
426429 public function getAllowedParams() {
427430 return array(
Index: branches/REL1_16/phase3/includes/api/ApiParse.php
@@ -38,6 +38,9 @@
3939 }
4040
4141 public function execute() {
 42+ // The data is hot but user-dependent, like page views, so we set vary cookies
 43+ $this->getMain()->setCacheMode( 'anon-public-user-private' );
 44+
4245 // Get parameters
4346 $params = $this->extractRequestParams();
4447 $text = $params['text'];
@@ -325,4 +328,4 @@
326329 public function getVersion() {
327330 return __CLASS__ . ': $Id$';
328331 }
329 -}
\ No newline at end of file
 332+}
Index: branches/REL1_16/phase3/includes/api/ApiQueryAllpages.php
@@ -43,6 +43,10 @@
4444 $this->run();
4545 }
4646
 47+ public function getCacheMode( $params ) {
 48+ return 'public';
 49+ }
 50+
4751 public function executeGenerator( $resultPageSet ) {
4852 if ( $resultPageSet->isResolvingRedirects() )
4953 $this->dieUsage( 'Use "gapfilterredir=nonredirects" option instead of "redirects" when using allpages as a generator', 'params' );
Index: branches/REL1_16/phase3/includes/api/ApiQueryAllimages.php
@@ -55,6 +55,10 @@
5656 $this->run();
5757 }
5858
 59+ public function getCacheMode( $params ) {
 60+ return 'public';
 61+ }
 62+
5963 public function executeGenerator( $resultPageSet ) {
6064 if ( $resultPageSet->isResolvingRedirects() )
6165 $this->dieUsage( 'Use "gaifilterredir=nonredirects" option instead of "redirects" when using allimages as a generator', 'params' );
Index: branches/REL1_16/phase3/includes/api/ApiQueryLogEvents.php
@@ -285,6 +285,15 @@
286286 return $vals;
287287 }
288288
 289+ public function getCacheMode( $params ) {
 290+ if ( !is_null( $params['prop'] ) && in_array( 'parsedcomment', $params['prop'] ) ) {
 291+ // formatComment() calls wfMsg() among other things
 292+ return 'anon-public-user-private';
 293+ } else {
 294+ return 'public';
 295+ }
 296+ }
 297+
289298 public function getAllowedParams() {
290299 global $wgLogTypes;
291300 return array (
Index: branches/REL1_16/phase3/includes/api/ApiQueryBase.php
@@ -47,6 +47,17 @@
4848 }
4949
5050 /**
 51+ * Get the cache mode for the data generated by this module. Override this
 52+ * in the module subclass.
 53+ *
 54+ * Public caching will only be allowed if *all* the modules that supply
 55+ * data for a given request return a cache mode of public.
 56+ */
 57+ public function getCacheMode( $params ) {
 58+ return 'private';
 59+ }
 60+
 61+ /**
5162 * Blank the internal arrays with query parameters
5263 */
5364 protected function resetQueryParams() {
Property changes on: branches/REL1_16/phase3/includes/api
___________________________________________________________________
Modified: svn:mergeinfo
5465 Merged /trunk/phase3/includes/api:r69339,69347,69350,69369,69379,69776,69931

Follow-up revisions

RevisionCommit summaryAuthorDate
r69986* Merged r69932 from REL1_16: API cache header fix. The base was quite differ...tstarling03:57, 27 July 2010
r70061Brought the API cache header handling into sync with the REL1_16 branch, by r...tstarling02:01, 28 July 2010
r70066* MFT r70062: fix for bug 24564 (fatal error with limit=max)...tstarling05:52, 28 July 2010

Past revisions this follows-up on

RevisionCommit summaryAuthorDate
r69339API: Make output containing private or user-specific data uncacheable for log...catrope19:00, 14 July 2010
r69347follow up r69339: Add a missing setVaryCookie for consistency and to avoid us...mah21:00, 14 July 2010
r69350follow up r69339:...mah21:46, 14 July 2010
r69369re r69339 use the actual function: s/hasCache/haveCache/mah01:15, 15 July 2010
r69379Apply r69357 to trunk; was a fix for trunk but got committed to REL1_16catrope09:25, 15 July 2010
r69776Rewrote r69339 etc. to clean up API cache header handling....tstarling07:17, 23 July 2010
r69784Followup to r69776: remove calls to setCachePrivate() and setVaryCookie() fro...catrope11:17, 23 July 2010
r69928Fixes for r69784:...tstarling06:00, 26 July 2010
r69931Fix for r69776: remove unused variable ApiMain::$mVaryCookietstarling07:35, 26 July 2010

Status & tagging log