yunion.io/x/cloudmux@v0.3.10-0-alpha.1/pkg/multicloud/huawei/obs/http.go (about) 1 // Copyright 2019 Yunion 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 // Copyright 2019 Huawei Technologies Co.,Ltd. 16 // Licensed under the Apache License, Version 2.0 (the "License"); you may not use 17 // this file except in compliance with the License. You may obtain a copy of the 18 // License at 19 // 20 // http://www.apache.org/licenses/LICENSE-2.0 21 // 22 // Unless required by applicable law or agreed to in writing, software distributed 23 // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 24 // CONDITIONS OF ANY KIND, either express or implied. See the License for the 25 // specific language governing permissions and limitations under the License. 26 27 package obs 28 29 import ( 30 "bytes" 31 "errors" 32 "io" 33 "math/rand" 34 "net" 35 "net/http" 36 "net/url" 37 "os" 38 "strings" 39 "time" 40 ) 41 42 func prepareHeaders(headers map[string][]string, meta bool, isObs bool) map[string][]string { 43 _headers := make(map[string][]string, len(headers)) 44 if headers != nil { 45 for key, value := range headers { 46 key = strings.TrimSpace(key) 47 if key == "" { 48 continue 49 } 50 _key := strings.ToLower(key) 51 if _, ok := allowed_request_http_header_metadata_names[_key]; !ok && !strings.HasPrefix(key, HEADER_PREFIX) && !strings.HasPrefix(key, HEADER_PREFIX_OBS) { 52 if !meta { 53 continue 54 } 55 if !isObs { 56 _key = HEADER_PREFIX_META + _key 57 } else { 58 _key = HEADER_PREFIX_META_OBS + _key 59 } 60 } else { 61 _key = key 62 } 63 _headers[_key] = value 64 } 65 } 66 return _headers 67 } 68 69 func (obsClient ObsClient) doActionWithoutBucket(action, method string, input ISerializable, output IBaseModel) error { 70 return obsClient.doAction(action, method, "", "", input, output, true, true) 71 } 72 73 func (obsClient ObsClient) doActionWithBucketV2(action, method, bucketName string, input ISerializable, output IBaseModel) error { 74 if strings.TrimSpace(bucketName) == "" && !obsClient.conf.cname { 75 return errors.New("Bucket is empty") 76 } 77 return obsClient.doAction(action, method, bucketName, "", input, output, false, true) 78 } 79 80 func (obsClient ObsClient) doActionWithBucket(action, method, bucketName string, input ISerializable, output IBaseModel) error { 81 if strings.TrimSpace(bucketName) == "" && !obsClient.conf.cname { 82 return errors.New("Bucket is empty") 83 } 84 return obsClient.doAction(action, method, bucketName, "", input, output, true, true) 85 } 86 87 func (obsClient ObsClient) doActionWithBucketAndKey(action, method, bucketName, objectKey string, input ISerializable, output IBaseModel) error { 88 return obsClient._doActionWithBucketAndKey(action, method, bucketName, objectKey, input, output, true) 89 } 90 91 func (obsClient ObsClient) doActionWithBucketAndKeyUnRepeatable(action, method, bucketName, objectKey string, input ISerializable, output IBaseModel) error { 92 return obsClient._doActionWithBucketAndKey(action, method, bucketName, objectKey, input, output, false) 93 } 94 95 func (obsClient ObsClient) _doActionWithBucketAndKey(action, method, bucketName, objectKey string, input ISerializable, output IBaseModel, repeatable bool) error { 96 if strings.TrimSpace(bucketName) == "" && !obsClient.conf.cname { 97 return errors.New("Bucket is empty") 98 } 99 if strings.TrimSpace(objectKey) == "" { 100 return errors.New("Key is empty") 101 } 102 return obsClient.doAction(action, method, bucketName, objectKey, input, output, true, repeatable) 103 } 104 105 func (obsClient ObsClient) doAction(action, method, bucketName, objectKey string, input ISerializable, output IBaseModel, xmlResult bool, repeatable bool) error { 106 107 var resp *http.Response 108 var respError error 109 doLog(LEVEL_INFO, "Enter method %s...", action) 110 start := GetCurrentTimestamp() 111 112 params, headers, data, err := input.trans(obsClient.conf.signature == SignatureObs) 113 if err != nil { 114 return err 115 } 116 if params == nil { 117 params = make(map[string]string) 118 } 119 120 if headers == nil { 121 headers = make(map[string][]string) 122 } 123 124 switch method { 125 case HTTP_GET: 126 resp, respError = obsClient.doHttpGet(bucketName, objectKey, params, headers, data, repeatable) 127 case HTTP_POST: 128 resp, respError = obsClient.doHttpPost(bucketName, objectKey, params, headers, data, repeatable) 129 case HTTP_PUT: 130 resp, respError = obsClient.doHttpPut(bucketName, objectKey, params, headers, data, repeatable) 131 case HTTP_DELETE: 132 resp, respError = obsClient.doHttpDelete(bucketName, objectKey, params, headers, data, repeatable) 133 case HTTP_HEAD: 134 resp, respError = obsClient.doHttpHead(bucketName, objectKey, params, headers, data, repeatable) 135 case HTTP_OPTIONS: 136 resp, respError = obsClient.doHttpOptions(bucketName, objectKey, params, headers, data, repeatable) 137 default: 138 respError = errors.New("Unexpect http method error") 139 } 140 if respError == nil && output != nil { 141 respError = ParseResponseToBaseModel(resp, output, xmlResult, obsClient.conf.signature == SignatureObs) 142 if respError != nil { 143 doLog(LEVEL_WARN, "Parse response to BaseModel with error: %v", respError) 144 } 145 } else { 146 doLog(LEVEL_WARN, "Do http request with error: %v", respError) 147 } 148 149 if isDebugLogEnabled() { 150 doLog(LEVEL_DEBUG, "End method %s, obsclient cost %d ms", action, (GetCurrentTimestamp() - start)) 151 } 152 153 return respError 154 } 155 156 func (obsClient ObsClient) doHttpGet(bucketName, objectKey string, params map[string]string, 157 headers map[string][]string, data interface{}, repeatable bool) (*http.Response, error) { 158 return obsClient.doHttp(HTTP_GET, bucketName, objectKey, params, prepareHeaders(headers, false, obsClient.conf.signature == SignatureObs), data, repeatable) 159 } 160 161 func (obsClient ObsClient) doHttpHead(bucketName, objectKey string, params map[string]string, 162 headers map[string][]string, data interface{}, repeatable bool) (*http.Response, error) { 163 return obsClient.doHttp(HTTP_HEAD, bucketName, objectKey, params, prepareHeaders(headers, false, obsClient.conf.signature == SignatureObs), data, repeatable) 164 } 165 166 func (obsClient ObsClient) doHttpOptions(bucketName, objectKey string, params map[string]string, 167 headers map[string][]string, data interface{}, repeatable bool) (*http.Response, error) { 168 return obsClient.doHttp(HTTP_OPTIONS, bucketName, objectKey, params, prepareHeaders(headers, false, obsClient.conf.signature == SignatureObs), data, repeatable) 169 } 170 171 func (obsClient ObsClient) doHttpDelete(bucketName, objectKey string, params map[string]string, 172 headers map[string][]string, data interface{}, repeatable bool) (*http.Response, error) { 173 return obsClient.doHttp(HTTP_DELETE, bucketName, objectKey, params, prepareHeaders(headers, false, obsClient.conf.signature == SignatureObs), data, repeatable) 174 } 175 176 func (obsClient ObsClient) doHttpPut(bucketName, objectKey string, params map[string]string, 177 headers map[string][]string, data interface{}, repeatable bool) (*http.Response, error) { 178 return obsClient.doHttp(HTTP_PUT, bucketName, objectKey, params, prepareHeaders(headers, true, obsClient.conf.signature == SignatureObs), data, repeatable) 179 } 180 181 func (obsClient ObsClient) doHttpPost(bucketName, objectKey string, params map[string]string, 182 headers map[string][]string, data interface{}, repeatable bool) (*http.Response, error) { 183 return obsClient.doHttp(HTTP_POST, bucketName, objectKey, params, prepareHeaders(headers, true, obsClient.conf.signature == SignatureObs), data, repeatable) 184 } 185 186 func (obsClient ObsClient) doHttpWithSignedUrl(action, method string, signedUrl string, actualSignedRequestHeaders http.Header, data io.Reader, output IBaseModel, xmlResult bool) (respError error) { 187 req, err := http.NewRequest(method, signedUrl, data) 188 if err != nil { 189 return err 190 } 191 if obsClient.conf.ctx != nil { 192 req = req.WithContext(obsClient.conf.ctx) 193 } 194 var resp *http.Response 195 196 doLog(LEVEL_INFO, "Do %s with signedUrl %s...", action, signedUrl) 197 198 req.Header = actualSignedRequestHeaders 199 if value, ok := req.Header[HEADER_HOST_CAMEL]; ok { 200 req.Host = value[0] 201 delete(req.Header, HEADER_HOST_CAMEL) 202 } else if value, ok := req.Header[HEADER_HOST]; ok { 203 req.Host = value[0] 204 delete(req.Header, HEADER_HOST) 205 } 206 207 if value, ok := req.Header[HEADER_CONTENT_LENGTH_CAMEL]; ok { 208 req.ContentLength = StringToInt64(value[0], -1) 209 delete(req.Header, HEADER_CONTENT_LENGTH_CAMEL) 210 } else if value, ok := req.Header[HEADER_CONTENT_LENGTH]; ok { 211 req.ContentLength = StringToInt64(value[0], -1) 212 delete(req.Header, HEADER_CONTENT_LENGTH) 213 } 214 215 req.Header[HEADER_USER_AGENT_CAMEL] = []string{USER_AGENT} 216 start := GetCurrentTimestamp() 217 resp, err = obsClient.httpClient.Do(req) 218 if isInfoLogEnabled() { 219 doLog(LEVEL_INFO, "Do http request cost %d ms", (GetCurrentTimestamp() - start)) 220 } 221 222 var msg interface{} 223 if err != nil { 224 respError = err 225 resp = nil 226 } else { 227 doLog(LEVEL_DEBUG, "Response headers: %v", resp.Header) 228 if resp.StatusCode >= 300 { 229 respError = ParseResponseToObsError(resp, obsClient.conf.signature == SignatureObs) 230 msg = resp.Status 231 resp = nil 232 } else { 233 if output != nil { 234 respError = ParseResponseToBaseModel(resp, output, xmlResult, obsClient.conf.signature == SignatureObs) 235 } 236 if respError != nil { 237 doLog(LEVEL_WARN, "Parse response to BaseModel with error: %v", respError) 238 } 239 } 240 } 241 242 if msg != nil { 243 doLog(LEVEL_ERROR, "Failed to send request with reason:%v", msg) 244 } 245 246 if isDebugLogEnabled() { 247 doLog(LEVEL_DEBUG, "End method %s, obsclient cost %d ms", action, (GetCurrentTimestamp() - start)) 248 } 249 250 return 251 } 252 253 func (obsClient ObsClient) doHttp(method, bucketName, objectKey string, params map[string]string, 254 headers map[string][]string, data interface{}, repeatable bool) (resp *http.Response, respError error) { 255 256 bucketName = strings.TrimSpace(bucketName) 257 258 method = strings.ToUpper(method) 259 260 var redirectUrl string 261 var requestUrl string 262 maxRetryCount := obsClient.conf.maxRetryCount 263 maxRedirectCount := obsClient.conf.maxRedirectCount 264 265 var _data io.Reader 266 if data != nil { 267 if dataStr, ok := data.(string); ok { 268 doLog(LEVEL_DEBUG, "Do http request with string: %s", dataStr) 269 headers["Content-Length"] = []string{IntToString(len(dataStr))} 270 _data = strings.NewReader(dataStr) 271 } else if dataByte, ok := data.([]byte); ok { 272 doLog(LEVEL_DEBUG, "Do http request with byte array") 273 headers["Content-Length"] = []string{IntToString(len(dataByte))} 274 _data = bytes.NewReader(dataByte) 275 } else if dataReader, ok := data.(io.Reader); ok { 276 _data = dataReader 277 } else { 278 doLog(LEVEL_WARN, "Data is not a valid io.Reader") 279 return nil, errors.New("Data is not a valid io.Reader") 280 } 281 } 282 283 var lastRequest *http.Request 284 redirectFlag := false 285 for i, redirectCount := 0, 0; i <= maxRetryCount; i++ { 286 if redirectUrl != "" { 287 if !redirectFlag { 288 parsedRedirectUrl, err := url.Parse(redirectUrl) 289 if err != nil { 290 return nil, err 291 } 292 requestUrl, err = obsClient.doAuth(method, bucketName, objectKey, params, headers, parsedRedirectUrl.Host) 293 if err != nil { 294 return nil, err 295 } 296 if parsedRequestUrl, err := url.Parse(requestUrl); err != nil { 297 return nil, err 298 } else if parsedRequestUrl.RawQuery != "" && parsedRedirectUrl.RawQuery == "" { 299 redirectUrl += "?" + parsedRequestUrl.RawQuery 300 } 301 } 302 requestUrl = redirectUrl 303 } else { 304 var err error 305 requestUrl, err = obsClient.doAuth(method, bucketName, objectKey, params, headers, "") 306 if err != nil { 307 return nil, err 308 } 309 } 310 311 req, err := http.NewRequest(method, requestUrl, _data) 312 if err != nil { 313 return nil, err 314 } 315 if obsClient.conf.ctx != nil { 316 req = req.WithContext(obsClient.conf.ctx) 317 } 318 doLog(LEVEL_DEBUG, "Do request with url [%s] and method [%s]", requestUrl, method) 319 320 if isDebugLogEnabled() { 321 auth := headers[HEADER_AUTH_CAMEL] 322 delete(headers, HEADER_AUTH_CAMEL) 323 doLog(LEVEL_DEBUG, "Request headers: %v", headers) 324 headers[HEADER_AUTH_CAMEL] = auth 325 } 326 327 for key, value := range headers { 328 if key == HEADER_HOST_CAMEL { 329 req.Host = value[0] 330 delete(headers, key) 331 } else if key == HEADER_CONTENT_LENGTH_CAMEL { 332 req.ContentLength = StringToInt64(value[0], -1) 333 delete(headers, key) 334 } else { 335 req.Header[key] = value 336 } 337 } 338 339 lastRequest = req 340 341 req.Header[HEADER_USER_AGENT_CAMEL] = []string{USER_AGENT} 342 343 if lastRequest != nil { 344 req.Host = lastRequest.Host 345 req.ContentLength = lastRequest.ContentLength 346 } 347 348 start := GetCurrentTimestamp() 349 resp, err = obsClient.httpClient.Do(req) 350 if isInfoLogEnabled() { 351 doLog(LEVEL_INFO, "Do http request cost %d ms", (GetCurrentTimestamp() - start)) 352 } 353 354 var msg interface{} 355 if err != nil { 356 msg = err 357 respError = err 358 resp = nil 359 if !repeatable { 360 break 361 } 362 } else { 363 doLog(LEVEL_DEBUG, "Response headers: %v", resp.Header) 364 if resp.StatusCode < 300 { 365 break 366 } else if !repeatable || (resp.StatusCode >= 400 && resp.StatusCode < 500) || resp.StatusCode == 304 { 367 respError = ParseResponseToObsError(resp, obsClient.conf.signature == SignatureObs) 368 resp = nil 369 break 370 } else if resp.StatusCode >= 300 && resp.StatusCode < 400 { 371 if location := resp.Header.Get(HEADER_LOCATION_CAMEL); location != "" && redirectCount < maxRedirectCount { 372 redirectUrl = location 373 doLog(LEVEL_WARN, "Redirect request to %s", redirectUrl) 374 msg = resp.Status 375 maxRetryCount++ 376 redirectCount++ 377 if resp.StatusCode == 302 && method == HTTP_GET { 378 redirectFlag = true 379 } else { 380 redirectFlag = false 381 } 382 } else { 383 respError = ParseResponseToObsError(resp, obsClient.conf.signature == SignatureObs) 384 resp = nil 385 break 386 } 387 } else { 388 msg = resp.Status 389 } 390 } 391 if i != maxRetryCount { 392 if resp != nil { 393 _err := resp.Body.Close() 394 if _err != nil { 395 doLog(LEVEL_WARN, "Failed to close resp body with reason: %v", _err) 396 } 397 resp = nil 398 } 399 if _, ok := headers[HEADER_AUTH_CAMEL]; ok { 400 delete(headers, HEADER_AUTH_CAMEL) 401 } 402 doLog(LEVEL_WARN, "Failed to send request with reason:%v, will try again", msg) 403 if r, ok := _data.(*strings.Reader); ok { 404 _, err := r.Seek(0, 0) 405 if err != nil { 406 return nil, err 407 } 408 } else if r, ok := _data.(*bytes.Reader); ok { 409 _, err := r.Seek(0, 0) 410 if err != nil { 411 return nil, err 412 } 413 } else if r, ok := _data.(*fileReaderWrapper); ok { 414 fd, err := os.Open(r.filePath) 415 if err != nil { 416 return nil, err 417 } 418 defer func() { 419 errMsg := fd.Close() 420 if errMsg != nil { 421 doLog(LEVEL_WARN, "Failed to close with reason: %v", errMsg) 422 } 423 }() 424 fileReaderWrapper := &fileReaderWrapper{filePath: r.filePath} 425 fileReaderWrapper.mark = r.mark 426 fileReaderWrapper.reader = fd 427 fileReaderWrapper.totalCount = r.totalCount 428 _data = fileReaderWrapper 429 _, err = fd.Seek(r.mark, 0) 430 if err != nil { 431 return nil, err 432 } 433 } else if r, ok := _data.(*readerWrapper); ok { 434 _, err := r.seek(0, 0) 435 if err != nil { 436 return nil, err 437 } 438 } 439 time.Sleep(time.Duration(float64(i+2) * rand.Float64() * float64(time.Second))) 440 } else { 441 doLog(LEVEL_ERROR, "Failed to send request with reason:%v", msg) 442 if resp != nil { 443 respError = ParseResponseToObsError(resp, obsClient.conf.signature == SignatureObs) 444 resp = nil 445 } 446 } 447 } 448 return 449 } 450 451 type connDelegate struct { 452 conn net.Conn 453 socketTimeout time.Duration 454 finalTimeout time.Duration 455 } 456 457 func getConnDelegate(conn net.Conn, socketTimeout int, finalTimeout int) *connDelegate { 458 return &connDelegate{ 459 conn: conn, 460 socketTimeout: time.Second * time.Duration(socketTimeout), 461 finalTimeout: time.Second * time.Duration(finalTimeout), 462 } 463 } 464 465 func (delegate *connDelegate) Read(b []byte) (n int, err error) { 466 setReadDeadlineErr := delegate.SetReadDeadline(time.Now().Add(delegate.socketTimeout)) 467 flag := isDebugLogEnabled() 468 469 if setReadDeadlineErr != nil && flag { 470 doLog(LEVEL_DEBUG, "Failed to set read deadline with reason: %v, but it's ok", setReadDeadlineErr) 471 } 472 473 n, err = delegate.conn.Read(b) 474 setReadDeadlineErr = delegate.SetReadDeadline(time.Now().Add(delegate.finalTimeout)) 475 if setReadDeadlineErr != nil && flag { 476 doLog(LEVEL_DEBUG, "Failed to set read deadline with reason: %v, but it's ok", setReadDeadlineErr) 477 } 478 return n, err 479 } 480 481 func (delegate *connDelegate) Write(b []byte) (n int, err error) { 482 setWriteDeadlineErr := delegate.SetWriteDeadline(time.Now().Add(delegate.socketTimeout)) 483 flag := isDebugLogEnabled() 484 if setWriteDeadlineErr != nil && flag { 485 doLog(LEVEL_DEBUG, "Failed to set write deadline with reason: %v, but it's ok", setWriteDeadlineErr) 486 } 487 488 n, err = delegate.conn.Write(b) 489 finalTimeout := time.Now().Add(delegate.finalTimeout) 490 setWriteDeadlineErr = delegate.SetWriteDeadline(finalTimeout) 491 if setWriteDeadlineErr != nil && flag { 492 doLog(LEVEL_DEBUG, "Failed to set write deadline with reason: %v, but it's ok", setWriteDeadlineErr) 493 } 494 setReadDeadlineErr := delegate.SetReadDeadline(finalTimeout) 495 if setReadDeadlineErr != nil && flag { 496 doLog(LEVEL_DEBUG, "Failed to set read deadline with reason: %v, but it's ok", setReadDeadlineErr) 497 } 498 return n, err 499 } 500 501 func (delegate *connDelegate) Close() error { 502 return delegate.conn.Close() 503 } 504 505 func (delegate *connDelegate) LocalAddr() net.Addr { 506 return delegate.conn.LocalAddr() 507 } 508 509 func (delegate *connDelegate) RemoteAddr() net.Addr { 510 return delegate.conn.RemoteAddr() 511 } 512 513 func (delegate *connDelegate) SetDeadline(t time.Time) error { 514 return delegate.conn.SetDeadline(t) 515 } 516 517 func (delegate *connDelegate) SetReadDeadline(t time.Time) error { 518 return delegate.conn.SetReadDeadline(t) 519 } 520 521 func (delegate *connDelegate) SetWriteDeadline(t time.Time) error { 522 return delegate.conn.SetWriteDeadline(t) 523 }