1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241
|
<?php
/**
* Response handler for Ajax requests
*
* @file
* @ingroup Ajax
*/
/**
* Handle responses for Ajax requests (send headers, print
* content, that sort of thing)
*
* @ingroup Ajax
*/
class AjaxResponse {
/** Number of seconds to get the response cached by a proxy */
private $mCacheDuration;
/** HTTP header Content-Type */
private $mContentType;
/** Disables output. Can be set by calling $AjaxResponse->disable() */
private $mDisabled;
/** Date for the HTTP header Last-modified */
private $mLastModified;
/** HTTP response code */
private $mResponseCode;
/** HTTP Vary header */
private $mVary;
/** Content of our HTTP response */
private $mText;
function __construct( $text = null ) {
$this->mCacheDuration = null;
$this->mVary = null;
$this->mDisabled = false;
$this->mText = '';
$this->mResponseCode = '200 OK';
$this->mLastModified = false;
$this->mContentType = 'application/x-wiki';
if ( $text ) {
$this->addText( $text );
}
}
function setCacheDuration( $duration ) {
$this->mCacheDuration = $duration;
}
function setVary( $vary ) {
$this->mVary = $vary;
}
function setResponseCode( $code ) {
$this->mResponseCode = $code;
}
function setContentType( $type ) {
$this->mContentType = $type;
}
function disable() {
$this->mDisabled = true;
}
/** Add content to the response */
function addText( $text ) {
if ( ! $this->mDisabled && $text ) {
$this->mText .= $text;
}
}
/** Output text */
function printText() {
if ( ! $this->mDisabled ) {
print $this->mText;
}
}
/** Construct the header and output it */
function sendHeaders() {
global $wgUseSquid, $wgUseESI;
if ( $this->mResponseCode ) {
$n = preg_replace( '/^ *(\d+)/', '\1', $this->mResponseCode );
header( "Status: " . $this->mResponseCode, true, (int)$n );
}
header ( "Content-Type: " . $this->mContentType );
if ( $this->mLastModified ) {
header ( "Last-Modified: " . $this->mLastModified );
} else {
header ( "Last-Modified: " . gmdate( "D, d M Y H:i:s" ) . " GMT" );
}
if ( $this->mCacheDuration ) {
# If squid caches are configured, tell them to cache the response,
# and tell the client to always check with the squid. Otherwise,
# tell the client to use a cached copy, without a way to purge it.
if ( $wgUseSquid ) {
# Expect explicite purge of the proxy cache, but require end user agents
# to revalidate against the proxy on each visit.
# Surrogate-Control controls our Squid, Cache-Control downstream caches
if ( $wgUseESI ) {
header( 'Surrogate-Control: max-age=' . $this->mCacheDuration . ', content="ESI/1.0"' );
header( 'Cache-Control: s-maxage=0, must-revalidate, max-age=0' );
} else {
header( 'Cache-Control: s-maxage=' . $this->mCacheDuration . ', must-revalidate, max-age=0' );
}
} else {
# Let the client do the caching. Cache is not purged.
header ( "Expires: " . gmdate( "D, d M Y H:i:s", time() + $this->mCacheDuration ) . " GMT" );
header ( "Cache-Control: s-maxage={$this->mCacheDuration},public,max-age={$this->mCacheDuration}" );
}
} else {
# always expired, always modified
header ( "Expires: Mon, 26 Jul 1997 05:00:00 GMT" ); // Date in the past
header ( "Cache-Control: no-cache, must-revalidate" ); // HTTP/1.1
header ( "Pragma: no-cache" ); // HTTP/1.0
}
if ( $this->mVary ) {
header ( "Vary: " . $this->mVary );
}
}
/**
* checkLastModified tells the client to use the client-cached response if
* possible. If sucessful, the AjaxResponse is disabled so that
* any future call to AjaxResponse::printText() have no effect. The method
* returns true iff the response code was set to 304 Not Modified.
*/
function checkLastModified ( $timestamp ) {
global $wgCachePages, $wgCacheEpoch, $wgUser;
$fname = 'AjaxResponse::checkLastModified';
if ( !$timestamp || $timestamp == '19700101000000' ) {
wfDebug( "$fname: CACHE DISABLED, NO TIMESTAMP\n" );
return;
}
if ( !$wgCachePages ) {
wfDebug( "$fname: CACHE DISABLED\n", false );
return;
}
if ( $wgUser->getOption( 'nocache' ) ) {
wfDebug( "$fname: USER DISABLED CACHE\n", false );
return;
}
$timestamp = wfTimestamp( TS_MW, $timestamp );
$lastmod = wfTimestamp( TS_RFC2822, max( $timestamp, $wgUser->mTouched, $wgCacheEpoch ) );
if ( !empty( $_SERVER['HTTP_IF_MODIFIED_SINCE'] ) ) {
# IE sends sizes after the date like this:
# Wed, 20 Aug 2003 06:51:19 GMT; length=5202
# this breaks strtotime().
$modsince = preg_replace( '/;.*$/', '', $_SERVER["HTTP_IF_MODIFIED_SINCE"] );
$modsinceTime = strtotime( $modsince );
$ismodsince = wfTimestamp( TS_MW, $modsinceTime ? $modsinceTime : 1 );
wfDebug( "$fname: -- client send If-Modified-Since: " . $modsince . "\n", false );
wfDebug( "$fname: -- we might send Last-Modified : $lastmod\n", false );
if ( ( $ismodsince >= $timestamp ) && $wgUser->validateCache( $ismodsince ) && $ismodsince >= $wgCacheEpoch ) {
ini_set( 'zlib.output_compression', 0 );
$this->setResponseCode( "304 Not Modified" );
$this->disable();
$this->mLastModified = $lastmod;
wfDebug( "$fname: CACHED client: $ismodsince ; user: {$wgUser->getTouched()} ; page: $timestamp ; site $wgCacheEpoch\n", false );
return true;
} else {
wfDebug( "$fname: READY client: $ismodsince ; user: {$wgUser->getTouched()} ; page: $timestamp ; site $wgCacheEpoch\n", false );
$this->mLastModified = $lastmod;
}
} else {
wfDebug( "$fname: client did not send If-Modified-Since header\n", false );
$this->mLastModified = $lastmod;
}
}
/**
* @param $mckey
* @param $touched
* @return bool
*/
function loadFromMemcached( $mckey, $touched ) {
global $wgMemc;
if ( !$touched ) {
return false;
}
$mcvalue = $wgMemc->get( $mckey );
if ( $mcvalue ) {
# Check to see if the value has been invalidated
if ( $touched <= $mcvalue['timestamp'] ) {
wfDebug( "Got $mckey from cache\n" );
$this->mText = $mcvalue['value'];
return true;
} else {
wfDebug( "$mckey has expired\n" );
}
}
return false;
}
/**
* @param $mckey
* @param $expiry int
* @return bool
*/
function storeInMemcached( $mckey, $expiry = 86400 ) {
global $wgMemc;
$wgMemc->set( $mckey,
array(
'timestamp' => wfTimestampNow(),
'value' => $this->mText
), $expiry
);
return true;
}
}
|