Skip to content

net/http: (*Transport).getConn traces through stale contexts #21597

Open
@bcmills

Description

@bcmills

(*http.Transport).getConn currently starts a dialConn call in a background goroutine:

go func() {
pc, err := t.dialConn(ctx, cm)
dialc <- dialRes{pc, err}
}()

That records traces to the provided Context and eventually invokes t.DialContext with it:

trace := httptrace.ContextClientTrace(ctx)

conn, err := t.dial(ctx, "tcp", cm.addr())

This is pretty much a textbook illustration of the problem described in #19643 (Context API for continuing work). If (*Transport).getConn returns early (due to cancellation or to availability of an idle connection), the caller may have already written out the corresponding traces, and dialConn (and/or the user-provided DialContext callback) will unexpectedly access a Context that the caller believes to be unreachable.

httptrace.ClientTrace says, "Functions may be called concurrently from different goroutines and some may be called after the request has completed or failed." However, that is not true of Context instances in general: if the http package wants to save a trace after a call has returned, it should call Value ahead of time and save only the ClientTrace pointer. If dialConn calls a user-provided DialContext function, then getConn should cancel the Context passed to it and wait for DialContext to return before itself returning.


See also #20617 (Context race in http.Transport).

Metadata

Metadata

Assignees

No one assigned

    Labels

    NeedsFixThe path to resolution is known, but the work has not been done.Thinkinghelp wanted

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions