diff --git a/modules/caddytls/matchers.go b/modules/caddytls/matchers.go index 597450ef7..466292e41 100644 --- a/modules/caddytls/matchers.go +++ b/modules/caddytls/matchers.go @@ -85,7 +85,15 @@ func asciiServerNameForMatch(name string) string { return name } - // SNI is ASCII on the wire, but config can use Unicode IDNs. + // Fast path: if the name is pure ASCII, skip idna.ToASCII. + // SNI values on the wire are always ASCII (RFC 6066), and most + // config patterns are also ASCII. For pure ASCII input, idna.ToASCII + // only validates and lowercases, which is equivalent to our fallback. + if isPureASCII(name) { + return strings.ToLower(name) + } + + // Config can use Unicode IDNs. ascii, err := idna.ToASCII(name) if err == nil { return strings.ToLower(ascii) @@ -109,6 +117,15 @@ func asciiServerNameForMatch(name string) string { return strings.Join(labels, ".") } +func isPureASCII(s string) bool { + for i := 0; i < len(s); i++ { + if s[i] >= 0x80 { + return false + } + } + return true +} + // UnmarshalCaddyfile sets up the MatchServerName from Caddyfile tokens. Syntax: // // sni diff --git a/replacer.go b/replacer.go index 2ab02b602..2fa8ef137 100644 --- a/replacer.go +++ b/replacer.go @@ -427,14 +427,10 @@ func readFileIntoBuffer(filename string, size int) ([]byte, error) { } defer file.Close() - buffer := make([]byte, size) - n, err := file.Read(buffer) - if err != nil && err != io.EOF { - return nil, err - } - - // slice the buffer to the actual size - return buffer[:n], nil + // io.LimitReader ensures we never read more than 'size' bytes. + // io.ReadAll starts with a small buffer and grows it as needed, + // preventing a massive 1MB allocation for small files. + return io.ReadAll(io.LimitReader(file, int64(size))) } // ReplacementFunc is a function that is called when a