Detect directory paths in object get without recursive flag#3114
Detect directory paths in object get without recursive flag#3114
Conversation
d26575b to
8f8a4a8
Compare
Add a WithRejectCollections TransferOption that causes downloadObject to
verify (via PROPFIND) that the remote path is not a WebDAV collection
before attempting the download. When the remote path is a directory,
the transfer fails early with a clear error:
remote object is a directory; use recursive mode to download directories
The CLI's object get command sets WithRejectCollections(!isRecursive) so
that non-recursive downloads of directories produce a helpful error
instead of downloading an HTML directory listing.
To avoid an unnecessary PROPFIND round-trip, the collection check is
skipped when:
- sortAttempts already received a non-zero Age header from a cache
(cached objects are never directories), or
- a previous downloadObject call for the same job already confirmed
the path is not a collection (cached in TransferJob.notCollection).
If the URL contains a ?recursive query parameter that forces recursive
mode, rejectCollections is cleared in NewTransferJob so the check is
not applied.
Closes #1706
8f8a4a8 to
b828f65
Compare
client/handle_http.go
Outdated
|
|
||
| // If the URL query forced recursive mode, clear rejectCollections since the user | ||
| // explicitly indicated they want recursive behavior via the URL. | ||
| if recursiveFromQuery && tj.rejectCollections { |
There was a problem hiding this comment.
@copilot The check of tj.rejectCollections is redundant, no matter what it is it will end up as false.
There was a problem hiding this comment.
Fixed in commit 0b70906. Removed the redundant check - when recursiveFromQuery is true, recursive is already true, so rejectCollections would never have been set to true in the first place.
| _, getErr = client.DoGet(fed.Ctx, downloadURL, destPath, false, opts...) | ||
| } | ||
|
|
||
| require.Error(t, getErr, "Expected an error when passing a dir path to object get command without recursive option set") |
There was a problem hiding this comment.
@copilot I believe we can be more specific? Isn't this a pelican parameter error?
There was a problem hiding this comment.
Fixed in commit 0b70906. Now validates that the error is specifically a ParameterError with code 1000:
var pe *error_codes.PelicanError
require.True(t, errors.As(getErr, &pe), "Error should be wrapped in PelicanError")
assert.Equal(t, 1000, pe.Code(), "Should be Parameter error code")- Remove redundant recursiveFromQuery check in handle_http.go (line 1242) The check was unnecessary because recursiveFromQuery implies recursive=true, and rejectCollections is only set when NOT recursive - Add specific ParameterError validation in fed_long_test.go (line 1042) Now verifies error is wrapped as PelicanError with code 1000 (Parameter error) Co-authored-by: turetske <498529+turetske@users.noreply.github.com>
client/handle_http.go
Outdated
| // If the URL query forced recursive mode, clear rejectCollections since the user | ||
| // explicitly indicated they want recursive behavior via the URL. | ||
| if recursiveFromQuery && tj.rejectCollections { | ||
| tj.rejectCollections = false |
There was a problem hiding this comment.
@copilot Is this correct? I suggested just removing the tj.rejectCollection but keeping recursiveFromQuery. Basically, if recursiveFromQuery, then tj.rejectCollections = false.
There was a problem hiding this comment.
You're right, I misunderstood. Fixed in commit 23647a9. Now keeping the logic but with the simplified condition:
if recursiveFromQuery {
tj.rejectCollections = false
}This removes the redundant tj.rejectCollections check while preserving the behavior of clearing rejectCollections when the URL query forces recursive mode.
Keep the logic to clear rejectCollections when recursiveFromQuery is true,
but remove the redundant check of tj.rejectCollections in the condition.
Now simply: if recursiveFromQuery { tj.rejectCollections = false }
Co-authored-by: turetske <498529+turetske@users.noreply.github.com>
|
@bbockelm Passing this back to you |
Changes Made
Issue 1: Simplified recursiveFromQuery check (handle_http.go:1242)
The original suggestion was to remove the redundant
tj.rejectCollectionscheck in the condition, not to remove the entire block. The corrected logic:This ensures that when a URL query parameter forces recursive mode, we unconditionally clear rejectCollections.
Issue 2: More specific error validation (fed_long_test.go:1042)
Added proper error type checking:
Original prompt
💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.