alibabacloud-gateway-fc/util/golang/client/client.go (224 lines of code) (raw):

// This file is auto-generated, don't edit it. Thanks. package client import ( "bytes" "crypto/hmac" "crypto/md5" "crypto/sha256" "encoding/base64" "encoding/hex" "fmt" "io" "io/ioutil" "net/http" "sort" "strings" "time" "github.com/alibabacloud-go/tea/tea" credential "github.com/aliyun/credentials-go/credentials" "github.com/pkg/errors" ) const ( // HTTPHeaderContentMD5 key in request headers HTTPHeaderContentMD5 = "Content-MD5" // HTTPHeaderPrefix key prefix in request headers HTTPHeaderPrefix = "x-fc-" // HTTPHeaderDate key in request headers HTTPHeaderDate = "Date" // AuthQueryKeyExpires key in request headers AuthQueryKeyExpires = "x-fc-expires" // HTTPHeaderContentType key in request headers HTTPHeaderContentType = "Content-Type" // HTTPHeaderAuthorization key in request headers HTTPHeaderAuthorization = "Authorization" // HTTPHeaderSecurityToken key in request headers HTTPHeaderSecurityToken = "x-fc-security-token" ) type Client struct { Credential credential.Credential } func NewClient(cred credential.Credential) (*Client, error) { client := new(Client) err := client.Init(cred) return client, err } func (client *Client) Init(cred credential.Credential) (_err error) { client.Credential = cred return nil } func TeeReader(r io.Reader, w io.Writer) io.Reader { return &teeReader{r, w} } type teeReader struct { r io.Reader w io.Writer } func (t *teeReader) Read(p []byte) (n int, err error) { n, err = t.r.Read(p) if n > 0 { if n, err := t.w.Write(p[:n]); err != nil { return n, err } } return } // InvokeHTTPTrigger invoke a http trigger func (client *Client) InvokeHTTPTrigger(url *string, method *string, body []byte, headers *http.Header) (_result *http.Response, _err error) { req, err := client.BuildHTTPRequest(url, method, body, headers) if err != nil { return nil, err } return client.SendHTTPRequestWithAuthorization(req) } // InvokeAnonymousHTTPTrigger invoke an anonymous http trigger func (client *Client) InvokeAnonymousHTTPTrigger(url *string, method *string, body []byte, headers *http.Header) (_result *http.Response, _err error) { req, err := client.BuildHTTPRequest(url, method, body, headers) if err != nil { return nil, err } return client.SendHTTPRequest(req) } func (client *Client) SendHTTPRequestWithAuthorization(req *http.Request) (_result *http.Response, _err error) { signedRequest, err := client.SignRequest(req) if err != nil { return nil, err } return client.SendHTTPRequest(signedRequest) } func (client *Client) SendHTTPRequest(req *http.Request) (_result *http.Response, _err error) { res, err := http.DefaultClient.Do(req) if err != nil { return nil, err } return res, nil } func (client *Client) SignRequest(req *http.Request) (_result *http.Request, _err error) { var ( contentMD5 = "" err error ) // CONTENT-MD5 if req.Body != nil { bodyNew := bytes.NewBuffer([]byte{}) tee := TeeReader(req.Body, bodyNew) contentMD5, err = md5Digest(tee) if err != nil { return nil, err } req.Body = ioutil.NopCloser(bodyNew) } return client.SignRequestWithContentMD5(req, tea.String(contentMD5)) } func (client *Client) SignRequestWithContentMD5(req *http.Request, contentMD5 *string) (_result *http.Request, _err error) { headerParams := make(map[string]string) req.Header.Set(HTTPHeaderDate, time.Now().UTC().Format(http.TimeFormat)) if len(tea.StringValue(contentMD5)) != 0 { req.Header.Set(HTTPHeaderContentMD5, tea.StringValue(contentMD5)) } if req.Header != nil { for k, _ := range req.Header { headerParams[k] = req.Header.Get(k) } } // Canonicalized pathWithQuery := req.URL.Path params := req.URL.Query() pathWithQuery = getSignResourceWithQueries(req.URL.Path, params) // Build Authorization header accessKeyId, _ := client.Credential.GetAccessKeyId() accessKeySecret, _ := client.Credential.GetAccessKeySecret() securityToken, _ := client.Credential.GetSecurityToken() if securityToken != nil && len(*securityToken) != 0 { req.Header.Set(HTTPHeaderSecurityToken, tea.StringValue(securityToken)) headerParams[HTTPHeaderSecurityToken] = tea.StringValue(securityToken) } authStr := getAuthString(tea.StringValue(accessKeyId), tea.StringValue(accessKeySecret), req.Method, headerParams, pathWithQuery) req.Header.Set(HTTPHeaderAuthorization, authStr) return req, nil } func (client *Client) BuildHTTPRequest(url *string, method *string, body []byte, headers *http.Header) (_result *http.Request, _err error) { res, err := http.NewRequest(tea.StringValue(method), tea.StringValue(url), bytes.NewReader(body)) if err != nil { return nil, err } if headers != nil && len(*headers) != 0 { res.Header = *headers } return res, nil } func md5Digest(reader io.Reader) (string, error) { ctx := md5.New() buffer := make([]byte, 8*1024) for { if c, err := reader.Read(buffer); err == nil { ctx.Write(buffer[:c]) } else if err == io.EOF { break } else { return "", errors.Wrapf(err, "failed to read from reader") } } return hex.EncodeToString(ctx.Sum(nil)), nil } func getAuthString(accessKeyID string, accessKeySecret string, method string, header map[string]string, pathWithQuerys string) string { return "FC " + accessKeyID + ":" + getSignature(accessKeySecret, method, header, pathWithQuerys) } type headers struct { Keys []string Vals []string } func (h *headers) Len() int { return len(h.Vals) } func (h *headers) Less(i, j int) bool { return bytes.Compare([]byte(h.Keys[i]), []byte(h.Keys[j])) < 0 } func (h *headers) Swap(i, j int) { h.Vals[i], h.Vals[j] = h.Vals[j], h.Vals[i] h.Keys[i], h.Keys[j] = h.Keys[j], h.Keys[i] } // GetSignature calculate user's signature func getSignature(key string, method string, req map[string]string, path string) string { header := &headers{} lowerKeyHeaders := map[string]string{} for k, v := range req { lowerKey := strings.ToLower(k) if strings.HasPrefix(lowerKey, HTTPHeaderPrefix) { header.Keys = append(header.Keys, lowerKey) header.Vals = append(header.Vals, v) } lowerKeyHeaders[lowerKey] = v } sort.Sort(header) fcHeaders := "" for i := range header.Keys { fcHeaders += header.Keys[i] + ":" + header.Vals[i] + "\n" } date := req[HTTPHeaderDate] if expires, ok := getExpiresFromURLQueries(path); ok { date = expires } signStr := method + "\n" + lowerKeyHeaders[strings.ToLower(HTTPHeaderContentMD5)] + "\n" + lowerKeyHeaders[strings.ToLower(HTTPHeaderContentType)] + "\n" + date + "\n" + fcHeaders + path h := hmac.New(sha256.New, []byte(key)) _, _ = io.WriteString(h, signStr) signedStr := base64.StdEncoding.EncodeToString(h.Sum(nil)) return signedStr } func getExpiresFromURLQueries(path string) (string, bool) { originItems := strings.Split(path, "\n") queriesUnescaped := map[string]string{} for _, item := range originItems[1:] { kvPair := strings.Split(item, "=") if len(kvPair) > 1 { queriesUnescaped[kvPair[0]] = kvPair[1] } } expires, ok := queriesUnescaped[AuthQueryKeyExpires] return expires, ok } func getSignResourceWithQueries(path string, queries map[string][]string) string { if len(path) == 0 { path = "/" } return path + "\n" + getSignQueries(queries) } func getSignQueries(queries map[string][]string) string { paramsList := []string{} for key, values := range queries { if len(values) == 0 { paramsList = append(paramsList, key) continue } for _, v := range values { paramsList = append(paramsList, fmt.Sprintf("%s=%s", key, v)) } } sort.Strings(paramsList) return strings.Join(paramsList, "\n") }