use std::collections::HashSet;
#[must_use]
pub fn is_hop_by_hop(name: &str) -> bool {
name.eq_ignore_ascii_case("connection")
|| name.eq_ignore_ascii_case("keep-alive")
|| name.eq_ignore_ascii_case("proxy-authenticate")
|| name.eq_ignore_ascii_case("proxy-authorization")
|| name.eq_ignore_ascii_case("proxy-connection")
|| name.eq_ignore_ascii_case("te")
|| name.eq_ignore_ascii_case("trailer")
|| name.eq_ignore_ascii_case("transfer-encoding")
|| name.eq_ignore_ascii_case("upgrade")
}
#[must_use]
pub fn connection_header_tokens(connection_header_value: &str) -> HashSet<String> {
connection_header_value
.split(',')
.map(|s| s.trim().to_ascii_lowercase())
.filter(|s| !s.is_empty())
.collect()
}
#[must_use]
pub fn collect_connection_header_names(headers: &[(String, String)]) -> HashSet<String> {
let mut out = HashSet::new();
for (k, v) in headers {
if k.eq_ignore_ascii_case("connection") {
out.extend(connection_header_tokens(v));
}
}
out
}
#[must_use]
pub fn collect_connection_header_names_hyper(headers: &hyper::HeaderMap) -> HashSet<String> {
let mut out = HashSet::new();
for v in headers.get_all(hyper::header::CONNECTION) {
if let Ok(s) = v.to_str() {
out.extend(connection_header_tokens(s));
}
}
out
}
#[must_use]
pub fn should_strip_proxy_header(name: &str, connection_tokens_lower: &HashSet<String>) -> bool {
if is_hop_by_hop(name) {
return true;
}
connection_tokens_lower.contains(&name.to_ascii_lowercase())
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn detects_common_hop_by_hop() {
assert!(is_hop_by_hop("Connection"));
assert!(is_hop_by_hop("TRANSFER-ENCODING"));
assert!(is_hop_by_hop("Proxy-Connection"));
}
#[test]
fn allows_end_to_end() {
assert!(!is_hop_by_hop("Content-Type"));
assert!(!is_hop_by_hop("Authorization"));
}
#[test]
fn connection_tokens_case_insensitive() {
let t = connection_header_tokens("Foo, BAR, keep-alive ");
assert!(t.contains("foo"));
assert!(t.contains("bar"));
assert!(t.contains("keep-alive"));
}
#[test]
fn strip_respects_connection_list() {
let conn = connection_header_tokens("X-My-Hop");
assert!(should_strip_proxy_header("X-My-Hop", &conn));
assert!(!should_strip_proxy_header("X-Other", &conn));
}
}