Skip to content

x/net/http2: response Write on HEAD fails with "http2: request body closed due to handler exiting" #66812

@c4rlo

Description

@c4rlo

Go version

go version go1.22.2 linux/amd64

Output of go env in your module/workspace:

GO111MODULE=''
GOARCH='amd64'
GOBIN=''
GOCACHE='<some-path>/.cache/go-build'
GOENV='<some-path>/.config/go/env'
GOEXE=''
GOEXPERIMENT=''
GOFLAGS=''
GOHOSTARCH='amd64'
GOHOSTOS='linux'
GOINSECURE=''
GOMODCACHE='<some-path>/go/pkg/mod'
GONOPROXY=''
GONOSUMDB=''
GOOS='linux'
GOPATH='<some-path>/go'
GOPRIVATE=''
GOPROXY='https://proxy.golang.org,direct'
GOROOT='/usr/lib/go'
GOSUMDB='sum.golang.org'
GOTMPDIR=''
GOTOOLCHAIN='auto'
GOTOOLDIR='/usr/lib/go/pkg/tool/linux_amd64'
GOVCS=''
GOVERSION='go1.22.2'
GCCGO='gccgo'
GOAMD64='v1'
AR='ar'
CC='gcc'
CXX='g++'
CGO_ENABLED='1'
GOMOD='<some-path>/go.mod'
GOWORK=''
CGO_CFLAGS='-O2 -g'
CGO_CPPFLAGS=''
CGO_CXXFLAGS='-O2 -g'
CGO_FFLAGS='-O2 -g'
CGO_LDFLAGS='-O2 -g'
PKG_CONFIG='pkg-config'
GOGCCFLAGS='-fPIC -m64 -pthread -Wl,--no-gc-sections -fmessage-length=0 -ffile-prefix-map=/tmp/go-build4138323568=/tmp/go-build -gno-record-gcc-switches'

What did you do?

Implement a trivial net/http Server that listens via HTTPS (using a self-signed cert for dev purposes) and responds with a fixed 5KB response:

package main

import (
	"io"
	"log"
	"net/http"
	"strings"
)

func main() {
    http.HandleFunc("GET /{$}", func(w http.ResponseWriter, r *http.Request) {
        w.Header().Set("Content-Type", "text/plain; charset=utf-8")
        response := strings.Repeat("A", 5000) + "\n"
        if n, err := io.WriteString(w, response); err != nil {
            log.Printf("Failed to send response, wrote %d/%d bytes: %v", n, len(response), err)
        } else {
            log.Printf("Sent %d/%d response bytes", n, len(response))
        }
    })
    log.Println("Listening")
    log.Fatal(http.ListenAndServeTLS("127.0.0.1:8443", "server.cer.pem", "server.key.pem", nil))
}

What did you see happen?

When hitting the server with:

$ curl -k -I https://127.0.0.1:8443/

The response is as expected (i.e. code 200 but empty), but the server logs an error:

$ go run .
2024/04/13 17:21:22 Listening
2024/04/13 17:21:23 Failed to send response, wrote 4096/5001 bytes: http2: request body closed due to handler exiting

What did you expect to see?

No error logged.


Note that an error is only logged when using HTTP/2, and only when the response exceeds 4096 bytes.

Interestingly, a different error is logged if I remove the explicit setting of the Content-Type header (in which case the same header+value still ends up in the response, presumably because net/http auto-detects the content type):

2024/04/13 17:44:48 Failed to send response, wrote 4096/5001 bytes: short write

Metadata

Metadata

Assignees

No one assigned

    Labels

    NeedsInvestigationSomeone must examine and confirm this is a valid issue and not a duplicate of an existing one.

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions