@recaptime-dev's working patches + fork for Phorge, a community fork of Phabricator. (Upstream dev and stable branches are at upstream/main and upstream/stable respectively.) hq.recaptime.dev/wiki/Phorge
phorge phabricator
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Enforce upload size limits and transport exceptions with appropriate response encoding

Summary:
- When a user uploads an oversized file, throw an exception.
- When an uncaught exception occurs during a Conduit request, return a Conduit response.
- When an uncaught exception occurs during a non-workflow Ajax request, return an Ajax response.

Test Plan:
- Uploaded overlarge files.
- Hit an exception page with ?__ajax__=1 and ?__conduit__=1

Reviewers: btrahan, vrana, jungejason

Reviewed By: btrahan

CC: aran

Maniphest Tasks: T875, T788

Differential Revision: https://secure.phabricator.com/D2385

+66 -4
+23 -1
src/aphront/default/configuration/AphrontDefaultApplicationConfiguration.php
··· 455 455 } 456 456 457 457 public function handleException(Exception $ex) { 458 + $request = $this->getRequest(); 459 + 460 + // For Conduit requests, return a Conduit response. 461 + if ($request->isConduit()) { 462 + $response = new ConduitAPIResponse(); 463 + $response->setErrorCode(get_class($ex)); 464 + $response->setErrorInfo($ex->getMessage()); 465 + 466 + return id(new AphrontJSONResponse()) 467 + ->setContent($response->toDictionary()); 468 + } 469 + 470 + // For non-workflow requests, return a Ajax response. 471 + if ($request->isAjax() && !$request->isJavelinWorkflow()) { 472 + $response = new AphrontAjaxResponse(); 473 + $response->setError( 474 + array( 475 + 'code' => get_class($ex), 476 + 'info' => $ex->getMessage(), 477 + )); 478 + return $response; 479 + } 458 480 459 481 $is_serious = PhabricatorEnv::getEnvConfig('phabricator.serious-business'); 460 482 461 - $user = $this->getRequest()->getUser(); 483 + $user = $request->getUser(); 462 484 if (!$user) { 463 485 // If we hit an exception very early, we won't have a user. 464 486 $user = new PhabricatorUser();
+2
src/aphront/default/configuration/__init__.php
··· 10 10 phutil_require_module('phabricator', 'aphront/request'); 11 11 phutil_require_module('phabricator', 'aphront/response/ajax'); 12 12 phutil_require_module('phabricator', 'aphront/response/dialog'); 13 + phutil_require_module('phabricator', 'aphront/response/json'); 13 14 phutil_require_module('phabricator', 'aphront/response/webpage'); 14 15 phutil_require_module('phabricator', 'applications/base/controller/404'); 15 16 phutil_require_module('phabricator', 'applications/base/controller/redirect'); 17 + phutil_require_module('phabricator', 'applications/conduit/protocol/response'); 16 18 phutil_require_module('phabricator', 'applications/people/storage/user'); 17 19 phutil_require_module('phabricator', 'infrastructure/env'); 18 20 phutil_require_module('phabricator', 'view/control/table');
+10
src/aphront/request/AphrontRequest.php
··· 24 24 */ 25 25 final class AphrontRequest { 26 26 27 + // NOTE: These magic request-type parameters are automatically included in 28 + // certain requests (e.g., by phabricator_render_form(), JX.Request, 29 + // JX.Workflow, and ConduitClient) and help us figure out what sort of 30 + // response the client expects. 31 + 27 32 const TYPE_AJAX = '__ajax__'; 28 33 const TYPE_FORM = '__form__'; 29 34 const TYPE_CONDUIT = '__conduit__'; 35 + const TYPE_WORKFLOW = '__wflow__'; 30 36 31 37 private $host; 32 38 private $path; ··· 169 175 170 176 final public function isAjax() { 171 177 return $this->getExists(self::TYPE_AJAX); 178 + } 179 + 180 + final public function isJavelinWorkflow() { 181 + return $this->getExists(self::TYPE_WORKFLOW); 172 182 } 173 183 174 184 final public function isConduit() {
+5
src/aphront/response/ajax/AphrontAjaxResponse.php
··· 29 29 return $this; 30 30 } 31 31 32 + public function setError($error) { 33 + $this->error = $error; 34 + return $this; 35 + } 36 + 32 37 public function buildResponseString() { 33 38 $response = CelerityAPI::getStaticResourceResponse(); 34 39 $object = $response->buildAjaxResponse(
+1 -1
src/applications/files/controller/dropupload/PhabricatorFileDropUploadController.php
··· 29 29 $data = file_get_contents('php://input'); 30 30 $name = $request->getStr('name'); 31 31 32 - $file = PhabricatorFile::newFromFileData( 32 + $file = PhabricatorFile::newFromXHRUpload( 33 33 $data, 34 34 array( 35 35 'name' => $request->getStr('name'),
+5 -1
src/applications/files/exception/upload/PhabricatorFileUploadException.php
··· 1 1 <?php 2 2 3 3 /* 4 - * Copyright 2011 Facebook, Inc. 4 + * Copyright 2012 Facebook, Inc. 5 5 * 6 6 * Licensed under the Apache License, Version 2.0 (the "License"); 7 7 * you may not use this file except in compliance with the License. ··· 35 35 "Unable to write file: failed to write to temporary directory.", 36 36 UPLOAD_ERR_EXTENSION => 37 37 "Unable to upload: a PHP extension stopped the upload.", 38 + 39 + -1000 => 40 + "Uploaded file exceeds limit in Phabricator ". 41 + "'storage.upload-size-limit' configuration.", 38 42 ); 39 43 40 44 $message = idx($map, $code, "Upload failed: unknown error.");
+19 -1
src/applications/files/storage/file/PhabricatorFile.php
··· 66 66 throw new Exception("File size disagrees with uploaded size."); 67 67 } 68 68 69 + self::validateFileSize(strlen($file_data)); 70 + 69 71 return $file_data; 70 72 } 71 73 ··· 82 84 return self::newFromFileData($file_data, $params); 83 85 } 84 86 85 - public static function newFromFileData($data, array $params = array()) { 87 + public static function newFromXHRUpload($data, array $params = array()) { 88 + self::validateFileSize(strlen($data)); 89 + return self::newFromFileData($data, $params); 90 + } 86 91 92 + private static function validateFileSize($size) { 93 + $limit = PhabricatorEnv::getEnvConfig('storage.upload-size-limit'); 94 + if (!$limit) { 95 + return; 96 + } 97 + 98 + $limit = phabricator_parse_bytes($limit); 99 + if ($size > $limit) { 100 + throw new PhabricatorFileUploadException(-1000); 101 + } 102 + } 103 + 104 + public static function newFromFileData($data, array $params = array()) { 87 105 $selector = PhabricatorEnv::newObjectFromConfig('storage.engine-selector'); 88 106 89 107 $engines = $selector->selectStorageEngines($data, $params);
+1
src/applications/files/storage/file/__init__.php
··· 13 13 phutil_require_module('phabricator', 'applications/phid/storage/phid'); 14 14 phutil_require_module('phabricator', 'infrastructure/env'); 15 15 phutil_require_module('phabricator', 'infrastructure/util/hash'); 16 + phutil_require_module('phabricator', 'view/utils'); 16 17 17 18 phutil_require_module('phutil', 'error'); 18 19 phutil_require_module('phutil', 'error/aggregate');