rclone/vendor/github.com/yunify/qingstor-sdk-go/request/builder/qingstor.go

164 lines
4.8 KiB
Go

// +-------------------------------------------------------------------------
// | Copyright (C) 2016 Yunify, Inc.
// +-------------------------------------------------------------------------
// | Licensed under the Apache License, Version 2.0 (the "License");
// | you may not use this work except in compliance with the License.
// | You may obtain a copy of the License in the LICENSE file, or at:
// |
// | http://www.apache.org/licenses/LICENSE-2.0
// |
// | Unless required by applicable law or agreed to in writing, software
// | distributed under the License is distributed on an "AS IS" BASIS,
// | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// | See the License for the specific language governing permissions and
// | limitations under the License.
// +-------------------------------------------------------------------------
package builder
import (
"bytes"
"crypto/md5"
"encoding/base64"
"fmt"
"io/ioutil"
"net/http"
"net/url"
"reflect"
"regexp"
"runtime"
"strconv"
"strings"
"github.com/pengsrc/go-shared/convert"
"github.com/yunify/qingstor-sdk-go"
"github.com/yunify/qingstor-sdk-go/logger"
"github.com/yunify/qingstor-sdk-go/request/data"
"github.com/yunify/qingstor-sdk-go/utils"
)
// QingStorBuilder is the request builder for QingStor service.
type QingStorBuilder struct {
baseBuilder *BaseBuilder
}
// BuildHTTPRequest builds http request with an operation and an input.
func (qb *QingStorBuilder) BuildHTTPRequest(o *data.Operation, i *reflect.Value) (*http.Request, error) {
qb.baseBuilder = &BaseBuilder{}
qb.baseBuilder.operation = o
qb.baseBuilder.input = i
_, err := qb.baseBuilder.parse()
if err != nil {
return nil, err
}
err = qb.parseURL()
if err != nil {
return nil, err
}
httpRequest, err := http.NewRequest(qb.baseBuilder.operation.RequestMethod,
qb.baseBuilder.parsedURL, qb.baseBuilder.parsedBody)
if err != nil {
return nil, err
}
err = qb.baseBuilder.setupHeaders(httpRequest)
if err != nil {
return nil, err
}
err = qb.setupHeaders(httpRequest)
if err != nil {
return nil, err
}
logger.Infof(nil, fmt.Sprintf(
"Built QingStor request: [%d] %s",
convert.StringToTimestamp(httpRequest.Header.Get("Date"), convert.RFC822),
httpRequest.URL.String(),
))
logger.Infof(nil, fmt.Sprintf(
"QingStor request headers: [%d] %s",
convert.StringToTimestamp(httpRequest.Header.Get("Date"), convert.RFC822),
fmt.Sprint(httpRequest.Header),
))
if qb.baseBuilder.parsedBodyString != "" {
logger.Infof(nil, fmt.Sprintf(
"QingStor request body string: [%d] %s",
convert.StringToTimestamp(httpRequest.Header.Get("Date"), convert.RFC822),
qb.baseBuilder.parsedBodyString,
))
}
return httpRequest, nil
}
func (qb *QingStorBuilder) parseURL() error {
config := qb.baseBuilder.operation.Config
zone := (*qb.baseBuilder.parsedProperties)["zone"]
port := strconv.Itoa(config.Port)
endpoint := config.Protocol + "://" + config.Host + ":" + port
if zone != "" {
endpoint = config.Protocol + "://" + zone + "." + config.Host + ":" + port
}
requestURI := qb.baseBuilder.operation.RequestURI
for key, value := range *qb.baseBuilder.parsedProperties {
endpoint = strings.Replace(endpoint, "<"+key+">", utils.URLQueryEscape(value), -1)
requestURI = strings.Replace(requestURI, "<"+key+">", utils.URLQueryEscape(value), -1)
}
requestURI = regexp.MustCompile(`/+`).ReplaceAllString(requestURI, "/")
requestURL, err := url.Parse(endpoint + requestURI)
if err != nil {
return err
}
if qb.baseBuilder.parsedQuery != nil {
queryValue := requestURL.Query()
for key, value := range *qb.baseBuilder.parsedQuery {
queryValue.Set(key, value)
}
requestURL.RawQuery = queryValue.Encode()
}
qb.baseBuilder.parsedURL = requestURL.String()
return nil
}
func (qb *QingStorBuilder) setupHeaders(httpRequest *http.Request) error {
if httpRequest.Header.Get("User-Agent") == "" {
version := fmt.Sprintf(`Go v%s`, strings.Replace(runtime.Version(), "go", "", -1))
system := fmt.Sprintf(`%s_%s_%s`, runtime.GOOS, runtime.GOARCH, runtime.Compiler)
ua := fmt.Sprintf(`qingstor-sdk-go/%s (%s; %s)`, sdk.Version, version, system)
if qb.baseBuilder.operation.Config.AdditionalUserAgent != "" {
ua = fmt.Sprintf(`%s %s`, ua, qb.baseBuilder.operation.Config.AdditionalUserAgent)
}
httpRequest.Header.Set("User-Agent", ua)
}
if s := httpRequest.Header.Get("X-QS-Fetch-Source"); s != "" {
u, err := url.Parse(s)
if err != nil {
return fmt.Errorf("invalid HTTP header value: %s", s)
}
httpRequest.Header.Set("X-QS-Fetch-Source", u.String())
}
if qb.baseBuilder.operation.APIName == "Delete Multiple Objects" {
buffer := &bytes.Buffer{}
buffer.ReadFrom(httpRequest.Body)
httpRequest.Body = ioutil.NopCloser(bytes.NewReader(buffer.Bytes()))
md5Value := md5.Sum(buffer.Bytes())
httpRequest.Header.Set("Content-MD5", base64.StdEncoding.EncodeToString(md5Value[:]))
}
return nil
}