1// Copyright 2014 The Go Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style 3// license that can be found in the LICENSE file. 4 5package oauth2 6 7import ( 8 "errors" 9 "log" 10 "net/http" 11 "sync" 12) 13 14// Transport is an http.RoundTripper that makes OAuth 2.0 HTTP requests, 15// wrapping a base RoundTripper and adding an Authorization header 16// with a token from the supplied Sources. 17// 18// Transport is a low-level mechanism. Most code will use the 19// higher-level Config.Client method instead. 20type Transport struct { 21 // Source supplies the token to add to outgoing requests' 22 // Authorization headers. 23 Source TokenSource 24 25 // Base is the base RoundTripper used to make HTTP requests. 26 // If nil, http.DefaultTransport is used. 27 Base http.RoundTripper 28} 29 30// RoundTrip authorizes and authenticates the request with an 31// access token from Transport's Source. 32func (t *Transport) RoundTrip(req *http.Request) (*http.Response, error) { 33 reqBodyClosed := false 34 if req.Body != nil { 35 defer func() { 36 if !reqBodyClosed { 37 req.Body.Close() 38 } 39 }() 40 } 41 42 if t.Source == nil { 43 return nil, errors.New("oauth2: Transport's Source is nil") 44 } 45 token, err := t.Source.Token() 46 if err != nil { 47 return nil, err 48 } 49 50 req2 := cloneRequest(req) // per RoundTripper contract 51 token.SetAuthHeader(req2) 52 53 // req.Body is assumed to be closed by the base RoundTripper. 54 reqBodyClosed = true 55 return t.base().RoundTrip(req2) 56} 57 58var cancelOnce sync.Once 59 60// CancelRequest does nothing. It used to be a legacy cancellation mechanism 61// but now only it only logs on first use to warn that it's deprecated. 62// 63// Deprecated: use contexts for cancellation instead. 64func (t *Transport) CancelRequest(req *http.Request) { 65 cancelOnce.Do(func() { 66 log.Printf("deprecated: golang.org/x/oauth2: Transport.CancelRequest no longer does anything; use contexts") 67 }) 68} 69 70func (t *Transport) base() http.RoundTripper { 71 if t.Base != nil { 72 return t.Base 73 } 74 return http.DefaultTransport 75} 76 77// cloneRequest returns a clone of the provided *http.Request. 78// The clone is a shallow copy of the struct and its Header map. 79func cloneRequest(r *http.Request) *http.Request { 80 // shallow copy of the struct 81 r2 := new(http.Request) 82 *r2 = *r 83 // deep copy of the Header 84 r2.Header = make(http.Header, len(r.Header)) 85 for k, s := range r.Header { 86 r2.Header[k] = append([]string(nil), s...) 87 } 88 return r2 89} 90