diff --git a/core/handlers/v2/schema.json b/core/handlers/v2/schema.json index 1a5cd572b..d2d3755e4 100644 --- a/core/handlers/v2/schema.json +++ b/core/handlers/v2/schema.json @@ -220,6 +220,12 @@ } }, "type": "object" + }, + "postActionHooks": { + "items": { + "$ref": "#/definitions/post-action-hooks" + }, + "type": "array" } }, "type": "object" @@ -238,6 +244,53 @@ }, "required": ["name", "function"], "type": "object" + }, + "post-action-hooks": { + "properties": { + "name": { + "type": "string" + }, + "parameters": { + "properties": { + "method": { + "type": "string" + }, + "destination": { + "type": "string" + }, + "scheme": { + "type": "string", + "enum": [ + "http", + "https" + ] + }, + "path": { + "type": "string" + }, + "query": { + "additionalProperties": { + "items": { + "type": "string" + }, + "type": "array" + }, + "type": "object" + }, + "headers": { + "$ref": "#/definitions/headers" + }, + "body": { + "type": "string" + }, + "encodedBody": { + "type": "boolean" + } + }, + "type": "object" + } + }, + "type": "object" } }, "description": "Hoverfly simulation schema", diff --git a/core/handlers/v2/simulation_views_validation.go b/core/handlers/v2/simulation_views_validation.go index 503d88f89..96bbd914d 100644 --- a/core/handlers/v2/simulation_views_validation.go +++ b/core/handlers/v2/simulation_views_validation.go @@ -378,7 +378,7 @@ var responseDefinitionV4 = map[string]interface{}{ "$ref": "#/definitions/headers", }, "postActionHooks": map[string]interface{}{ - "$ref": "#/definitions/postActionHooks", + "$ref": "#/definitions/post-action-hooks", }, "status": map[string]interface{}{ "type": "integer", diff --git a/core/hoverfly.go b/core/hoverfly.go index 0a2403a5d..e42ee0d39 100644 --- a/core/hoverfly.go +++ b/core/hoverfly.go @@ -220,6 +220,24 @@ func (hf *Hoverfly) processRequest(req *http.Request) *http.Response { return result.Response } +// postProcessRequest - after a response, fire any webhooks that the user has configured. +func (hf *Hoverfly) postProcessRequest(req *http.Request) *http.Response { + requestDetails, err := models.NewRequestDetailsFromHttpRequest(req) + if err != nil { + log.Debug("Failed to process request for postProcessRequest") + } + response, matchingErr := hf.GetResponse(requestDetails) + // We really don't need to do anything here, if there is match just return + if matchingErr != nil { + return req.Response + } + _, err = hf.ApplyPostHooks(response) + if err != nil { + return modes.ErrorResponse(req, err, "There was an error when executing the post hooks").Response + } + return req.Response +} + func (hf *Hoverfly) applyResponseDelay(result modes.ProcessResult) { if result.FixedDelay > 0 { time.Sleep(time.Duration(result.FixedDelay) * time.Millisecond) diff --git a/core/hoverfly_funcs.go b/core/hoverfly_funcs.go index 42cb5103c..5edee0822 100644 --- a/core/hoverfly_funcs.go +++ b/core/hoverfly_funcs.go @@ -433,10 +433,10 @@ func (hf *Hoverfly) ApplyMiddleware(pair models.RequestResponsePair) (models.Req return pair, nil } -func (hf *Hoverfly) ApplyPostHooks(pair models.RequestResponsePair) (models.RequestResponsePair, error) { - if pair.Response.PostActionHooks != nil { - log.Debug("Post action hooks detected") - for _, postActionHook := range pair.Response.PostActionHooks { +func (hf *Hoverfly) ApplyPostHooks(resp *models.ResponseDetails) (*models.ResponseDetails, error) { + if resp.PostActionHooks != nil { + log.Info("Post action hooks detected") + for _, postActionHook := range resp.PostActionHooks { postActionHookStruct := &models.PostActionHook{} jsonBytes, err := json.Marshal(postActionHook) if err != nil { @@ -452,10 +452,13 @@ func (hf *Hoverfly) ApplyPostHooks(pair models.RequestResponsePair) (models.Requ // For now response is not needed, see what else we could need from it. _, err = postActionHookStruct.Execute() if err != nil { - return pair, err + log.Debug("There was an error executing the post hook") + return resp, err } log.Debug("Executed Post action hook") } + } else { + log.Debug("No post hooks found") } - return pair, nil + return resp, nil } diff --git a/core/modes/simulate_mode.go b/core/modes/simulate_mode.go index 6d697c6ad..58a762b27 100644 --- a/core/modes/simulate_mode.go +++ b/core/modes/simulate_mode.go @@ -11,7 +11,6 @@ import ( type HoverflySimulate interface { GetResponse(models.RequestDetails) (*models.ResponseDetails, *errors.HoverflyError) ApplyMiddleware(models.RequestResponsePair) (models.RequestResponsePair, error) - ApplyPostHooks(models.RequestResponsePair) (models.RequestResponsePair, error) } type SimulateMode struct { @@ -55,11 +54,6 @@ func (this SimulateMode) Process(request *http.Request, details models.RequestDe return ReturnErrorAndLog(request, err, &pair, "There was an error when executing middleware", Simulate) } - pair, err = this.Hoverfly.ApplyPostHooks(pair) - if err != nil { - return ReturnErrorAndLog(request, err, &pair, "There was an error when executing the post hooks", Spy) - } - return newProcessResult( ReconstructResponse(request, pair), pair.Response.FixedDelay, diff --git a/core/modes/spy_mode.go b/core/modes/spy_mode.go index c345bae04..51ab3588f 100644 --- a/core/modes/spy_mode.go +++ b/core/modes/spy_mode.go @@ -14,7 +14,6 @@ import ( type HoverflySpy interface { GetResponse(models.RequestDetails) (*models.ResponseDetails, *errors.HoverflyError) ApplyMiddleware(models.RequestResponsePair) (models.RequestResponsePair, error) - ApplyPostHooks(models.RequestResponsePair) (models.RequestResponsePair, error) DoRequest(*http.Request) (*http.Response, error) } @@ -69,10 +68,6 @@ func (this SpyMode) Process(request *http.Request, details models.RequestDetails if err != nil { return ReturnErrorAndLog(request, err, &pair, "There was an error when executing middleware", Spy) } - pair, err = this.Hoverfly.ApplyPostHooks(pair) - if err != nil { - return ReturnErrorAndLog(request, err, &pair, "There was an error when executing the post hooks", Spy) - } return newProcessResult( ReconstructResponse(request, pair), diff --git a/core/proxy.go b/core/proxy.go index 14bfaa8ac..e79d6eaf4 100644 --- a/core/proxy.go +++ b/core/proxy.go @@ -64,6 +64,15 @@ func NewProxy(hoverfly *Hoverfly) *goproxy.ProxyHttpServer { return r, resp }) + // Fire Post processing events + proxy.OnRequest(matchesFilter(hoverfly.Cfg.Destination)).DoFunc( + func(r *http.Request, ctx *goproxy.ProxyCtx) (*http.Request, *http.Response) { + // Important, clone the request as use of pointers lead to flaky behaviors + reqClone := r.Clone(ctx.Req.Context()) + go hoverfly.postProcessRequest(reqClone) + return r, ctx.Resp + }) + if hoverfly.Cfg.Verbose { proxy.OnRequest().DoFunc( func(r *http.Request, ctx *goproxy.ProxyCtx) (*http.Request, *http.Response) { @@ -126,6 +135,11 @@ func NewWebserverProxy(hoverfly *Hoverfly) *goproxy.ProxyHttpServer { w.Write([]byte(body)) hoverfly.Counter.Count(hoverfly.Cfg.GetMode()) + go func() { + // Important, clone the request as use of pointers lead to flaky behaviors + reqClone := r.Clone(r.Context()) + hoverfly.postProcessRequest(reqClone) + }() }) if hoverfly.Cfg.Verbose {