mirror of
https://github.com/nextcloud/server.git
synced 2026-10-18 05:49:26 +02:00
ChunkingV2Plugin::beforeGet eagerly resolves the request path during beforeMethod:GET to block reading intermediate chunked uploads. App-provided DAV collections (versions, trashbin) are attached to the root lazily in a beforeMethod:* closure in Server.php, while uploads is registered eagerly. When beforeGet runs before that closure, getNodeForPath() throws NotFound and aborts the whole request, turning every GET under /dav/versions/ and /dav/trashbin/ into "404 File not found: versions in 'root'". PROPFIND is unaffected, since nothing resolves the path that early for it. This does not currently surface on master only by accident of listener ordering: beforeGet and the collection closure share the default priority, and because beforeGet is registered as a first-class callable (a Closure), the wildcard closure happens to sort before it, so the collections are already attached by the time beforeGet resolves the path. That ordering is not guaranteed -- it depends on how equal-priority listeners are tie-broken -- so the unguarded resolution is a latent fault that any reordering can expose. On stable 28 it is already broken, because the backport registered the handler as an array callable, which tie-breaks the other way and runs beforeGet first. Catch NotFound in beforeGet and bail out: a path that cannot be resolved is by definition not an intermediate upload. This removes the dependency on listener ordering entirely and makes the handler consistent with beforePut()/beforeMove()/beforeDelete(), which already swallow NotFound for the same reason. Add a ChunkingV2Plugin unit test (the NotFound case is the regression guard) and a file-versions integration scenario covering a real version download. Assisted-by: ClaudeCode:claude-opus-4-8[1m] Signed-off-by: David Dreschner <david.dreschner@nextcloud.com>
255 lines
9.5 KiB
Gherkin
255 lines
9.5 KiB
Gherkin
# SPDX-FileCopyrightText: 2016 Nextcloud GmbH and Nextcloud contributors
|
|
# SPDX-License-Identifier: AGPL-3.0-or-later
|
|
Feature: FilesDrop
|
|
|
|
Scenario: Put file via files drop
|
|
Given user "user0" exists
|
|
And As an "user0"
|
|
And user "user0" created a folder "/drop"
|
|
And as "user0" creating a share with
|
|
| path | drop |
|
|
| shareType | 3 |
|
|
| publicUpload | true |
|
|
And Updating last share with
|
|
| permissions | 4 |
|
|
When Dropping file "/a.txt" with "abc"
|
|
And Downloading file "/drop/a.txt"
|
|
Then Downloaded content should be "abc"
|
|
|
|
Scenario: Put file same file multiple times via files drop
|
|
Given user "user0" exists
|
|
And As an "user0"
|
|
And user "user0" created a folder "/drop"
|
|
And as "user0" creating a share with
|
|
| path | drop |
|
|
| shareType | 3 |
|
|
| publicUpload | true |
|
|
And Updating last share with
|
|
| permissions | 4 |
|
|
When Dropping file "/a.txt" with "abc"
|
|
And Dropping file "/a.txt" with "def"
|
|
And Downloading file "/drop/a.txt"
|
|
Then Downloaded content should be "abc"
|
|
And Downloading file "/drop/a (2).txt"
|
|
Then Downloaded content should be "def"
|
|
|
|
Scenario: Files request forbid directory without a nickname
|
|
Given user "user0" exists
|
|
And As an "user0"
|
|
And user "user0" created a folder "/drop"
|
|
And as "user0" creating a share with
|
|
| path | drop |
|
|
| shareType | 3 |
|
|
| publicUpload | true |
|
|
| attributes | [{"scope":"fileRequest","key":"enabled","value":true}] |
|
|
And Updating last share with
|
|
| permissions | 4 |
|
|
When Dropping file "/folder/a.txt" with "abc"
|
|
Then the HTTP status code should be "400"
|
|
|
|
Scenario: Files drop allow MKCOL without a nickname
|
|
Given user "user0" exists
|
|
And As an "user0"
|
|
And user "user0" created a folder "/drop"
|
|
And as "user0" creating a share with
|
|
| path | drop |
|
|
| shareType | 3 |
|
|
| publicUpload | true |
|
|
And Updating last share with
|
|
| permissions | 4 |
|
|
When Creating folder "folder" in drop
|
|
Then the HTTP status code should be "201"
|
|
|
|
Scenario: Files request forbid MKCOL without a nickname
|
|
Given user "user0" exists
|
|
And As an "user0"
|
|
And user "user0" created a folder "/drop"
|
|
And as "user0" creating a share with
|
|
| path | drop |
|
|
| shareType | 3 |
|
|
| publicUpload | true |
|
|
| attributes | [{"scope":"fileRequest","key":"enabled","value":true}] |
|
|
And Updating last share with
|
|
| permissions | 4 |
|
|
When Creating folder "folder" in drop
|
|
Then the HTTP status code should be "400"
|
|
|
|
Scenario: Files request allows MKCOL with a nickname
|
|
Given user "user0" exists
|
|
And As an "user0"
|
|
And user "user0" created a folder "/drop"
|
|
And as "user0" creating a share with
|
|
| path | drop |
|
|
| shareType | 3 |
|
|
| publicUpload | true |
|
|
| attributes | [{"scope":"fileRequest","key":"enabled","value":true}] |
|
|
And Updating last share with
|
|
| permissions | 4 |
|
|
When Creating folder "folder" in drop as "nickname"
|
|
Then the HTTP status code should be "201"
|
|
|
|
Scenario: Files request forbid subfolder creation without a nickname
|
|
Given user "user0" exists
|
|
And As an "user0"
|
|
And user "user0" created a folder "/drop"
|
|
And as "user0" creating a share with
|
|
| path | drop |
|
|
| shareType | 3 |
|
|
| publicUpload | true |
|
|
| attributes | [{"scope":"fileRequest","key":"enabled","value":true}] |
|
|
And Updating last share with
|
|
| permissions | 4 |
|
|
When dropping file "/folder/a.txt" with "abc"
|
|
Then the HTTP status code should be "400"
|
|
|
|
Scenario: Files request drop
|
|
Given user "user0" exists
|
|
And As an "user0"
|
|
And user "user0" created a folder "/drop"
|
|
And as "user0" creating a share with
|
|
| path | drop |
|
|
| shareType | 4 |
|
|
| permissions | 4 |
|
|
| attributes | [{"scope":"fileRequest","key":"enabled","value":true}] |
|
|
| shareWith | |
|
|
When Dropping file "/folder/a.txt" with "abc" as "Alice"
|
|
And Downloading file "/drop/Alice/folder/a.txt"
|
|
Then Downloaded content should be "abc"
|
|
|
|
Scenario: File drop uploading folder with name of file
|
|
Given user "user0" exists
|
|
And As an "user0"
|
|
And user "user0" created a folder "/drop"
|
|
And as "user0" creating a share with
|
|
| path | drop |
|
|
| shareType | 4 |
|
|
| permissions | 4 |
|
|
| attributes | [{"scope":"fileRequest","key":"enabled","value":true}] |
|
|
| shareWith | |
|
|
When Dropping file "/folder" with "its a file" as "Alice"
|
|
Then the HTTP status code should be "201"
|
|
When Dropping file "/folder/a.txt" with "abc" as "Alice"
|
|
Then the HTTP status code should be "201"
|
|
When Downloading file "/drop/Alice/folder"
|
|
Then the HTTP status code should be "200"
|
|
And Downloaded content should be "its a file"
|
|
When Downloading file "/drop/Alice/folder (2)/a.txt"
|
|
Then Downloaded content should be "abc"
|
|
|
|
Scenario: File drop uploading file with name of folder
|
|
Given user "user0" exists
|
|
And As an "user0"
|
|
And user "user0" created a folder "/drop"
|
|
And as "user0" creating a share with
|
|
| path | drop |
|
|
| shareType | 4 |
|
|
| permissions | 4 |
|
|
| attributes | [{"scope":"fileRequest","key":"enabled","value":true}] |
|
|
| shareWith | |
|
|
When Dropping file "/folder/a.txt" with "abc" as "Alice"
|
|
Then the HTTP status code should be "201"
|
|
When Dropping file "/folder" with "its a file" as "Alice"
|
|
Then the HTTP status code should be "201"
|
|
When Downloading file "/drop/Alice/folder/a.txt"
|
|
Then the HTTP status code should be "200"
|
|
And Downloaded content should be "abc"
|
|
When Downloading file "/drop/Alice/folder (2)"
|
|
Then the HTTP status code should be "200"
|
|
And Downloaded content should be "its a file"
|
|
|
|
Scenario: Put file same file multiple times via files drop
|
|
Given user "user0" exists
|
|
And As an "user0"
|
|
And user "user0" created a folder "/drop"
|
|
And as "user0" creating a share with
|
|
| path | drop |
|
|
| shareType | 4 |
|
|
| permissions | 4 |
|
|
| attributes | [{"scope":"fileRequest","key":"enabled","value":true}] |
|
|
| shareWith | |
|
|
When Dropping file "/folder/a.txt" with "abc" as "Mallory"
|
|
And Dropping file "/folder/a.txt" with "def" as "Mallory"
|
|
# Ensure folder structure and that we only checked
|
|
# for files duplicates, but merged the existing folders
|
|
Then as "user0" the folder "/drop/Mallory" exists
|
|
Then as "user0" the folder "/drop/Mallory/folder" exists
|
|
Then as "user0" the folder "/drop/Mallory (2)" does not exist
|
|
Then as "user0" the folder "/drop/Mallory/folder (2)" does not exist
|
|
Then as "user0" the file "/drop/Mallory/folder/a.txt" exists
|
|
Then as "user0" the file "/drop/Mallory/folder/a (2).txt" exists
|
|
And Downloading file "/drop/Mallory/folder/a.txt"
|
|
Then Downloaded content should be "abc"
|
|
And Downloading file "/drop/Mallory/folder/a (2).txt"
|
|
Then Downloaded content should be "def"
|
|
|
|
Scenario: Files drop prevents GET
|
|
Given user "user0" exists
|
|
And As an "user0"
|
|
And user "user0" created a folder "/drop"
|
|
And as "user0" creating a share with
|
|
| path | drop |
|
|
| shareType | 4 |
|
|
| permissions | 4 |
|
|
| shareWith | |
|
|
| attributes | [{"scope":"fileRequest","key":"enabled","value":true}] |
|
|
When Dropping file "/folder/a.txt" with "abc" as "Mallory"
|
|
When as "user0" the file "/drop/Mallory/folder/a.txt" exists
|
|
And Downloading public folder "Mallory"
|
|
Then the HTTP status code should be "405"
|
|
And Downloading public folder "Mallory/folder"
|
|
Then the HTTP status code should be "405"
|
|
And Downloading public file "Mallory/folder/a.txt"
|
|
Then the HTTP status code should be "405"
|
|
|
|
Scenario: Files drop requires nickname if file request is enabled
|
|
Given user "user0" exists
|
|
And As an "user0"
|
|
And user "user0" created a folder "/drop"
|
|
And as "user0" creating a share with
|
|
| path | drop |
|
|
| shareType | 4 |
|
|
| permissions | 4 |
|
|
| attributes | [{"scope":"fileRequest","key":"enabled","value":true}] |
|
|
| shareWith | |
|
|
When Dropping file "/folder/a.txt" with "abc"
|
|
Then the HTTP status code should be "400"
|
|
|
|
Scenario: Files request drop with invalid nickname with slashes
|
|
Given user "user0" exists
|
|
And As an "user0"
|
|
And user "user0" created a folder "/drop"
|
|
And as "user0" creating a share with
|
|
| path | drop |
|
|
| shareType | 4 |
|
|
| permissions | 4 |
|
|
| attributes | [{"scope":"fileRequest","key":"enabled","value":true}] |
|
|
| shareWith | |
|
|
When Dropping file "/folder/a.txt" with "abc" as "Alice/Bob/Mallory"
|
|
Then the HTTP status code should be "400"
|
|
|
|
Scenario: Files request drop with invalid nickname with forbidden characters
|
|
Given user "user0" exists
|
|
And As an "user0"
|
|
And user "user0" created a folder "/drop"
|
|
And as "user0" creating a share with
|
|
| path | drop |
|
|
| shareType | 4 |
|
|
| permissions | 4 |
|
|
| attributes | [{"scope":"fileRequest","key":"enabled","value":true}] |
|
|
| shareWith | |
|
|
When Dropping file "/folder/a.txt" with "abc" as ".htaccess"
|
|
Then the HTTP status code should be "400"
|
|
|
|
Scenario: Files request drop with invalid nickname with forbidden characters
|
|
Given user "user0" exists
|
|
And As an "user0"
|
|
And user "user0" created a folder "/drop"
|
|
And as "user0" creating a share with
|
|
| path | drop |
|
|
| shareType | 4 |
|
|
| permissions | 4 |
|
|
| attributes | [{"scope":"fileRequest","key":"enabled","value":true}] |
|
|
| shareWith | |
|
|
When Dropping file "/folder/a.txt" with "abc" as ".Mallory"
|
|
Then the HTTP status code should be "400"
|