func (qss *QingStorSigner) BuildStringToSign(request *http.Request) (string, error) {
	logger := log.FromContext(request.Context())
	date := request.Header.Get("Date")
	if request.Header.Get("X-QS-Date") != "" {
		date = ""
	}
	stringToSign := fmt.Sprintf(
		"%s\n%s\n%s\n%s\n",
		request.Method,
		request.Header.Get("Content-MD5"),
		request.Header.Get("Content-Type"),
		date,
	)
	stringToSign += qss.buildCanonicalizedHeaders(request)
	canonicalizedResource, err := qss.buildCanonicalizedResource(request)
	if err != nil {
		return "", err
	}
	stringToSign += canonicalizedResource
	logger.Debug("build string to sign",
		zap.String("string", stringToSign),
		zap.Int64("date", convert.StringToTimestamp(request.Header.Get("Date"), convert.RFC822)),
	)
	return stringToSign, nil
}
BuildStringToSign build the string to sign.
package signer
import (
	"crypto/hmac"
	"crypto/sha256"
	"encoding/base64"
	"fmt"
	"net/http"
	"sort"
	"strings"
	"github.com/pengsrc/go-shared/convert"
	"go.uber.org/zap"
	"github.com/qingstor/qingstor-sdk-go/v4/log"
	"github.com/qingstor/qingstor-sdk-go/v4/request/errors"
	"github.com/qingstor/qingstor-sdk-go/v4/utils"
)
type QingStorSigner struct {
	AccessKeyID            string
	SecretAccessKey        string
	EnableVirtualHostStyle bool
}
func (qss *QingStorSigner) WriteSignature(request *http.Request) error {
	authorization, err := qss.BuildSignature(request)
	if err != nil {
		return err
	}
	request.Header.Set("Authorization", authorization)
	return nil
}
func (qss *QingStorSigner) WriteQuerySignature(request *http.Request, expires int) error {
	query, err := qss.BuildQuerySignature(request, expires)
	if err != nil {
		return err
	}
	if request.URL.RawQuery != "" {
		query = "?" + request.URL.RawQuery + "&" + query
	} else {
		query = "?" + query
	}
	newRequest, err := http.NewRequest(request.Method,
		request.URL.Scheme+"://"+request.URL.Host+utils.URLQueryEscape(request.URL.Path)+query, nil)
	if err != nil {
		return errors.NewSDKError(
			errors.WithAction("new http request in WriteQuerySignature"),
			errors.WithError(err),
		)
	}
	request.URL = newRequest.URL
	return nil
}
func (qss *QingStorSigner) BuildSignature(request *http.Request) (string, error) {
	logger := log.FromContext(request.Context())
	stringToSign, err := qss.BuildStringToSign(request)
	if err != nil {
		return "", err
	}
	h := hmac.New(sha256.New, []byte(qss.SecretAccessKey))
	h.Write([]byte(stringToSign))
	signature := strings.TrimSpace(base64.StdEncoding.EncodeToString(h.Sum(nil)))
	authorization := "QS " + qss.AccessKeyID + ":" + signature
	logger.Debug("build signature",
		zap.String("qs_authorization", authorization),
		zap.Int64("date", convert.StringToTimestamp(request.Header.Get("Date"), convert.RFC822)),
	)
	return authorization, nil
}
func (qss *QingStorSigner) BuildQuerySignature(request *http.Request, expires int) (string, error) {
	logger := log.FromContext(request.Context())
	stringToSign, err := qss.BuildQueryStringToSign(request, expires)
	if err != nil {
		return "", err
	}
	h := hmac.New(sha256.New, []byte(qss.SecretAccessKey))
	h.Write([]byte(stringToSign))
	signature := strings.TrimSpace(base64.StdEncoding.EncodeToString(h.Sum(nil)))
	signature = utils.URLQueryEscape(signature)
	query := fmt.Sprintf(
		"access_key_id=%s&expires=%d&signature=%s",
		qss.AccessKeyID, expires, signature,
	)
	logger.Debug("build query signature",
		zap.String("signature", query),
		zap.Int64("date", convert.StringToTimestamp(request.Header.Get("Date"), convert.RFC822)),
	)
	return query, nil
}