199 lines
5.2 KiB
Go
199 lines
5.2 KiB
Go
package httputil
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"encoding/json"
|
|
"io"
|
|
"mime/multipart"
|
|
"net/http"
|
|
"net/url"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
)
|
|
|
|
func ClientPost(connTimeout int, url string, headers map[string]string, data any) (*http.Response, error) {
|
|
req, err := getPostRequest(url, headers, data)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
cl := getClientByTimeoutSet(connTimeout)
|
|
return cl.Do(req)
|
|
}
|
|
|
|
func DefaultClientPost(url string, headers map[string]string, data any) (*http.Response, error) {
|
|
return ClientPost(defaultTimeOut, url, headers, data)
|
|
}
|
|
|
|
func ClientPostWithCtx(ctx context.Context, connTimeout int, url string, headers map[string]string, data any) (*http.Response, error) {
|
|
req, err := getPostRequest(url, headers, data)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
req = req.WithContext(ctx)
|
|
cl := getClientByTimeoutSet(connTimeout)
|
|
return cl.Do(req)
|
|
}
|
|
|
|
func DefaultClientPostWithCtx(ctx context.Context, url string, headers map[string]string, data any) (*http.Response, error) {
|
|
return ClientPostWithCtx(ctx, defaultTimeOut, url, headers, data)
|
|
}
|
|
|
|
func ClientPostWithProxy(connTimeout int, p *ProxyCfg, url string, headers map[string]string, data any) (*http.Response, error) {
|
|
if p == nil {
|
|
return nil, errProxyNil
|
|
}
|
|
pUrl, pHeaders, err := p.Build(url, headers)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return ClientPost(connTimeout, pUrl, pHeaders, data)
|
|
}
|
|
|
|
func ClientPostWithResp(connTimeout int, bind any, url string, headers map[string]string, data any) (int, error) {
|
|
resp, err := ClientPost(connTimeout, url, headers, data)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
ct, err := io.ReadAll(resp.Body)
|
|
resp.Body.Close()
|
|
if err != nil {
|
|
return resp.StatusCode, err
|
|
}
|
|
return resp.StatusCode, json.Unmarshal(ct, &bind)
|
|
}
|
|
|
|
func DefaultClientPostWithResp(bind any, url string, headers map[string]string, data any) (int, error) {
|
|
return ClientPostWithResp(defaultTimeOut, bind, url, headers, data)
|
|
}
|
|
|
|
func ClientPostWithRespWithCtx(ctx context.Context, connTimeout int, bind any, url string, headers map[string]string, data any) (int, error) {
|
|
resp, err := ClientPostWithCtx(ctx, connTimeout, url, headers, data)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
ct, err := io.ReadAll(resp.Body)
|
|
resp.Body.Close()
|
|
if err != nil {
|
|
return resp.StatusCode, err
|
|
}
|
|
return resp.StatusCode, json.Unmarshal(ct, &bind)
|
|
}
|
|
|
|
func DefaultClientPostWithRespWithCtx(ctx context.Context, bind any, url string, headers map[string]string, data any) (int, error) {
|
|
return ClientPostWithRespWithCtx(ctx, defaultTimeOut, bind, url, headers, data)
|
|
}
|
|
|
|
func ClientPostWithRespWithProxy(connTimeout int, p *ProxyCfg, bind any, url string, headers map[string]string, data any) (int, error) {
|
|
resp, err := ClientPostWithProxy(connTimeout, p, url, headers, data)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
ct, err := io.ReadAll(resp.Body)
|
|
resp.Body.Close()
|
|
if err != nil {
|
|
return resp.StatusCode, err
|
|
}
|
|
return resp.StatusCode, json.Unmarshal(ct, &bind)
|
|
}
|
|
|
|
func DefaultClientPostWithRespWithProxy(p *ProxyCfg, bind any, url string, headers map[string]string, data any) (int, error) {
|
|
return ClientPostWithRespWithProxy(defaultTimeOut, p, &bind, url, headers, data)
|
|
}
|
|
|
|
func getPostRequest(url string, headers map[string]string, data any) (*http.Request, error) {
|
|
switch data.(type) {
|
|
case []byte, string, *bytes.Reader, *bytes.Buffer:
|
|
req, err := http.NewRequest(http.MethodPost, url, toReader(data))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
for k, v := range headers {
|
|
req.Header.Set(k, v)
|
|
}
|
|
return req, nil
|
|
default:
|
|
}
|
|
paramsValues := toUrlValues(data)
|
|
if checkParamFile(paramsValues) {
|
|
body := &bytes.Buffer{}
|
|
writer := multipart.NewWriter(body)
|
|
for k, v := range paramsValues {
|
|
for _, vv := range v {
|
|
// is file
|
|
if k[0] == '@' {
|
|
if err := addFormFile(writer, k[1:], vv); err != nil {
|
|
return nil, err
|
|
}
|
|
continue
|
|
}
|
|
_ = writer.WriteField(k, vv)
|
|
}
|
|
}
|
|
req, err := http.NewRequest(http.MethodPost, url, body)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
for k, v := range headers {
|
|
req.Header.Set(k, v)
|
|
}
|
|
req.Header.Set("Content-Type", writer.FormDataContentType())
|
|
if err = writer.Close(); err != nil {
|
|
return nil, err
|
|
}
|
|
return req, nil
|
|
}
|
|
req, err := http.NewRequest(http.MethodPost, url, strings.NewReader(paramsValues.Encode()))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
|
|
for k, v := range headers {
|
|
req.Header.Set(k, v)
|
|
}
|
|
return req, nil
|
|
}
|
|
|
|
func toReader(v interface{}) *bytes.Reader {
|
|
switch t := v.(type) {
|
|
case []byte:
|
|
return bytes.NewReader(t)
|
|
case string:
|
|
return bytes.NewReader([]byte(t))
|
|
case *bytes.Buffer:
|
|
return bytes.NewReader(t.Bytes())
|
|
case *bytes.Reader:
|
|
return t
|
|
case nil:
|
|
return bytes.NewReader(nil)
|
|
default:
|
|
panic("Invalid value")
|
|
}
|
|
}
|
|
|
|
// Does the params contain a file?
|
|
func checkParamFile(params url.Values) bool {
|
|
for k := range params {
|
|
if k[0] == '@' {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
// Add a file to a multipart writer.
|
|
func addFormFile(writer *multipart.Writer, name, path string) error {
|
|
file, err := os.Open(path)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer file.Close()
|
|
part, err := writer.CreateFormFile(name, filepath.Base(path))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
_, err = io.Copy(part, file)
|
|
return err
|
|
}
|