From 7d3ce2ca01f2d4954d89430e48ca23c89416668b Mon Sep 17 00:00:00 2001 From: Shulhan Date: Thu, 25 Jan 2024 18:59:23 +0700 Subject: all: support parameter binding in HTTP Path If HTTP Path contains key, for example "/:book", and the Params contains the same key, the Path will be filled with value from Params. The same key in Params will be deleted and not send on query parameter or body. --- example/example.go | 31 +++++++++++++++++++++++++++++-- go.mod | 6 +++--- go.sum | 12 ++++++------ http_target.go | 40 ++++++++++++++++++++++++++++++++++++++++ run_request.go | 1 + trunks.go | 10 +++++++--- 6 files changed, 86 insertions(+), 14 deletions(-) diff --git a/example/example.go b/example/example.go index 332cbb3..1be51ef 100644 --- a/example/example.go +++ b/example/example.go @@ -31,8 +31,9 @@ import ( ) const ( - pathExample = "/example" - pathExampleError = "/example/error" + pathExample = `/example` + pathExampleError = `/example/error` + pathExampleNamePage = `/example/:name/page` ) const ( @@ -153,6 +154,14 @@ func (ex *Example) registerEndpoints() (err error) { Call: ex.pathExamplePost, }) + err = ex.trunks.Httpd.RegisterEndpoint(&libhttp.Endpoint{ + Method: libhttp.RequestMethodPost, + Path: pathExampleNamePage, + RequestType: libhttp.RequestTypeJSON, + ResponseType: libhttp.ResponseTypeJSON, + Call: ex.pathExamplePost, + }) + return err } @@ -289,6 +298,24 @@ func (ex *Example) registerTargets() (err error) { }, }, IsCustomizable: true, + }, { + Name: `HTTP Post path binding`, + Hint: `Test parameter with parameter in path`, + Method: libhttp.RequestMethodPost, + Path: pathExampleNamePage, + RequestType: libhttp.RequestTypeJSON, + Params: trunks.KeyFormInput{ + `name`: trunks.FormInput{ + Label: `Name`, + Hint: `This parameter send in path.`, + Value: `testname`, + }, + `id`: trunks.FormInput{ + Label: `ID`, + Hint: `This parameter send in body as JSON.`, + Value: `123`, + }, + }, }}, } diff --git a/go.mod b/go.mod index dc9404b..53a2641 100644 --- a/go.mod +++ b/go.mod @@ -7,7 +7,7 @@ go 1.20 require ( git.sr.ht/~shulhan/ciigo v0.11.0 - github.com/shuLhan/share v0.52.0 + github.com/shuLhan/share v0.52.1-0.20240125111329-f9b7b2734bb5 github.com/tsenart/vegeta/v12 v12.11.1 ) @@ -21,9 +21,9 @@ require ( github.com/rs/dnscache v0.0.0-20230804202142-fc85eb664529 // indirect github.com/yuin/goldmark v1.6.0 // indirect github.com/yuin/goldmark-meta v1.1.0 // indirect - golang.org/x/net v0.19.0 // indirect + golang.org/x/net v0.20.0 // indirect golang.org/x/sync v0.5.0 // indirect - golang.org/x/sys v0.15.0 // indirect + golang.org/x/sys v0.16.0 // indirect golang.org/x/text v0.14.0 // indirect gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect gopkg.in/yaml.v2 v2.4.0 // indirect diff --git a/go.sum b/go.sum index f8d15f3..de470d7 100644 --- a/go.sum +++ b/go.sum @@ -26,8 +26,8 @@ github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjR github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= github.com/rs/dnscache v0.0.0-20230804202142-fc85eb664529 h1:18kd+8ZUlt/ARXhljq+14TwAoKa61q6dX8jtwOf6DH8= github.com/rs/dnscache v0.0.0-20230804202142-fc85eb664529/go.mod h1:qe5TWALJ8/a1Lqznoc5BDHpYX/8HU60Hm2AwRmqzxqA= -github.com/shuLhan/share v0.52.0 h1:xbHez3JUYlt7WsUV8JOBLJOkd65P6dpp6zIq1EFXVvI= -github.com/shuLhan/share v0.52.0/go.mod h1:aNDs/SjnVYXaLEEJzjmfrUFeLD6u0YHWy6pI8o8iqYw= +github.com/shuLhan/share v0.52.1-0.20240125111329-f9b7b2734bb5 h1:Mrreh2BaoSDgO9IyqcstjfVwafJxlrgAqwNkyxxzNWw= +github.com/shuLhan/share v0.52.1-0.20240125111329-f9b7b2734bb5/go.mod h1:97/BcWdLau8i+xeFvPHdyqph1HgxVBSVhQEUIyCmgRc= github.com/streadway/quantile v0.0.0-20220407130108-4246515d968d h1:X4+kt6zM/OVO6gbJdAfJR60MGPsqCzbtXNnjoGqdfAs= github.com/tsenart/vegeta/v12 v12.11.1 h1:Rbwe7Zxr7sJ+BDTReemeQalYPvKiSV+O7nwmUs20B3E= github.com/tsenart/vegeta/v12 v12.11.1/go.mod h1:swiFmrgpqj2llHURgHYFRFN0tfrIrlnspg01HjwOnSQ= @@ -37,13 +37,13 @@ github.com/yuin/goldmark-meta v1.1.0 h1:pWw+JLHGZe8Rk0EGsMVssiNb/AaPMHfSRszZeUei github.com/yuin/goldmark-meta v1.1.0/go.mod h1:U4spWENafuA7Zyg+Lj5RqK/MF+ovMYtBvXi1lBb2VP0= golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20230713183714-613f0c0eb8a1 h1:MGwJjxBy0HJshjDNfLsYO8xppfqWlA5ZT9OhtUUhTNw= -golang.org/x/net v0.19.0 h1:zTwKpTd2XuCqf8huc7Fo2iSy+4RHPd10s4KzeTnVr1c= -golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U= +golang.org/x/net v0.20.0 h1:aCL9BSgETF1k+blQaYUBx9hJ9LOGP3gAVemcZlf1Kpo= +golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.5.0 h1:60k92dhOjHxJkrqnwsfl8KuaHbn/5dl0lUPUklKo3qE= golang.org/x/sync v0.5.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= -golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc= -golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU= +golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= diff --git a/http_target.go b/http_target.go index 8e42309..0ce1265 100644 --- a/http_target.go +++ b/http_target.go @@ -5,6 +5,7 @@ package trunks import ( "fmt" + "log" "os" "path/filepath" "sort" @@ -13,6 +14,7 @@ import ( libhttp "github.com/shuLhan/share/lib/http" "github.com/shuLhan/share/lib/mlog" + libpath "github.com/shuLhan/share/lib/path" vegeta "github.com/tsenart/vegeta/v12/lib" ) @@ -149,6 +151,44 @@ func (ht *HttpTarget) getResultByName(name string) (result *AttackResult) { return nil } +// paramsToPath fill the key in path with value from parameter. +// The key is sub-path that start with ":", for example "/:name", the key is +// name. +// The key in Params will be deleted if its exists in Path. +func (ht *HttpTarget) paramsToPath() { + var ( + logp = `paramsToPath` + + rute *libpath.Route + err error + ) + + rute, err = libpath.NewRoute(ht.Path) + if err != nil { + log.Printf(`%s %q: %s`, logp, ht.ID, err) + return + } + + var ( + fin FormInput + key string + ok bool + ) + + for _, key = range rute.Keys() { + fin, ok = ht.Params[key] + if !ok { + continue + } + ok = rute.Set(key, fin.Value) + if ok { + delete(ht.Params, key) + } + } + + ht.Path = rute.String() +} + func (ht *HttpTarget) sortResults() { sort.Slice(ht.Results, func(x, y int) bool { return ht.Results[x].Name > ht.Results[y].Name diff --git a/run_request.go b/run_request.go index 9dfd50a..2694288 100644 --- a/run_request.go +++ b/run_request.go @@ -55,6 +55,7 @@ func generateRunRequest( outrr.Target.Vars = req.Target.Vars outrr.HttpTarget.Headers = req.HttpTarget.Headers outrr.HttpTarget.Params = req.HttpTarget.Params + outrr.HttpTarget.paramsToPath() return outrr } diff --git a/trunks.go b/trunks.go index 1148c0d..9d47808 100644 --- a/trunks.go +++ b/trunks.go @@ -196,7 +196,7 @@ func (trunks *Trunks) RunHttp(req *RunRequest) (res *RunResponse, err error) { req.Target.BaseUrl = origTarget.BaseUrl req.Target.Name = origTarget.Name req.HttpTarget.ConvertParams = origHttpTarget.ConvertParams - res, err = trunks.runHttpTarget(req) + res, err = trunks.runHTTPTarget(req) } else { req = generateRunRequest(trunks.Env, req, origTarget, origHttpTarget) res, err = req.HttpTarget.Run(req) @@ -326,9 +326,11 @@ func (trunks *Trunks) getTargetByResultFilename(name string) (t *Target, ht *Htt return t, ht } -func (trunks *Trunks) runHttpTarget(rr *RunRequest) (res *RunResponse, err error) { +// runHTTPTarget default [HttpTarget.Run] handler that generate HTTP request +// and send it to the target. +func (trunks *Trunks) runHTTPTarget(rr *RunRequest) (res *RunResponse, err error) { var ( - logp = "runHttpTarget" + logp = `runHTTPTarget` headers = rr.HttpTarget.Headers.ToHttpHeader() params interface{} ) @@ -340,6 +342,8 @@ func (trunks *Trunks) runHttpTarget(rr *RunRequest) (res *RunResponse, err error httpc := libhttp.NewClient(httpcOpts) + rr.HttpTarget.paramsToPath() + if rr.HttpTarget.ConvertParams == nil { switch rr.HttpTarget.RequestType { case libhttp.RequestTypeJSON: -- cgit v1.3