Skip to content

fix(core/layers): handle non-trailing-slash path in native recursive list#7705

Open
tonghuaroot wants to merge 2 commits into
apache:mainfrom
tonghuaroot:fix-simulate-native-recursive-prefix
Open

fix(core/layers): handle non-trailing-slash path in native recursive list#7705
tonghuaroot wants to merge 2 commits into
apache:mainfrom
tonghuaroot:fix-simulate-native-recursive-prefix

Conversation

@tonghuaroot

@tonghuaroot tonghuaroot commented Jun 7, 2026

Copy link
Copy Markdown
Contributor

Which issue does this PR close?

Related to #4256 (does not close it). Fixes a latent correctness bug in the recursive-list path, found while investigating #4256.

Rationale for this change

SimulateAccessor::simulate_list's non-recursive and simulated-recursive arms already prefix-handle a list path without a trailing slash (list the parent, wrap in PrefixLister), so listing dir/file returns both dir/file and dir/file2. The native-recursive arm (_, true, _) didn't — it forwarded the path straight to the backend. On a backend with subtree semantics (WebDAV Depth: infinity) that returns only dir/file, dropping prefix-siblings. The in-memory service hid this because its native lister is prefix-based.

What changes are included in this PR?

  • Native-recursive arm: for a non-trailing-slash path, list the parent and wrap in PrefixLister, matching the other two arms; trailing-slash paths forward as before.
  • Regression test with a mock Depth: infinity backend.

…list

The native-recursive arm of SimulateAccessor::simulate_list `(_, true, _)`
forwarded the list path directly to the backend. For a path without a
trailing slash (for example `dir/file`), a backend that natively supports
recursive list (such as a WebDAV server honoring `Depth: infinity`) walks
the subtree of `dir/file` and returns only that entry, silently dropping
prefix-siblings like `dir/file2`.

Both the simulated-recursive arm `(true, false, true)` and the
non-recursive arm `(false, false, _)` already handle this: for a path
without a trailing slash they list the parent directory and wrap the
result in a PrefixLister so that entries sharing the path prefix are
returned. The native-recursive arm now applies the same handling, making
recursive list of a non-trailing-slash path consistent across all
backends regardless of native capability.

The in-memory service tolerated the bug because its native lister treats
the trailing path component as a prefix, so it stayed latent until a real
WebDAV backend with native `Depth: infinity` exercised it. A focused
regression test using a WebDAV-style native-recursive mock backend is
added: it fails before this change (the sibling is dropped) and passes
after it.

Discovered while investigating apache#4256.

Signed-off-by: tonghuaroot <23011166+tonghuaroot@users.noreply.github.com>
@tonghuaroot tonghuaroot requested a review from Xuanwo as a code owner June 7, 2026 09:50
@dosubot dosubot Bot added size:L This PR changes 100-499 lines, ignoring generated files. releases-note/fix The PR fixes a bug or has a title that begins with "fix" labels Jun 7, 2026
Drop step-by-step narration in the prefix-handling arm and the test
fixture/regression-test doc comments; keep the non-obvious intent.

@erickguan erickguan left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good find in the linked issue! Can you rebase? You could click request review near reviewers to send a notification.

self.config.list_recursive,
) {
// Backend supports recursive list, forward directly.
// Match the non-recursive arm: for a non-trailing-slash path, list

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

minor (non-blocking): If we are breaking out these pattern matching, I would go with some more clear function names. A bunch of boolean matches are really difficult to follow.

Comment on lines +371 to +372
/// Native-recursive backend with WebDAV `Depth: infinity` semantics: a file
/// path lists only that file and its subtree, not prefix-siblings.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
/// Native-recursive backend with WebDAV `Depth: infinity` semantics: a file
/// path lists only that file and its subtree, not prefix-siblings.
/// Native-recursive backend, e.g., WebDAV with `Depth: infinity` semantics, a file
/// path lists only that file and its subtree, not prefix-siblings.

Did you find tests for non-recursive service tests (perhaps tests for this layer's behavior?

fn info(&self) -> Arc<AccessorInfo> {
let info = AccessorInfo::default();
info.set_scheme("memory");
info.set_native_capability(Capability {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We integrated this API into capability() API in Service trait now.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

releases-note/fix The PR fixes a bug or has a title that begins with "fix" size:L This PR changes 100-499 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants