1
0
Fork 0
mirror of https://we.phorge.it/source/phorge.git synced 2024-11-22 14:52:41 +01:00

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
This commit is contained in:
epriestley 2012-05-07 06:17:00 -07:00
parent b80ea9e0e8
commit 7b5f47b17d
9 changed files with 67 additions and 5 deletions

2
externals/javelin vendored

@ -1 +1 @@
Subproject commit 748eac2b2fb3f210dc68506d2bc36f96a6b0d77f
Subproject commit 1cdedbfc00a32f3167aa3bc14dd917cf886014ff

View file

@ -455,10 +455,32 @@ class AphrontDefaultApplicationConfiguration
}
public function handleException(Exception $ex) {
$request = $this->getRequest();
// For Conduit requests, return a Conduit response.
if ($request->isConduit()) {
$response = new ConduitAPIResponse();
$response->setErrorCode(get_class($ex));
$response->setErrorInfo($ex->getMessage());
return id(new AphrontJSONResponse())
->setContent($response->toDictionary());
}
// For non-workflow requests, return a Ajax response.
if ($request->isAjax() && !$request->isJavelinWorkflow()) {
$response = new AphrontAjaxResponse();
$response->setError(
array(
'code' => get_class($ex),
'info' => $ex->getMessage(),
));
return $response;
}
$is_serious = PhabricatorEnv::getEnvConfig('phabricator.serious-business');
$user = $this->getRequest()->getUser();
$user = $request->getUser();
if (!$user) {
// If we hit an exception very early, we won't have a user.
$user = new PhabricatorUser();

View file

@ -10,9 +10,11 @@ phutil_require_module('phabricator', 'aphront/applicationconfiguration');
phutil_require_module('phabricator', 'aphront/request');
phutil_require_module('phabricator', 'aphront/response/ajax');
phutil_require_module('phabricator', 'aphront/response/dialog');
phutil_require_module('phabricator', 'aphront/response/json');
phutil_require_module('phabricator', 'aphront/response/webpage');
phutil_require_module('phabricator', 'applications/base/controller/404');
phutil_require_module('phabricator', 'applications/base/controller/redirect');
phutil_require_module('phabricator', 'applications/conduit/protocol/response');
phutil_require_module('phabricator', 'applications/people/storage/user');
phutil_require_module('phabricator', 'infrastructure/env');
phutil_require_module('phabricator', 'view/control/table');

View file

@ -24,9 +24,15 @@
*/
final class AphrontRequest {
// NOTE: These magic request-type parameters are automatically included in
// certain requests (e.g., by phabricator_render_form(), JX.Request,
// JX.Workflow, and ConduitClient) and help us figure out what sort of
// response the client expects.
const TYPE_AJAX = '__ajax__';
const TYPE_FORM = '__form__';
const TYPE_CONDUIT = '__conduit__';
const TYPE_WORKFLOW = '__wflow__';
private $host;
private $path;
@ -171,6 +177,10 @@ final class AphrontRequest {
return $this->getExists(self::TYPE_AJAX);
}
final public function isJavelinWorkflow() {
return $this->getExists(self::TYPE_WORKFLOW);
}
final public function isConduit() {
return $this->getExists(self::TYPE_CONDUIT);
}

View file

@ -29,6 +29,11 @@ final class AphrontAjaxResponse extends AphrontResponse {
return $this;
}
public function setError($error) {
$this->error = $error;
return $this;
}
public function buildResponseString() {
$response = CelerityAPI::getStaticResourceResponse();
$object = $response->buildAjaxResponse(

View file

@ -29,7 +29,7 @@ final class PhabricatorFileDropUploadController
$data = file_get_contents('php://input');
$name = $request->getStr('name');
$file = PhabricatorFile::newFromFileData(
$file = PhabricatorFile::newFromXHRUpload(
$data,
array(
'name' => $request->getStr('name'),

View file

@ -1,7 +1,7 @@
<?php
/*
* Copyright 2011 Facebook, Inc.
* Copyright 2012 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -35,6 +35,10 @@ final class PhabricatorFileUploadException extends Exception {
"Unable to write file: failed to write to temporary directory.",
UPLOAD_ERR_EXTENSION =>
"Unable to upload: a PHP extension stopped the upload.",
-1000 =>
"Uploaded file exceeds limit in Phabricator ".
"'storage.upload-size-limit' configuration.",
);
$message = idx($map, $code, "Upload failed: unknown error.");

View file

@ -66,6 +66,8 @@ final class PhabricatorFile extends PhabricatorFileDAO {
throw new Exception("File size disagrees with uploaded size.");
}
self::validateFileSize(strlen($file_data));
return $file_data;
}
@ -82,8 +84,24 @@ final class PhabricatorFile extends PhabricatorFileDAO {
return self::newFromFileData($file_data, $params);
}
public static function newFromFileData($data, array $params = array()) {
public static function newFromXHRUpload($data, array $params = array()) {
self::validateFileSize(strlen($data));
return self::newFromFileData($data, $params);
}
private static function validateFileSize($size) {
$limit = PhabricatorEnv::getEnvConfig('storage.upload-size-limit');
if (!$limit) {
return;
}
$limit = phabricator_parse_bytes($limit);
if ($size > $limit) {
throw new PhabricatorFileUploadException(-1000);
}
}
public static function newFromFileData($data, array $params = array()) {
$selector = PhabricatorEnv::newObjectFromConfig('storage.engine-selector');
$engines = $selector->selectStorageEngines($data, $params);

View file

@ -13,6 +13,7 @@ phutil_require_module('phabricator', 'applications/phid/constants');
phutil_require_module('phabricator', 'applications/phid/storage/phid');
phutil_require_module('phabricator', 'infrastructure/env');
phutil_require_module('phabricator', 'infrastructure/util/hash');
phutil_require_module('phabricator', 'view/utils');
phutil_require_module('phutil', 'error');
phutil_require_module('phutil', 'error/aggregate');