Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/integration-sqlite.yml
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ jobs:
- 'capabilities_features'
- 'collaboration_features'
- 'comments_features'
- 'dav_features'
- '--tags ~@requires-s3 dav_features'
- 'features'
- 'federation_features'
- '--tags ~@large files_features'
Expand Down
23 changes: 16 additions & 7 deletions apps/dav/lib/Upload/ChunkingV2Plugin.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
use OCP\IConfig;
use OCP\Lock\ILockingProvider;
use Sabre\DAV\Exception\BadRequest;
use Sabre\DAV\Exception\Forbidden;
use Sabre\DAV\Exception\InsufficientStorage;
use Sabre\DAV\Exception\MethodNotAllowed;
use Sabre\DAV\Exception\NotFound;
Expand Down Expand Up @@ -107,18 +108,26 @@ public function forbiddenMethod(RequestInterface $request) {
* @param string $path
* @param bool $createIfNotExists
* @return FutureFile|UploadFile|ICollection|INode
* @throws Forbidden if the file already exists, but is not updateable
*/
private function getUploadFile(string $path, bool $createIfNotExists = false) {
try {
$actualFile = $this->server->tree->getNodeForPath($path);
// Only directly upload to the target file if it is on the same storage
// There may be further potential to optimize here by also uploading
// to other storages directly. This would require to also carefully pick
// the storage/path used in getStorage()
if ($actualFile instanceof File && $this->uploadFolder->getStorage()->getId() === $actualFile->getNode()->getStorage()->getId()) {
return $actualFile;
if ($actualFile instanceof File) {
$node = $actualFile->getNode();
// check that the node has update permissions
if (!$node->isUpdateable()) {
throw new Forbidden();
}
// Only directly upload to the target file if it is on the same storage
// There may be further potential to optimize here by also uploading
// to other storages directly. This would require to also carefully pick
// the storage/path used in getStorage()
if ($this->uploadFolder->getStorage()->getId() === $node->getStorage()->getId()) {
return $actualFile;
}
}
} catch (NotFound $e) {
} catch (NotFound) {
// If there is no target file we upload to the upload folder first
}

Expand Down
20 changes: 20 additions & 0 deletions build/integration/dav_features/webdav-related.feature
Original file line number Diff line number Diff line change
Expand Up @@ -737,3 +737,23 @@ Feature: webdav-related
When As an "user0"
And Downloading file "/üäöé/äöü.txt"
Then Downloaded content should be the created file

@requires-s3
Scenario: Cannot overwrite a file the user may not update with new chunking v2
Given using new dav path
And user "user0" exists
And user "user1" exists
And As an "user1"
And user "user1" created a folder "/testshare"
And User "user1" copies file "/welcome.txt" to "/testshare/test.txt"
And as "user1" creating a share with
| path | testshare |
| shareType | 0 |
| permissions | 5 |
| shareWith | user0 |
And user "user0" accepts last share
And As an "user0"
And user "user0" creates a file locally with "3" x 5 MB chunks
When user "user0" creates a new chunking v2 upload with id "chunking-update" and destination "/testshare/test.txt"
Then the HTTP status code should be "403"
And Downloaded content when downloading file "/testshare/test.txt" with range "bytes=0-6" should be "Welcome"
14 changes: 11 additions & 3 deletions build/integration/features/bootstrap/WebDav.php
Original file line number Diff line number Diff line change
Expand Up @@ -987,9 +987,17 @@ public function userCreatesANewChunkingv2UploadWithIdAndDestination($user, $id,
$this->s3MultipartDestination = $this->getTargetDestination($user, $targetDestination);
$this->newUploadId();
$destination = '/uploads/' . $user . '/' . $this->getUploadId($id);
$this->response = $this->makeDavRequest($user, 'MKCOL', $destination, [
'Destination' => $this->s3MultipartDestination,
], null, 'uploads');
try {
$this->response = $this->makeDavRequest($user, 'MKCOL', $destination, [
'Destination' => $this->s3MultipartDestination,
], null, 'uploads');
} catch (\GuzzleHttp\Exception\ServerException $e) {
// 5xx responses cause a server exception
$this->response = $e->getResponse();
} catch (\GuzzleHttp\Exception\ClientException $e) {
// 4xx responses cause a client exception
$this->response = $e->getResponse();
}
}

/**
Expand Down
Loading