3 final class FileAllocateConduitAPIMethod
4 extends FileConduitAPIMethod
{
6 public function getAPIMethodName() {
7 return 'file.allocate';
10 public function getMethodDescription() {
11 return pht('Prepare to upload a file.');
14 protected function defineParamTypes() {
17 'contentLength' => 'int',
18 'contentHash' => 'optional string',
19 'viewPolicy' => 'optional string',
20 'deleteAfterEpoch' => 'optional int',
24 protected function defineReturnType() {
25 return 'map<string, wild>';
28 protected function execute(ConduitAPIRequest
$request) {
29 $viewer = $request->getUser();
31 $hash = $request->getValue('contentHash');
32 $name = $request->getValue('name');
33 $view_policy = $request->getValue('viewPolicy');
34 $length = $request->getValue('contentLength');
38 'authorPHID' => $viewer->getPHID(),
39 'isExplicitUpload' => true,
42 if ($view_policy !== null) {
43 $properties['viewPolicy'] = $view_policy;
46 $ttl = $request->getValue('deleteAfterEpoch');
48 $properties['ttl.absolute'] = $ttl;
53 $file = PhabricatorFile
::newFileFromContentHash(
58 if ($hash !== null && !$file) {
59 $chunked_hash = PhabricatorChunkedFileStorageEngine
::getChunkedHash(
62 $file = id(new PhabricatorFileQuery())
64 ->withContentHashes(array($chunked_hash))
68 if (strlen($name) && !$hash && !$file) {
69 if ($length > PhabricatorFileStorageEngine
::getChunkThreshold()) {
70 // If we don't have a hash, but this file is large enough to store in
71 // chunks and thus may be resumable, try to find a partially uploaded
72 // file by the same author with the same name and same length. This
73 // allows us to resume uploads in Javascript where we can't efficiently
74 // compute file hashes.
75 $file = id(new PhabricatorFileQuery())
77 ->withAuthorPHIDs(array($viewer->getPHID()))
78 ->withNames(array($name))
79 ->withLengthBetween($length, $length)
88 'upload' => (bool)$file->getIsPartial(),
89 'filePHID' => $file->getPHID(),
93 // If there are any non-chunk engines which this file can fit into,
94 // just tell the client to upload the file.
95 $engines = PhabricatorFileStorageEngine
::loadStorageEngines($length);
103 // Otherwise, this is a large file and we want to perform a chunked
104 // upload if we have a chunk engine available.
105 $chunk_engines = PhabricatorFileStorageEngine
::loadWritableChunkEngines();
106 if ($chunk_engines) {
107 $chunk_properties = $properties;
109 if ($hash !== null) {
110 $chunk_properties +
= array(
111 'chunkedHash' => $chunked_hash,
115 $chunk_engine = head($chunk_engines);
116 $file = $chunk_engine->allocateChunks($length, $chunk_properties);
120 'filePHID' => $file->getPHID(),
124 // None of the storage engines can accept this file.
125 if (PhabricatorFileStorageEngine
::loadWritableEngines()) {
127 'Unable to upload file: this file is too large for any '.
128 'configured storage engine.');
131 'Unable to upload file: the server is not configured with any '.
132 'writable storage engines.');