add download method
This commit is contained in:
		
							
								
								
									
										4
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,4 @@ | ||||
| .idea/ | ||||
| */.DS_Store | ||||
| .vscode | ||||
| go.sum | ||||
							
								
								
									
										15
									
								
								client.go
									
									
									
									
									
								
							
							
						
						
									
										15
									
								
								client.go
									
									
									
									
									
								
							| @@ -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...) | ||||
| } | ||||
|   | ||||
| @@ -59,23 +59,26 @@ func TestClient_Post(t *testing.T) { | ||||
| 		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) | ||||
| 	} | ||||
| } | ||||
|   | ||||
							
								
								
									
										87
									
								
								download.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										87
									
								
								download.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,87 @@ | ||||
| /** | ||||
|  * @Author: fuxiao | ||||
|  * @Email: 576101059@qq.com | ||||
|  * @Date: 2021/8/26 1:59 下午 | ||||
|  * @Desc: TODO | ||||
|  */ | ||||
|  | ||||
| package http | ||||
|  | ||||
| import ( | ||||
| 	"os" | ||||
| 	"strings" | ||||
| 	 | ||||
| 	"github.com/dobyte/http/internal" | ||||
| ) | ||||
|  | ||||
| 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: fuxiao | ||||
|  * @Email: 576101059@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: fuxiao | ||||
|  * @Email: 576101059@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: fuxiao | ||||
|  * @Email: 576101059@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: fuxiao | ||||
|  * @Email: 576101059@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 | ||||
| } | ||||
| @@ -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: | ||||
| @@ -86,219 +72,3 @@ func BuildParams(params interface{}) string { | ||||
| 	 | ||||
| 	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)) | ||||
| } | ||||
|   | ||||
							
								
								
									
										16
									
								
								response.go
									
									
									
									
									
								
							
							
						
						
									
										16
									
								
								response.go
									
									
									
									
									
								
							| @@ -10,6 +10,7 @@ package http | ||||
| import ( | ||||
| 	"io/ioutil" | ||||
| 	"net/http" | ||||
| 	"sync" | ||||
| 	 | ||||
| 	"github.com/dobyte/http/internal" | ||||
| ) | ||||
| @@ -19,16 +20,19 @@ 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 | ||||
| 		} | ||||
| @@ -37,14 +41,14 @@ func (r *Response) Bytes() []byte { | ||||
| 	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. | ||||
|   | ||||
		Reference in New Issue
	
	Block a user