You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

358 lines
9.5 KiB

  1. package sdk
  2. import (
  3. "bytes"
  4. "context"
  5. "crypto/tls"
  6. "fmt"
  7. "golib.gaore.com/GaoreGo/gaore-common-sdk-go/sdk/auth"
  8. "golib.gaore.com/GaoreGo/gaore-common-sdk-go/sdk/auth/credentials"
  9. "golib.gaore.com/GaoreGo/gaore-common-sdk-go/sdk/requests"
  10. "golib.gaore.com/GaoreGo/gaore-common-sdk-go/sdk/responses"
  11. "golib.gaore.com/GaoreGo/gaore-common-sdk-go/sdk/utils"
  12. "net"
  13. "net/http"
  14. "net/http/httputil"
  15. "net/url"
  16. "os"
  17. "regexp"
  18. "runtime"
  19. "strings"
  20. "time"
  21. )
  22. var Version = "0.0.1"
  23. var defaultConnectTimeout = 5 * time.Second
  24. var defaultReadTimeout = 10 * time.Second
  25. var defaultDomain = ".gaore.com"
  26. var DefaultUserAgent = fmt.Sprintf("GaoreGoSdk (%s;%s) Golang/%s Core/%s", runtime.GOOS, runtime.GOARCH, strings.Trim(runtime.Version(), "go"), Version)
  27. var debug utils.Debug
  28. func init() {
  29. debug = utils.Init("sdk")
  30. }
  31. type Client struct {
  32. Host string
  33. httpClient *http.Client
  34. isInsecure bool
  35. signer auth.Signer
  36. readTimeout time.Duration
  37. connectTimeout time.Duration
  38. config *Config
  39. httpProxy string
  40. httpsProxy string
  41. noProxy string
  42. }
  43. func (client *Client) GetNoProxy() string {
  44. return client.noProxy
  45. }
  46. func (client *Client) SetNoProxy(noProxy string) {
  47. client.noProxy = noProxy
  48. }
  49. func (client *Client) GetHttpsProxy() string {
  50. return client.httpsProxy
  51. }
  52. func (client *Client) SetHttpsProxy(httpsProxy string) {
  53. client.httpsProxy = httpsProxy
  54. }
  55. func (client *Client) SetHttpProxy(httpProxy string) {
  56. client.httpProxy = httpProxy
  57. }
  58. func (client *Client) GetHttpProxy() string {
  59. return client.httpProxy
  60. }
  61. func (client *Client) GetHTTPSInsecure() bool {
  62. return client.isInsecure
  63. }
  64. func (client *Client) InitClientConfig() (config *Config) {
  65. if client.config != nil {
  66. return client.config
  67. } else {
  68. return NewConfig()
  69. }
  70. }
  71. func (client *Client) InitWithAccessKey(accessKeyId, accessKeySecret, accessKeyFrom string) (err error) {
  72. config := client.InitWithConfig()
  73. credential := &credentials.BaseCredential{
  74. AccessKeyId: accessKeyId,
  75. AccessKeySecret: accessKeySecret,
  76. AccessKeyFrom: accessKeyFrom,
  77. }
  78. return client.InitWithOptions(config, credential)
  79. }
  80. func (client *Client) InitWithAliAppcode(accessKeyId, accessKeySecret string, env ...string) (err error) {
  81. config := client.InitWithConfig()
  82. credential := credentials.NewAliAppcodeCredential(accessKeyId, accessKeySecret)
  83. if len(env) > 0 {
  84. config.Env = env[0]
  85. }
  86. return client.InitWithOptions(config, credential)
  87. }
  88. func (client *Client) InitWithStsToken(accessKeyId, accessKeySecret, accessKeyFrom string) (err error) {
  89. config := client.InitWithConfig()
  90. credential := &credentials.StdTokenCredential{
  91. AccessKeyId: accessKeyId,
  92. AccessKeySecret: accessKeySecret,
  93. AccessKeyFrom: accessKeyFrom,
  94. }
  95. return client.InitWithOptions(config, credential)
  96. }
  97. func (client *Client) InitWithOptions(config *Config, credential auth.Credential) (err error) {
  98. client.httpClient = &http.Client{}
  99. client.config = config
  100. if config.Transport != nil {
  101. client.httpClient.Transport = config.Transport
  102. } else if config.HttpTransport != nil {
  103. client.httpClient.Transport = config.HttpTransport
  104. }
  105. if config.Timeout > 0 {
  106. client.httpClient.Timeout = config.Timeout
  107. }
  108. client.signer, err = auth.NewSignerWithCredential(credential, client.ProcessCommonRequestWithSigner)
  109. return
  110. }
  111. func (client *Client) InitWithConfig() (config *Config) {
  112. if client.config != nil {
  113. return client.config
  114. } else {
  115. return NewConfig()
  116. }
  117. }
  118. func (client *Client) ProcessCommonRequestWithSigner(request *requests.CommonRequest, signerInterface interface{}) (response *responses.CommonResponse, err error) {
  119. if signer, isSigner := signerInterface.(auth.Signer); isSigner {
  120. response = responses.NewCommonResponse()
  121. err = client.DoActionWithSigner(request, response, signer)
  122. return
  123. }
  124. panic("should not be here")
  125. }
  126. func Timeout(connectTimeout time.Duration) func(ctx context.Context, net, addr string) (c net.Conn, err error) {
  127. return func(ctx context.Context, network, address string) (c net.Conn, err error) {
  128. return (&net.Dialer{
  129. Timeout: connectTimeout,
  130. DualStack: true,
  131. }).DialContext(ctx, network, address)
  132. }
  133. }
  134. func (client *Client) setTimeOut(request requests.AcsRequest) {
  135. readTimeout, connectTimeout := client.getTimeOut(request)
  136. client.httpClient.Timeout = readTimeout
  137. if trans, ok := client.httpClient.Transport.(*http.Transport); ok && trans != nil {
  138. trans.DialContext = Timeout(connectTimeout)
  139. client.httpClient.Transport = trans
  140. } else if client.httpClient.Transport == nil {
  141. client.httpClient.Transport = &http.Transport{
  142. DialContext: Timeout(connectTimeout),
  143. }
  144. }
  145. }
  146. func (client *Client) getTimeOut(request requests.AcsRequest) (time.Duration, time.Duration) {
  147. readTimeOut := defaultReadTimeout
  148. connectTimeOut := defaultConnectTimeout
  149. reqReadTimeout := request.GetReadTimeout()
  150. reqConnectTimeout := request.GetConnectTimeout()
  151. if reqReadTimeout != 0*time.Millisecond {
  152. readTimeOut = reqReadTimeout
  153. } else if client.readTimeout != 0*time.Microsecond {
  154. readTimeOut = client.readTimeout
  155. } else if client.httpClient.Timeout != 0 {
  156. readTimeOut = client.httpClient.Timeout
  157. }
  158. if reqConnectTimeout != 0*time.Microsecond {
  159. connectTimeOut = reqConnectTimeout
  160. } else if client.connectTimeout != 0*time.Millisecond {
  161. connectTimeOut = client.connectTimeout
  162. }
  163. return readTimeOut, connectTimeOut
  164. }
  165. func (client *Client) getHTTPSInsecure(request requests.AcsRequest) (insecure bool) {
  166. if request.GetHTTPSInsecure() != nil {
  167. insecure = *request.GetHTTPSInsecure()
  168. } else {
  169. insecure = client.GetHTTPSInsecure()
  170. }
  171. return
  172. }
  173. func (client *Client) DoAction(request requests.AcsRequest, response responses.AcsResponse) (err error) {
  174. return client.DoActionWithSigner(request, response, nil)
  175. }
  176. func (client *Client) DoActionWithSigner(request requests.AcsRequest, response responses.AcsResponse, signer auth.Signer) (err error) {
  177. httpRequest, err := client.buildRequestWithSigner(request, signer)
  178. if err != nil {
  179. return err
  180. }
  181. client.setTimeOut(request)
  182. proxy, err := client.getHttpProxy(httpRequest.URL.Scheme)
  183. if err != nil {
  184. return err
  185. }
  186. noProxy := client.getNoProxy(httpRequest.URL.Scheme)
  187. var flag bool
  188. for _, value := range noProxy {
  189. if strings.HasPrefix(value, "*") {
  190. value = fmt.Sprint(".%s", value)
  191. }
  192. noProxyReg, err := regexp.Compile(value)
  193. if err != nil {
  194. return err
  195. }
  196. if noProxyReg.MatchString(httpRequest.Host) {
  197. flag = true
  198. break
  199. }
  200. }
  201. if trans, ok := client.httpClient.Transport.(*http.Transport); ok && trans != nil {
  202. if trans.TLSClientConfig != nil {
  203. trans.TLSClientConfig.InsecureSkipVerify = client.getHTTPSInsecure(request)
  204. } else {
  205. trans.TLSClientConfig = &tls.Config{
  206. InsecureSkipVerify: client.getHTTPSInsecure(request),
  207. }
  208. }
  209. if proxy != nil && !flag {
  210. trans.Proxy = http.ProxyURL(proxy)
  211. }
  212. client.httpClient.Transport = trans
  213. }
  214. dump, err := httputil.DumpRequest(httpRequest, true)
  215. debug("client %s", bytes.NewBuffer(dump).String())
  216. var httpResponse *http.Response
  217. httpResponse, err = hookDo(client.httpClient.Do)(httpRequest)
  218. if err != nil {
  219. return
  220. }
  221. err = responses.Unmarshal(response, httpResponse, request.GetAcceptFormat())
  222. return
  223. }
  224. func (client *Client) buildRequestWithSigner(request requests.AcsRequest, signer auth.Signer) (httpRequest *http.Request, err error) {
  225. // init param
  226. domain := request.GetDomain()
  227. if strings.Index(domain.Default, ".") < 0 {
  228. domain.Default += defaultDomain
  229. request.SetDomain(domain)
  230. }
  231. if request.GetScheme() == "" {
  232. request.SetScheme(client.config.Scheme)
  233. }
  234. if request.GetEnv() == "" && client.config.Env != "" {
  235. request.SetEnv(client.config.Env)
  236. }
  237. err = requests.InitParam(request)
  238. if err != nil {
  239. return
  240. }
  241. // build signature
  242. var finalSigner auth.Signer
  243. if signer != nil {
  244. finalSigner = signer
  245. } else {
  246. finalSigner = client.signer
  247. }
  248. err = auth.Sign(request, finalSigner)
  249. if err != nil {
  250. return
  251. }
  252. // build request
  253. requestMethod := request.GetMethod()
  254. requestUrl := request.BuildUrl()
  255. body := request.GetBodyReader()
  256. httpRequest, err = http.NewRequest(requestMethod, requestUrl, body)
  257. if err != nil {
  258. return
  259. }
  260. for key, val := range request.GetHeaders() {
  261. httpRequest.Header[key] = []string{val}
  262. }
  263. if host, isContainsHost := request.GetHeaders()["host"]; isContainsHost {
  264. httpRequest.Host = host
  265. }
  266. userAgent := DefaultUserAgent
  267. httpRequest.Header.Set("User-Agent", userAgent)
  268. return
  269. }
  270. func (client *Client) getHttpProxy(scheme string) (proxy *url.URL, err error) {
  271. switch scheme {
  272. case "https":
  273. if client.GetHttpsProxy() != "" {
  274. proxy, err = url.Parse(client.httpsProxy)
  275. } else if rawurl := os.Getenv("HTTPS_PROXY"); rawurl != "" {
  276. proxy, err = url.Parse(rawurl)
  277. } else if rawurl := os.Getenv("https_proxy"); rawurl != "" {
  278. proxy, err = url.Parse(rawurl)
  279. }
  280. default:
  281. if client.GetHttpProxy() != "" {
  282. proxy, err = url.Parse(client.httpProxy)
  283. } else if rawurl := os.Getenv("HTTP_PROXY"); rawurl != "" {
  284. proxy, err = url.Parse(rawurl)
  285. } else if rawurl := os.Getenv("http_proxy"); rawurl != "" {
  286. proxy, err = url.Parse(rawurl)
  287. }
  288. }
  289. return
  290. }
  291. func (client *Client) getNoProxy(scheme string) []string {
  292. var urls []string
  293. if client.GetNoProxy() != "" {
  294. urls = strings.Split(client.noProxy, ",")
  295. } else if rawurl := os.Getenv("NO_PROXY"); rawurl != "" {
  296. urls = strings.Split(rawurl, ",")
  297. } else if rawurl := os.Getenv("no_proxy"); rawurl != "" {
  298. urls = strings.Split(rawurl, ",")
  299. }
  300. return urls
  301. }
  302. func hookDo(fn func(req *http.Request) (*http.Response, error)) func(req *http.Request) (*http.Response, error) {
  303. return fn
  304. }