Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions ingress/ingress.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,12 @@ func (ing Ingress) FindMatchingRule(hostname, path string) (*Rule, int) {
}

func matchHost(ruleHost, reqHost string) bool {
// Hostnames are case-insensitive (RFC 4343, RFC 3986 §3.2.2), so compare
// them case-insensitively. cloudflared accepts mixed-case hostnames in
// ingress config, and the request Host header can also be mixed-case.
ruleHost = strings.ToLower(ruleHost)
reqHost = strings.ToLower(reqHost)

if ruleHost == reqHost {
return true
}
Expand Down
53 changes: 53 additions & 0 deletions ingress/matchhost_case_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package ingress

import (
"testing"

"github.com/stretchr/testify/assert"
)

// Hostnames are case-insensitive (RFC 4343, RFC 3986 §3.2.2). cloudflared
// accepts mixed-case hostnames in ingress config and the request Host header
// can be mixed-case, so rule matching must ignore case.
func TestMatchHostCaseInsensitive(t *testing.T) {
tests := []struct {
rule, req string
want bool
}{
{"myapp.example.com", "MyApp.example.com", true}, // mixed-case request Host
{"MyApp.example.com", "myapp.example.com", true}, // uppercase rule hostname
{"*.example.com", "foo.EXAMPLE.com", true}, // wildcard, mixed-case request
{"*.Example.com", "foo.example.com", true}, // wildcard, uppercase rule
{"a.example.com", "b.example.com", false}, // still a non-match
{"*.example.com", "example.com", false}, // wildcard does not match apex
}
for _, test := range tests {
assert.Equalf(t, test.want, matchHost(test.rule, test.req),
"matchHost(%q, %q)", test.rule, test.req)
}
}

// End-to-end: a mixed-case request Host resolves to the correct rule rather
// than falling through to the catch-all.
func TestFindMatchingRuleCaseInsensitive(t *testing.T) {
ingress := Ingress{
Rules: []Rule{
{Hostname: "tunnel-a.example.com"},
{Hostname: "*.wild.example.com"},
{Hostname: "*"}, // catch-all
},
}
tests := []struct {
host string
wantRuleIndex int
}{
{"Tunnel-A.example.com", 0},
{"TUNNEL-A.EXAMPLE.COM", 0},
{"Foo.Wild.Example.com", 1},
{"other.example.com", 2},
}
for _, test := range tests {
_, ruleIndex := ingress.FindMatchingRule(test.host, "/")
assert.Equalf(t, test.wantRuleIndex, ruleIndex, "host=%s", test.host)
}
}