diff --git a/pkg/engine/parser/parser.go b/pkg/engine/parser/parser.go index 4fa13fc3..cb2fd378 100644 --- a/pkg/engine/parser/parser.go +++ b/pkg/engine/parser/parser.go @@ -2,6 +2,7 @@ package parser import ( "mime/multipart" + "net/http" "strings" "github.com/PuerkitoBio/goquery" @@ -63,6 +64,7 @@ var responseParsers = []responseParser{ {bodyParser, bodyMetaContentTagParser}, {bodyParser, bodyHtmlManifestTagParser}, {bodyParser, bodyHtmlDoctypeTagParser}, + {bodyParser, bodyHtmxAttrParser}, // custom field regex parser {bodyParser, customFieldRegexParser}, @@ -600,6 +602,44 @@ func bodyMetaContentTagParser(resp *navigation.Response) (navigationRequests []* return } +func bodyHtmxAttrParser(resp *navigation.Response) (navigationRequests []*navigation.Request) { + // exclude hx-delete + resp.Reader.Find("[hx-get],[hx-post],[hx-put],[hx-patch]").Each(func(i int, item *goquery.Selection) { + req := &navigation.Request{ + RootHostname: resp.RootHostname, + Depth: resp.Depth, + Source: resp.Resp.Request.URL.String(), + Tag: "htmx", + } + + if hxGet, ok := item.Attr("hx-get"); ok && hxGet != "" { + req.Method = http.MethodGet + req.URL = resp.AbsoluteURL(hxGet) + req.Attribute = "hx-get" + navigationRequests = append(navigationRequests, req) + } + if hxPost, ok := item.Attr(("hx-post")); ok && hxPost != "" { + req.Method = http.MethodPost + req.URL = resp.AbsoluteURL(hxPost) + req.Attribute = "hx-post" + navigationRequests = append(navigationRequests, req) + } + if hxPut, ok := item.Attr(("hx-put")); ok && hxPut != "" { + req.Method = http.MethodPut + req.URL = resp.AbsoluteURL(hxPut) + req.Attribute = "hx-put" + navigationRequests = append(navigationRequests, req) + } + if hxPatch, ok := item.Attr(("hx-patch")); ok && hxPatch != "" { + req.Method = http.MethodPatch + req.URL = resp.AbsoluteURL(hxPatch) + req.Attribute = "hx-patch" + navigationRequests = append(navigationRequests, req) + } + }) + return +} + // ------------------------------------------------------------------------- // Begin JS Regex based parsers // ------------------------------------------------------------------------- diff --git a/pkg/engine/parser/parser_test.go b/pkg/engine/parser/parser_test.go index ac9a580f..a381c875 100644 --- a/pkg/engine/parser/parser_test.go +++ b/pkg/engine/parser/parser_test.go @@ -489,3 +489,37 @@ func TestRegexBodyParsers(t *testing.T) { require.Equal(t, requireFields, navigationRequests[0].CustomFields, "could not get correct url") }) } + +func TestHtmxBodyParser(t *testing.T) { + parsed, _ := urlutil.Parse("https://htmx.org/examples/") + + t.Run("hx-get", func(t *testing.T) { + documentReader, _ := goquery.NewDocumentFromReader(strings.NewReader(``)) + resp := &navigation.Response{Resp: &http.Response{Request: &http.Request{URL: parsed.URL}}, Reader: documentReader} + navigationRequests := bodyHtmxAttrParser(resp) + require.Equal(t, "https://htmx.org/contact/1/edit", navigationRequests[0].URL, "could not get correct url") + require.Equal(t, "GET", navigationRequests[0].Method, "could not get correct method") + }) + t.Run("hx-post", func(t *testing.T) { + documentReader, _ := goquery.NewDocumentFromReader(strings.NewReader(`
`)) + resp := &navigation.Response{Resp: &http.Response{Request: &http.Request{URL: parsed.URL}}, Reader: documentReader} + navigationRequests := bodyHtmxAttrParser(resp) + require.Equal(t, "https://htmx.org/users", navigationRequests[0].URL, "could not get correct url") + require.Equal(t, "POST", navigationRequests[0].Method, "could not get correct method") + }) + t.Run("hx-put", func(t *testing.T) { + documentReader, _ := goquery.NewDocumentFromReader(strings.NewReader(`