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::::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::::with_capacity(24_576); } #[test] #[should_panic] fn with_capacity_overflow() { HeaderMap::::with_capacity(24_577); } #[test] #[should_panic] fn reserve_overflow() { // See https://github.com/hyperium/http/issues/352 let mut headers = HeaderMap::::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::().unwrap(), "world".parse().unwrap(), ); headers.insert( "zomg".parse::().unwrap(), "bar".parse().unwrap(), ); headers.append( "hello".parse::().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::::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::().unwrap(), "world".parse().unwrap(), ); headers.insert( "zomg".parse::().unwrap(), "foo".parse().unwrap(), ); headers.append( "hello".parse::().unwrap(), "world2".parse().unwrap(), ); headers.insert( "more".parse::().unwrap(), "words".parse().unwrap(), ); headers.append( "more".parse::().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::().unwrap(), "world".parse().unwrap(), ); assert_ne!(a, b); b.insert( "hello".parse::().unwrap(), "world".parse().unwrap(), ); assert_eq!(a, b); a.insert("foo".parse::().unwrap(), "bar".parse().unwrap()); a.append("foo".parse::().unwrap(), "baz".parse().unwrap()); assert_ne!(a, b); b.insert("foo".parse::().unwrap(), "bar".parse().unwrap()); assert_ne!(a, b); b.append("foo".parse::().unwrap(), "baz".parse().unwrap()); assert_eq!(a, b); a.append("a".parse::().unwrap(), "a".parse().unwrap()); a.append("a".parse::().unwrap(), "b".parse().unwrap()); b.append("a".parse::().unwrap(), "b".parse().unwrap()); b.append("a".parse::().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::>(); assert_eq!(&vals, &[&"json", &"html", &"xml"]); } fn custom_std(n: usize) -> Vec { (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(headers: &mut HeaderMap, key: K) -> Vec 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(headers: &mut HeaderMap, key: K) -> Option where K: IntoHeaderName { match headers.entry(key) { Entry::Occupied(e) => Some(e.remove_entry().1), Entry::Vacant(_) => None, } }