node_request.go 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239
  1. package core
  2. import (
  3. "bytes"
  4. "fmt"
  5. "io"
  6. "mime/multipart"
  7. "net"
  8. "net/http"
  9. "path/filepath"
  10. "strings"
  11. "time"
  12. C "github.com/Dreamacro/clash/constant"
  13. "github.com/cdle/sillyplus/utils"
  14. "github.com/dop251/goja"
  15. "github.com/goccy/go-json"
  16. )
  17. func fetch(vm *goja.Runtime, uuid string, wts ...interface{}) (interface{}, error) {
  18. var method = "get"
  19. var url = ""
  20. var req *http.Request
  21. var headers map[string]interface{}
  22. var transport *http.Transport
  23. var formData map[string]interface{}
  24. // var isJson bool
  25. var isJsonBody bool
  26. var body []byte
  27. var allow_redirects bool = true
  28. var responseType = ""
  29. // var err error
  30. // var useproxy bool
  31. var timeout time.Duration = 0
  32. var login = false
  33. var instance C.Conn
  34. for _, wt := range wts {
  35. switch wt := wt.(type) {
  36. case string:
  37. url = wt
  38. case map[string]interface{}:
  39. props := wt
  40. for i := range props {
  41. switch strings.ToLower(i) {
  42. case "timeout":
  43. timeout = time.Duration(utils.Int64(props[i])) * time.Millisecond
  44. case "headers":
  45. headers = props[i].(map[string]interface{})
  46. case "method":
  47. method = strings.ToLower(props[i].(string))
  48. case "url":
  49. if f, ok := props[i].(func(i goja.FunctionCall) goja.Value); ok {
  50. url = f(goja.FunctionCall{}).ToString().String()
  51. } else {
  52. if props[i] == nil {
  53. panic(Error(vm, "无效的url请求地址nil"))
  54. }
  55. url = fmt.Sprint(props[i])
  56. }
  57. case "json":
  58. if props[i].(bool) {
  59. responseType = "json"
  60. }
  61. case "responsetype":
  62. responseType = props[i].(string)
  63. case "datatype":
  64. responseType = props[i].(string)
  65. case "allowredirects":
  66. allow_redirects = props[i].(bool)
  67. case "body":
  68. switch v := props[i].(type) {
  69. case string:
  70. body = []byte(v)
  71. case []byte:
  72. body = v
  73. case *Buffer:
  74. body = v.value
  75. default:
  76. d, _ := json.Marshal(props[i])
  77. body = d
  78. isJsonBody = true
  79. }
  80. case "login":
  81. login = true
  82. case "formdata":
  83. formData = props[i].(map[string]interface{})
  84. case "form":
  85. formData = props[i].(map[string]interface{})
  86. case "proxy":
  87. var err error
  88. var params = props[i].(map[string]interface{})
  89. if _, ok := params["name"]; !ok {
  90. params["name"] = "临时"
  91. }
  92. instance, err = GetProxyTransport(url, uuid, params)
  93. if err != nil {
  94. panic(Error(vm, err))
  95. }
  96. if instance != nil {
  97. defer instance.Close()
  98. }
  99. }
  100. }
  101. }
  102. var err error
  103. if instance == nil {
  104. instance, err = GetProxyTransport(url, uuid, nil)
  105. if err != nil {
  106. panic(Error(vm, err))
  107. }
  108. if instance != nil {
  109. defer instance.Close()
  110. }
  111. }
  112. if instance != nil {
  113. transport = &http.Transport{
  114. Dial: func(string, string) (net.Conn, error) {
  115. return instance, nil
  116. },
  117. MaxIdleConns: 100,
  118. IdleConnTimeout: 90 * time.Second,
  119. TLSHandshakeTimeout: 10 * time.Second,
  120. ExpectContinueTimeout: 10 * time.Second,
  121. }
  122. }
  123. method = strings.ToUpper(method)
  124. if len(formData) > 0 {
  125. // 创建一个新的 buffer
  126. payload := &bytes.Buffer{}
  127. writer := multipart.NewWriter(payload)
  128. func() {
  129. defer writer.Close()
  130. // defer func() {
  131. // ch <- true
  132. // }()
  133. for key := range formData {
  134. value := fmt.Sprint(formData[key])
  135. // 添加文本上传字段
  136. if !strings.HasPrefix(value, "url(") || !strings.HasSuffix(value, ")") {
  137. fieldWriter, err := writer.CreateFormField(key)
  138. if err != nil {
  139. console.Error("cff", err)
  140. return
  141. }
  142. if _, err := fieldWriter.Write([]byte(value)); err != nil {
  143. console.Error("fw", err)
  144. return
  145. }
  146. continue
  147. } else {
  148. url := strings.TrimPrefix(value, "url(")
  149. url = strings.TrimSuffix(url, ")")
  150. resp, err := http.Get(url)
  151. if err != nil {
  152. // console.Error("failed to download file %s: %v\n", url, err)
  153. panic(Error(vm, "failed to download file %s: %v\n", url, err))
  154. // return
  155. }
  156. defer resp.Body.Close()
  157. part, err := writer.CreateFormFile(key, filepath.Base(url))
  158. if err != nil {
  159. panic(Error(vm, "failed to get file info for %s: %v\n", url, err))
  160. }
  161. // 复制管道中的内容到表单字段中
  162. if _, err = io.Copy(part, resp.Body); err != nil {
  163. panic(Error(vm, err))
  164. }
  165. }
  166. }
  167. }()
  168. // 关闭表单写入器
  169. req, err = http.NewRequest(method, url, payload)
  170. // <-ch
  171. // ch = nil
  172. if err != nil {
  173. return nil, err
  174. }
  175. req.Header.Set("Content-Type", writer.FormDataContentType())
  176. } else {
  177. req, err = http.NewRequest(method, url, bytes.NewBuffer(body))
  178. if err != nil {
  179. return nil, err
  180. }
  181. if isJsonBody {
  182. req.Header.Set("Content-Type", "application/json")
  183. }
  184. }
  185. if login {
  186. req.Header.Set("Cookie", "uuid=40e67d5e-f6f3-11ed-8bc2-dca9049272e5; token="+getTempAuth())
  187. }
  188. for i := range headers {
  189. req.Header.Set(i, fmt.Sprint(headers[i]))
  190. }
  191. }
  192. var rspObj goja.Proxy
  193. var rsp *http.Response
  194. var err error
  195. var client = &http.Client{
  196. Timeout: timeout,
  197. }
  198. if transport != nil {
  199. client.Transport = transport
  200. }
  201. if !allow_redirects {
  202. client.CheckRedirect = func(req *http.Request, via []*http.Request) error {
  203. return http.ErrUseLastResponse
  204. }
  205. }
  206. rsp, err = client.Do(req)
  207. if err != nil {
  208. return nil, err
  209. }
  210. obj, err := MakeResponseObject(vm, rsp, responseType)
  211. rspObj = vm.NewProxy(obj, &goja.ProxyTrapConfig{
  212. Get: func(target *goja.Object, property string, receiver goja.Value) (value goja.Value) {
  213. obj := target.Get(property)
  214. if obj != nil {
  215. return obj
  216. }
  217. switch property {
  218. case "statusText", "statusMessage":
  219. return vm.ToValue("")
  220. case "statusCode":
  221. return target.Get("status")
  222. // case "body":
  223. // return vm.ToValue(target.Get("getBody").Export().(func() interface{})())
  224. case "then":
  225. return goja.Undefined()
  226. }
  227. console.Error("response has no property " + property)
  228. return goja.Undefined()
  229. },
  230. })
  231. return rspObj, err
  232. }