25개 이상의 토픽을 선택하실 수 없습니다. Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

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