更新时间:2023-06-28 GMT+08:00
自定义样例
自定义请求样例
自定义请求Go样例:
package main
import (
"crypto/tls"
"encoding/json"
"errors"
"fmt"
"io/ioutil"
"net/http"
"net/http/cookiejar"
"strings"
"sync"
)
var (
trs = sync.Map{}
jars = sync.Map{}
)
func getTr(addr string) *http.Transport {
if v, ok := trs.Load(addr); ok {
return v.(*http.Transport)
} else {
tr := &http.Transport{
TLSClientConfig: &tls.Config{
InsecureSkipVerify: true,
},
MaxConnsPerHost: 5000,
MaxIdleConnsPerHost: 5000,
}
v, _ = trs.LoadOrStore(addr, tr)
return v.(*http.Transport)
}
}
func getJar(goroutineId string) *cookiejar.Jar {
if v, ok := jars.Load(goroutineId); ok {
return v.(*cookiejar.Jar)
} else {
jar, _ := cookiejar.New(nil)
v, _ = jars.LoadOrStore(goroutineId, jar)
return v.(*cookiejar.Jar)
}
}
func outgoingLength(req *http.Request) int64 {
if req.Body == nil || req.Body == http.NoBody {
return 0
}
if req.ContentLength != 0 {
return req.ContentLength
}
return -1
}
func redirectBehavior(reqMethod string, resp *http.Response, req *http.Request) (redirectMethod string, shouldRedirect, includeBody bool) {
switch resp.StatusCode {
case 301, 302, 303:
redirectMethod = reqMethod
shouldRedirect = true
includeBody = false
if reqMethod != "GET" && reqMethod != "HEAD" {
redirectMethod = "GET"
}
case 307, 308:
redirectMethod = reqMethod
shouldRedirect = true
includeBody = true
if resp.Header.Get("Location") == "" {
shouldRedirect = false
break
}
if req.GetBody == nil && outgoingLength(req) != 0 {
shouldRedirect = false
}
}
return redirectMethod, shouldRedirect, includeBody
}
func Do(params map[string]string) interface{} {
parent := acquireResult(params[InnerVarName])
sub := parent
var (
err error
redirectCount int
req *http.Request
res *http.Response
)
defer func() {
if p := recover(); p != nil {
sub.ResponseCode = 500
sub.Success = false
sub.FailureMessage = fmt.Sprintf("%v", sub)
} else if err != nil {
sub.ResponseCode = 500
sub.Success = false
sub.FailureMessage = err.Error()
}
}()
redirect := params["redirect"]
for {
// process params
url, method, body := params["url"], params["method"], params["body"]
sub.Url, sub.Method, sub.RequestBody = url, method, body
sub.SentBytes = len(body)
// create request
req, err = http.NewRequest(method, url, strings.NewReader(body))
if err != nil {
return parent
}
// load cookies
jar := getJar(params[InnerVarGoroutineId])
cookies := jar.Cookies(req.URL)
for _, c := range cookies {
req.AddCookie(c)
}
// write headers
if params["headers"] != "" {
headers := map[string][]string{}
if err = json.Unmarshal([]byte(params["headers"]), &headers); err != nil {
return parent
}
for k, vs := range headers {
for _, v := range vs {
req.Header.Add(k, v)
}
}
}
for k, v := range req.Header {
sub.RequestHeader[k] = strings.Join(v, ",")
}
// do request
sub.begin()
res, err = getTr(fmt.Sprintf("%s://%s", req.URL.Scheme, req.URL.Host)).RoundTrip(req)
sub.end()
if err != nil {
return parent
}
var b []byte
b, err = ioutil.ReadAll(res.Body)
if err != nil {
_ = res.Body.Close()
return parent
}
// store cookies
jar.SetCookies(req.URL, res.Cookies())
for k, v := range res.Header {
sub.ResponseHeader[k] = strings.Join(v, ",")
}
sub.ResponseBody = string(b)
sub.ReceivedBytes = len(b)
sub.ResponseCode = res.StatusCode
_ = res.Body.Close()
if redirect != "on" {
break
}
if redirectMethod, shouldRedirect, includeBody := redirectBehavior(method, res, req); shouldRedirect {
redirectCount++
if redirectCount > 10 {
err = errors.New("stopped after 10 redirects")
return parent
}
params["url"] = res.Header.Get("Location")
params["method"] = redirectMethod
if !includeBody {
params["body"] = ""
}
parent = acquireResult(params[InnerVarName])
sub = parent
continue
}
break
}
return parent
}
自定义请求JSON样例:
{
"name": "Http 1.0",
"plugin": "http.so",
"desc": "Http plugin supports http 1.0 test.",
"funcs": [
{
"name": "Do",
"type": "req",
"desc": "This is the entry of http request.",
"params": [
{
"name": "url",
"default": "",
"range": [],
"desc": "The url of http request",
"required": true
},
{
"name": "headers",
"default": "{\"Content-Type\": [\"text/plain;utf-8\"]}",
"range": [],
"desc": "The headers of http request",
"required": true
},
{
"name": "method",
"default": "GET",
"range": [
"GET",
"HEAD",
"POST",
"PUT",
"PATCH",
"DELETE",
"CONNECT",
"OPTIONS",
"TRACE"
],
"desc": "The method of http request",
"required": true
},
{
"name": "body",
"default": "",
"range": [],
"desc": "The body of http request",
"required": true
},
{
"name": "redirect",
"default": "on",
"range": [
"on",
"off"
],
"desc": "If enable auto redirect",
"required": true
}
]
}
]
}
自定义函数样例
自定义函数Go样例:
package main
import (
"fmt"
"math/rand"
"strconv"
)
func RandomNum(params map[string]string) (s string) {
var err error
defer func() {
if r := recover(); r != nil {
s = fmt.Sprintf("%v", r)
} else if err != nil {
s = err.Error()
}
}()
min, err := strconv.ParseInt(params["min"], 10, 64)
if err != nil {
return
}
max, err := strconv.ParseInt(params["max"], 10, 64)
if err != nil {
return
}
if min > max {
min, max = max, min
}
return strconv.FormatInt(min+rand.Int63n(max-min+1), 10)
}
var (
charSet = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789")
)
func RandomText(params map[string]string) (s string) {
var err error
defer func() {
if r := recover(); r != nil {
s = fmt.Sprintf("%v", r)
} else if err != nil {
s = err.Error()
}
}()
length, err := strconv.ParseInt(params["length"], 10, 64)
if err != nil {
return
}
if length == 0 {
return ""
}
set := []rune(params["charset"])
if len(set) == 0 {
set = charSet
}
n := len(set)
rs := make([]rune, length)
for i := int64(0); i < length; i++ {
rs[i] = set[rand.Intn(n)]
}
return string(rs)
}
自定义函数JSON样例:
{
"name": "Random",
"plugin": "random.so",
"desc": "Random plugin supports generating random value.",
"funcs": [
{
"name": "RandomNum",
"type": "func",
"desc": "RandomNum generates random number.",
"params": [
{
"name": "min",
"default": "0",
"range": [],
"desc": "The maximum of random number.",
"required": true
},
{
"name": "max",
"default": "100",
"range": [],
"desc": "The maximum of random number.",
"required": true
}
]
},
{
"name": "RandomText",
"type": "func",
"desc": "RandomText generates random text of a specified length.",
"params": [
{
"name": "length",
"default": "32",
"range": [],
"desc": "The length of random text.",
"required": true
},
{
"name": "charset",
"default": "",
"range": [],
"desc": "Random text is generated randomly from the specified character set. if empty, default char set is 0-9 a-z A-Z",
"required": false
}
]
}
]
}
父主题: 插件管理