/** * Get the result of a chunk upload. * @param array $warnings Array of Api upload warnings * @return array */ private function getChunkResult($warnings) { $result = array(); $result['result'] = 'Continue'; if ($warnings && count($warnings) > 0) { $result['warnings'] = $warnings; } $request = $this->getMain()->getRequest(); $chunkPath = $request->getFileTempname('chunk'); $chunkSize = $request->getUpload('chunk')->getSize(); if ($this->mParams['offset'] == 0) { try { $filekey = $this->performStash(); } catch (UploadStashException $e) { $this->handleStashException($e); } catch (Exception $e) { // FIXME: Error handling here is wrong/different from rest of this $this->dieUsage($e->getMessage(), 'stashfailed'); } } else { $filekey = $this->mParams['filekey']; $status = $this->mUpload->addChunk($chunkPath, $chunkSize, $this->mParams['offset']); if (!$status->isGood()) { $extradata = array('offset' => $this->mUpload->getOffset()); $this->dieUsage($status->getWikiText(), 'stashfailed', 0, $extradata); return array(); } } // Check we added the last chunk: if ($this->mParams['offset'] + $chunkSize == $this->mParams['filesize']) { if ($this->mParams['async']) { $progress = UploadBase::getSessionStatus($this->getUser(), $filekey); if ($progress && $progress['result'] === 'Poll') { $this->dieUsage("Chunk assembly already in progress.", 'stashfailed'); } UploadBase::setSessionStatus($this->getUser(), $filekey, array('result' => 'Poll', 'stage' => 'queued', 'status' => Status::newGood())); JobQueueGroup::singleton()->push(new AssembleUploadChunksJob(Title::makeTitle(NS_FILE, $filekey), array('filename' => $this->mParams['filename'], 'filekey' => $filekey, 'session' => $this->getContext()->exportSession()))); $result['result'] = 'Poll'; $result['stage'] = 'queued'; } else { $status = $this->mUpload->concatenateChunks(); if (!$status->isGood()) { $this->dieUsage($status->getWikiText(), 'stashfailed'); return array(); } // The fully concatenated file has a new filekey. So remove // the old filekey and fetch the new one. $this->mUpload->stash->removeFile($filekey); $filekey = $this->mUpload->getLocalFile()->getFileKey(); $result['result'] = 'Success'; } } $result['filekey'] = $filekey; $result['offset'] = $this->mParams['offset'] + $chunkSize; return $result; }
/** * Get the result of a chunk upload. * @param array $warnings Array of Api upload warnings * @return array */ private function getChunkResult($warnings) { $result = []; if ($warnings && count($warnings) > 0) { $result['warnings'] = $warnings; } $request = $this->getMain()->getRequest(); $chunkPath = $request->getFileTempname('chunk'); $chunkSize = $request->getUpload('chunk')->getSize(); $totalSoFar = $this->mParams['offset'] + $chunkSize; $minChunkSize = $this->getConfig()->get('MinUploadChunkSize'); // Sanity check sizing if ($totalSoFar > $this->mParams['filesize']) { $this->dieUsage('Offset plus current chunk is greater than claimed file size', 'invalid-chunk'); } // Enforce minimum chunk size if ($totalSoFar != $this->mParams['filesize'] && $chunkSize < $minChunkSize) { $this->dieUsage("Minimum chunk size is {$minChunkSize} bytes for non-final chunks", 'chunk-too-small'); } if ($this->mParams['offset'] == 0) { try { $filekey = $this->performStash(); } catch (UploadStashException $e) { $this->handleStashException($e); } catch (Exception $e) { // FIXME: Error handling here is wrong/different from rest of this $this->dieUsage($e->getMessage(), 'stashfailed'); } } else { $filekey = $this->mParams['filekey']; // Don't allow further uploads to an already-completed session $progress = UploadBase::getSessionStatus($this->getUser(), $filekey); if (!$progress) { // Probably can't get here, but check anyway just in case $this->dieUsage('No chunked upload session with this key', 'stashfailed'); } elseif ($progress['result'] !== 'Continue' || $progress['stage'] !== 'uploading') { $this->dieUsage('Chunked upload is already completed, check status for details', 'stashfailed'); } $status = $this->mUpload->addChunk($chunkPath, $chunkSize, $this->mParams['offset']); if (!$status->isGood()) { $extradata = ['offset' => $this->mUpload->getOffset()]; $this->dieUsage($status->getWikiText(false, false, 'en'), 'stashfailed', 0, $extradata); } } // Check we added the last chunk: if ($totalSoFar == $this->mParams['filesize']) { if ($this->mParams['async']) { UploadBase::setSessionStatus($this->getUser(), $filekey, ['result' => 'Poll', 'stage' => 'queued', 'status' => Status::newGood()]); JobQueueGroup::singleton()->push(new AssembleUploadChunksJob(Title::makeTitle(NS_FILE, $filekey), ['filename' => $this->mParams['filename'], 'filekey' => $filekey, 'session' => $this->getContext()->exportSession()])); $result['result'] = 'Poll'; $result['stage'] = 'queued'; } else { $status = $this->mUpload->concatenateChunks(); if (!$status->isGood()) { UploadBase::setSessionStatus($this->getUser(), $filekey, ['result' => 'Failure', 'stage' => 'assembling', 'status' => $status]); $this->dieUsage($status->getWikiText(false, false, 'en'), 'stashfailed'); } // The fully concatenated file has a new filekey. So remove // the old filekey and fetch the new one. UploadBase::setSessionStatus($this->getUser(), $filekey, false); $this->mUpload->stash->removeFile($filekey); $filekey = $this->mUpload->getLocalFile()->getFileKey(); $result['result'] = 'Success'; } } else { UploadBase::setSessionStatus($this->getUser(), $filekey, ['result' => 'Continue', 'stage' => 'uploading', 'offset' => $totalSoFar, 'status' => Status::newGood()]); $result['result'] = 'Continue'; $result['offset'] = $totalSoFar; } $result['filekey'] = $filekey; return $result; }