github.com/alibabacloud-go/tea@v1.3.10/tea/tea.go (about)

     1  package tea
     2  
     3  import (
     4  	"bytes"
     5  	"context"
     6  	"crypto/tls"
     7  	"crypto/x509"
     8  	"encoding/base64"
     9  	"encoding/json"
    10  	"errors"
    11  	"fmt"
    12  	"io"
    13  	"math"
    14  	"math/rand"
    15  	"net"
    16  	"net/http"
    17  	"net/url"
    18  	"os"
    19  	"reflect"
    20  	"regexp"
    21  	"strconv"
    22  	"strings"
    23  	"sync"
    24  	"time"
    25  
    26  	"github.com/alibabacloud-go/debug/debug"
    27  	"github.com/alibabacloud-go/tea/utils"
    28  
    29  	"golang.org/x/net/proxy"
    30  )
    31  
    32  var debugLog = debug.Init("tea")
    33  
    34  type HttpRequest interface {
    35  }
    36  
    37  type HttpResponse interface {
    38  }
    39  
    40  type HttpClient interface {
    41  	Call(request *http.Request, transport *http.Transport) (response *http.Response, err error)
    42  }
    43  
    44  type teaClient struct {
    45  	sync.Mutex
    46  	httpClient *http.Client
    47  	ifInit     bool
    48  }
    49  
    50  func (client *teaClient) Call(request *http.Request, transport *http.Transport) (response *http.Response, err error) {
    51  	response, err = client.httpClient.Do(request)
    52  	return
    53  }
    54  
    55  var hookDo = func(fn func(req *http.Request, transport *http.Transport) (*http.Response, error)) func(req *http.Request, transport *http.Transport) (*http.Response, error) {
    56  	return fn
    57  }
    58  
    59  var basicTypes = []string{
    60  	"int", "int16", "int64", "int32", "float32", "float64", "string", "bool", "uint64", "uint32", "uint16",
    61  }
    62  
    63  // Verify whether the parameters meet the requirements
    64  var validateParams = []string{"require", "pattern", "maxLength", "minLength", "maximum", "minimum", "maxItems", "minItems"}
    65  
    66  // CastError is used for cast type fails
    67  type CastError struct {
    68  	Message *string
    69  }
    70  
    71  // Request is used wrap http request
    72  type Request struct {
    73  	Protocol *string
    74  	Port     *int
    75  	Method   *string
    76  	Pathname *string
    77  	Domain   *string
    78  	Headers  map[string]*string
    79  	Query    map[string]*string
    80  	Body     io.Reader
    81  }
    82  
    83  // Response is use d wrap http response
    84  type Response struct {
    85  	Body          io.ReadCloser
    86  	StatusCode    *int
    87  	StatusMessage *string
    88  	Headers       map[string]*string
    89  }
    90  
    91  // SDKError struct is used save error code and message
    92  type SDKError struct {
    93  	Code               *string
    94  	StatusCode         *int
    95  	Message            *string
    96  	Data               *string
    97  	Stack              *string
    98  	errMsg             *string
    99  	Description        *string
   100  	AccessDeniedDetail map[string]interface{}
   101  }
   102  
   103  // RuntimeObject is used for converting http configuration
   104  type RuntimeObject struct {
   105  	IgnoreSSL      *bool                  `json:"ignoreSSL" xml:"ignoreSSL"`
   106  	ReadTimeout    *int                   `json:"readTimeout" xml:"readTimeout"`
   107  	ConnectTimeout *int                   `json:"connectTimeout" xml:"connectTimeout"`
   108  	LocalAddr      *string                `json:"localAddr" xml:"localAddr"`
   109  	HttpProxy      *string                `json:"httpProxy" xml:"httpProxy"`
   110  	HttpsProxy     *string                `json:"httpsProxy" xml:"httpsProxy"`
   111  	NoProxy        *string                `json:"noProxy" xml:"noProxy"`
   112  	MaxIdleConns   *int                   `json:"maxIdleConns" xml:"maxIdleConns"`
   113  	Key            *string                `json:"key" xml:"key"`
   114  	Cert           *string                `json:"cert" xml:"cert"`
   115  	CA             *string                `json:"ca" xml:"ca"`
   116  	Socks5Proxy    *string                `json:"socks5Proxy" xml:"socks5Proxy"`
   117  	Socks5NetWork  *string                `json:"socks5NetWork" xml:"socks5NetWork"`
   118  	Listener       utils.ProgressListener `json:"listener" xml:"listener"`
   119  	Tracker        *utils.ReaderTracker   `json:"tracker" xml:"tracker"`
   120  	Logger         *utils.Logger          `json:"logger" xml:"logger"`
   121  	HttpClient
   122  }
   123  
   124  var clientPool = &sync.Map{}
   125  
   126  func (r *RuntimeObject) getClientTag(domain string) string {
   127  	return strconv.FormatBool(BoolValue(r.IgnoreSSL)) + strconv.Itoa(IntValue(r.ReadTimeout)) +
   128  		strconv.Itoa(IntValue(r.ConnectTimeout)) + StringValue(r.LocalAddr) + StringValue(r.HttpProxy) +
   129  		StringValue(r.HttpsProxy) + StringValue(r.NoProxy) + StringValue(r.Socks5Proxy) + StringValue(r.Socks5NetWork) + domain
   130  }
   131  
   132  // NewRuntimeObject is used for shortly create runtime object
   133  func NewRuntimeObject(runtime map[string]interface{}) *RuntimeObject {
   134  	if runtime == nil {
   135  		return &RuntimeObject{}
   136  	}
   137  
   138  	runtimeObject := &RuntimeObject{
   139  		IgnoreSSL:      TransInterfaceToBool(runtime["ignoreSSL"]),
   140  		ReadTimeout:    TransInterfaceToInt(runtime["readTimeout"]),
   141  		ConnectTimeout: TransInterfaceToInt(runtime["connectTimeout"]),
   142  		LocalAddr:      TransInterfaceToString(runtime["localAddr"]),
   143  		HttpProxy:      TransInterfaceToString(runtime["httpProxy"]),
   144  		HttpsProxy:     TransInterfaceToString(runtime["httpsProxy"]),
   145  		NoProxy:        TransInterfaceToString(runtime["noProxy"]),
   146  		MaxIdleConns:   TransInterfaceToInt(runtime["maxIdleConns"]),
   147  		Socks5Proxy:    TransInterfaceToString(runtime["socks5Proxy"]),
   148  		Socks5NetWork:  TransInterfaceToString(runtime["socks5NetWork"]),
   149  		Key:            TransInterfaceToString(runtime["key"]),
   150  		Cert:           TransInterfaceToString(runtime["cert"]),
   151  		CA:             TransInterfaceToString(runtime["ca"]),
   152  	}
   153  	if runtime["listener"] != nil {
   154  		runtimeObject.Listener = runtime["listener"].(utils.ProgressListener)
   155  	}
   156  	if runtime["tracker"] != nil {
   157  		runtimeObject.Tracker = runtime["tracker"].(*utils.ReaderTracker)
   158  	}
   159  	if runtime["logger"] != nil {
   160  		runtimeObject.Logger = runtime["logger"].(*utils.Logger)
   161  	}
   162  	if runtime["httpClient"] != nil {
   163  		runtimeObject.HttpClient = runtime["httpClient"].(HttpClient)
   164  	}
   165  	return runtimeObject
   166  }
   167  
   168  // NewCastError is used for cast type fails
   169  func NewCastError(message *string) (err error) {
   170  	return &CastError{
   171  		Message: message,
   172  	}
   173  }
   174  
   175  // NewRequest is used shortly create Request
   176  func NewRequest() (req *Request) {
   177  	return &Request{
   178  		Headers: map[string]*string{},
   179  		Query:   map[string]*string{},
   180  	}
   181  }
   182  
   183  // NewResponse is create response with http response
   184  func NewResponse(httpResponse *http.Response) (res *Response) {
   185  	res = &Response{}
   186  	res.Body = httpResponse.Body
   187  	res.Headers = make(map[string]*string)
   188  	res.StatusCode = Int(httpResponse.StatusCode)
   189  	res.StatusMessage = String(httpResponse.Status)
   190  	return
   191  }
   192  
   193  // NewSDKError is used for shortly create SDKError object
   194  func NewSDKError(obj map[string]interface{}) *SDKError {
   195  	err := &SDKError{}
   196  	if val, ok := obj["code"].(int); ok {
   197  		err.Code = String(strconv.Itoa(val))
   198  	} else if val, ok := obj["code"].(string); ok {
   199  		err.Code = String(val)
   200  	}
   201  
   202  	if obj["message"] != nil {
   203  		err.Message = String(obj["message"].(string))
   204  	}
   205  	if obj["description"] != nil {
   206  		err.Description = String(obj["description"].(string))
   207  	}
   208  	if detail := obj["accessDeniedDetail"]; detail != nil {
   209  		r := reflect.ValueOf(detail)
   210  		if r.Kind().String() == "map" {
   211  			res := make(map[string]interface{})
   212  			tmp := r.MapKeys()
   213  			for _, key := range tmp {
   214  				res[key.String()] = r.MapIndex(key).Interface()
   215  			}
   216  			err.AccessDeniedDetail = res
   217  		}
   218  	}
   219  	if data := obj["data"]; data != nil {
   220  		r := reflect.ValueOf(data)
   221  		if r.Kind().String() == "map" {
   222  			res := make(map[string]interface{})
   223  			tmp := r.MapKeys()
   224  			for _, key := range tmp {
   225  				res[key.String()] = r.MapIndex(key).Interface()
   226  			}
   227  			if statusCode := res["statusCode"]; statusCode != nil {
   228  				if code, ok := statusCode.(int); ok {
   229  					err.StatusCode = Int(code)
   230  				} else if tmp, ok := statusCode.(string); ok {
   231  					code, err_ := strconv.Atoi(tmp)
   232  					if err_ == nil {
   233  						err.StatusCode = Int(code)
   234  					}
   235  				} else if code, ok := statusCode.(*int); ok {
   236  					err.StatusCode = code
   237  				}
   238  			}
   239  		}
   240  		byt := bytes.NewBuffer([]byte{})
   241  		jsonEncoder := json.NewEncoder(byt)
   242  		jsonEncoder.SetEscapeHTML(false)
   243  		jsonEncoder.Encode(data)
   244  		err.Data = String(string(bytes.TrimSpace(byt.Bytes())))
   245  	}
   246  
   247  	if statusCode, ok := obj["statusCode"].(int); ok {
   248  		err.StatusCode = Int(statusCode)
   249  	} else if status, ok := obj["statusCode"].(string); ok {
   250  		statusCode, err_ := strconv.Atoi(status)
   251  		if err_ == nil {
   252  			err.StatusCode = Int(statusCode)
   253  		}
   254  	}
   255  
   256  	return err
   257  }
   258  
   259  // Set ErrMsg by msg
   260  func (err *SDKError) SetErrMsg(msg string) {
   261  	err.errMsg = String(msg)
   262  }
   263  
   264  func (err *SDKError) Error() string {
   265  	if err.errMsg == nil {
   266  		str := fmt.Sprintf("SDKError:\n   StatusCode: %d\n   Code: %s\n   Message: %s\n   Data: %s\n",
   267  			IntValue(err.StatusCode), StringValue(err.Code), StringValue(err.Message), StringValue(err.Data))
   268  		err.SetErrMsg(str)
   269  	}
   270  	return StringValue(err.errMsg)
   271  }
   272  
   273  // Return message of CastError
   274  func (err *CastError) Error() string {
   275  	return StringValue(err.Message)
   276  }
   277  
   278  // Convert is use convert map[string]interface object to struct
   279  func Convert(in interface{}, out interface{}) error {
   280  	byt, _ := json.Marshal(in)
   281  	decoder := jsonParser.NewDecoder(bytes.NewReader(byt))
   282  	decoder.UseNumber()
   283  	err := decoder.Decode(&out)
   284  	return err
   285  }
   286  
   287  // Recover is used to format error
   288  func Recover(in interface{}) error {
   289  	if in == nil {
   290  		return nil
   291  	}
   292  	return errors.New(fmt.Sprint(in))
   293  }
   294  
   295  // ReadBody is used read response body
   296  func (response *Response) ReadBody() (body []byte, err error) {
   297  	defer response.Body.Close()
   298  	var buffer [512]byte
   299  	result := bytes.NewBuffer(nil)
   300  
   301  	for {
   302  		n, err := response.Body.Read(buffer[0:])
   303  		result.Write(buffer[0:n])
   304  		if err != nil && err == io.EOF {
   305  			break
   306  		} else if err != nil {
   307  			return nil, err
   308  		}
   309  	}
   310  	return result.Bytes(), nil
   311  }
   312  
   313  func getTeaClient(tag string) *teaClient {
   314  	client, ok := clientPool.Load(tag)
   315  	if client == nil && !ok {
   316  		client = &teaClient{
   317  			httpClient: &http.Client{},
   318  			ifInit:     false,
   319  		}
   320  		clientPool.Store(tag, client)
   321  	}
   322  	return client.(*teaClient)
   323  }
   324  
   325  // DoRequest is used send request to server
   326  func DoRequest(request *Request, requestRuntime map[string]interface{}) (response *Response, err error) {
   327  	runtimeObject := NewRuntimeObject(requestRuntime)
   328  	fieldMap := make(map[string]string)
   329  	utils.InitLogMsg(fieldMap)
   330  	defer func() {
   331  		if runtimeObject.Logger != nil {
   332  			runtimeObject.Logger.PrintLog(fieldMap, err)
   333  		}
   334  	}()
   335  	if request.Method == nil {
   336  		request.Method = String("GET")
   337  	}
   338  
   339  	if request.Protocol == nil {
   340  		request.Protocol = String("http")
   341  	} else {
   342  		request.Protocol = String(strings.ToLower(StringValue(request.Protocol)))
   343  	}
   344  
   345  	requestURL := ""
   346  	request.Domain = request.Headers["host"]
   347  	if request.Port != nil {
   348  		request.Domain = String(fmt.Sprintf("%s:%d", StringValue(request.Domain), IntValue(request.Port)))
   349  	}
   350  	requestURL = fmt.Sprintf("%s://%s%s", StringValue(request.Protocol), StringValue(request.Domain), StringValue(request.Pathname))
   351  	queryParams := request.Query
   352  	// sort QueryParams by key
   353  	q := url.Values{}
   354  	for key, value := range queryParams {
   355  		q.Add(key, StringValue(value))
   356  	}
   357  	querystring := q.Encode()
   358  	if len(querystring) > 0 {
   359  		if strings.Contains(requestURL, "?") {
   360  			requestURL = fmt.Sprintf("%s&%s", requestURL, querystring)
   361  		} else {
   362  			requestURL = fmt.Sprintf("%s?%s", requestURL, querystring)
   363  		}
   364  	}
   365  	debugLog("> %s %s", StringValue(request.Method), requestURL)
   366  
   367  	httpRequest, err := http.NewRequest(StringValue(request.Method), requestURL, request.Body)
   368  	if err != nil {
   369  		return
   370  	}
   371  	httpRequest.Host = StringValue(request.Domain)
   372  
   373  	var client HttpClient
   374  	if runtimeObject.HttpClient == nil {
   375  		client = getTeaClient(runtimeObject.getClientTag(StringValue(request.Domain)))
   376  	} else {
   377  		client = runtimeObject.HttpClient
   378  	}
   379  
   380  	trans, err := getHttpTransport(request, runtimeObject)
   381  	if err != nil {
   382  		return
   383  	}
   384  	if defaultClient, ok := client.(*teaClient); ok {
   385  		defaultClient.Lock()
   386  		if !defaultClient.ifInit || defaultClient.httpClient.Transport == nil {
   387  			defaultClient.httpClient.Transport = trans
   388  		}
   389  		defaultClient.httpClient.Timeout = time.Duration(IntValue(runtimeObject.ReadTimeout)) * time.Millisecond
   390  		defaultClient.ifInit = true
   391  		defaultClient.Unlock()
   392  	}
   393  
   394  	for key, value := range request.Headers {
   395  		if value == nil || key == "content-length" {
   396  			continue
   397  		} else if key == "host" {
   398  			httpRequest.Header["Host"] = []string{*value}
   399  			delete(httpRequest.Header, "host")
   400  		} else if key == "user-agent" {
   401  			httpRequest.Header["User-Agent"] = []string{*value}
   402  			delete(httpRequest.Header, "user-agent")
   403  		} else {
   404  			httpRequest.Header[key] = []string{*value}
   405  		}
   406  		debugLog("> %s: %s", key, StringValue(value))
   407  	}
   408  	contentlength, _ := strconv.Atoi(StringValue(request.Headers["content-length"]))
   409  	event := utils.NewProgressEvent(utils.TransferStartedEvent, 0, int64(contentlength), 0)
   410  	utils.PublishProgress(runtimeObject.Listener, event)
   411  
   412  	putMsgToMap(fieldMap, httpRequest)
   413  	startTime := time.Now()
   414  	fieldMap["{start_time}"] = startTime.Format("2006-01-02 15:04:05")
   415  	res, err := hookDo(client.Call)(httpRequest, trans)
   416  	fieldMap["{cost}"] = time.Since(startTime).String()
   417  	completedBytes := int64(0)
   418  	if runtimeObject.Tracker != nil {
   419  		completedBytes = runtimeObject.Tracker.CompletedBytes
   420  	}
   421  	if err != nil {
   422  		event = utils.NewProgressEvent(utils.TransferFailedEvent, completedBytes, int64(contentlength), 0)
   423  		utils.PublishProgress(runtimeObject.Listener, event)
   424  		return
   425  	}
   426  
   427  	event = utils.NewProgressEvent(utils.TransferCompletedEvent, completedBytes, int64(contentlength), 0)
   428  	utils.PublishProgress(runtimeObject.Listener, event)
   429  
   430  	response = NewResponse(res)
   431  	fieldMap["{code}"] = strconv.Itoa(res.StatusCode)
   432  	fieldMap["{res_headers}"] = transToString(res.Header)
   433  	debugLog("< HTTP/1.1 %s", res.Status)
   434  	for key, value := range res.Header {
   435  		debugLog("< %s: %s", key, strings.Join(value, ""))
   436  		if len(value) != 0 {
   437  			response.Headers[strings.ToLower(key)] = String(value[0])
   438  		}
   439  	}
   440  	return
   441  }
   442  
   443  func getHttpTransport(req *Request, runtime *RuntimeObject) (*http.Transport, error) {
   444  	trans := new(http.Transport)
   445  	httpProxy, err := getHttpProxy(StringValue(req.Protocol), StringValue(req.Domain), runtime)
   446  	if err != nil {
   447  		return nil, err
   448  	}
   449  	if strings.ToLower(*req.Protocol) == "https" {
   450  		if BoolValue(runtime.IgnoreSSL) != true {
   451  			trans.TLSClientConfig = &tls.Config{
   452  				InsecureSkipVerify: false,
   453  			}
   454  			if runtime.Key != nil && runtime.Cert != nil && StringValue(runtime.Key) != "" && StringValue(runtime.Cert) != "" {
   455  				cert, err := tls.X509KeyPair([]byte(StringValue(runtime.Cert)), []byte(StringValue(runtime.Key)))
   456  				if err != nil {
   457  					return nil, err
   458  				}
   459  				trans.TLSClientConfig.Certificates = []tls.Certificate{cert}
   460  			}
   461  			if runtime.CA != nil && StringValue(runtime.CA) != "" {
   462  				clientCertPool := x509.NewCertPool()
   463  				ok := clientCertPool.AppendCertsFromPEM([]byte(StringValue(runtime.CA)))
   464  				if !ok {
   465  					return nil, errors.New("Failed to parse root certificate")
   466  				}
   467  				trans.TLSClientConfig.RootCAs = clientCertPool
   468  			}
   469  		} else {
   470  			trans.TLSClientConfig = &tls.Config{
   471  				InsecureSkipVerify: true,
   472  			}
   473  		}
   474  	}
   475  	if httpProxy != nil {
   476  		trans.Proxy = http.ProxyURL(httpProxy)
   477  		if httpProxy.User != nil {
   478  			password, _ := httpProxy.User.Password()
   479  			auth := httpProxy.User.Username() + ":" + password
   480  			basic := "Basic " + base64.StdEncoding.EncodeToString([]byte(auth))
   481  			req.Headers["Proxy-Authorization"] = String(basic)
   482  		}
   483  	}
   484  	if runtime.Socks5Proxy != nil && StringValue(runtime.Socks5Proxy) != "" {
   485  		socks5Proxy, err := getSocks5Proxy(runtime)
   486  		if err != nil {
   487  			return nil, err
   488  		}
   489  		if socks5Proxy != nil {
   490  			var auth *proxy.Auth
   491  			if socks5Proxy.User != nil {
   492  				password, _ := socks5Proxy.User.Password()
   493  				auth = &proxy.Auth{
   494  					User:     socks5Proxy.User.Username(),
   495  					Password: password,
   496  				}
   497  			}
   498  			dialer, err := proxy.SOCKS5(strings.ToLower(StringValue(runtime.Socks5NetWork)), socks5Proxy.String(), auth,
   499  				&net.Dialer{
   500  					Timeout:   time.Duration(IntValue(runtime.ConnectTimeout)) * time.Millisecond,
   501  					DualStack: true,
   502  					LocalAddr: getLocalAddr(StringValue(runtime.LocalAddr)),
   503  				})
   504  			if err != nil {
   505  				return nil, err
   506  			}
   507  			trans.Dial = dialer.Dial
   508  		}
   509  	} else {
   510  		trans.DialContext = setDialContext(runtime)
   511  	}
   512  	if runtime.MaxIdleConns != nil && *runtime.MaxIdleConns > 0 {
   513  		trans.MaxIdleConns = IntValue(runtime.MaxIdleConns)
   514  		trans.MaxIdleConnsPerHost = IntValue(runtime.MaxIdleConns)
   515  	}
   516  	return trans, nil
   517  }
   518  
   519  func transToString(object interface{}) string {
   520  	byt, _ := json.Marshal(object)
   521  	return string(byt)
   522  }
   523  
   524  func putMsgToMap(fieldMap map[string]string, request *http.Request) {
   525  	fieldMap["{host}"] = request.Host
   526  	fieldMap["{method}"] = request.Method
   527  	fieldMap["{uri}"] = request.URL.RequestURI()
   528  	fieldMap["{pid}"] = strconv.Itoa(os.Getpid())
   529  	fieldMap["{version}"] = strings.Split(request.Proto, "/")[1]
   530  	hostname, _ := os.Hostname()
   531  	fieldMap["{hostname}"] = hostname
   532  	fieldMap["{req_headers}"] = transToString(request.Header)
   533  	fieldMap["{target}"] = request.URL.Path + request.URL.RawQuery
   534  }
   535  
   536  func getNoProxy(protocol string, runtime *RuntimeObject) []string {
   537  	var urls []string
   538  	if runtime.NoProxy != nil && StringValue(runtime.NoProxy) != "" {
   539  		urls = strings.Split(StringValue(runtime.NoProxy), ",")
   540  	} else if rawurl := os.Getenv("NO_PROXY"); rawurl != "" {
   541  		urls = strings.Split(rawurl, ",")
   542  	} else if rawurl := os.Getenv("no_proxy"); rawurl != "" {
   543  		urls = strings.Split(rawurl, ",")
   544  	}
   545  
   546  	return urls
   547  }
   548  
   549  func ToReader(obj interface{}) io.Reader {
   550  	switch obj.(type) {
   551  	case *string:
   552  		tmp := obj.(*string)
   553  		return strings.NewReader(StringValue(tmp))
   554  	case []byte:
   555  		return strings.NewReader(string(obj.([]byte)))
   556  	case io.Reader:
   557  		return obj.(io.Reader)
   558  	default:
   559  		panic("Invalid Body. Please set a valid Body.")
   560  	}
   561  }
   562  
   563  func ToString(val interface{}) string {
   564  	return fmt.Sprintf("%v", val)
   565  }
   566  
   567  func getHttpProxy(protocol, host string, runtime *RuntimeObject) (proxy *url.URL, err error) {
   568  	urls := getNoProxy(protocol, runtime)
   569  	for _, url := range urls {
   570  		if url == host {
   571  			return nil, nil
   572  		}
   573  	}
   574  	if protocol == "https" {
   575  		if runtime.HttpsProxy != nil && StringValue(runtime.HttpsProxy) != "" {
   576  			proxy, err = url.Parse(StringValue(runtime.HttpsProxy))
   577  		} else if rawurl := os.Getenv("HTTPS_PROXY"); rawurl != "" {
   578  			proxy, err = url.Parse(rawurl)
   579  		} else if rawurl := os.Getenv("https_proxy"); rawurl != "" {
   580  			proxy, err = url.Parse(rawurl)
   581  		}
   582  	} else {
   583  		if runtime.HttpProxy != nil && StringValue(runtime.HttpProxy) != "" {
   584  			proxy, err = url.Parse(StringValue(runtime.HttpProxy))
   585  		} else if rawurl := os.Getenv("HTTP_PROXY"); rawurl != "" {
   586  			proxy, err = url.Parse(rawurl)
   587  		} else if rawurl := os.Getenv("http_proxy"); rawurl != "" {
   588  			proxy, err = url.Parse(rawurl)
   589  		}
   590  	}
   591  
   592  	return proxy, err
   593  }
   594  
   595  func getSocks5Proxy(runtime *RuntimeObject) (proxy *url.URL, err error) {
   596  	if runtime.Socks5Proxy != nil && StringValue(runtime.Socks5Proxy) != "" {
   597  		proxy, err = url.Parse(StringValue(runtime.Socks5Proxy))
   598  	}
   599  	return proxy, err
   600  }
   601  
   602  func getLocalAddr(localAddr string) (addr *net.TCPAddr) {
   603  	if localAddr != "" {
   604  		addr = &net.TCPAddr{
   605  			IP: []byte(localAddr),
   606  		}
   607  	}
   608  	return addr
   609  }
   610  
   611  func setDialContext(runtime *RuntimeObject) func(cxt context.Context, net, addr string) (c net.Conn, err error) {
   612  	return func(ctx context.Context, network, address string) (net.Conn, error) {
   613  		if runtime.LocalAddr != nil && StringValue(runtime.LocalAddr) != "" {
   614  			netAddr := &net.TCPAddr{
   615  				IP: []byte(StringValue(runtime.LocalAddr)),
   616  			}
   617  			return (&net.Dialer{
   618  				Timeout:   time.Duration(IntValue(runtime.ConnectTimeout)) * time.Second,
   619  				DualStack: true,
   620  				LocalAddr: netAddr,
   621  			}).DialContext(ctx, network, address)
   622  		}
   623  		return (&net.Dialer{
   624  			Timeout:   time.Duration(IntValue(runtime.ConnectTimeout)) * time.Second,
   625  			DualStack: true,
   626  		}).DialContext(ctx, network, address)
   627  	}
   628  }
   629  
   630  func ToObject(obj interface{}) map[string]interface{} {
   631  	result := make(map[string]interface{})
   632  	byt, _ := json.Marshal(obj)
   633  	err := json.Unmarshal(byt, &result)
   634  	if err != nil {
   635  		return nil
   636  	}
   637  	return result
   638  }
   639  
   640  func AllowRetry(retry interface{}, retryTimes *int) *bool {
   641  	if IntValue(retryTimes) == 0 {
   642  		return Bool(true)
   643  	}
   644  	retryMap, ok := retry.(map[string]interface{})
   645  	if !ok {
   646  		return Bool(false)
   647  	}
   648  	retryable, ok := retryMap["retryable"].(bool)
   649  	if !ok || !retryable {
   650  		return Bool(false)
   651  	}
   652  
   653  	maxAttempts, ok := retryMap["maxAttempts"].(int)
   654  	if !ok || maxAttempts < IntValue(retryTimes) {
   655  		return Bool(false)
   656  	}
   657  	return Bool(true)
   658  }
   659  
   660  func Merge(args ...interface{}) map[string]*string {
   661  	finalArg := make(map[string]*string)
   662  	for _, obj := range args {
   663  		switch obj.(type) {
   664  		case map[string]*string:
   665  			arg := obj.(map[string]*string)
   666  			for key, value := range arg {
   667  				if value != nil {
   668  					finalArg[key] = value
   669  				}
   670  			}
   671  		default:
   672  			byt, _ := json.Marshal(obj)
   673  			arg := make(map[string]string)
   674  			err := json.Unmarshal(byt, &arg)
   675  			if err != nil {
   676  				return finalArg
   677  			}
   678  			for key, value := range arg {
   679  				if value != "" {
   680  					finalArg[key] = String(value)
   681  				}
   682  			}
   683  		}
   684  	}
   685  
   686  	return finalArg
   687  }
   688  
   689  func isNil(a interface{}) bool {
   690  	defer func() {
   691  		recover()
   692  	}()
   693  	vi := reflect.ValueOf(a)
   694  	return vi.IsNil()
   695  }
   696  
   697  func ToMap(args ...interface{}) map[string]interface{} {
   698  	isNotNil := false
   699  	finalArg := make(map[string]interface{})
   700  	for _, obj := range args {
   701  		if obj == nil {
   702  			continue
   703  		}
   704  
   705  		if isNil(obj) {
   706  			continue
   707  		}
   708  		isNotNil = true
   709  
   710  		switch obj.(type) {
   711  		case map[string]*string:
   712  			arg := obj.(map[string]*string)
   713  			for key, value := range arg {
   714  				if value != nil {
   715  					finalArg[key] = StringValue(value)
   716  				}
   717  			}
   718  		case map[string]interface{}:
   719  			arg := obj.(map[string]interface{})
   720  			for key, value := range arg {
   721  				if value != nil {
   722  					finalArg[key] = value
   723  				}
   724  			}
   725  		case *string:
   726  			str := obj.(*string)
   727  			arg := make(map[string]interface{})
   728  			err := json.Unmarshal([]byte(StringValue(str)), &arg)
   729  			if err == nil {
   730  				for key, value := range arg {
   731  					if value != nil {
   732  						finalArg[key] = value
   733  					}
   734  				}
   735  			}
   736  			tmp := make(map[string]string)
   737  			err = json.Unmarshal([]byte(StringValue(str)), &tmp)
   738  			if err == nil {
   739  				for key, value := range arg {
   740  					if value != "" {
   741  						finalArg[key] = value
   742  					}
   743  				}
   744  			}
   745  		case []byte:
   746  			byt := obj.([]byte)
   747  			arg := make(map[string]interface{})
   748  			err := json.Unmarshal(byt, &arg)
   749  			if err == nil {
   750  				for key, value := range arg {
   751  					if value != nil {
   752  						finalArg[key] = value
   753  					}
   754  				}
   755  				break
   756  			}
   757  		default:
   758  			val := reflect.ValueOf(obj)
   759  			res := structToMap(val)
   760  			for key, value := range res {
   761  				if value != nil {
   762  					finalArg[key] = value
   763  				}
   764  			}
   765  		}
   766  	}
   767  
   768  	if !isNotNil {
   769  		return nil
   770  	}
   771  	return finalArg
   772  }
   773  
   774  func structToMap(dataValue reflect.Value) map[string]interface{} {
   775  	out := make(map[string]interface{})
   776  	if !dataValue.IsValid() {
   777  		return out
   778  	}
   779  	if dataValue.Kind().String() == "ptr" {
   780  		if dataValue.IsNil() {
   781  			return out
   782  		}
   783  		dataValue = dataValue.Elem()
   784  	}
   785  	if !dataValue.IsValid() {
   786  		return out
   787  	}
   788  	dataType := dataValue.Type()
   789  	if dataType.Kind().String() != "struct" {
   790  		return out
   791  	}
   792  	for i := 0; i < dataType.NumField(); i++ {
   793  		field := dataType.Field(i)
   794  		name, containsNameTag := field.Tag.Lookup("json")
   795  		if !containsNameTag {
   796  			name = field.Name
   797  		} else {
   798  			strs := strings.Split(name, ",")
   799  			name = strs[0]
   800  		}
   801  		fieldValue := dataValue.FieldByName(field.Name)
   802  		if !fieldValue.IsValid() || fieldValue.IsNil() {
   803  			continue
   804  		}
   805  		if field.Type.String() == "io.Reader" || field.Type.String() == "io.Writer" {
   806  			continue
   807  		} else if field.Type.Kind().String() == "struct" {
   808  			out[name] = structToMap(fieldValue)
   809  		} else if field.Type.Kind().String() == "ptr" &&
   810  			field.Type.Elem().Kind().String() == "struct" {
   811  			if fieldValue.Elem().IsValid() {
   812  				out[name] = structToMap(fieldValue)
   813  			}
   814  		} else if field.Type.Kind().String() == "ptr" {
   815  			if fieldValue.IsValid() && !fieldValue.IsNil() {
   816  				out[name] = fieldValue.Elem().Interface()
   817  			}
   818  		} else if field.Type.Kind().String() == "slice" {
   819  			tmp := make([]interface{}, 0)
   820  			num := fieldValue.Len()
   821  			for i := 0; i < num; i++ {
   822  				value := fieldValue.Index(i)
   823  				if !value.IsValid() {
   824  					continue
   825  				}
   826  				if value.Type().Kind().String() == "ptr" &&
   827  					value.Type().Elem().Kind().String() == "struct" {
   828  					if value.IsValid() && !value.IsNil() {
   829  						tmp = append(tmp, structToMap(value))
   830  					}
   831  				} else if value.Type().Kind().String() == "struct" {
   832  					tmp = append(tmp, structToMap(value))
   833  				} else if value.Type().Kind().String() == "ptr" {
   834  					if value.IsValid() && !value.IsNil() {
   835  						tmp = append(tmp, value.Elem().Interface())
   836  					}
   837  				} else {
   838  					tmp = append(tmp, value.Interface())
   839  				}
   840  			}
   841  			if len(tmp) > 0 {
   842  				out[name] = tmp
   843  			}
   844  		} else {
   845  			out[name] = fieldValue.Interface()
   846  		}
   847  
   848  	}
   849  	return out
   850  }
   851  
   852  func Retryable(err error) *bool {
   853  	if err == nil {
   854  		return Bool(false)
   855  	}
   856  	if realErr, ok := err.(*SDKError); ok {
   857  		if realErr.StatusCode == nil {
   858  			return Bool(false)
   859  		}
   860  		code := IntValue(realErr.StatusCode)
   861  		return Bool(code >= http.StatusInternalServerError)
   862  	}
   863  	return Bool(true)
   864  }
   865  
   866  func GetBackoffTime(backoff interface{}, retrytimes *int) *int {
   867  	backoffMap, ok := backoff.(map[string]interface{})
   868  	if !ok {
   869  		return Int(0)
   870  	}
   871  	policy, ok := backoffMap["policy"].(string)
   872  	if !ok || policy == "no" {
   873  		return Int(0)
   874  	}
   875  
   876  	period, ok := backoffMap["period"].(int)
   877  	if !ok || period == 0 {
   878  		return Int(0)
   879  	}
   880  
   881  	maxTime := math.Pow(2.0, float64(IntValue(retrytimes)))
   882  	return Int(rand.Intn(int(maxTime-1)) * period)
   883  }
   884  
   885  func Sleep(backoffTime *int) {
   886  	sleeptime := time.Duration(IntValue(backoffTime)) * time.Second
   887  	time.Sleep(sleeptime)
   888  }
   889  
   890  func Validate(params interface{}) error {
   891  	if params == nil {
   892  		return nil
   893  	}
   894  	requestValue := reflect.ValueOf(params)
   895  	if requestValue.IsNil() {
   896  		return nil
   897  	}
   898  	err := validate(requestValue.Elem())
   899  	return err
   900  }
   901  
   902  // Verify whether the parameters meet the requirements
   903  func validate(dataValue reflect.Value) error {
   904  	if strings.HasPrefix(dataValue.Type().String(), "*") { // Determines whether the input is a structure object or a pointer object
   905  		if dataValue.IsNil() {
   906  			return nil
   907  		}
   908  		dataValue = dataValue.Elem()
   909  	}
   910  	dataType := dataValue.Type()
   911  	for i := 0; i < dataType.NumField(); i++ {
   912  		field := dataType.Field(i)
   913  		valueField := dataValue.Field(i)
   914  		for _, value := range validateParams {
   915  			err := validateParam(field, valueField, value)
   916  			if err != nil {
   917  				return err
   918  			}
   919  		}
   920  	}
   921  	return nil
   922  }
   923  
   924  func validateParam(field reflect.StructField, valueField reflect.Value, tagName string) error {
   925  	tag, containsTag := field.Tag.Lookup(tagName) // Take out the checked regular expression
   926  	if containsTag && tagName == "require" {
   927  		err := checkRequire(field, valueField)
   928  		if err != nil {
   929  			return err
   930  		}
   931  	}
   932  	if strings.HasPrefix(field.Type.String(), "[]") { // Verify the parameters of the array type
   933  		err := validateSlice(field, valueField, containsTag, tag, tagName)
   934  		if err != nil {
   935  			return err
   936  		}
   937  	} else if valueField.Kind() == reflect.Ptr { // Determines whether it is a pointer object
   938  		err := validatePtr(field, valueField, containsTag, tag, tagName)
   939  		if err != nil {
   940  			return err
   941  		}
   942  	}
   943  	return nil
   944  }
   945  
   946  func validateSlice(field reflect.StructField, valueField reflect.Value, containsregexpTag bool, tag, tagName string) error {
   947  	if valueField.IsValid() && !valueField.IsNil() { // Determines whether the parameter has a value
   948  		if containsregexpTag {
   949  			if tagName == "maxItems" {
   950  				err := checkMaxItems(field, valueField, tag)
   951  				if err != nil {
   952  					return err
   953  				}
   954  			}
   955  
   956  			if tagName == "minItems" {
   957  				err := checkMinItems(field, valueField, tag)
   958  				if err != nil {
   959  					return err
   960  				}
   961  			}
   962  		}
   963  
   964  		for m := 0; m < valueField.Len(); m++ {
   965  			elementValue := valueField.Index(m)
   966  			if elementValue.Type().Kind() == reflect.Ptr { // Determines whether the child elements of an array are of a basic type
   967  				err := validatePtr(field, elementValue, containsregexpTag, tag, tagName)
   968  				if err != nil {
   969  					return err
   970  				}
   971  			}
   972  		}
   973  	}
   974  	return nil
   975  }
   976  
   977  func validatePtr(field reflect.StructField, elementValue reflect.Value, containsregexpTag bool, tag, tagName string) error {
   978  	if elementValue.IsNil() {
   979  		return nil
   980  	}
   981  	if isFilterType(elementValue.Elem().Type().String(), basicTypes) {
   982  		if containsregexpTag {
   983  			if tagName == "pattern" {
   984  				err := checkPattern(field, elementValue.Elem(), tag)
   985  				if err != nil {
   986  					return err
   987  				}
   988  			}
   989  
   990  			if tagName == "maxLength" {
   991  				err := checkMaxLength(field, elementValue.Elem(), tag)
   992  				if err != nil {
   993  					return err
   994  				}
   995  			}
   996  
   997  			if tagName == "minLength" {
   998  				err := checkMinLength(field, elementValue.Elem(), tag)
   999  				if err != nil {
  1000  					return err
  1001  				}
  1002  			}
  1003  
  1004  			if tagName == "maximum" {
  1005  				err := checkMaximum(field, elementValue.Elem(), tag)
  1006  				if err != nil {
  1007  					return err
  1008  				}
  1009  			}
  1010  
  1011  			if tagName == "minimum" {
  1012  				err := checkMinimum(field, elementValue.Elem(), tag)
  1013  				if err != nil {
  1014  					return err
  1015  				}
  1016  			}
  1017  		}
  1018  	} else {
  1019  		err := validate(elementValue)
  1020  		if err != nil {
  1021  			return err
  1022  		}
  1023  	}
  1024  	return nil
  1025  }
  1026  
  1027  func checkRequire(field reflect.StructField, valueField reflect.Value) error {
  1028  	name, _ := field.Tag.Lookup("json")
  1029  	strs := strings.Split(name, ",")
  1030  	name = strs[0]
  1031  	if !valueField.IsNil() && valueField.IsValid() {
  1032  		return nil
  1033  	}
  1034  	return errors.New(name + " should be setted")
  1035  }
  1036  
  1037  func checkPattern(field reflect.StructField, valueField reflect.Value, tag string) error {
  1038  	if valueField.IsValid() && valueField.String() != "" {
  1039  		value := valueField.String()
  1040  		r, _ := regexp.Compile("^" + tag + "$")
  1041  		if match := r.MatchString(value); !match { // Determines whether the parameter value satisfies the regular expression or not, and throws an error
  1042  			return errors.New(value + " is not matched " + tag)
  1043  		}
  1044  	}
  1045  	return nil
  1046  }
  1047  
  1048  func checkMaxItems(field reflect.StructField, valueField reflect.Value, tag string) error {
  1049  	if valueField.IsValid() && valueField.String() != "" {
  1050  		maxItems, err := strconv.Atoi(tag)
  1051  		if err != nil {
  1052  			return err
  1053  		}
  1054  		length := valueField.Len()
  1055  		if maxItems < length {
  1056  			errMsg := fmt.Sprintf("The length of %s is %d which is more than %d", field.Name, length, maxItems)
  1057  			return errors.New(errMsg)
  1058  		}
  1059  	}
  1060  	return nil
  1061  }
  1062  
  1063  func checkMinItems(field reflect.StructField, valueField reflect.Value, tag string) error {
  1064  	if valueField.IsValid() {
  1065  		minItems, err := strconv.Atoi(tag)
  1066  		if err != nil {
  1067  			return err
  1068  		}
  1069  		length := valueField.Len()
  1070  		if minItems > length {
  1071  			errMsg := fmt.Sprintf("The length of %s is %d which is less than %d", field.Name, length, minItems)
  1072  			return errors.New(errMsg)
  1073  		}
  1074  	}
  1075  	return nil
  1076  }
  1077  
  1078  func checkMaxLength(field reflect.StructField, valueField reflect.Value, tag string) error {
  1079  	if valueField.IsValid() && valueField.String() != "" {
  1080  		maxLength, err := strconv.Atoi(tag)
  1081  		if err != nil {
  1082  			return err
  1083  		}
  1084  		length := valueField.Len()
  1085  		if valueField.Kind().String() == "string" {
  1086  			length = strings.Count(valueField.String(), "") - 1
  1087  		}
  1088  		if maxLength < length {
  1089  			errMsg := fmt.Sprintf("The length of %s is %d which is more than %d", field.Name, length, maxLength)
  1090  			return errors.New(errMsg)
  1091  		}
  1092  	}
  1093  	return nil
  1094  }
  1095  
  1096  func checkMinLength(field reflect.StructField, valueField reflect.Value, tag string) error {
  1097  	if valueField.IsValid() {
  1098  		minLength, err := strconv.Atoi(tag)
  1099  		if err != nil {
  1100  			return err
  1101  		}
  1102  		length := valueField.Len()
  1103  		if valueField.Kind().String() == "string" {
  1104  			length = strings.Count(valueField.String(), "") - 1
  1105  		}
  1106  		if minLength > length {
  1107  			errMsg := fmt.Sprintf("The length of %s is %d which is less than %d", field.Name, length, minLength)
  1108  			return errors.New(errMsg)
  1109  		}
  1110  	}
  1111  	return nil
  1112  }
  1113  
  1114  func checkMaximum(field reflect.StructField, valueField reflect.Value, tag string) error {
  1115  	if valueField.IsValid() && valueField.String() != "" {
  1116  		maximum, err := strconv.ParseFloat(tag, 64)
  1117  		if err != nil {
  1118  			return err
  1119  		}
  1120  		byt, _ := json.Marshal(valueField.Interface())
  1121  		num, err := strconv.ParseFloat(string(byt), 64)
  1122  		if err != nil {
  1123  			return err
  1124  		}
  1125  		if maximum < num {
  1126  			errMsg := fmt.Sprintf("The size of %s is %f which is greater than %f", field.Name, num, maximum)
  1127  			return errors.New(errMsg)
  1128  		}
  1129  	}
  1130  	return nil
  1131  }
  1132  
  1133  func checkMinimum(field reflect.StructField, valueField reflect.Value, tag string) error {
  1134  	if valueField.IsValid() && valueField.String() != "" {
  1135  		minimum, err := strconv.ParseFloat(tag, 64)
  1136  		if err != nil {
  1137  			return err
  1138  		}
  1139  
  1140  		byt, _ := json.Marshal(valueField.Interface())
  1141  		num, err := strconv.ParseFloat(string(byt), 64)
  1142  		if err != nil {
  1143  			return err
  1144  		}
  1145  		if minimum > num {
  1146  			errMsg := fmt.Sprintf("The size of %s is %f which is less than %f", field.Name, num, minimum)
  1147  			return errors.New(errMsg)
  1148  		}
  1149  	}
  1150  	return nil
  1151  }
  1152  
  1153  // Determines whether realType is in filterTypes
  1154  func isFilterType(realType string, filterTypes []string) bool {
  1155  	for _, value := range filterTypes {
  1156  		if value == realType {
  1157  			return true
  1158  		}
  1159  	}
  1160  	return false
  1161  }
  1162  
  1163  func TransInterfaceToBool(val interface{}) *bool {
  1164  	if val == nil {
  1165  		return nil
  1166  	}
  1167  
  1168  	return Bool(val.(bool))
  1169  }
  1170  
  1171  func TransInterfaceToInt(val interface{}) *int {
  1172  	if val == nil {
  1173  		return nil
  1174  	}
  1175  
  1176  	return Int(val.(int))
  1177  }
  1178  
  1179  func TransInterfaceToString(val interface{}) *string {
  1180  	if val == nil {
  1181  		return nil
  1182  	}
  1183  
  1184  	return String(val.(string))
  1185  }
  1186  
  1187  func Prettify(i interface{}) string {
  1188  	resp, _ := json.MarshalIndent(i, "", "   ")
  1189  	return string(resp)
  1190  }
  1191  
  1192  func ToInt(a *int32) *int {
  1193  	return Int(int(Int32Value(a)))
  1194  }
  1195  
  1196  func ForceInt(a interface{}) int {
  1197  	num, _ := a.(int)
  1198  	return num
  1199  }
  1200  
  1201  func ToInt32(a *int) *int32 {
  1202  	return Int32(int32(IntValue(a)))
  1203  }