Skip to content
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: Server sends duplicate `Transfer-Encoding: chunked` when set explicitly #15960

Closed
seoester opened this issue Jun 5, 2016 · 2 comments

Comments

Projects
None yet
5 participants
@seoester
Copy link

commented Jun 5, 2016

When setting the Transfer-Encoding header to chunked explicitly within a handler for a net/http Server (to trigger chunked encoding), the header field is sent to the client twice.

While this does not break most clients (e.g. Chrome, wget) it is confusing and in discord with RFC 2616:

The "chunked" transfer-coding MUST NOT be applied more than once to a message-body.

The transfer-coding is of course only applied once, just the header is sent twice.

server.go:1148 sets the chunked flag when a Transfer-Encoding is manually set and != "identity".
But Transfer-Encoding is not removed from the header map.
As I understand, this is the generally sought after behaviour, (developers should be able to use custom transfer-codings without interference), with the exception of when Transfer-Encoding is set to chunked.

Later on the Transfer-Encoding header is sent when writing the header map and then again by server.go:1176.

If Transfer-Encoding is simply not meant to be set to chunked to signal the server to chunk the response this should perhaps be pointed out in the documentation.
It does however provide a nice way to enable sending chunked content without use of the Flusher interface (and is very readable), even though so far it is essentially a side effect. Just dropping the explicit header in this case should be fine as HTTP does not allow multiple chunked codings.

  1. What version of Go are you using (go version)?
    go version go1.6.2 linux/amd64
  2. What operating system and processor architecture are you using (go env)?
    GOARCH="amd64"
    GOBIN=""
    GOEXE=""
    GOHOSTARCH="amd64"
    GOHOSTOS="linux"
    GOOS="linux"
    GOPATH=""
    GORACE=""
    GOROOT="/usr/local/go"
    GOTOOLDIR="/usr/local/go/pkg/tool/linux_amd64"
    GO15VENDOREXPERIMENT="1"
    CC="gcc"
    GOGCCFLAGS="-fPIC -m64 -pthread -fmessage-length=0"
    CXX="g++"
    CGO_ENABLED="1"
  3. What did you do?
package main

import (
    "net/http"
)

func myHandler(w http.ResponseWriter, r *http.Request) {
    w.Header().Set("Transfer-Encoding", "chunked")
    w.Write([]byte("Some content..."))
}

func main() {
    http.ListenAndServe(":8080", http.HandlerFunc(myHandler))
}

@ianlancetaylor ianlancetaylor added this to the Go1.8 milestone Jun 5, 2016

@adg adg self-assigned this Jun 6, 2016

@gopherbot

This comment has been minimized.

Copy link

commented Jun 6, 2016

CL https://golang.org/cl/23811 mentions this issue.

@seoester

This comment has been minimized.

Copy link
Author

commented Jun 6, 2016

Thanks for the quick response! (@adg)

But there must be a check for the header field's value (== "chunked").
Otherwise support for any further transfer codings would be broken (e.g. gzip).

(Sorry for any ambiguous wording on my end)

E.g.:

        ...
        if hasTE && te == "identity" {
            cw.chunking = false
            w.closeAfterReply = true
        } else if hasTE && te == "chunked" {
            cw.chunking = true
            setHeader.transferEncoding = "chunked"
            delHeader("Transfer-Encoding")
        } else {
            // HTTP/1.1 or greater: use chunked transfer encoding
            ...
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
You can’t perform that action at this time.