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);
     }
 }
 /**
  * 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;
 }