generated from bing/readnotes
185 lines
4.5 KiB
Go
185 lines
4.5 KiB
Go
|
package curl
|
||
|
|
||
|
import (
|
||
|
"bytes"
|
||
|
"context"
|
||
|
"crypto/tls"
|
||
|
"encoding/json"
|
||
|
"fmt"
|
||
|
"io"
|
||
|
"io/ioutil"
|
||
|
"net"
|
||
|
"net/http"
|
||
|
netURL "net/url"
|
||
|
"strings"
|
||
|
"time"
|
||
|
)
|
||
|
|
||
|
type curlV1 struct {
|
||
|
DefaultHeader http.Header
|
||
|
}
|
||
|
|
||
|
func V1(defaultHeader http.Header) *curlV1 {
|
||
|
return &curlV1{
|
||
|
DefaultHeader: defaultHeader,
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func (v1 *curlV1) getDomain(url string) string {
|
||
|
strs := strings.Split(url, "//")
|
||
|
if len(strs) < 2 {
|
||
|
return ""
|
||
|
}
|
||
|
schema := v1.getSchema(url)
|
||
|
paths := strings.Split(strs[1], "/")
|
||
|
switch schema {
|
||
|
case "unix":
|
||
|
tmpstrs := []string{}
|
||
|
for _, p := range paths {
|
||
|
tmpstrs = append(tmpstrs, p)
|
||
|
if strings.Contains(p, ".sock") {
|
||
|
break
|
||
|
}
|
||
|
}
|
||
|
return strings.Join(tmpstrs, "/")
|
||
|
case "http":
|
||
|
return paths[0]
|
||
|
case "https":
|
||
|
return paths[0]
|
||
|
default:
|
||
|
return paths[0]
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func (v1 *curlV1) getSchema(url string) string {
|
||
|
strs := strings.Split(url, ":")
|
||
|
return strs[0]
|
||
|
}
|
||
|
|
||
|
func (v1 *curlV1) getPath(url string) string {
|
||
|
schema := v1.getSchema(url)
|
||
|
domain := v1.getDomain(url)
|
||
|
s := fmt.Sprintf("%s://%s", schema, domain)
|
||
|
if len(url) <= len(s) {
|
||
|
return ""
|
||
|
}
|
||
|
return url[len(s):]
|
||
|
}
|
||
|
|
||
|
func (v1 *curlV1) NewClient(url string) (*http.Client, string) {
|
||
|
schema := v1.getSchema(url)
|
||
|
domain := v1.getDomain(url)
|
||
|
path := v1.getPath(url)
|
||
|
if schema == "unix" {
|
||
|
defaultTimeout := 60 * time.Second
|
||
|
tr := new(http.Transport)
|
||
|
tr.DisableCompression = true
|
||
|
tr.DialContext = func(_ context.Context, _, _ string) (net.Conn, error) {
|
||
|
return net.DialTimeout("unix", domain, defaultTimeout)
|
||
|
}
|
||
|
tr.TLSClientConfig = &tls.Config{
|
||
|
InsecureSkipVerify: true,
|
||
|
}
|
||
|
client := &http.Client{Transport: tr}
|
||
|
return client, path
|
||
|
}
|
||
|
// 绕过github等可能因为特征码返回503问题
|
||
|
// https://www.imwzk.com/posts/2021-03-14-why-i-always-get-503-with-golang/
|
||
|
defaultCipherSuites := []uint16{0xc02f, 0xc030, 0xc02b, 0xc02c, 0xcca8, 0xcca9, 0xc013, 0xc009,
|
||
|
0xc014, 0xc00a, 0x009c, 0x009d, 0x002f, 0x0035, 0xc012, 0x000a}
|
||
|
client := &http.Client{
|
||
|
Transport: &http.Transport{
|
||
|
TLSClientConfig: &tls.Config{
|
||
|
InsecureSkipVerify: true,
|
||
|
CipherSuites: append(defaultCipherSuites[8:], defaultCipherSuites[:8]...),
|
||
|
},
|
||
|
},
|
||
|
// 获取301重定向
|
||
|
CheckRedirect: func(req *http.Request, via []*http.Request) error {
|
||
|
return http.ErrUseLastResponse
|
||
|
},
|
||
|
}
|
||
|
return client, path
|
||
|
}
|
||
|
|
||
|
func (v1 *curlV1) DoRequest(method, url string, body interface{}, header http.Header) (*http.Response, error) {
|
||
|
var reqBody io.Reader
|
||
|
contentType := "application/json"
|
||
|
switch v := body.(type) {
|
||
|
case string:
|
||
|
reqBody = strings.NewReader(v)
|
||
|
contentType = "text/plain"
|
||
|
case []byte:
|
||
|
reqBody = bytes.NewReader(v)
|
||
|
case map[string]string:
|
||
|
val := netURL.Values{}
|
||
|
for k, v := range v {
|
||
|
val.Set(k, v)
|
||
|
}
|
||
|
reqBody = strings.NewReader(val.Encode())
|
||
|
contentType = "application/x-www-form-urlencoded"
|
||
|
default:
|
||
|
data, err := json.Marshal(v)
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
reqBody = bytes.NewReader(data)
|
||
|
}
|
||
|
if header == nil {
|
||
|
header = http.Header{}
|
||
|
}
|
||
|
if header.Get("Content-Type") == "" {
|
||
|
header.Set("Content-Type", contentType)
|
||
|
}
|
||
|
for k, values := range v1.DefaultHeader {
|
||
|
if header.Get(k) == "" {
|
||
|
for _, v := range values {
|
||
|
header.Add(k, v)
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
client, location := v1.NewClient(url)
|
||
|
schema := v1.getSchema(url)
|
||
|
req, err := http.NewRequest(method, location, reqBody)
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
req.URL.Scheme = schema
|
||
|
if schema == "unix" {
|
||
|
req.URL.Scheme = "http"
|
||
|
}
|
||
|
req.URL.Host = v1.getDomain(url)
|
||
|
req.Header = header
|
||
|
return client.Do(req)
|
||
|
}
|
||
|
|
||
|
func (v1 *curlV1) DoRequestReturnBytes(method, url string, body interface{}, header http.Header) ([]byte, error) {
|
||
|
resp, err := v1.DoRequest(method, url, body, header)
|
||
|
if err != nil {
|
||
|
return []byte{}, err
|
||
|
}
|
||
|
defer resp.Body.Close()
|
||
|
res, err := ioutil.ReadAll(resp.Body)
|
||
|
return res, err
|
||
|
}
|
||
|
|
||
|
func (v1 *curlV1) Get(url string, body interface{}, header http.Header) ([]byte, error) {
|
||
|
return v1.DoRequestReturnBytes(http.MethodGet, url, body, header)
|
||
|
}
|
||
|
|
||
|
func (v1 *curlV1) Put(url string, body interface{}, header http.Header) ([]byte, error) {
|
||
|
return v1.DoRequestReturnBytes(http.MethodPut, url, body, header)
|
||
|
}
|
||
|
|
||
|
func (v1 *curlV1) Post(url string, body interface{}, header http.Header) ([]byte, error) {
|
||
|
return v1.DoRequestReturnBytes(http.MethodPost, url, body, header)
|
||
|
}
|
||
|
|
||
|
func (v1 *curlV1) Patch(url string, body interface{}, header http.Header) ([]byte, error) {
|
||
|
return v1.DoRequestReturnBytes(http.MethodPatch, url, body, header)
|
||
|
}
|
||
|
|
||
|
func (v1 *curlV1) Delete(url string, body interface{}, header http.Header) ([]byte, error) {
|
||
|
return v1.DoRequestReturnBytes(http.MethodDelete, url, body, header)
|
||
|
}
|