github.com/aliyun/credentials-go@v1.4.7/credentials/internal/http/http.go (about) 1 package http 2 3 import ( 4 "bytes" 5 "context" 6 "fmt" 7 "io" 8 "io/ioutil" 9 "net" 10 "net/http" 11 "net/url" 12 "strings" 13 "time" 14 15 "github.com/alibabacloud-go/debug/debug" 16 "github.com/aliyun/credentials-go/credentials/internal/utils" 17 ) 18 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 34 func (req *Request) BuildRequestURL() string { 35 httpUrl := fmt.Sprintf("%s://%s%s", req.Protocol, req.Host, req.Path) 36 if req.URL != "" { 37 httpUrl = req.URL 38 } 39 40 querystring := utils.GetURLFormedMap(req.Queries) 41 if querystring != "" { 42 httpUrl = httpUrl + "?" + querystring 43 } 44 45 return fmt.Sprintf("%s %s", req.Method, httpUrl) 46 } 47 48 type Response struct { 49 StatusCode int 50 Headers map[string]string 51 Body []byte 52 } 53 54 var newRequest = http.NewRequest 55 56 type do func(req *http.Request) (*http.Response, error) 57 58 var hookDo = func(fn do) do { 59 return fn 60 } 61 62 var debuglog = debug.Init("credential") 63 64 func Do(req *Request) (res *Response, err error) { 65 querystring := utils.GetURLFormedMap(req.Queries) 66 // do request 67 httpUrl := fmt.Sprintf("%s://%s%s?%s", req.Protocol, req.Host, req.Path, querystring) 68 if req.URL != "" { 69 httpUrl = req.URL 70 } 71 72 var body io.Reader 73 if req.Method == "GET" { 74 body = strings.NewReader("") 75 } else if req.Body != nil { 76 body = bytes.NewReader(req.Body) 77 } else { 78 body = strings.NewReader(utils.GetURLFormedMap(req.Form)) 79 } 80 81 httpRequest, err := newRequest(req.Method, httpUrl, body) 82 if err != nil { 83 return 84 } 85 86 if req.Form != nil { 87 httpRequest.Header["Content-Type"] = []string{"application/x-www-form-urlencoded"} 88 } 89 90 for key, value := range req.Headers { 91 if value != "" { 92 debuglog("> %s: %s", key, value) 93 httpRequest.Header.Set(key, value) 94 } 95 } 96 97 httpClient := &http.Client{} 98 99 if req.ReadTimeout != 0 { 100 httpClient.Timeout = req.ReadTimeout + req.ConnectTimeout 101 } 102 103 transport := http.DefaultTransport.(*http.Transport).Clone() 104 if req.Proxy != "" { 105 var proxy *url.URL 106 proxy, err = url.Parse(req.Proxy) 107 if err != nil { 108 return 109 } 110 transport.Proxy = http.ProxyURL(proxy) 111 } 112 113 if req.ConnectTimeout != 0 { 114 transport.DialContext = func(ctx context.Context, network, address string) (net.Conn, error) { 115 return (&net.Dialer{ 116 Timeout: req.ConnectTimeout, 117 DualStack: true, 118 }).DialContext(ctx, network, address) 119 } 120 } 121 122 httpClient.Transport = transport 123 124 httpResponse, err := hookDo(httpClient.Do)(httpRequest) 125 if err != nil { 126 return 127 } 128 129 defer httpResponse.Body.Close() 130 131 responseBody, err := ioutil.ReadAll(httpResponse.Body) 132 if err != nil { 133 return 134 } 135 res = &Response{ 136 StatusCode: httpResponse.StatusCode, 137 Headers: make(map[string]string), 138 Body: responseBody, 139 } 140 for key, v := range httpResponse.Header { 141 res.Headers[key] = v[0] 142 } 143 144 return 145 }