summaryrefslogtreecommitdiff
path: root/example.go
diff options
context:
space:
mode:
authorShulhan <ms@kilabit.info>2024-02-13 02:14:35 +0700
committerShulhan <ms@kilabit.info>2024-02-15 01:12:34 +0700
commit372d10a3e1ea01f8d03e44e6ab8be673d05c0773 (patch)
tree02df85cae2d4398cfd74ae193b05f490628cc517 /example.go
parentbc00c07248b1097f6e8f9281edc659cbd4bdd4ff (diff)
downloadgorankusu-372d10a3e1ea01f8d03e44e6ab8be673d05c0773.tar.xz
all: move example to root directory
The goal is to remove duplicate code in testing and show the example on how to create Gorankusu service from godoc. Implements: https://todo.sr.ht/~shulhan/gorankusu/5
Diffstat (limited to 'example.go')
-rw-r--r--example.go775
1 files changed, 775 insertions, 0 deletions
diff --git a/example.go b/example.go
new file mode 100644
index 0000000..16fa47b
--- /dev/null
+++ b/example.go
@@ -0,0 +1,775 @@
+// SPDX-FileCopyrightText: 2021 M. Shulhan <ms@kilabit.info>
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+package gorankusu
+
+import (
+ "context"
+ "encoding/json"
+ "fmt"
+ "mime/multipart"
+ "net/http"
+ "net/url"
+ "sync"
+ "time"
+
+ liberrors "github.com/shuLhan/share/lib/errors"
+ libhttp "github.com/shuLhan/share/lib/http"
+ "github.com/shuLhan/share/lib/mlog"
+ "github.com/shuLhan/share/lib/websocket"
+ vegeta "github.com/tsenart/vegeta/v12/lib"
+)
+
+const (
+ pathExample = `/example`
+ pathExampleError = `/example/error`
+ pathExampleNamePage = `/example/:name/page`
+ pathExampleRawbodyJSON = `/example/rawbody/json`
+ pathExampleUpload = `/example/upload`
+)
+
+const (
+ websocketAddress = `127.0.0.1:28240`
+)
+
+type requestResponse struct {
+ Method string
+ URL string
+ Headers http.Header
+ Form url.Values
+ MultipartForm *multipart.Form
+ Body string
+}
+
+// Example provide an example how to use the Gorankusu library from setting
+// it up to creating targets.
+//
+// To run the example, execute
+//
+// $ go run ./internal/cmd/gorankusu
+//
+// It will run a web user interface at http://127.0.0.1:8217 .
+type Example struct {
+ *Gorankusu
+ wsServer *websocket.Server
+
+ targetExampleErrorGet vegeta.Target
+ targetExampleGet vegeta.Target
+ targetExamplePostForm vegeta.Target
+}
+
+// NewExample create, initialize, and setup an example of Gorankusu.
+func NewExample() (ex *Example, err error) {
+ var logp = `NewExample`
+
+ var env = &Environment{
+ ResultsDir: `testdata/example/`,
+ ResultsSuffix: `example`,
+ }
+
+ ex = &Example{}
+
+ ex.Gorankusu, err = New(env)
+ if err != nil {
+ return nil, fmt.Errorf(`%s: %w`, logp, err)
+ }
+
+ err = ex.registerEndpoints()
+ if err != nil {
+ return nil, fmt.Errorf(`%s: %w`, logp, err)
+ }
+
+ // Create and register endpoint for WebSocket server.
+ var wsOpts = &websocket.ServerOptions{
+ Address: websocketAddress,
+ }
+
+ ex.wsServer = websocket.NewServer(wsOpts)
+
+ err = ex.registerWebSocketEndpoints()
+ if err != nil {
+ return nil, fmt.Errorf(`%s: %w`, logp, err)
+ }
+
+ // Register target for testing HTTP endpoints.
+ err = ex.registerTargetHTTP()
+ if err != nil {
+ return nil, fmt.Errorf(`%s: %w`, logp, err)
+ }
+
+ // Register target for testing WebSocket endpoints.
+ err = ex.registerTargetWebSocket()
+ if err != nil {
+ return nil, fmt.Errorf(`%s: %w`, logp, err)
+ }
+
+ err = ex.registerNavLinks()
+ if err != nil {
+ return nil, fmt.Errorf(`%s: %w`, logp, err)
+ }
+
+ return ex, nil
+}
+
+// Start the Example servers.
+func (ex *Example) Start() (err error) {
+ go func() {
+ err = ex.wsServer.Start()
+ if err != nil {
+ mlog.Errf(`example.Start: %s`, err)
+ }
+ }()
+
+ return ex.Gorankusu.Start()
+}
+
+// Stop the Example servers.
+func (ex *Example) Stop() {
+ ex.wsServer.Stop()
+ ex.Gorankusu.Stop()
+}
+
+// registerEndpoints register HTTP endpoints for testing.
+func (ex *Example) registerEndpoints() (err error) {
+ err = ex.Gorankusu.Httpd.RegisterEndpoint(&libhttp.Endpoint{
+ Method: libhttp.RequestMethodGet,
+ Path: pathExample,
+ RequestType: libhttp.RequestTypeQuery,
+ ResponseType: libhttp.ResponseTypeJSON,
+ Call: ex.pathExampleGet,
+ })
+ if err != nil {
+ return err
+ }
+
+ err = ex.Gorankusu.Httpd.RegisterEndpoint(&libhttp.Endpoint{
+ Method: libhttp.RequestMethodGet,
+ Path: pathExampleError,
+ RequestType: libhttp.RequestTypeQuery,
+ ResponseType: libhttp.ResponseTypeJSON,
+ Call: ex.pathExampleErrorGet,
+ })
+ if err != nil {
+ return err
+ }
+
+ err = ex.Gorankusu.Httpd.RegisterEndpoint(&libhttp.Endpoint{
+ Method: libhttp.RequestMethodPost,
+ Path: pathExample,
+ RequestType: libhttp.RequestTypeForm,
+ ResponseType: libhttp.ResponseTypeJSON,
+ Call: ex.pathExamplePost,
+ })
+
+ err = ex.Gorankusu.Httpd.RegisterEndpoint(&libhttp.Endpoint{
+ Method: libhttp.RequestMethodPost,
+ Path: pathExampleNamePage,
+ RequestType: libhttp.RequestTypeJSON,
+ ResponseType: libhttp.ResponseTypeJSON,
+ Call: ex.pathExamplePost,
+ })
+
+ err = ex.Gorankusu.Httpd.RegisterEndpoint(&libhttp.Endpoint{
+ Method: libhttp.RequestMethodPost,
+ Path: pathExampleRawbodyJSON,
+ RequestType: libhttp.RequestTypeJSON,
+ ResponseType: libhttp.ResponseTypeJSON,
+ Call: ex.pathExampleRawbodyJSON,
+ })
+
+ err = ex.Gorankusu.Httpd.RegisterEndpoint(&libhttp.Endpoint{
+ Method: libhttp.RequestMethodPost,
+ Path: pathExampleUpload,
+ RequestType: libhttp.RequestTypeMultipartForm,
+ ResponseType: libhttp.ResponseTypeJSON,
+ Call: ex.pathExampleUpload,
+ })
+
+ return err
+}
+
+func (ex *Example) registerWebSocketEndpoints() (err error) {
+ err = ex.wsServer.RegisterTextHandler(http.MethodGet, pathExample, ex.handleWSExampleGet)
+ if err != nil {
+ return err
+ }
+ return nil
+}
+
+func (ex *Example) registerTargetHTTP() (err error) {
+ var targetHTTP = &Target{
+ ID: `example_http`,
+ Name: `Example HTTP`,
+ Hint: `This section provide an example of HTTP endpoints that can be tested and attacked.`,
+ BaseURL: fmt.Sprintf(`http://%s`, ex.Gorankusu.Env.ListenAddress),
+ Opts: &AttackOptions{
+ Duration: 300 * time.Second,
+ RatePerSecond: 1,
+ },
+ Vars: KeyFormInput{
+ `A`: FormInput{
+ Label: `A`,
+ Hint: `This is the global variabel for all HTTP targets below.`,
+ Kind: FormInputKindNumber,
+ Value: `1`,
+ },
+ },
+ HTTPTargets: []*HTTPTarget{{
+ ID: `http_get`,
+ Name: `HTTP Get`,
+ Hint: fmt.Sprintf(`Test or attack endpoint %q using HTTP GET.`, pathExample),
+ Method: libhttp.RequestMethodGet,
+ Path: pathExample,
+ RequestType: libhttp.RequestTypeQuery,
+ Headers: KeyFormInput{
+ `X-Get`: FormInput{
+ Label: `X-Get`,
+ Hint: `Custom HTTP header to be send.`,
+ Kind: FormInputKindNumber,
+ Value: `1.1`,
+ },
+ },
+ Params: KeyFormInput{
+ `Param1`: FormInput{
+ Label: `Param1`,
+ Hint: `Parameter with number.`,
+ Kind: FormInputKindNumber,
+ Value: `1`,
+ },
+ },
+ Run: ex.runExampleGet,
+ AllowAttack: true,
+ Attack: ex.attackExampleGet,
+ PreAttack: ex.preattackExampleGet,
+ RequestDumper: requestDumperWithoutDate,
+ ResponseDumper: responseDumperWithoutDate,
+ }, {
+ ID: `http_error_get`,
+ Name: `HTTP Error Get`,
+ Hint: fmt.Sprintf(`Test error on endpoint %q using HTTP GET.`, pathExampleError),
+ Method: libhttp.RequestMethodGet,
+ Path: pathExampleError,
+ RequestType: libhttp.RequestTypeQuery,
+ Headers: KeyFormInput{
+ `X-Get`: FormInput{
+ Label: `X-Get`,
+ Hint: `Custom HTTP header to be send.`,
+ Kind: FormInputKindNumber,
+ Value: `1.1`,
+ },
+ },
+ Params: KeyFormInput{
+ `Param1`: FormInput{
+ Label: `Param1`,
+ Hint: `Parameter with number.`,
+ Kind: FormInputKindNumber,
+ Value: `1`,
+ },
+ },
+ Run: ex.runExampleGet,
+ AllowAttack: true,
+ Attack: ex.attackExampleErrorGet,
+ PreAttack: ex.preattackExampleErrorGet,
+ RequestDumper: requestDumperWithoutDate,
+ ResponseDumper: responseDumperWithoutDate,
+ }, {
+ ID: `http_post_form`,
+ Name: `HTTP Post Form`,
+ Hint: fmt.Sprintf(`Test or attack endpoint %q using HTTP POST.`, pathExample),
+ Method: libhttp.RequestMethodPost,
+ Path: pathExample,
+ RequestType: libhttp.RequestTypeForm,
+ Headers: KeyFormInput{
+ `X-PostForm`: FormInput{
+ Label: `X-PostForm`,
+ Hint: `Custom HTTP header to be send.`,
+ Kind: FormInputKindNumber,
+ Value: `1`,
+ },
+ },
+ Params: KeyFormInput{
+ `Param1`: FormInput{
+ Label: `Param1`,
+ Hint: `Parameter with number.`,
+ Kind: FormInputKindNumber,
+ Value: `1`,
+ },
+ `Param2`: FormInput{
+ Label: `Param2`,
+ Hint: `Parameter with string.`,
+ Kind: FormInputKindString,
+ Value: `a string`,
+ },
+ },
+ Run: ex.runExamplePostForm,
+ AllowAttack: true,
+ PreAttack: ex.preattackExamplePostForm,
+ Attack: ex.attackExamplePostForm,
+ RequestDumper: requestDumperWithoutDate,
+ ResponseDumper: responseDumperWithoutDate,
+ }, {
+ ID: `http_free_form`,
+ Name: `HTTP free form`,
+ Hint: fmt.Sprintf(`Test endpoint %q using custom HTTP method and/or content type.`, pathExample),
+ Method: libhttp.RequestMethodGet,
+ Path: pathExample,
+ RequestType: libhttp.RequestTypeForm,
+ Headers: KeyFormInput{
+ `X-FreeForm`: FormInput{
+ Label: `X-FreeForm`,
+ Hint: `Custom HTTP header to be send.`,
+ Kind: FormInputKindString,
+ Value: `1`,
+ },
+ },
+ Params: KeyFormInput{
+ `Param1`: FormInput{
+ Label: `Param1`,
+ Hint: `Parameter with number.`,
+ Kind: FormInputKindNumber,
+ Value: `123`,
+ },
+ },
+ RequestDumper: requestDumperWithoutDate,
+ ResponseDumper: responseDumperWithoutDate,
+ IsCustomizable: true,
+ }, {
+ ID: `http_post_path_binding`,
+ Name: `HTTP Post path binding`,
+ Hint: `Test parameter with parameter in path`,
+ Method: libhttp.RequestMethodPost,
+ Path: pathExampleNamePage,
+ RequestType: libhttp.RequestTypeJSON,
+ Params: KeyFormInput{
+ `name`: FormInput{
+ Label: `Name`,
+ Hint: `This parameter send in path.`,
+ Value: `testname`,
+ },
+ `id`: FormInput{
+ Label: `ID`,
+ Hint: `This parameter send in body as JSON.`,
+ Value: `123`,
+ },
+ },
+ RequestDumper: requestDumperWithoutDate,
+ ResponseDumper: responseDumperWithoutDate,
+ }, {
+ ID: `http_rawbody_json`,
+ Name: `HTTP raw body - JSON`,
+ Hint: `Test POST request with manually input raw JSON.`,
+ Method: libhttp.RequestMethodPost,
+ Path: pathExampleRawbodyJSON,
+ RequestType: libhttp.RequestTypeJSON,
+ RequestDumper: requestDumperWithoutDate,
+ ResponseDumper: responseDumperWithoutDate,
+ WithRawBody: true,
+ }, {
+ ID: `http_upload`,
+ Name: `HTTP upload`,
+ Hint: `Test uploading file`,
+ Method: libhttp.RequestMethodPost,
+ Path: pathExampleUpload,
+ RequestType: libhttp.RequestTypeMultipartForm,
+ Params: KeyFormInput{
+ `file`: FormInput{
+ Label: `File`,
+ Hint: `File to be uploaded.`,
+ Kind: FormInputKindFile,
+ FormDataName: func(key string) string {
+ if key == FormDataFilename {
+ return `name`
+ }
+ return key
+ },
+ },
+ `agree`: FormInput{
+ Label: `Agree`,
+ Hint: `Additional parameter along file.`,
+ Kind: FormInputKindBoolean,
+ },
+ },
+ RequestDumper: requestDumperWithoutDate,
+ ResponseDumper: responseDumperWithoutDate,
+ }},
+ }
+
+ err = ex.Gorankusu.RegisterTarget(targetHTTP)
+ if err != nil {
+ return err
+ }
+ return nil
+}
+
+func (ex *Example) registerTargetWebSocket() (err error) {
+ var targetWebSocket = &Target{
+ ID: `example_websocket`,
+ Name: `Example WebSocket`,
+ Hint: `This section provide an example of WebSocket endpoints that can be tested.`,
+ BaseURL: fmt.Sprintf(`ws://%s`, websocketAddress),
+ Opts: &AttackOptions{},
+ Vars: KeyFormInput{
+ `WebSocketVar`: FormInput{
+ Label: `WebSocketVar`,
+ Kind: FormInputKindString,
+ Value: `hello`,
+ },
+ },
+ WebSocketTargets: []*WebSocketTarget{{
+ ID: `ws_get`,
+ Name: `Similar to HTTP GET`,
+ Hint: `Test WebSocket endpoint with parameters.`,
+ Params: KeyFormInput{
+ `Param1`: FormInput{
+ Label: `Param1`,
+ Hint: `Parameter with kind is number.`,
+ Kind: `number`,
+ Value: `123`,
+ },
+ },
+ Run: ex.runWebSocketGet,
+ }},
+ }
+
+ err = ex.Gorankusu.RegisterTarget(targetWebSocket)
+ if err != nil {
+ return err
+ }
+
+ return nil
+}
+
+func (ex *Example) registerNavLinks() (err error) {
+ var logp = `registerNavLinks`
+
+ err = ex.Gorankusu.RegisterNavLink(&NavLink{
+ Text: `Link in IFrame`,
+ Href: `https://git.sr.ht/~shulhan/gorankusu`,
+ OpenInIFrame: true,
+ })
+ if err != nil {
+ return fmt.Errorf(`%s: %w`, logp, err)
+ }
+
+ err = ex.Gorankusu.RegisterNavLink(&NavLink{
+ Text: `Link in new window`,
+ Href: `https://git.sr.ht/~shulhan/gorankusu`,
+ })
+ if err != nil {
+ return fmt.Errorf(`%s: %w`, logp, err)
+ }
+
+ return nil
+}
+
+func (ex *Example) pathExampleGet(epr *libhttp.EndpointRequest) ([]byte, error) {
+ var data = &requestResponse{
+ Method: epr.HttpRequest.Method,
+ URL: epr.HttpRequest.URL.String(),
+ Headers: epr.HttpRequest.Header,
+ Form: epr.HttpRequest.Form,
+ MultipartForm: epr.HttpRequest.MultipartForm,
+ Body: string(epr.RequestBody),
+ }
+
+ var res = libhttp.EndpointResponse{}
+ res.Code = http.StatusOK
+ res.Message = pathExample
+ res.Data = data
+
+ return json.Marshal(&res)
+}
+
+func (ex *Example) pathExampleErrorGet(_ *libhttp.EndpointRequest) ([]byte, error) {
+ return nil, liberrors.Internal(fmt.Errorf(`server error`))
+}
+
+func (ex *Example) pathExamplePost(epr *libhttp.EndpointRequest) (resb []byte, err error) {
+ var data = &requestResponse{
+ Method: epr.HttpRequest.Method,
+ URL: epr.HttpRequest.URL.String(),
+ Headers: epr.HttpRequest.Header,
+ Form: epr.HttpRequest.Form,
+ MultipartForm: epr.HttpRequest.MultipartForm,
+ Body: string(epr.RequestBody),
+ }
+
+ var res = libhttp.EndpointResponse{}
+ res.Code = http.StatusOK
+ res.Message = pathExample
+ res.Data = data
+
+ return json.Marshal(&res)
+}
+
+func (ex *Example) pathExampleRawbodyJSON(epr *libhttp.EndpointRequest) (resbody []byte, err error) {
+ var (
+ logp = `pathExampleRawbodyJSON`
+ data map[string]any
+ )
+
+ err = json.Unmarshal(epr.RequestBody, &data)
+ if err != nil {
+ return nil, fmt.Errorf(`%s: %w`, logp, err)
+ }
+
+ var res = libhttp.EndpointResponse{}
+ res.Code = http.StatusOK
+ res.Data = data
+
+ resbody, err = json.Marshal(&res)
+ return resbody, err
+}
+
+func (ex *Example) pathExampleUpload(epr *libhttp.EndpointRequest) (resb []byte, err error) {
+ var logp = `pathExampleUpload`
+
+ var res = libhttp.EndpointResponse{}
+
+ res.Code = http.StatusOK
+ res.Data = epr.HttpRequest.MultipartForm.Value
+
+ resb, err = json.MarshalIndent(res, ``, ` `)
+ if err != nil {
+ return nil, fmt.Errorf(`%s: %w`, logp, err)
+ }
+
+ return resb, nil
+}
+
+func (ex *Example) runExampleGet(req *RunRequest) (res *RunResponse, err error) {
+ if req.Target.HTTPClient == nil {
+ var httpcOpts = &libhttp.ClientOptions{
+ ServerUrl: req.Target.BaseURL,
+ AllowInsecure: true,
+ }
+ req.Target.HTTPClient = libhttp.NewClient(httpcOpts)
+ }
+
+ res = &RunResponse{}
+
+ var (
+ headers = req.HTTPTarget.Headers.ToHTTPHeader()
+ params = req.HTTPTarget.Params.ToURLValues()
+
+ httpRequest *http.Request
+ )
+
+ httpRequest, err = req.Target.HTTPClient.GenerateHttpRequest(
+ req.HTTPTarget.Method,
+ req.HTTPTarget.Path,
+ req.HTTPTarget.RequestType,
+ headers,
+ params,
+ )
+ if err != nil {
+ return nil, err
+ }
+
+ err = res.SetHTTPRequest(req.HTTPTarget.RequestDumper, httpRequest)
+ if err != nil {
+ return nil, err
+ }
+
+ var httpResponse *http.Response
+
+ httpResponse, _, err = req.Target.HTTPClient.Do(httpRequest)
+ if err != nil {
+ return nil, err
+ }
+
+ err = res.SetHTTPResponse(req.HTTPTarget.ResponseDumper, httpResponse)
+ if err != nil {
+ return nil, err
+ }
+
+ return res, nil
+}
+
+func (ex *Example) preattackExampleErrorGet(rr *RunRequest) {
+ ex.targetExampleErrorGet = vegeta.Target{
+ Method: rr.HTTPTarget.Method.String(),
+ URL: fmt.Sprintf(`%s%s`, rr.Target.BaseURL, rr.HTTPTarget.Path),
+ Header: rr.HTTPTarget.Headers.ToHTTPHeader(),
+ }
+
+ var q = rr.HTTPTarget.Params.ToURLValues().Encode()
+ if len(q) > 0 {
+ ex.targetExampleErrorGet.URL += `?` + q
+ }
+
+ fmt.Printf("preattackExampleErrorGet: %+v\n", ex.targetExampleErrorGet)
+}
+
+func (ex *Example) preattackExampleGet(rr *RunRequest) {
+ ex.targetExampleGet = vegeta.Target{
+ Method: rr.HTTPTarget.Method.String(),
+ URL: fmt.Sprintf(`%s%s`, rr.Target.BaseURL, rr.HTTPTarget.Path),
+ Header: rr.HTTPTarget.Headers.ToHTTPHeader(),
+ }
+
+ var q = rr.HTTPTarget.Params.ToURLValues().Encode()
+ if len(q) > 0 {
+ ex.targetExampleGet.URL += `?` + q
+ }
+
+ fmt.Printf("preattackExampleGet: %+v\n", ex.targetExampleGet)
+}
+
+func (ex *Example) attackExampleErrorGet(rr *RunRequest) vegeta.Targeter {
+ return func(tgt *vegeta.Target) error {
+ rr.HTTPTarget.Lock()
+ *tgt = ex.targetExampleErrorGet
+ rr.HTTPTarget.Unlock()
+ return nil
+ }
+}
+
+func (ex *Example) attackExampleGet(rr *RunRequest) vegeta.Targeter {
+ return func(tgt *vegeta.Target) error {
+ rr.HTTPTarget.Lock()
+ *tgt = ex.targetExampleGet
+ rr.HTTPTarget.Unlock()
+ return nil
+ }
+}
+
+func (ex *Example) runExamplePostForm(req *RunRequest) (res *RunResponse, err error) {
+ if req.Target.HTTPClient == nil {
+ var httpcOpts = &libhttp.ClientOptions{
+ ServerUrl: req.Target.BaseURL,
+ AllowInsecure: true,
+ }
+ req.Target.HTTPClient = libhttp.NewClient(httpcOpts)
+ }
+
+ res = &RunResponse{}
+
+ var (
+ headers = req.HTTPTarget.Headers.ToHTTPHeader()
+ params = req.HTTPTarget.Params.ToURLValues()
+
+ httpRequest *http.Request
+ )
+
+ httpRequest, err = req.Target.HTTPClient.GenerateHttpRequest(
+ req.HTTPTarget.Method,
+ req.HTTPTarget.Path,
+ req.HTTPTarget.RequestType,
+ headers,
+ params,
+ )
+ if err != nil {
+ return nil, err
+ }
+
+ err = res.SetHTTPRequest(req.HTTPTarget.RequestDumper, httpRequest)
+ if err != nil {
+ return nil, err
+ }
+
+ var httpResponse *http.Response
+
+ httpResponse, _, err = req.Target.HTTPClient.Do(httpRequest)
+ if err != nil {
+ return nil, err
+ }
+
+ err = res.SetHTTPResponse(req.HTTPTarget.ResponseDumper, httpResponse)
+ if err != nil {
+ return nil, err
+ }
+
+ return res, nil
+}
+
+func (ex *Example) preattackExamplePostForm(rr *RunRequest) {
+ ex.targetExamplePostForm = vegeta.Target{
+ Method: rr.HTTPTarget.Method.String(),
+ URL: fmt.Sprintf(`%s%s`, rr.Target.BaseURL, rr.HTTPTarget.Path),
+ Header: rr.HTTPTarget.Headers.ToHTTPHeader(),
+ }
+
+ var q = rr.HTTPTarget.Params.ToURLValues().Encode()
+ if len(q) > 0 {
+ ex.targetExamplePostForm.Body = []byte(q)
+ }
+
+ fmt.Printf("preattackExamplePostForm: %+v\n", ex.targetExamplePostForm)
+}
+
+func (ex *Example) attackExamplePostForm(rr *RunRequest) vegeta.Targeter {
+ return func(tgt *vegeta.Target) error {
+ rr.HTTPTarget.Lock()
+ *tgt = ex.targetExamplePostForm
+ rr.HTTPTarget.Unlock()
+ return nil
+ }
+}
+
+func (ex *Example) handleWSExampleGet(_ context.Context, req *websocket.Request) (res websocket.Response) {
+ res.ID = req.ID
+ res.Code = http.StatusOK
+ res.Body = req.Body
+ return res
+}
+
+func (ex *Example) runWebSocketGet(rr *RunRequest) (res interface{}, err error) {
+ var wg sync.WaitGroup
+
+ var wsc = &websocket.Client{
+ Endpoint: `ws://` + websocketAddress,
+ HandleText: func(_ *websocket.Client, frame *websocket.Frame) error {
+ res = frame.Payload()
+ wg.Done()
+ return nil
+ },
+ }
+
+ err = wsc.Connect()
+ if err != nil {
+ return nil, err
+ }
+
+ var body []byte
+
+ body, err = json.Marshal(rr.WebSocketTarget.Params)
+ if err != nil {
+ return nil, err
+ }
+
+ var req = websocket.Request{
+ ID: uint64(time.Now().UnixNano()),
+ Method: http.MethodGet,
+ Target: pathExample,
+ Body: string(body),
+ }
+
+ var reqtext []byte
+
+ reqtext, err = json.Marshal(&req)
+ if err != nil {
+ return nil, err
+ }
+
+ err = wsc.SendText(reqtext)
+ if err != nil {
+ return nil, err
+ }
+ wg.Add(1)
+ wg.Wait()
+
+ _ = wsc.Close()
+
+ return res, nil
+}
+
+func requestDumperWithoutDate(req *http.Request) ([]byte, error) {
+ req.Header.Del(libhttp.HeaderDate)
+ return DumpHTTPRequest(req)
+}
+
+func responseDumperWithoutDate(resp *http.Response) ([]byte, error) {
+ resp.Header.Del(libhttp.HeaderDate)
+ return DumpHTTPResponse(resp)
+}