Skip to content

x/net/http2: serverConn.processHeaders has two error paths that don't clean up #48675

Description

@bradfitz

I continue to hunt a stream accounting bug in either the Go HTTP/2 transport and/or server. Reading code again now, I noticed:

(*serverConn).processHeaders does:

st := sc.newStream(id, 0, initialState)

... where that newStream call is what's responsible for incrementing the stream count:

sc.curClientStreams++

(that's what's ultimately causing the return sc.countError("over_max_streams", streamError(id, ErrCodeProtocol)) I'm hitting)

But just after that newStream call are two error exit paths:

st := sc.newStream(id, 0, initialState)

if f.HasPriority() {
        if err := sc.checkPriority(f.StreamID, f.Priority); err != nil {
                return err
        }
        sc.writeSched.AdjustStream(st.id, f.Priority)
}

rw, req, err := sc.newWriterAndRequest(st, f)
if err != nil {
        return err
}
// ... [no returns]
go sc.runHandler(rw, req, handler)
return nil

Those two return err errors are suspect. If those happen, then curClientStreams can be left incremented, never to be decremented again.

The decrement happens in (*serverConn).closeStream, which is called from:

  • processResetStream, reading a RSTStream frame from the client (e.g. they canceled the request)
  • wroteFrame, called after a frame write is successful, including handler panics. But if we return err above before starting the handler, we can't ever write anything, as the handler never runs.

I'm not sure whether this is what we're hitting yet, but it looks suspicious.

/cc @neild

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

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions