summaryrefslogtreecommitdiffstats
path: root/apps/dav
diff options
context:
space:
mode:
authorJohn Molakvoæ <skjnldsv@protonmail.com>2024-01-10 13:11:06 +0100
committerJohn Molakvoæ <skjnldsv@protonmail.com>2024-01-10 13:26:25 +0100
commit9703b1da41837c48b527ee791440defa3026cdf1 (patch)
treef127247ac691d840137531419b52ede6e3447cb7 /apps/dav
parent50aeae6a858094d86d93d0db12889ca98d226ab0 (diff)
downloadnextcloud-server-9703b1da41837c48b527ee791440defa3026cdf1.tar.gz
nextcloud-server-9703b1da41837c48b527ee791440defa3026cdf1.zip
fix(quota): automatically detect chunk quota with `OC-Total-Length` header
Signed-off-by: John Molakvoæ <skjnldsv@protonmail.com>
Diffstat (limited to 'apps/dav')
-rw-r--r--apps/dav/lib/Connector/Sabre/QuotaPlugin.php83
1 files changed, 50 insertions, 33 deletions
diff --git a/apps/dav/lib/Connector/Sabre/QuotaPlugin.php b/apps/dav/lib/Connector/Sabre/QuotaPlugin.php
index 1eed3d0d778..687b05e86cb 100644
--- a/apps/dav/lib/Connector/Sabre/QuotaPlugin.php
+++ b/apps/dav/lib/Connector/Sabre/QuotaPlugin.php
@@ -31,6 +31,7 @@
namespace OCA\DAV\Connector\Sabre;
use OCA\DAV\Upload\FutureFile;
+use OCA\DAV\Upload\UploadFolder;
use OCP\Files\StorageNotAvailableException;
use Sabre\DAV\Exception\InsufficientStorage;
use Sabre\DAV\Exception\ServiceUnavailable;
@@ -90,6 +91,19 @@ class QuotaPlugin extends \Sabre\DAV\ServerPlugin {
* @param bool $modified modified
*/
public function beforeCreateFile($uri, $data, INode $parent, $modified) {
+ $request = $this->server->httpRequest;
+ if ($parent instanceof UploadFolder && $request->getHeader('Destination')) {
+ // If chunked upload and Total-Length header is set, use that
+ // value for quota check. This allows us to also check quota while
+ // uploading chunks and not only when the file is assembled.
+ $length = $request->getHeader('OC-Total-Length');
+ $destinationPath = $this->server->calculateUri($request->getHeader('Destination'));
+ $quotaPath = $this->getPathForDestination($destinationPath);
+ if ($quotaPath && is_numeric($length)) {
+ return $this->checkQuota($quotaPath, (int)$length);
+ }
+ }
+
if (!$parent instanceof Node) {
return;
}
@@ -114,29 +128,20 @@ class QuotaPlugin extends \Sabre\DAV\ServerPlugin {
}
/**
- * Check if we're moving a Futurefile in which case we need to check
+ * Check if we're moving a FutureFile in which case we need to check
* the quota on the target destination.
- *
- * @param string $source source path
- * @param string $destination destination path
*/
- public function beforeMove($source, $destination) {
- $sourceNode = $this->server->tree->getNodeForPath($source);
+ public function beforeMove(string $sourcePath, string $destinationPath): bool {
+ $sourceNode = $this->server->tree->getNodeForPath($sourcePath);
if (!$sourceNode instanceof FutureFile) {
- return;
+ return true;
}
- // get target node for proper path conversion
- if ($this->server->tree->nodeExists($destination)) {
- $destinationNode = $this->server->tree->getNodeForPath($destination);
- $path = $destinationNode->getPath();
- } else {
- $parent = dirname($destination);
- if ($parent === '.') {
- $parent = '';
- }
- $parentNode = $this->server->tree->getNodeForPath($parent);
- $path = $parentNode->getPath();
+ try {
+ // The final path is not known yet, we check the quota on the parent
+ $path = $this->getPathForDestination($destinationPath);
+ } catch (\Exception $e) {
+ return true;
}
return $this->checkQuota($path, $sourceNode->getSize());
@@ -151,26 +156,36 @@ class QuotaPlugin extends \Sabre\DAV\ServerPlugin {
return true;
}
+ try {
+ $path = $this->getPathForDestination($destinationPath);
+ } catch (\Exception $e) {
+ return true;
+ }
+
+ return $this->checkQuota($path, $sourceNode->getSize());
+ }
+
+ private function getPathForDestination(string $destinationPath): string {
// get target node for proper path conversion
if ($this->server->tree->nodeExists($destinationPath)) {
$destinationNode = $this->server->tree->getNodeForPath($destinationPath);
if (!$destinationNode instanceof Node) {
- return true;
- }
- $path = $destinationNode->getPath();
- } else {
- $parent = dirname($destinationPath);
- if ($parent === '.') {
- $parent = '';
- }
- $parentNode = $this->server->tree->getNodeForPath($parent);
- if (!$parentNode instanceof Node) {
- return true;
+ throw new \Exception('Invalid destination node');
}
- $path = $parentNode->getPath();
+ return $destinationNode->getPath();
}
- return $this->checkQuota($path, $sourceNode->getSize());
+ $parent = dirname($destinationPath);
+ if ($parent === '.') {
+ $parent = '';
+ }
+
+ $parentNode = $this->server->tree->getNodeForPath($parent);
+ if (!$parentNode instanceof Node) {
+ throw new \Exception('Invalid destination node');
+ }
+
+ return $parentNode->getPath();
}
@@ -182,7 +197,7 @@ class QuotaPlugin extends \Sabre\DAV\ServerPlugin {
* @throws InsufficientStorage
* @return bool
*/
- public function checkQuota($path, $length = null) {
+ public function checkQuota(string $path, $length = null) {
if ($length === null) {
$length = $this->getLength();
}
@@ -194,7 +209,7 @@ class QuotaPlugin extends \Sabre\DAV\ServerPlugin {
}
$req = $this->server->httpRequest;
- // If chunked upload
+ // If LEGACY chunked upload
if ($req->getHeader('OC-Chunked')) {
$info = \OC_FileChunking::decodeName($newName);
$chunkHandler = $this->getFileChunking($info);
@@ -210,12 +225,14 @@ class QuotaPlugin extends \Sabre\DAV\ServerPlugin {
$freeSpace = $this->getFreeSpace($path);
if ($freeSpace >= 0 && $length > $freeSpace) {
+ // If LEGACY chunked upload, clean up
if (isset($chunkHandler)) {
$chunkHandler->cleanup();
}
throw new InsufficientStorage("Insufficient space in $path, $length required, $freeSpace available");
}
}
+
return true;
}