-
Notifications
You must be signed in to change notification settings - Fork 18k
net/http/httptrace: internal nettrace leaks into other net.Dial calls #25198
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
I'm not entirely convinced this is a bug. The Transport.DialFunc is for the Transport. If you have some unrelated dialing to do, use an unrelated context? |
For the bug report, this dialing is not connected, but in the program I'm writing, we're using a network name resolution to go from hostname to IP. In that case, I want to enable cancellation via the context without getting confusing httptrace callbacks |
How about: package httptrace
func WithoutClientTrace(context.Context) context.Context { ... } |
Either that or make |
That works, since nil is already reserved: func WithClientTrace(ctx context.Context, trace *ClientTrace) context.Context {
if trace == nil {
panic("nil trace")
}
... Want to send a CL, including test & docs? |
Can do, will probably send it off tomorrow |
I encountered this and found this still open, so I have no choice but implementing a hack: import (
"context"
"net"
"net/http/httptrace"
"reflect"
)
var stdNetTraceKey, stdHttpTraceKey interface{}
type captureContext struct {
context.Context
capture func(reflect.Type)
}
func (c captureContext) Value(key interface{}) interface{} {
c.capture(reflect.TypeOf(key))
return nil
}
func init() {
var stdNetTraceType, stdHttpTraceType reflect.Type
capture := captureContext{context.Background(), nil}
capture.capture = func(t reflect.Type) { stdNetTraceType = t }
(&net.Dialer{}).DialContext(capture, "invalid", "")
capture.capture = func(t reflect.Type) { stdHttpTraceType = t }
httptrace.ContextClientTrace(capture)
stdNetTraceKey = reflect.New(stdNetTraceType).Elem().Interface()
stdHttpTraceKey = reflect.New(stdHttpTraceType).Elem().Interface()
}
func shadowStandardClientTrace(ctx context.Context) context.Context {
ctx = context.WithValue(ctx, stdHttpTraceKey, nil)
ctx = context.WithValue(ctx, stdNetTraceKey, nil)
return ctx
} |
What version of Go are you using (
go version
)?go version go1.10.2 linux/amd64
Does this issue reproduce with the latest release?
Yep
What did you do?
Run the following program
What did you expect to see?
Nothing printed on stdout
What did you see instead?
DNSStart: www.golang.org
printed on stdoutAdditionally, ConnectStart and ConnectDone gets called twice, once for the resolution service and once for the actual HTTP connection. This also gets really annoying once your resolution service might be using HTTP itself, resulting in even more confusion.
Normally, I'd stash away the ClientTrace while the resolution function runs and call the DNSStart and DNSDone functions independently, but there is no way to remove a ClientTrace once it's been put into the context.
I'm fairly confident I can come up with a workaround for this, but this sort of interaction is unexpected and could cause confusion if you were using a library for ClientTraces that weren't expecting overridden Dial functions.
The text was updated successfully, but these errors were encountered: