Source File
trace.go
Belonging Package
net/http/httptrace
// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Package httptrace provides mechanisms to trace the events within
// HTTP client requests.
package httptrace
import (
)
// unique type to prevent assignment.
type clientEventContextKey struct{}
// ContextClientTrace returns the ClientTrace associated with the
// provided context. If none, it returns nil.
func ( context.Context) *ClientTrace {
, := .Value(clientEventContextKey{}).(*ClientTrace)
return
}
// WithClientTrace returns a new context based on the provided parent
// ctx. HTTP client requests made with the returned context will use
// the provided trace hooks, in addition to any previous hooks
// registered with ctx. Any hooks defined in the provided trace will
// be called first.
func ( context.Context, *ClientTrace) context.Context {
if == nil {
panic("nil trace")
}
:= ContextClientTrace()
.compose()
= context.WithValue(, clientEventContextKey{}, )
if .hasNetHooks() {
:= &nettrace.Trace{
ConnectStart: .ConnectStart,
ConnectDone: .ConnectDone,
}
if .DNSStart != nil {
.DNSStart = func( string) {
.DNSStart(DNSStartInfo{Host: })
}
}
if .DNSDone != nil {
.DNSDone = func( []any, bool, error) {
:= make([]net.IPAddr, len())
for , := range {
[] = .(net.IPAddr)
}
.DNSDone(DNSDoneInfo{
Addrs: ,
Coalesced: ,
Err: ,
})
}
}
= context.WithValue(, nettrace.TraceKey{}, )
}
return
}
// ClientTrace is a set of hooks to run at various stages of an outgoing
// HTTP request. Any particular hook may be nil. Functions may be
// called concurrently from different goroutines and some may be called
// after the request has completed or failed.
//
// ClientTrace currently traces a single HTTP request & response
// during a single round trip and has no hooks that span a series
// of redirected requests.
//
// See https://blog.golang.org/http-tracing for more.
type ClientTrace struct {
// GetConn is called before a connection is created or
// retrieved from an idle pool. The hostPort is the
// "host:port" of the target or proxy. GetConn is called even
// if there's already an idle cached connection available.
GetConn func(hostPort string)
// GotConn is called after a successful connection is
// obtained. There is no hook for failure to obtain a
// connection; instead, use the error from
// Transport.RoundTrip.
GotConn func(GotConnInfo)
// PutIdleConn is called when the connection is returned to
// the idle pool. If err is nil, the connection was
// successfully returned to the idle pool. If err is non-nil,
// it describes why not. PutIdleConn is not called if
// connection reuse is disabled via Transport.DisableKeepAlives.
// PutIdleConn is called before the caller's Response.Body.Close
// call returns.
// For HTTP/2, this hook is not currently used.
PutIdleConn func(err error)
// GotFirstResponseByte is called when the first byte of the response
// headers is available.
GotFirstResponseByte func()
// Got100Continue is called if the server replies with a "100
// Continue" response.
Got100Continue func()
// Got1xxResponse is called for each 1xx informational response header
// returned before the final non-1xx response. Got1xxResponse is called
// for "100 Continue" responses, even if Got100Continue is also defined.
// If it returns an error, the client request is aborted with that error value.
Got1xxResponse func(code int, header textproto.MIMEHeader) error
// DNSStart is called when a DNS lookup begins.
DNSStart func(DNSStartInfo)
// DNSDone is called when a DNS lookup ends.
DNSDone func(DNSDoneInfo)
// ConnectStart is called when a new connection's Dial begins.
// If net.Dialer.DualStack (IPv6 "Happy Eyeballs") support is
// enabled, this may be called multiple times.
ConnectStart func(network, addr string)
// ConnectDone is called when a new connection's Dial
// completes. The provided err indicates whether the
// connection completed successfully.
// If net.Dialer.DualStack ("Happy Eyeballs") support is
// enabled, this may be called multiple times.
ConnectDone func(network, addr string, err error)
// TLSHandshakeStart is called when the TLS handshake is started. When
// connecting to an HTTPS site via an HTTP proxy, the handshake happens
// after the CONNECT request is processed by the proxy.
TLSHandshakeStart func()
// TLSHandshakeDone is called after the TLS handshake with either the
// successful handshake's connection state, or a non-nil error on handshake
// failure.
TLSHandshakeDone func(tls.ConnectionState, error)
// WroteHeaderField is called after the Transport has written
// each request header. At the time of this call the values
// might be buffered and not yet written to the network.
WroteHeaderField func(key string, value []string)
// WroteHeaders is called after the Transport has written
// all request headers.
WroteHeaders func()
// Wait100Continue is called if the Request specified
// "Expect: 100-continue" and the Transport has written the
// request headers but is waiting for "100 Continue" from the
// server before writing the request body.
Wait100Continue func()
// WroteRequest is called with the result of writing the
// request and any body. It may be called multiple times
// in the case of retried requests.
WroteRequest func(WroteRequestInfo)
}
// WroteRequestInfo contains information provided to the WroteRequest
// hook.
type WroteRequestInfo struct {
// Err is any error encountered while writing the Request.
Err error
}
// compose modifies t such that it respects the previously-registered hooks in old,
// subject to the composition policy requested in t.Compose.
func ( *ClientTrace) ( *ClientTrace) {
if == nil {
return
}
:= reflect.ValueOf().Elem()
:= reflect.ValueOf().Elem()
:= .Type()
for := 0; < .NumField(); ++ {
:= .Field()
:= .Type()
if .Kind() != reflect.Func {
continue
}
:= .Field()
if .IsNil() {
continue
}
if .IsNil() {
.Set()
continue
}
// Make a copy of tf for tf to call. (Otherwise it
// creates a recursive call cycle and stack overflows)
:= reflect.ValueOf(.Interface())
// We need to call both tf and of in some order.
:= reflect.MakeFunc(, func( []reflect.Value) []reflect.Value {
.Call()
return .Call()
})
.Field().Set()
}
}
// DNSStartInfo contains information about a DNS request.
type DNSStartInfo struct {
Host string
}
// DNSDoneInfo contains information about the results of a DNS lookup.
type DNSDoneInfo struct {
// Addrs are the IPv4 and/or IPv6 addresses found in the DNS
// lookup. The contents of the slice should not be mutated.
Addrs []net.IPAddr
// Err is any error that occurred during the DNS lookup.
Err error
// Coalesced is whether the Addrs were shared with another
// caller who was doing the same DNS lookup concurrently.
Coalesced bool
}
func ( *ClientTrace) () bool {
if == nil {
return false
}
return .DNSStart != nil || .DNSDone != nil || .ConnectStart != nil || .ConnectDone != nil
}
// GotConnInfo is the argument to the ClientTrace.GotConn function and
// contains information about the obtained connection.
type GotConnInfo struct {
// Conn is the connection that was obtained. It is owned by
// the http.Transport and should not be read, written or
// closed by users of ClientTrace.
Conn net.Conn
// Reused is whether this connection has been previously
// used for another HTTP request.
Reused bool
// WasIdle is whether this connection was obtained from an
// idle pool.
WasIdle bool
// IdleTime reports how long the connection was previously
// idle, if WasIdle is true.
IdleTime time.Duration
}
The pages are generated with Golds v0.6.7. (GOOS=linux GOARCH=amd64) Golds is a Go 101 project developed by Tapir Liu. PR and bug reports are welcome and can be submitted to the issue list. Please follow @Go100and1 (reachable from the left QR code) to get the latest news of Golds. |