-
Notifications
You must be signed in to change notification settings - Fork 17.9k
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
net/http: Docs update for connection reuse #26095
Comments
https://golang.org/pkg/net/http/#Response
I believe this is sufficient, and pretty clearly mentioned. Please let us know if you had anything else in mind or maybe you missed this part ? |
Here https://golang.org/pkg/net/http/#Client.Do:
I think it would also be good on top in the examples section to put a example with |
@agnivade the text you've highlighted is clear on what needs to be done (read to completion and closed) to avoid something bad (may not reuse connection), but I think the problem is the other places where closing the body is mentioned. This is a very common complaint so I think it's worth digging deeper on this.
Perhaps we've been trying to avoid duplicating:
all over the docs because it's verbose and because some people might not care about connection reuse. One alternative is to to be more concise and say "the caller must read the body to completion and close" without saying why, but that's dishonest since they don't really need to in all cases. @bradfitz am I missing any nuance here? |
I see. Then this line |
Exactly. I would love to see it documented in every function but it's a lot copy paste. Are there references in godocs which we can use so the phrase is only documented once? Another option would be to change the Body.Close() method to automatically read all data before closing it but I think this would be a bigger change |
Didn't this "read body to completion" come up as a security issue at some point? I don't remember if it was just server or client related (or both), but basically if Go automatically read the body to completion than it would be trivial for the program to be DoS'd (cpu/memory consumption). The counterpart could just send an infinite body and the Go program would sit there consuming it all, and if you're not consuming it explicitly in your code (ioutil.Discard or otherwise) then the developer of the program might not know it was happening. I thought I saw a commit a while back that had Go read part of the body to a certain point but if it kept going then it would close the connection abruptly, to avoid this potiental DoS. If thats the case, and you make another request while some goroutine is doing this, it would make sense that a new connection would be made (what you're seeing here and why reading the body to completion is the "solution"). In fact, if you don't read the body to completion from both a security and "HTTP" standpoint doesn't it make more sense to close the connection on (or near) body close and reopen a new connection when needed? That way it's only one connection at a time. |
To be precise, what does it mean for a Body to be read to completion?
The RFC verbiage doesn't help me understand under what conditions it may or may not reuse the connection. I suspect this was chosen because the request might return an error, but this information is already fuzzy when reading the package documentation:
Above, the example fails to convey the careful dance required to make connections reusable. The error Second, the Body is consumed and assigned to a variable called The number of users that do this correctly in private repositories is none. I have never seen it, nor can I remember the last time I've seen it in open source projects. I suspect it's because of the term I think the term |
@bradfitz sorry for a noisy comment, but this looks to be part of the Go 1.12 milestone. Wanted to ping you again for 👀. |
Change https://golang.org/cl/158417 mentions this issue: |
I sent off https://golang.org/cl/158417 to add a bit more. That's probably enough for Go 1.12. |
Updates #26095 (or fixes it) Change-Id: I92488dabe823b82e1ba534648fe6d63d25d0ae9f Reviewed-on: https://go-review.googlesource.com/c/158417 Reviewed-by: Ian Lance Taylor <[email protected]>
From what i see in the source code, response.Body.Close() method should take care of draining body: Line 979 in 9d23975
|
Took me some hours to find this hack |
@dmarkhas @drscre this issue has gone stale. I am going to close it based on @bradfitz 's comment #26095 (comment). If there is work unaddressed I would appreciate if it you can open a new issue that captures the delta. Thank you. |
What version of Go are you using (
go version
)?go version go1.10.2 windows/amd64
Does this issue reproduce with the latest release?
yes
What operating system and processor architecture are you using (
go env
)?set GOARCH=amd64
set GOBIN=
set GOCACHE=C:\Users\firefart\AppData\Local\go-build
set GOEXE=.exe
set GOHOSTARCH=amd64
set GOHOSTOS=windows
set GOOS=windows
set GOPATH=C:\Users\firefart\go
set GORACE=
set GOROOT=C:\Go
set GOTMPDIR=
set GOTOOLDIR=C:\Go\pkg\tool\windows_amd64
set GCCGO=gccgo
set CC=gcc
set CXX=g++
set CGO_ENABLED=1
set CGO_CFLAGS=-g -O2
set CGO_CPPFLAGS=
set CGO_CXXFLAGS=-g -O2
set CGO_FFLAGS=-g -O2
set CGO_LDFLAGS=-g -O2
set PKG_CONFIG=pkg-config
set GOGCCFLAGS=-m64 -mthreads -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -fdebug-prefix-map=C:\Users\firefart\AppData\Local\Temp\go-build959778686=/tmp/go-build -gno-record-gcc-switches
Suggested Change
Currently the docs on https://golang.org/pkg/net/http/ say that you need to close the response Body after you are done with it so golang can reuse the connection. In my tests it turned out, that you have to actually consume the body before closing it otherwise the connection will not be reused.
I think it should be stated everywhere in the referenced docs where Close is mentioned that you have to consume the body too. If you do not consume the body golang will create new connections on every request.
If you aren't interested in the body, you need to do smth like
This blog post also describes the problem:
https://awmanoj.github.io/tech/2016/12/16/keep-alive-http-requests-in-golang/
Here is a sample program to demonstrate the problem:
Here is the timing output from only closing the body, and the other time with consuming it before. Each test was executed twice to make sure it's no network based problem. Also a https URL was used to demonstrate the problem because the TLS handshake takes a lot of time.
You can also verify this behaviour using wireshark and have a look at the source port. If it changes on every request there is no connection reuse.
So it would be great if you can add this case to the net/http docs
The text was updated successfully, but these errors were encountered: