diff --git a/cmd/integration-test/http.go b/cmd/integration-test/http.go index b11e48ccc..f5bb031d1 100644 --- a/cmd/integration-test/http.go +++ b/cmd/integration-test/http.go @@ -12,6 +12,7 @@ import ( "strconv" "strings" "sync" + "sync/atomic" "time" "github.com/julienschmidt/httprouter" @@ -90,6 +91,8 @@ var httpTestcases = []TestCaseInfo{ {Path: "protocols/http/multi-http-var-sharing.yaml", TestCase: &httpMultiVarSharing{}}, {Path: "protocols/http/raw-path-single-slash.yaml", TestCase: &httpRawPathSingleSlash{}}, {Path: "protocols/http/raw-unsafe-path-single-slash.yaml", TestCase: &httpRawUnsafePathSingleSlash{}}, + {Path: "protocols/http/disable-http-cache.yaml", TestCase: &httpDisableCache{}}, + {Path: "protocols/http/http-cache.yaml", TestCase: &httpCache{}}, } type httpMultiVarSharing struct{} @@ -1756,3 +1759,67 @@ func (h *httpRawUnsafePathSingleSlash) Execute(filepath string) error { } return nil } + +type httpCache struct{} + +func (h *httpCache) Execute(filePath string) error { + router := httprouter.New() + var requestCount int32 + router.GET("/", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { + atomic.AddInt32(&requestCount, 1) + w.Header().Set("Cache-Control", "max-age=2") + w.WriteHeader(http.StatusOK) + _, _ = fmt.Fprint(w, requestCount) + }) + ts := httptest.NewServer(router) + defer ts.Close() + + results, err := testutils.RunNucleiTemplateAndGetResults(filePath, ts.URL, debug) + if err != nil { + return err + } + + // We expect 2 results because we made 2 requests and both should match + if err := expectResultsCount(results, 2); err != nil { + return err + } + + // We expect only 1 actual request to the server because of caching + if count := atomic.LoadInt32(&requestCount); count != 1 { + return fmt.Errorf("expected 1 request to server, got %d", count) + } + + return nil +} + +type httpDisableCache struct{} + +func (h *httpDisableCache) Execute(filePath string) error { + var requestCount int32 + router := httprouter.New() + router.GET("/", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { + atomic.AddInt32(&requestCount, 1) + w.Header().Set("Cache-Control", "max-age=2") + w.WriteHeader(http.StatusOK) + _, _ = fmt.Fprint(w, requestCount) + }) + ts := httptest.NewServer(router) + defer ts.Close() + + results, err := testutils.RunNucleiTemplateAndGetResults(filePath, ts.URL, debug) + if err != nil { + return err + } + + // We expect 2 results because we made 2 requests and both should match + if err := expectResultsCount(results, 2); err != nil { + return err + } + + // We expect 2 actual requests to the server because cache is disabled + if count := atomic.LoadInt32(&requestCount); count != 2 { + return fmt.Errorf("expected 2 requests to server, got %d", count) + } + + return nil +} diff --git a/integration_tests/protocols/http/disable-http-cache.yaml b/integration_tests/protocols/http/disable-http-cache.yaml new file mode 100644 index 000000000..5c3d5ffaf --- /dev/null +++ b/integration_tests/protocols/http/disable-http-cache.yaml @@ -0,0 +1,23 @@ +id: disable-http-cache + +info: + name: Disable HTTP Cache Test + author: dwisiswant0 + severity: info + description: Tests if disable-http-cache works as expected + tags: test + +requests: + - raw: + - | + GET / HTTP/1.1 + Host: {{Hostname}} + - | + GET / HTTP/1.1 + Host: {{Hostname}} + disable-http-cache: true + matchers: + - type: dsl + dsl: + - body_1 == "1" + - body_2 == "2" diff --git a/integration_tests/protocols/http/http-cache.yaml b/integration_tests/protocols/http/http-cache.yaml new file mode 100644 index 000000000..d146f2984 --- /dev/null +++ b/integration_tests/protocols/http/http-cache.yaml @@ -0,0 +1,23 @@ +id: http-cache + +info: + name: HTTP Cache Test + author: dwisiswant0 + severity: info + description: Tests if HTTP cache (RFC 9111) works as expected + tags: test + +requests: + - raw: + - | + GET / HTTP/1.1 + Host: {{Hostname}} + - | + GET / HTTP/1.1 + Host: {{Hostname}} + disable-http-cache: false + matchers: + - type: dsl + dsl: + - body_1 == "1" + - body_2 == "1"