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) }