-
Notifications
You must be signed in to change notification settings - Fork 85
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
StandaloneWSClient.url(String) permits inconsistent states with query params #267
Comments
@gmethvin & @marcospereira, I could use your guidance here. Would be nice to nail this down before v2. |
Hi @htmldoug, Thanks for the detailed and well-thought issue. Right now, I think the tolerant approach is the recommended one. There are some other expectations that we can do around the API:
Ideally, these changes should add comprehensive tests to ensure they are consistent.
We can have a method like this: def copy(url: String) That does all the work necessary to ensure things are consistent. |
Thanks for the direction. I'd be interested in submitting a PR for the tolerant route, having written one already around my existing use of the play25 WSClient. Implementation is here: https://gist.github.com/htmldoug/38cfa714b33123c6695ec272cfcae6c1 Before proceeding, I'd like for you to witness how gnarly it is and confirm that you really want it. Feel free to mark it up with comments for any changes you'd like to see. Overloading Note that one consequence of removing the query params from the val baseUrl: String = "http://example.com/path?a=1"
ws.url(baseUrl).url == baseUrl // false. yields "http://example.com/path" perhaps surprising.
ws.queryString("a") // this would work now though. yay! Overall, I think this is a sensible way to go. Just give me the green light and I'll put up a PR. |
There are a couple of posts that talk about parsing URIs:
There are external libraries that will augment the functionality of WS: galimatias validates URLs, and scala-url-builder and url-builder will build up guaranteed valid URLs. |
Summary
Behavior of query parameters in
wsClient.url(String)
is not well defined and permits inconsistent states. For example,wsClient.url("http://postman-echo.com/get?pipe=|").execute()
successfully sends the request ashttp://postman-echo.com/get?pipe=%7C"
, butwsRequest.queryString
returns an empty map, andwsRequest.uri
throws aURISyntaxException
.This makes methods
uri
andqueryString
hard to reason about and use, since they may differ from what is actually sent or throw exceptions.Behavior Example
Prints:
Wireshark sees:
Observations
The scaladoc is unclear. "url" implies https://tools.ietf.org/html/rfc1738, and yet
"base URL"
implies maybe not?Tolerant or Strict?
I think we'd benefit from committing to one of these two approaches and documenting.
Tolerant
The behavior of
org.asynchttpclient.util.UriEncoder.FIXING
could be pulled up toStandaloneAhcWSClient.url(String)
to create something sane, parsing query params, perhaps decoding the values, and putting them in thequeryString
field. From there,lazy val uri: URI
can figure it out andqueryString
would reflect reality.Downside is that
StandaloneWSRequest.copy(url = "")
exists and would still allow for inconsistent states. At least it'd be better.Scaladoc would be updated to indicate that the URI parameter means https://tools.ietf.org/html/rfc1738 and tolerantly accepts query string values either encoded or in plaintext.
Strict
StandaloneAhcWSRequest
would throw if query params are present inurl
, which could be renamedbaseUrl: String
, and defined as "everything up to the query params".A consistency oriented implementation could add
require(uri.getQuery == null)
which would force parsing of the `java.net.URI. This is a bit heavy to do every method call of the builder.Alternatively, we could move this check into StandaloneAhcWSClient.validate().
Scaladoc would be updated to indicate that query params MUST NOT be part of the "baseUrl".
Workarounds
In my current production Play 2.5 services, I'm defensively decorating
WSClient
to intercept theWSRequest
prior to execution, and running it throughUriEncoder.FIXING
just as AHC does under the hood, and moving any query params into theWSRequest.queryString
field.It's kludgy without #264. I ended up requiring a WSClient and just rebuilding the whole request from scratch. I'd love for this to be handled upfront by the library so I don't have to second guess every request.
Relates to playframework/playframework#7444.
The text was updated successfully, but these errors were encountered: