diff options
Diffstat (limited to 'third_party/rust/http/tests/header_map.rs')
-rw-r--r-- | third_party/rust/http/tests/header_map.rs | 638 |
1 files changed, 638 insertions, 0 deletions
diff --git a/third_party/rust/http/tests/header_map.rs b/third_party/rust/http/tests/header_map.rs new file mode 100644 index 0000000000..f2beba0862 --- /dev/null +++ b/third_party/rust/http/tests/header_map.rs @@ -0,0 +1,638 @@ +use http::header::*; +use http::*; + +#[test] +fn smoke() { + let mut headers = HeaderMap::new(); + + assert!(headers.get("hello").is_none()); + + let name: HeaderName = "hello".parse().unwrap(); + + match headers.entry(&name) { + Entry::Vacant(e) => { + e.insert("world".parse().unwrap()); + } + _ => panic!(), + } + + assert!(headers.get("hello").is_some()); + + match headers.entry(&name) { + Entry::Occupied(mut e) => { + assert_eq!(e.get(), &"world"); + + // Push another value + e.append("zomg".parse().unwrap()); + + let mut i = e.iter(); + + assert_eq!(*i.next().unwrap(), "world"); + assert_eq!(*i.next().unwrap(), "zomg"); + assert!(i.next().is_none()); + } + _ => panic!(), + } +} + +#[test] +#[should_panic] +fn reserve_over_capacity() { + // See https://github.com/hyperium/http/issues/352 + let mut headers = HeaderMap::<u32>::with_capacity(32); + headers.reserve(50_000); // over MAX_SIZE +} + +#[test] +fn with_capacity_max() { + // The largest capacity such that (cap + cap / 3) < MAX_SIZE. + HeaderMap::<u32>::with_capacity(24_576); +} + +#[test] +#[should_panic] +fn with_capacity_overflow() { + HeaderMap::<u32>::with_capacity(24_577); +} + +#[test] +#[should_panic] +fn reserve_overflow() { + // See https://github.com/hyperium/http/issues/352 + let mut headers = HeaderMap::<u32>::with_capacity(0); + headers.reserve(std::usize::MAX); // next_power_of_two overflows +} + +#[test] +fn drain() { + let mut headers = HeaderMap::new(); + + // Insert a single value + let name: HeaderName = "hello".parse().unwrap(); + headers.insert(name, "world".parse().unwrap()); + + { + let mut iter = headers.drain(); + let (name, value) = iter.next().unwrap(); + assert_eq!(name.unwrap().as_str(), "hello"); + + assert_eq!(value, "world"); + + assert!(iter.next().is_none()); + } + + assert!(headers.is_empty()); + + // Insert two sequential values + headers.insert( + "hello".parse::<HeaderName>().unwrap(), + "world".parse().unwrap(), + ); + headers.insert( + "zomg".parse::<HeaderName>().unwrap(), + "bar".parse().unwrap(), + ); + headers.append( + "hello".parse::<HeaderName>().unwrap(), + "world2".parse().unwrap(), + ); + + // Drain... + { + let mut iter = headers.drain(); + + let (name, value) = iter.next().unwrap(); + assert_eq!(name.unwrap().as_str(), "hello"); + assert_eq!(value, "world"); + + let (name, value) = iter.next().unwrap(); + assert_eq!(name, None); + assert_eq!(value, "world2"); + + let (name, value) = iter.next().unwrap(); + assert_eq!(name.unwrap().as_str(), "zomg"); + assert_eq!(value, "bar"); + + assert!(iter.next().is_none()); + } +} + +#[test] +fn drain_drop_immediately() { + // test mem::forgetting does not double-free + + let mut headers = HeaderMap::new(); + headers.insert("hello", "world".parse().unwrap()); + headers.insert("zomg", "bar".parse().unwrap()); + headers.append("hello", "world2".parse().unwrap()); + + let iter = headers.drain(); + assert_eq!(iter.size_hint(), (2, Some(3))); + // not consuming `iter` +} + +#[test] +fn drain_forget() { + // test mem::forgetting does not double-free + + let mut headers = HeaderMap::<HeaderValue>::new(); + headers.insert("hello", "world".parse().unwrap()); + headers.insert("zomg", "bar".parse().unwrap()); + + assert_eq!(headers.len(), 2); + + { + let mut iter = headers.drain(); + assert_eq!(iter.size_hint(), (2, Some(2))); + let _ = iter.next().unwrap(); + std::mem::forget(iter); + } + + assert_eq!(headers.len(), 0); +} + +#[test] +fn drain_entry() { + let mut headers = HeaderMap::new(); + + headers.insert( + "hello".parse::<HeaderName>().unwrap(), + "world".parse().unwrap(), + ); + headers.insert( + "zomg".parse::<HeaderName>().unwrap(), + "foo".parse().unwrap(), + ); + headers.append( + "hello".parse::<HeaderName>().unwrap(), + "world2".parse().unwrap(), + ); + headers.insert( + "more".parse::<HeaderName>().unwrap(), + "words".parse().unwrap(), + ); + headers.append( + "more".parse::<HeaderName>().unwrap(), + "insertions".parse().unwrap(), + ); + assert_eq!(5, headers.len()); + + // Using insert_mult + { + let mut e = match headers.entry("hello") { + Entry::Occupied(e) => e, + _ => panic!(), + }; + + let vals: Vec<_> = e.insert_mult("wat".parse().unwrap()).collect(); + assert_eq!(2, vals.len()); + assert_eq!(vals[0], "world"); + assert_eq!(vals[1], "world2"); + } + + assert_eq!(5-2+1, headers.len()); +} + +#[test] +fn eq() { + let mut a = HeaderMap::new(); + let mut b = HeaderMap::new(); + + assert_eq!(a, b); + + a.insert( + "hello".parse::<HeaderName>().unwrap(), + "world".parse().unwrap(), + ); + assert_ne!(a, b); + + b.insert( + "hello".parse::<HeaderName>().unwrap(), + "world".parse().unwrap(), + ); + assert_eq!(a, b); + + a.insert("foo".parse::<HeaderName>().unwrap(), "bar".parse().unwrap()); + a.append("foo".parse::<HeaderName>().unwrap(), "baz".parse().unwrap()); + assert_ne!(a, b); + + b.insert("foo".parse::<HeaderName>().unwrap(), "bar".parse().unwrap()); + assert_ne!(a, b); + + b.append("foo".parse::<HeaderName>().unwrap(), "baz".parse().unwrap()); + assert_eq!(a, b); + + a.append("a".parse::<HeaderName>().unwrap(), "a".parse().unwrap()); + a.append("a".parse::<HeaderName>().unwrap(), "b".parse().unwrap()); + b.append("a".parse::<HeaderName>().unwrap(), "b".parse().unwrap()); + b.append("a".parse::<HeaderName>().unwrap(), "a".parse().unwrap()); + + assert_ne!(a, b); +} + +#[test] +fn into_header_name() { + let mut m = HeaderMap::new(); + m.insert(HOST, "localhost".parse().unwrap()); + m.insert(&ACCEPT, "*/*".parse().unwrap()); + m.insert("connection", "keep-alive".parse().unwrap()); + + m.append(LOCATION, "/".parse().unwrap()); + m.append(&VIA, "bob".parse().unwrap()); + m.append("transfer-encoding", "chunked".parse().unwrap()); + + assert_eq!(m.len(), 6); +} + +#[test] +fn as_header_name() { + let mut m = HeaderMap::new(); + let v: HeaderValue = "localhost".parse().unwrap(); + m.insert(HOST, v.clone()); + + let expected = Some(&v); + + assert_eq!(m.get("host"), expected); + assert_eq!(m.get(&HOST), expected); + + let s = String::from("host"); + assert_eq!(m.get(&s), expected); + assert_eq!(m.get(s.as_str()), expected); +} + +#[test] +fn insert_all_std_headers() { + let mut m = HeaderMap::new(); + + for (i, hdr) in STD.iter().enumerate() { + m.insert(hdr.clone(), hdr.as_str().parse().unwrap()); + + for j in 0..(i + 1) { + assert_eq!(m[&STD[j]], STD[j].as_str()); + } + + if i != 0 { + for j in (i + 1)..STD.len() { + assert!( + m.get(&STD[j]).is_none(), + "contained {}; j={}", + STD[j].as_str(), + j + ); + } + } + } +} + +#[test] +fn insert_79_custom_std_headers() { + let mut h = HeaderMap::new(); + let hdrs = custom_std(79); + + for (i, hdr) in hdrs.iter().enumerate() { + h.insert(hdr.clone(), hdr.as_str().parse().unwrap()); + + for j in 0..(i + 1) { + assert_eq!(h[&hdrs[j]], hdrs[j].as_str()); + } + + for j in (i + 1)..hdrs.len() { + assert!(h.get(&hdrs[j]).is_none()); + } + } +} + +#[test] +fn append_multiple_values() { + let mut map = HeaderMap::new(); + + map.append(header::CONTENT_TYPE, "json".parse().unwrap()); + map.append(header::CONTENT_TYPE, "html".parse().unwrap()); + map.append(header::CONTENT_TYPE, "xml".parse().unwrap()); + + let vals = map + .get_all(&header::CONTENT_TYPE) + .iter() + .collect::<Vec<_>>(); + + assert_eq!(&vals, &[&"json", &"html", &"xml"]); +} + +fn custom_std(n: usize) -> Vec<HeaderName> { + (0..n) + .map(|i| { + let s = format!("{}-{}", STD[i % STD.len()].as_str(), i); + s.parse().unwrap() + }) + .collect() +} + +const STD: &'static [HeaderName] = &[ + ACCEPT, + ACCEPT_CHARSET, + ACCEPT_ENCODING, + ACCEPT_LANGUAGE, + ACCEPT_RANGES, + ACCESS_CONTROL_ALLOW_CREDENTIALS, + ACCESS_CONTROL_ALLOW_HEADERS, + ACCESS_CONTROL_ALLOW_METHODS, + ACCESS_CONTROL_ALLOW_ORIGIN, + ACCESS_CONTROL_EXPOSE_HEADERS, + ACCESS_CONTROL_MAX_AGE, + ACCESS_CONTROL_REQUEST_HEADERS, + ACCESS_CONTROL_REQUEST_METHOD, + AGE, + ALLOW, + ALT_SVC, + AUTHORIZATION, + CACHE_CONTROL, + CACHE_STATUS, + CDN_CACHE_CONTROL, + CONNECTION, + CONTENT_DISPOSITION, + CONTENT_ENCODING, + CONTENT_LANGUAGE, + CONTENT_LENGTH, + CONTENT_LOCATION, + CONTENT_RANGE, + CONTENT_SECURITY_POLICY, + CONTENT_SECURITY_POLICY_REPORT_ONLY, + CONTENT_TYPE, + COOKIE, + DNT, + DATE, + ETAG, + EXPECT, + EXPIRES, + FORWARDED, + FROM, + HOST, + IF_MATCH, + IF_MODIFIED_SINCE, + IF_NONE_MATCH, + IF_RANGE, + IF_UNMODIFIED_SINCE, + LAST_MODIFIED, + LINK, + LOCATION, + MAX_FORWARDS, + ORIGIN, + PRAGMA, + PROXY_AUTHENTICATE, + PROXY_AUTHORIZATION, + PUBLIC_KEY_PINS, + PUBLIC_KEY_PINS_REPORT_ONLY, + RANGE, + REFERER, + REFERRER_POLICY, + RETRY_AFTER, + SERVER, + SET_COOKIE, + STRICT_TRANSPORT_SECURITY, + TE, + TRAILER, + TRANSFER_ENCODING, + USER_AGENT, + UPGRADE, + UPGRADE_INSECURE_REQUESTS, + VARY, + VIA, + WARNING, + WWW_AUTHENTICATE, + X_CONTENT_TYPE_OPTIONS, + X_DNS_PREFETCH_CONTROL, + X_FRAME_OPTIONS, + X_XSS_PROTECTION, +]; + +#[test] +fn get_invalid() { + let mut headers = HeaderMap::new(); + headers.insert("foo", "bar".parse().unwrap()); + assert!(headers.get("Evil\r\nKey").is_none()); +} + +#[test] +#[should_panic] +fn insert_invalid() { + let mut headers = HeaderMap::new(); + headers.insert("evil\r\nfoo", "bar".parse().unwrap()); +} + +#[test] +fn value_htab() { + // RFC 7230 Section 3.2: + // > field-content = field-vchar [ 1*( SP / HTAB ) field-vchar ] + HeaderValue::from_static("hello\tworld"); + HeaderValue::from_str("hello\tworld").unwrap(); +} + + +#[test] +fn remove_multiple_a() { + let mut headers = HeaderMap::new(); + headers.insert(VIA, "1.1 example.com".parse().unwrap()); + headers.insert(SET_COOKIE, "cookie_1=value 1".parse().unwrap()); + headers.append(SET_COOKIE, "cookie_2=value 2".parse().unwrap()); + headers.append(VIA, "1.1 other.com".parse().unwrap()); + headers.append(SET_COOKIE, "cookie_3=value 3".parse().unwrap()); + headers.insert(VARY, "*".parse().unwrap()); + + assert_eq!(headers.len(), 6); + + let cookie = headers.remove(SET_COOKIE); + assert_eq!(cookie, Some("cookie_1=value 1".parse().unwrap())); + assert_eq!(headers.len(), 3); + + let via = headers.remove(VIA); + assert_eq!(via, Some("1.1 example.com".parse().unwrap())); + assert_eq!(headers.len(), 1); + + let vary = headers.remove(VARY); + assert_eq!(vary, Some("*".parse().unwrap())); + assert_eq!(headers.len(), 0); +} + +#[test] +fn remove_multiple_b() { + let mut headers = HeaderMap::new(); + headers.insert(VIA, "1.1 example.com".parse().unwrap()); + headers.insert(SET_COOKIE, "cookie_1=value 1".parse().unwrap()); + headers.append(SET_COOKIE, "cookie_2=value 2".parse().unwrap()); + headers.append(VIA, "1.1 other.com".parse().unwrap()); + headers.append(SET_COOKIE, "cookie_3=value 3".parse().unwrap()); + headers.insert(VARY, "*".parse().unwrap()); + + assert_eq!(headers.len(), 6); + + let vary = headers.remove(VARY); + assert_eq!(vary, Some("*".parse().unwrap())); + assert_eq!(headers.len(), 5); + + let via = headers.remove(VIA); + assert_eq!(via, Some("1.1 example.com".parse().unwrap())); + assert_eq!(headers.len(), 3); + + let cookie = headers.remove(SET_COOKIE); + assert_eq!(cookie, Some("cookie_1=value 1".parse().unwrap())); + assert_eq!(headers.len(), 0); +} + +#[test] +fn remove_entry_multi_0() { + let mut headers = HeaderMap::new(); + let cookies = remove_all_values(&mut headers, SET_COOKIE); + assert_eq!(cookies.len(), 0); + assert_eq!(headers.len(), 0); +} + +#[test] +fn remove_entry_multi_0_others() { + let mut headers = HeaderMap::new(); + headers.insert(VIA, "1.1 example.com".parse().unwrap()); + headers.append(VIA, "1.1 other.com".parse().unwrap()); + + let cookies = remove_all_values(&mut headers, SET_COOKIE); + assert_eq!(cookies.len(), 0); + assert_eq!(headers.len(), 2); +} + +#[test] +fn remove_entry_multi_1() { + let mut headers = HeaderMap::new(); + headers.insert(SET_COOKIE, "cookie_1=value 1".parse().unwrap()); + + let cookies = remove_all_values(&mut headers, SET_COOKIE); + assert_eq!(cookies.len(), 1); + assert_eq!(headers.len(), 0); +} + +#[test] +fn remove_entry_multi_1_other() { + let mut headers = HeaderMap::new(); + headers.insert(SET_COOKIE, "cookie_1=value 1".parse().unwrap()); + headers.insert(VIA, "1.1 example.com".parse().unwrap()); + + let cookies = remove_all_values(&mut headers, SET_COOKIE); + assert_eq!(cookies.len(), 1); + assert_eq!(headers.len(), 1); + + let vias = remove_all_values(&mut headers, VIA); + assert_eq!(vias.len(), 1); + assert_eq!(headers.len(), 0); +} + +// For issue hyperimum/http#446 +#[test] +fn remove_entry_multi_2() { + let mut headers = HeaderMap::new(); + headers.insert(SET_COOKIE, "cookie_1=value 1".parse().unwrap()); + headers.append(SET_COOKIE, "cookie_2=value 2".parse().unwrap()); + + let cookies = remove_all_values(&mut headers, SET_COOKIE); + assert_eq!(cookies.len(), 2); + assert_eq!(headers.len(), 0); +} + +#[test] +fn remove_entry_multi_3() { + let mut headers = HeaderMap::new(); + headers.insert(SET_COOKIE, "cookie_1=value 1".parse().unwrap()); + headers.append(SET_COOKIE, "cookie_2=value 2".parse().unwrap()); + headers.append(SET_COOKIE, "cookie_3=value 3".parse().unwrap()); + + let cookies = remove_all_values(&mut headers, SET_COOKIE); + assert_eq!(cookies.len(), 3); + assert_eq!(headers.len(), 0); +} + +#[test] +fn remove_entry_multi_3_others() { + let mut headers = HeaderMap::new(); + headers.insert(VIA, "1.1 example.com".parse().unwrap()); + headers.insert(SET_COOKIE, "cookie_1=value 1".parse().unwrap()); + headers.append(SET_COOKIE, "cookie_2=value 2".parse().unwrap()); + headers.append(VIA, "1.1 other.com".parse().unwrap()); + headers.append(SET_COOKIE, "cookie_3=value 3".parse().unwrap()); + headers.insert(VARY, "*".parse().unwrap()); + + let cookies = remove_all_values(&mut headers, SET_COOKIE); + assert_eq!(cookies.len(), 3); + assert_eq!(headers.len(), 3); + + let vias = remove_all_values(&mut headers, VIA); + assert_eq!(vias.len(), 2); + assert_eq!(headers.len(), 1); + + let varies = remove_all_values(&mut headers, VARY); + assert_eq!(varies.len(), 1); + assert_eq!(headers.len(), 0); +} + +fn remove_all_values<K>(headers: &mut HeaderMap, key: K) -> Vec<HeaderValue> + where K: IntoHeaderName +{ + match headers.entry(key) { + Entry::Occupied(e) => e.remove_entry_mult().1.collect(), + Entry::Vacant(_) => vec![], + } +} + +#[test] +fn remove_entry_3_others_a() { + let mut headers = HeaderMap::new(); + headers.insert(VIA, "1.1 example.com".parse().unwrap()); + headers.insert(SET_COOKIE, "cookie_1=value 1".parse().unwrap()); + headers.append(SET_COOKIE, "cookie_2=value 2".parse().unwrap()); + headers.append(VIA, "1.1 other.com".parse().unwrap()); + headers.append(SET_COOKIE, "cookie_3=value 3".parse().unwrap()); + headers.insert(VARY, "*".parse().unwrap()); + + assert_eq!(headers.len(), 6); + + let cookie = remove_values(&mut headers, SET_COOKIE); + assert_eq!(cookie, Some("cookie_1=value 1".parse().unwrap())); + assert_eq!(headers.len(), 3); + + let via = remove_values(&mut headers, VIA); + assert_eq!(via, Some("1.1 example.com".parse().unwrap())); + assert_eq!(headers.len(), 1); + + let vary = remove_values(&mut headers, VARY); + assert_eq!(vary, Some("*".parse().unwrap())); + assert_eq!(headers.len(), 0); +} + +#[test] +fn remove_entry_3_others_b() { + let mut headers = HeaderMap::new(); + headers.insert(VIA, "1.1 example.com".parse().unwrap()); + headers.insert(SET_COOKIE, "cookie_1=value 1".parse().unwrap()); + headers.append(SET_COOKIE, "cookie_2=value 2".parse().unwrap()); + headers.append(VIA, "1.1 other.com".parse().unwrap()); + headers.append(SET_COOKIE, "cookie_3=value 3".parse().unwrap()); + headers.insert(VARY, "*".parse().unwrap()); + + assert_eq!(headers.len(), 6); + + let vary = remove_values(&mut headers, VARY); + assert_eq!(vary, Some("*".parse().unwrap())); + assert_eq!(headers.len(), 5); + + let via = remove_values(&mut headers, VIA); + assert_eq!(via, Some("1.1 example.com".parse().unwrap())); + assert_eq!(headers.len(), 3); + + let cookie = remove_values(&mut headers, SET_COOKIE); + assert_eq!(cookie, Some("cookie_1=value 1".parse().unwrap())); + assert_eq!(headers.len(), 0); +} + +fn remove_values<K>(headers: &mut HeaderMap, key: K) -> Option<HeaderValue> + where K: IntoHeaderName +{ + match headers.entry(key) { + Entry::Occupied(e) => Some(e.remove_entry().1), + Entry::Vacant(_) => None, + } +} |