63 lines
1.7 KiB
Go
63 lines
1.7 KiB
Go
package transport
|
|
|
|
import "net/http"
|
|
|
|
// RoundTripFunc, similar to http.HandlerFunc, is an adapter
|
|
// to allow the use of ordinary functions as http.RoundTrippers.
|
|
type RoundTripFunc func(r *http.Request) (*http.Response, error)
|
|
|
|
func (f RoundTripFunc) RoundTrip(req *http.Request) (*http.Response, error) {
|
|
return f(req)
|
|
}
|
|
|
|
// Chain wraps given base RoundTripper, which is used to make HTTP requests
|
|
// (e.g. http.DefaultTransport) with RoundTripper middlewares.
|
|
func Chain(base http.RoundTripper, mw ...func(http.RoundTripper) http.RoundTripper) *chain {
|
|
if base == nil {
|
|
base = http.DefaultTransport
|
|
}
|
|
|
|
// Filter out nil transports.
|
|
mws := []func(http.RoundTripper) http.RoundTripper{}
|
|
for _, fn := range mw {
|
|
if fn != nil {
|
|
mws = append(mws, fn)
|
|
}
|
|
}
|
|
|
|
if c, ok := base.(*chain); ok {
|
|
c.middlewares = append(c.middlewares, mws...)
|
|
return c
|
|
}
|
|
|
|
return &chain{
|
|
baseTransport: base,
|
|
middlewares: mws,
|
|
}
|
|
}
|
|
|
|
type chain struct {
|
|
baseTransport http.RoundTripper
|
|
middlewares []func(http.RoundTripper) http.RoundTripper
|
|
}
|
|
|
|
func (c *chain) RoundTrip(req *http.Request) (*http.Response, error) {
|
|
rt := c.baseTransport
|
|
|
|
// Apply middlewares in reversed order so the first middleware becomes
|
|
// the innermost onion layer and the last becomes the outermost. Example:
|
|
// Given
|
|
// [Auth, VCTraceID, Debug],
|
|
// the middlewares are applied in this order:
|
|
// rt = Debug(rt)
|
|
// rt = VCTraceID(rt)
|
|
// rt = Auth(rt)
|
|
// The Auth and VCTraceID are called before the Debug middleware,
|
|
// which can then see the final request headers, as seen by http.DefaultTransport.
|
|
for i := len(c.middlewares) - 1; i >= 0; i-- {
|
|
rt = c.middlewares[i](rt)
|
|
}
|
|
|
|
return rt.RoundTrip(req)
|
|
}
|