diff options
Diffstat (limited to 'httputil/transport.go')
-rw-r--r-- | httputil/transport.go | 87 |
1 files changed, 87 insertions, 0 deletions
diff --git a/httputil/transport.go b/httputil/transport.go new file mode 100644 index 0000000..fdad3b4 --- /dev/null +++ b/httputil/transport.go | |||
@@ -0,0 +1,87 @@ | |||
1 | // Copyright 2015 The Go Authors. All rights reserved. | ||
2 | // | ||
3 | // Use of this source code is governed by a BSD-style | ||
4 | // license that can be found in the LICENSE file or at | ||
5 | // https://developers.google.com/open-source/licenses/bsd. | ||
6 | |||
7 | // This file implements a http.RoundTripper that authenticates | ||
8 | // requests issued against api.github.com endpoint. | ||
9 | |||
10 | package httputil | ||
11 | |||
12 | import ( | ||
13 | "net/http" | ||
14 | "net/url" | ||
15 | ) | ||
16 | |||
17 | // AuthTransport is an implementation of http.RoundTripper that authenticates | ||
18 | // with the GitHub API. | ||
19 | // | ||
20 | // When both a token and client credentials are set, the latter is preferred. | ||
21 | type AuthTransport struct { | ||
22 | UserAgent string | ||
23 | GithubToken string | ||
24 | GithubClientID string | ||
25 | GithubClientSecret string | ||
26 | Base http.RoundTripper | ||
27 | } | ||
28 | |||
29 | // RoundTrip implements the http.RoundTripper interface. | ||
30 | func (t *AuthTransport) RoundTrip(req *http.Request) (*http.Response, error) { | ||
31 | var reqCopy *http.Request | ||
32 | if t.UserAgent != "" { | ||
33 | reqCopy = copyRequest(req) | ||
34 | reqCopy.Header.Set("User-Agent", t.UserAgent) | ||
35 | } | ||
36 | if req.URL.Host == "api.github.com" && req.URL.Scheme == "https" { | ||
37 | switch { | ||
38 | case t.GithubClientID != "" && t.GithubClientSecret != "": | ||
39 | if reqCopy == nil { | ||
40 | reqCopy = copyRequest(req) | ||
41 | } | ||
42 | if reqCopy.URL.RawQuery == "" { | ||
43 | reqCopy.URL.RawQuery = "client_id=" + t.GithubClientID + "&client_secret=" + t.GithubClientSecret | ||
44 | } else { | ||
45 | reqCopy.URL.RawQuery += "&client_id=" + t.GithubClientID + "&client_secret=" + t.GithubClientSecret | ||
46 | } | ||
47 | case t.GithubToken != "": | ||
48 | if reqCopy == nil { | ||
49 | reqCopy = copyRequest(req) | ||
50 | } | ||
51 | reqCopy.Header.Set("Authorization", "token "+t.GithubToken) | ||
52 | } | ||
53 | } | ||
54 | if reqCopy != nil { | ||
55 | return t.base().RoundTrip(reqCopy) | ||
56 | } | ||
57 | return t.base().RoundTrip(req) | ||
58 | } | ||
59 | |||
60 | // CancelRequest cancels an in-flight request by closing its connection. | ||
61 | func (t *AuthTransport) CancelRequest(req *http.Request) { | ||
62 | type canceler interface { | ||
63 | CancelRequest(req *http.Request) | ||
64 | } | ||
65 | if cr, ok := t.base().(canceler); ok { | ||
66 | cr.CancelRequest(req) | ||
67 | } | ||
68 | } | ||
69 | |||
70 | func (t *AuthTransport) base() http.RoundTripper { | ||
71 | if t.Base != nil { | ||
72 | return t.Base | ||
73 | } | ||
74 | return http.DefaultTransport | ||
75 | } | ||
76 | |||
77 | func copyRequest(req *http.Request) *http.Request { | ||
78 | req2 := new(http.Request) | ||
79 | *req2 = *req | ||
80 | req2.URL = new(url.URL) | ||
81 | *req2.URL = *req.URL | ||
82 | req2.Header = make(http.Header, len(req.Header)) | ||
83 | for k, s := range req.Header { | ||
84 | req2.Header[k] = append([]string(nil), s...) | ||
85 | } | ||
86 | return req2 | ||
87 | } | ||