Skip to content

Commit

Permalink
error handling + support offlinehttp in flow templates (#4653)
Browse files Browse the repository at this point in the history
  • Loading branch information
tarunKoyalwar authored Jan 17, 2024
1 parent 44745cb commit 68b9dd5
Show file tree
Hide file tree
Showing 3 changed files with 32 additions and 17 deletions.
14 changes: 10 additions & 4 deletions pkg/templates/compile.go
Original file line number Diff line number Diff line change
Expand Up @@ -183,8 +183,9 @@ func (template *Template) compileProtocolRequests(options *protocols.ExecutorOpt
requests = append(requests, template.convertRequestToProtocolsRequest(template.RequestsJavascript)...)
}
}
template.Executer = tmplexec.NewTemplateExecuter(requests, options)
return nil
var err error
template.Executer, err = tmplexec.NewTemplateExecuter(requests, options)
return err
}

// convertRequestToProtocolsRequest is a convenience wrapper to convert
Expand Down Expand Up @@ -228,8 +229,13 @@ mainLoop:
}
if len(operatorsList) > 0 {
options.Operators = operatorsList
template.Executer = tmplexec.NewTemplateExecuter([]protocols.Request{&offlinehttp.Request{}}, options)
return nil
var err error
template.Executer, err = tmplexec.NewTemplateExecuter([]protocols.Request{&offlinehttp.Request{}}, options)
if err != nil {
// it seems like flow executor cannot be used for offline http matching (ex:http(1) && http(2))
return ErrIncompatibleWithOfflineMatching
}
return err
}

return ErrIncompatibleWithOfflineMatching
Expand Down
25 changes: 16 additions & 9 deletions pkg/tmplexec/exec.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ type TemplateExecuter struct {
var _ protocols.Executer = &TemplateExecuter{}

// NewTemplateExecuter creates a new request TemplateExecuter for list of requests
func NewTemplateExecuter(requests []protocols.Request, options *protocols.ExecutorOptions) *TemplateExecuter {
func NewTemplateExecuter(requests []protocols.Request, options *protocols.ExecutorOptions) (*TemplateExecuter, error) {
isMultiProto := false
lastProto := ""
for _, request := range requests {
Expand All @@ -47,7 +47,11 @@ func NewTemplateExecuter(requests []protocols.Request, options *protocols.Execut
// we use a dummy input here because goal of flow executor at this point is to just check
// syntax and other things are correct before proceeding to actual execution
// during execution new instance of flow will be created as it is tightly coupled with lot of executor options
e.engine = flow.NewFlowExecutor(requests, scan.NewScanContext(contextargs.NewWithInput("dummy")), options, e.results)
var err error
e.engine, err = flow.NewFlowExecutor(requests, scan.NewScanContext(contextargs.NewWithInput("dummy")), options, e.results)
if err != nil {
return nil, fmt.Errorf("could not create flow executor: %s", err)
}
} else {
// Review:
// multiproto engine is only used if there is more than one protocol in template
Expand All @@ -58,8 +62,7 @@ func NewTemplateExecuter(requests []protocols.Request, options *protocols.Execut
e.engine = generic.NewGenericEngine(requests, options, e.results)
}
}

return e
return e, nil
}

// Compile compiles the execution generators preparing any requests possible.
Expand Down Expand Up @@ -146,7 +149,7 @@ func (e *TemplateExecuter) Execute(ctx *scan.ScanContext) (bool, error) {
}
}
}
var err error
var errx error

// Note: this is required for flow executor
// flow executer is tightly coupled with lot of executor options
Expand All @@ -155,20 +158,24 @@ func (e *TemplateExecuter) Execute(ctx *scan.ScanContext) (bool, error) {
// so in compile step earlier we compile it to validate javascript syntax and other things
// and while executing we create new instance of flow executor everytime
if e.options.Flow != "" {
flowexec := flow.NewFlowExecutor(e.requests, ctx, e.options, results)
flowexec, err := flow.NewFlowExecutor(e.requests, ctx, e.options, results)
if err != nil {
ctx.LogError(err)
return false, fmt.Errorf("could not create flow executor: %s", err)
}
if err := flowexec.Compile(); err != nil {
ctx.LogError(err)
return false, err
}
err = flowexec.ExecuteWithResults(ctx)
errx = flowexec.ExecuteWithResults(ctx)
} else {
err = e.engine.ExecuteWithResults(ctx)
errx = e.engine.ExecuteWithResults(ctx)
}

if lastMatcherEvent != nil {
writeFailureCallback(lastMatcherEvent, e.options.Options.MatcherStatus)
}
return results.Load(), err
return results.Load(), errx
}

// ExecuteWithResults executes the protocol requests and returns results instead of writing them.
Expand Down
10 changes: 6 additions & 4 deletions pkg/tmplexec/flow/flow_executor.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ type FlowExecutor struct {
// NewFlowExecutor creates a new flow executor from a list of requests
// Note: Unlike other engine for every target x template flow needs to be compiled and executed everytime
// unlike other engines where we compile once and execute multiple times
func NewFlowExecutor(requests []protocols.Request, ctx *scan.ScanContext, options *protocols.ExecutorOptions, results *atomic.Bool) *FlowExecutor {
func NewFlowExecutor(requests []protocols.Request, ctx *scan.ScanContext, options *protocols.ExecutorOptions, results *atomic.Bool) (*FlowExecutor, error) {
allprotos := make(map[string][]protocols.Request)
for _, req := range requests {
switch req.Type() {
Expand All @@ -79,9 +79,11 @@ func NewFlowExecutor(requests []protocols.Request, ctx *scan.ScanContext, option
allprotos[templateTypes.CodeProtocol.String()] = append(allprotos[templateTypes.CodeProtocol.String()], req)
case templateTypes.JavascriptProtocol:
allprotos[templateTypes.JavascriptProtocol.String()] = append(allprotos[templateTypes.JavascriptProtocol.String()], req)
case templateTypes.OfflineHTTPProtocol:
// offlinehttp is run in passive mode but templates are same so instead of using offlinehttp() we use http() in flow
allprotos[templateTypes.HTTPProtocol.String()] = append(allprotos[templateTypes.OfflineHTTPProtocol.String()], req)
default:
ctx.LogError(fmt.Errorf("invalid request type %s", req.Type().String()))
return nil
return nil, fmt.Errorf("invalid request type %s", req.Type().String())
}
}
f := &FlowExecutor{
Expand All @@ -96,7 +98,7 @@ func NewFlowExecutor(requests []protocols.Request, ctx *scan.ScanContext, option
jsVM: protocolstate.NewJSRuntime(),
ctx: ctx,
}
return f
return f, nil
}

// Compile compiles js program and registers all functions
Expand Down

0 comments on commit 68b9dd5

Please sign in to comment.