github.com/huaweicloud/golangsdk@v0.0.0-20210831081626-d823fe11ceba/openstack/obs/http.go (about)

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