when use io.copy and fmt.Fprintf write to http.ResponseWriter, the Response's head is not the same

2,013 views
Skip to first unread message

wachmc

unread,
Feb 5, 2012, 2:52:50 AM2/5/12
to golang-nuts
when i try this:
func handler(w http.ResponseWriter, r *http.Request) {
rr := strings.NewReader("<body>hello</body>")
io.copy(w, rr)
}
the Response's head's Content-Type:text/plain;

but try this:
func handler(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "<body>hello</body>")
}
the Response's head's Content-Type:text/html;

what lead to the difference?

David Symonds

unread,
Feb 5, 2012, 3:38:05 AM2/5/12
to wachmc, golang-nuts

Sounds like a bug. Can you file it on the issue tracker?

Dave.

Sanjay Menakuru

unread,
Feb 5, 2012, 4:18:21 AM2/5/12
to golan...@googlegroups.com, wachmc
I can't reproduce this... This is what I'm testing with http://play.golang.org/p/xi2czF7UDC  on tip, and seems to give text/html for both

What revision are you on?

Sanjay

Patrick Mylund Nielsen

unread,
Feb 5, 2012, 4:26:28 AM2/5/12
to golan...@googlegroups.com, wachmc
There's definitely something strange here. Using your example on the latest tip (da15310087d6+), Linux x64:

HTTP/1.1 200 OK
Date: Sun, 05 Feb 2012 09:22:27 GMT
Content-Type: text/plain; charset=utf-8

HTTP/1.1 200 OK
Date: Sun, 05 Feb 2012 09:22:29 GMT
Content-Type: text/plain; charset=utf-8

wachmc

unread,
Feb 5, 2012, 7:24:02 AM2/5/12
to golang-nuts
my 8g version is release.r60.3 9516

On Feb 5, 5:18 pm, Sanjay Menakuru <balasan...@gmail.com> wrote:
> I can't reproduce this... This is what I'm testing withhttp://play.golang.org/p/xi2czF7UDC on tip, and seems to give text/html

wachmc

unread,
Feb 5, 2012, 7:40:02 AM2/5/12
to golang-nuts
Patrick, i try curl the result are both text/plain,
but under firefox/chromium the result are text/plain and text/html...

On Feb 5, 5:26 pm, Patrick Mylund Nielsen <g...@patrickmylund.com>
wrote:
> There's definitely something strange here. Using your example on the latest
> tip (da15310087d6+), Linux x64:
>
> # curl -Ihttp://localhost:8080/1
> HTTP/1.1 200 OK
> Date: Sun, 05 Feb 2012 09:22:27 GMT
> Content-Type: text/plain; charset=utf-8
>
> # curl -Ihttp://localhost:8080/2

Sanjay Menakuru

unread,
Feb 5, 2012, 7:41:33 AM2/5/12
to golan...@googlegroups.com
When you curl -I, you're sending a HEAD request, and the io.Copy and fmt.Fprintf are actually just returning an error because writing on a HEAD request is not allowed. And the actual output will be the default 503 response, so the text/plain response is expected there

Sanjay

Sanjay Menakuru

unread,
Feb 5, 2012, 7:52:35 AM2/5/12
to golan...@googlegroups.com
Try curl -D /dev/stdout http://localhost:8080/1 and curl -D /dev/stdout http://localhost:8080/2.

Both give me:
HTTP/1.1 200 OK
Date: Sun, 05 Feb 2012 12:43:04 GMT
Transfer-Encoding: chunked
Content-Type: text/html; charset=utf-8

<body>hello</body>

Or alternatively -v will show dataflow in detail.

Sanjay

Sanjay Menakuru

unread,
Feb 5, 2012, 7:53:30 AM2/5/12
to golan...@googlegroups.com
If you take a look at this function http://tip.golang.org/src/pkg/net/http/sniff.go?s=576:618#L11, you can see one of the patterns its matching is "<BODY" declared on line 64.

Sanjay
Message has been deleted

wachmc

unread,
Feb 5, 2012, 7:55:10 AM2/5/12
to golang-nuts
thanks

On Feb 5, 8:53 pm, Sanjay Menakuru <balasan...@gmail.com> wrote:
> If you take a look at this
> functionhttp://tip.golang.org/src/pkg/net/http/sniff.go?s=576:618#L11, you

wachmc

unread,
Feb 5, 2012, 8:01:18 AM2/5/12
to golang-nuts
But, i still don't know why use io.copy, the outcome is text/plain?

On Feb 5, 8:53 pm, Sanjay Menakuru <balasan...@gmail.com> wrote:
> If you take a look at this
> functionhttp://tip.golang.org/src/pkg/net/http/sniff.go?s=576:618#L11, you
Message has been deleted

Patrick Mylund Nielsen

unread,
Feb 5, 2012, 7:48:08 AM2/5/12
to golan...@googlegroups.com
One can argue if that's what it's supposed to be doing, though:

RFC 2616: "The HEAD method is identical to GET except that the server MUST NOT return a message-body in the response. The metainformation contained in the HTTP headers in response to a HEAD request SHOULD be identical to the information sent in response to a GET request. This method can be used for obtaining metainformation about the entity implied by the request without transferring the entity-body itself."

Should a HEAD request for an MP3 file really be returning Content-Type: text/plain?

David Symonds

unread,
Feb 5, 2012, 5:28:39 PM2/5/12
to Patrick Mylund Nielsen, golan...@googlegroups.com
On Sun, Feb 5, 2012 at 11:48 PM, Patrick Mylund Nielsen
<g...@patrickmylund.com> wrote:

> One can argue if that's what it's supposed to be doing, though:
>
> RFC 2616: "The HEAD method is identical to GET except that the server MUST
> NOT return a message-body in the response. The metainformation contained in
> the HTTP headers in response to a HEAD request SHOULD be identical to the
> information sent in response to a GET request. This method can be used for
> obtaining metainformation about the entity implied by the request without
> transferring the entity-body itself."
>
> Should a HEAD request for an MP3 file really be returning Content-Type:
> text/plain?

"SHOULD" implies something to be done if it is feasible. In this case,
the sniffer cannot sniff an absent body, so the handler code needs to
explicitly w.Header().Set("Content-Type", "audio/mp3") or whatever.
So, yes, the server should be doing this, but it's not something that
the net/http can really help with.


Dave.

David Symonds

unread,
Feb 5, 2012, 5:30:47 PM2/5/12
to Patrick Mylund Nielsen, golan...@googlegroups.com
On Mon, Feb 6, 2012 at 9:28 AM, David Symonds <dsym...@golang.org> wrote:

> So, yes, the server should be doing this, but it's not something that
> the net/http can really help with.

Actually, it could, if the handler always yields a body even for HEAD
requests. However, it's probably a good idea for HEAD-aware handlers
to start with something like

if req.Method == "HEAD" {
// set headers, etc.
return
}

because HEAD requests are meant to be lightweight, and copying a large
response body around is not lightweight.


Dave.

David Symonds

unread,
Feb 5, 2012, 11:54:56 PM2/5/12
to Patrick Mylund Nielsen, golan...@googlegroups.com
On Mon, Feb 6, 2012 at 3:47 PM, Patrick Mylund Nielsen
<g...@patrickmylund.com> wrote:

> It seems the RFC is pretty specific about Content-Type: "The Content-Type
> entity-header field indicates the media type of the entity-body sent to the
> recipient or, in the case of the HEAD method, the media type that would have
> been sent had the request been a GET."
>
> If you agree with the previous:  http://codereview.appspot.com/5633045

That looks sensible to me. I'd put the "w.req.Method != "HEAD" check
on the outer if statement, and remove Content-Type from the filter
list (it's reasonable to set it for 304 responses too).


Dave.

Patrick Mylund Nielsen

unread,
Feb 5, 2012, 11:47:16 PM2/5/12
to David Symonds, golan...@googlegroups.com
Dave,

It seems the RFC is pretty specific about Content-Type: "The Content-Type entity-header field indicates the media type of the entity-body sent to the recipient or, in the case of the HEAD method, the media type that would have been sent had the request been a GET."

If you agree with the previous:  http://codereview.appspot.com/5633045 

Best,
Patrick

On Mon, Feb 6, 2012 at 05:25, Patrick Mylund Nielsen <g...@patrickmylund.com> wrote:
Yeah. It seems silly to start reading the body just to infer the type for that header.

Perhaps it would be less confusing if the Content-Type header just wasn't set (by default) for HEAD requests?

Patrick Mylund Nielsen

unread,
Feb 5, 2012, 11:25:54 PM2/5/12
to David Symonds, golan...@googlegroups.com
Yeah. It seems silly to start reading the body just to infer the type for that header.

Perhaps it would be less confusing if the Content-Type header just wasn't set (by default) for HEAD requests?

On Sun, Feb 5, 2012 at 23:30, David Symonds <dsym...@golang.org> wrote:
Reply all
Reply to author
Forward
0 new messages