[grid] Fix 500 when downloading a file whose name contains spaces - #17968
Conversation
Qodo reviews are paused for this user.Troubleshooting steps vary by plan Learn more → On a Teams plan? Using GitHub Enterprise Server, GitLab Self-Managed, or Bitbucket Data Center? |
|
did not look too deep into this but:
PS: this is a fix to a deprecated method to download the file: |
|
Thanks for taking a look, @joerg1985! Some answers, hopefully they address the concerns: 1. On 2. On the charset — it is pinned to UTF-8: each disallowed code point is turned into its UTF-8 bytes and percent-encoded per RFC 3986. I avoided 3. On the risk in PS. on the deprecated endpoint — fair point. The |
…ownload paths The existing round-trip test for JdkHttpMessages#quoteIllegalCharacters only covers a space and an apostrophe (both single-byte ASCII), so the multi-byte UTF-8 percent-encoding branch (codePointAt/surrogate-pair handling) was implemented but never exercised end-to-end through a real client/server round trip. Add a case with a Cyrillic character, an umlaut, and an emoji (a surrogate pair) to close that gap.
🔗 Related Issues
Fixes #17955
💥 What does this PR do?
GET /session/{sessionId}/se/files/{fileName}returns 500 whenever the filename contains a space (reported on 4.46, still present in 4.48):
The root cause is a decode/re-encode asymmetry between the server and the
HTTP client:
(
QueryStringDecoder.path()inRequestConverter), so%20becomes aliteral space in the
HttpRequestURI.JdkHttpMessages#getRawUribuilds the target URI with
URI#create, which rejects characters like aliteral space, and the whole request fails with a 500.
This PR makes the proxy quote such characters, and stops the node from
decoding the file name a second time.
What changed:
JdkHttpMessages— characters that are not allowed in a URI arepercent-encoded when building the URI of an outgoing request. Every
character that
URIaccepts is left untouched, so URIs that were validbefore are sent byte-for-byte exactly as they were.
LocalNode#extractFileName— no longer callsurlDecode(...).replace(' ', '+'). The path of the request has alreadybeen decoded by the server, so the extra decode turned a real file name
into
name+with+spaces.pdf, which never matched the file on disk.The substring after
/se/files/is now used as-is.HttpClientTestBase— new round-trip test: a request whose path holds aspace (and a non-ASCII character) is sent through a real Netty server, and
the handler must receive the same path decoded back.
LocalNodeTest—extractsFileNameFromRequestUrinow also covers a namewith spaces; the existing assertions are unchanged.
🔧 Implementation Notes
An alternative would be to keep the raw, undecoded path in
RequestConverter, but every route (UrlTemplate,getSessionId, …)matches against the decoded value, so that would be a much larger change.
Quoting at the outgoing edge instead is local and provably safe: the
transformation is the identity function for every URI that was already
valid, so only requests that previously failed with
URISyntaxExceptionbehave differently.
The deprecated
GET /se/files/{name}endpoint is kept working rather thanremoved (it was marked for removal in #16844). The
POST /se/filesendpoint,which all bindings use, is unaffected.
🤖 AI assistance
in
JdkHttpMessagesandLocalNode#extractFileName, and the two testadditions. I reviewed the final diff, ran the tests locally
(
//java/test/org/openqa/selenium/remote/http:small-tests,//java/test/org/openqa/selenium/grid/node/local:LocalNodeTest)and verified the fix end-to-end against a running Grid server.
💡 Additional Considerations
?still cannot be referenced by thisendpoint (the character separates the query string) — same as before this
PR.
%is ambiguous after decoding, and islikewise out of scope here.
🔄 Types of changes