5

Assume that we have a function handling an HTTP Request, something like:

func handler(w http.ResponseWriter,  r *http.Request) {
    w.Write([]byte("first piece of data"))
    // do something
    w.Write([]byte("second piece of data"))
}  

I'm wondering that if the first call to w.Write() is flushed to client or not?

If it is flushed, then we actually responses to clients twice, this is strange because how can we determine Content-Length before the second call to write?

If it is not flushed (say the data is buffered locally), then what if we write a huge amount of data at the first call? (will that stack overflow?)

Any explanation will be appreciated! :)

Simon Fox
  • 5,995
  • 1
  • 18
  • 22
dastan
  • 1,006
  • 1
  • 16
  • 36

1 Answers1

6

I'm wondering that if the first call to w.Write() is flushed to client or not?

net/http's default ResonseWriter has a (currently 4KB) large output buffer over the net.Conn it writes to. Additionally, the OS normally will buffer writes to a socket. So in most cases some kind of buffering takes place.

If it is flushed, then we actually responses to clients twice, this is strange because how can we determine Content-Length before the second call to write?

Well there's HTTP 1.1 which allows persistent connections. Such responses usually don't include a Content-Length header. Additionally, there's HTTP trailers.

If your client does not support HTTP 1.1 and persistent connections they will have some sort of read timeout, during this time you can write to the connection as many times as you like; it's one response.

This has more to do with the nature of TCP sockets and HTTP implementations than Go.

If it is not flushed (say the data is buffered locally), then what if we write a huge amount of data at the first call? (will that stack overflow?)

No, allocating a buffer on the stack makes no sense – the buffer's body will live on the heap. If you hit your per-process memory limit your application will panic "out of memory".

See also:

Edit to answer your question in the comments:

Chunked Transfer Encoding is part of the HTTP 1.1 specification and not supported in HTTP 1.0.

Edit to clarify:

As long as the total time it takes you to write both parts of your response does not exceed your client's read time out, and you don't specify a Content-Length header you just write your response and then close the connection. That's totally OK and not "hacky".

Community
  • 1
  • 1
thwd
  • 23,956
  • 8
  • 74
  • 108
  • HTTP trailers are supported by both, Go's `net/http` Server and Client implementations. And no, a client without a read timeout wouldn't last a day in the wild. An HTTP's server output buffering strategy has absolutelty nothing to do with HTTP and yes, the OS buffers writes to sockets, which in case of HTTP are TCP sockets. You're trying too hard to bash other peoples answers. – thwd Sep 25 '14 at 14:54
  • 2
    [Yes they do](https://golang.org/src/pkg/net/http/transfer.go#L32), I will ignore your comments from now on. – thwd Sep 25 '14 at 15:01
  • If the client only support HTTP 1.0, can I still use 'chunked-encoding'? I'm not quite clear about your answer on this aspect. Please explain more. – dastan Sep 29 '14 at 09:13
  • I know `chunked-encoding` is not supported by HTTP 1.0, but according to your previous explanation 'If your client does not support HTTP 1.1...', there seems to be a `hacking way` to achieve the same effect on HTTP 1.0, and I wanna know that. – dastan Sep 29 '14 at 10:03