Calling Close() on http.Request.Body

11,050 views
Skip to first unread message

Maxim Khitrov

unread,
Nov 11, 2012, 7:34:49 PM11/11/12
to golang-nuts
Hello,

I'm writing an http server that will need to deal with large file
uploads. I went digging through the net/http source to figure out what
r.Body.Close() does, because there isn't much information about it in
the docs. I assumed that Body was an io.ReadCloser for a reason, such
as to allow the server to stop the client from sending any more data.

Assuming I found the right section of the code (*body.Close() in
transfer.go), I was surprised to see that Close() will actually read
the rest of the request and then leave the connection open.

My question is under what circumstances should an http request handler
actually call r.Body.Close()? It looks like if I want the client to
abort the upload, I should set the "Connection: close" header and then
return from the handler without doing anything else. Is that correct?

Am I also correct in assuming that unless the entire request is
consumed by the server, there is no way for the client to actually
show anything that was sent in the response? Even when I write
something to w, an early close results in a "The connection was reset"
error message (in Firefox).

- Max

Kevin Gillette

unread,
Nov 11, 2012, 10:32:35 PM11/11/12
to golan...@googlegroups.com
The implicit wrapping function that calls your handler calls r.Body.Close() always when your handler returns. When using r.Body in an http client, you may need to manually call it

Jesse McNelis

unread,
Nov 12, 2012, 1:48:02 AM11/12/12
to Maxim Khitrov, golang-nuts
On Mon, Nov 12, 2012 at 11:34 AM, Maxim Khitrov <m...@mxcrypt.com> wrote:
Assuming I found the right section of the code (*body.Close() in
transfer.go), I was surprised to see that Close() will actually read
the rest of the request and then leave the connection open.

HTTP is a request/response protocol. You can't send a response without a request and you can't receive a new request until you've processed the previous request.
The http pkg uses keep-alive to avoid having to make a new connection for each request, but this means that it needs to clear the previous request so it can wait for a new  one and that's what r.Body.Close() does.

My question is under what circumstances should an http request handler
actually call r.Body.Close()? It looks like if I want the client to
abort the upload, I should set the "Connection: close" header and then
return from the handler without doing anything else. Is that correct?

If you want the client to abort the upload you'll need to hijack and close the tcp connection.

Am I also correct in assuming that unless the entire request is
consumed by the server, there is no way for the client to actually
show anything that was sent in the response? Even when I write
something to w, an early close results in a "The connection was reset"
error message (in Firefox).

A http client doesn't expect a response until it's finished sending the request.


--
=====================
http://jessta.id.au


Maxim Khitrov

unread,
Nov 12, 2012, 1:51:39 PM11/12/12
to Jesse McNelis, golang-nuts
On Mon, Nov 12, 2012 at 1:48 AM, Jesse McNelis <jes...@jessta.id.au> wrote:
> On Mon, Nov 12, 2012 at 11:34 AM, Maxim Khitrov <m...@mxcrypt.com> wrote:
>>
>> Assuming I found the right section of the code (*body.Close() in
>> transfer.go), I was surprised to see that Close() will actually read
>> the rest of the request and then leave the connection open.
>
>
> HTTP is a request/response protocol. You can't send a response without a
> request and you can't receive a new request until you've processed the
> previous request.
> The http pkg uses keep-alive to avoid having to make a new connection for
> each request, but this means that it needs to clear the previous request so
> it can wait for a new one and that's what r.Body.Close() does.

I understand why it does this, it's just that the name Close() and the
docs do not imply this behavior. I would add exactly what you wrote to
the documentation of http.Request to clear this up.

>> My question is under what circumstances should an http request handler
>> actually call r.Body.Close()? It looks like if I want the client to
>> abort the upload, I should set the "Connection: close" header and then
>> return from the handler without doing anything else. Is that correct?
>
>
> If you want the client to abort the upload you'll need to hijack and close
> the tcp connection.

Looking at the server.go source and from my own testing, hijacking the
connection isn't necessary. I'm still unclear about possible cases
when a handler would need to call Body.Close() directly. If there are
no such cases, then why was it declared as io.ReadCloser instead of
simply io.Reader? The code in server.go could have always done a type
assertion.

>> Am I also correct in assuming that unless the entire request is
>> consumed by the server, there is no way for the client to actually
>> show anything that was sent in the response? Even when I write
>> something to w, an early close results in a "The connection was reset"
>> error message (in Firefox).
>
>
> A http client doesn't expect a response until it's finished sending the
> request.

That's not a technical limitation, however, but I suspect it's in the
RFC. I just wanted to see if there are some possible ways around that
behavior.

Anoop K

unread,
Feb 28, 2013, 2:25:18 AM2/28/13
to golan...@googlegroups.com
If r.Body is read as ioutil.ReadAll(r.Body), do we still need to invoke defer r.Body.Close(). Won't ioutil.ReadAll ensures that data from socket is read till EOF ?

Tamás Gulácsi

unread,
Feb 28, 2013, 3:03:46 AM2/28/13
to golan...@googlegroups.com
If you don't want to leave sockets opened, then call Close!
Reply all
Reply to author
Forward
0 new messages