liuhaijun 3f5f28d785 add sheduling agent
Change-Id: I89f35fb3984044c57f10727432755012542f9fd8
2023-11-16 10:55:57 +00:00

184 lines
5.4 KiB
Go

package httputils
import (
"crypto/tls"
"crypto/x509"
"encoding/base64"
"fmt"
"git.inspur.com/sbg-jszt/cfn/cfn-schedule-agent/config"
"io"
"net"
"net/http"
"net/url"
"os"
"time"
)
const DefaultTimeout = 10 * time.Second
func HttpGet(url string, auth *config.Auth, timeout time.Duration, customHeaders map[string]string, cookies []*http.Cookie) ([]byte, int, []*http.Cookie, error) {
req, err := http.NewRequest(http.MethodGet, url, nil)
if err != nil {
return nil, 0, nil, err
}
for _, c := range cookies {
req.AddCookie(c)
}
transport, err := CreateTransport(auth, &http.Transport{}, timeout, customHeaders)
if err != nil {
return nil, 0, nil, err
}
client := http.Client{Transport: transport, Timeout: timeout}
resp, err := client.Do(req)
if err != nil {
return nil, 0, nil, err
}
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
return body, resp.StatusCode, resp.Cookies(), err
}
// HttpPost sends an HTTP Post request to the given URL and returns the response body.
func HttpPost(url string, auth *config.Auth, body io.Reader, timeout time.Duration, customHeaders map[string]string) ([]byte, int, []*http.Cookie, error) {
req, err := http.NewRequest(http.MethodPost, url, body)
if err != nil {
return nil, 0, nil, err
}
transport, err := CreateTransport(auth, &http.Transport{TLSClientConfig: &tls.Config{InsecureSkipVerify: true}}, timeout, customHeaders)
if err != nil {
return nil, 0, nil, err
}
client := http.Client{Transport: transport, Timeout: timeout}
resp, err := client.Do(req)
if err != nil {
return nil, 0, nil, err
}
defer resp.Body.Close()
respBody, err := io.ReadAll(resp.Body)
return respBody, resp.StatusCode, resp.Cookies(), err
}
// Url拼接的部分Query条件
func ConvertToQueryParams(requrl string, params map[string]string) string {
data := url.Values{}
for key, value := range params {
data.Set(key, value)
}
u, _ := url.ParseRequestURI(requrl)
u.RawQuery = data.Encode()
return u.String()
}
type authRoundTripper struct {
auth string
originalRT http.RoundTripper
}
type customHeadersRoundTripper struct {
headers map[string]string
originalRT http.RoundTripper
}
func (rt *authRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) {
req.Header.Set("Authorization", rt.auth)
return rt.originalRT.RoundTrip(req)
}
func (rt *customHeadersRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) {
// note: no need to check for nil or empty map - newCustomHeadersRoundTripper will assure us there will always be at least 1
for k, v := range rt.headers {
req.Header.Set(k, v)
}
return rt.originalRT.RoundTrip(req)
}
func newAuthRoundTripper(auth *config.Auth, rt http.RoundTripper) http.RoundTripper {
switch auth.Type {
case config.AuthTypeBearer:
token := auth.Token
return &authRoundTripper{auth: "Bearer " + token, originalRT: rt}
case config.AuthTypeBasic:
encoded := base64.StdEncoding.EncodeToString([]byte(auth.Username + ":" + auth.Password))
return &authRoundTripper{auth: "Basic " + encoded, originalRT: rt}
default:
return rt
}
}
func newCustomHeadersRoundTripper(headers map[string]string, rt http.RoundTripper) http.RoundTripper {
if len(headers) == 0 {
// if there are no custom headers then there is no need for a special RoundTripper; therefore just return the original RoundTripper
return rt
}
return &customHeadersRoundTripper{
headers: headers,
originalRT: rt,
}
}
// Creates a new HTTP Transport with TLS, Timeouts, and optional custom headers.
//
// Please remember that setting long timeouts is not recommended as it can make
// idle connections stay open for as long as 2 * timeout. This should only be
// done in cases where you know the request is very likely going to be reused at
// some point in the near future.
func CreateTransport(auth *config.Auth, transportConfig *http.Transport, timeout time.Duration, customHeaders map[string]string) (http.RoundTripper, error) {
// Limits the time spent establishing a TCP connection if a new one is
// needed. If DialContext is not set, Dial is used, we only create a new one
// if neither is defined.
if transportConfig.DialContext == nil {
transportConfig.DialContext = (&net.Dialer{
Timeout: timeout,
}).DialContext
}
transportConfig.IdleConnTimeout = timeout
// We might need some custom RoundTrippers to manipulate the requests (for auth and other custom request headers).
// Chain together the RoundTrippers that we need, retaining the outer-most round tripper so we can return it.
outerRoundTripper := newCustomHeadersRoundTripper(customHeaders, transportConfig)
if auth != nil {
tlscfg, err := GetTLSConfig(auth)
if err != nil {
return nil, err
}
if tlscfg != nil {
transportConfig.TLSClientConfig = tlscfg
}
outerRoundTripper = newAuthRoundTripper(auth, outerRoundTripper)
}
return outerRoundTripper, nil
}
func GetTLSConfig(auth *config.Auth) (*tls.Config, error) {
if auth.InsecureSkipVerify || auth.CAFile != "" {
var certPool *x509.CertPool
if auth.CAFile != "" {
certPool = x509.NewCertPool()
cert, err := os.ReadFile(auth.CAFile)
if err != nil {
return nil, fmt.Errorf("failed to get root CA certificates: %s", err)
}
if ok := certPool.AppendCertsFromPEM(cert); !ok {
return nil, fmt.Errorf("supplied CA file could not be parsed")
}
}
return &tls.Config{
InsecureSkipVerify: auth.InsecureSkipVerify,
RootCAs: certPool,
}, nil
}
return nil, nil
}