This commit is contained in:
vasyansk committed 2026-11-02 17:37:51 +07:00
1 parent c5f1e64873
commit 550427e2d4
4 files changed
+141 -1

No files matched your search

+47 -1
View File
@@ -55,7 +55,9 @@ func normalizeName(name string) string {
// normalizeValue canonicalizes a single RR value for comparison.
func normalizeValue(t RecordType, content string) string {
if t == TXT {
return content // byte-exact — case and whitespace are significant (DKIM/SPF/DMARC)
// byte-exact — case and whitespace are significant (DKIM/SPF/DMARC);
// only the presentation quoting/chunking is stripped.
return TXTPayload(content)
}
c := strings.Join(strings.Fields(content), " ") // collapse whitespace
switch t {
@@ -95,3 +97,47 @@ func (r Record) Equal(o Record) bool {
}
return slices.Equal(r.NormalizedValues(), o.NormalizedValues())
}
// TXTPayload returns the logical content of a TXT value. A value written as
// one or more quoted strings ("a" "b") is the concatenation of their
// contents; an unquoted value is returned as is. This makes a template value
// without quotes comparable with the quoted form providers store.
func TXTPayload(v string) string {
t := strings.TrimSpace(v)
if !strings.HasPrefix(t, `"`) {
return v
}
var b strings.Builder
inQ := false
for i := 0; i < len(t); i++ {
c := t[i]
switch {
case inQ && c == '\\' && i+1 < len(t):
i++
b.WriteByte(t[i])
case c == '"':
inQ = !inQ
case inQ:
b.WriteByte(c)
}
}
return b.String()
}
// QuoteTXT renders a TXT value in the quoted form providers require: payload
// split into <=255-byte strings, each quoted. Already-quoted values pass
// through unchanged.
func QuoteTXT(v string) string {
if strings.HasPrefix(strings.TrimSpace(v), `"`) {
return v
}
const max = 255
esc := strings.NewReplacer(`\`, `\\`, `"`, `\"`)
var parts []string
for len(v) > max {
parts = append(parts, `"`+esc.Replace(v[:max])+`"`)
v = v[max:]
}
parts = append(parts, `"`+esc.Replace(v)+`"`)
return strings.Join(parts, " ")
}