Followup r95753 per CR: prevent extensions from making isMovable() return true for...
[lhc/web/wiklou.git] / includes / resourceloader / ResourceLoaderModule.php
index 73fcddf..49e9ef6 100644 (file)
@@ -99,7 +99,7 @@ abstract class ResourceLoaderModule {
         * Set this module's origin. This is called by ResourceLodaer::register()
         * when registering the module. Other code should not call this.
         *
-        * @param $name Int origin
+        * @param $origin Int origin
         */
        public function setOrigin( $origin ) {
                $this->origin = $origin;
@@ -160,6 +160,27 @@ abstract class ResourceLoaderModule {
                return null;
        }
 
+       /**
+        * Get the origin of this module. Should only be overridden for foreign modules.
+        * 
+        * @return String: Origin name, 'local' for local modules
+        */
+       public function getSource() {
+               // Stub, override expected
+               return 'local';
+       }
+       
+       /**
+        * Where on the HTML page should this module's JS be loaded?
+        * 'top': in the <head>
+        * 'bottom': at the bottom of the <body>
+        *
+        * @return string
+        */
+       public function getPosition() {
+               return 'bottom';
+       }
+
        /**
         * Get the loader JS for this module, if set.
         *
@@ -293,4 +314,54 @@ abstract class ResourceLoaderModule {
        public function isKnownEmpty( ResourceLoaderContext $context ) {
                return false;
        }
+
+
+       /** @var JSParser lazy-initialized; use self::javaScriptParser() */
+       private static $jsParser;
+       private static $parseCacheVersion = 1;
+
+       /**
+        * Validate a given script file; if valid returns the original source.
+        * If invalid, returns replacement JS source that throws an exception.
+        *
+        * @param string $fileName
+        * @param string $contents
+        * @return string JS with the original, or a replacement error
+        */
+       protected function validateScriptFile( $fileName, $contents ) {
+               global $wgResourceLoaderValidateJS;
+               if ( $wgResourceLoaderValidateJS ) {
+                       // Try for cache hit
+                       // Use CACHE_ANYTHING since filtering is very slow compared to DB queries
+                       $key = wfMemcKey( 'resourceloader', 'jsparse', self::$parseCacheVersion, md5( $contents ) );
+                       $cache = wfGetCache( CACHE_ANYTHING );
+                       $cacheEntry = $cache->get( $key );
+                       if ( is_string( $cacheEntry ) ) {
+                               return $cacheEntry;
+                       }
+
+                       $parser = self::javaScriptParser();
+                       try {
+                               $parser->parse( $contents, $fileName, 1 );
+                               $result = $contents;
+                       } catch (Exception $e) {
+                               // We'll save this to cache to avoid having to validate broken JS over and over...
+                               $err = $e->getMessage();
+                               $result = "throw new Error(" . Xml::encodeJsVar("JavaScript parse error: $err") . ");";
+                       }
+                       
+                       $cache->set( $key, $result );
+                       return $result;
+               } else {
+                       return $contents;
+               }
+       }
+
+       protected static function javaScriptParser() {
+               if ( !self::$jsParser ) {
+                       self::$jsParser = new JSParser();
+               }
+               return self::$jsParser;
+       }
+
 }