class WebRequest {
protected $data, $headers = array();
+ /**
+ * Flag to make WebRequest::getHeader return an array of values.
+ * @since 1.26
+ */
+ const GETHEADER_LIST = 1;
+
/**
* Lazy-init response object
* @var WebResponse
}
/**
- * Get a request header, or false if it isn't set
- * @param string $name Case-insensitive header name
+ * Get a request header, or false if it isn't set.
*
- * @return string|bool False on failure
- */
- public function getHeader( $name ) {
+ * @param string $name Case-insensitive header name
+ * @param int $flags Bitwise combination of:
+ * WebRequest::GETHEADER_LIST Treat the header as a comma-separated list
+ * of values, as described in RFC 2616 ยง 4.2.
+ * (since 1.26).
+ * @return string|array|bool False if header is unset; otherwise the
+ * header value(s) as either a string (the default) or an array, if
+ * WebRequest::GETHEADER_LIST flag was set.
+ */
+ public function getHeader( $name, $flags = 0 ) {
$this->initHeaders();
$name = strtoupper( $name );
- if ( isset( $this->headers[$name] ) ) {
- return $this->headers[$name];
- } else {
+ if ( !isset( $this->headers[$name] ) ) {
return false;
}
+ $value = $this->headers[$name];
+ if ( $flags & self::GETHEADER_LIST ) {
+ $value = array_map( 'trim', explode( ',', $value ) );
+ }
+ return $value;
}
/**
return $this->protocol;
}
- /**
- * @param string $name The name of the header to get (case insensitive).
- * @return bool|string
- */
- public function getHeader( $name ) {
- $name = strtoupper( $name );
- return isset( $this->headers[$name] ) ? $this->headers[$name] : false;
+ private function initHeaders() {
+ return;
}
/**
return $this->base->checkSessionCookie();
}
- public function getHeader( $name ) {
- return $this->base->getHeader( $name );
+ public function getHeader( $name, $flags = 0 ) {
+ return $this->base->getHeader( $name, $flags );
}
public function getAllHeaders() {
$result_array['modulemessages'] = array_values( array_unique( $p_result->getModuleMessages() ) );
}
+ if ( isset( $prop['jsconfigvars'] ) ) {
+ $result_array['jsconfigvars'] = $this->formatJsConfigVars( $p_result->getJsConfigVars() );
+ }
+
+ if ( isset( $prop['encodedjsconfigvars'] ) ) {
+ $result_array['encodedjsconfigvars'] = FormatJson::encode(
+ $p_result->getJsConfigVars(), false, FormatJson::ALL_OK
+ );
+ $result_array[ApiResult::META_SUBELEMENTS][] = 'encodedjsconfigvars';
+ }
+
if ( isset( $prop['indicators'] ) ) {
$result_array['indicators'] = (array)$p_result->getIndicators();
ApiResult::setArrayType( $result_array['indicators'], 'BCkvp', 'name' );
return $result;
}
+ private function formatJsConfigVars( $vars, $forceHash = true ) {
+ // Process subarrays and determine if this is a JS [] or {}
+ $hash = $forceHash;
+ $maxKey = -1;
+ $bools = array();
+ foreach ( $vars as $k => $v ) {
+ if ( is_array( $v ) || is_object( $v ) ) {
+ $vars[$k] = $this->formatJsConfigVars( (array)$v, false );
+ } elseif ( is_bool( $v ) ) {
+ // Better here to use real bools even in BC formats
+ $bools[] = $k;
+ }
+ if ( is_string( $k ) ) {
+ $hash = true;
+ } elseif ( $k > $maxKey ) {
+ $maxKey = $k;
+ }
+ }
+ if ( !$hash && $maxKey !== count( $vars ) - 1 ) {
+ $hash = true;
+ }
+
+ // Get the list of keys we actually care about. Unfortunately, we can't support
+ // certain keys that conflict with ApiResult metadata.
+ $keys = array_diff( array_keys( $vars ), array(
+ ApiResult::META_TYPE, ApiResult::META_PRESERVE_KEYS, ApiResult::META_KVP_KEY_NAME,
+ ApiResult::META_INDEXED_TAG_NAME, ApiResult::META_BC_BOOLS
+ ) );
+
+ // Set metadata appropriately
+ if ( $hash ) {
+ return array(
+ ApiResult::META_TYPE => 'kvp',
+ ApiResult::META_KVP_KEY_NAME => 'key',
+ ApiResult::META_PRESERVE_KEYS => $keys,
+ ApiResult::META_BC_BOOLS => $bools,
+ ApiResult::META_INDEXED_TAG_NAME => 'var',
+ ) + $vars;
+ } else {
+ return array(
+ ApiResult::META_TYPE => 'array',
+ ApiResult::META_BC_BOOLS => $bools,
+ ApiResult::META_INDEXED_TAG_NAME => 'value',
+ ) + $vars;
+ }
+ }
+
private function setIndexedTagNames( &$array, $mapping ) {
foreach ( $mapping as $key => $name ) {
if ( isset( $array[$key] ) ) {
'headitems',
'headhtml',
'modules',
+ 'jsconfigvars',
+ 'encodedjsconfigvars',
'indicators',
'iwlinks',
'wikitext',
'properties',
'limitreportdata',
'limitreporthtml',
- )
+ ),
+ ApiBase::PARAM_HELP_MSG_PER_VALUE => array(),
),
'pst' => false,
'onlypst' => false,
"apihelp-parse-param-pageid": "Parse the content of this page. Overrides <var>$1page</var>.",
"apihelp-parse-param-redirects": "If <var>$1page</var> or <var>$1pageid</var> is set to a redirect, resolve it.",
"apihelp-parse-param-oldid": "Parse the content of this revision. Overrides <var>$1page</var> and <var>$1pageid</var>.",
- "apihelp-parse-param-prop": "Which pieces of information to get:\n;text:Gives the parsed text of the wikitext.\n;langlinks:Gives the language links in the parsed wikitext.\n;categories:Gives the categories in the parsed wikitext.\n;categorieshtml:Gives the HTML version of the categories.\n;links:Gives the internal links in the parsed wikitext.\n;templates:Gives the templates in the parsed wikitext.\n;images:Gives the images in the parsed wikitext.\n;externallinks:Gives the external links in the parsed wikitext.\n;sections:Gives the sections in the parsed wikitext.\n;revid:Adds the revision ID of the parsed page.\n;displaytitle:Adds the title of the parsed wikitext.\n;headitems:Gives items to put in the <head> of the page.\n;headhtml:Gives parsed <head> of the page.\n;modules:Gives the ResourceLoader modules used on the page.\n;indicators:Gives the HTML of page status indicators used on the page.\n;iwlinks:Gives interwiki links in the parsed wikitext.\n;wikitext:Gives the original wikitext that was parsed.\n;properties:Gives various properties defined in the parsed wikitext.\n;limitreportdata:Gives the limit report in a structured way. Gives no data, when $1disablepp is set.\n;limitreporthtml:Gives the HTML version of the limit report. Gives no data, when $1disablepp is set.",
+ "apihelp-parse-param-prop": "Which pieces of information to get:",
+ "apihelp-parse-paramvalue-prop-text": "Gives the parsed text of the wikitext.",
+ "apihelp-parse-paramvalue-prop-langlinks": "Gives the language links in the parsed wikitext.",
+ "apihelp-parse-paramvalue-prop-categories": "Gives the categories in the parsed wikitext.",
+ "apihelp-parse-paramvalue-prop-categorieshtml": "Gives the HTML version of the categories.",
+ "apihelp-parse-paramvalue-prop-links": "Gives the internal links in the parsed wikitext.",
+ "apihelp-parse-paramvalue-prop-templates": "Gives the templates in the parsed wikitext.",
+ "apihelp-parse-paramvalue-prop-images": "Gives the images in the parsed wikitext.",
+ "apihelp-parse-paramvalue-prop-externallinks": "Gives the external links in the parsed wikitext.",
+ "apihelp-parse-paramvalue-prop-sections": "Gives the sections in the parsed wikitext.",
+ "apihelp-parse-paramvalue-prop-revid": "Adds the revision ID of the parsed page.",
+ "apihelp-parse-paramvalue-prop-displaytitle": "Adds the title of the parsed wikitext.",
+ "apihelp-parse-paramvalue-prop-headitems": "Gives items to put in the <code><head></code> of the page.",
+ "apihelp-parse-paramvalue-prop-headhtml": "Gives parsed <code><head></code> of the page.",
+ "apihelp-parse-paramvalue-prop-modules": "Gives the ResourceLoader modules used on the page.",
+ "apihelp-parse-paramvalue-prop-jsconfigvars": "Gives the JavaScript configuration variables specific to the page.",
+ "apihelp-parse-paramvalue-prop-encodedjsconfigvars": "Gives the JavaScript configuration variables specific to the page as a JSON string.",
+ "apihelp-parse-paramvalue-prop-indicators": "Gives the HTML of page status indicators used on the page.",
+ "apihelp-parse-paramvalue-prop-iwlinks": "Gives interwiki links in the parsed wikitext.",
+ "apihelp-parse-paramvalue-prop-wikitext": "Gives the original wikitext that was parsed.",
+ "apihelp-parse-paramvalue-prop-properties": "Gives various properties defined in the parsed wikitext.",
+ "apihelp-parse-paramvalue-prop-limitreportdata": "Gives the limit report in a structured way. Gives no data, when <var>$1disablepp</var> is set.",
+ "apihelp-parse-paramvalue-prop-limitreporthtml": "Gives the HTML version of the limit report. Gives no data, when <var>$1disablepp</var> is set.",
"apihelp-parse-param-pst": "Do a pre-save transform on the input before parsing it. Only valid when used with text.",
"apihelp-parse-param-onlypst": "Do a pre-save transform (PST) on the input, but don't parse it. Returns the same wikitext, after a PST has been applied. Only valid when used with <var>$1text</var>.",
"apihelp-parse-param-effectivelanglinks": "Includes language links supplied by extensions (for use with <kbd>$1prop=langlinks</kbd>).",
"apihelp-parse-param-pageid": "{{doc-apihelp-param|parse|pageid}}",
"apihelp-parse-param-redirects": "{{doc-apihelp-param|parse|redirects}}",
"apihelp-parse-param-oldid": "{{doc-apihelp-param|parse|oldid}}",
- "apihelp-parse-param-prop": "{{doc-apihelp-param|parse|prop}}",
+ "apihelp-parse-param-prop": "{{doc-apihelp-param|parse|prop|paramvalues=1}}",
+ "apihelp-parse-paramvalue-prop-text": "{{doc-apihelp-paramvalue|parse|prop|text}}",
+ "apihelp-parse-paramvalue-prop-langlinks": "{{doc-apihelp-paramvalue|parse|prop|langlinks}}",
+ "apihelp-parse-paramvalue-prop-categories": "{{doc-apihelp-paramvalue|parse|prop|categories}}",
+ "apihelp-parse-paramvalue-prop-categorieshtml": "{{doc-apihelp-paramvalue|parse|prop|categorieshtml}}",
+ "apihelp-parse-paramvalue-prop-links": "{{doc-apihelp-paramvalue|parse|prop|links}}",
+ "apihelp-parse-paramvalue-prop-templates": "{{doc-apihelp-paramvalue|parse|prop|templates}}",
+ "apihelp-parse-paramvalue-prop-images": "{{doc-apihelp-paramvalue|parse|prop|images}}",
+ "apihelp-parse-paramvalue-prop-externallinks": "{{doc-apihelp-paramvalue|parse|prop|externallinks}}",
+ "apihelp-parse-paramvalue-prop-sections": "{{doc-apihelp-paramvalue|parse|prop|sections}}",
+ "apihelp-parse-paramvalue-prop-revid": "{{doc-apihelp-paramvalue|parse|prop|revid}}",
+ "apihelp-parse-paramvalue-prop-displaytitle": "{{doc-apihelp-paramvalue|parse|prop|displaytitle}}",
+ "apihelp-parse-paramvalue-prop-headitems": "{{doc-apihelp-paramvalue|parse|prop|headitems}}",
+ "apihelp-parse-paramvalue-prop-headhtml": "{{doc-apihelp-paramvalue|parse|prop|headhtml}}",
+ "apihelp-parse-paramvalue-prop-modules": "{{doc-apihelp-paramvalue|parse|prop|modules}}",
+ "apihelp-parse-paramvalue-prop-jsconfigvars": "{{doc-apihelp-paramvalue|parse|prop|jsconfigvars}}",
+ "apihelp-parse-paramvalue-prop-encodedjsconfigvars": "{{doc-apihelp-paramvalue|parse|prop|encodedjsconfigvars}}",
+ "apihelp-parse-paramvalue-prop-indicators": "{{doc-apihelp-paramvalue|parse|prop|indicators}}",
+ "apihelp-parse-paramvalue-prop-iwlinks": "{{doc-apihelp-paramvalue|parse|prop|iwlinks}}",
+ "apihelp-parse-paramvalue-prop-wikitext": "{{doc-apihelp-paramvalue|parse|prop|wikitext}}",
+ "apihelp-parse-paramvalue-prop-properties": "{{doc-apihelp-paramvalue|parse|prop|properties}}",
+ "apihelp-parse-paramvalue-prop-limitreportdata": "{{doc-apihelp-paramvalue|parse|prop|limitreportdata}}",
+ "apihelp-parse-paramvalue-prop-limitreporthtml": "{{doc-apihelp-paramvalue|parse|prop|limitreporthtml}}",
"apihelp-parse-param-pst": "{{doc-apihelp-param|parse|pst}}",
"apihelp-parse-param-onlypst": "{{doc-apihelp-param|parse|onlypst}}",
"apihelp-parse-param-effectivelanglinks": "{{doc-apihelp-param|parse|effectivelanglinks}}",
* @return bool
*/
function loadFromCache() {
- global $wgMemc;
-
$this->dataLoaded = false;
$this->extraDataLoaded = false;
$key = $this->getCacheKey();
if ( !$key ) {
-
return false;
}
- $cachedValues = $wgMemc->get( $key );
+ $cache = ObjectCache::getMainWANInstance();
+ $cachedValues = $cache->get( $key );
// Check if the key existed and belongs to this version of MediaWiki
if ( isset( $cachedValues['version'] ) && $cachedValues['version'] == MW_FILE_VERSION ) {
* Save the file metadata to memcached
*/
function saveToCache() {
- global $wgMemc;
-
$this->load();
- $key = $this->getCacheKey();
+ $key = $this->getCacheKey();
if ( !$key ) {
return;
}
}
// Cache presence for 1 week and negatives for 1 day
- $wgMemc->set( $key, $cache, $this->fileExists ? 86400 * 7 : 86400 );
+ $cache = ObjectCache::getMainWANInstance();
+ $cache->set( $key, $cache, $this->fileExists ? 86400 * 7 : 86400 );
+ }
+
+ /**
+ * Purge the file object/metadata cache
+ */
+ function invalidateCache() {
+ $this->load();
+
+ $key = $this->getCacheKey();
+ if ( !$key ) {
+ return;
+ }
+
+ $cache = ObjectCache::getMainWANInstance();
+ $cache->delete( $key );
}
/**
__METHOD__
);
- $this->saveToCache();
+ $this->invalidateCache();
$this->unlock(); // done
* Refresh metadata in memcached, but don't touch thumbnails or squid
*/
function purgeMetadataCache() {
- $this->loadFromDB( File::READ_LATEST );
- $this->saveToCache();
+ $this->invalidateCache();
}
/**
# to after $wikiPage->doEdit has been called.
$dbw->commit( __METHOD__ );
- # Save to memcache.
- # We shall not saveToCache before the commit since otherwise
- # in case of a rollback there is an usable file from memcached
- # which in fact doesn't really exist (bug 24978)
- $this->saveToCache();
+ # Update memcache after the commit
+ $this->invalidateCache();
if ( $exists ) {
# Invalidate the cache for the description page
array( 'img_sha1' => $this->sha1 ),
array( 'img_name' => $this->getName() ),
__METHOD__ );
- $this->saveToCache();
+ $this->invalidateCache();
}
$this->unlock(); // done
* @ingroup Media
*/
class DjVuHandler extends ImageHandler {
+ const EXPENSIVE_SIZE_LIMIT = 10485760; // 10MiB
+
/**
* @return bool
*/
return true;
}
+ /**
+ * True if creating thumbnails from the file is large or otherwise resource-intensive.
+ * @param File $file
+ * @return bool
+ */
+ public function isExpensiveToThumbnail( $file ) {
+ return $file->getSize() > static::EXPENSIVE_SIZE_LIMIT;
+ }
+
/**
* @param File $file
* @return bool
* Activate the profiler (assuming $wgProfiler is set)
*/
protected function activateProfiler() {
- global $wgProfiler, $wgTrxProfilerLimits;
+ global $wgProfiler, $wgProfileLimit, $wgTrxProfilerLimits;
$output = $this->getOption( 'profiler' );
if ( !$output ) {
if ( is_array( $wgProfiler ) && isset( $wgProfiler['class'] ) ) {
$class = $wgProfiler['class'];
$profiler = new $class(
- array( 'sampling' => 1, 'output' => $output ) + $wgProfiler
+ array( 'sampling' => 1, 'output' => array( $output ) )
+ + $wgProfiler
+ + array( 'threshold' => $wgProfileLimit )
);
$profiler->setTemplated( true );
Profiler::replaceStubInstance( $profiler );
$.extend( postData, {
pst: '',
preview: '',
- prop: 'text|displaytitle|modules|categorieshtml|templates|langlinks|limitreporthtml',
+ prop: 'text|displaytitle|modules|jsconfigvars|categorieshtml|templates|langlinks|limitreporthtml',
disableeditsection: true
} );
request = api.post( postData );
request.done( function ( response ) {
var li, newList, $displaytitle, $content, $parent, $list;
+ if ( response.parse.jsconfigvars ) {
+ mw.config.set( response.parse.jsconfigvars );
+ }
if ( response.parse.modules ) {
mw.loader.load( response.parse.modules.concat(
response.parse.modulescripts,
* @covers FauxRequest::getHeader
*/
public function testGetSetHeader() {
- $value = 'test/test';
+ $value = 'text/plain, text/html';
$request = new FauxRequest();
- $request->setHeader( 'Content-Type', $value );
+ $request->setHeader( 'Accept', $value );
- $this->assertEquals( $request->getHeader( 'Content-Type' ), $value );
- $this->assertEquals( $request->getHeader( 'CONTENT-TYPE' ), $value );
- $this->assertEquals( $request->getHeader( 'content-type' ), $value );
+ $this->assertEquals( $request->getHeader( 'Nonexistent' ), false );
+ $this->assertEquals( $request->getHeader( 'Accept' ), $value );
+ $this->assertEquals( $request->getHeader( 'ACCEPT' ), $value );
+ $this->assertEquals( $request->getHeader( 'accept' ), $value );
+ $this->assertEquals(
+ $request->getHeader( 'Accept', WebRequest::GETHEADER_LIST ),
+ array( 'text/plain', 'text/html' )
+ );
}
}