Skip to content
Projects
Groups
Snippets
Help
Loading...
Sign in
Toggle navigation
D
dex
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Commits
Issue Boards
Open sidebar
go
dex
Commits
e5f60fe9
Commit
e5f60fe9
authored
Mar 08, 2017
by
Eric Chiang
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
vendor: revendor
parent
777eeafa
Show whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
116 additions
and
347 deletions
+116
-347
glide.lock
glide.lock
+3
-4
jwks.go
vendor/github.com/coreos/go-oidc/jwks.go
+2
-3
oidc.go
vendor/github.com/coreos/go-oidc/oidc.go
+32
-12
verify.go
vendor/github.com/coreos/go-oidc/verify.go
+79
-107
ctxhttp.go
vendor/golang.org/x/net/context/ctxhttp/ctxhttp.go
+0
-74
ctxhttp_pre17.go
vendor/golang.org/x/net/context/ctxhttp/ctxhttp_pre17.go
+0
-147
No files found.
glide.lock
View file @
e5f60fe9
hash:
1207c251a7dab3b824746d66219beabc40f0b1d3c08ed90ac50f5bbdb8872631
updated: 2017-0
1-25T20:32:43.599648533+01
:00
hash:
fbef1f81a0f86f519714bbe568692a92709c446ef487a3fa9875e58f86e14430
updated: 2017-0
3-08T10:31:06.364335442-08
:00
imports:
- name: github.com/beevik/etree
version: 4cd0dd976db869f817248477718071a28e978df0
...
...
@@ -8,7 +8,7 @@ imports:
subpackages:
- crdb
- name: github.com/coreos/go-oidc
version:
2b5d73091ea4b7ddb15e3ac00077f153120b5b61
version:
be73733bb8cc830d0205609b95d125215f8e9c70
- name: github.com/ghodss/yaml
version: bea76d6a4713e18b7f5321a2b020738552def3ea
- name: github.com/go-sql-driver/mysql
...
...
@@ -62,7 +62,6 @@ imports:
version: 6a513affb38dc9788b449d59ffed099b8de18fa0
subpackages:
- context
- context/ctxhttp
- http2
- http2/hpack
- internal/timeseries
...
...
vendor/github.com/coreos/go-oidc/jwks.go
View file @
e5f60fe9
package
oidc
import
(
"context"
"encoding/json"
"fmt"
"io/ioutil"
...
...
@@ -9,8 +10,6 @@ import (
"time"
"github.com/pquerna/cachecontrol"
"golang.org/x/net/context"
"golang.org/x/net/context/ctxhttp"
jose
"gopkg.in/square/go-jose.v2"
)
...
...
@@ -163,7 +162,7 @@ func (r *remoteKeySet) updateKeys(ctx context.Context) error {
return
fmt
.
Errorf
(
"oidc: can't create request: %v"
,
err
)
}
resp
,
err
:=
ctxhttp
.
Do
(
ctx
,
clientFromContext
(
ctx
)
,
req
)
resp
,
err
:=
doRequest
(
ctx
,
req
)
if
err
!=
nil
{
return
fmt
.
Errorf
(
"oidc: get keys failed %v"
,
err
)
}
...
...
vendor/github.com/coreos/go-oidc/oidc.go
View file @
e5f60fe9
...
...
@@ -2,6 +2,7 @@
package
oidc
import
(
"context"
"encoding/json"
"errors"
"fmt"
...
...
@@ -10,8 +11,6 @@ import (
"strings"
"time"
"golang.org/x/net/context"
"golang.org/x/net/context/ctxhttp"
"golang.org/x/oauth2"
jose
"gopkg.in/square/go-jose.v2"
)
...
...
@@ -46,11 +45,12 @@ func ClientContext(ctx context.Context, client *http.Client) context.Context {
return
context
.
WithValue
(
ctx
,
oauth2
.
HTTPClient
,
client
)
}
func
clientFromContext
(
ctx
context
.
Context
)
*
http
.
Client
{
if
client
,
ok
:=
ctx
.
Value
(
oauth2
.
HTTPClient
)
.
(
*
http
.
Client
);
ok
{
return
client
func
doRequest
(
ctx
context
.
Context
,
req
*
http
.
Request
)
(
*
http
.
Response
,
error
)
{
client
:=
http
.
DefaultClient
if
c
,
ok
:=
ctx
.
Value
(
oauth2
.
HTTPClient
)
.
(
*
http
.
Client
);
ok
{
client
=
c
}
return
http
.
DefaultClient
return
client
.
Do
(
req
.
WithContext
(
ctx
))
}
// Provider represents an OpenID Connect server's configuration.
...
...
@@ -85,7 +85,11 @@ type providerJSON struct {
// or "https://login.salesforce.com".
func
NewProvider
(
ctx
context
.
Context
,
issuer
string
)
(
*
Provider
,
error
)
{
wellKnown
:=
strings
.
TrimSuffix
(
issuer
,
"/"
)
+
"/.well-known/openid-configuration"
resp
,
err
:=
ctxhttp
.
Get
(
ctx
,
clientFromContext
(
ctx
),
wellKnown
)
req
,
err
:=
http
.
NewRequest
(
"GET"
,
wellKnown
,
nil
)
if
err
!=
nil
{
return
nil
,
err
}
resp
,
err
:=
doRequest
(
ctx
,
req
)
if
err
!=
nil
{
return
nil
,
err
}
...
...
@@ -174,7 +178,7 @@ func (p *Provider) UserInfo(ctx context.Context, tokenSource oauth2.TokenSource)
}
token
.
SetAuthHeader
(
req
)
resp
,
err
:=
ctxhttp
.
Do
(
ctx
,
clientFromContext
(
ctx
)
,
req
)
resp
,
err
:=
doRequest
(
ctx
,
req
)
if
err
!=
nil
{
return
nil
,
err
}
...
...
@@ -201,18 +205,34 @@ func (p *Provider) UserInfo(ctx context.Context, tokenSource oauth2.TokenSource)
// The ID Token only holds fields OpenID Connect requires. To access additional
// claims returned by the server, use the Claims method.
type
IDToken
struct
{
// The URL of the server which issued this token. This will always be the same
// as the URL used for initial discovery.
// The URL of the server which issued this token. OpenID Connect
// requires this value always be identical to the URL used for
// initial discovery.
//
// Note: Because of a known issue with Google Accounts' implementation
// this value may differ when using Google.
//
// See: https://developers.google.com/identity/protocols/OpenIDConnect#obtainuserinfo
Issuer
string
// The client, or set of clients, that this token is issued for.
// The client ID, or set of client IDs, that this token is issued for. For
// common uses, this is the client that initialized the auth flow.
//
// This package ensures the audience contains an expected value.
Audience
[]
string
// A unique string which identifies the end user.
Subject
string
IssuedAt
time
.
Time
// Expiry of the token. Ths package will not process tokens that have
// expired unless that validation is explicitly turned off.
Expiry
time
.
Time
// When the token was issued by the provider.
IssuedAt
time
.
Time
// Initial nonce provided during the authentication redirect.
//
// If present, this package ensures this is a valid nonce.
Nonce
string
// Raw payload of the id_token.
...
...
vendor/github.com/coreos/go-oidc/verify.go
View file @
e5f60fe9
...
...
@@ -2,6 +2,7 @@ package oidc
import
(
"bytes"
"context"
"encoding/base64"
"encoding/json"
"errors"
...
...
@@ -9,61 +10,71 @@ import (
"strings"
"time"
"golang.org/x/net/context"
"golang.org/x/oauth2"
jose
"gopkg.in/square/go-jose.v2"
)
const
(
issuerGoogleAccounts
=
"https://accounts.google.com"
issuerGoogleAccountsNoScheme
=
"accounts.google.com"
)
// IDTokenVerifier provides verification for ID Tokens.
type
IDTokenVerifier
struct
{
keySet
*
remoteKeySet
config
*
verificationConfig
}
// verificationConfig is the unexported configuration for an IDTokenVerifier.
//
// Users interact with this struct using a VerificationOption.
type
verificationConfig
struct
{
config
*
Config
issuer
string
// If provided, this value must be in the ID Token audiences.
audience
string
// If not nil, check the expiry of the id token.
checkExpiry
func
()
time
.
Time
// If specified, only these sets of algorithms may be used to sign the JWT.
requiredAlgs
[]
string
// If not nil, don't verify nonce.
nonceSource
NonceSource
}
// VerificationOption provides additional checks on ID Tokens.
type
VerificationOption
interface
{
// Unexport this method so other packages can't implement this interface.
updateConfig
(
c
*
verificationConfig
)
// Config is the configuration for an IDTokenVerifier.
type
Config
struct
{
// Expected audience of the token. For a majority of the cases this is expected to be
// the ID of the client that initialized the login flow. It may occasionally differ if
// the provider supports the authorizing party (azp) claim.
//
// If not provided, users must explicitly set SkipClientIDCheck.
ClientID
string
// Method to verify the ID Token nonce. If a nonce is present and this method
// is nil, users must explicitly set SkipNonceCheck.
//
// If the ID Token nonce is empty, for example if the client didn't provide a nonce in
// the initial redirect, this may be nil.
ClaimNonce
func
(
nonce
string
)
error
// If specified, only this set of algorithms may be used to sign the JWT.
//
// Since many providers only support RS256, SupportedSigningAlgs defaults to this value.
SupportedSigningAlgs
[]
string
// If true, no ClientID check performed. Must be true if ClientID field is empty.
SkipClientIDCheck
bool
// If true, token expiry is not checked.
SkipExpiryCheck
bool
// If true, nonce claim is not checked. Must be true if ClaimNonce field is empty.
SkipNonceCheck
bool
// Time function to check Token expiry. Defaults to time.Now
Now
func
()
time
.
Time
}
// Verifier returns an IDTokenVerifier that uses the provider's key set to verify JWTs.
//
// The returned IDTokenVerifier is tied to the Provider's context and its behavior is
// undefined once the Provider's context is canceled.
func
(
p
*
Provider
)
Verifier
(
options
...
VerificationOption
)
*
IDTokenVerifier
{
config
:=
&
verificationConfig
{
issuer
:
p
.
issuer
}
for
_
,
option
:=
range
options
{
option
.
updateConfig
(
config
)
}
func
(
p
*
Provider
)
Verifier
(
config
*
Config
)
*
IDTokenVerifier
{
return
newVerifier
(
p
.
remoteKeySet
,
config
)
return
newVerifier
(
p
.
remoteKeySet
,
config
,
p
.
issuer
)
}
func
newVerifier
(
keySet
*
remoteKeySet
,
config
*
verificationConfig
)
*
IDTokenVerifier
{
// As discussed in the godocs for VerifrySigningAlg, because almost all providers
// only support RS256, default to only allowing it.
if
len
(
config
.
requiredAlgs
)
==
0
{
config
.
requiredAlgs
=
[]
string
{
RS256
}
func
newVerifier
(
keySet
*
remoteKeySet
,
config
*
Config
,
issuer
string
)
*
IDTokenVerifier
{
// If SupportedSigningAlgs is empty defaults to only support RS256.
if
len
(
config
.
SupportedSigningAlgs
)
==
0
{
config
.
SupportedSigningAlgs
=
[]
string
{
RS256
}
}
return
&
IDTokenVerifier
{
keySet
:
keySet
,
config
:
config
,
issuer
:
issuer
,
}
}
...
...
@@ -89,7 +100,7 @@ func contains(sli []string, ele string) bool {
}
// Verify parses a raw ID Token, verifies it's been signed by the provider, preforms
// any additional checks
passed as VerifictionOptions
, and returns the payload.
// any additional checks
depending on the Config
, and returns the payload.
//
// See: https://openid.net/specs/openid-connect-core-1_0.html#IDTokenValidation
//
...
...
@@ -134,20 +145,38 @@ func (v *IDTokenVerifier) Verify(ctx context.Context, rawIDToken string) (*IDTok
}
// Check issuer.
if
t
.
Issuer
!=
v
.
config
.
issuer
{
return
nil
,
fmt
.
Errorf
(
"oidc: id token issued by a different provider, expected %q got %q"
,
v
.
config
.
issuer
,
t
.
Issuer
)
if
t
.
Issuer
!=
v
.
issuer
{
// Google sometimes returns "accounts.google.com" as the issuer claim instead of
// the required "https://accounts.google.com". Detect this case and allow it only
// for Google.
//
// We will not add hooks to let other providers go off spec like this.
if
!
(
v
.
issuer
==
issuerGoogleAccounts
&&
t
.
Issuer
==
issuerGoogleAccountsNoScheme
)
{
return
nil
,
fmt
.
Errorf
(
"oidc: id token issued by a different provider, expected %q got %q"
,
v
.
issuer
,
t
.
Issuer
)
}
}
// If a client ID has been provided, make sure it's part of the audience.
if
v
.
config
.
audience
!=
""
{
if
!
contains
(
t
.
Audience
,
v
.
config
.
audience
)
{
return
nil
,
fmt
.
Errorf
(
"oidc: expected audience %q got %q"
,
v
.
config
.
audience
,
t
.
Audience
)
// If a client ID has been provided, make sure it's part of the audience. SkipClientIDCheck must be true if ClientID is empty.
//
// This check DOES NOT ensure that the ClientID is the party to which the ID Token was issued (i.e. Authorized party).
if
!
v
.
config
.
SkipClientIDCheck
{
if
v
.
config
.
ClientID
!=
""
{
if
!
contains
(
t
.
Audience
,
v
.
config
.
ClientID
)
{
return
nil
,
fmt
.
Errorf
(
"oidc: expected audience %q got %q"
,
v
.
config
.
ClientID
,
t
.
Audience
)
}
}
else
{
return
nil
,
fmt
.
Errorf
(
"oidc: Invalid configuration. ClientID must be provided or SkipClientIDCheck must be set."
)
}
}
// If a SkipExpiryCheck is false, make sure token is not expired.
if
!
v
.
config
.
SkipExpiryCheck
{
now
:=
time
.
Now
if
v
.
config
.
Now
!=
nil
{
now
=
v
.
config
.
Now
}
// If a checkExpiry is specified, make sure token is not expired.
if
v
.
config
.
checkExpiry
!=
nil
{
if
t
.
Expiry
.
Before
(
v
.
config
.
checkExpiry
())
{
if
t
.
Expiry
.
Before
(
now
())
{
return
nil
,
fmt
.
Errorf
(
"oidc: token is expired (Token Expiry: %v)"
,
t
.
Expiry
)
}
}
...
...
@@ -155,14 +184,14 @@ func (v *IDTokenVerifier) Verify(ctx context.Context, rawIDToken string) (*IDTok
// If a set of required algorithms has been provided, ensure that the signatures use those.
var
keyIDs
,
gotAlgs
[]
string
for
_
,
sig
:=
range
jws
.
Signatures
{
if
len
(
v
.
config
.
requiredAlgs
)
==
0
||
contains
(
v
.
config
.
required
Algs
,
sig
.
Header
.
Algorithm
)
{
if
len
(
v
.
config
.
SupportedSigningAlgs
)
==
0
||
contains
(
v
.
config
.
SupportedSigning
Algs
,
sig
.
Header
.
Algorithm
)
{
keyIDs
=
append
(
keyIDs
,
sig
.
Header
.
KeyID
)
}
else
{
gotAlgs
=
append
(
gotAlgs
,
sig
.
Header
.
Algorithm
)
}
}
if
len
(
keyIDs
)
==
0
{
return
nil
,
fmt
.
Errorf
(
"oidc: no signatures use a
require algorithm, expected %q got %q"
,
v
.
config
.
required
Algs
,
gotAlgs
)
return
nil
,
fmt
.
Errorf
(
"oidc: no signatures use a
supported algorithm, expected %q got %q"
,
v
.
config
.
SupportedSigning
Algs
,
gotAlgs
)
}
// Get keys from the remote key set. This may trigger a re-sync.
...
...
@@ -192,79 +221,22 @@ func (v *IDTokenVerifier) Verify(ctx context.Context, rawIDToken string) (*IDTok
// Check the nonce after we've verified the token. We don't want to allow unverified
// payloads to trigger a nonce lookup.
if
v
.
config
.
nonceSource
!=
nil
{
if
err
:=
v
.
config
.
nonceSource
.
ClaimNonce
(
t
.
Nonce
);
err
!=
nil
{
// If SkipNonceCheck is not set ClaimNonce cannot be Nil.
if
!
v
.
config
.
SkipNonceCheck
&&
t
.
Nonce
!=
""
{
if
v
.
config
.
ClaimNonce
!=
nil
{
if
err
:=
v
.
config
.
ClaimNonce
(
t
.
Nonce
);
err
!=
nil
{
return
nil
,
err
}
}
else
{
return
nil
,
fmt
.
Errorf
(
"oidc: Invalid configuration. ClaimNonce must be provided or SkipNonceCheck must be set."
)
}
}
return
t
,
nil
}
// VerifyAudience ensures that an ID Token was issued for the specific client.
//
// Note that a verified token may be valid for other clients, as OpenID Connect allows a token to have
// multiple audiences.
func
VerifyAudience
(
clientID
string
)
VerificationOption
{
return
clientVerifier
{
clientID
}
}
type
clientVerifier
struct
{
clientID
string
}
func
(
v
clientVerifier
)
updateConfig
(
c
*
verificationConfig
)
{
c
.
audience
=
v
.
clientID
}
// VerifyExpiry ensures that an ID Token has not expired.
func
VerifyExpiry
()
VerificationOption
{
return
expiryVerifier
{}
}
type
expiryVerifier
struct
{}
func
(
v
expiryVerifier
)
updateConfig
(
c
*
verificationConfig
)
{
c
.
checkExpiry
=
time
.
Now
}
// VerifySigningAlg enforces that an ID Token is signed by a specific signing algorithm.
//
// Because so many providers only support RS256, if this verifiction option isn't used,
// the IDTokenVerifier defaults to only allowing RS256.
func
VerifySigningAlg
(
allowedAlgs
...
string
)
VerificationOption
{
return
algVerifier
{
allowedAlgs
}
}
type
algVerifier
struct
{
algs
[]
string
}
func
(
v
algVerifier
)
updateConfig
(
c
*
verificationConfig
)
{
c
.
requiredAlgs
=
v
.
algs
}
// Nonce returns an auth code option which requires the ID Token created by the
// OpenID Connect provider to contain the specified nonce.
func
Nonce
(
nonce
string
)
oauth2
.
AuthCodeOption
{
return
oauth2
.
SetAuthURLParam
(
"nonce"
,
nonce
)
}
// NonceSource represents a source which can verify a nonce is valid and has not
// been claimed before.
type
NonceSource
interface
{
ClaimNonce
(
nonce
string
)
error
}
// VerifyNonce ensures that the ID Token contains a nonce which can be claimed by the nonce source.
func
VerifyNonce
(
source
NonceSource
)
VerificationOption
{
return
nonceVerifier
{
source
}
}
type
nonceVerifier
struct
{
nonceSource
NonceSource
}
func
(
n
nonceVerifier
)
updateConfig
(
c
*
verificationConfig
)
{
c
.
nonceSource
=
n
.
nonceSource
}
vendor/golang.org/x/net/context/ctxhttp/ctxhttp.go
deleted
100644 → 0
View file @
777eeafa
// Copyright 2016 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.
// +build go1.7
// Package ctxhttp provides helper functions for performing context-aware HTTP requests.
package
ctxhttp
// import "golang.org/x/net/context/ctxhttp"
import
(
"io"
"net/http"
"net/url"
"strings"
"golang.org/x/net/context"
)
// Do sends an HTTP request with the provided http.Client and returns
// an HTTP response.
//
// If the client is nil, http.DefaultClient is used.
//
// The provided ctx must be non-nil. If it is canceled or times out,
// ctx.Err() will be returned.
func
Do
(
ctx
context
.
Context
,
client
*
http
.
Client
,
req
*
http
.
Request
)
(
*
http
.
Response
,
error
)
{
if
client
==
nil
{
client
=
http
.
DefaultClient
}
resp
,
err
:=
client
.
Do
(
req
.
WithContext
(
ctx
))
// If we got an error, and the context has been canceled,
// the context's error is probably more useful.
if
err
!=
nil
{
select
{
case
<-
ctx
.
Done
()
:
err
=
ctx
.
Err
()
default
:
}
}
return
resp
,
err
}
// Get issues a GET request via the Do function.
func
Get
(
ctx
context
.
Context
,
client
*
http
.
Client
,
url
string
)
(
*
http
.
Response
,
error
)
{
req
,
err
:=
http
.
NewRequest
(
"GET"
,
url
,
nil
)
if
err
!=
nil
{
return
nil
,
err
}
return
Do
(
ctx
,
client
,
req
)
}
// Head issues a HEAD request via the Do function.
func
Head
(
ctx
context
.
Context
,
client
*
http
.
Client
,
url
string
)
(
*
http
.
Response
,
error
)
{
req
,
err
:=
http
.
NewRequest
(
"HEAD"
,
url
,
nil
)
if
err
!=
nil
{
return
nil
,
err
}
return
Do
(
ctx
,
client
,
req
)
}
// Post issues a POST request via the Do function.
func
Post
(
ctx
context
.
Context
,
client
*
http
.
Client
,
url
string
,
bodyType
string
,
body
io
.
Reader
)
(
*
http
.
Response
,
error
)
{
req
,
err
:=
http
.
NewRequest
(
"POST"
,
url
,
body
)
if
err
!=
nil
{
return
nil
,
err
}
req
.
Header
.
Set
(
"Content-Type"
,
bodyType
)
return
Do
(
ctx
,
client
,
req
)
}
// PostForm issues a POST request via the Do function.
func
PostForm
(
ctx
context
.
Context
,
client
*
http
.
Client
,
url
string
,
data
url
.
Values
)
(
*
http
.
Response
,
error
)
{
return
Post
(
ctx
,
client
,
url
,
"application/x-www-form-urlencoded"
,
strings
.
NewReader
(
data
.
Encode
()))
}
vendor/golang.org/x/net/context/ctxhttp/ctxhttp_pre17.go
deleted
100644 → 0
View file @
777eeafa
// 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.
// +build !go1.7
package
ctxhttp
// import "golang.org/x/net/context/ctxhttp"
import
(
"io"
"net/http"
"net/url"
"strings"
"golang.org/x/net/context"
)
func
nop
()
{}
var
(
testHookContextDoneBeforeHeaders
=
nop
testHookDoReturned
=
nop
testHookDidBodyClose
=
nop
)
// Do sends an HTTP request with the provided http.Client and returns an HTTP response.
// If the client is nil, http.DefaultClient is used.
// If the context is canceled or times out, ctx.Err() will be returned.
func
Do
(
ctx
context
.
Context
,
client
*
http
.
Client
,
req
*
http
.
Request
)
(
*
http
.
Response
,
error
)
{
if
client
==
nil
{
client
=
http
.
DefaultClient
}
// TODO(djd): Respect any existing value of req.Cancel.
cancel
:=
make
(
chan
struct
{})
req
.
Cancel
=
cancel
type
responseAndError
struct
{
resp
*
http
.
Response
err
error
}
result
:=
make
(
chan
responseAndError
,
1
)
// Make local copies of test hooks closed over by goroutines below.
// Prevents data races in tests.
testHookDoReturned
:=
testHookDoReturned
testHookDidBodyClose
:=
testHookDidBodyClose
go
func
()
{
resp
,
err
:=
client
.
Do
(
req
)
testHookDoReturned
()
result
<-
responseAndError
{
resp
,
err
}
}()
var
resp
*
http
.
Response
select
{
case
<-
ctx
.
Done
()
:
testHookContextDoneBeforeHeaders
()
close
(
cancel
)
// Clean up after the goroutine calling client.Do:
go
func
()
{
if
r
:=
<-
result
;
r
.
resp
!=
nil
{
testHookDidBodyClose
()
r
.
resp
.
Body
.
Close
()
}
}()
return
nil
,
ctx
.
Err
()
case
r
:=
<-
result
:
var
err
error
resp
,
err
=
r
.
resp
,
r
.
err
if
err
!=
nil
{
return
resp
,
err
}
}
c
:=
make
(
chan
struct
{})
go
func
()
{
select
{
case
<-
ctx
.
Done
()
:
close
(
cancel
)
case
<-
c
:
// The response's Body is closed.
}
}()
resp
.
Body
=
&
notifyingReader
{
resp
.
Body
,
c
}
return
resp
,
nil
}
// Get issues a GET request via the Do function.
func
Get
(
ctx
context
.
Context
,
client
*
http
.
Client
,
url
string
)
(
*
http
.
Response
,
error
)
{
req
,
err
:=
http
.
NewRequest
(
"GET"
,
url
,
nil
)
if
err
!=
nil
{
return
nil
,
err
}
return
Do
(
ctx
,
client
,
req
)
}
// Head issues a HEAD request via the Do function.
func
Head
(
ctx
context
.
Context
,
client
*
http
.
Client
,
url
string
)
(
*
http
.
Response
,
error
)
{
req
,
err
:=
http
.
NewRequest
(
"HEAD"
,
url
,
nil
)
if
err
!=
nil
{
return
nil
,
err
}
return
Do
(
ctx
,
client
,
req
)
}
// Post issues a POST request via the Do function.
func
Post
(
ctx
context
.
Context
,
client
*
http
.
Client
,
url
string
,
bodyType
string
,
body
io
.
Reader
)
(
*
http
.
Response
,
error
)
{
req
,
err
:=
http
.
NewRequest
(
"POST"
,
url
,
body
)
if
err
!=
nil
{
return
nil
,
err
}
req
.
Header
.
Set
(
"Content-Type"
,
bodyType
)
return
Do
(
ctx
,
client
,
req
)
}
// PostForm issues a POST request via the Do function.
func
PostForm
(
ctx
context
.
Context
,
client
*
http
.
Client
,
url
string
,
data
url
.
Values
)
(
*
http
.
Response
,
error
)
{
return
Post
(
ctx
,
client
,
url
,
"application/x-www-form-urlencoded"
,
strings
.
NewReader
(
data
.
Encode
()))
}
// notifyingReader is an io.ReadCloser that closes the notify channel after
// Close is called or a Read fails on the underlying ReadCloser.
type
notifyingReader
struct
{
io
.
ReadCloser
notify
chan
<-
struct
{}
}
func
(
r
*
notifyingReader
)
Read
(
p
[]
byte
)
(
int
,
error
)
{
n
,
err
:=
r
.
ReadCloser
.
Read
(
p
)
if
err
!=
nil
&&
r
.
notify
!=
nil
{
close
(
r
.
notify
)
r
.
notify
=
nil
}
return
n
,
err
}
func
(
r
*
notifyingReader
)
Close
()
error
{
err
:=
r
.
ReadCloser
.
Close
()
if
r
.
notify
!=
nil
{
close
(
r
.
notify
)
r
.
notify
=
nil
}
return
err
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment