Skip to content
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

httpclient Response object references original Request; refs #16685 #16691

Closed
wants to merge 6 commits into from
Closed

Conversation

daehee
Copy link
Contributor

@daehee daehee commented Jan 12, 2021

  • Add request field to Response & AsyncResponse objects,
  • Update related tests in thttpclient.nim
  • Clear "ambiguous identifier" error on tasynchttpserver.nim

* Avoid ambiguous identifier collision with asynchttpserver Request
object
@daehee
Copy link
Contributor Author

daehee commented Jan 12, 2021

@dom96 thanks for the feedback, updated

@daehee daehee requested review from timotheecour and dom96 January 13, 2021 14:53
doAssert req.reqMethod == HttpGet
doAssert $req.url == "http://example.com/"
let clientAgent = $req.headers["user-agent"]
doAssert clientAgent.contains("Nim httpclient")
Copy link
Member

Choose a reason for hiding this comment

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

DRY:

Suggested change
doAssert clientAgent.contains("Nim httpclient")
doAssert clientAgent == defUserAgent

template testPreparedRequest(req: PreparedRequest) =
doAssert req.reqMethod == HttpGet
doAssert $req.url == "http://example.com/"
let clientAgent = $req.headers["user-agent"]
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
let clientAgent = $req.headers["user-agent"]
let clientAgent = req.headers["user-agent"]

Copy link
Member

@timotheecour timotheecour left a comment

Choose a reason for hiding this comment

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

LGTM after addressing remaining comments

@timotheecour
Copy link
Member

let's wait until #16710

Co-authored-by: Dominik Picheta <[email protected]>
@Araq
Copy link
Member

Araq commented Jan 14, 2021

What are the use cases? In general you should avoid keeping everything in memory just because somebody might need it later. The "later" may never come but everybody pays the price. (Higher memory consumption.)

@daehee
Copy link
Contributor Author

daehee commented Jan 14, 2021

@Araq I'd have to think more on the broader range of use cases for the community, but here are some immediate examples:

  1. To see what ultimately is constructed by httpclient request, which can be used e.g. calculate full size of the original Request (sum of method, URL, headers and body)
  2. Get the history of 3xx redirects e.g. https://requests.readthedocs.io/en/master/user/quickstart/?highlight=history#redirection-and-history

Without the original request attached to the Response, the original Uri, HttpHeader, other related request data needs to be passed along with the Response and may lead to more verbose, error-prone code.

Just as a quick hacky example:

import uri, httpclient, options, strformat

proc getRedirectTarget(resp: Response, u: Uri): tuple[url: Uri, code: HttpCode] =
  if resp.headers.hasKey("location") and resp.code.is3xx():
    var target = parseUri(resp.headers["location"])
    if not target.isAbsolute():
      target = parseUri(&"{u.scheme}://{u.hostname}{target}")
    result = (target, resp.code)

let url = "https://tinyurl.com/examplezoom"
let client = newHttpClient(maxRedirects=0)
let resp = client.get(url)
echo resp.getRedirectTarget(parseUri(url))

@Araq
Copy link
Member

Araq commented Jan 14, 2021

To see what ultimately is constructed by httpclient request, which can be used e.g. calculate full size of the original Request (sum of method, URL, headers and body)

For debugging, make the debugging code opt-in.

@juancarlospaco
Copy link
Collaborator

This should be compile-time opt-in,
for performance, debugging and backwards compat.

@timotheecour
Copy link
Member

timotheecour commented Jan 15, 2021

For debugging, make the debugging code opt-in.

it's not just for debugging, but how about this:
add:

type RequestOption* = object
  preparedRequest*: bool
  # can grow in future
proc initRequestOption(): RequestOption = RequestOption(preparedRequest: false)
proc request(..., option = initRequestOption()) = ...

rationale for object instead of set[SomeOption]: same as in jsonutils #15133 (comment)

@dom96
Copy link
Contributor

dom96 commented Jan 15, 2021

For the best of both worlds, just put these additions behind a define: when defined(httpRespReqRef) (or something, feel free to choose a better name).

@timotheecour
Copy link
Member

I don't see how when defined(httpRespReqRef) is the "best of both worlds", whether to populate RequestOption should be decided at call site, not via some global all-or-nothing flag; if some 3rd party dependency requires it, you'd be forced to use it. defined that controls API's should be used sparingly, eg for legacy behavior, not for things that can co-exist long in the future.

Also, defined flags should have nim prefix.

@daehee
Copy link
Contributor Author

daehee commented Jan 18, 2021

On a related note what's the possibility of the Request type in asynchttpserver being refactored out and shared with httpclient? This new request object discussed here would create redundancy with what already exists in asynchttpserver:

Request* = object
client*: AsyncSocket # TODO: Separate this into a Response object?
reqMethod*: HttpMethod
headers*: HttpHeaders
protocol*: tuple[orig: string, major, minor: int]
url*: Uri
hostname*: string ## The hostname of the client that made the request.
body*: string

@juancarlospaco
Copy link
Collaborator

I like the idea of a shared Request object, if it is possible.

If you really taking the effort to improve it, would be better first to fix httpclient to be reusable, as it is now is kinda single-shot thing,
1st request always work, multiple requests with the same httpclient may eventually fail, thats even more broken.

@ringabout
Copy link
Member

ringabout commented Feb 9, 2021

let's wait until #16710

@timotheecour

@Araq
Copy link
Member

Araq commented Feb 23, 2021

This is not opt-in. Please re-open once addressed.

@bung87
Copy link
Collaborator

bung87 commented May 27, 2022

how about add a property like preserveRequest to client type and give a bool value when constructor new client ?

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

Successfully merging this pull request may close these issues.

7 participants