Skip to content

x/net/http2: unexpected custom errors when HTTP2.0 PUT request gets lesser content than the specified content-length #30648

@harshavardhana

Description

@harshavardhana

What version of Go are you using (go version)?

$ go version
go version go1.12 linux/amd64

Does this issue reproduce with the latest release?

Yes with go1.12

What operating system and processor architecture are you using (go env)?

go env Output
$ go env
GOARCH="amd64"
GOBIN=""
GOCACHE="/home/harsha/.cache/go-build"
GOEXE=""
GOFLAGS=""
GOHOSTARCH="amd64"
GOHOSTOS="linux"
GOOS="linux"
GOPATH="/home/harsha/mygo"
GOPROXY=""
GORACE=""
GOROOT="/home/harsha/.gimme/versions/go1.12.linux.amd64"
GOTMPDIR=""
GOTOOLDIR="/home/harsha/.gimme/versions/go1.12.linux.amd64/pkg/tool/linux_amd64"
GCCGO="/usr/bin/gccgo"
CC="gcc"
CXX="g++"
CGO_ENABLED="1"
GOMOD=""
CGO_CFLAGS="-g -O2"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-g -O2"
CGO_FFLAGS="-g -O2"
CGO_LDFLAGS="-g -O2"
PKG_CONFIG="pkg-config"
GOGCCFLAGS="-fPIC -m64 -pthread -fmessage-length=0 -fdebug-prefix-map=/tmp/go-build150613686=/tmp/go-build -gno-record-gcc-switches"

What did you do?

Set a high content-length and send shorter data leads to unexpected errors reported by the server

// endStream closes a Request.Body's pipe. It is called when a DATA
// frame says a request body is over (or after trailers).
func (st *http2stream) endStream() {
        sc := st.sc
        sc.serveG.check()

        if st.declBodyBytes != -1 && st.declBodyBytes != st.bodyBytes {
                st.body.CloseWithError(fmt.Errorf("request declared a Content-Length of %d but only wrote %d bytes",
                        st.declBodyBytes, st.bodyBytes))
        } else {
                st.body.closeWithErrorAndCode(io.EOF, st.copyTrailersToHandlerRequest)
                st.body.CloseWithError(io.EOF)
        }
        st.state = http2stateHalfClosedRemote
}

Should be ideally

// endStream closes a Request.Body's pipe. It is called when a DATA
// frame says a request body is over (or after trailers).
func (st *http2stream) endStream() {
        sc := st.sc
        sc.serveG.check()

        if st.declBodyBytes != -1 && st.declBodyBytes != st.bodyBytes {
                st.body.CloseWithError(io.ErrUnexpectedEOF)
        } else {
                st.body.closeWithErrorAndCode(io.EOF, st.copyTrailersToHandlerRequest)
                st.body.CloseWithError(io.EOF)
        }
        st.state = http2stateHalfClosedRemote
}

What did you expect to see?

Expected to see io.ErrUnexpectedEOF

What did you see instead?

request declared a Content-Length of %d but only wrote %d bytes

This behavior differs from HTTP 1.1 behavior.

Metadata

Metadata

Assignees

No one assigned

    Labels

    FrozenDueToAgeWaitingForInfoIssue is not actionable because of missing required information, which needs to be provided.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions