Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.
 
 
 

281 строка
8.6 KiB

  1. package http
  2. import (
  3. "bytes"
  4. "encoding/json"
  5. "encoding/xml"
  6. "errors"
  7. "fmt"
  8. "gitlab.ecloud.com/ecloud/ecloudsdkcore/auth"
  9. "gitlab.ecloud.com/ecloud/ecloudsdkcore/auth/provider"
  10. "gitlab.ecloud.com/ecloud/ecloudsdkcore/errs"
  11. "gitlab.ecloud.com/ecloud/ecloudsdkcore/request"
  12. "gitlab.ecloud.com/ecloud/ecloudsdkcore/response"
  13. "gitlab.ecloud.com/ecloud/ecloudsdkcore/utils"
  14. "io/ioutil"
  15. "net/http"
  16. "net/url"
  17. "strings"
  18. "sync"
  19. )
  20. type NetHttpClient struct {
  21. }
  22. type RetryFunc func(request *request.HttpRequest,
  23. returnType *interface{}) (*response.HttpResponse, error)
  24. func NewHttpClient() *NetHttpClient {
  25. return &NetHttpClient{}
  26. }
  27. var clientPool = &sync.Map{}
  28. // doRequest do the request.
  29. func (hc *NetHttpClient) getClient(request *request.HttpRequest, cm map[string]interface{}) (*http.Client, error) {
  30. var host string
  31. if cm["ClientProxyHost"] != nil && cm["ClientProxyPort"] != nil {
  32. host = fmt.Sprintf("%s:%s", *cm["ClientProxyHost"].(*string), *cm["ClientProxyPort"].(*string))
  33. } else {
  34. url, err := url.Parse(request.Url)
  35. if err != nil {
  36. return nil, errs.NewInvalidParameterError(fmt.Sprintf("request url invalid, url=: %s", request.Url), err)
  37. }
  38. host = url.Host
  39. }
  40. client, ok := clientPool.Load(host)
  41. if client == nil && !ok {
  42. var err error
  43. client, err = hc.buildHttpClient(cm)
  44. if err != nil {
  45. return nil, err
  46. }
  47. clientPool.Store(host, client)
  48. }
  49. return client.(*http.Client), nil
  50. }
  51. func (hc *NetHttpClient) Execute(hr *request.HttpRequest, cm map[string]interface{}, rt interface{}) (*response.HttpResponse, error) {
  52. req, err := hc.buildRequest(hr, cm)
  53. if err != nil {
  54. return nil, err
  55. }
  56. client, err := hc.getClient(hr, cm)
  57. if err != nil {
  58. return nil, errs.NewServerRequestError("get http error: ", err)
  59. }
  60. resp, err := client.Do(req)
  61. if err != nil {
  62. return nil, errs.NewServerRequestError(err.Error(), err)
  63. }
  64. if resp == nil {
  65. return nil, errs.NewServerResponseError("response is nil", nil, -1, nil, "")
  66. }
  67. if err = handleResponse(resp, cm, rt); err != nil {
  68. return nil, err
  69. }
  70. return &response.HttpResponse{
  71. StatusCode: resp.StatusCode,
  72. Headers: resp.Header,
  73. Data: resp,
  74. }, nil
  75. }
  76. func (hc *NetHttpClient) buildHttpClient(cm map[string]interface{}) (*http.Client, error) {
  77. hcb := NewHttpClientBuilder()
  78. if utils.IsSet(cm["ReadTimeout"]) {
  79. hcb.SetReadTimeout(utils.Int32Value(cm["ReadTimeout"].(*int32)))
  80. }
  81. if utils.IsSet(cm["ConnectTimeout"]) {
  82. hcb.SetConnectTimeout(utils.Int32Value(cm["ConnectTimeout"].(*int32)))
  83. }
  84. if utils.IsSet(cm["ClientProxyHost"]) {
  85. proxy := Proxy{
  86. Protocol: cm["ClientProxyProtocol"].(*string),
  87. Host: cm["ClientProxyHost"].(*string),
  88. Port: cm["ClientProxyPort"].(*int32),
  89. Username: cm["ClientProxyUsername"].(*string),
  90. Password: cm["ClientProxyPassword"].(*string),
  91. }
  92. hcb.SetClientProxy(proxy)
  93. }
  94. ignore := true
  95. if utils.IsSet(cm["IgnoreSSL"]) {
  96. ignore = utils.BoolValue(cm["IgnoreSSL"].(*bool))
  97. }
  98. certFile := ""
  99. if utils.IsSet(cm["CertFile"]) {
  100. certFile = utils.StringValue(cm["CertFile"].(*string))
  101. }
  102. clientCertFile := ""
  103. if utils.IsSet(cm["ClientCertFile"]) {
  104. clientCertFile = utils.StringValue(cm["ClientCertFile"].(*string))
  105. }
  106. clientKeyFile := ""
  107. if utils.IsSet(cm["ClientKeyFile"]) {
  108. clientKeyFile = utils.StringValue(cm["ClientKeyFile"].(*string))
  109. }
  110. err := hcb.ApplySSLSettings(ignore, certFile, clientCertFile, clientKeyFile)
  111. if err != nil {
  112. return nil, err
  113. }
  114. return hcb.Build(), nil
  115. }
  116. func handleResponse(resp *http.Response, cm map[string]interface{}, returnType interface{}) error {
  117. body, err := ioutil.ReadAll(resp.Body)
  118. if err != nil {
  119. if resp.Body != nil {
  120. _ = resp.Body.Close()
  121. }
  122. return errs.NewServerResponseError(fmt.Sprintf("response status is: %s,status code is:%d",
  123. resp.Status, resp.StatusCode), err, resp.StatusCode, resp.Header, "can not read response body")
  124. }
  125. // successful
  126. if isSuccessful(resp.StatusCode) {
  127. if returnType == nil || resp.StatusCode == 204 {
  128. if resp.Body != nil {
  129. _ = resp.Body.Close()
  130. }
  131. return nil
  132. }
  133. // If we succeed, return the data, otherwise pass on to deserialize error.
  134. err = deserialize(returnType, body, cm, resp.Header.Get("Content-Type"))
  135. if err != nil {
  136. return errs.NewServerResponseError(fmt.Sprintf("can't deserialize response body with content-type: %s,response body:%s",
  137. resp.Header.Get("Content-Type"), string(body)), err, resp.StatusCode, resp.Header, string(body))
  138. }
  139. } else {
  140. if body == nil {
  141. return errs.NewServerResponseError(fmt.Sprintf("response status is: %s,status code is:%d",
  142. resp.Status, resp.StatusCode), nil, resp.StatusCode, resp.Header, "response body is nil")
  143. }
  144. respBody := string(body)
  145. return errs.NewServerResponseError(fmt.Sprintf("response status: %s,http status code:%d,response body:%s",
  146. resp.Status, resp.StatusCode, respBody), nil, resp.StatusCode, resp.Header, respBody)
  147. }
  148. return nil
  149. }
  150. func isSuccessful(code int) bool {
  151. return code >= 200 && code < 300
  152. }
  153. func (hc *NetHttpClient) buildRequest(hr *request.HttpRequest, cm map[string]interface{}) (request *http.Request, err error) {
  154. req, err := prepareRequest(hr, cm)
  155. if err != nil {
  156. return nil, err
  157. }
  158. return req, nil
  159. }
  160. // prepareRequest build the request
  161. func prepareRequest(hr *request.HttpRequest, cm map[string]interface{}) (req *http.Request, err error) {
  162. var body *bytes.Buffer
  163. rawBody := hr.Body
  164. contentType := hr.ContentType
  165. // Detect rawBody
  166. if rawBody != nil {
  167. if utils.IsSet(cm["Provider"]) {
  168. provider := cm["Provider"].(provider.ICredentialProvider)
  169. credential, err := provider.GetCredential()
  170. if err != nil {
  171. return nil, err
  172. }
  173. if *credential.CredentialType == auth.CredentialMop && *credential.EncryptionType == auth.EncrytMopRsa {
  174. bodyBuf := &bytes.Buffer{}
  175. err := json.NewEncoder(bodyBuf).Encode(rawBody)
  176. if err != nil {
  177. return nil, err
  178. }
  179. encryptContent, err := auth.GetCredentialManager(*credential.CredentialType).Encrypt(bodyBuf.Bytes(), *credential.PublicKey)
  180. if err != nil {
  181. return nil, err
  182. }
  183. rawBody = encryptContent
  184. }
  185. }
  186. contentType = utils.DetectContentType(rawBody)
  187. body, err = utils.SetBody(rawBody, contentType)
  188. if err != nil {
  189. return nil, errs.NewServerRequestError(fmt.Sprintf("set request body error: %s", err.Error()), err)
  190. }
  191. }
  192. // Setup url and query parameters, url contains query strings
  193. rawUrl := hr.Url
  194. if len(rawUrl) == 0 {
  195. return nil, errs.NewServerRequestError("request url is empty", nil)
  196. }
  197. realUrl, err := url.Parse(rawUrl)
  198. if err != nil {
  199. return nil, errs.NewServerRequestError(fmt.Sprintf("can't parse request url: %s, "+
  200. "error is: %s", rawUrl, err.Error()), err)
  201. }
  202. // Generate a new http.Request
  203. method := hr.Method
  204. if body != nil {
  205. req, err = http.NewRequest(method, realUrl.String(), body)
  206. } else {
  207. req, err = http.NewRequest(method, realUrl.String(), nil)
  208. }
  209. if err != nil {
  210. return nil, errs.NewServerRequestError(fmt.Sprintf("can't create http request, "+
  211. "method=%s, url=%s, error: %s", method, realUrl.String(), err.Error()), err)
  212. }
  213. // Add request headers
  214. headers := hr.HeaderParams
  215. for name, value := range headers {
  216. if name == "Host" {
  217. req.Host = value
  218. continue
  219. }
  220. req.Header.Add(name, value)
  221. }
  222. if len(contentType) == 0 {
  223. contentType = "application/json; charset=utf-8"
  224. }
  225. req.Header.Add("Content-Type", contentType)
  226. return req, nil
  227. }
  228. func deserialize(respType interface{}, respBody []byte, configMap map[string]interface{}, contentType string) (err error) {
  229. if respBody == nil {
  230. //return errs.NewGenericResponseError("response body is nil", nil, respBody)
  231. return errs.NewServerResponseError("response body is nil", nil, -1, nil, "")
  232. }
  233. if utils.IsSet(configMap["Provider"]) {
  234. provider := configMap["Provider"].(provider.ICredentialProvider)
  235. credential, err := provider.GetCredential()
  236. if err != nil {
  237. return err
  238. }
  239. if *credential.CredentialType == auth.CredentialMop && *credential.EncryptionType == auth.EncrytMopRsa {
  240. decryptContent, err := auth.GetCredentialManager(*credential.CredentialType).Decrypt(string(respBody), *credential.PrivateKey)
  241. if err != nil {
  242. return err
  243. }
  244. respBody = utils.StringToBytes(decryptContent)
  245. }
  246. }
  247. if strings.Contains(contentType, "application/xml") {
  248. if err = xml.Unmarshal(respBody, respType); err != nil {
  249. return errs.NewServerResponseError(fmt.Sprintf("can't deserialize response body with: %s",
  250. string(respBody)), err, -1, nil, string(respBody))
  251. }
  252. return nil
  253. } else if strings.Contains(contentType, "json") {
  254. if err = json.Unmarshal(respBody, respType); err != nil {
  255. return errs.NewServerResponseError(fmt.Sprintf("can't deserialize response body with: %s",
  256. string(respBody)), err, -1, nil, string(respBody))
  257. }
  258. return nil
  259. }
  260. return errors.New("undefined response type")
  261. }