| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239 |
- package core
- import (
- "bytes"
- "fmt"
- "io"
- "mime/multipart"
- "net"
- "net/http"
- "path/filepath"
- "strings"
- "time"
- C "github.com/Dreamacro/clash/constant"
- "github.com/cdle/sillyplus/utils"
- "github.com/dop251/goja"
- "github.com/goccy/go-json"
- )
- func fetch(vm *goja.Runtime, uuid string, wts ...interface{}) (interface{}, error) {
- var method = "get"
- var url = ""
- var req *http.Request
- var headers map[string]interface{}
- var transport *http.Transport
- var formData map[string]interface{}
- // var isJson bool
- var isJsonBody bool
- var body []byte
- var allow_redirects bool = true
- var responseType = ""
- // var err error
- // var useproxy bool
- var timeout time.Duration = 0
- var login = false
- var instance C.Conn
- for _, wt := range wts {
- switch wt := wt.(type) {
- case string:
- url = wt
- case map[string]interface{}:
- props := wt
- for i := range props {
- switch strings.ToLower(i) {
- case "timeout":
- timeout = time.Duration(utils.Int64(props[i])) * time.Millisecond
- case "headers":
- headers = props[i].(map[string]interface{})
- case "method":
- method = strings.ToLower(props[i].(string))
- case "url":
- if f, ok := props[i].(func(i goja.FunctionCall) goja.Value); ok {
- url = f(goja.FunctionCall{}).ToString().String()
- } else {
- if props[i] == nil {
- panic(Error(vm, "无效的url请求地址nil"))
- }
- url = fmt.Sprint(props[i])
- }
- case "json":
- if props[i].(bool) {
- responseType = "json"
- }
- case "responsetype":
- responseType = props[i].(string)
- case "datatype":
- responseType = props[i].(string)
- case "allowredirects":
- allow_redirects = props[i].(bool)
- case "body":
- switch v := props[i].(type) {
- case string:
- body = []byte(v)
- case []byte:
- body = v
- case *Buffer:
- body = v.value
- default:
- d, _ := json.Marshal(props[i])
- body = d
- isJsonBody = true
- }
- case "login":
- login = true
- case "formdata":
- formData = props[i].(map[string]interface{})
- case "form":
- formData = props[i].(map[string]interface{})
- case "proxy":
- var err error
- var params = props[i].(map[string]interface{})
- if _, ok := params["name"]; !ok {
- params["name"] = "临时"
- }
- instance, err = GetProxyTransport(url, uuid, params)
- if err != nil {
- panic(Error(vm, err))
- }
- if instance != nil {
- defer instance.Close()
- }
- }
- }
- }
- var err error
- if instance == nil {
- instance, err = GetProxyTransport(url, uuid, nil)
- if err != nil {
- panic(Error(vm, err))
- }
- if instance != nil {
- defer instance.Close()
- }
- }
- if instance != nil {
- transport = &http.Transport{
- Dial: func(string, string) (net.Conn, error) {
- return instance, nil
- },
- MaxIdleConns: 100,
- IdleConnTimeout: 90 * time.Second,
- TLSHandshakeTimeout: 10 * time.Second,
- ExpectContinueTimeout: 10 * time.Second,
- }
- }
- method = strings.ToUpper(method)
- if len(formData) > 0 {
- // 创建一个新的 buffer
- payload := &bytes.Buffer{}
- writer := multipart.NewWriter(payload)
- func() {
- defer writer.Close()
- // defer func() {
- // ch <- true
- // }()
- for key := range formData {
- value := fmt.Sprint(formData[key])
- // 添加文本上传字段
- if !strings.HasPrefix(value, "url(") || !strings.HasSuffix(value, ")") {
- fieldWriter, err := writer.CreateFormField(key)
- if err != nil {
- console.Error("cff", err)
- return
- }
- if _, err := fieldWriter.Write([]byte(value)); err != nil {
- console.Error("fw", err)
- return
- }
- continue
- } else {
- url := strings.TrimPrefix(value, "url(")
- url = strings.TrimSuffix(url, ")")
- resp, err := http.Get(url)
- if err != nil {
- // console.Error("failed to download file %s: %v\n", url, err)
- panic(Error(vm, "failed to download file %s: %v\n", url, err))
- // return
- }
- defer resp.Body.Close()
- part, err := writer.CreateFormFile(key, filepath.Base(url))
- if err != nil {
- panic(Error(vm, "failed to get file info for %s: %v\n", url, err))
- }
- // 复制管道中的内容到表单字段中
- if _, err = io.Copy(part, resp.Body); err != nil {
- panic(Error(vm, err))
- }
- }
- }
- }()
- // 关闭表单写入器
- req, err = http.NewRequest(method, url, payload)
- // <-ch
- // ch = nil
- if err != nil {
- return nil, err
- }
- req.Header.Set("Content-Type", writer.FormDataContentType())
- } else {
- req, err = http.NewRequest(method, url, bytes.NewBuffer(body))
- if err != nil {
- return nil, err
- }
- if isJsonBody {
- req.Header.Set("Content-Type", "application/json")
- }
- }
- if login {
- req.Header.Set("Cookie", "uuid=40e67d5e-f6f3-11ed-8bc2-dca9049272e5; token="+getTempAuth())
- }
- for i := range headers {
- req.Header.Set(i, fmt.Sprint(headers[i]))
- }
- }
- var rspObj goja.Proxy
- var rsp *http.Response
- var err error
- var client = &http.Client{
- Timeout: timeout,
- }
- if transport != nil {
- client.Transport = transport
- }
- if !allow_redirects {
- client.CheckRedirect = func(req *http.Request, via []*http.Request) error {
- return http.ErrUseLastResponse
- }
- }
- rsp, err = client.Do(req)
- if err != nil {
- return nil, err
- }
- obj, err := MakeResponseObject(vm, rsp, responseType)
- rspObj = vm.NewProxy(obj, &goja.ProxyTrapConfig{
- Get: func(target *goja.Object, property string, receiver goja.Value) (value goja.Value) {
- obj := target.Get(property)
- if obj != nil {
- return obj
- }
- switch property {
- case "statusText", "statusMessage":
- return vm.ToValue("")
- case "statusCode":
- return target.Get("status")
- // case "body":
- // return vm.ToValue(target.Get("getBody").Export().(func() interface{})())
- case "then":
- return goja.Undefined()
- }
- console.Error("response has no property " + property)
- return goja.Undefined()
- },
- })
- return rspObj, err
- }
|