public function getModules()
 {
     if ($this->modules === self::INHERIT_VALUE) {
         return $this->context->getModules();
     }
     return $this->modules;
 }
 public function getModules()
 {
     if (!is_null($this->modules)) {
         return $this->modules;
     } else {
         return $this->context->getModules();
     }
 }
 public function testTypicalRequest()
 {
     $ctx = new ResourceLoaderContext($this->getResourceLoader(), new FauxRequest(['debug' => 'false', 'lang' => 'zh', 'modules' => 'foo|foo.quux,baz,bar|baz.quux', 'only' => 'styles', 'skin' => 'fallback']));
     // Request parameters
     $this->assertEquals($ctx->getModules(), ['foo', 'foo.quux', 'foo.baz', 'foo.bar', 'baz.quux']);
     $this->assertEquals(false, $ctx->getDebug());
     $this->assertEquals('zh', $ctx->getLanguage());
     $this->assertEquals('styles', $ctx->getOnly());
     $this->assertEquals('fallback', $ctx->getSkin());
     $this->assertEquals(null, $ctx->getUser());
     // Misc
     $this->assertEquals('ltr', $ctx->getDirection());
     $this->assertEquals('zh|fallback|||styles|||||', $ctx->getHash());
 }
Пример #4
0
 /**
  * Construct an ResourceFileCache from a context
  * @param $context ResourceLoaderContext
  * @return ResourceFileCache
  */
 public static function newFromContext(ResourceLoaderContext $context)
 {
     $cache = new self();
     if ($context->getOnly() === 'styles') {
         $cache->mType = 'css';
     } else {
         $cache->mType = 'js';
     }
     $modules = array_unique($context->getModules());
     // remove duplicates
     sort($modules);
     // normalize the order (permutation => combination)
     $cache->mKey = sha1($context->getHash() . implode('|', $modules));
     if (count($modules) == 1) {
         $cache->mCacheWorthy = true;
         // won't take up much space
     }
     return $cache;
 }
Пример #5
0
 /**
  * Helper for createLoaderURL()
  *
  * @since 1.24
  * @see makeLoaderQuery
  * @param ResourceLoaderContext $context
  * @param array $extraQuery
  * @return array
  */
 public static function createLoaderQuery(ResourceLoaderContext $context, $extraQuery = array())
 {
     return self::makeLoaderQuery($context->getModules(), $context->getLanguage(), $context->getSkin(), $context->getUser(), $context->getVersion(), $context->getDebug(), $context->getOnly(), $context->getRequest()->getBool('printable'), $context->getRequest()->getBool('handheld'), $extraQuery);
 }
 /**
  * Customize caching policy for RL modules
  *
  * * cache "static" modules for 30 days when cb param in the URL matches $wgStyleVersion
  * * cache "dynamic" modules for 30 days when version param is present in the URL and matches $mtime timestamp
  * * otherwise fallback to caching for 5 minutes
  *
  * @see BAC-1241
  *
  * @param ResourceLoader $rl
  * @param ResourceLoaderContext $context
  * @param $mtime int UNIX timestamp from module(s) calculated from filesystem
  * @param $maxage int UNIX timestamp for maxage
  * @param $smaxage int UNIX timestamp for smaxage
  * @return bool it's a hook
  */
 public static function onResourceLoaderModifyMaxAge(ResourceLoader $rl, ResourceLoaderContext $context, $mtime, &$maxage, &$smaxage)
 {
     global $wgStyleVersion, $wgResourceLoaderMaxage;
     // parse cb and version provided as URL parameters
     // version%3D123456-20140220T090000Z
     // cb%3D123456%26
     $version = explode('-', (string) $context->getVersion(), 2);
     if (count($version) === 2) {
         list($cb, $ts) = $version;
         $ts = strtotime($ts);
         // convert MW to UNIX timestamp
     } else {
         $cb = $context->getRequest()->getVal('cb', false);
         $ts = false;
     }
     // check if at least one of required modules serves dynamic content
     $hasDynamicModule = false;
     $modules = $context->getModules();
     foreach ($modules as $moduleName) {
         if (!$rl->getModule($moduleName) instanceof ResourceLoaderFileModule) {
             $hasDynamicModule = true;
             break;
         }
     }
     if ($hasDynamicModule) {
         // use long TTL when version value matches $mtime passed to the hook
         $useLongTTL = !empty($ts) && $ts <= $mtime;
     } else {
         // use long TTL when cache buster value from URL matches $wgStyleVersion
         $useLongTTL = !empty($cb) && $cb <= $wgStyleVersion;
     }
     // modify caching times
     if (!$useLongTTL) {
         WikiaLogger::instance()->info('rl.shortTTL', ['modules' => join(',', $modules), 'cb' => $cb, 'ts' => $ts]);
     }
     $cachingTimes = $wgResourceLoaderMaxage[$useLongTTL ? 'versioned' : 'unversioned'];
     $maxage = $cachingTimes['client'];
     $smaxage = $cachingTimes['server'];
     return true;
 }
Пример #7
0
 /**
  * Outputs a response to a resource load-request, including a content-type header.
  *
  * @param $context ResourceLoaderContext: Context in which a response should be formed
  */
 public function respond(ResourceLoaderContext $context)
 {
     global $wgResourceLoaderMaxage, $wgCacheEpoch;
     // Buffer output to catch warnings. Normally we'd use ob_clean() on the
     // top-level output buffer to clear warnings, but that breaks when ob_gzhandler
     // is used: ob_clean() will clear the GZIP header in that case and it won't come
     // back for subsequent output, resulting in invalid GZIP. So we have to wrap
     // the whole thing in our own output buffer to be sure the active buffer
     // doesn't use ob_gzhandler.
     // See http://bugs.php.net/bug.php?id=36514
     ob_start();
     wfProfileIn(__METHOD__);
     $errors = '';
     // Split requested modules into two groups, modules and missing
     $modules = array();
     $missing = array();
     foreach ($context->getModules() as $name) {
         if (isset($this->moduleInfos[$name])) {
             $module = $this->getModule($name);
             // Do not allow private modules to be loaded from the web.
             // This is a security issue, see bug 34907.
             if ($module->getGroup() === 'private') {
                 $errors .= $this->makeComment("Cannot show private module \"{$name}\"");
                 continue;
             }
             $modules[$name] = $this->getModule($name);
         } else {
             $missing[] = $name;
         }
     }
     // If a version wasn't specified we need a shorter expiry time for updates
     // to propagate to clients quickly
     if (is_null($context->getVersion())) {
         $maxage = $wgResourceLoaderMaxage['unversioned']['client'];
         $smaxage = $wgResourceLoaderMaxage['unversioned']['server'];
     } else {
         $maxage = $wgResourceLoaderMaxage['versioned']['client'];
         $smaxage = $wgResourceLoaderMaxage['versioned']['server'];
     }
     // Preload information needed to the mtime calculation below
     try {
         $this->preloadModuleInfo(array_keys($modules), $context);
     } catch (Exception $e) {
         // Add exception to the output as a comment
         $errors .= $this->makeComment($e->__toString());
     }
     wfProfileIn(__METHOD__ . '-getModifiedTime');
     // To send Last-Modified and support If-Modified-Since, we need to detect
     // the last modified time
     $mtime = wfTimestamp(TS_UNIX, $wgCacheEpoch);
     foreach ($modules as $module) {
         try {
             // Calculate maximum modified time
             $mtime = max($mtime, $module->getModifiedTime($context));
         } catch (Exception $e) {
             // Add exception to the output as a comment
             $errors .= $this->makeComment($e->__toString());
         }
     }
     wfProfileOut(__METHOD__ . '-getModifiedTime');
     if ($context->getOnly() === 'styles') {
         header('Content-Type: text/css; charset=utf-8');
     } else {
         header('Content-Type: text/javascript; charset=utf-8');
     }
     header('Last-Modified: ' . wfTimestamp(TS_RFC2822, $mtime));
     if ($context->getDebug()) {
         // Do not cache debug responses
         header('Cache-Control: private, no-cache, must-revalidate');
         header('Pragma: no-cache');
     } else {
         header("Cache-Control: public, max-age={$maxage}, s-maxage={$smaxage}");
         $exp = min($maxage, $smaxage);
         header('Expires: ' . wfTimestamp(TS_RFC2822, $exp + time()));
     }
     // If there's an If-Modified-Since header, respond with a 304 appropriately
     // Some clients send "timestamp;length=123". Strip the part after the first ';'
     // so we get a valid timestamp.
     $ims = $context->getRequest()->getHeader('If-Modified-Since');
     // Never send 304s in debug mode
     if ($ims !== false && !$context->getDebug()) {
         $imsTS = strtok($ims, ';');
         if ($mtime <= wfTimestamp(TS_UNIX, $imsTS)) {
             // There's another bug in ob_gzhandler (see also the comment at
             // the top of this function) that causes it to gzip even empty
             // responses, meaning it's impossible to produce a truly empty
             // response (because the gzip header is always there). This is
             // a problem because 304 responses have to be completely empty
             // per the HTTP spec, and Firefox behaves buggily when they're not.
             // See also http://bugs.php.net/bug.php?id=51579
             // To work around this, we tear down all output buffering before
             // sending the 304.
             // On some setups, ob_get_level() doesn't seem to go down to zero
             // no matter how often we call ob_get_clean(), so instead of doing
             // the more intuitive while ( ob_get_level() > 0 ) ob_get_clean();
             // we have to be safe here and avoid an infinite loop.
             for ($i = 0; $i < ob_get_level(); $i++) {
                 ob_end_clean();
             }
             header('HTTP/1.0 304 Not Modified');
             header('Status: 304 Not Modified');
             wfProfileOut(__METHOD__);
             return;
         }
     }
     // Generate a response
     $response = $this->makeModuleResponse($context, $modules, $missing);
     // Prepend comments indicating exceptions
     $response = $errors . $response;
     // Capture any PHP warnings from the output buffer and append them to the
     // response in a comment if we're in debug mode.
     if ($context->getDebug() && strlen($warnings = ob_get_contents())) {
         $response = $this->makeComment($warnings) . $response;
     }
     // Remove the output buffer and output the response
     ob_end_clean();
     echo $response;
     wfProfileOut(__METHOD__);
 }