download: do not exit (#597)

Signed-off-by: Varun Patil <radialapps@gmail.com>
pull/602/head
Varun Patil 2023-04-20 11:33:54 -07:00
parent 4239e05b3c
commit 3e6e8f9b14
2 changed files with 137 additions and 102 deletions

View File

@ -114,7 +114,7 @@ class DownloadController extends GenericApiController
} }
// Download multiple files // Download multiple files
$this->multiple($name, $fileIds); // exits return $this->multiple($name, $fileIds);
}); });
} }
@ -127,7 +127,7 @@ class DownloadController extends GenericApiController
*/ */
public function one(int $fileid, bool $resumable = true, int $numChunks = 0): Http\Response public function one(int $fileid, bool $resumable = true, int $numChunks = 0): Http\Response
{ {
return Util::guardEx(function () use ($fileid, $resumable, $numChunks) { return Util::guardExDirect(function (Http\IOutput $out) use ($fileid, $resumable, $numChunks) {
$file = $this->fs->getUserFile($fileid); $file = $this->fs->getUserFile($fileid);
// check if http_range is sent by browser // check if http_range is sent by browser
@ -175,17 +175,17 @@ class DownloadController extends GenericApiController
// Only send partial content header if downloading a piece of the file // Only send partial content header if downloading a piece of the file
if ($seekStart > 0 || $seekEnd < ($size - 1)) { if ($seekStart > 0 || $seekEnd < ($size - 1)) {
header('HTTP/1.1 206 Partial Content'); $out->setHeader('HTTP/1.1 206 Partial Content');
} }
// Set headers // Set headers
header('Accept-Ranges: bytes'); $out->setHeader('Accept-Ranges: bytes');
header("Content-Range: bytes {$seekStart}-{$seekEnd}/{$size}"); $out->setHeader("Content-Range: bytes {$seekStart}-{$seekEnd}/{$size}");
header('Content-Length: '.($seekEnd - $seekStart + 1)); $out->setHeader('Content-Length: '.($seekEnd - $seekStart + 1));
header('Content-Type: '.$file->getMimeType()); $out->setHeader('Content-Type: '.$file->getMimeType());
// Make sure the browser downloads the file // Make sure the browser downloads the file
header('Content-Disposition: attachment; filename="'.$file->getName().'"'); $out->setHeader('Content-Disposition: attachment; filename="'.$file->getName().'"');
// Open file to send // Open file to send
$res = $file->fopen('rb'); $res = $file->fopen('rb');
@ -215,7 +215,7 @@ class DownloadController extends GenericApiController
$chunkRead += \strlen($buffer); $chunkRead += \strlen($buffer);
// Send buffer // Send buffer
echo $buffer; $out->setOutput($buffer);
// Flush output if chunk is large enough // Flush output if chunk is large enough
if ($chunkRead > 1024 * 512) { if ($chunkRead > 1024 * 512) {
@ -235,8 +235,6 @@ class DownloadController extends GenericApiController
// Close file // Close file
fclose($res); fclose($res);
exit;
}); });
} }
@ -246,8 +244,9 @@ class DownloadController extends GenericApiController
* @param string $name Name of zip file * @param string $name Name of zip file
* @param int[] $fileIds * @param int[] $fileIds
*/ */
private function multiple(string $name, array $fileIds) private function multiple(string $name, array $fileIds): Http\Response
{ {
return Util::guardExDirect(function ($out) use ($name, $fileIds) {
// Disable time limit // Disable time limit
$executionTime = (int) \OC::$server->get(IniGetWrapper::class)->getNumeric('max_execution_time'); $executionTime = (int) \OC::$server->get(IniGetWrapper::class)->getNumeric('max_execution_time');
@set_time_limit(0); @set_time_limit(0);
@ -350,7 +349,6 @@ class DownloadController extends GenericApiController
// Done // Done
$streamer->finalize(); $streamer->finalize();
});
exit;
} }
} }

View File

@ -27,6 +27,43 @@ trait UtilController
} }
} }
/**
* Return a callback response with guarded exceptions.
*/
public static function guardExDirect(\Closure $closure): Http\Response
{
return new class($closure) extends Http\Response implements Http\ICallbackResponse {
private \Closure $_closure;
public function __construct(\Closure $closure)
{
$this->_closure = $closure;
}
public function callback(Http\IOutput $output)
{
try {
($this->_closure)($output);
} catch (\OCA\Memories\HttpResponseException $e) {
$res = $e->response;
$output->setHttpResponseCode($res->getStatus());
if ($res instanceof Http\DataResponse) {
$output->setHeader('Content-Type: application/json');
$output->setOutput(json_encode($res->getData()));
} else {
$output->setOutput($res->render());
}
} catch (\Exception $e) {
$output->setHttpResponseCode(Http::STATUS_INTERNAL_SERVER_ERROR);
$output->setHeader('Content-Type: application/json');
$output->setOutput(json_encode([
'message' => $e->getMessage(),
]));
}
}
};
}
/** /**
* Get the current user. * Get the current user.
* *