///|
pub(all) struct HeaderRepair {
input : String
output : String
changed : Bool
review : HeaderReview
disposition : Disposition
filename : FilenameReport?
} derive(Eq, Debug)
///|
pub fn repair_header(header : String) -> HeaderRepair {
repair_header_with_policy(header, FilenamePolicy::default())
}
///|
pub fn repair_header_with_policy(
header : String,
policy : FilenamePolicy,
) -> HeaderRepair {
let review = lint_header_with_policy(header, policy)
match parse_header(header) {
Ok(disposition) => {
let normalized = normalize_disposition_with_policy(disposition, policy)
let output = normalized.disposition.to_header()
{
input: header,
output,
changed: header != output || normalized.changed,
review,
disposition: normalized.disposition,
filename: normalized.filename,
}
}
Err(_) => {
let report = sanitize_filename_with_policy(policy.default_name, policy)
let fallback = DispositionBuilder::attachment()
.with_filename(report.value)
.build()
{
input: header,
output: fallback.to_header(),
changed: true,
review,
disposition: fallback,
filename: Some(report),
}
}
}
}
///|
pub fn canonicalize_header(header : String) -> Result[String, ParseError] {
match parse_header_strict(header) {
Ok(disposition) => Ok(disposition.to_header())
Err(err) => Err(err)
}
}
///|
pub fn canonicalize_header_loose(header : String) -> Result[String, ParseError] {
match parse_header(header) {
Ok(disposition) => Ok(disposition.to_header())
Err(err) => Err(err)
}
}
///|
pub fn HeaderRepair::is_lossless(self : HeaderRepair) -> Bool {
!self.changed && self.review.status == Accepted
}
///|
pub fn HeaderRepair::has_filename_change(self : HeaderRepair) -> Bool {
match self.filename {
Some(report) => report.changed
None => false
}
}
///|
pub fn HeaderRepair::to_text(self : HeaderRepair) -> String {
let buf = StringBuilder(
size_hint=self.input.length() + self.output.length() + 96,
)
buf.write_string("input: ")
buf.write_string(self.input)
buf.write_string("\noutput: ")
buf.write_string(self.output)
buf.write_string("\nchanged: ")
if self.changed {
buf.write_string("true")
} else {
buf.write_string("false")
}
buf.write_string("\nstatus: ")
buf.write_string(self.review.status.name())
match self.filename {
Some(report) => {
buf.write_string("\nfilename: ")
buf.write_string(report.value)
}
None => ()
}
buf.to_string()
}
///|
pub fn repair_headers(headers : Array[String]) -> Array[HeaderRepair] {
let repairs : Array[HeaderRepair] = []
for header in headers {
repairs.push(repair_header(header))
}
repairs
}
///|
pub fn repairs_to_headers(repairs : Array[HeaderRepair]) -> Array[String] {
let headers : Array[String] = []
for repair in repairs {
headers.push(repair.output)
}
headers
}
///|
pub fn repairs_to_text(repairs : Array[HeaderRepair]) -> String {
let buf = StringBuilder(size_hint=256)
let mut first = true
for repair in repairs {
if first {
first = false
} else {
buf.write_string("\n\n")
}
buf.write_string(repair.to_text())
}
buf.to_string()
}
///|
struct NormalizedDisposition {
disposition : Disposition
filename : FilenameReport?
changed : Bool
} derive(Eq, Debug)
///|
fn normalize_disposition_with_policy(
disposition : Disposition,
policy : FilenamePolicy,
) -> NormalizedDisposition {
let params : Array[Parameter] = []
let diagnostics = clone_diagnostics(disposition.diagnostics)
let mut filename_report : FilenameReport? = None
let mut saw_filename = false
let mut changed = false
for p in disposition.params {
if p.is_filename() {
if !saw_filename {
let report = sanitize_filename_with_policy(p.value, policy)
filename_report = Some(report)
params.push(Parameter::plain("filename", report.value))
if needs_extended_filename(report.value) {
params.push(
Parameter::extended(
"filename",
report.value,
charset="UTF-8",
language="",
),
)
}
if report.changed || p.effective_name() != "filename" {
changed = true
}
saw_filename = true
} else {
changed = true
}
} else if !has_equivalent_parameter(params, p) {
params.push(p)
} else {
changed = true
}
}
let normalized : Disposition = { kind: disposition.kind, params, diagnostics }
{ disposition: normalized, filename: filename_report, changed }
}
///|
fn has_equivalent_parameter(
params : Array[Parameter],
candidate : Parameter,
) -> Bool {
for p in params {
if p.name == candidate.name && p.extended == candidate.extended {
return true
}
}
false
}