2023-10-04 13:48:21 +00:00
|
|
|
package httptool
|
|
|
|
|
|
|
|
import (
|
2023-10-14 06:57:57 +00:00
|
|
|
"bytes"
|
|
|
|
"encoding/json"
|
|
|
|
"errors"
|
|
|
|
"fmt"
|
|
|
|
"github.com/fthvgb1/wp-go/helper/maps"
|
|
|
|
"github.com/fthvgb1/wp-go/helper/number"
|
|
|
|
str "github.com/fthvgb1/wp-go/helper/strings"
|
|
|
|
"golang.org/x/exp/constraints"
|
2023-10-04 13:48:21 +00:00
|
|
|
"io"
|
2023-10-14 06:57:57 +00:00
|
|
|
"mime/multipart"
|
2023-10-04 13:48:21 +00:00
|
|
|
"net/http"
|
|
|
|
"net/url"
|
2023-10-14 06:57:57 +00:00
|
|
|
"os"
|
|
|
|
"strings"
|
2023-10-04 13:48:21 +00:00
|
|
|
"time"
|
|
|
|
)
|
|
|
|
|
2023-10-14 06:57:57 +00:00
|
|
|
func GetString(u string, q map[string]any, a ...any) (r string, code int, err error) {
|
|
|
|
res, err := Get(u, q, a...)
|
2023-10-04 13:48:21 +00:00
|
|
|
if res != nil {
|
|
|
|
code = res.StatusCode
|
|
|
|
}
|
|
|
|
if err != nil {
|
|
|
|
return "", code, err
|
|
|
|
}
|
|
|
|
defer res.Body.Close()
|
|
|
|
rr, err := io.ReadAll(res.Body)
|
|
|
|
if err != nil {
|
|
|
|
return "", code, err
|
|
|
|
}
|
|
|
|
r = string(rr)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2023-10-14 06:57:57 +00:00
|
|
|
func Get(u string, q map[string]any, a ...any) (res *http.Response, err error) {
|
2024-06-12 09:51:47 +00:00
|
|
|
cli, req, err := BuildClient(u, "get", q, a...)
|
2023-10-14 06:57:57 +00:00
|
|
|
res, err = cli.Do(req)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
func GetToJsonAny[T any](u string, q map[string]any, a ...any) (r T, code int, err error) {
|
|
|
|
rr, err := Get(u, q, a...)
|
2023-10-04 13:48:21 +00:00
|
|
|
if err != nil {
|
2023-10-14 06:57:57 +00:00
|
|
|
return
|
2023-10-04 13:48:21 +00:00
|
|
|
}
|
2023-10-14 06:57:57 +00:00
|
|
|
code = rr.StatusCode
|
|
|
|
b, err := io.ReadAll(rr.Body)
|
|
|
|
if err != nil {
|
|
|
|
return
|
2023-10-04 13:48:21 +00:00
|
|
|
}
|
2024-06-06 14:59:03 +00:00
|
|
|
defer rr.Body.Close()
|
2023-10-14 06:57:57 +00:00
|
|
|
err = json.Unmarshal(b, &r)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
func PostWwwString(u string, form map[string]any, a ...any) (r string, code int, err error) {
|
|
|
|
rr, err := Post(u, 1, form, a...)
|
|
|
|
if err != nil {
|
|
|
|
return "", 0, err
|
|
|
|
}
|
|
|
|
code = rr.StatusCode
|
|
|
|
rs, err := io.ReadAll(rr.Body)
|
|
|
|
if err != nil {
|
|
|
|
return "", code, err
|
|
|
|
}
|
2024-06-06 14:59:03 +00:00
|
|
|
defer rr.Body.Close()
|
2023-10-14 06:57:57 +00:00
|
|
|
r = string(rs)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
func PostFormDataString(u string, form map[string]any, a ...any) (r string, code int, err error) {
|
|
|
|
rr, err := Post(u, 2, form, a...)
|
|
|
|
if err != nil {
|
|
|
|
return "", 0, err
|
|
|
|
}
|
|
|
|
code = rr.StatusCode
|
|
|
|
rs, err := io.ReadAll(rr.Body)
|
|
|
|
if err != nil {
|
|
|
|
return "", code, err
|
2023-10-04 13:48:21 +00:00
|
|
|
}
|
2024-06-06 14:59:03 +00:00
|
|
|
defer rr.Body.Close()
|
2023-10-14 06:57:57 +00:00
|
|
|
r = string(rs)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2024-06-12 09:51:47 +00:00
|
|
|
func BuildClient(u, method string, q map[string]any, a ...any) (res *http.Client, req *http.Request, err error) {
|
2023-10-14 06:57:57 +00:00
|
|
|
parse, err := url.Parse(u)
|
|
|
|
if err != nil {
|
|
|
|
return nil, nil, err
|
|
|
|
}
|
|
|
|
cli := http.Client{}
|
|
|
|
values := parse.Query()
|
|
|
|
setValue(q, values)
|
2023-10-04 13:48:21 +00:00
|
|
|
parse.RawQuery = values.Encode()
|
2023-10-14 06:57:57 +00:00
|
|
|
req = &http.Request{
|
2024-06-12 09:51:47 +00:00
|
|
|
Method: strings.ToUpper(method),
|
2023-10-04 13:48:21 +00:00
|
|
|
URL: parse,
|
|
|
|
}
|
2024-06-06 14:59:03 +00:00
|
|
|
SetArgs(&cli, req, a...)
|
2023-10-14 06:57:57 +00:00
|
|
|
return &cli, req, err
|
|
|
|
}
|
|
|
|
|
|
|
|
// Post request
|
|
|
|
//
|
|
|
|
// u url
|
|
|
|
//
|
|
|
|
// types 1 x-www-form-urlencoded, 2 form-data, 3 json, 4 binary
|
|
|
|
func Post(u string, types int, form map[string]any, a ...any) (res *http.Response, err error) {
|
|
|
|
cli, req, err := PostClient(u, types, form, a...)
|
|
|
|
res, err = cli.Do(req)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2024-06-10 09:44:41 +00:00
|
|
|
// SetBody
|
|
|
|
// types 1 x-www-form-urlencoded, 2 form-data, 3 json, 4 binary
|
|
|
|
func SetBody(req *http.Request, types int, form map[string]any) (err error) {
|
2023-10-14 06:57:57 +00:00
|
|
|
switch types {
|
|
|
|
case 1:
|
|
|
|
values := url.Values{}
|
|
|
|
setValue(form, values)
|
|
|
|
req.Header.Add("Content-Type", "application/x-www-form-urlencoded")
|
|
|
|
b := strings.NewReader(values.Encode())
|
|
|
|
req.Body = io.NopCloser(b)
|
|
|
|
case 2:
|
|
|
|
payload := &bytes.Buffer{}
|
|
|
|
writer := multipart.NewWriter(payload)
|
|
|
|
err = setFormData(form, writer)
|
|
|
|
if err != nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
err = writer.Close()
|
|
|
|
if err != nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
req.Body = io.NopCloser(payload)
|
|
|
|
req.Header.Add("Content-Type", writer.FormDataContentType())
|
|
|
|
case 3:
|
|
|
|
fo, err := json.Marshal(form)
|
|
|
|
if err != nil {
|
2024-06-10 09:44:41 +00:00
|
|
|
return err
|
2023-10-14 06:57:57 +00:00
|
|
|
}
|
|
|
|
b := bytes.NewReader(fo)
|
|
|
|
req.Body = io.NopCloser(b)
|
|
|
|
req.Header.Add("Content-Type", "application/json")
|
|
|
|
case 4:
|
|
|
|
b, ok := maps.GetStrAnyVal[[]byte](form, "binary")
|
2024-06-10 14:50:18 +00:00
|
|
|
if ok {
|
|
|
|
req.Body = io.NopCloser(bytes.NewReader(b))
|
|
|
|
req.Header.Add("Content-Type", "application/octet-stream")
|
|
|
|
req.ContentLength = int64(len(b))
|
|
|
|
return
|
|
|
|
}
|
|
|
|
bb, ok := maps.GetStrAnyVal[*[]byte](form, "binary")
|
2024-06-19 08:10:42 +00:00
|
|
|
if ok {
|
|
|
|
req.Body = io.NopCloser(NewBodyBuffer(bb))
|
|
|
|
req.Header.Add("Content-Type", "application/octet-stream")
|
|
|
|
req.ContentLength = int64(len(*bb))
|
|
|
|
return
|
2023-10-14 06:57:57 +00:00
|
|
|
}
|
2024-06-19 08:10:42 +00:00
|
|
|
bf, ok := maps.GetStrAnyVal[*BodyBuffer](form, "binary")
|
|
|
|
if ok {
|
|
|
|
req.Body = bf
|
|
|
|
req.Header.Add("Content-Type", "application/octet-stream")
|
|
|
|
req.ContentLength = int64(len(*bf.Data))
|
|
|
|
return
|
|
|
|
}
|
|
|
|
return errors.New("no binary value")
|
2024-06-10 14:50:18 +00:00
|
|
|
|
2024-06-10 09:44:41 +00:00
|
|
|
}
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2024-06-10 14:50:18 +00:00
|
|
|
type BodyBuffer struct {
|
2024-06-19 08:10:42 +00:00
|
|
|
Offset int
|
|
|
|
Data *[]byte
|
|
|
|
ReadFn func([]byte) (int, error)
|
|
|
|
CloseFn func() error
|
2024-06-10 14:50:18 +00:00
|
|
|
}
|
|
|
|
|
2024-06-19 08:10:42 +00:00
|
|
|
func (b *BodyBuffer) Close() error {
|
|
|
|
if b.CloseFn != nil {
|
|
|
|
return b.CloseFn()
|
2024-06-10 14:50:18 +00:00
|
|
|
}
|
2024-06-19 08:10:42 +00:00
|
|
|
b.Offset = 0
|
|
|
|
return nil
|
2024-06-10 14:50:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (b *BodyBuffer) Read(p []byte) (int, error) {
|
2024-06-19 08:10:42 +00:00
|
|
|
return b.ReadFn(p)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (b *BodyBuffer) Reads(p []byte) (int, error) {
|
2024-06-10 18:21:57 +00:00
|
|
|
data := (*b.Data)[b.Offset:]
|
|
|
|
if len(p) <= len(data) {
|
|
|
|
copy(p, data[0:len(p)])
|
|
|
|
b.Offset += len(p)
|
2024-06-10 14:50:18 +00:00
|
|
|
return len(p), nil
|
|
|
|
}
|
2024-06-10 18:21:57 +00:00
|
|
|
if len(data) <= 0 {
|
|
|
|
b.Offset = 0
|
2024-06-10 14:50:18 +00:00
|
|
|
return 0, io.EOF
|
|
|
|
}
|
2024-06-10 18:21:57 +00:00
|
|
|
copy(p, data)
|
|
|
|
b.Offset = 0
|
|
|
|
return len(data), io.EOF
|
2024-06-10 14:50:18 +00:00
|
|
|
}
|
|
|
|
|
2024-06-19 08:10:42 +00:00
|
|
|
func NewBodyBuffer(byt *[]byte, readFn ...func(*BodyBuffer, []byte) (int, error)) *BodyBuffer {
|
|
|
|
var fn func([]byte) (int, error)
|
|
|
|
b := &BodyBuffer{Data: byt}
|
|
|
|
if len(readFn) > 1 {
|
|
|
|
fn = func(p []byte) (int, error) {
|
|
|
|
return readFn[0](b, p)
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
fn = b.Reads
|
|
|
|
}
|
|
|
|
b.ReadFn = fn
|
|
|
|
return b
|
2024-06-10 14:50:18 +00:00
|
|
|
}
|
|
|
|
|
2024-06-10 09:44:41 +00:00
|
|
|
func PostClient(u string, types int, form map[string]any, a ...any) (cli *http.Client, req *http.Request, err error) {
|
|
|
|
parse, err := url.Parse(u)
|
|
|
|
if err != nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
cli = &http.Client{}
|
|
|
|
req = &http.Request{
|
|
|
|
Method: "POST",
|
|
|
|
URL: parse,
|
|
|
|
Header: http.Header{},
|
2023-10-14 06:57:57 +00:00
|
|
|
}
|
2024-06-10 18:21:57 +00:00
|
|
|
err = SetBody(req, types, form)
|
|
|
|
if err != nil {
|
|
|
|
return
|
|
|
|
}
|
2024-06-06 14:59:03 +00:00
|
|
|
SetArgs(cli, req, a...)
|
2023-10-14 06:57:57 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
func PostToJsonAny[T any](u string, types int, form map[string]any, a ...any) (r T, code int, err error) {
|
|
|
|
rr, err := Post(u, types, form, a...)
|
|
|
|
if err != nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
code = rr.StatusCode
|
|
|
|
b, err := io.ReadAll(rr.Body)
|
|
|
|
if err != nil {
|
|
|
|
return
|
|
|
|
}
|
2024-06-06 14:59:03 +00:00
|
|
|
defer rr.Body.Close()
|
2023-10-14 06:57:57 +00:00
|
|
|
err = json.Unmarshal(b, &r)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2024-06-06 14:59:03 +00:00
|
|
|
func SetUrl(u string, req *http.Request) error {
|
|
|
|
parse, err := url.Parse(u)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
req.URL = parse
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func RequestToJSON[T any](client *http.Client, req *http.Request, a ...any) (res *http.Response, r T, err error) {
|
|
|
|
SetArgs(client, req, a...)
|
|
|
|
res, err = client.Do(req)
|
|
|
|
if err != nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
bt, err := io.ReadAll(res.Body)
|
|
|
|
if err != nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
err = json.Unmarshal(bt, &r)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
func SetArgs(cli *http.Client, req *http.Request, a ...any) {
|
2023-10-14 06:57:57 +00:00
|
|
|
if len(a) < 1 {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
for _, arg := range a {
|
|
|
|
h, ok := arg.(map[string]string)
|
|
|
|
if ok && len(h) > 0 {
|
2024-06-06 14:59:03 +00:00
|
|
|
if req.Header == nil {
|
|
|
|
req.Header = make(http.Header)
|
|
|
|
}
|
2023-10-14 06:57:57 +00:00
|
|
|
for k, v := range h {
|
|
|
|
req.Header.Add(k, v)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
hh, ok := arg.(http.Header)
|
|
|
|
if ok {
|
|
|
|
req.Header = hh
|
|
|
|
}
|
|
|
|
t, ok := arg.(time.Duration)
|
|
|
|
if ok {
|
|
|
|
cli.Timeout = t
|
|
|
|
}
|
|
|
|
checkRedirect, ok := arg.(func(req *http.Request, via []*http.Request) error)
|
|
|
|
if ok {
|
|
|
|
cli.CheckRedirect = checkRedirect
|
|
|
|
}
|
|
|
|
jar, ok := arg.(http.CookieJar)
|
|
|
|
if ok {
|
|
|
|
cli.Jar = jar
|
|
|
|
}
|
|
|
|
c, ok := arg.(string)
|
|
|
|
if ok && c != "" {
|
2024-06-06 14:59:03 +00:00
|
|
|
if req.Header == nil {
|
|
|
|
req.Header = make(http.Header)
|
|
|
|
}
|
2023-10-14 06:57:57 +00:00
|
|
|
req.Header.Add("cookie", c)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func set[T constraints.Integer | constraints.Float](a []T, k string, values url.Values) {
|
|
|
|
if !strings.Contains(k, "[]") {
|
|
|
|
k = str.Join(k, "[]")
|
|
|
|
}
|
|
|
|
for _, vv := range a {
|
|
|
|
values.Add(k, number.ToString(vv))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func setFormData(m map[string]any, values *multipart.Writer) (err error) {
|
|
|
|
for k, v := range m {
|
|
|
|
switch v.(type) {
|
|
|
|
case *os.File:
|
|
|
|
f := v.(*os.File)
|
|
|
|
if f == nil {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
ff, err := values.CreateFormFile(k, f.Name())
|
|
|
|
if err != nil {
|
|
|
|
return err
|
2023-10-04 13:48:21 +00:00
|
|
|
}
|
2023-10-14 06:57:57 +00:00
|
|
|
_, err = io.Copy(ff, f)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
2023-10-04 13:48:21 +00:00
|
|
|
}
|
2023-10-14 06:57:57 +00:00
|
|
|
case string:
|
|
|
|
err = values.WriteField(k, v.(string))
|
|
|
|
case int64, int, int8, int32, int16, uint64, uint, uint8, uint32, uint16, float32, float64:
|
|
|
|
err = values.WriteField(k, fmt.Sprintf("%v", v))
|
|
|
|
case []string:
|
|
|
|
if !strings.Contains(k, "[]") {
|
|
|
|
k = str.Join(k, "[]")
|
2023-10-04 13:48:21 +00:00
|
|
|
}
|
2023-10-14 06:57:57 +00:00
|
|
|
for _, vv := range v.([]string) {
|
|
|
|
err = values.WriteField(k, vv)
|
2023-10-04 13:48:21 +00:00
|
|
|
}
|
2023-10-14 06:57:57 +00:00
|
|
|
case *[]string:
|
|
|
|
if !strings.Contains(k, "[]") {
|
|
|
|
k = str.Join(k, "[]")
|
|
|
|
}
|
|
|
|
for _, vv := range *(v.(*[]string)) {
|
|
|
|
err = values.WriteField(k, vv)
|
|
|
|
}
|
|
|
|
case []int64:
|
|
|
|
err = sets(v.([]int64), k, values)
|
|
|
|
case []int:
|
|
|
|
err = sets(v.([]int), k, values)
|
|
|
|
case []int8:
|
|
|
|
err = sets(v.([]int8), k, values)
|
|
|
|
case []int16:
|
|
|
|
err = sets(v.([]int16), k, values)
|
|
|
|
case []int32:
|
|
|
|
err = sets(v.([]int32), k, values)
|
|
|
|
case []uint64:
|
|
|
|
err = sets(v.([]uint64), k, values)
|
|
|
|
case []uint:
|
|
|
|
err = sets(v.([]uint), k, values)
|
|
|
|
case []uint8:
|
|
|
|
err = sets(v.([]uint8), k, values)
|
|
|
|
case []uint16:
|
|
|
|
err = sets(v.([]uint16), k, values)
|
|
|
|
case []uint32:
|
|
|
|
err = sets(v.([]uint32), k, values)
|
|
|
|
case []float32:
|
|
|
|
err = sets(v.([]float32), k, values)
|
|
|
|
case []float64:
|
|
|
|
err = sets(v.([]float64), k, values)
|
2023-10-04 13:48:21 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return
|
|
|
|
}
|
2023-10-14 06:57:57 +00:00
|
|
|
|
|
|
|
func sets[T constraints.Integer | constraints.Float](a []T, k string, values *multipart.Writer) error {
|
|
|
|
if !strings.Contains(k, "[]") {
|
|
|
|
k = str.Join(k, "[]")
|
|
|
|
}
|
|
|
|
for _, vv := range a {
|
|
|
|
err := values.WriteField(k, number.ToString(vv))
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func setValue(m map[string]any, values url.Values) {
|
|
|
|
for k, v := range m {
|
|
|
|
switch v.(type) {
|
|
|
|
case string:
|
|
|
|
values.Add(k, v.(string))
|
|
|
|
case int64, int, int8, int32, int16, uint64, uint, uint8, uint32, uint16, float32, float64:
|
|
|
|
values.Add(k, fmt.Sprintf("%v", v))
|
|
|
|
case []string:
|
|
|
|
if !strings.Contains(k, "[]") {
|
|
|
|
k = str.Join(k, "[]")
|
|
|
|
}
|
|
|
|
for _, vv := range v.([]string) {
|
|
|
|
values.Add(k, vv)
|
|
|
|
}
|
|
|
|
case *[]string:
|
|
|
|
if !strings.Contains(k, "[]") {
|
|
|
|
k = str.Join(k, "[]")
|
|
|
|
}
|
|
|
|
for _, vv := range *(v.(*[]string)) {
|
|
|
|
values.Add(k, vv)
|
|
|
|
}
|
|
|
|
case []int64:
|
|
|
|
set(v.([]int64), k, values)
|
|
|
|
case []int:
|
|
|
|
set(v.([]int), k, values)
|
|
|
|
case []int8:
|
|
|
|
set(v.([]int8), k, values)
|
|
|
|
case []int16:
|
|
|
|
set(v.([]int16), k, values)
|
|
|
|
case []int32:
|
|
|
|
set(v.([]int32), k, values)
|
|
|
|
case []uint64:
|
|
|
|
set(v.([]uint64), k, values)
|
|
|
|
case []uint:
|
|
|
|
set(v.([]uint), k, values)
|
|
|
|
case []uint8:
|
|
|
|
set(v.([]uint8), k, values)
|
|
|
|
case []uint16:
|
|
|
|
set(v.([]uint16), k, values)
|
|
|
|
case []uint32:
|
|
|
|
set(v.([]uint32), k, values)
|
|
|
|
case []float32:
|
|
|
|
set(v.([]float32), k, values)
|
|
|
|
case []float64:
|
|
|
|
set(v.([]float64), k, values)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|