// DKIM 规范化(RFC 6376 3.4)。
//
// simple 保留原字节,relaxed 做小写、折叠压缩与行尾空白清理;
// body 两种模式都要处理「末尾空行」与「缺少结尾 CRLF」。
///|
pub enum CanonMode {
Simple
Relaxed
}
///|
fn is_wsp_byte(b : Byte) -> Bool {
b == b' ' || b == b'\t'
}
///|
/// 规范化一个头部字段,输出总是以 CRLF 结尾。
pub fn canonicalize_header(field : HeaderField, mode : CanonMode) -> Bytes {
match mode {
Simple => {
let out : Array[Byte] = []
for b in field.raw {
out.push(b)
}
out.push(b'\r')
out.push(b'\n')
Bytes::from_array(out)
}
Relaxed => {
let raw = field.raw
let n = raw.length()
let mut colon = 0
while colon < n && raw[colon] != b':' {
colon = colon + 1
}
let out : Array[Byte] = []
// 字段名:去掉尾部 WSP 并转小写
let mut name_end = colon
while name_end > 0 && is_wsp_byte(raw[name_end - 1]) {
name_end = name_end - 1
}
for i in 0..= b'A' && b <= b'Z' {
out.push((b.to_uint() + 32U).to_byte())
} else {
out.push(b)
}
}
out.push(b':')
// 值:展开折叠、压缩 WSP、去掉首尾 WSP
let value = collect_relaxed_value(
raw,
if colon < n {
colon + 1
} else {
n
},
)
for b in value {
out.push(b)
}
out.push(b'\r')
out.push(b'\n')
Bytes::from_array(out)
}
}
}
///|
/// 收集 relaxed 头部值:CRLF 折叠变成单个 SP,WSP 序列压缩成一个 SP。
fn collect_relaxed_value(raw : Bytes, start : Int) -> Array[Byte] {
let out : Array[Byte] = []
let n = raw.length()
let mut i = start
let mut pending_wsp = false
let mut wrote_any = false
while i < n {
let b = raw[i]
if b == b'\r' || b == b'\n' {
// 折叠边界
pending_wsp = true
i = i + 1
continue
}
if is_wsp_byte(b) {
pending_wsp = true
i = i + 1
continue
}
if pending_wsp && wrote_any {
out.push(b' ')
}
pending_wsp = false
out.push(b)
wrote_any = true
i = i + 1
}
out
}
///|
/// 规范化正文。
pub fn canonicalize_body(body : Bytes, mode : CanonMode) -> Bytes {
let out : Array[Byte] = []
match mode {
Simple =>
for b in body {
out.push(b)
}
Relaxed => {
let n = body.length()
let mut pos = 0
while pos < n {
let line_start = pos
let mut line_end = pos
while line_end < n && body[line_end] != b'\n' {
line_end = line_end + 1
}
let content_end = if line_end > line_start &&
body[line_end - 1] == b'\r' {
line_end - 1
} else {
line_end
}
// 行内压缩 WSP,去掉行尾 WSP
let mut pending_wsp = false
let mut wrote = false
for i in line_start..= 4 &&
out[end - 4] == b'\r' &&
out[end - 3] == b'\n' &&
out[end - 2] == b'\r' &&
out[end - 1] == b'\n' {
end = end - 2
}
if end == 0 {
out.push(b'\r')
out.push(b'\n')
} else if end >= 2 && out[end - 2] == b'\r' && out[end - 1] == b'\n' {
// 已经是单个 CRLF 结尾
} else {
out.push(b'\r')
out.push(b'\n')
}
let result : Array[Byte] = []
let final_len = if end == 0 {
2
} else if out[end - 1] == b'\n' {
end
} else {
out.length()
}
for i in 0..