public function processRequest()
 {
     $alt = PhabricatorEnv::getEnvConfig('security.alternate-file-domain');
     if (!$alt) {
         return new Aphront400Response();
     }
     $request = $this->getRequest();
     $alt_domain = id(new PhutilURI($alt))->getDomain();
     if ($alt_domain != $request->getHost()) {
         return new Aphront400Response();
     }
     $file = id(new PhabricatorFile())->loadOneWhere('phid = %s', $this->phid);
     if (!$file) {
         return new Aphront404Response();
     }
     if (!$file->validateSecretKey($this->key)) {
         return new Aphront404Response();
     }
     // It's safe to bypass view restrictions because we know we are being served
     // off an alternate domain which we will not set cookies on.
     $data = $file->loadFileData();
     $response = new AphrontFileResponse();
     $response->setContent($data);
     $response->setMimeType($file->getMimeType());
     $response->setCacheDurationInSeconds(60 * 60 * 24 * 30);
     return $response;
 }
 public function processRequest()
 {
     $path = $this->path;
     // Sanity checking to keep this from exposing anything sensitive.
     $path = preg_replace('@(//|\\.\\.)@', '', $path);
     $matches = null;
     if (!preg_match('/\\.(css|js)$/', $path, $matches)) {
         throw new Exception("Only CSS and JS 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());
     }
     $type = $matches[1];
     $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 $path) {
                 $data[] = Filesystem::readFile($root . '/webroot/' . $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();
         }
     }
     $response = new AphrontFileResponse();
     $response->setContent($data);
     switch ($type) {
         case 'css':
             $response->setMimeType("text/css; charset=utf-8");
             break;
         case 'js':
             $response->setMimeType("text/javascript; charset=utf-8");
             break;
     }
     return $this->makeResponseCacheable($response);
 }
 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 processRequest()
 {
     // Build the view selection form.
     $select_map = array('highlighted' => 'View as Highlighted Text', 'blame' => 'View as Highlighted Text with Blame', 'plain' => 'View as Plain Text', 'plainblame' => 'View as Plain Text with Blame', 'raw' => 'View as raw document');
     $request = $this->getRequest();
     $drequest = $this->getDiffusionRequest();
     $path = $drequest->getPath();
     $selected = $request->getStr('view');
     $needs_blame = $selected == 'blame' || $selected == 'plainblame';
     $file_query = DiffusionFileContentQuery::newFromDiffusionRequest($this->diffusionRequest);
     $file_query->setNeedsBlame($needs_blame);
     $file_query->loadFileContent();
     $data = $file_query->getRawData();
     if ($selected === 'raw') {
         $response = new AphrontFileResponse();
         $response->setContent($data);
         $mime_type = $this->getDocumentType($path);
         if ($mime_type) {
             $response->setMimeType($mime_type);
         } else {
             $as_filename = idx(pathinfo($path), 'basename');
             $response->setDownload($as_filename);
         }
         return $response;
     }
     $select = '<select name="view">';
     foreach ($select_map as $k => $v) {
         $option = phutil_render_tag('option', array('value' => $k, 'selected' => $k == $selected ? 'selected' : null), phutil_escape_html($v));
         $select .= $option;
     }
     $select .= '</select>';
     require_celerity_resource('diffusion-source-css');
     $view_select_panel = new AphrontPanelView();
     $view_select_form = phutil_render_tag('form', array('action' => $request->getRequestURI(), 'method' => 'get', 'class' => 'diffusion-browse-type-form'), $select . '<button>View</button>');
     $view_select_panel->appendChild($view_select_form);
     $view_select_panel->appendChild('<div style="clear: both;"></div>');
     // Build the content of the file.
     $corpus = $this->buildCorpus($selected, $file_query, $needs_blame, $drequest, $path, $data);
     // Render the page.
     $content = array();
     $content[] = $this->buildCrumbs(array('branch' => true, 'path' => true, 'view' => 'browse'));
     $content[] = $view_select_panel;
     $content[] = $corpus;
     $content[] = $this->buildOpenRevisions();
     $nav = $this->buildSideNav('browse', true);
     $nav->appendChild($content);
     $basename = basename($this->getDiffusionRequest()->getPath());
     return $this->buildStandardPageResponse($nav, array('title' => $basename));
 }
 public function processRequest()
 {
     $request = $this->getRequest();
     $alt = PhabricatorEnv::getEnvConfig('security.alternate-file-domain');
     $uri = new PhutilURI($alt);
     $alt_domain = $uri->getDomain();
     if ($alt_domain && $alt_domain != $request->getHost()) {
         return id(new AphrontRedirectResponse())->setURI($uri->setPath($request->getPath()));
     }
     $file = id(new PhabricatorFile())->loadOneWhere('phid = %s', $this->phid);
     if (!$file) {
         return new Aphront404Response();
     }
     if (!$file->validateSecretKey($this->key)) {
         return new Aphront403Response();
     }
     $data = $file->loadFileData();
     $response = new AphrontFileResponse();
     $response->setContent($data);
     $response->setCacheDurationInSeconds(60 * 60 * 24 * 30);
     $is_view = $file->isViewableInBrowser();
     if ($is_view) {
         $response->setMimeType($file->getViewableMimeType());
     } else {
         if (!$request->isHTTPPost()) {
             // NOTE: Require POST to download files. We'd rather go full-bore and
             // do a real CSRF check, but can't currently authenticate users on the
             // file domain. This should blunt any attacks based on iframes, script
             // tags, applet tags, etc., at least. Send the user to the "info" page
             // if they're using some other method.
             return id(new AphrontRedirectResponse())->setURI(PhabricatorEnv::getProductionURI($file->getBestURI()));
         }
         $response->setMimeType($file->getMimeType());
         $response->setDownload($file->getName());
     }
     return $response;
 }
 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;
 }
 public function processRequest()
 {
     $request = $this->getRequest();
     $user = $request->getUser();
     $file = id(new PhabricatorFile())->loadOneWhere('phid = %s', $this->phid);
     if (!$file) {
         return new Aphront404Response();
     }
     switch ($this->view) {
         case 'download':
         case 'view':
             $data = $file->loadFileData();
             $response = new AphrontFileResponse();
             $response->setContent($data);
             $response->setCacheDurationInSeconds(60 * 60 * 24 * 30);
             if ($this->view == 'view') {
                 if (!$file->isViewableInBrowser()) {
                     return new Aphront400Response();
                 }
                 $download = false;
             } else {
                 $download = true;
             }
             if ($download) {
                 if (!$request->isFormPost()) {
                     // Require a POST to download files to hinder attacks where you
                     // <applet src="http://phabricator.example.com/file/..." /> on some
                     // other domain.
                     return id(new AphrontRedirectResponse())->setURI($file->getInfoURI());
                 }
             }
             if ($download) {
                 $mime_type = $file->getMimeType();
             } else {
                 $mime_type = $file->getViewableMimeType();
             }
             // If an alternate file domain is configured, forbid all views which
             // don't originate from it.
             if (!$download) {
                 $alt = PhabricatorEnv::getEnvConfig('security.alternate-file-domain');
                 if ($alt) {
                     $domain = id(new PhutilURI($alt))->getDomain();
                     if ($domain != $request->getHost()) {
                         return new Aphront400Response();
                     }
                 }
             }
             $response->setMimeType($mime_type);
             if ($download) {
                 $response->setDownload($file->getName());
             }
             return $response;
         default:
             break;
     }
     $author_child = null;
     if ($file->getAuthorPHID()) {
         $author = id(new PhabricatorUser())->loadOneWhere('phid = %s', $file->getAuthorPHID());
         if ($author) {
             $author_child = id(new AphrontFormStaticControl())->setLabel('Author')->setName('author')->setValue($author->getUserName());
         }
     }
     $form = new AphrontFormView();
     if ($file->isViewableInBrowser()) {
         $form->setAction($file->getViewURI());
         $button_name = 'View File';
     } else {
         $form->setAction('/file/download/' . $file->getPHID() . '/');
         $button_name = 'Download File';
     }
     $file_id = 'F' . $file->getID();
     $form->setUser($user);
     $form->appendChild(id(new AphrontFormStaticControl())->setLabel('Name')->setName('name')->setValue($file->getName()))->appendChild(id(new AphrontFormStaticControl())->setLabel('ID')->setName('id')->setValue($file_id)->setCaption('Download this file with: <tt>arc download ' . phutil_escape_html($file_id) . '</tt>'))->appendChild(id(new AphrontFormStaticControl())->setLabel('PHID')->setName('phid')->setValue($file->getPHID()))->appendChild($author_child)->appendChild(id(new AphrontFormStaticControl())->setLabel('Created')->setName('created')->setValue(phabricator_datetime($file->getDateCreated(), $user)))->appendChild(id(new AphrontFormStaticControl())->setLabel('Mime Type')->setName('mime')->setValue($file->getMimeType()))->appendChild(id(new AphrontFormStaticControl())->setLabel('Size')->setName('size')->setValue($file->getByteSize() . ' bytes'))->appendChild(id(new AphrontFormStaticControl())->setLabel('Engine')->setName('storageEngine')->setValue($file->getStorageEngine()))->appendChild(id(new AphrontFormStaticControl())->setLabel('Format')->setName('storageFormat')->setValue($file->getStorageFormat()))->appendChild(id(new AphrontFormStaticControl())->setLabel('Handle')->setName('storageHandle')->setValue($file->getStorageHandle()))->appendChild(id(new AphrontFormSubmitControl())->setValue($button_name));
     $panel = new AphrontPanelView();
     $panel->setHeader('File Info - ' . $file->getName());
     $panel->appendChild($form);
     $panel->setWidth(AphrontPanelView::WIDTH_FORM);
     $transformations = id(new PhabricatorTransformedFile())->loadAllWhere('originalPHID = %s', $file->getPHID());
     $rows = array();
     foreach ($transformations as $transformed) {
         $phid = $transformed->getTransformedPHID();
         $rows[] = array(phutil_escape_html($transformed->getTransform()), phutil_render_tag('a', array('href' => PhabricatorFileURI::getViewURIForPHID($phid)), $phid));
     }
     $table = new AphrontTableView($rows);
     $table->setHeaders(array('Transform', 'File'));
     $xform_panel = new AphrontPanelView();
     $xform_panel->appendChild($table);
     $xform_panel->setWidth(AphrontPanelView::WIDTH_FORM);
     $xform_panel->setHeader('Transformations');
     return $this->buildStandardPageResponse(array($panel, $xform_panel), array('title' => 'File Info - ' . $file->getName()));
 }
 public function processRequest()
 {
     $request = $this->getRequest();
     $viewer = $this->getViewer();
     $alt = PhabricatorEnv::getEnvConfig('security.alternate-file-domain');
     $base_uri = PhabricatorEnv::getEnvConfig('phabricator.base-uri');
     $alt_uri = new PhutilURI($alt);
     $alt_domain = $alt_uri->getDomain();
     $req_domain = $request->getHost();
     $main_domain = id(new PhutilURI($base_uri))->getDomain();
     $cache_response = true;
     if (empty($alt) || $main_domain == $alt_domain) {
         // Alternate files domain isn't configured or it's set
         // to the same as the default domain
         $response = $this->loadFile($viewer);
         if ($response) {
             return $response;
         }
         $file = $this->getFile();
         // when the file is not CDNable, don't allow cache
         $cache_response = $file->getCanCDN();
     } else {
         if ($req_domain != $alt_domain) {
             // Alternate domain is configured but this request isn't using it
             $response = $this->loadFile($viewer);
             if ($response) {
                 return $response;
             }
             $file = $this->getFile();
             // if the user can see the file, generate a token;
             // redirect to the alt domain with the token;
             $token_uri = $file->getCDNURIWithToken();
             $token_uri = new PhutilURI($token_uri);
             $token_uri = $this->addURIParameters($token_uri);
             return id(new AphrontRedirectResponse())->setIsExternal(true)->setURI($token_uri);
         } else {
             // We are using the alternate domain. We don't have authentication
             // on this domain, so we bypass policy checks when loading the file.
             $bypass_policies = PhabricatorUser::getOmnipotentUser();
             $response = $this->loadFile($bypass_policies);
             if ($response) {
                 return $response;
             }
             $file = $this->getFile();
             $acquire_token_uri = id(new PhutilURI($file->getViewURI()))->setDomain($main_domain);
             $acquire_token_uri = $this->addURIParameters($acquire_token_uri);
             if ($this->token) {
                 // validate the token, if it is valid, continue
                 $validated_token = $file->validateOneTimeToken($this->token);
                 if (!$validated_token) {
                     $dialog = $this->newDialog()->setShortTitle(pht('Expired File'))->setTitle(pht('File Link Has Expired'))->appendParagraph(pht('The link you followed to view this file is invalid or ' . 'expired.'))->appendParagraph(pht('Continue to generate a new link to the file. You may be ' . 'required to log in.'))->addCancelButton($acquire_token_uri, pht('Continue'));
                     // Build an explicit response so we can respond with HTTP/403 instead
                     // of HTTP/200.
                     $response = id(new AphrontDialogResponse())->setDialog($dialog)->setHTTPResponseCode(403);
                     return $response;
                 }
                 // return the file data without cache headers
                 $cache_response = false;
             } else {
                 if (!$file->getCanCDN()) {
                     // file cannot be served via cdn, and no token given
                     // redirect to the main domain to aquire a token
                     // This is marked as an "external" URI because it is fully qualified.
                     return id(new AphrontRedirectResponse())->setIsExternal(true)->setURI($acquire_token_uri);
                 }
             }
         }
     }
     $response = new AphrontFileResponse();
     if ($cache_response) {
         $response->setCacheDurationInSeconds(60 * 60 * 24 * 30);
     }
     $begin = null;
     $end = null;
     // NOTE: It's important to accept "Range" requests when playing audio.
     // If we don't, Safari has difficulty figuring out how long sounds are
     // and glitches when trying to loop them. In particular, Safari sends
     // an initial request for bytes 0-1 of the audio file, and things go south
     // if we can't respond with a 206 Partial Content.
     $range = $request->getHTTPHeader('range');
     if ($range) {
         $matches = null;
         if (preg_match('/^bytes=(\\d+)-(\\d+)$/', $range, $matches)) {
             // Note that the "Range" header specifies bytes differently than
             // we do internally: the range 0-1 has 2 bytes (byte 0 and byte 1).
             $begin = (int) $matches[1];
             $end = (int) $matches[2] + 1;
             $response->setHTTPResponseCode(206);
             $response->setRange($begin, $end - 1);
         }
     } else {
         if (isset($validated_token)) {
             // We set this on the response, and the response deletes it after the
             // transfer completes. This allows transfers to be resumed, in theory.
             $response->setTemporaryFileToken($validated_token);
         }
     }
     $is_viewable = $file->isViewableInBrowser();
     $force_download = $request->getExists('download');
     if ($is_viewable && !$force_download) {
         $response->setMimeType($file->getViewableMimeType());
     } else {
         if (!$request->isHTTPPost() && !$alt_domain) {
             // NOTE: Require POST to download files from the primary domain. We'd
             // rather go full-bore and do a real CSRF check, but can't currently
             // authenticate users on the file domain. This should blunt any
             // attacks based on iframes, script tags, applet tags, etc., at least.
             // Send the user to the "info" page if they're using some other method.
             // This is marked as "external" because it is fully qualified.
             return id(new AphrontRedirectResponse())->setIsExternal(true)->setURI(PhabricatorEnv::getProductionURI($file->getBestURI()));
         }
         $response->setMimeType($file->getMimeType());
         $response->setDownload($file->getName());
     }
     $iterator = $file->getFileDataIterator($begin, $end);
     $response->setContentLength($file->getByteSize());
     $response->setContentIterator($iterator);
     return $response;
 }
 public function handleRequest(AphrontRequest $request)
 {
     $viewer = $request->getViewer();
     $this->phid = $request->getURIData('phid');
     $this->key = $request->getURIData('key');
     $alt = PhabricatorEnv::getEnvConfig('security.alternate-file-domain');
     $base_uri = PhabricatorEnv::getEnvConfig('phabricator.base-uri');
     $alt_uri = new PhutilURI($alt);
     $alt_domain = $alt_uri->getDomain();
     $req_domain = $request->getHost();
     $main_domain = id(new PhutilURI($base_uri))->getDomain();
     if (!strlen($alt) || $main_domain == $alt_domain) {
         // No alternate domain.
         $should_redirect = false;
         $is_alternate_domain = false;
     } else {
         if ($req_domain != $alt_domain) {
             // Alternate domain, but this request is on the main domain.
             $should_redirect = true;
             $is_alternate_domain = false;
         } else {
             // Alternate domain, and on the alternate domain.
             $should_redirect = false;
             $is_alternate_domain = true;
         }
     }
     $response = $this->loadFile();
     if ($response) {
         return $response;
     }
     $file = $this->getFile();
     if ($should_redirect) {
         return id(new AphrontRedirectResponse())->setIsExternal(true)->setURI($file->getCDNURI());
     }
     $response = new AphrontFileResponse();
     $response->setCacheDurationInSeconds(60 * 60 * 24 * 30);
     $response->setCanCDN($file->getCanCDN());
     $begin = null;
     $end = null;
     // NOTE: It's important to accept "Range" requests when playing audio.
     // If we don't, Safari has difficulty figuring out how long sounds are
     // and glitches when trying to loop them. In particular, Safari sends
     // an initial request for bytes 0-1 of the audio file, and things go south
     // if we can't respond with a 206 Partial Content.
     $range = $request->getHTTPHeader('range');
     if ($range) {
         $matches = null;
         if (preg_match('/^bytes=(\\d+)-(\\d+)$/', $range, $matches)) {
             // Note that the "Range" header specifies bytes differently than
             // we do internally: the range 0-1 has 2 bytes (byte 0 and byte 1).
             $begin = (int) $matches[1];
             $end = (int) $matches[2] + 1;
             $response->setHTTPResponseCode(206);
             $response->setRange($begin, $end - 1);
         }
     }
     $is_viewable = $file->isViewableInBrowser();
     $force_download = $request->getExists('download');
     $request_type = $request->getHTTPHeader('X-Phabricator-Request-Type');
     $is_lfs = $request_type == 'git-lfs';
     if ($is_viewable && !$force_download) {
         $response->setMimeType($file->getViewableMimeType());
     } else {
         if (!$request->isHTTPPost() && !$is_alternate_domain && !$is_lfs) {
             // NOTE: Require POST to download files from the primary domain. We'd
             // rather go full-bore and do a real CSRF check, but can't currently
             // authenticate users on the file domain. This should blunt any
             // attacks based on iframes, script tags, applet tags, etc., at least.
             // Send the user to the "info" page if they're using some other method.
             // This is marked as "external" because it is fully qualified.
             return id(new AphrontRedirectResponse())->setIsExternal(true)->setURI(PhabricatorEnv::getProductionURI($file->getBestURI()));
         }
         $response->setMimeType($file->getMimeType());
         $response->setDownload($file->getName());
     }
     $iterator = $file->getFileDataIterator($begin, $end);
     $response->setContentLength($file->getByteSize());
     $response->setContentIterator($iterator);
     return $response;
 }
 public function processRequest()
 {
     $request = $this->getRequest();
     $user = $request->getUser();
     $file = id(new PhabricatorFile())->loadOneWhere('phid = %s', $this->phid);
     if (!$file) {
         return new Aphront404Response();
     }
     switch ($this->view) {
         case 'download':
         case 'view':
             $data = $file->loadFileData();
             $response = new AphrontFileResponse();
             $response->setContent($data);
             $response->setCacheDurationInSeconds(60 * 60 * 24 * 30);
             if ($this->view == 'view') {
                 if (!$file->isViewableInBrowser()) {
                     return new Aphront400Response();
                 }
                 $download = false;
             } else {
                 $download = true;
             }
             if ($download) {
                 $mime_type = $file->getMimeType();
             } else {
                 $mime_type = $file->getViewableMimeType();
             }
             $response->setMimeType($mime_type);
             if ($download) {
                 $response->setDownload($file->getName());
             }
             return $response;
         default:
             break;
     }
     $author_child = null;
     if ($file->getAuthorPHID()) {
         $author = id(new PhabricatorUser())->loadOneWhere('phid = %s', $file->getAuthorPHID());
         if ($author) {
             $author_child = id(new AphrontFormStaticControl())->setLabel('Author')->setName('author')->setValue($author->getUserName());
         }
     }
     $form = new AphrontFormView();
     if ($file->isViewableInBrowser()) {
         $form->setAction('/file/view/' . $file->getPHID() . '/');
         $button_name = 'View File';
     } else {
         $form->setAction('/file/download/' . $file->getPHID() . '/');
         $button_name = 'Download File';
     }
     $file_id = 'F' . $file->getID();
     $form->setUser($user);
     $form->appendChild(id(new AphrontFormStaticControl())->setLabel('Name')->setName('name')->setValue($file->getName()))->appendChild(id(new AphrontFormStaticControl())->setLabel('ID')->setName('id')->setValue($file_id)->setCaption('Download this file with: <tt>arc download ' . phutil_escape_html($file_id) . '</tt>'))->appendChild(id(new AphrontFormStaticControl())->setLabel('PHID')->setName('phid')->setValue($file->getPHID()))->appendChild($author_child)->appendChild(id(new AphrontFormStaticControl())->setLabel('Created')->setName('created')->setValue(phabricator_datetime($file->getDateCreated(), $user)))->appendChild(id(new AphrontFormStaticControl())->setLabel('Mime Type')->setName('mime')->setValue($file->getMimeType()))->appendChild(id(new AphrontFormStaticControl())->setLabel('Size')->setName('size')->setValue($file->getByteSize() . ' bytes'))->appendChild(id(new AphrontFormStaticControl())->setLabel('Engine')->setName('storageEngine')->setValue($file->getStorageEngine()))->appendChild(id(new AphrontFormStaticControl())->setLabel('Format')->setName('storageFormat')->setValue($file->getStorageFormat()))->appendChild(id(new AphrontFormStaticControl())->setLabel('Handle')->setName('storageHandle')->setValue($file->getStorageHandle()))->appendChild(id(new AphrontFormSubmitControl())->setValue($button_name));
     $panel = new AphrontPanelView();
     $panel->setHeader('File Info - ' . $file->getName());
     $panel->appendChild($form);
     $panel->setWidth(AphrontPanelView::WIDTH_FORM);
     $transformations = id(new PhabricatorTransformedFile())->loadAllWhere('originalPHID = %s', $file->getPHID());
     $rows = array();
     foreach ($transformations as $transformed) {
         $phid = $transformed->getTransformedPHID();
         $rows[] = array(phutil_escape_html($transformed->getTransform()), phutil_render_tag('a', array('href' => PhabricatorFileURI::getViewURIForPHID($phid)), $phid));
     }
     $table = new AphrontTableView($rows);
     $table->setHeaders(array('Transform', 'File'));
     $xform_panel = new AphrontPanelView();
     $xform_panel->appendChild($table);
     $xform_panel->setWidth(AphrontPanelView::WIDTH_FORM);
     $xform_panel->setHeader('Transformations');
     return $this->buildStandardPageResponse(array($panel, $xform_panel), array('title' => 'File Info - ' . $file->getName()));
 }