///|
fn optional_offer_values(values : Array[String]) -> Array[String?] {
let result : Array[String?] = []
if values.length() == 0 {
result.push(None)
} else {
for value in values {
result.push(Some(value))
}
}
result
}
///|
fn generated_variant_id(index : Int) -> String {
let buf = StringBuilder()
buf.write_string("variant-")
buf.write_string(index.to_string())
buf.to_string()
}
///|
fn build_response_variant(
index : Int,
media : String,
language : String?,
encoding : String?,
charset : String?,
) -> ServerVariant {
{
id: generated_variant_id(index),
media,
language,
encoding,
charset,
server_weight: 1000,
index,
}
}
///|
pub fn build_response_variants(
media_offers : Array[String],
language_offers : Array[String],
encoding_offers : Array[String],
charset_offers : Array[String],
) -> Array[ServerVariant] {
let variants : Array[ServerVariant] = []
let languages = optional_offer_values(language_offers)
let encodings = optional_offer_values(encoding_offers)
let charsets = optional_offer_values(charset_offers)
let mut index = 0
for media in media_offers {
for language in languages {
for encoding in encodings {
for charset in charsets {
variants.push(
build_response_variant(index, media, language, encoding, charset),
)
index = index + 1
}
}
}
}
variants
}
///|
fn has_charset_param(content_type : String) -> Bool {
match parse_content_type(content_type[:]) {
Ok(offer) => {
for param in offer.params {
if param.name == "charset" {
return true
}
}
false
}
Err(_) => content_type.to_lower().contains("charset=")
}
}
///|
fn content_type_header_value(
content_type : String,
charset : String?,
) -> String {
match charset {
Some(value) =>
if has_charset_param(content_type) {
content_type
} else {
let buf = StringBuilder()
buf.write_string(content_type)
buf.write_string("; charset=")
buf.write_string(value)
buf.to_string()
}
None => content_type
}
}
///|
fn push_header(headers : Array[Param], name : String, value : String) -> Unit {
if !value.is_empty() {
headers.push({ name, value })
}
}
///|
pub fn response_headers(summary : ResponseSummary) -> Array[Param] {
let headers : Array[Param] = []
match summary.content_type {
Some(value) =>
push_header(
headers,
"Content-Type",
content_type_header_value(value, summary.charset),
)
None => ()
}
match summary.content_language {
Some(value) => push_header(headers, "Content-Language", value)
None => ()
}
match summary.content_encoding {
Some(value) =>
if value != "identity" {
push_header(headers, "Content-Encoding", value)
}
None => ()
}
if summary.vary.length() > 0 {
push_header(headers, "Vary", join_header_names(summary.vary))
}
headers
}
///|
pub fn response_header_value(
summary : ResponseSummary,
name : StringView,
) -> String? {
let wanted = match normalize_header_name(name) {
Ok(value) => value
Err(_) => return None
}
for header in response_headers(summary) {
if normalize_header_name(header.name[:]) == Ok(wanted) {
return Some(header.value)
}
}
None
}
///|
pub fn format_response_headers(headers : Array[Param]) -> String {
let buf = StringBuilder()
for i in 0.. 0 {
buf.write_char('\n')
}
buf.write_string(headers[i].name)
buf.write_string(": ")
buf.write_string(headers[i].value)
}
buf.to_string()
}
///|
pub fn response_header_block(summary : ResponseSummary) -> String {
format_response_headers(response_headers(summary))
}
///|
pub fn negotiate_response_summary(
preferences : RequestPreferences,
media_offers : Array[String],
language_offers : Array[String],
encoding_offers : Array[String],
charset_offers : Array[String],
) -> Result[ResponseSummary, ParseError] {
let variants = build_response_variants(
media_offers, language_offers, encoding_offers, charset_offers,
)
match negotiate_variant(preferences, variants) {
Ok(decision) => Ok(summarize_response(decision))
Err(err) => Err(err)
}
}
///|
pub fn negotiate_response(
preferences : RequestPreferences,
media_offers : Array[String],
language_offers : Array[String],
encoding_offers : Array[String],
charset_offers : Array[String],
) -> Result[ResponseNegotiation, ParseError] {
let variants = build_response_variants(
media_offers, language_offers, encoding_offers, charset_offers,
)
match negotiate_variant(preferences, variants) {
Ok(decision) => {
let summary = summarize_response(decision)
let headers = response_headers(summary)
Ok({
decision,
summary,
headers,
header_block: format_response_headers(headers),
})
}
Err(err) => Err(err)
}
}