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