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
}