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.

342 line
9.0 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) InitWithStsToken(accessKeyId, accessKeySecret, accessKeyFrom string) (err error) {
  81. config := client.InitWithConfig()
  82. credential := &credentials.StdTokenCredential{
  83. AccessKeyId: accessKeyId,
  84. AccessKeySecret: accessKeySecret,
  85. AccessKeyFrom: accessKeyFrom,
  86. }
  87. return client.InitWithOptions(config, credential)
  88. }
  89. func (client *Client) InitWithOptions(config *Config, credential auth.Credential) (err error) {
  90. client.httpClient = &http.Client{}
  91. client.config = config
  92. if config.Transport != nil {
  93. client.httpClient.Transport = config.Transport
  94. } else if config.HttpTransport != nil {
  95. client.httpClient.Transport = config.HttpTransport
  96. }
  97. if config.Timeout > 0 {
  98. client.httpClient.Timeout = config.Timeout
  99. }
  100. client.signer, err = auth.NewSignerWithCredential(credential, client.ProcessCommonRequestWithSigner)
  101. return
  102. }
  103. func (client *Client) InitWithConfig() (config *Config) {
  104. if client.config != nil {
  105. return client.config
  106. } else {
  107. return NewConfig()
  108. }
  109. }
  110. func (client *Client) ProcessCommonRequestWithSigner(request *requests.CommonRequest, signerInterface interface{}) (response *responses.CommonResponse, err error) {
  111. if signer, isSigner := signerInterface.(auth.Signer); isSigner {
  112. response = responses.NewCommonResponse()
  113. err = client.DoActionWithSigner(request, response, signer)
  114. return
  115. }
  116. panic("should not be here")
  117. }
  118. func Timeout(connectTimeout time.Duration) func(ctx context.Context, net, addr string) (c net.Conn, err error) {
  119. return func(ctx context.Context, network, address string) (c net.Conn, err error) {
  120. return (&net.Dialer{
  121. Timeout: connectTimeout,
  122. DualStack: true,
  123. }).DialContext(ctx, network, address)
  124. }
  125. }
  126. func (client *Client) setTimeOut(request requests.AcsRequest) {
  127. readTimeout, connectTimeout := client.getTimeOut(request)
  128. client.httpClient.Timeout = readTimeout
  129. if trans, ok := client.httpClient.Transport.(*http.Transport); ok && trans != nil {
  130. trans.DialContext = Timeout(connectTimeout)
  131. client.httpClient.Transport = trans
  132. } else if client.httpClient.Transport == nil {
  133. client.httpClient.Transport = &http.Transport{
  134. DialContext: Timeout(connectTimeout),
  135. }
  136. }
  137. }
  138. func (client *Client) getTimeOut(request requests.AcsRequest) (time.Duration, time.Duration) {
  139. readTimeOut := defaultReadTimeout
  140. connectTimeOut := defaultConnectTimeout
  141. reqReadTimeout := request.GetReadTimeout()
  142. reqConnectTimeout := request.GetConnectTimeout()
  143. if reqReadTimeout != 0*time.Millisecond {
  144. readTimeOut = reqReadTimeout
  145. } else if client.readTimeout != 0*time.Microsecond {
  146. readTimeOut = client.readTimeout
  147. } else if client.httpClient.Timeout != 0 {
  148. readTimeOut = client.httpClient.Timeout
  149. }
  150. if reqConnectTimeout != 0*time.Microsecond {
  151. connectTimeOut = reqConnectTimeout
  152. } else if client.connectTimeout != 0*time.Millisecond {
  153. connectTimeOut = client.connectTimeout
  154. }
  155. return readTimeOut, connectTimeOut
  156. }
  157. func (client *Client) getHTTPSInsecure(request requests.AcsRequest) (insecure bool) {
  158. if request.GetHTTPSInsecure() != nil {
  159. insecure = *request.GetHTTPSInsecure()
  160. } else {
  161. insecure = client.GetHTTPSInsecure()
  162. }
  163. return
  164. }
  165. func (client *Client) DoAction(request requests.AcsRequest, response responses.AcsResponse) (err error) {
  166. return client.DoActionWithSigner(request, response, nil)
  167. }
  168. func (client *Client) DoActionWithSigner(request requests.AcsRequest, response responses.AcsResponse, signer auth.Signer) (err error) {
  169. httpRequest, err := client.buildRequestWithSigner(request, signer)
  170. if err != nil {
  171. return err
  172. }
  173. client.setTimeOut(request)
  174. proxy, err := client.getHttpProxy(httpRequest.URL.Scheme)
  175. if err != nil {
  176. return err
  177. }
  178. noProxy := client.getNoProxy(httpRequest.URL.Scheme)
  179. var flag bool
  180. for _, value := range noProxy {
  181. if strings.HasPrefix(value, "*") {
  182. value = fmt.Sprint(".%s", value)
  183. }
  184. noProxyReg, err := regexp.Compile(value)
  185. if err != nil {
  186. return err
  187. }
  188. if noProxyReg.MatchString(httpRequest.Host) {
  189. flag = true
  190. break
  191. }
  192. }
  193. if trans, ok := client.httpClient.Transport.(*http.Transport); ok && trans != nil {
  194. if trans.TLSClientConfig != nil {
  195. trans.TLSClientConfig.InsecureSkipVerify = client.getHTTPSInsecure(request)
  196. } else {
  197. trans.TLSClientConfig = &tls.Config{
  198. InsecureSkipVerify: client.getHTTPSInsecure(request),
  199. }
  200. }
  201. if proxy != nil && !flag {
  202. trans.Proxy = http.ProxyURL(proxy)
  203. }
  204. client.httpClient.Transport = trans
  205. }
  206. dump, err := httputil.DumpRequest(httpRequest, true)
  207. debug("client %s", bytes.NewBuffer(dump).String())
  208. var httpResponse *http.Response
  209. httpResponse, err = hookDo(client.httpClient.Do)(httpRequest)
  210. if err != nil {
  211. return
  212. }
  213. err = responses.Unmarshal(response, httpResponse, request.GetAcceptFormat())
  214. return
  215. }
  216. func (client *Client) buildRequestWithSigner(request requests.AcsRequest, signer auth.Signer) (httpRequest *http.Request, err error) {
  217. // init param
  218. domain := request.GetDomain()
  219. if strings.Index(domain, ".") < 0 {
  220. domain += defaultDomain
  221. request.SetDomain(domain)
  222. }
  223. if request.GetScheme() == "" {
  224. request.SetScheme(client.config.Scheme)
  225. }
  226. err = requests.InitParam(request)
  227. if err != nil {
  228. return
  229. }
  230. // build signature
  231. var finalSigner auth.Signer
  232. if signer != nil {
  233. finalSigner = signer
  234. } else {
  235. finalSigner = client.signer
  236. }
  237. err = auth.Sign(request, finalSigner)
  238. if err != nil {
  239. return
  240. }
  241. // build request
  242. requestMethod := request.GetMethod()
  243. requestUrl := request.BuildUrl()
  244. body := request.GetBodyReader()
  245. httpRequest, err = http.NewRequest(requestMethod, requestUrl, body)
  246. if err != nil {
  247. return
  248. }
  249. for key, val := range request.GetHeaders() {
  250. httpRequest.Header[key] = []string{val}
  251. }
  252. if host, isContainsHost := request.GetHeaders()["host"]; isContainsHost {
  253. httpRequest.Host = host
  254. }
  255. userAgent := DefaultUserAgent
  256. httpRequest.Header.Set("User-Agent", userAgent)
  257. return
  258. }
  259. func (client *Client) getHttpProxy(scheme string) (proxy *url.URL, err error) {
  260. switch scheme {
  261. case "https":
  262. if client.GetHttpsProxy() != "" {
  263. proxy, err = url.Parse(client.httpsProxy)
  264. } else if rawurl := os.Getenv("HTTPS_PROXY"); rawurl != "" {
  265. proxy, err = url.Parse(rawurl)
  266. } else if rawurl := os.Getenv("https_proxy"); rawurl != "" {
  267. proxy, err = url.Parse(rawurl)
  268. }
  269. default:
  270. if client.GetHttpProxy() != "" {
  271. proxy, err = url.Parse(client.httpProxy)
  272. } else if rawurl := os.Getenv("HTTP_PROXY"); rawurl != "" {
  273. proxy, err = url.Parse(rawurl)
  274. } else if rawurl := os.Getenv("http_proxy"); rawurl != "" {
  275. proxy, err = url.Parse(rawurl)
  276. }
  277. }
  278. return
  279. }
  280. func (client *Client) getNoProxy(scheme string) []string {
  281. var urls []string
  282. if client.GetNoProxy() != "" {
  283. urls = strings.Split(client.noProxy, ",")
  284. } else if rawurl := os.Getenv("NO_PROXY"); rawurl != "" {
  285. urls = strings.Split(rawurl, ",")
  286. } else if rawurl := os.Getenv("no_proxy"); rawurl != "" {
  287. urls = strings.Split(rawurl, ",")
  288. }
  289. return urls
  290. }
  291. func hookDo(fn func(req *http.Request) (*http.Response, error)) func(req *http.Request) (*http.Response, error) {
  292. return fn
  293. }