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.

325 lines
8.6 KiB

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