diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -2938,6 +2938,7 @@ 'PhabricatorFileUploadDialogController' => 'applications/files/controller/PhabricatorFileUploadDialogController.php', 'PhabricatorFileUploadException' => 'applications/files/exception/PhabricatorFileUploadException.php', 'PhabricatorFileUploadSource' => 'applications/files/uploadsource/PhabricatorFileUploadSource.php', + 'PhabricatorFileUploadSourceByteLimitException' => 'applications/files/uploadsource/PhabricatorFileUploadSourceByteLimitException.php', 'PhabricatorFileinfoSetupCheck' => 'applications/config/check/PhabricatorFileinfoSetupCheck.php', 'PhabricatorFilesApplication' => 'applications/files/application/PhabricatorFilesApplication.php', 'PhabricatorFilesApplicationStorageEnginePanel' => 'applications/files/applicationpanel/PhabricatorFilesApplicationStorageEnginePanel.php', @@ -8362,6 +8363,7 @@ 'PhabricatorFileUploadDialogController' => 'PhabricatorFileController', 'PhabricatorFileUploadException' => 'Exception', 'PhabricatorFileUploadSource' => 'Phobject', + 'PhabricatorFileUploadSourceByteLimitException' => 'Exception', 'PhabricatorFileinfoSetupCheck' => 'PhabricatorSetupCheck', 'PhabricatorFilesApplication' => 'PhabricatorApplication', 'PhabricatorFilesApplicationStorageEnginePanel' => 'PhabricatorApplicationConfigurationPanel', diff --git a/src/applications/diffusion/query/DiffusionFileFutureQuery.php b/src/applications/diffusion/query/DiffusionFileFutureQuery.php --- a/src/applications/diffusion/query/DiffusionFileFutureQuery.php +++ b/src/applications/diffusion/query/DiffusionFileFutureQuery.php @@ -88,7 +88,7 @@ } final protected function executeQuery() { - $future = $this->newQueryFuture(); + $future = $this->newConfiguredQueryFuture(); $drequest = $this->getRequest(); @@ -105,6 +105,11 @@ ->setViewPolicy(PhabricatorPolicies::POLICY_NOONE) ->setExecFuture($future); + $byte_limit = $this->getByteLimit(); + if ($byte_limit) { + $source->setByteLimit($byte_limit); + } + $unguarded = AphrontWriteGuard::beginScopedUnguardedWrites(); $file = $source->uploadFile(); unset($unguarded); @@ -116,18 +121,8 @@ $this->didHitTimeLimit = true; $file = null; - } - - $byte_limit = $this->getByteLimit(); - - if ($byte_limit && ($file->getByteSize() > $byte_limit)) { + } catch (PhabricatorFileUploadSourceByteLimitException $ex) { $this->didHitByteLimit = true; - - $unguarded = AphrontWriteGuard::beginScopedUnguardedWrites(); - id(new PhabricatorDestructionEngine()) - ->destroyObject($file); - unset($unguarded); - $file = null; } @@ -141,11 +136,6 @@ $future->setTimeout($this->getTimeout()); } - $byte_limit = $this->getByteLimit(); - if ($byte_limit) { - $future->setStdoutSizeLimit($byte_limit + 1); - } - return $future; } diff --git a/src/applications/files/uploadsource/PhabricatorFileUploadSource.php b/src/applications/files/uploadsource/PhabricatorFileUploadSource.php --- a/src/applications/files/uploadsource/PhabricatorFileUploadSource.php +++ b/src/applications/files/uploadsource/PhabricatorFileUploadSource.php @@ -12,6 +12,8 @@ private $shouldChunk; private $didRewind; private $totalBytesWritten = 0; + private $totalBytesRead = 0; + private $byteLimit = 0; public function setName($name) { $this->name = $name; @@ -40,6 +42,15 @@ return $this->viewPolicy; } + public function setByteLimit($byte_limit) { + $this->byteLimit = $byte_limit; + return $this; + } + + public function getByteLimit() { + return $this->byteLimit; + } + public function uploadFile() { if (!$this->shouldChunkFile()) { return $this->writeSingleFile(); @@ -81,8 +92,15 @@ return false; } + $read_bytes = $data->current(); + $this->totalBytesRead += strlen($read_bytes); + + if ($this->byteLimit && ($this->totalBytesRead > $this->byteLimit)) { + throw new PhabricatorFileUploadSourceByteLimitException(); + } + $rope = $this->getRope(); - $rope->append($data->current()); + $rope->append($read_bytes); return true; } @@ -160,8 +178,10 @@ } } - // If we have extra bytes at the end, write them. - if ($rope->getByteLength()) { + // If we have extra bytes at the end, write them. Note that it's possible + // that we have more than one chunk of bytes left if the read was very + // fast. + while ($rope->getByteLength()) { $this->writeChunk($file, $engine); } diff --git a/src/applications/files/uploadsource/PhabricatorFileUploadSourceByteLimitException.php b/src/applications/files/uploadsource/PhabricatorFileUploadSourceByteLimitException.php new file mode 100644 --- /dev/null +++ b/src/applications/files/uploadsource/PhabricatorFileUploadSourceByteLimitException.php @@ -0,0 +1,4 @@ +