http.go 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151
  1. package http
  2. import (
  3. "bytes"
  4. "context"
  5. "fmt"
  6. "io"
  7. "io/ioutil"
  8. "net"
  9. "net/http"
  10. "net/url"
  11. "runtime"
  12. "strings"
  13. "time"
  14. "github.com/alibabacloud-go/debug/debug"
  15. credentials_go "github.com/aliyun/credentials-go"
  16. "github.com/aliyun/credentials-go/credentials/internal/utils"
  17. )
  18. var defaultUserAgent = fmt.Sprintf("AlibabaCloud (%s; %s) Golang/%s Credentials/%s TeaDSL/1", runtime.GOOS, runtime.GOARCH, strings.Trim(runtime.Version(), "go"), credentials_go.PACKAGE_VERSION)
  19. type Request struct {
  20. Method string // http request method
  21. URL string // http url
  22. Protocol string // http or https
  23. Host string // http host
  24. ReadTimeout time.Duration
  25. ConnectTimeout time.Duration
  26. Proxy string // http proxy
  27. Form map[string]string // http form
  28. Body []byte // request body for JSON or stream
  29. Path string
  30. Queries map[string]string
  31. Headers map[string]string
  32. }
  33. func (req *Request) BuildRequestURL() string {
  34. httpUrl := fmt.Sprintf("%s://%s%s", req.Protocol, req.Host, req.Path)
  35. if req.URL != "" {
  36. httpUrl = req.URL
  37. }
  38. querystring := utils.GetURLFormedMap(req.Queries)
  39. if querystring != "" {
  40. httpUrl = httpUrl + "?" + querystring
  41. }
  42. return fmt.Sprintf("%s %s", req.Method, httpUrl)
  43. }
  44. type Response struct {
  45. StatusCode int
  46. Headers map[string]string
  47. Body []byte
  48. }
  49. var newRequest = http.NewRequest
  50. type do func(req *http.Request) (*http.Response, error)
  51. var hookDo = func(fn do) do {
  52. return fn
  53. }
  54. var debuglog = debug.Init("credential")
  55. func Do(req *Request) (res *Response, err error) {
  56. querystring := utils.GetURLFormedMap(req.Queries)
  57. // do request
  58. httpUrl := fmt.Sprintf("%s://%s%s?%s", req.Protocol, req.Host, req.Path, querystring)
  59. if req.URL != "" {
  60. httpUrl = req.URL
  61. }
  62. var body io.Reader
  63. if req.Method == "GET" {
  64. body = strings.NewReader("")
  65. } else if req.Body != nil {
  66. body = bytes.NewReader(req.Body)
  67. } else {
  68. body = strings.NewReader(utils.GetURLFormedMap(req.Form))
  69. }
  70. httpRequest, err := newRequest(req.Method, httpUrl, body)
  71. if err != nil {
  72. return
  73. }
  74. httpRequest.Header["User-Agent"] = []string{defaultUserAgent}
  75. if req.Form != nil {
  76. httpRequest.Header["Content-Type"] = []string{"application/x-www-form-urlencoded"}
  77. }
  78. for key, value := range req.Headers {
  79. if value != "" {
  80. debuglog("> %s: %s", key, value)
  81. httpRequest.Header.Set(key, value)
  82. }
  83. }
  84. httpClient := &http.Client{}
  85. if req.ReadTimeout != 0 {
  86. httpClient.Timeout = req.ReadTimeout + req.ConnectTimeout
  87. }
  88. transport := http.DefaultTransport.(*http.Transport).Clone()
  89. if req.Proxy != "" {
  90. var proxy *url.URL
  91. proxy, err = url.Parse(req.Proxy)
  92. if err != nil {
  93. return
  94. }
  95. transport.Proxy = http.ProxyURL(proxy)
  96. }
  97. if req.ConnectTimeout != 0 {
  98. transport.DialContext = func(ctx context.Context, network, address string) (net.Conn, error) {
  99. return (&net.Dialer{
  100. Timeout: req.ConnectTimeout,
  101. DualStack: true,
  102. }).DialContext(ctx, network, address)
  103. }
  104. }
  105. httpClient.Transport = transport
  106. httpResponse, err := hookDo(httpClient.Do)(httpRequest)
  107. if err != nil {
  108. return
  109. }
  110. defer httpResponse.Body.Close()
  111. responseBody, err := ioutil.ReadAll(httpResponse.Body)
  112. if err != nil {
  113. return
  114. }
  115. res = &Response{
  116. StatusCode: httpResponse.StatusCode,
  117. Headers: make(map[string]string),
  118. Body: responseBody,
  119. }
  120. for key, v := range httpResponse.Header {
  121. res.Headers[key] = v[0]
  122. }
  123. return
  124. }