Compare commits
3 Commits
Author | SHA1 | Date | |
---|---|---|---|
9f29f019ad | |||
63c8b46474 | |||
|
4744b3d3c0 |
4
.gitignore
vendored
Normal file
4
.gitignore
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
.idea/
|
||||
*/.DS_Store
|
||||
.vscode
|
||||
go.sum
|
25
client.go
25
client.go
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* @Author: fuxiao
|
||||
* @Email: 576101059@qq.com
|
||||
* @Author: Echo
|
||||
* @Email: 1711788888@qq.com
|
||||
* @Date: 2021/8/14 4:11 下午
|
||||
* @Desc: TODO
|
||||
*/
|
||||
@@ -29,13 +29,13 @@ type Client struct {
|
||||
|
||||
const (
|
||||
defaultUserAgent = "DobyteHttpClient"
|
||||
|
||||
|
||||
HeaderUserAgent = "User-Agent"
|
||||
HeaderContentType = "Content-Type"
|
||||
HeaderAuthorization = "Authorization"
|
||||
HeaderCookie = "Cookie"
|
||||
HeaderHost = "Host"
|
||||
|
||||
|
||||
ContentTypeJson = "application/json"
|
||||
ContentTypeXml = "application/xml"
|
||||
ContentTypeFormData = "form-data"
|
||||
@@ -57,7 +57,7 @@ func NewClient() *Client {
|
||||
middlewares: make([]MiddlewareFunc, 0),
|
||||
}
|
||||
client.headers[HeaderUserAgent] = defaultUserAgent
|
||||
|
||||
|
||||
return client
|
||||
}
|
||||
|
||||
@@ -155,42 +155,57 @@ func (c *Client) Use(middlewares ...MiddlewareFunc) *Client {
|
||||
return c
|
||||
}
|
||||
|
||||
// Download download a file from the network address to the local.
|
||||
func (c *Client) Download(url, dir string, filename ...string) (string, error) {
|
||||
return NewDownload(c).Download(url, dir, filename...)
|
||||
}
|
||||
|
||||
// Request send an http request.
|
||||
func (c *Client) Request(method, url string, data ...interface{}) (*Response, error) {
|
||||
return NewRequest(c).request(method, url, data...)
|
||||
}
|
||||
|
||||
// Get send an http request use get method.
|
||||
func (c *Client) Get(url string, data ...interface{}) (*Response, error) {
|
||||
return c.Request(MethodGet, url, data...)
|
||||
}
|
||||
|
||||
// Post send an http request use post method.
|
||||
func (c *Client) Post(url string, data ...interface{}) (*Response, error) {
|
||||
return c.Request(MethodPost, url, data...)
|
||||
}
|
||||
|
||||
// Put send an http request use put method.
|
||||
func (c *Client) Put(url string, data ...interface{}) (*Response, error) {
|
||||
return c.Request(MethodPut, url, data...)
|
||||
}
|
||||
|
||||
// Patch send an http request use patch method.
|
||||
func (c *Client) Patch(url string, data ...interface{}) (*Response, error) {
|
||||
return c.Request(MethodPatch, url, data...)
|
||||
}
|
||||
|
||||
// Delete send an http request use patch method.
|
||||
func (c *Client) Delete(url string, data ...interface{}) (*Response, error) {
|
||||
return c.Request(MethodDelete, url, data...)
|
||||
}
|
||||
|
||||
// Head send an http request use head method.
|
||||
func (c *Client) Head(url string, data ...interface{}) (*Response, error) {
|
||||
return c.Request(MethodHead, url, data...)
|
||||
}
|
||||
|
||||
// Options send an http request use options method.
|
||||
func (c *Client) Options(url string, data ...interface{}) (*Response, error) {
|
||||
return c.Request(MethodOptions, url, data...)
|
||||
}
|
||||
|
||||
// Connect send an http request use connect method.
|
||||
func (c *Client) Connect(url string, data ...interface{}) (*Response, error) {
|
||||
return c.Request(MethodConnect, url, data...)
|
||||
}
|
||||
|
||||
// Trace send an http request use trace method.
|
||||
func (c *Client) Trace(url string, data ...interface{}) (*Response, error) {
|
||||
return c.Request(MethodTrace, url, data...)
|
||||
}
|
||||
|
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* @Author: fuxiao
|
||||
* @Email: 576101059@qq.com
|
||||
* @Author: Echo
|
||||
* @Email: 1711788888@qq.com
|
||||
* @Date: 2021/8/16 2:54 下午
|
||||
* @Desc: TODO
|
||||
*/
|
||||
@@ -10,8 +10,8 @@ package http_test
|
||||
import (
|
||||
"errors"
|
||||
"testing"
|
||||
|
||||
"github.com/dobyte/http"
|
||||
|
||||
"git.echol.cn/loser/http"
|
||||
)
|
||||
|
||||
const token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlc2MiOjE2MjgwNDAzMjYxNTQ2MzIwMDAsImV4cCI6MTYyODIyMDMyNiwiaWF0IjoxNjI4MDQwMzI2LCJpZCI6MX0.KM19c6URIih-5SyycYIjNAdSiPKxMQEz3DoROm0N3nw"
|
||||
@@ -23,13 +23,13 @@ func TestClient_Request(t *testing.T) {
|
||||
}).Use(func(r *http.Request) (*http.Response, error) {
|
||||
return nil, errors.New("Invalid params.")
|
||||
})
|
||||
|
||||
|
||||
resp, err := client.Request(http.MethodGet, "/common/regions")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
t.Log(resp.Response.Status)
|
||||
}
|
||||
|
||||
@@ -42,7 +42,7 @@ func TestClient_Post(t *testing.T) {
|
||||
r.Request.Header.Set("Client-Type", "2")
|
||||
return r.Next()
|
||||
})
|
||||
|
||||
|
||||
type updateRegionArg struct {
|
||||
Id int `json:"id"`
|
||||
Pid int `json:"pid"`
|
||||
@@ -50,7 +50,7 @@ func TestClient_Post(t *testing.T) {
|
||||
Name string `json:"name"`
|
||||
Sort int `json:"sort"`
|
||||
}
|
||||
|
||||
|
||||
data := updateRegionArg{
|
||||
Id: 1,
|
||||
Pid: 0,
|
||||
@@ -58,24 +58,27 @@ func TestClient_Post(t *testing.T) {
|
||||
Name: "北京市",
|
||||
Sort: 0,
|
||||
}
|
||||
|
||||
//data := map[string]interface{}{
|
||||
// "id": 1,
|
||||
// "pid": 0,
|
||||
// "code": "110000",
|
||||
// "name": "北京市",
|
||||
// "sort": 0,
|
||||
//}
|
||||
|
||||
|
||||
if resp, err := client.Put("/backend/region/update-region", data); err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
} else {
|
||||
t.Log(resp.Response.Status)
|
||||
t.Log(resp.Response.Header)
|
||||
t.Log(resp.Bytes())
|
||||
t.Log(resp.String())
|
||||
t.Log(resp.ReadBytes())
|
||||
t.Log(resp.ReadString())
|
||||
t.Log(resp.GetHeaders())
|
||||
t.Log(resp.GetCookies())
|
||||
}
|
||||
}
|
||||
|
||||
func TestClient_Download(t *testing.T) {
|
||||
url := "https://www.baidu.com/img/PCtm_d9c8750bed0b3c7d089fa7d55720d6cf.png"
|
||||
|
||||
if path, err := http.NewClient().Download(url, "./"); err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
} else {
|
||||
t.Log(path)
|
||||
}
|
||||
}
|
||||
|
86
download.go
Normal file
86
download.go
Normal file
@@ -0,0 +1,86 @@
|
||||
/**
|
||||
* @Author: Echo
|
||||
* @Email: 1711788888@qq.com
|
||||
* @Date: 2021/8/26 1:59 下午
|
||||
* @Desc: TODO
|
||||
*/
|
||||
|
||||
package http
|
||||
|
||||
import (
|
||||
"git.echol.cn/loser/http/internal"
|
||||
"os"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var contentTypeToFileSuffix = map[string]string{
|
||||
"application/x-001": ".001",
|
||||
"text/h323": ".323",
|
||||
"drawing/907": ".907",
|
||||
"audio/x-mei-aac": ".acp",
|
||||
"audio/aiff": ".aif",
|
||||
"text/asa": ".asa",
|
||||
"text/asp": ".asp",
|
||||
"audio/basic": ".au",
|
||||
"application/vnd.adobe.workflow": ".awf",
|
||||
"application/x-bmp": ".bmp",
|
||||
"application/x-c4t": ".c4t",
|
||||
"application/x-cals": ".cal",
|
||||
"application/x-netcdf": ".cdf",
|
||||
"application/x-cel": ".cel",
|
||||
"application/x-g4": ".cg4",
|
||||
"application/x-cit": ".cit",
|
||||
"text/xml": ".cml",
|
||||
"application/x-cmx": ".cmx",
|
||||
"application/pkix-crl": ".crl",
|
||||
"application/x-csi": ".csi",
|
||||
"application/x-cut": ".cut",
|
||||
"application/x-dbm": ".dbm",
|
||||
}
|
||||
|
||||
type Download struct {
|
||||
request *Request
|
||||
}
|
||||
|
||||
func NewDownload(c *Client) *Download {
|
||||
return &Download{
|
||||
request: NewRequest(c),
|
||||
}
|
||||
}
|
||||
|
||||
// Download download a file from the network address to the local.
|
||||
func (d *Download) Download(url, dir string, filename ...string) (string, error) {
|
||||
resp, err := d.request.request(MethodGet, url)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
var path string
|
||||
|
||||
if len(filename) > 0 {
|
||||
path = strings.TrimRight(dir, string(os.PathSeparator)) + string(os.PathSeparator) + filename[0]
|
||||
} else {
|
||||
path = d.genFilePath(resp, dir)
|
||||
}
|
||||
|
||||
if err = internal.SaveToFile(path, resp.ReadBytes()); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return path, nil
|
||||
}
|
||||
|
||||
// genFilePath generate file path based on response content type
|
||||
func (d *Download) genFilePath(resp *Response, dir string) string {
|
||||
path := strings.TrimRight(dir, string(os.PathSeparator)) + string(os.PathSeparator) + internal.RandStr(16)
|
||||
|
||||
if suffix := internal.GetFileType(resp.ReadBytes()); suffix != "" {
|
||||
path += "." + suffix
|
||||
}
|
||||
|
||||
if internal.Exists(path) {
|
||||
return d.genFilePath(resp, dir)
|
||||
}
|
||||
|
||||
return path
|
||||
}
|
234
internal/conv.go
Normal file
234
internal/conv.go
Normal file
@@ -0,0 +1,234 @@
|
||||
/**
|
||||
* @Author: Echo
|
||||
* @Email: 1711788888@qq.com
|
||||
* @Date: 2021/8/26 5:00 下午
|
||||
* @Desc: TODO
|
||||
*/
|
||||
|
||||
package internal
|
||||
|
||||
import (
|
||||
"encoding"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"time"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
type stringInterface interface {
|
||||
String() string
|
||||
}
|
||||
|
||||
type errorInterface interface {
|
||||
Error() string
|
||||
}
|
||||
|
||||
func String(any interface{}) string {
|
||||
switch v := any.(type) {
|
||||
case nil:
|
||||
return ""
|
||||
case string:
|
||||
return v
|
||||
case int:
|
||||
return strconv.Itoa(v)
|
||||
case int8:
|
||||
return strconv.Itoa(int(v))
|
||||
case int16:
|
||||
return strconv.Itoa(int(v))
|
||||
case int32:
|
||||
return strconv.Itoa(int(v))
|
||||
case int64:
|
||||
return strconv.FormatInt(v, 10)
|
||||
case uint:
|
||||
return strconv.FormatUint(uint64(v), 10)
|
||||
case uint8:
|
||||
return strconv.FormatUint(uint64(v), 10)
|
||||
case uint16:
|
||||
return strconv.FormatUint(uint64(v), 10)
|
||||
case uint64:
|
||||
return strconv.FormatUint(v, 10)
|
||||
case float32:
|
||||
return strconv.FormatFloat(float64(v), 'f', -1, 32)
|
||||
case float64:
|
||||
return strconv.FormatFloat(v, 'f', -1, 64)
|
||||
case bool:
|
||||
return strconv.FormatBool(v)
|
||||
case []byte:
|
||||
return string(v)
|
||||
case time.Time:
|
||||
return v.String()
|
||||
case *time.Time:
|
||||
if v == nil {
|
||||
return ""
|
||||
}
|
||||
return v.String()
|
||||
default:
|
||||
if v == nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
if i, ok := v.(stringInterface); ok {
|
||||
return i.String()
|
||||
}
|
||||
|
||||
if i, ok := v.(errorInterface); ok {
|
||||
return i.Error()
|
||||
}
|
||||
|
||||
var (
|
||||
rv = reflect.ValueOf(v)
|
||||
kind = rv.Kind()
|
||||
)
|
||||
|
||||
switch kind {
|
||||
case reflect.Chan,
|
||||
reflect.Map,
|
||||
reflect.Slice,
|
||||
reflect.Func,
|
||||
reflect.Ptr,
|
||||
reflect.Interface,
|
||||
reflect.UnsafePointer:
|
||||
if rv.IsNil() {
|
||||
return ""
|
||||
}
|
||||
case reflect.String:
|
||||
return rv.String()
|
||||
}
|
||||
|
||||
if kind == reflect.Ptr {
|
||||
return String(rv.Elem().Interface())
|
||||
}
|
||||
|
||||
if b, e := json.Marshal(v); e != nil {
|
||||
return fmt.Sprint(v)
|
||||
} else {
|
||||
return string(b)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func Scan(b []byte, any interface{}) error {
|
||||
switch v := any.(type) {
|
||||
case nil:
|
||||
return fmt.Errorf("cache: Scan(nil)")
|
||||
case *string:
|
||||
*v = String(b)
|
||||
return nil
|
||||
case *[]byte:
|
||||
*v = b
|
||||
return nil
|
||||
case *int:
|
||||
var err error
|
||||
*v, err = strconv.Atoi(String(b))
|
||||
return err
|
||||
case *int8:
|
||||
n, err := strconv.ParseInt(String(b), 10, 8)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
*v = int8(n)
|
||||
return nil
|
||||
case *int16:
|
||||
n, err := strconv.ParseInt(String(b), 10, 16)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
*v = int16(n)
|
||||
return nil
|
||||
case *int32:
|
||||
n, err := strconv.ParseInt(String(b), 10, 32)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
*v = int32(n)
|
||||
return nil
|
||||
case *int64:
|
||||
n, err := strconv.ParseInt(String(b), 10, 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
*v = n
|
||||
return nil
|
||||
case *uint:
|
||||
n, err := strconv.ParseUint(String(b), 10, 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
*v = uint(n)
|
||||
return nil
|
||||
case *uint8:
|
||||
n, err := strconv.ParseUint(String(b), 10, 8)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
*v = uint8(n)
|
||||
return nil
|
||||
case *uint16:
|
||||
n, err := strconv.ParseUint(String(b), 10, 16)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
*v = uint16(n)
|
||||
return nil
|
||||
case *uint32:
|
||||
n, err := strconv.ParseUint(String(b), 10, 32)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
*v = uint32(n)
|
||||
return nil
|
||||
case *uint64:
|
||||
n, err := strconv.ParseUint(String(b), 10, 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
*v = n
|
||||
return nil
|
||||
case *float32:
|
||||
n, err := strconv.ParseFloat(String(b), 32)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
*v = float32(n)
|
||||
return err
|
||||
case *float64:
|
||||
var err error
|
||||
*v, err = strconv.ParseFloat(String(b), 64)
|
||||
return err
|
||||
case *bool:
|
||||
*v = len(b) == 1 && b[0] == '1'
|
||||
return nil
|
||||
case *time.Time:
|
||||
var err error
|
||||
*v, err = time.Parse(time.RFC3339Nano, String(b))
|
||||
return err
|
||||
case encoding.BinaryUnmarshaler:
|
||||
return v.UnmarshalBinary(b)
|
||||
default:
|
||||
var (
|
||||
rv = reflect.ValueOf(v)
|
||||
kind = rv.Kind()
|
||||
)
|
||||
|
||||
if kind != reflect.Ptr {
|
||||
return fmt.Errorf("can't unmarshal %T", v)
|
||||
}
|
||||
|
||||
switch kind = rv.Elem().Kind(); kind {
|
||||
case reflect.Array, reflect.Slice, reflect.Map, reflect.Struct:
|
||||
return json.Unmarshal(b, v)
|
||||
}
|
||||
|
||||
return fmt.Errorf("can't unmarshal %T", v)
|
||||
}
|
||||
}
|
||||
|
||||
func UnsafeStringToBytes(s string) []byte {
|
||||
return *(*[]byte)(unsafe.Pointer(&s))
|
||||
}
|
||||
|
||||
func UnsafeBytesToString(b []byte) string {
|
||||
return *(*string)(unsafe.Pointer(&b))
|
||||
}
|
66
internal/file.go
Normal file
66
internal/file.go
Normal file
@@ -0,0 +1,66 @@
|
||||
/**
|
||||
* @Author: Echo
|
||||
* @Email: 1711788888@qq.com
|
||||
* @Date: 2021/8/26 4:59 下午
|
||||
* @Desc: TODO
|
||||
*/
|
||||
|
||||
package internal
|
||||
|
||||
import (
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
// Exists check if the file or path exists.
|
||||
func Exists(path string) bool {
|
||||
if stat, err := os.Stat(path); stat != nil && !os.IsNotExist(err) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// SaveToFile save data to file.
|
||||
func SaveToFile(path string, data []byte) error {
|
||||
dir := filepath.Dir(path)
|
||||
if !Exists(dir) {
|
||||
if err := MakeDir(dir); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
f, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, os.FileMode(0666))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
if n, err := f.Write(data); err != nil {
|
||||
return err
|
||||
} else if n < len(data) {
|
||||
return io.ErrShortWrite
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// MakeDir create directories recursively.
|
||||
func MakeDir(dir string) error {
|
||||
if err := os.MkdirAll(dir, os.ModePerm); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// RealPath get the real path.
|
||||
func RealPath(path string) string {
|
||||
p, err := filepath.Abs(path)
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
if !Exists(p) {
|
||||
return ""
|
||||
}
|
||||
return p
|
||||
}
|
28
internal/rand.go
Normal file
28
internal/rand.go
Normal file
@@ -0,0 +1,28 @@
|
||||
/**
|
||||
* @Author: Echo
|
||||
* @Email: 1711788888@qq.com
|
||||
* @Date: 2021/8/26 4:51 下午
|
||||
* @Desc: TODO
|
||||
*/
|
||||
|
||||
package internal
|
||||
|
||||
import (
|
||||
"math/rand"
|
||||
"time"
|
||||
)
|
||||
|
||||
var seedStr = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
|
||||
|
||||
// RandStr generate a string of specified length.
|
||||
func RandStr(length int) (lastStr string) {
|
||||
rand.Seed(time.Now().UnixNano())
|
||||
|
||||
pos, seedLen := 0, len(seedStr)
|
||||
for i := 0; i < length; i++ {
|
||||
pos = rand.Intn(seedLen)
|
||||
lastStr += seedStr[pos : pos+1]
|
||||
}
|
||||
|
||||
return lastStr
|
||||
}
|
120
internal/stream.go
Normal file
120
internal/stream.go
Normal file
@@ -0,0 +1,120 @@
|
||||
/**
|
||||
* @Author: Echo
|
||||
* @Email: 1711788888@qq.com
|
||||
* @Date: 2021/8/26 6:21 下午
|
||||
* @Desc: TODO
|
||||
*/
|
||||
|
||||
package internal
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/hex"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
)
|
||||
|
||||
var fileTypeMap sync.Map
|
||||
|
||||
func init() {
|
||||
fileTypeMap.Store("ffd8ffe000104a464946", "jpg")
|
||||
fileTypeMap.Store("89504e470d0a1a0a0000", "png")
|
||||
fileTypeMap.Store("47494638396126026f01", "gif")
|
||||
fileTypeMap.Store("49492a00227105008037", "tif")
|
||||
fileTypeMap.Store("424d228c010000000000", "bmp")
|
||||
fileTypeMap.Store("424d8240090000000000", "bmp")
|
||||
fileTypeMap.Store("424d8e1b030000000000", "bmp")
|
||||
fileTypeMap.Store("41433130313500000000", "dwg")
|
||||
fileTypeMap.Store("3c21444f435459504520", "html")
|
||||
fileTypeMap.Store("3c68746d6c3e0", "html")
|
||||
fileTypeMap.Store("3c21646f637479706520", "htm")
|
||||
fileTypeMap.Store("48544d4c207b0d0a0942", "css")
|
||||
fileTypeMap.Store("696b2e71623d696b2e71", "js")
|
||||
fileTypeMap.Store("7b5c727466315c616e73", "rtf")
|
||||
fileTypeMap.Store("38425053000100000000", "psd")
|
||||
fileTypeMap.Store("46726f6d3a203d3f6762", "eml")
|
||||
fileTypeMap.Store("d0cf11e0a1b11ae10000", "doc")
|
||||
fileTypeMap.Store("d0cf11e0a1b11ae10000", "vsd")
|
||||
fileTypeMap.Store("5374616E64617264204A", "mdb")
|
||||
fileTypeMap.Store("252150532D41646F6265", "ps")
|
||||
fileTypeMap.Store("255044462d312e350d0a", "pdf")
|
||||
fileTypeMap.Store("2e524d46000000120001", "rmvb")
|
||||
fileTypeMap.Store("464c5601050000000900", "flv")
|
||||
fileTypeMap.Store("00000020667479706d70", "mp4")
|
||||
fileTypeMap.Store("49443303000000002176", "mp3")
|
||||
fileTypeMap.Store("000001ba210001000180", "mpg")
|
||||
fileTypeMap.Store("3026b2758e66cf11a6d9", "wmv")
|
||||
fileTypeMap.Store("52494646e27807005741", "wav")
|
||||
fileTypeMap.Store("52494646d07d60074156", "avi")
|
||||
fileTypeMap.Store("4d546864000000060001", "mid")
|
||||
fileTypeMap.Store("504b0304140000000800", "zip")
|
||||
fileTypeMap.Store("526172211a0700cf9073", "rar")
|
||||
fileTypeMap.Store("235468697320636f6e66", "ini")
|
||||
fileTypeMap.Store("504b03040a0000000000", "jar")
|
||||
fileTypeMap.Store("4d5a9000030000000400", "exe")
|
||||
fileTypeMap.Store("3c25402070616765206c", "jsp")
|
||||
fileTypeMap.Store("4d616e69666573742d56", "mf")
|
||||
fileTypeMap.Store("3c3f786d6c2076657273", "xml")
|
||||
fileTypeMap.Store("494e5345525420494e54", "sql")
|
||||
fileTypeMap.Store("7061636b616765207765", "java")
|
||||
fileTypeMap.Store("406563686f206f66660d", "bat")
|
||||
fileTypeMap.Store("1f8b0800000000000000", "gz")
|
||||
fileTypeMap.Store("6c6f67346a2e726f6f74", "properties")
|
||||
fileTypeMap.Store("cafebabe0000002e0041", "class")
|
||||
fileTypeMap.Store("49545346030000006000", "chm")
|
||||
fileTypeMap.Store("04000000010000001300", "mxp")
|
||||
fileTypeMap.Store("504b0304140006000800", "docx")
|
||||
fileTypeMap.Store("d0cf11e0a1b11ae10000", "wps")
|
||||
fileTypeMap.Store("6431303a637265617465", "torrent")
|
||||
fileTypeMap.Store("6D6F6F76", "mov")
|
||||
fileTypeMap.Store("FF575043", "wpd")
|
||||
fileTypeMap.Store("CFAD12FEC5FD746F", "dbx")
|
||||
fileTypeMap.Store("2142444E", "pst")
|
||||
fileTypeMap.Store("AC9EBD8F", "qdf")
|
||||
fileTypeMap.Store("E3828596", "pwl")
|
||||
fileTypeMap.Store("2E7261FD", "ram")
|
||||
}
|
||||
|
||||
// bytesToHexString get the binary of the previous result byte.
|
||||
func bytesToHexString(stream []byte) string {
|
||||
if stream == nil || len(stream) <= 0 {
|
||||
return ""
|
||||
}
|
||||
|
||||
var (
|
||||
hv string
|
||||
res = bytes.Buffer{}
|
||||
temp = make([]byte, 0)
|
||||
)
|
||||
|
||||
for _, v := range stream {
|
||||
if hv = hex.EncodeToString(append(temp, v&0xFF)); len(hv) < 2 {
|
||||
res.WriteString(strconv.FormatInt(int64(0), 10))
|
||||
}
|
||||
|
||||
res.WriteString(hv)
|
||||
}
|
||||
|
||||
return res.String()
|
||||
}
|
||||
|
||||
// GetFileType judge the file type based on the binary byte stream.
|
||||
func GetFileType(stream []byte) string {
|
||||
var (
|
||||
fileType string
|
||||
fileCode = bytesToHexString(stream)
|
||||
)
|
||||
|
||||
fileTypeMap.Range(func(key, value interface{}) bool {
|
||||
if strings.HasPrefix(fileCode, strings.ToLower(key.(string))) ||
|
||||
strings.HasPrefix(key.(string), strings.ToLower(fileCode)) {
|
||||
fileType = value.(string)
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
})
|
||||
|
||||
return fileType
|
||||
}
|
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* @Author: fuxiao
|
||||
* @Email: 576101059@qq.com
|
||||
* @Author: Echo
|
||||
* @Email: 1711788888@qq.com
|
||||
* @Date: 2021/8/16 3:47 下午
|
||||
* @Desc: TODO
|
||||
*/
|
||||
@@ -8,27 +8,13 @@
|
||||
package internal
|
||||
|
||||
import (
|
||||
"encoding"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"os"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
const fileUploadingKey = "@file:"
|
||||
|
||||
func Exists(path string) bool {
|
||||
if stat, err := os.Stat(path); stat != nil && !os.IsNotExist(err) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func BuildParams(params interface{}) string {
|
||||
switch v := params.(type) {
|
||||
case string:
|
||||
@@ -42,9 +28,9 @@ func BuildParams(params interface{}) string {
|
||||
params = nil
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
m := make(map[string]interface{})
|
||||
|
||||
|
||||
if params != nil {
|
||||
if b, err := json.Marshal(params); err != nil {
|
||||
return String(params)
|
||||
@@ -54,25 +40,25 @@ func BuildParams(params interface{}) string {
|
||||
} else {
|
||||
return ""
|
||||
}
|
||||
|
||||
|
||||
urlEncode := true
|
||||
|
||||
|
||||
if len(m) == 0 {
|
||||
return String(params)
|
||||
}
|
||||
|
||||
|
||||
for k, v := range m {
|
||||
if strings.Contains(k, fileUploadingKey) || strings.Contains(String(v), fileUploadingKey) {
|
||||
urlEncode = false
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
var (
|
||||
s = ""
|
||||
str = ""
|
||||
)
|
||||
|
||||
|
||||
for k, v := range m {
|
||||
if len(str) > 0 {
|
||||
str += "&"
|
||||
@@ -83,222 +69,6 @@ func BuildParams(params interface{}) string {
|
||||
}
|
||||
str += k + "=" + s
|
||||
}
|
||||
|
||||
|
||||
return str
|
||||
}
|
||||
|
||||
func String(any interface{}) string {
|
||||
switch v := any.(type) {
|
||||
case nil:
|
||||
return ""
|
||||
case string:
|
||||
return v
|
||||
case int:
|
||||
return strconv.Itoa(v)
|
||||
case int8:
|
||||
return strconv.Itoa(int(v))
|
||||
case int16:
|
||||
return strconv.Itoa(int(v))
|
||||
case int32:
|
||||
return strconv.Itoa(int(v))
|
||||
case int64:
|
||||
return strconv.FormatInt(v, 10)
|
||||
case uint:
|
||||
return strconv.FormatUint(uint64(v), 10)
|
||||
case uint8:
|
||||
return strconv.FormatUint(uint64(v), 10)
|
||||
case uint16:
|
||||
return strconv.FormatUint(uint64(v), 10)
|
||||
case uint64:
|
||||
return strconv.FormatUint(v, 10)
|
||||
case float32:
|
||||
return strconv.FormatFloat(float64(v), 'f', -1, 32)
|
||||
case float64:
|
||||
return strconv.FormatFloat(v, 'f', -1, 64)
|
||||
case bool:
|
||||
return strconv.FormatBool(v)
|
||||
case []byte:
|
||||
return string(v)
|
||||
case time.Time:
|
||||
return v.String()
|
||||
case *time.Time:
|
||||
if v == nil {
|
||||
return ""
|
||||
}
|
||||
return v.String()
|
||||
default:
|
||||
if v == nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
if i, ok := v.(stringInterface); ok {
|
||||
return i.String()
|
||||
}
|
||||
|
||||
if i, ok := v.(errorInterface); ok {
|
||||
return i.Error()
|
||||
}
|
||||
|
||||
var (
|
||||
rv = reflect.ValueOf(v)
|
||||
kind = rv.Kind()
|
||||
)
|
||||
|
||||
switch kind {
|
||||
case reflect.Chan,
|
||||
reflect.Map,
|
||||
reflect.Slice,
|
||||
reflect.Func,
|
||||
reflect.Ptr,
|
||||
reflect.Interface,
|
||||
reflect.UnsafePointer:
|
||||
if rv.IsNil() {
|
||||
return ""
|
||||
}
|
||||
case reflect.String:
|
||||
return rv.String()
|
||||
}
|
||||
|
||||
if kind == reflect.Ptr {
|
||||
return String(rv.Elem().Interface())
|
||||
}
|
||||
|
||||
if b, e := json.Marshal(v); e != nil {
|
||||
return fmt.Sprint(v)
|
||||
} else {
|
||||
return string(b)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func Scan(b []byte, any interface{}) error {
|
||||
switch v := any.(type) {
|
||||
case nil:
|
||||
return fmt.Errorf("cache: Scan(nil)")
|
||||
case *string:
|
||||
*v = String(b)
|
||||
return nil
|
||||
case *[]byte:
|
||||
*v = b
|
||||
return nil
|
||||
case *int:
|
||||
var err error
|
||||
*v, err = strconv.Atoi(String(b))
|
||||
return err
|
||||
case *int8:
|
||||
n, err := strconv.ParseInt(String(b), 10, 8)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
*v = int8(n)
|
||||
return nil
|
||||
case *int16:
|
||||
n, err := strconv.ParseInt(String(b), 10, 16)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
*v = int16(n)
|
||||
return nil
|
||||
case *int32:
|
||||
n, err := strconv.ParseInt(String(b), 10, 32)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
*v = int32(n)
|
||||
return nil
|
||||
case *int64:
|
||||
n, err := strconv.ParseInt(String(b), 10, 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
*v = n
|
||||
return nil
|
||||
case *uint:
|
||||
n, err := strconv.ParseUint(String(b), 10, 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
*v = uint(n)
|
||||
return nil
|
||||
case *uint8:
|
||||
n, err := strconv.ParseUint(String(b), 10, 8)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
*v = uint8(n)
|
||||
return nil
|
||||
case *uint16:
|
||||
n, err := strconv.ParseUint(String(b), 10, 16)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
*v = uint16(n)
|
||||
return nil
|
||||
case *uint32:
|
||||
n, err := strconv.ParseUint(String(b), 10, 32)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
*v = uint32(n)
|
||||
return nil
|
||||
case *uint64:
|
||||
n, err := strconv.ParseUint(String(b), 10, 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
*v = n
|
||||
return nil
|
||||
case *float32:
|
||||
n, err := strconv.ParseFloat(String(b), 32)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
*v = float32(n)
|
||||
return err
|
||||
case *float64:
|
||||
var err error
|
||||
*v, err = strconv.ParseFloat(String(b), 64)
|
||||
return err
|
||||
case *bool:
|
||||
*v = len(b) == 1 && b[0] == '1'
|
||||
return nil
|
||||
case *time.Time:
|
||||
var err error
|
||||
*v, err = time.Parse(time.RFC3339Nano, String(b))
|
||||
return err
|
||||
case encoding.BinaryUnmarshaler:
|
||||
return v.UnmarshalBinary(b)
|
||||
default:
|
||||
var (
|
||||
rv = reflect.ValueOf(v)
|
||||
kind = rv.Kind()
|
||||
)
|
||||
|
||||
if kind != reflect.Ptr {
|
||||
return fmt.Errorf("can't unmarshal %T", v)
|
||||
}
|
||||
|
||||
switch kind = rv.Elem().Kind(); kind {
|
||||
case reflect.Array, reflect.Slice, reflect.Map, reflect.Struct:
|
||||
return json.Unmarshal(b, v)
|
||||
}
|
||||
|
||||
return fmt.Errorf("can't unmarshal %T", v)
|
||||
}
|
||||
}
|
||||
|
||||
type stringInterface interface {
|
||||
String() string
|
||||
}
|
||||
|
||||
type errorInterface interface {
|
||||
Error() string
|
||||
}
|
||||
|
||||
func UnsafeStringToBytes(s string) []byte {
|
||||
return *(*[]byte)(unsafe.Pointer(&s))
|
||||
}
|
||||
|
||||
func UnsafeBytesToString(b []byte) string {
|
||||
return *(*string)(unsafe.Pointer(&b))
|
||||
}
|
||||
|
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* @Author: fuxiao
|
||||
* @Email: 576101059@qq.com
|
||||
* @Author: Echo
|
||||
* @Email: 1711788888@qq.com
|
||||
* @Date: 2021/8/16 9:47 上午
|
||||
* @Desc: request's middleware
|
||||
*/
|
||||
@@ -27,6 +27,6 @@ func (m *middleware) Next() (*Response, error) {
|
||||
return m.resp, m.err
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return m.resp, m.err
|
||||
}
|
||||
|
41
request.go
41
request.go
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* @Author: fuxiao
|
||||
* @Email: 576101059@qq.com
|
||||
* @Author: Echo
|
||||
* @Email: 1711788888@qq.com
|
||||
* @Date: 2021/8/16 9:40 上午
|
||||
* @Desc: TODO
|
||||
*/
|
||||
@@ -14,6 +14,7 @@ import (
|
||||
"encoding/xml"
|
||||
"errors"
|
||||
"fmt"
|
||||
"git.echol.cn/loser/http/internal"
|
||||
"io"
|
||||
"log"
|
||||
"mime/multipart"
|
||||
@@ -23,8 +24,6 @@ import (
|
||||
"regexp"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/dobyte/http/internal"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -70,7 +69,7 @@ func (r *Request) request(method, url string, data ...interface{}) (resp *Respon
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
|
||||
if count := len(r.client.middlewares); count > 0 {
|
||||
handlers := make([]MiddlewareFunc, 0, count+1)
|
||||
handlers = append(handlers, r.client.middlewares...)
|
||||
@@ -86,7 +85,7 @@ func (r *Request) request(method, url string, data ...interface{}) (resp *Respon
|
||||
} else {
|
||||
resp, err = r.call()
|
||||
}
|
||||
|
||||
|
||||
return resp, err
|
||||
}
|
||||
|
||||
@@ -94,7 +93,7 @@ func (r *Request) request(method, url string, data ...interface{}) (resp *Respon
|
||||
func (r *Request) prepare(method, url string, data ...interface{}) (req *http.Request, err error) {
|
||||
method = strings.ToUpper(method)
|
||||
url = r.client.baseUrl + url
|
||||
|
||||
|
||||
var params string
|
||||
if len(data) > 0 {
|
||||
switch data[0].(type) {
|
||||
@@ -121,10 +120,10 @@ func (r *Request) prepare(method, url string, data ...interface{}) (req *http.Re
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if method == MethodGet {
|
||||
buffer := bytes.NewBuffer(nil)
|
||||
|
||||
|
||||
if params != "" {
|
||||
switch r.client.headers[HeaderContentType] {
|
||||
case ContentTypeJson, ContentTypeXml:
|
||||
@@ -137,7 +136,7 @@ func (r *Request) prepare(method, url string, data ...interface{}) (req *http.Re
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if req, err = http.NewRequest(method, url, buffer); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -147,7 +146,7 @@ func (r *Request) prepare(method, url string, data ...interface{}) (req *http.Re
|
||||
buffer = bytes.NewBuffer(nil)
|
||||
writer = multipart.NewWriter(buffer)
|
||||
)
|
||||
|
||||
|
||||
for _, item := range strings.Split(params, "&") {
|
||||
array := strings.Split(item, "=")
|
||||
if len(array[1]) > 6 && strings.Compare(array[1][0:6], fileUploadingKey) == 0 {
|
||||
@@ -178,11 +177,11 @@ func (r *Request) prepare(method, url string, data ...interface{}) (req *http.Re
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if err = writer.Close(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
|
||||
if req, err = http.NewRequest(method, url, buffer); err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
@@ -205,13 +204,13 @@ func (r *Request) prepare(method, url string, data ...interface{}) (req *http.Re
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if r.client.ctx != nil {
|
||||
req = req.WithContext(r.client.ctx)
|
||||
} else {
|
||||
req = req.WithContext(context.Background())
|
||||
}
|
||||
|
||||
|
||||
if len(r.client.headers) > 0 {
|
||||
for key, value := range r.client.headers {
|
||||
if key != "" {
|
||||
@@ -219,7 +218,7 @@ func (r *Request) prepare(method, url string, data ...interface{}) (req *http.Re
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if len(r.client.cookies) > 0 {
|
||||
var cookies = make([]string, 0)
|
||||
for key, value := range r.client.cookies {
|
||||
@@ -229,18 +228,18 @@ func (r *Request) prepare(method, url string, data ...interface{}) (req *http.Re
|
||||
}
|
||||
req.Header.Set(HeaderCookie, strings.Join(cookies, ";"))
|
||||
}
|
||||
|
||||
|
||||
if host := req.Header.Get(HeaderHost); host != "" {
|
||||
req.Host = host
|
||||
}
|
||||
|
||||
|
||||
return req, nil
|
||||
}
|
||||
|
||||
// call nitiate an HTTP request and return the response data.
|
||||
func (r *Request) call() (resp *Response, err error) {
|
||||
resp = &Response{Request: r.Request}
|
||||
|
||||
|
||||
for {
|
||||
if resp.Response, err = r.client.Do(r.Request); err != nil {
|
||||
if resp.Response != nil {
|
||||
@@ -248,7 +247,7 @@ func (r *Request) call() (resp *Response, err error) {
|
||||
log.Printf(`%+v`, err)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if r.retryCount > 0 {
|
||||
r.retryCount--
|
||||
time.Sleep(r.retryInterval)
|
||||
@@ -259,6 +258,6 @@ func (r *Request) call() (resp *Response, err error) {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return resp, err
|
||||
}
|
||||
|
33
response.go
33
response.go
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* @Author: fuxiao
|
||||
* @Email: 576101059@qq.com
|
||||
* @Author: Echo
|
||||
* @Email: 1711788888@qq.com
|
||||
* @Date: 2021/8/15 4:56 下午
|
||||
* @Desc: TODO
|
||||
*/
|
||||
@@ -8,10 +8,10 @@
|
||||
package http
|
||||
|
||||
import (
|
||||
"git.echol.cn/loser/http/internal"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
|
||||
"github.com/dobyte/http/internal"
|
||||
"sync"
|
||||
)
|
||||
|
||||
type Response struct {
|
||||
@@ -19,32 +19,35 @@ type Response struct {
|
||||
Request *http.Request
|
||||
body []byte
|
||||
cookies map[string]string
|
||||
mu sync.Mutex
|
||||
}
|
||||
|
||||
// Bytes retrieves and returns the response content as []byte.
|
||||
func (r *Response) Bytes() []byte {
|
||||
// ReadBytes retrieves and returns the response content as []byte.
|
||||
func (r *Response) ReadBytes() []byte {
|
||||
if r == nil || r.Response == nil {
|
||||
return []byte{}
|
||||
}
|
||||
|
||||
|
||||
if r.body == nil {
|
||||
var err error
|
||||
r.mu.Lock()
|
||||
defer r.mu.Unlock()
|
||||
if r.body, err = ioutil.ReadAll(r.Response.Body); err != nil {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return r.body
|
||||
}
|
||||
|
||||
// String retrieves and returns the response content as string.
|
||||
func (r *Response) String() string {
|
||||
return internal.UnsafeBytesToString(r.Bytes())
|
||||
// ReadString retrieves and returns the response content as string.
|
||||
func (r *Response) ReadString() string {
|
||||
return internal.UnsafeBytesToString(r.ReadBytes())
|
||||
}
|
||||
|
||||
// Scan convert the response into a complex data structure.
|
||||
func (r *Response) Scan(any interface{}) error {
|
||||
return internal.Scan(r.Bytes(), any)
|
||||
return internal.Scan(r.ReadBytes(), any)
|
||||
}
|
||||
|
||||
// Close closes the response when it will never be used.
|
||||
@@ -63,7 +66,7 @@ func (r *Response) HasHeader(key string) bool {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -82,7 +85,7 @@ func (r *Response) GetHeaders() map[string]interface{} {
|
||||
headers[k] = v[0]
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return headers
|
||||
}
|
||||
|
||||
@@ -92,7 +95,7 @@ func (r *Response) HasCookie(key string) bool {
|
||||
r.cookies = r.GetCookies()
|
||||
}
|
||||
_, ok := r.cookies[key]
|
||||
|
||||
|
||||
return ok
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user