00001 <?php
00007 if( !defined( 'MEDIAWIKI' ) ) {
00008 die( 1 );
00009 }
00010
00017 class AjaxResponse {
00018
00020 private $mCacheDuration;
00021
00023 private $mContentType;
00024
00026 private $mDisabled;
00027
00029 private $mLastModified;
00030
00032 private $mResponseCode;
00033
00035 private $mVary;
00036
00038 private $mText;
00039
00040 function __construct( $text = NULL ) {
00041 $this->mCacheDuration = NULL;
00042 $this->mVary = NULL;
00043
00044 $this->mDisabled = false;
00045 $this->mText = '';
00046 $this->mResponseCode = '200 OK';
00047 $this->mLastModified = false;
00048 $this->mContentType= 'application/x-wiki';
00049
00050 if ( $text ) {
00051 $this->addText( $text );
00052 }
00053 }
00054
00055 function setCacheDuration( $duration ) {
00056 $this->mCacheDuration = $duration;
00057 }
00058
00059 function setVary( $vary ) {
00060 $this->mVary = $vary;
00061 }
00062
00063 function setResponseCode( $code ) {
00064 $this->mResponseCode = $code;
00065 }
00066
00067 function setContentType( $type ) {
00068 $this->mContentType = $type;
00069 }
00070
00071 function disable() {
00072 $this->mDisabled = true;
00073 }
00074
00076 function addText( $text ) {
00077 if ( ! $this->mDisabled && $text ) {
00078 $this->mText .= $text;
00079 }
00080 }
00081
00083 function printText() {
00084 if ( ! $this->mDisabled ) {
00085 print $this->mText;
00086 }
00087 }
00088
00090 function sendHeaders() {
00091 global $wgUseSquid, $wgUseESI;
00092
00093 if ( $this->mResponseCode ) {
00094 $n = preg_replace( '/^ *(\d+)/', '\1', $this->mResponseCode );
00095 header( "Status: " . $this->mResponseCode, true, (int)$n );
00096 }
00097
00098 header ("Content-Type: " . $this->mContentType );
00099
00100 if ( $this->mLastModified ) {
00101 header ("Last-Modified: " . $this->mLastModified );
00102 }
00103 else {
00104 header ("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT");
00105 }
00106
00107 if ( $this->mCacheDuration ) {
00108
00109 # If squid caches are configured, tell them to cache the response,
00110 # and tell the client to always check with the squid. Otherwise,
00111 # tell the client to use a cached copy, without a way to purge it.
00112
00113 if( $wgUseSquid ) {
00114
00115 # Expect explicite purge of the proxy cache, but require end user agents
00116 # to revalidate against the proxy on each visit.
00117 # Surrogate-Control controls our Squid, Cache-Control downstream caches
00118
00119 if ( $wgUseESI ) {
00120 header( 'Surrogate-Control: max-age='.$this->mCacheDuration.', content="ESI/1.0"');
00121 header( 'Cache-Control: s-maxage=0, must-revalidate, max-age=0' );
00122 } else {
00123 header( 'Cache-Control: s-maxage='.$this->mCacheDuration.', must-revalidate, max-age=0' );
00124 }
00125
00126 } else {
00127
00128 # Let the client do the caching. Cache is not purged.
00129 header ("Expires: " . gmdate( "D, d M Y H:i:s", time() + $this->mCacheDuration ) . " GMT");
00130 header ("Cache-Control: s-max-age={$this->mCacheDuration},public,max-age={$this->mCacheDuration}");
00131 }
00132
00133 } else {
00134 # always expired, always modified
00135 header ("Expires: Mon, 26 Jul 1997 05:00:00 GMT");
00136 header ("Cache-Control: no-cache, must-revalidate");
00137 header ("Pragma: no-cache");
00138 }
00139
00140 if ( $this->mVary ) {
00141 header ( "Vary: " . $this->mVary );
00142 }
00143 }
00144
00151 function checkLastModified ( $timestamp ) {
00152 global $wgCachePages, $wgCacheEpoch, $wgUser;
00153 $fname = 'AjaxResponse::checkLastModified';
00154
00155 if ( !$timestamp || $timestamp == '19700101000000' ) {
00156 wfDebug( "$fname: CACHE DISABLED, NO TIMESTAMP\n" );
00157 return;
00158 }
00159 if( !$wgCachePages ) {
00160 wfDebug( "$fname: CACHE DISABLED\n", false );
00161 return;
00162 }
00163 if( $wgUser->getOption( 'nocache' ) ) {
00164 wfDebug( "$fname: USER DISABLED CACHE\n", false );
00165 return;
00166 }
00167
00168 $timestamp = wfTimestamp( TS_MW, $timestamp );
00169 $lastmod = wfTimestamp( TS_RFC2822, max( $timestamp, $wgUser->mTouched, $wgCacheEpoch ) );
00170
00171 if( !empty( $_SERVER['HTTP_IF_MODIFIED_SINCE'] ) ) {
00172 # IE sends sizes after the date like this:
00173 # Wed, 20 Aug 2003 06:51:19 GMT; length=5202
00174 # this breaks strtotime().
00175 $modsince = preg_replace( '/;.*$/', '', $_SERVER["HTTP_IF_MODIFIED_SINCE"] );
00176 $modsinceTime = strtotime( $modsince );
00177 $ismodsince = wfTimestamp( TS_MW, $modsinceTime ? $modsinceTime : 1 );
00178 wfDebug( "$fname: -- client send If-Modified-Since: " . $modsince . "\n", false );
00179 wfDebug( "$fname: -- we might send Last-Modified : $lastmod\n", false );
00180 if( ($ismodsince >= $timestamp ) && $wgUser->validateCache( $ismodsince ) && $ismodsince >= $wgCacheEpoch ) {
00181 ini_set('zlib.output_compression', 0);
00182 $this->setResponseCode( "304 Not Modified" );
00183 $this->disable();
00184 $this->mLastModified = $lastmod;
00185
00186 wfDebug( "$fname: CACHED client: $ismodsince ; user: $wgUser->mTouched ; page: $timestamp ; site $wgCacheEpoch\n", false );
00187
00188 return true;
00189 } else {
00190 wfDebug( "$fname: READY client: $ismodsince ; user: $wgUser->mTouched ; page: $timestamp ; site $wgCacheEpoch\n", false );
00191 $this->mLastModified = $lastmod;
00192 }
00193 } else {
00194 wfDebug( "$fname: client did not send If-Modified-Since header\n", false );
00195 $this->mLastModified = $lastmod;
00196 }
00197 }
00198
00199 function loadFromMemcached( $mckey, $touched ) {
00200 global $wgMemc;
00201 if ( !$touched ) return false;
00202
00203 $mcvalue = $wgMemc->get( $mckey );
00204 if ( $mcvalue ) {
00205 # Check to see if the value has been invalidated
00206 if ( $touched <= $mcvalue['timestamp'] ) {
00207 wfDebug( "Got $mckey from cache\n" );
00208 $this->mText = $mcvalue['value'];
00209 return true;
00210 } else {
00211 wfDebug( "$mckey has expired\n" );
00212 }
00213 }
00214
00215 return false;
00216 }
00217
00218 function storeInMemcached( $mckey, $expiry = 86400 ) {
00219 global $wgMemc;
00220
00221 $wgMemc->set( $mckey,
00222 array(
00223 'timestamp' => wfTimestampNow(),
00224 'value' => $this->mText
00225 ), $expiry
00226 );
00227
00228 return true;
00229 }
00230 }