Add parameter to configure the ban page Content-Type response header (#325)

* Add parameter to configure Ban Response Content-Type

* Add testing for new BanResponseContentType parameter

* Ensure there is a fallback to default Content-Type is user provided empty value

* Set Content-Type even if banTemplate is nil

* Add more edge cases for testing ban response Content-Type

* Add CR/LF validation for BanResponseContentType

* Add CaptchaResponseContentType to allow separate Content-Type configuration for captcha responses

* Add testing for new CaptchaResponseContentType

* Update README

* Split nil and CR/LF response Content-Type value validation into separate function

* Throw error instead of setting the default in case of empty parameter declaration

* Update testing accordingly

*  remove HTML from var name, add tests and infer content type from filePath

* 🍱 fix lint ?

* 🍱 fix lint

* 🍱 fix lint

* 🍱 fix lint + naming

* 🍱 fix lint

* 🍱 fuck lint

---------

Co-authored-by: maxlerebourg <maxlerebourg@gmail.com>
This commit is contained in:
omer
2026-06-28 22:30:48 +02:00
committed by GitHub
co-authored by maxlerebourg
parent f4dcd933c8
commit 7c73cb38dd
14 changed files with 168 additions and 63 deletions
+47 -3
View File
@@ -2,7 +2,6 @@ package crowdsec_bouncer_traefik_plugin //nolint:revive,stylecheck
import (
"context"
htmltemplate "html/template"
"net/http"
"net/http/httptest"
"reflect"
@@ -190,11 +189,11 @@ func Test_crowdsecQuery(t *testing.T) {
func TestHandleBanServeHTTPWithDifferentMethods(t *testing.T) {
html := "<html>You are banned</html>"
banTemplate, _ := htmltemplate.New("html").Parse(html)
banTemplate, _ := template.New("html").Delims("{{", "}}").Parse(html)
tests := []struct {
name string
method string
banTemplate *htmltemplate.Template
banTemplate *template.Template
expectBodyContent bool
}{
{
@@ -235,6 +234,7 @@ func TestHandleBanServeHTTPWithDifferentMethods(t *testing.T) {
remediationStatusCode: http.StatusForbidden,
remediationCustomHeader: "X-Test-Remediation",
banTemplate: tt.banTemplate,
banTemplateContentType: "text/html; charset=utf-8",
}
rw := httptest.NewRecorder()
@@ -269,6 +269,50 @@ func TestHandleBanServeHTTPWithDifferentMethods(t *testing.T) {
}
}
func TestHandleBanServeHTTPContentType(t *testing.T) {
html := "<html>You are banned</html>"
banTemplate, _ := template.New("html").Delims("{{", "}}").Parse(html)
tests := []struct {
name string
banTemplate *template.Template
banTemplateContentType string
}{
{
name: "Default HTML content type",
banTemplate: banTemplate,
banTemplateContentType: "text/html; charset=utf-8",
},
{
name: "Custom JSON content type",
banTemplate: banTemplate,
banTemplateContentType: "application/json",
},
{
name: "Content type set even when banTemplate is nil",
banTemplate: nil,
banTemplateContentType: "application/json",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
bouncer := &Bouncer{
remediationStatusCode: http.StatusForbidden,
banTemplate: tt.banTemplate,
banTemplateContentType: tt.banTemplateContentType,
}
rw := httptest.NewRecorder()
req := &http.Request{Method: http.MethodGet}
bouncer.handleBanServeHTTP(rw, req, "0.0.0.0", "TEST")
if got := rw.Header().Get("Content-Type"); got != tt.banTemplateContentType {
t.Errorf("Expected Content-Type %q, got %q", tt.banTemplateContentType, got)
}
})
}
}
func TestCaptchaMethodBasedLogic(t *testing.T) {
tests := []struct {
name string