initial commit
This commit is contained in:
		
							
								
								
									
										76
									
								
								vendor/golang.org/x/oauth2/internal/oauth2.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										76
									
								
								vendor/golang.org/x/oauth2/internal/oauth2.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,76 @@
 | 
			
		||||
// 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 internal contains support packages for oauth2 package.
 | 
			
		||||
package internal
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"bufio"
 | 
			
		||||
	"crypto/rsa"
 | 
			
		||||
	"crypto/x509"
 | 
			
		||||
	"encoding/pem"
 | 
			
		||||
	"errors"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"io"
 | 
			
		||||
	"strings"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// ParseKey converts the binary contents of a private key file
 | 
			
		||||
// to an *rsa.PrivateKey. It detects whether the private key is in a
 | 
			
		||||
// PEM container or not. If so, it extracts the the private key
 | 
			
		||||
// from PEM container before conversion. It only supports PEM
 | 
			
		||||
// containers with no passphrase.
 | 
			
		||||
func ParseKey(key []byte) (*rsa.PrivateKey, error) {
 | 
			
		||||
	block, _ := pem.Decode(key)
 | 
			
		||||
	if block != nil {
 | 
			
		||||
		key = block.Bytes
 | 
			
		||||
	}
 | 
			
		||||
	parsedKey, err := x509.ParsePKCS8PrivateKey(key)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		parsedKey, err = x509.ParsePKCS1PrivateKey(key)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, fmt.Errorf("private key should be a PEM or plain PKSC1 or PKCS8; parse error: %v", err)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	parsed, ok := parsedKey.(*rsa.PrivateKey)
 | 
			
		||||
	if !ok {
 | 
			
		||||
		return nil, errors.New("private key is invalid")
 | 
			
		||||
	}
 | 
			
		||||
	return parsed, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func ParseINI(ini io.Reader) (map[string]map[string]string, error) {
 | 
			
		||||
	result := map[string]map[string]string{
 | 
			
		||||
		"": map[string]string{}, // root section
 | 
			
		||||
	}
 | 
			
		||||
	scanner := bufio.NewScanner(ini)
 | 
			
		||||
	currentSection := ""
 | 
			
		||||
	for scanner.Scan() {
 | 
			
		||||
		line := strings.TrimSpace(scanner.Text())
 | 
			
		||||
		if strings.HasPrefix(line, ";") {
 | 
			
		||||
			// comment.
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
		if strings.HasPrefix(line, "[") && strings.HasSuffix(line, "]") {
 | 
			
		||||
			currentSection = strings.TrimSpace(line[1 : len(line)-1])
 | 
			
		||||
			result[currentSection] = map[string]string{}
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
		parts := strings.SplitN(line, "=", 2)
 | 
			
		||||
		if len(parts) == 2 && parts[0] != "" {
 | 
			
		||||
			result[currentSection][strings.TrimSpace(parts[0])] = strings.TrimSpace(parts[1])
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	if err := scanner.Err(); err != nil {
 | 
			
		||||
		return nil, fmt.Errorf("error scanning ini: %v", err)
 | 
			
		||||
	}
 | 
			
		||||
	return result, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func CondVal(v string) []string {
 | 
			
		||||
	if v == "" {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
	return []string{v}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										62
									
								
								vendor/golang.org/x/oauth2/internal/oauth2_test.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										62
									
								
								vendor/golang.org/x/oauth2/internal/oauth2_test.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,62 @@
 | 
			
		||||
// 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 internal contains support packages for oauth2 package.
 | 
			
		||||
package internal
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"reflect"
 | 
			
		||||
	"strings"
 | 
			
		||||
	"testing"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func TestParseINI(t *testing.T) {
 | 
			
		||||
	tests := []struct {
 | 
			
		||||
		ini  string
 | 
			
		||||
		want map[string]map[string]string
 | 
			
		||||
	}{
 | 
			
		||||
		{
 | 
			
		||||
			`root = toor
 | 
			
		||||
[foo]  
 | 
			
		||||
bar = hop
 | 
			
		||||
ini = nin
 | 
			
		||||
`,
 | 
			
		||||
			map[string]map[string]string{
 | 
			
		||||
				"":    map[string]string{"root": "toor"},
 | 
			
		||||
				"foo": map[string]string{"bar": "hop", "ini": "nin"},
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			`[empty]
 | 
			
		||||
[section]
 | 
			
		||||
empty=
 | 
			
		||||
`,
 | 
			
		||||
			map[string]map[string]string{
 | 
			
		||||
				"":        map[string]string{},
 | 
			
		||||
				"empty":   map[string]string{},
 | 
			
		||||
				"section": map[string]string{"empty": ""},
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			`ignore
 | 
			
		||||
[invalid
 | 
			
		||||
=stuff
 | 
			
		||||
;comment=true
 | 
			
		||||
`,
 | 
			
		||||
			map[string]map[string]string{
 | 
			
		||||
				"": map[string]string{},
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
	for _, tt := range tests {
 | 
			
		||||
		result, err := ParseINI(strings.NewReader(tt.ini))
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			t.Errorf("ParseINI(%q) error %v, want: no error", tt.ini, err)
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
		if !reflect.DeepEqual(result, tt.want) {
 | 
			
		||||
			t.Errorf("ParseINI(%q) = %#v, want: %#v", tt.ini, result, tt.want)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										225
									
								
								vendor/golang.org/x/oauth2/internal/token.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										225
									
								
								vendor/golang.org/x/oauth2/internal/token.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,225 @@
 | 
			
		||||
// 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 internal contains support packages for oauth2 package.
 | 
			
		||||
package internal
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"encoding/json"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"io"
 | 
			
		||||
	"io/ioutil"
 | 
			
		||||
	"mime"
 | 
			
		||||
	"net/http"
 | 
			
		||||
	"net/url"
 | 
			
		||||
	"strconv"
 | 
			
		||||
	"strings"
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
	"golang.org/x/net/context"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Token represents the crendentials used to authorize
 | 
			
		||||
// the requests to access protected resources on the OAuth 2.0
 | 
			
		||||
// provider's backend.
 | 
			
		||||
//
 | 
			
		||||
// This type is a mirror of oauth2.Token and exists to break
 | 
			
		||||
// an otherwise-circular dependency. Other internal packages
 | 
			
		||||
// should convert this Token into an oauth2.Token before use.
 | 
			
		||||
type Token struct {
 | 
			
		||||
	// AccessToken is the token that authorizes and authenticates
 | 
			
		||||
	// the requests.
 | 
			
		||||
	AccessToken string
 | 
			
		||||
 | 
			
		||||
	// TokenType is the type of token.
 | 
			
		||||
	// The Type method returns either this or "Bearer", the default.
 | 
			
		||||
	TokenType string
 | 
			
		||||
 | 
			
		||||
	// RefreshToken is a token that's used by the application
 | 
			
		||||
	// (as opposed to the user) to refresh the access token
 | 
			
		||||
	// if it expires.
 | 
			
		||||
	RefreshToken string
 | 
			
		||||
 | 
			
		||||
	// Expiry is the optional expiration time of the access token.
 | 
			
		||||
	//
 | 
			
		||||
	// If zero, TokenSource implementations will reuse the same
 | 
			
		||||
	// token forever and RefreshToken or equivalent
 | 
			
		||||
	// mechanisms for that TokenSource will not be used.
 | 
			
		||||
	Expiry time.Time
 | 
			
		||||
 | 
			
		||||
	// Raw optionally contains extra metadata from the server
 | 
			
		||||
	// when updating a token.
 | 
			
		||||
	Raw interface{}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// tokenJSON is the struct representing the HTTP response from OAuth2
 | 
			
		||||
// providers returning a token in JSON form.
 | 
			
		||||
type tokenJSON struct {
 | 
			
		||||
	AccessToken  string         `json:"access_token"`
 | 
			
		||||
	TokenType    string         `json:"token_type"`
 | 
			
		||||
	RefreshToken string         `json:"refresh_token"`
 | 
			
		||||
	ExpiresIn    expirationTime `json:"expires_in"` // at least PayPal returns string, while most return number
 | 
			
		||||
	Expires      expirationTime `json:"expires"`    // broken Facebook spelling of expires_in
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (e *tokenJSON) expiry() (t time.Time) {
 | 
			
		||||
	if v := e.ExpiresIn; v != 0 {
 | 
			
		||||
		return time.Now().Add(time.Duration(v) * time.Second)
 | 
			
		||||
	}
 | 
			
		||||
	if v := e.Expires; v != 0 {
 | 
			
		||||
		return time.Now().Add(time.Duration(v) * time.Second)
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type expirationTime int32
 | 
			
		||||
 | 
			
		||||
func (e *expirationTime) UnmarshalJSON(b []byte) error {
 | 
			
		||||
	var n json.Number
 | 
			
		||||
	err := json.Unmarshal(b, &n)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	i, err := n.Int64()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	*e = expirationTime(i)
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var brokenAuthHeaderProviders = []string{
 | 
			
		||||
	"https://accounts.google.com/",
 | 
			
		||||
	"https://api.dropbox.com/",
 | 
			
		||||
	"https://api.dropboxapi.com/",
 | 
			
		||||
	"https://api.instagram.com/",
 | 
			
		||||
	"https://api.netatmo.net/",
 | 
			
		||||
	"https://api.odnoklassniki.ru/",
 | 
			
		||||
	"https://api.pushbullet.com/",
 | 
			
		||||
	"https://api.soundcloud.com/",
 | 
			
		||||
	"https://api.twitch.tv/",
 | 
			
		||||
	"https://app.box.com/",
 | 
			
		||||
	"https://connect.stripe.com/",
 | 
			
		||||
	"https://login.microsoftonline.com/",
 | 
			
		||||
	"https://login.salesforce.com/",
 | 
			
		||||
	"https://oauth.sandbox.trainingpeaks.com/",
 | 
			
		||||
	"https://oauth.trainingpeaks.com/",
 | 
			
		||||
	"https://oauth.vk.com/",
 | 
			
		||||
	"https://openapi.baidu.com/",
 | 
			
		||||
	"https://slack.com/",
 | 
			
		||||
	"https://test-sandbox.auth.corp.google.com",
 | 
			
		||||
	"https://test.salesforce.com/",
 | 
			
		||||
	"https://user.gini.net/",
 | 
			
		||||
	"https://www.douban.com/",
 | 
			
		||||
	"https://www.googleapis.com/",
 | 
			
		||||
	"https://www.linkedin.com/",
 | 
			
		||||
	"https://www.strava.com/oauth/",
 | 
			
		||||
	"https://www.wunderlist.com/oauth/",
 | 
			
		||||
	"https://api.patreon.com/",
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func RegisterBrokenAuthHeaderProvider(tokenURL string) {
 | 
			
		||||
	brokenAuthHeaderProviders = append(brokenAuthHeaderProviders, tokenURL)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// providerAuthHeaderWorks reports whether the OAuth2 server identified by the tokenURL
 | 
			
		||||
// implements the OAuth2 spec correctly
 | 
			
		||||
// See https://code.google.com/p/goauth2/issues/detail?id=31 for background.
 | 
			
		||||
// In summary:
 | 
			
		||||
// - Reddit only accepts client secret in the Authorization header
 | 
			
		||||
// - Dropbox accepts either it in URL param or Auth header, but not both.
 | 
			
		||||
// - Google only accepts URL param (not spec compliant?), not Auth header
 | 
			
		||||
// - Stripe only accepts client secret in Auth header with Bearer method, not Basic
 | 
			
		||||
func providerAuthHeaderWorks(tokenURL string) bool {
 | 
			
		||||
	for _, s := range brokenAuthHeaderProviders {
 | 
			
		||||
		if strings.HasPrefix(tokenURL, s) {
 | 
			
		||||
			// Some sites fail to implement the OAuth2 spec fully.
 | 
			
		||||
			return false
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Assume the provider implements the spec properly
 | 
			
		||||
	// otherwise. We can add more exceptions as they're
 | 
			
		||||
	// discovered. We will _not_ be adding configurable hooks
 | 
			
		||||
	// to this package to let users select server bugs.
 | 
			
		||||
	return true
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func RetrieveToken(ctx context.Context, clientID, clientSecret, tokenURL string, v url.Values) (*Token, error) {
 | 
			
		||||
	hc, err := ContextClient(ctx)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	v.Set("client_id", clientID)
 | 
			
		||||
	bustedAuth := !providerAuthHeaderWorks(tokenURL)
 | 
			
		||||
	if bustedAuth && clientSecret != "" {
 | 
			
		||||
		v.Set("client_secret", clientSecret)
 | 
			
		||||
	}
 | 
			
		||||
	req, err := http.NewRequest("POST", tokenURL, strings.NewReader(v.Encode()))
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
 | 
			
		||||
	if !bustedAuth {
 | 
			
		||||
		req.SetBasicAuth(clientID, clientSecret)
 | 
			
		||||
	}
 | 
			
		||||
	r, err := hc.Do(req)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	defer r.Body.Close()
 | 
			
		||||
	body, err := ioutil.ReadAll(io.LimitReader(r.Body, 1<<20))
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, fmt.Errorf("oauth2: cannot fetch token: %v", err)
 | 
			
		||||
	}
 | 
			
		||||
	if code := r.StatusCode; code < 200 || code > 299 {
 | 
			
		||||
		return nil, fmt.Errorf("oauth2: cannot fetch token: %v\nResponse: %s", r.Status, body)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var token *Token
 | 
			
		||||
	content, _, _ := mime.ParseMediaType(r.Header.Get("Content-Type"))
 | 
			
		||||
	switch content {
 | 
			
		||||
	case "application/x-www-form-urlencoded", "text/plain":
 | 
			
		||||
		vals, err := url.ParseQuery(string(body))
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
		token = &Token{
 | 
			
		||||
			AccessToken:  vals.Get("access_token"),
 | 
			
		||||
			TokenType:    vals.Get("token_type"),
 | 
			
		||||
			RefreshToken: vals.Get("refresh_token"),
 | 
			
		||||
			Raw:          vals,
 | 
			
		||||
		}
 | 
			
		||||
		e := vals.Get("expires_in")
 | 
			
		||||
		if e == "" {
 | 
			
		||||
			// TODO(jbd): Facebook's OAuth2 implementation is broken and
 | 
			
		||||
			// returns expires_in field in expires. Remove the fallback to expires,
 | 
			
		||||
			// when Facebook fixes their implementation.
 | 
			
		||||
			e = vals.Get("expires")
 | 
			
		||||
		}
 | 
			
		||||
		expires, _ := strconv.Atoi(e)
 | 
			
		||||
		if expires != 0 {
 | 
			
		||||
			token.Expiry = time.Now().Add(time.Duration(expires) * time.Second)
 | 
			
		||||
		}
 | 
			
		||||
	default:
 | 
			
		||||
		var tj tokenJSON
 | 
			
		||||
		if err = json.Unmarshal(body, &tj); err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
		token = &Token{
 | 
			
		||||
			AccessToken:  tj.AccessToken,
 | 
			
		||||
			TokenType:    tj.TokenType,
 | 
			
		||||
			RefreshToken: tj.RefreshToken,
 | 
			
		||||
			Expiry:       tj.expiry(),
 | 
			
		||||
			Raw:          make(map[string]interface{}),
 | 
			
		||||
		}
 | 
			
		||||
		json.Unmarshal(body, &token.Raw) // no error checks for optional fields
 | 
			
		||||
	}
 | 
			
		||||
	// Don't overwrite `RefreshToken` with an empty value
 | 
			
		||||
	// if this was a token refreshing request.
 | 
			
		||||
	if token.RefreshToken == "" {
 | 
			
		||||
		token.RefreshToken = v.Get("refresh_token")
 | 
			
		||||
	}
 | 
			
		||||
	return token, nil
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										36
									
								
								vendor/golang.org/x/oauth2/internal/token_test.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								vendor/golang.org/x/oauth2/internal/token_test.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,36 @@
 | 
			
		||||
// 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 internal contains support packages for oauth2 package.
 | 
			
		||||
package internal
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"testing"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func TestRegisterBrokenAuthHeaderProvider(t *testing.T) {
 | 
			
		||||
	RegisterBrokenAuthHeaderProvider("https://aaa.com/")
 | 
			
		||||
	tokenURL := "https://aaa.com/token"
 | 
			
		||||
	if providerAuthHeaderWorks(tokenURL) {
 | 
			
		||||
		t.Errorf("URL: %s is a broken provider", tokenURL)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func Test_providerAuthHeaderWorks(t *testing.T) {
 | 
			
		||||
	for _, p := range brokenAuthHeaderProviders {
 | 
			
		||||
		if providerAuthHeaderWorks(p) {
 | 
			
		||||
			t.Errorf("URL: %s not found in list", p)
 | 
			
		||||
		}
 | 
			
		||||
		p := fmt.Sprintf("%ssomesuffix", p)
 | 
			
		||||
		if providerAuthHeaderWorks(p) {
 | 
			
		||||
			t.Errorf("URL: %s not found in list", p)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	p := "https://api.not-in-the-list-example.com/"
 | 
			
		||||
	if !providerAuthHeaderWorks(p) {
 | 
			
		||||
		t.Errorf("URL: %s found in list", p)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										69
									
								
								vendor/golang.org/x/oauth2/internal/transport.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										69
									
								
								vendor/golang.org/x/oauth2/internal/transport.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,69 @@
 | 
			
		||||
// 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 internal contains support packages for oauth2 package.
 | 
			
		||||
package internal
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"net/http"
 | 
			
		||||
 | 
			
		||||
	"golang.org/x/net/context"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// HTTPClient is the context key to use with golang.org/x/net/context's
 | 
			
		||||
// WithValue function to associate an *http.Client value with a context.
 | 
			
		||||
var HTTPClient ContextKey
 | 
			
		||||
 | 
			
		||||
// ContextKey is just an empty struct. It exists so HTTPClient can be
 | 
			
		||||
// an immutable public variable with a unique type. It's immutable
 | 
			
		||||
// because nobody else can create a ContextKey, being unexported.
 | 
			
		||||
type ContextKey struct{}
 | 
			
		||||
 | 
			
		||||
// ContextClientFunc is a func which tries to return an *http.Client
 | 
			
		||||
// given a Context value. If it returns an error, the search stops
 | 
			
		||||
// with that error.  If it returns (nil, nil), the search continues
 | 
			
		||||
// down the list of registered funcs.
 | 
			
		||||
type ContextClientFunc func(context.Context) (*http.Client, error)
 | 
			
		||||
 | 
			
		||||
var contextClientFuncs []ContextClientFunc
 | 
			
		||||
 | 
			
		||||
func RegisterContextClientFunc(fn ContextClientFunc) {
 | 
			
		||||
	contextClientFuncs = append(contextClientFuncs, fn)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func ContextClient(ctx context.Context) (*http.Client, error) {
 | 
			
		||||
	if ctx != nil {
 | 
			
		||||
		if hc, ok := ctx.Value(HTTPClient).(*http.Client); ok {
 | 
			
		||||
			return hc, nil
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	for _, fn := range contextClientFuncs {
 | 
			
		||||
		c, err := fn(ctx)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
		if c != nil {
 | 
			
		||||
			return c, nil
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return http.DefaultClient, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func ContextTransport(ctx context.Context) http.RoundTripper {
 | 
			
		||||
	hc, err := ContextClient(ctx)
 | 
			
		||||
	// This is a rare error case (somebody using nil on App Engine).
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return ErrorTransport{err}
 | 
			
		||||
	}
 | 
			
		||||
	return hc.Transport
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ErrorTransport returns the specified error on RoundTrip.
 | 
			
		||||
// This RoundTripper should be used in rare error cases where
 | 
			
		||||
// error handling can be postponed to response handling time.
 | 
			
		||||
type ErrorTransport struct{ Err error }
 | 
			
		||||
 | 
			
		||||
func (t ErrorTransport) RoundTrip(*http.Request) (*http.Response, error) {
 | 
			
		||||
	return nil, t.Err
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										38
									
								
								vendor/golang.org/x/oauth2/internal/transport_test.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								vendor/golang.org/x/oauth2/internal/transport_test.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,38 @@
 | 
			
		||||
// Copyright 2015 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 internal
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"net/http"
 | 
			
		||||
	"testing"
 | 
			
		||||
 | 
			
		||||
	"golang.org/x/net/context"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func TestContextClient(t *testing.T) {
 | 
			
		||||
	rc := &http.Client{}
 | 
			
		||||
	RegisterContextClientFunc(func(context.Context) (*http.Client, error) {
 | 
			
		||||
		return rc, nil
 | 
			
		||||
	})
 | 
			
		||||
 | 
			
		||||
	c := &http.Client{}
 | 
			
		||||
	ctx := context.WithValue(context.Background(), HTTPClient, c)
 | 
			
		||||
 | 
			
		||||
	hc, err := ContextClient(ctx)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatalf("want valid client; got err = %v", err)
 | 
			
		||||
	}
 | 
			
		||||
	if hc != c {
 | 
			
		||||
		t.Fatalf("want context client = %p; got = %p", c, hc)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	hc, err = ContextClient(context.TODO())
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatalf("want valid client; got err = %v", err)
 | 
			
		||||
	}
 | 
			
		||||
	if hc != rc {
 | 
			
		||||
		t.Fatalf("want registered client = %p; got = %p", c, hc)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user