forked from evergreen-ci/evergreen
/
http.go
137 lines (112 loc) · 3.56 KB
/
http.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
package thirdparty
import (
"bytes"
"encoding/json"
"net/http"
"net/url"
"github.com/evergreen-ci/evergreen/util"
"github.com/mongodb/grip"
"github.com/pkg/errors"
)
var (
MaxRedirects = 10
)
type httpClient interface {
doGet(string, string, string) (*http.Response, error)
doPost(string, string, string, interface{}) (*http.Response, error)
doPut(string, string, string, interface{}) (*http.Response, error)
}
type liveHttp struct{}
func shouldRedirectGet(statusCode int) bool {
switch statusCode {
case http.StatusMovedPermanently, http.StatusFound, http.StatusSeeOther, http.StatusTemporaryRedirect:
return true
}
return false
}
func doFollowingRedirectsWithHeaders(client *http.Client, ireq *http.Request) (resp *http.Response, err error) {
// Default Go HTTP client silently wipes headers on redirect, so we need to
// write our own. See http://golang.org/src/pkg/net/http/client.go#L273
if t, ok := client.Transport.(*http.Transport); ok {
defer t.CloseIdleConnections()
}
var base *url.URL
var urlStr string
req := ireq
for redirect := 0; ; redirect++ {
if redirect != 0 {
req = new(http.Request)
req.Method = ireq.Method
// This line is what Go doesn't do. Undocumented but known issue, see
// https://groups.google.com/forum/#!topic/golang-nuts/OwGvopYXpwE
req.Header = ireq.Header
req.URL, err = base.Parse(urlStr)
if err != nil {
break
}
}
if resp, err = client.Transport.RoundTrip(req); err != nil {
break
}
if shouldRedirectGet(resp.StatusCode) {
grip.Warning(resp.Body.Close())
if urlStr = resp.Header.Get("Location"); urlStr == "" {
err = errors.Errorf("%d response missing Location header", resp.StatusCode)
break
}
if redirect+1 >= MaxRedirects {
return nil, errors.New("Too many redirects")
}
base = req.URL
continue
}
return
}
return
}
func (self liveHttp) doGet(url string, username string, password string) (*http.Response, error) {
req, err := http.NewRequest("GET", url, nil)
if err != nil {
return nil, errors.Wrap(err, "GET")
}
req.Header.Add("Accept", "*/*")
req.SetBasicAuth(username, password)
req.Header.Add("Content-Type", "application/json")
client := util.GetHTTPClient()
defer util.PutHTTPClient(client)
var resp *http.Response
resp, err = doFollowingRedirectsWithHeaders(client, req)
if err != nil {
return resp, errors.WithStack(err)
}
return resp, nil
}
func (self liveHttp) postOrPut(method string, url string, username string, password string, content interface{}) (*http.Response, error) {
body := &bytes.Buffer{}
if err := json.NewEncoder(body).Encode(content); err != nil {
return nil, errors.Wrap(err, "error encoding request")
}
req, err := http.NewRequest(method, url, body)
if err != nil {
return nil, errors.Wrapf(err, "%s", method)
}
req.Header.Add("Accept", "*/*")
req.SetBasicAuth(username, password)
req.Header.Add("Content-Type", "application/json")
client := util.GetHTTPClient()
defer util.PutHTTPClient(client)
var resp *http.Response
resp, err = doFollowingRedirectsWithHeaders(client, req)
if err != nil {
return resp, errors.WithStack(err)
}
return resp, nil
}
func (self liveHttp) doPost(url string, username string, password string, content interface{}) (*http.Response, error) {
resp, err := self.postOrPut("POST", url, username, password, content)
return resp, errors.WithStack(err)
}
func (self liveHttp) doPut(url string, username string, password string, content interface{}) (*http.Response, error) {
resp, err := self.postOrPut("PUT", url, username, password, content)
return resp, errors.WithStack(err)
}