protected function buildResourceTransformer()
 {
     $xformer = new CelerityResourceTransformer();
     $xformer->setMinify(false);
     $xformer->setTranslateURICallback(array($this, 'translateResourceURI'));
     return $xformer;
 }
 public function processRequest()
 {
     $path = $this->path;
     // Sanity checking to keep this from exposing anything sensitive, since it
     // ultimately boils down to disk reads.
     if (preg_match('@(//|\\.\\.)@', $path)) {
         return new Aphront400Response();
     }
     $type = CelerityResourceTransformer::getResourceType($path);
     $type_map = $this->getSupportedResourceTypes();
     if (empty($type_map[$type])) {
         throw new Exception("Only static resources may be served.");
     }
     if (isset($_SERVER['HTTP_IF_MODIFIED_SINCE']) && !PhabricatorEnv::getEnvConfig('celerity.force-disk-reads')) {
         // Return a "304 Not Modified". We don't care about the value of this
         // field since we never change what resource is served by a given URI.
         return $this->makeResponseCacheable(new Aphront304Response());
     }
     $root = dirname(phutil_get_library_root('phabricator'));
     if ($this->package) {
         $map = CelerityResourceMap::getInstance();
         $paths = $map->resolvePackage($this->hash);
         if (!$paths) {
             return new Aphront404Response();
         }
         try {
             $data = array();
             foreach ($paths as $package_path) {
                 $data[] = Filesystem::readFile($root . '/webroot/' . $package_path);
             }
             $data = implode("\n\n", $data);
         } catch (Exception $ex) {
             return new Aphront404Response();
         }
     } else {
         try {
             $data = Filesystem::readFile($root . '/webroot/' . $path);
         } catch (Exception $ex) {
             return new Aphront404Response();
         }
     }
     $xformer = new CelerityResourceTransformer();
     $xformer->setMinify(PhabricatorEnv::getEnvConfig('celerity.minify'));
     $xformer->setCelerityMap(CelerityResourceMap::getInstance());
     $data = $xformer->transformResource($path, $data);
     $response = new AphrontFileResponse();
     $response->setContent($data);
     $response->setMimeType($type_map[$type]);
     return $this->makeResponseCacheable($response);
 }
 public function testTransformation()
 {
     $files = dirname(__FILE__) . '/transformer/';
     foreach (Filesystem::listDirectory($files) as $file) {
         $name = basename($file);
         $data = Filesystem::readFile($files . '/' . $file);
         $parts = preg_split('/^~~~+\\n/m', $data);
         $parts = array_merge($parts, array(null));
         list($options, $in, $expect) = $parts;
         $options = PhutilSimpleOptions::parse($options) + array('minify' => false, 'name' => $name);
         $xformer = new CelerityResourceTransformer();
         $xformer->setRawResourceMap(array('/rsrc/example.png' => array('uri' => '/res/hash/example.png')));
         $xformer->setMinify($options['minify']);
         $result = $xformer->transformResource($options['name'], $in);
         $this->assertEqual(rtrim($expect), rtrim($result), $file);
     }
 }
 private function composeImage($color, $icon_data)
 {
     $icon_img = imagecreatefromstring($icon_data);
     $map = CelerityResourceTransformer::getCSSVariableMap();
     $color_string = idx($map, $color, '#ff00ff');
     $color_const = hexdec(trim($color_string, '#'));
     $canvas = imagecreatetruecolor(100, 100);
     imagefill($canvas, 0, 0, $color_const);
     imagecopy($canvas, $icon_img, 0, 0, 0, 0, 100, 100);
     return PhabricatorImageTransformer::saveImageDataInAnyFormat($canvas, 'image/png');
 }
 protected function serveResource(array $spec)
 {
     $path = $spec['path'];
     $hash = idx($spec, 'hash');
     // Sanity checking to keep this from exposing anything sensitive, since it
     // ultimately boils down to disk reads.
     if (preg_match('@(//|\\.\\.)@', $path)) {
         return new Aphront400Response();
     }
     $type = CelerityResourceTransformer::getResourceType($path);
     $type_map = self::getSupportedResourceTypes();
     if (empty($type_map[$type])) {
         throw new Exception(pht('Only static resources may be served.'));
     }
     $dev_mode = PhabricatorEnv::getEnvConfig('phabricator.developer-mode');
     $map = $this->getCelerityResourceMap();
     $expect_hash = $map->getHashForName($path);
     // Test if the URI hash is correct for our current resource map. If it
     // is not, refuse to cache this resource. This avoids poisoning caches
     // and CDNs if we're getting a request for a new resource to an old node
     // shortly after a push.
     $is_cacheable = $hash === $expect_hash;
     $is_locally_cacheable = $this->isLocallyCacheableResourceType($type);
     if (AphrontRequest::getHTTPHeader('If-Modified-Since') && $is_cacheable) {
         // Return a "304 Not Modified". We don't care about the value of this
         // field since we never change what resource is served by a given URI.
         return $this->makeResponseCacheable(new Aphront304Response());
     }
     $cache = null;
     $data = null;
     if ($is_cacheable && $is_locally_cacheable && !$dev_mode) {
         $cache = PhabricatorCaches::getImmutableCache();
         $request_path = $this->getRequest()->getPath();
         $cache_key = $this->getCacheKey($request_path);
         $data = $cache->getKey($cache_key);
     }
     if ($data === null) {
         if ($map->isPackageResource($path)) {
             $resource_names = $map->getResourceNamesForPackageName($path);
             if (!$resource_names) {
                 return new Aphront404Response();
             }
             try {
                 $data = array();
                 foreach ($resource_names as $resource_name) {
                     $data[] = $map->getResourceDataForName($resource_name);
                 }
                 $data = implode("\n\n", $data);
             } catch (Exception $ex) {
                 return new Aphront404Response();
             }
         } else {
             try {
                 $data = $map->getResourceDataForName($path);
             } catch (Exception $ex) {
                 return new Aphront404Response();
             }
         }
         $xformer = $this->buildResourceTransformer();
         if ($xformer) {
             $data = $xformer->transformResource($path, $data);
         }
         if ($cache) {
             $cache->setKey($cache_key, $data);
         }
     }
     $response = new AphrontFileResponse();
     $response->setContent($data);
     $response->setMimeType($type_map[$type]);
     // NOTE: This is a piece of magic required to make WOFF fonts work in
     // Firefox and IE. Possibly we should generalize this more.
     $cross_origin_types = array('woff' => true, 'woff2' => true, 'eot' => true);
     if (isset($cross_origin_types[$type])) {
         // We could be more tailored here, but it's not currently trivial to
         // generate a comprehensive list of valid origins (an install may have
         // arbitrarily many Phame blogs, for example), and we lose nothing by
         // allowing access from anywhere.
         $response->addAllowOrigin('*');
     }
     if ($is_cacheable) {
         $response = $this->makeResponseCacheable($response);
     }
     return $response;
 }
Example #6
0
$file_map = array();
foreach ($files as $path => $raw_hash) {
    echo ".";
    $path = '/' . Filesystem::readablePath($path, $root);
    $data = Filesystem::readFile($root . $path);
    $data = $xformer->transformResource($path, $data);
    $hash = md5($data);
    $hash = md5($hash . $path . $resource_hash);
    $file_map[$path] = array('hash' => $hash, 'disk' => $path);
}
echo "\n";
$resource_graph = array();
$hash_map = array();
$parser = new PhutilDocblockParser();
foreach ($file_map as $path => $info) {
    $type = CelerityResourceTransformer::getResourceType($path);
    $data = Filesystem::readFile($root . $info['disk']);
    $matches = array();
    $ok = preg_match('@/[*][*].*?[*]/@s', $data, $matches);
    if (!$ok) {
        throw new Exception("File {$path} does not have a header doc comment. Encode dependency " . "data in a header docblock.");
    }
    list($description, $metadata) = $parser->parse($matches[0]);
    $provides = preg_split('/\\s+/', trim(idx($metadata, 'provides')));
    $requires = preg_split('/\\s+/', trim(idx($metadata, 'requires')));
    $provides = array_filter($provides);
    $requires = array_filter($requires);
    if (!$provides) {
        // Tests and documentation-only JS is permitted to @provide no targets.
        continue;
    }
Example #7
0
 public function getResourceType($path)
 {
     return CelerityResourceTransformer::getResourceType($path);
 }
 /**
  * Find text resources (like JS and CSS) and return information about them.
  *
  * @param CelerityPhysicalResources Resource map to find text resources for.
  * @param CelerityResourceTransformer Configured resource transformer.
  * @return map<string, map<string, string>> Resource information map.
  */
 private function rebuildTextResources(CelerityPhysicalResources $resources, CelerityResourceTransformer $xformer)
 {
     $text_map = $resources->findTextResources();
     $result_map = array();
     foreach ($text_map as $name => $data_hash) {
         $raw_data = $resources->getResourceData($name);
         $xformed_data = $xformer->transformResource($name, $raw_data);
         $data_hash = $resources->getCelerityHash($xformed_data);
         $hash = $resources->getCelerityHash($data_hash . $name);
         list($provides, $requires) = $this->getProvidesAndRequires($name, $raw_data);
         $result_map[$name] = array('hash' => $hash);
         if ($provides !== null) {
             $result_map[$name] += array('provides' => $provides, 'requires' => $requires);
         }
     }
     return $result_map;
 }