Repository navigation
net/http: Connection header values lost when close is included #82065
Description
Go version
go version go1.27.1 windows/amd64
Output of go env in your module/workspace:
set AR=ar
set CC=gcc
set CGO_CFLAGS=-O2 -g
set CGO_CPPFLAGS=
set CGO_CXXFLAGS=-O2 -g
set CGO_ENABLED=0
set CGO_FFLAGS=-O2 -g
set CGO_LDFLAGS=-O2 -g
set CXX=g++
set GCCGO=gccgo
set GO111MODULE=
set GOAMD64=v1
set GOARCH=amd64
set GOAUTH=netrc
set GOBIN=C:\Users\Maksim\go\bin
set GOCACHE=C:\Users\Maksim\AppData\Local\go-build
set GOCACHEPROG=
set GODEBUG=
set GOENV=C:\Users\Maksim\AppData\Roaming\go\env
set GOEXE=.exe
set GOEXPERIMENT=
set GOFIPS140=off
set GOFLAGS=
set GOGCCFLAGS=-m64 -fno-caret-diagnostics -Qunused-arguments -Wl,--no-gc-sections -fmessage-length=0 -ffile-prefix-map=C:\Users\Maksim\AppData\Local\Temp\go-build1384164418=/tmp/go-build -gno-record-gcc-switches
set GOHOSTARCH=amd64
set GOHOSTOS=windows
set GOINSECURE=
set GOMOD=NUL
set GOMODCACHE=C:\Users\Maksim\go\pkg\mod
set GONOPROXY=
set GONOSUMDB=
set GOOS=windows
set GOPACKAGESDRIVER=
set GOPATH=C:\Users\Maksim\go
set GOPRIVATE=
set GOPROXY=https://proxy.golang.org,direct
set GOROOT=C:\Users\Maksim\AndroidStudioProjects\muzlogate-p1\.tools\go
set GOSUMDB=sum.golang.org
set GOTELEMETRY=local
set GOTELEMETRYDIR=C:\Users\Maksim\AppData\Roaming\go\telemetry
set GOTMPDIR=
set GOTOOLCHAIN=auto
set GOTOOLDIR=C:\Users\Maksim\AndroidStudioProjects\muzlogate-p1\.tools\go\pkg\tool\windows_amd64
set GOVCS=
set GOVERSION=go1.27.1
set GOWORK=
set PKG_CONFIG=pkg-configWhat did you do?
Run this standalone reproducer with an unmodified Go toolchain:
package main
import (
"bufio"
"fmt"
"io"
"net"
"net/http"
"net/http/httptest"
"net/http/httputil"
"net/url"
"time"
)
func main() {
ln, err := net.Listen("tcp", "127.0.0.1:0")
if err != nil { panic(err) }
defer ln.Close()
go func() {
c, err := ln.Accept()
if err != nil { return }
defer c.Close()
c.SetDeadline(time.Now().Add(5 * time.Second))
if _, err := http.ReadRequest(bufio.NewReader(c)); err != nil { return }
io.WriteString(c, "HTTP/1.1 200 OK\r\nConnection: X-Hop, close\r\nX-Hop: connection-only\r\nX-Extension: keep\r\nContent-Length: 2\r\n\r\nok")
}()
target, err := url.Parse("http://" + ln.Addr().String())
if err != nil { panic(err) }
p := httputil.NewSingleHostReverseProxy(target)
tr := http.DefaultTransport.(*http.Transport).Clone()
p.Transport = tr
defer tr.CloseIdleConnections()
front := httptest.NewServer(p)
defer front.Close()
front.Client().Timeout = 5 * time.Second
res, err := front.Client().Get(front.URL)
if err != nil { panic(err) }
defer res.Body.Close()
body, err := io.ReadAll(res.Body)
if err != nil { panic(err) }
fmt.Printf("status=%d X-Hop=%q X-Extension=%q body=%q\n", res.StatusCode, res.Header.Get("X-Hop"), res.Header.Get("X-Extension"), body)
}What did you see happen?
The reverse proxy forwards the connection-specific X-Hop header.
status=200 X-Hop="connection-only" X-Extension="keep" body="ok"
Reproduced on Go 1.26.8, 1.27.1, and master (Windows/amd64).
What did you expect to see?
The reverse proxy should remove X-Hop because it is nominated by Connection, while preserving X-Extension.
status=200 X-Hop="" X-Extension="keep" body="ok"
RFC 9110 §7.6.1 requires intermediaries to remove connection-specific fields before forwarding.
Root cause: readTransfer/shouldClose removes the entire Connection field when it contains close. ReverseProxy subsequently cannot determine which other fields were nominated.
Related: #44034 (historical parser behavior), #81319 (1xx responses), #80875 (Upgrade).
A local candidate fix exists, but it changes observable Response.Header and Response.Write behavior. Maintainer guidance on compatibility would be appreciated before submitting a CL.
Activity
gabyhelp commentedon Oct 8, 2026
Related Issues
(Emoji vote if this was helpful or unhelpful; more detailed feedback welcome in this discussion.)
gopherbot commentedon Oct 8, 2026
Change https://go.dev/cl/846726 mentions this issue:
net/http: preserve response Connection options for intermediaries[-]net/http: ReadResponse drops Connection options needed by ReverseProxy[/-][+]net/http: Connection header values lost when close is included[/+]