// Copyright 2014 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 oauth2 import ( "errors" "log" "net/http" "sync" ) // Transport is an http.RoundTripper that makes OAuth 2.0 HTTP requests, // wrapping a base RoundTripper and adding an Authorization header // with a token from the supplied Sources. // // Transport is a low-level mechanism. Most code will use the // higher-level Config.Client method instead. type Transport struct { // Source supplies the token to add to outgoing requests' // Authorization headers. Source TokenSource // Base is the base RoundTripper used to make HTTP requests. // If nil, http.DefaultTransport is used. Base http.RoundTripper } // RoundTrip authorizes and authenticates the request with an // access token from Transport's Source. func (t *Transport) RoundTrip(req *http.Request) (*http.Response, error) { reqBodyClosed := false if req.Body != nil { defer func() { if !reqBodyClosed { req.Body.Close() } }() } if t.Source == nil { return nil, errors.New("oauth2: Transport's Source is nil") } token, err := t.Source.Token() if err != nil { return nil, err } req2 := cloneRequest(req) // per RoundTripper contract token.SetAuthHeader(req2) // req.Body is assumed to be closed by the base RoundTripper. reqBodyClosed = true return t.base().RoundTrip(req2) } var cancelOnce sync.Once // CancelRequest does nothing. It used to be a legacy cancellation mechanism // but now only it only logs on first use to warn that it's deprecated. // // Deprecated: use contexts for cancellation instead. func (t *Transport) CancelRequest(req *http.Request) { cancelOnce.Do(func() { log.Printf("deprecated: golang.org/x/oauth2: Transport.CancelRequest no longer does anything; use contexts") }) } func (t *Transport) base() http.RoundTripper { if t.Base != nil { return t.Base } return http.DefaultTransport } // cloneRequest returns a clone of the provided *http.Request. // The clone is a shallow copy of the struct and its Header map. func cloneRequest(r *http.Request) *http.Request { // shallow copy of the struct r2 := new(http.Request) *r2 = *r // deep copy of the Header r2.Header = make(http.Header, len(r.Header)) for k, s := range r.Header { r2.Header[k] = append([]string(nil), s...) } return r2 }