func()

in oss/client.go [334:455]


func (c *Client) sendRequest(ctx context.Context, input *OperationInput, opts *Options) (output *OperationOutput, err error) {
	var request *http.Request
	var response *http.Response
	if c.getLogLevel() >= LogInfo {
		c.inner.Log.Infof("sendRequest Start: input[%p]", input)
		defer func() {
			c.inner.Log.Infof("sendRequest End: input[%p], http.Request[%p], http.Response[%p]", input, request, response)
		}()
	}

	// covert input into httpRequest
	if !isValidEndpoint(opts.Endpoint) {
		return output, NewErrParamInvalid("Endpoint")
	}

	var writers []io.Writer
	// tracker in OperationMetaData
	for _, w := range input.OpMetadata.Values(OpMetaKeyRequestBodyTracker) {
		if ww, ok := w.(io.Writer); ok {
			writers = append(writers, ww)
		}
	}
	// host & path
	host, path := buildURL(input, opts)
	strUrl := fmt.Sprintf("%s://%s%s", opts.Endpoint.Scheme, host, path)

	// querys
	if len(input.Parameters) > 0 {
		var buf bytes.Buffer
		for k, v := range input.Parameters {
			if buf.Len() > 0 {
				buf.WriteByte('&')
			}
			buf.WriteString(url.QueryEscape(k))
			if len(v) > 0 {
				buf.WriteString("=" + strings.Replace(url.QueryEscape(v), "+", "%20", -1))
			}
		}
		strUrl += "?" + buf.String()
	}

	request, err = http.NewRequestWithContext(ctx, input.Method, strUrl, nil)
	if err != nil {
		return output, err
	}

	// headers
	for k, v := range input.Headers {
		if len(k) > 0 && len(v) > 0 {
			request.Header.Add(k, v)
		}
	}
	request.Header.Set("User-Agent", c.inner.UserAgent)

	// body
	var body io.Reader
	if input.Body == nil {
		body = strings.NewReader("")
	} else {
		body = input.Body
	}
	var length int64
	if clen := request.Header.Get("Content-Length"); clen != "" {
		length, _ = strconv.ParseInt(clen, 10, 64)
	} else {
		length = GetReaderLen(body)
	}
	if length >= 0 {
		request.ContentLength = length
	}
	request.Body = TeeReadNopCloser(body, writers...)

	//signing context
	subResource, _ := input.OpMetadata.Get(signer.SubResource).([]string)
	clockOffset := c.inner.ClockOffset
	signingCtx := &signer.SigningContext{
		Product:           Ptr(opts.Product),
		Region:            Ptr(opts.Region),
		Bucket:            input.Bucket,
		Key:               input.Key,
		Request:           request,
		SubResource:       subResource,
		AuthMethodQuery:   opts.AuthMethod != nil && *opts.AuthMethod == AuthMethodQuery,
		ClockOffset:       clockOffset,
		AdditionalHeaders: opts.AdditionalHeaders,
	}

	if date := request.Header.Get(HeaderOssDate); date != "" {
		signingCtx.Time, _ = http.ParseTime(date)
	} else if signTime, ok := input.OpMetadata.Get(signer.SignTime).(time.Time); ok {
		signingCtx.Time = signTime
	}

	// send http request
	response, err = c.sendHttpRequest(ctx, signingCtx, opts)

	if err != nil {
		return output, err
	}

	// covert http response into output context
	output = &OperationOutput{
		Input:       input,
		Status:      response.Status,
		StatusCode:  response.StatusCode,
		Body:        response.Body,
		Headers:     response.Header,
		httpRequest: request,
	}

	// save other info by Metadata filed, ex. retry detail info
	//output.OpMetadata.Set(...)
	if signingCtx.AuthMethodQuery {
		output.OpMetadata.Set(signer.SignTime, signingCtx.Time)
	}

	if signingCtx.ClockOffset != clockOffset {
		c.inner.ClockOffset = signingCtx.ClockOffset
	}

	return output, err
}