|
|
|
package requestapi
|
|
|
|
|
|
|
|
import (
|
|
|
|
"bytes"
|
|
|
|
"crypto/tls"
|
|
|
|
"errors"
|
|
|
|
"fmt"
|
|
|
|
"io"
|
|
|
|
"io/ioutil"
|
|
|
|
"net/http"
|
|
|
|
"time"
|
|
|
|
|
|
|
|
"github.com/ajikamaludin/go-grpc_basic/pkg/v1/cert"
|
|
|
|
"github.com/ajikamaludin/go-grpc_basic/pkg/v1/utils/constants"
|
|
|
|
"github.com/ajikamaludin/go-grpc_basic/pkg/v1/utils/logger"
|
|
|
|
)
|
|
|
|
|
|
|
|
// Info is the http req info
|
|
|
|
type ReqInfo struct {
|
|
|
|
URL string
|
|
|
|
Method string
|
|
|
|
HeadersInfo map[string]interface{}
|
|
|
|
Body []byte
|
|
|
|
}
|
|
|
|
|
|
|
|
type ResInfo struct {
|
|
|
|
StatusCode int
|
|
|
|
Header http.Header
|
|
|
|
Body []byte
|
|
|
|
}
|
|
|
|
|
|
|
|
func Invoke(reqinf *ReqInfo, timeout time.Duration, crt *cert.Cert) (*ResInfo, error) {
|
|
|
|
var req *http.Request
|
|
|
|
var err error
|
|
|
|
|
|
|
|
// STORE request log
|
|
|
|
err = logger.StoreHifRequest(reqinf.URL, "", reqinf.Body, reqinf.HeadersInfo)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
switch reqinf.Method {
|
|
|
|
case constants.MethodGET:
|
|
|
|
req, err = http.NewRequest(constants.MethodGET, reqinf.URL, nil)
|
|
|
|
case constants.MethodPOST:
|
|
|
|
req, err = http.NewRequest(constants.MethodPOST, reqinf.URL, bytes.NewReader(reqinf.Body))
|
|
|
|
}
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
// set header
|
|
|
|
for key, value := range reqinf.HeadersInfo {
|
|
|
|
req.Header.Add(key, value.(string))
|
|
|
|
}
|
|
|
|
|
|
|
|
// execute
|
|
|
|
cl := newHTTPCLientCrt(crt, timeout)
|
|
|
|
|
|
|
|
res, err := cl.Do(req)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
defer res.Body.Close()
|
|
|
|
|
|
|
|
var bufs bytes.Buffer
|
|
|
|
|
|
|
|
// duplicate streams
|
|
|
|
resdup := io.TeeReader(res.Body, &bufs)
|
|
|
|
|
|
|
|
// STORE response log
|
|
|
|
err = logger.StoreHifResponse(reqinf.URL, "", res.StatusCode, res.Header, resdup)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
if !(res.StatusCode == http.StatusOK || res.StatusCode == http.StatusCreated) {
|
|
|
|
return nil, errors.New(fmt.Sprintf("%v for %v", res.StatusCode, reqinf.URL))
|
|
|
|
}
|
|
|
|
|
|
|
|
// read body
|
|
|
|
buf, err := ioutil.ReadAll(&bufs)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return &ResInfo{
|
|
|
|
StatusCode: res.StatusCode,
|
|
|
|
Body: buf,
|
|
|
|
}, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func newHTTPCLientCrt(crt *cert.Cert, timeout time.Duration) *http.Client {
|
|
|
|
// define the default http client
|
|
|
|
defaultRoundTripper := http.DefaultTransport
|
|
|
|
defaultTransportPtr, _ := defaultRoundTripper.(*http.Transport)
|
|
|
|
tr := defaultTransportPtr.Clone()
|
|
|
|
|
|
|
|
if crt == nil {
|
|
|
|
return &http.Client{
|
|
|
|
Timeout: timeout,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// use cert
|
|
|
|
tr.TLSClientConfig = &tls.Config{
|
|
|
|
RootCAs: crt.Pool,
|
|
|
|
}
|
|
|
|
if crt.AllowSkip {
|
|
|
|
tr.TLSClientConfig = &tls.Config{
|
|
|
|
InsecureSkipVerify: true,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// define the max connection idle
|
|
|
|
tr.MaxIdleConns = 100
|
|
|
|
tr.MaxIdleConnsPerHost = 20
|
|
|
|
|
|
|
|
return &http.Client{
|
|
|
|
Timeout: timeout,
|
|
|
|
Transport: tr,
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|