-
-
Notifications
You must be signed in to change notification settings - Fork 243
Description
Currently, there are a few high-level Response methods to inspect body:
- Body - reads the whole body and returns it as String
- Text - reads the whole body and returns it as String
- Form - reads the whole body and returns it as Object
- JSON - reads the whole body and returns it as Value
- JSONP - reads the whole body and returns it as Value
All these methods internally use Response.getContent to retrieve body.
Now, we want to add a more low-level method that would allow user to read body manually:
func (r *Response) Reader() io.ReadCloser
This method will return a reader, which can be used to read response body. Unlike the methods listed above, it should be able to work with infinite responses too, and does not place any limitations on response format.
This method will be mutual exclusive with the methods listed above. User should either call Reader or one of those methods.
Here is how it should work:
- check if the chain is failed; if it is, it should return nil
- check if getContent was already called by checking contentState; if it's not contentPending, then it should report failure and return nil
- check if the underlying type of resp.Body is bodyWrapper; if so, it should call bodyWrapper.DisableRewinds, to prevent bodyWrapper from trying to read the whole body into memory, and thus to allow infinite response
- set contentState to some new state, say, contentHijacked, which would mean that Response does not own body content anymore
- return resp.Body
Also getContent should be modified to report failure if contentState is contentHijacked.
We should also modify Body/Text/Form/etc, so that they will path method name (e.g. "Text()") to getContent, and modify getContent to store this method name. Then, when Response.Reader will report failure that getContent() was already called, it will be able to use that method name to explain user which exact method caused conflict, like this:
cannot call Reader() because Text() was already called
We use the same approach in Request.setType and Request.setBody.
Unit tests should be updated:
- we need to add a new subtest to TestResponse_BodyDeferred to cover contentHijacked
- we need to add a test for Response.Reader
- we need to add tests that checks how Reader and Body/Text/Form/etc are mutually-exclusive
We also need to add integration test to e2e/chunked_test.go
, which will stream a large (e.g. a megabyte) response from server to client, and use Response.Reader to retrieve that response.