Home > database >  why does golang http ResponseWriter auto add content-length if it's no more than 2kb
why does golang http ResponseWriter auto add content-length if it's no more than 2kb

Time:01-12

func (handler Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
    var content string
    ...
    w.Write([]byte(content))
}

if len(content) <= 2048, the content-length will be added automatically in the response. And if it's over 2048, there is no content-length, and the Transfer-Encoding: chunked will be added.
I can't find where to determine the 2048.

I'm asking for help to find the source code that where to determine the 2048.

CodePudding user response:

Let's look at the documentation of this feature in the http.ResponseWriter interface just for clarity:

[I]f the total size of all written data is under a few KB and there are no Flush calls, the Content-Length header is added automatically.

First, we can see that the number may not be exactly 2048 (2 KB), but that is in the range we would expect for "a few KB". Second, we can see that this behaviour has something to do with the Flush method, which is documented in the Flusher interface:

Flush sends any buffered data to the client.

The Flusher interface is implemented by ResponseWriters that allow an HTTP handler to flush buffered data to the client.

The default HTTP/1.x and HTTP/2 ResponseWriter implementations support Flusher, but ResponseWriter wrappers may not. Handlers should always test for this ability at runtime.

As it says, your ResponseWriter may support data buffering and flushing. What this means is that when you write data to the response writer, it does not immediately get transmitted over the connection. Instead, it first gets written into a buffer. Each time the buffer is too full to write to anymore, and when the ServeHTTP method returns, the whole buffer will get transmitted. This ensures that data gets transmitted efficiently even when you do lots of tiny writes, and that all data gets transmitted in the end. You also have the option of proactively emptying the buffer at any time with the Flush method. The HTTP headers must be sent before the body data, but there's no need to send them until the first time the buffer is emptied.

Putting all this together, you'll see that if the total amount written is no more than the buffer size, and we never call Flush, then the headers do not need to be sent until all the data is ready, at which point we know the content length. If the total amount written is more than the buffer size, then the headers must be sent before the content length is known, and so the ResponseWriter can't determine it automatically.

This is implemented in the source in net/http/server.go. Specifically, here are the declarations of the buffer size, and the chunkedWriter which implements part of the buffered writing behaviour:

// This should be >= 512 bytes for DetectContentType,
// but otherwise it's somewhat arbitrary.
const bufferBeforeChunkingSize = 2048

// chunkWriter writes to a response's conn buffer, and is the writer
// wrapped by the response.w buffered writer.
//
// chunkWriter also is responsible for finalizing the Header, including
// conditionally setting the Content-Type and setting a Content-Length
// in cases where the handler's final output is smaller than the buffer
// size. It also conditionally adds chunk headers, when in chunking mode.
//
// See the comment above (*response).Write for the entire write flow.
type chunkWriter struct {

Link to the source code for 1.19.5. Please note that the source code is subject to change with each Go release.

CodePudding user response:

The value is defined here:

// This should be >= 512 bytes for DetectContentType,
// but otherwise it's somewhat arbitrary.
const bufferBeforeChunkingSize = 2048

The Life of a Write explains what happens:

If the handler didn't declare a Content-Length up front, we either go into chunking mode or, if the handler finishes running before the chunking buffer size, we compute a Content-Length and send that in the header instead.

  • Related