///|
pub fn parse_header_block(input : String) -> Array[Header] {
let lines = split_lines(input)
let unfolded : Array[String] = []
for line in lines {
if is_header_continuation(line) && unfolded.length() > 0 {
let last = unfolded[unfolded.length() - 1]
unfolded[unfolded.length() - 1] = last + " " + trim_ascii(line)
} else if line != "" {
unfolded.push(line)
}
}
let headers : Array[Header] = []
for line in unfolded {
match split_once(line, ':') {
Some((name, value)) =>
headers.push(header(trim_ascii(name), trim_ascii(value)))
None => ()
}
}
headers
}
///|
pub fn header_value(headers : Array[Header], name : String) -> String {
let target = lower_ascii(name)
for item in headers {
if lower_ascii(item.name) == target {
return item.value
}
}
""
}
///|
pub fn all_header_values(
headers : Array[Header],
name : String,
) -> Array[String] {
let target = lower_ascii(name)
let out : Array[String] = []
for item in headers {
if lower_ascii(item.name) == target {
out.push(item.value)
}
}
out
}
///|
pub fn parse_content_type(value : String) -> ContentType {
let parts = split_char(value, ';')
let main = if parts.length() > 0 {
trim_ascii(parts[0])
} else {
"text/plain"
}
let media_parts = split_char(lower_ascii(main), '/')
let media_type = if media_parts.length() > 0 {
trim_ascii(media_parts[0])
} else {
"text"
}
let subtype = if media_parts.length() > 1 {
trim_ascii(media_parts[1])
} else {
"plain"
}
let params : Array[(String, String)] = []
let mut charset = if media_type == "text" { "us-ascii" } else { "" }
let mut boundary = ""
let mut name = ""
let mut i = 1
while i < parts.length() {
match split_once(parts[i], '=') {
Some((key, raw_value)) => {
let k = lower_ascii(trim_ascii(key))
let v = remove_quotes(raw_value)
params.push((k, v))
if k == "charset" {
charset = v
} else if k == "boundary" {
boundary = v
} else if k == "name" {
name = v
}
}
None => ()
}
i = i + 1
}
content_type(media_type, subtype, charset, boundary, name, params)
}
///|
pub fn content_type_from_headers(headers : Array[Header]) -> ContentType {
let value = header_value(headers, "Content-Type")
if value == "" {
default_content_type()
} else {
parse_content_type(value)
}
}
///|
pub fn parse_encoding(value : String) -> TransferEncoding {
match lower_ascii(trim_ascii(value)) {
"7bit" => SevenBit
"8bit" => EightBit
"binary" => Binary
"base64" => Base64
"quoted-printable" => QuotedPrintable
"" => SevenBit
other => UnknownEncoding(other)
}
}
///|
pub fn encoding_from_headers(headers : Array[Header]) -> TransferEncoding {
parse_encoding(header_value(headers, "Content-Transfer-Encoding"))
}
///|
pub fn disposition_from_headers(headers : Array[Header]) -> String {
let value = header_value(headers, "Content-Disposition")
if value == "" {
""
} else {
let parts = split_char(value, ';')
if parts.length() > 0 {
lower_ascii(trim_ascii(parts[0]))
} else {
""
}
}
}
///|
pub fn filename_from_headers(
headers : Array[Header],
ct : ContentType,
) -> String {
let disp = header_value(headers, "Content-Disposition")
let parts = split_char(disp, ';')
for part in parts {
match split_once(part, '=') {
Some((key, value)) =>
if lower_ascii(trim_ascii(key)) == "filename" {
return remove_quotes(value)
}
None => ()
}
}
ct.name
}