1
0
mirror of https://github.com/TwiN/gatus.git synced 2026-02-15 06:50:07 +00:00

fix: handle HTTP header names case-insensitively (#1506)

Details: HTTP header names should be case-insensitive per RFC 7230. When the users
configure the headers like 'user-agent' (lowercase), gatus was adding its own 'User-Agent'
header because the case-sensitive map lookup failed to find the existing header.

Fixed headers:
- User-Agent
- Content-Type
- Host

Fixes #1491"

Co-authored-by: TwiN <twin@linux.com>
This commit is contained in:
Anurag Ekkati
2026-01-24 18:49:16 -08:00
committed by GitHub
parent 720888009e
commit 48531911bb
2 changed files with 109 additions and 5 deletions

View File

@@ -21,6 +21,30 @@ import (
"github.com/TwiN/gatus/v5/test"
)
func TestHasHeader(t *testing.T) {
scenarios := []struct {
name string
headers map[string]string
lookup string
expected bool
}{
{name: "exact-match", headers: map[string]string{"User-Agent": "test"}, lookup: "User-Agent", expected: true},
{name: "lowercase-lookup", headers: map[string]string{"User-Agent": "test"}, lookup: "user-agent", expected: true},
{name: "uppercase-lookup", headers: map[string]string{"user-agent": "test"}, lookup: "USER-AGENT", expected: true},
{name: "mixed-case", headers: map[string]string{"UsEr-AgEnT": "test"}, lookup: "uSeR-aGeNt", expected: true},
{name: "not-found", headers: map[string]string{"Content-Type": "test"}, lookup: "User-Agent", expected: false},
{name: "empty-headers", headers: map[string]string{}, lookup: "User-Agent", expected: false},
{name: "nil-headers", headers: nil, lookup: "User-Agent", expected: false},
}
for _, scenario := range scenarios {
t.Run(scenario.name, func(t *testing.T) {
if result := hasHeader(scenario.headers, scenario.lookup); result != scenario.expected {
t.Errorf("expected %v, got %v", scenario.expected, result)
}
})
}
}
func TestEndpoint(t *testing.T) {
defer client.InjectHTTPClient(nil)
scenarios := []struct {
@@ -722,6 +746,76 @@ func TestEndpoint_buildHTTPRequestWithHostHeader(t *testing.T) {
}
}
func TestEndpoint_buildHTTPRequestWithLowercaseUserAgent(t *testing.T) {
condition := Condition("[STATUS] == 200")
endpoint := Endpoint{
Name: "website-health",
URL: "https://twin.sh/health",
Conditions: []Condition{condition},
Headers: map[string]string{
"user-agent": "CustomAgent/1.0",
},
}
err := endpoint.ValidateAndSetDefaults()
if err != nil {
t.Fatal("did not expect an error, got", err)
}
if _, exists := endpoint.Headers[UserAgentHeader]; exists {
t.Error("User-Agent header should not have been added since user-agent was already specified")
}
request := endpoint.buildHTTPRequest()
if userAgent := request.Header.Get("User-Agent"); userAgent != "CustomAgent/1.0" {
t.Errorf("request.Header.Get(User-Agent) should've been CustomAgent/1.0, but was %s", userAgent)
}
}
func TestEndpoint_buildHTTPRequestWithLowercaseContentType(t *testing.T) {
condition := Condition("[STATUS] == 200")
endpoint := Endpoint{
Name: "website-graphql",
URL: "https://twin.sh/graphql",
Method: "POST",
Conditions: []Condition{condition},
GraphQL: true,
Headers: map[string]string{
"content-type": "application/graphql",
},
Body: `{ users { id } }`,
}
err := endpoint.ValidateAndSetDefaults()
if err != nil {
t.Fatal("did not expect an error, got", err)
}
if _, exists := endpoint.Headers[ContentTypeHeader]; exists {
t.Error("Content-Type header should not have been added since content-type was already specified")
}
request := endpoint.buildHTTPRequest()
if contentType := request.Header.Get("Content-Type"); contentType != "application/graphql" {
t.Errorf("request.Header.Get(Content-Type) should've been application/graphql, but was %s", contentType)
}
}
func TestEndpoint_buildHTTPRequestWithLowercaseHostHeader(t *testing.T) {
condition := Condition("[STATUS] == 200")
endpoint := Endpoint{
Name: "website-health",
URL: "https://twin.sh/health",
Method: "POST",
Conditions: []Condition{condition},
Headers: map[string]string{
"host": "example.com",
},
}
err := endpoint.ValidateAndSetDefaults()
if err != nil {
t.Fatal("did not expect an error, got", err)
}
request := endpoint.buildHTTPRequest()
if request.Host != "example.com" {
t.Error("request.Host should've been example.com, but was", request.Host)
}
}
func TestEndpoint_buildHTTPRequestWithGraphQLEnabled(t *testing.T) {
condition := Condition("[STATUS] == 200")
endpoint := Endpoint{