fix(services/dbfs): root the put path and stop encoding paths in JSON bodies - #8079
Merged
Conversation
… bodies
Two defects in how this service addresses paths, both in core.rs.
The path in the dbfs/put body is not rooted:
let req_body = &json!({
"path": path,
Every sibling roots it first -- create_dir at :60, delete at :89,
rename at :116, list at :142, get-status at :193 all call
build_rooted_abs_path. The value arrives from DbfsBackend::write as the
operator-relative path and nothing else applies the root, so with any
non-default root a write and the stat, list or delete that follows it
address different DBFS paths.
And four values are percent-encoded inside JSON request bodies:
"path": percent_encode_path(&p), // :65, :94
"source_path": percent_encode_path(&source), // :126
"destination_path": percent_encode_path(&target), // :127
Nothing URL-decodes a JSON string value. The genuine query strings at
:149 and :200 are encoded, and the server does decode those -- so the
two halves of this file disagree with each other. create_dir("my dir/")
creates a directory literally named my%20dir, while the get-status that
follows asks for "my dir" and gets NotFound. For delete it is worse than
an error: deleter.rs notes the server answers 200 even when the path
does not exist, so the call reports success having removed nothing.
A repo-wide grep for percent_encode_path inside json! across
core/services matches these four lines and nothing else; dbfs is the
only service in the tree that does it.
Neither change affects an ordinary path. percent_encode_path leaves
A-Z a-z 0-9 / - _ . ! ~ * ' ( ) untouched, so a plain key serialises
identically; only a path containing a space, %, #, ?, &, +, ,, :, =, @
or a non-ASCII byte changes, and those are the ones broken today.
One test, on the only one of the four that is a synchronous request
builder. The other three send inside async methods, so pinning them
would mean restructuring; their evidence is the in-file inconsistency
above. Reverting the rooting fails that test and nothing else.
The lister emits root-prefixed entry paths as well -- that is a separate
change to a separate file and is not in here.
Note for rebasing: apache#7801 renames build_rooted_abs_path in this file. If
it lands first the new call in dbfs_create_file_request needs the new
name.
erickguan
requested changes
Aug 15, 2026
|
|
||
| pub(super) use error::*; | ||
|
|
||
| #[cfg(test)] |
Contributor
Author
There was a problem hiding this comment.
Removed. The diff is now 5 lines, all in core.rs.
For what it is worth, I think I have your bar straight now: a test earns its place when it establishes something reading the code cannot. That test asserted build_rooted_abs_path(&self.root, path) yields /data/my file.txt, which is plain from the call itself — whereas the thing you were after on #8067 was a real API response, which no hand-built fixture can stand in for. I will aim at that line rather than at a test count.
erickguan
approved these changes
Aug 15, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Which issue does this PR close?
None — found while reading the service.
Rationale for this change
Two defects in how
dbfsaddresses paths, both incore.rs.1. The
dbfs/putbody is not rooted.Every sibling roots it first —
create_dirat:60,deleteat:89,renameat:116,listat:142,get-statusat:193all callbuild_rooted_abs_path. Nothing else applies the root; it lives only inDbfsCore.root. So with any non-default root, a write and thestat,listordeletethat follows it address different DBFS paths.2. Four values are percent-encoded inside JSON request bodies.
Nothing URL-decodes a JSON string value. The genuine query strings at
:149and:200are encoded, and the server does decode those — so the two halves of this file disagree with each other:create_dir("my dir/")creates a directory literally namedmy%20dir,get-statusthat follows asks formy dirand getsNotFound.For
deleteit is worse than an error:deleter.rsnotes the server answers200even when the path does not exist, so the call reports success having removed nothing.A repo-wide grep for
percent_encode_pathinside ajson!acrosscore/servicesmatches these four lines and nothing else — dbfs is the only service in the tree that does it.Blast radius
Neither change affects an ordinary path.
percent_encode_pathleavesA-Z a-z 0-9 / - _ . ! ~ * ' ( )untouched, so a plain key serialises identically before and after. Only a path containing a space,%,#,?,&,+,,,:,=,@or a non-ASCII byte changes — and those are exactly the ones broken today.Tests
One, on the only one of the four that is a synchronous request builder:
It pins both halves at once — rooted, and not encoded. Reverting the rooting fails it and nothing else:
The other three send inside
asyncmethods, so pinning them would mean restructuring the functions; their evidence is the in-file inconsistency above. Happy to add more if you would like the coverage.Worth noting that
services-dbfshas no directory under.github/services, so nothing has been exercising any of this.Note for rebasing
#7801 renames
build_rooted_abs_pathin this file. If it lands first, the new call indbfs_create_file_requestneeds the new name.Are there any user-facing changes?
Yes, for
services-dbfs: a write now lands at the same DBFS path thatstat,listanddeleteuse, and a path containing a characterpercent_encode_pathescapes is no longer created, deleted or renamed under its escaped spelling.Not in this PR
The lister emits root-prefixed entry paths —
lister.rsnever callsbuild_rel_path, unlike the other ~34 HTTP service listers. That is a separate file and a separate user-visible surface, so I have kept it out to stay independently revertable.