Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
projectdiscovery
GitHub Repository: projectdiscovery/nuclei
Path: blob/dev/pkg/core/executors_test.go
2851 views
1
package core
2
3
import (
4
"context"
5
"fmt"
6
"sync/atomic"
7
"testing"
8
"time"
9
10
inputtypes "github.com/projectdiscovery/nuclei/v3/pkg/input/types"
11
"github.com/projectdiscovery/nuclei/v3/pkg/output"
12
"github.com/projectdiscovery/nuclei/v3/pkg/protocols"
13
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/contextargs"
14
"github.com/projectdiscovery/nuclei/v3/pkg/scan"
15
"github.com/projectdiscovery/nuclei/v3/pkg/templates"
16
tmpltypes "github.com/projectdiscovery/nuclei/v3/pkg/templates/types"
17
"github.com/projectdiscovery/nuclei/v3/pkg/types"
18
)
19
20
// fakeExecuter is a simple stub for protocols.Executer used to test executeTemplateOnInput
21
type fakeExecuter struct {
22
withResults bool
23
}
24
25
func (f *fakeExecuter) Compile() error { return nil }
26
func (f *fakeExecuter) Requests() int { return 1 }
27
func (f *fakeExecuter) Execute(ctx *scan.ScanContext) (bool, error) { return !f.withResults, nil }
28
func (f *fakeExecuter) ExecuteWithResults(ctx *scan.ScanContext) ([]*output.ResultEvent, error) {
29
if !f.withResults {
30
return nil, nil
31
}
32
return []*output.ResultEvent{{Host: "h"}}, nil
33
}
34
35
// newTestEngine creates a minimal Engine for tests
36
func newTestEngine() *Engine {
37
return New(&types.Options{})
38
}
39
40
func Test_executeTemplateOnInput_CallbackPath(t *testing.T) {
41
e := newTestEngine()
42
called := 0
43
e.Callback = func(*output.ResultEvent) { called++ }
44
45
tpl := &templates.Template{}
46
tpl.Executer = &fakeExecuter{withResults: true}
47
48
ok, err := e.executeTemplateOnInput(context.Background(), tpl, &contextargs.MetaInput{Input: "x"})
49
if err != nil {
50
t.Fatalf("unexpected error: %v", err)
51
}
52
if !ok {
53
t.Fatalf("expected match true")
54
}
55
if called == 0 {
56
t.Fatalf("expected callback to be called")
57
}
58
}
59
60
func Test_executeTemplateOnInput_ExecutePath(t *testing.T) {
61
e := newTestEngine()
62
tpl := &templates.Template{}
63
tpl.Executer = &fakeExecuter{withResults: false}
64
65
ok, err := e.executeTemplateOnInput(context.Background(), tpl, &contextargs.MetaInput{Input: "x"})
66
if err != nil {
67
t.Fatalf("unexpected error: %v", err)
68
}
69
if !ok {
70
t.Fatalf("expected match true from Execute path")
71
}
72
}
73
74
type fakeExecuterErr struct{}
75
76
func (f *fakeExecuterErr) Compile() error { return nil }
77
func (f *fakeExecuterErr) Requests() int { return 1 }
78
func (f *fakeExecuterErr) Execute(ctx *scan.ScanContext) (bool, error) { return false, nil }
79
func (f *fakeExecuterErr) ExecuteWithResults(ctx *scan.ScanContext) ([]*output.ResultEvent, error) {
80
return nil, fmt.Errorf("boom")
81
}
82
83
func Test_executeTemplateOnInput_CallbackErrorPropagates(t *testing.T) {
84
e := newTestEngine()
85
e.Callback = func(*output.ResultEvent) {}
86
tpl := &templates.Template{}
87
tpl.Executer = &fakeExecuterErr{}
88
89
ok, err := e.executeTemplateOnInput(context.Background(), tpl, &contextargs.MetaInput{Input: "x"})
90
if err == nil {
91
t.Fatalf("expected error to propagate")
92
}
93
if ok {
94
t.Fatalf("expected match to be false on error")
95
}
96
}
97
98
type fakeTargetProvider struct {
99
values []*contextargs.MetaInput
100
}
101
102
func (f *fakeTargetProvider) Count() int64 { return int64(len(f.values)) }
103
func (f *fakeTargetProvider) Iterate(cb func(value *contextargs.MetaInput) bool) {
104
for _, v := range f.values {
105
if !cb(v) {
106
return
107
}
108
}
109
}
110
func (f *fakeTargetProvider) Set(string, string) {}
111
func (f *fakeTargetProvider) SetWithProbe(string, string, inputtypes.InputLivenessProbe) error {
112
return nil
113
}
114
func (f *fakeTargetProvider) SetWithExclusions(string, string) error { return nil }
115
func (f *fakeTargetProvider) InputType() string { return "test" }
116
func (f *fakeTargetProvider) Close() {}
117
118
type slowExecuter struct{}
119
120
func (s *slowExecuter) Compile() error { return nil }
121
func (s *slowExecuter) Requests() int { return 1 }
122
func (s *slowExecuter) Execute(ctx *scan.ScanContext) (bool, error) {
123
select {
124
case <-ctx.Context().Done():
125
return false, ctx.Context().Err()
126
case <-time.After(200 * time.Millisecond):
127
return true, nil
128
}
129
}
130
func (s *slowExecuter) ExecuteWithResults(ctx *scan.ScanContext) ([]*output.ResultEvent, error) {
131
return nil, nil
132
}
133
134
func Test_executeTemplateWithTargets_RespectsCancellation(t *testing.T) {
135
e := newTestEngine()
136
e.SetExecuterOptions(&protocols.ExecutorOptions{Logger: e.Logger, ResumeCfg: types.NewResumeCfg(), ProtocolType: tmpltypes.HTTPProtocol})
137
138
tpl := &templates.Template{}
139
tpl.Executer = &slowExecuter{}
140
141
targets := &fakeTargetProvider{values: []*contextargs.MetaInput{{Input: "a"}, {Input: "b"}, {Input: "c"}}}
142
143
ctx, cancel := context.WithCancel(context.Background())
144
cancel()
145
146
var matched atomic.Bool
147
e.executeTemplateWithTargets(ctx, tpl, targets, &matched)
148
}
149
150