1
2
3 package management
4
5
6
7
8 import (
9 "bytes"
10 "crypto/tls"
11 "fmt"
12 "net/http"
13 "time"
14 )
15
16 const (
17 msVersionHeader = "x-ms-version"
18 requestIDHeader = "x-ms-request-id"
19 uaHeader = "User-Agent"
20 contentHeader = "Content-Type"
21 defaultContentHeaderValue = "application/xml"
22 )
23
24 func (client client) SendAzureGetRequest(url string) ([]byte, error) {
25 resp, err := client.sendAzureRequest("GET", url, "", nil)
26 if err != nil {
27 return nil, err
28 }
29 return getResponseBody(resp)
30 }
31
32 func (client client) SendAzurePostRequest(url string, data []byte) (OperationID, error) {
33 return client.doAzureOperation("POST", url, "", data)
34 }
35
36 func (client client) SendAzurePostRequestWithReturnedResponse(url string, data []byte) ([]byte, error) {
37 resp, err := client.sendAzureRequest("POST", url, "", data)
38 if err != nil {
39 return nil, err
40 }
41
42 return getResponseBody(resp)
43 }
44
45 func (client client) SendAzurePutRequest(url, contentType string, data []byte) (OperationID, error) {
46 return client.doAzureOperation("PUT", url, contentType, data)
47 }
48
49 func (client client) SendAzureDeleteRequest(url string) (OperationID, error) {
50 return client.doAzureOperation("DELETE", url, "", nil)
51 }
52
53 func (client client) doAzureOperation(method, url, contentType string, data []byte) (OperationID, error) {
54 response, err := client.sendAzureRequest(method, url, contentType, data)
55 if err != nil {
56 return "", err
57 }
58 return getOperationID(response)
59 }
60
61 func getOperationID(response *http.Response) (OperationID, error) {
62 requestID := response.Header.Get(requestIDHeader)
63 if requestID == "" {
64 return "", fmt.Errorf("Could not retrieve operation id from %q header", requestIDHeader)
65 }
66 return OperationID(requestID), nil
67 }
68
69
70
71 func (client client) sendAzureRequest(method, url, contentType string, data []byte) (*http.Response, error) {
72 if method == "" {
73 return nil, fmt.Errorf(errParamNotSpecified, "method")
74 }
75 if url == "" {
76 return nil, fmt.Errorf(errParamNotSpecified, "url")
77 }
78
79 response, err := client.sendRequest(client.httpClient, url, method, contentType, data, 5)
80 if err != nil {
81 return nil, err
82 }
83
84 return response, nil
85 }
86
87
88
89 func (client client) createHTTPClient() (*http.Client, error) {
90 cert, err := tls.X509KeyPair(client.publishSettings.SubscriptionCert, client.publishSettings.SubscriptionKey)
91 if err != nil {
92 return nil, err
93 }
94
95 return &http.Client{
96 Transport: &http.Transport{
97 Proxy: http.ProxyFromEnvironment,
98 TLSClientConfig: &tls.Config{
99 Renegotiation: tls.RenegotiateOnceAsClient,
100 Certificates: []tls.Certificate{cert},
101 },
102 },
103 }, nil
104 }
105
106
107
108
109 func (client client) sendRequest(httpClient *http.Client, url, requestType, contentType string, data []byte, numberOfRetries int) (*http.Response, error) {
110
111 absURI := client.createAzureRequestURI(url)
112
113 for {
114 request, reqErr := client.createAzureRequest(absURI, requestType, contentType, data)
115 if reqErr != nil {
116 return nil, reqErr
117 }
118
119 response, err := httpClient.Do(request)
120 if err != nil {
121 if numberOfRetries == 0 {
122 return nil, err
123 }
124
125 return client.sendRequest(httpClient, url, requestType, contentType, data, numberOfRetries-1)
126 }
127 if response.StatusCode == http.StatusTemporaryRedirect {
128
129
130 u, err := response.Location()
131 if err != nil {
132 return response, fmt.Errorf("Redirect requested but location header could not be retrieved: %v", err)
133 }
134 absURI = u.String()
135 continue
136 }
137
138 if response.StatusCode >= http.StatusBadRequest {
139 body, err := getResponseBody(response)
140 if err != nil {
141
142 return nil, err
143 }
144 azureErr := getAzureError(body)
145 if azureErr != nil {
146 if numberOfRetries == 0 {
147 return nil, azureErr
148 }
149 if response.StatusCode == http.StatusServiceUnavailable || response.StatusCode == http.StatusTooManyRequests {
150
151 time.Sleep(client.config.OperationPollInterval)
152 }
153
154 return client.sendRequest(httpClient, url, requestType, contentType, data, numberOfRetries-1)
155 }
156 }
157
158 return response, nil
159 }
160 }
161
162
163
164 func (client client) createAzureRequestURI(url string) string {
165 return fmt.Sprintf("%s/%s/%s", client.config.ManagementURL, client.publishSettings.SubscriptionID, url)
166 }
167
168
169
170 func (client client) createAzureRequest(url string, requestType string, contentType string, data []byte) (*http.Request, error) {
171 var request *http.Request
172 var err error
173
174 if data != nil {
175 body := bytes.NewBuffer(data)
176 request, err = http.NewRequest(requestType, url, body)
177 } else {
178 request, err = http.NewRequest(requestType, url, nil)
179 }
180
181 if err != nil {
182 return nil, err
183 }
184
185 request.Header.Set(msVersionHeader, client.config.APIVersion)
186 request.Header.Set(uaHeader, client.config.UserAgent)
187
188 if contentType != "" {
189 request.Header.Set(contentHeader, contentType)
190 } else {
191 request.Header.Set(contentHeader, defaultContentHeaderValue)
192 }
193
194 return request, nil
195 }
196
View as plain text