diff --git a/types.go b/types.go index 6f79038b..95fce25d 100644 --- a/types.go +++ b/types.go @@ -438,25 +438,54 @@ func (rr *TXT) String() string { return rr.Hdr.String() + sprintTxt(rr.Txt) } func sprintName(s string) string { var dst strings.Builder - dst.Grow(len(s)) + for i := 0; i < len(s); { if i+1 < len(s) && s[i] == '\\' && s[i+1] == '.' { - dst.WriteString(s[i : i+2]) + if dst.Len() != 0 { + dst.WriteString(s[i : i+2]) + } i += 2 continue } b, n := nextByte(s, i) - switch { - case n == 0: - i++ // dangling back slash - case b == '.': - dst.WriteByte('.') + if n == 0 { + i++ + continue + } + if b == '.' { + if dst.Len() != 0 { + dst.WriteByte('.') + } + i += n + continue + } + switch b { + case ' ', '\'', '@', ';', '(', ')', '"', '\\': // additional chars to escape + if dst.Len() == 0 { + dst.Grow(len(s) * 2) + dst.WriteString(s[:i]) + } + dst.WriteByte('\\') + dst.WriteByte(b) default: - writeDomainNameByte(&dst, b) + if ' ' <= b && b <= '~' { + if dst.Len() != 0 { + dst.WriteByte(b) + } + } else { + if dst.Len() == 0 { + dst.Grow(len(s) * 2) + dst.WriteString(s[:i]) + } + dst.WriteString(escapeByte(b)) + } } i += n } + if dst.Len() == 0 { + return s + } return dst.String() } @@ -510,16 +539,6 @@ func sprintTxt(txt []string) string { return out.String() } -func writeDomainNameByte(s *strings.Builder, b byte) { - switch b { - case '.', ' ', '\'', '@', ';', '(', ')': // additional chars to escape - s.WriteByte('\\') - s.WriteByte(b) - default: - writeTXTStringByte(s, b) - } -} - func writeTXTStringByte(s *strings.Builder, b byte) { switch { case b == '"' || b == '\\': diff --git a/types_test.go b/types_test.go index a3400d96..251b3f39 100644 --- a/types_test.go +++ b/types_test.go @@ -133,6 +133,16 @@ func BenchmarkSprintName(b *testing.B) { } } +func BenchmarkSprintName_NoEscape(b *testing.B) { + for n := 0; n < b.N; n++ { + got := sprintName("large.example.com") + + if want := "large.example.com"; got != want { + b.Fatalf("expected %q, got %q", got, want) + } + } +} + func BenchmarkSprintTxtOctet(b *testing.B) { for n := 0; n < b.N; n++ { got := sprintTxtOctet("abc\\.def\007\"\127@\255\x05\xef\\") @@ -149,6 +159,7 @@ func BenchmarkSprintTxt(b *testing.B) { "example.com", } + b.ResetTimer() for n := 0; n < b.N; n++ { got := sprintTxt(txt)