blob: d47113be423d6da38ba0159e3f170d25e1662c12 [file] [log] [blame]
// Copyright 2016 The LUCI Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package auth
import (
"context"
"net/http"
)
// NewModifyingTransport returns a transport that can modify headers of
// http.Request's that pass through it (e.g. by appending authentication
// information).
//
// Go docs explicitly prohibit this kind of behavior, but everyone cheat and
// implement it anyway. E.g. https://github.com/golang/oauth2.
//
// Works only with Go >=1.5 transports (that use Request.Cancel instead of
// deprecated Transport.CancelRequest). For same reason doesn't implement
// CancelRequest itself.
//
// TODO(vadimsh): Move it elsewhere. It has no direct relation to auth.
func NewModifyingTransport(base http.RoundTripper, modifier func(*http.Request) error) http.RoundTripper {
return &modifyingTransport{
base: base,
modifier: modifier,
}
}
type modifyingTransport struct {
base http.RoundTripper
modifier func(*http.Request) error
}
func (t *modifyingTransport) RoundTrip(req *http.Request) (*http.Response, error) {
clone := *req
clone.Header = make(http.Header, len(req.Header))
for k, v := range req.Header {
clone.Header[k] = v
}
if err := t.modifier(&clone); err != nil {
return nil, err
}
return t.base.RoundTrip(&clone)
}
var globalInstrumentTransport func(context.Context, http.RoundTripper, string) http.RoundTripper
// SetMonitoringInstrumentation sets a global callback used by Authenticator to
// add monitoring instrumentation to a transport.
//
// This is used by tsmon library in init(). We have to resort to callbacks to
// break module dependency cycle (tsmon is using auth lib already).
func SetMonitoringInstrumentation(cb func(context.Context, http.RoundTripper, string) http.RoundTripper) {
globalInstrumentTransport = cb
}