use http::{HeaderMap, HeaderName, HeaderValue};
use crate::Error;
pub fn append_header_value(headers: &mut HeaderMap, name: HeaderName, value: HeaderValue) -> bool {
headers.append(name, value)
}
pub fn extract_single_header_value<'a>(
headers: &'a HeaderMap,
name: &HeaderName,
) -> Result<Option<&'a HeaderValue>, Error> {
let mut values = headers.get_all(name).iter();
let first = values.next();
if values.next().is_some() {
return Err(Error::duplicate_header(name.clone()));
}
Ok(first)
}
pub fn extract_single_header_text<'a>(
headers: &'a HeaderMap,
name: &HeaderName,
) -> Result<Option<&'a str>, Error> {
extract_single_header_value(headers, name)?
.map(|value| {
value
.to_str()
.map_err(|_| Error::invalid_header(name.clone()))
})
.transpose()
}
#[cfg(test)]
mod tests {
use http::{HeaderMap, HeaderValue, header::USER_AGENT};
use super::*;
#[test]
fn distinguishes_missing_invalid_and_duplicate() {
let mut headers = HeaderMap::new();
assert_eq!(extract_single_header_text(&headers, &USER_AGENT), Ok(None));
headers.insert(USER_AGENT, HeaderValue::from_bytes(&[0xff]).unwrap());
assert!(matches!(
extract_single_header_text(&headers, &USER_AGENT),
Err(Error::InvalidHeader { .. })
));
headers.clear();
headers.append(USER_AGENT, HeaderValue::from_static("one"));
headers.append(USER_AGENT, HeaderValue::from_static("two"));
assert!(matches!(
extract_single_header_text(&headers, &USER_AGENT),
Err(Error::DuplicateHeader { .. })
));
}
#[test]
fn append_preserves_existing_values() {
let mut headers = HeaderMap::new();
let name = HeaderName::from_static("x-example");
assert!(!append_header_value(
&mut headers,
name.clone(),
HeaderValue::from_static("first"),
));
assert!(append_header_value(
&mut headers,
name.clone(),
HeaderValue::from_static("second"),
));
assert_eq!(
headers
.get_all(name)
.iter()
.map(HeaderValue::to_str)
.collect::<Result<Vec<_>, _>>()
.unwrap(),
vec!["first", "second"]
);
}
}