summaryrefslogtreecommitdiffstats
path: root/vendor/http/tests
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/http/tests')
-rw-r--r--vendor/http/tests/header_map.rs638
-rw-r--r--vendor/http/tests/header_map_fuzz.rs375
-rw-r--r--vendor/http/tests/status_code.rs82
3 files changed, 1095 insertions, 0 deletions
diff --git a/vendor/http/tests/header_map.rs b/vendor/http/tests/header_map.rs
new file mode 100644
index 000000000..f2beba086
--- /dev/null
+++ b/vendor/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,
+ }
+}
diff --git a/vendor/http/tests/header_map_fuzz.rs b/vendor/http/tests/header_map_fuzz.rs
new file mode 100644
index 000000000..68a8604f7
--- /dev/null
+++ b/vendor/http/tests/header_map_fuzz.rs
@@ -0,0 +1,375 @@
+use http::header::*;
+use http::*;
+
+use quickcheck::{Arbitrary, Gen, QuickCheck, TestResult};
+use rand::rngs::StdRng;
+use rand::seq::SliceRandom;
+use rand::{Rng, SeedableRng};
+
+use std::collections::HashMap;
+
+#[test]
+fn header_map_fuzz() {
+ fn prop(fuzz: Fuzz) -> TestResult {
+ fuzz.run();
+ TestResult::from_bool(true)
+ }
+
+ QuickCheck::new().quickcheck(prop as fn(Fuzz) -> TestResult)
+}
+
+#[derive(Debug, Clone)]
+#[allow(dead_code)]
+struct Fuzz {
+ // The magic seed that makes the test case reproducible
+ seed: [u8; 32],
+
+ // Actions to perform
+ steps: Vec<Step>,
+
+ // Number of steps to drop
+ reduce: usize,
+}
+
+#[derive(Debug)]
+struct Weight {
+ insert: usize,
+ remove: usize,
+ append: usize,
+}
+
+#[derive(Debug, Clone)]
+struct Step {
+ action: Action,
+ expect: AltMap,
+}
+
+#[derive(Debug, Clone)]
+enum Action {
+ Insert {
+ name: HeaderName, // Name to insert
+ val: HeaderValue, // Value to insert
+ old: Option<HeaderValue>, // Old value
+ },
+ Append {
+ name: HeaderName,
+ val: HeaderValue,
+ ret: bool,
+ },
+ Remove {
+ name: HeaderName, // Name to remove
+ val: Option<HeaderValue>, // Value to get
+ },
+}
+
+// An alternate implementation of HeaderMap backed by HashMap
+#[derive(Debug, Clone, Default)]
+struct AltMap {
+ map: HashMap<HeaderName, Vec<HeaderValue>>,
+}
+
+impl Fuzz {
+ fn new(seed: [u8; 32]) -> Fuzz {
+ // Seed the RNG
+ let mut rng = StdRng::from_seed(seed);
+
+ let mut steps = vec![];
+ let mut expect = AltMap::default();
+ let num = rng.gen_range(5, 500);
+
+ let weight = Weight {
+ insert: rng.gen_range(1, 10),
+ remove: rng.gen_range(1, 10),
+ append: rng.gen_range(1, 10),
+ };
+
+ while steps.len() < num {
+ steps.push(expect.gen_step(&weight, &mut rng));
+ }
+
+ Fuzz {
+ seed: seed,
+ steps: steps,
+ reduce: 0,
+ }
+ }
+
+ fn run(self) {
+ // Create a new header map
+ let mut map = HeaderMap::new();
+
+ // Number of steps to perform
+ let take = self.steps.len() - self.reduce;
+
+ for step in self.steps.into_iter().take(take) {
+ step.action.apply(&mut map);
+
+ step.expect.assert_identical(&map);
+ }
+ }
+}
+
+impl Arbitrary for Fuzz {
+ fn arbitrary<G: Gen>(g: &mut G) -> Self {
+ Fuzz::new(Rng::gen(g))
+ }
+}
+
+impl AltMap {
+ fn gen_step(&mut self, weight: &Weight, rng: &mut StdRng) -> Step {
+ let action = self.gen_action(weight, rng);
+
+ Step {
+ action: action,
+ expect: self.clone(),
+ }
+ }
+
+ /// This will also apply the action against `self`
+ fn gen_action(&mut self, weight: &Weight, rng: &mut StdRng) -> Action {
+ let sum = weight.insert + weight.remove + weight.append;
+
+ let mut num = rng.gen_range(0, sum);
+
+ if num < weight.insert {
+ return self.gen_insert(rng);
+ }
+
+ num -= weight.insert;
+
+ if num < weight.remove {
+ return self.gen_remove(rng);
+ }
+
+ num -= weight.remove;
+
+ if num < weight.append {
+ return self.gen_append(rng);
+ }
+
+ unreachable!();
+ }
+
+ fn gen_insert(&mut self, rng: &mut StdRng) -> Action {
+ let name = self.gen_name(4, rng);
+ let val = gen_header_value(rng);
+ let old = self.insert(name.clone(), val.clone());
+
+ Action::Insert {
+ name: name,
+ val: val,
+ old: old,
+ }
+ }
+
+ fn gen_remove(&mut self, rng: &mut StdRng) -> Action {
+ let name = self.gen_name(-4, rng);
+ let val = self.remove(&name);
+
+ Action::Remove {
+ name: name,
+ val: val,
+ }
+ }
+
+ fn gen_append(&mut self, rng: &mut StdRng) -> Action {
+ let name = self.gen_name(-5, rng);
+ let val = gen_header_value(rng);
+
+ let vals = self.map.entry(name.clone()).or_insert(vec![]);
+
+ let ret = !vals.is_empty();
+ vals.push(val.clone());
+
+ Action::Append {
+ name: name,
+ val: val,
+ ret: ret,
+ }
+ }
+
+ /// Negative numbers weigh finding an existing header higher
+ fn gen_name(&self, weight: i32, rng: &mut StdRng) -> HeaderName {
+ let mut existing = rng.gen_ratio(1, weight.abs() as u32);
+
+ if weight < 0 {
+ existing = !existing;
+ }
+
+ if existing {
+ // Existing header
+ if let Some(name) = self.find_random_name(rng) {
+ name
+ } else {
+ gen_header_name(rng)
+ }
+ } else {
+ gen_header_name(rng)
+ }
+ }
+
+ fn find_random_name(&self, rng: &mut StdRng) -> Option<HeaderName> {
+ if self.map.is_empty() {
+ None
+ } else {
+ let n = rng.gen_range(0, self.map.len());
+ self.map.keys().nth(n).map(Clone::clone)
+ }
+ }
+
+ fn insert(&mut self, name: HeaderName, val: HeaderValue) -> Option<HeaderValue> {
+ let old = self.map.insert(name, vec![val]);
+ old.and_then(|v| v.into_iter().next())
+ }
+
+ fn remove(&mut self, name: &HeaderName) -> Option<HeaderValue> {
+ self.map.remove(name).and_then(|v| v.into_iter().next())
+ }
+
+ fn assert_identical(&self, other: &HeaderMap<HeaderValue>) {
+ assert_eq!(self.map.len(), other.keys_len());
+
+ for (key, val) in &self.map {
+ // Test get
+ assert_eq!(other.get(key), val.get(0));
+
+ // Test get_all
+ let vals = other.get_all(key);
+ let actual: Vec<_> = vals.iter().collect();
+ assert_eq!(&actual[..], &val[..]);
+ }
+ }
+}
+
+impl Action {
+ fn apply(self, map: &mut HeaderMap<HeaderValue>) {
+ match self {
+ Action::Insert { name, val, old } => {
+ let actual = map.insert(name, val);
+ assert_eq!(actual, old);
+ }
+ Action::Remove { name, val } => {
+ // Just to help track the state, load all associated values.
+ let _ = map.get_all(&name).iter().collect::<Vec<_>>();
+
+ let actual = map.remove(&name);
+ assert_eq!(actual, val);
+ }
+ Action::Append { name, val, ret } => {
+ assert_eq!(ret, map.append(name, val));
+ }
+ }
+ }
+}
+
+fn gen_header_name(g: &mut StdRng) -> HeaderName {
+ const STANDARD_HEADERS: &'static [HeaderName] = &[
+ header::ACCEPT,
+ header::ACCEPT_CHARSET,
+ header::ACCEPT_ENCODING,
+ header::ACCEPT_LANGUAGE,
+ header::ACCEPT_RANGES,
+ header::ACCESS_CONTROL_ALLOW_CREDENTIALS,
+ header::ACCESS_CONTROL_ALLOW_HEADERS,
+ header::ACCESS_CONTROL_ALLOW_METHODS,
+ header::ACCESS_CONTROL_ALLOW_ORIGIN,
+ header::ACCESS_CONTROL_EXPOSE_HEADERS,
+ header::ACCESS_CONTROL_MAX_AGE,
+ header::ACCESS_CONTROL_REQUEST_HEADERS,
+ header::ACCESS_CONTROL_REQUEST_METHOD,
+ header::AGE,
+ header::ALLOW,
+ header::ALT_SVC,
+ header::AUTHORIZATION,
+ header::CACHE_CONTROL,
+ header::CACHE_STATUS,
+ header::CDN_CACHE_CONTROL,
+ header::CONNECTION,
+ header::CONTENT_DISPOSITION,
+ header::CONTENT_ENCODING,
+ header::CONTENT_LANGUAGE,
+ header::CONTENT_LENGTH,
+ header::CONTENT_LOCATION,
+ header::CONTENT_RANGE,
+ header::CONTENT_SECURITY_POLICY,
+ header::CONTENT_SECURITY_POLICY_REPORT_ONLY,
+ header::CONTENT_TYPE,
+ header::COOKIE,
+ header::DNT,
+ header::DATE,
+ header::ETAG,
+ header::EXPECT,
+ header::EXPIRES,
+ header::FORWARDED,
+ header::FROM,
+ header::HOST,
+ header::IF_MATCH,
+ header::IF_MODIFIED_SINCE,
+ header::IF_NONE_MATCH,
+ header::IF_RANGE,
+ header::IF_UNMODIFIED_SINCE,
+ header::LAST_MODIFIED,
+ header::LINK,
+ header::LOCATION,
+ header::MAX_FORWARDS,
+ header::ORIGIN,
+ header::PRAGMA,
+ header::PROXY_AUTHENTICATE,
+ header::PROXY_AUTHORIZATION,
+ header::PUBLIC_KEY_PINS,
+ header::PUBLIC_KEY_PINS_REPORT_ONLY,
+ header::RANGE,
+ header::REFERER,
+ header::REFERRER_POLICY,
+ header::REFRESH,
+ header::RETRY_AFTER,
+ header::SEC_WEBSOCKET_ACCEPT,
+ header::SEC_WEBSOCKET_EXTENSIONS,
+ header::SEC_WEBSOCKET_KEY,
+ header::SEC_WEBSOCKET_PROTOCOL,
+ header::SEC_WEBSOCKET_VERSION,
+ header::SERVER,
+ header::SET_COOKIE,
+ header::STRICT_TRANSPORT_SECURITY,
+ header::TE,
+ header::TRAILER,
+ header::TRANSFER_ENCODING,
+ header::UPGRADE,
+ header::UPGRADE_INSECURE_REQUESTS,
+ header::USER_AGENT,
+ header::VARY,
+ header::VIA,
+ header::WARNING,
+ header::WWW_AUTHENTICATE,
+ header::X_CONTENT_TYPE_OPTIONS,
+ header::X_DNS_PREFETCH_CONTROL,
+ header::X_FRAME_OPTIONS,
+ header::X_XSS_PROTECTION,
+ ];
+
+ if g.gen_ratio(1, 2) {
+ STANDARD_HEADERS.choose(g).unwrap().clone()
+ } else {
+ let value = gen_string(g, 1, 25);
+ HeaderName::from_bytes(value.as_bytes()).unwrap()
+ }
+}
+
+fn gen_header_value(g: &mut StdRng) -> HeaderValue {
+ let value = gen_string(g, 0, 70);
+ HeaderValue::from_bytes(value.as_bytes()).unwrap()
+}
+
+fn gen_string(g: &mut StdRng, min: usize, max: usize) -> String {
+ let bytes: Vec<_> = (min..max)
+ .map(|_| {
+ // Chars to pick from
+ b"ABCDEFGHIJKLMNOPQRSTUVabcdefghilpqrstuvwxyz----"
+ .choose(g)
+ .unwrap()
+ .clone()
+ })
+ .collect();
+
+ String::from_utf8(bytes).unwrap()
+}
diff --git a/vendor/http/tests/status_code.rs b/vendor/http/tests/status_code.rs
new file mode 100644
index 000000000..160df6bad
--- /dev/null
+++ b/vendor/http/tests/status_code.rs
@@ -0,0 +1,82 @@
+use http::*;
+
+#[test]
+fn from_bytes() {
+ for ok in &[
+ "100", "101", "199", "200", "250", "299", "321", "399", "499", "599", "600", "999"
+ ] {
+ assert!(StatusCode::from_bytes(ok.as_bytes()).is_ok());
+ }
+
+ for not_ok in &[
+ "0", "00", "10", "40", "99", "000", "010", "099", "1000", "1999",
+ ] {
+ assert!(StatusCode::from_bytes(not_ok.as_bytes()).is_err());
+ }
+}
+
+#[test]
+fn equates_with_u16() {
+ let status = StatusCode::from_u16(200u16).unwrap();
+ assert_eq!(200u16, status);
+ assert_eq!(status, 200u16);
+}
+
+#[test]
+fn roundtrip() {
+ for s in 100..1000 {
+ let sstr = s.to_string();
+ let status = StatusCode::from_bytes(sstr.as_bytes()).unwrap();
+ assert_eq!(s, u16::from(status));
+ assert_eq!(sstr, status.as_str());
+ }
+}
+
+#[test]
+fn is_informational() {
+ assert!(status_code(100).is_informational());
+ assert!(status_code(199).is_informational());
+
+ assert!(!status_code(200).is_informational());
+}
+
+#[test]
+fn is_success() {
+ assert!(status_code(200).is_success());
+ assert!(status_code(299).is_success());
+
+ assert!(!status_code(199).is_success());
+ assert!(!status_code(300).is_success());
+}
+
+#[test]
+fn is_redirection() {
+ assert!(status_code(300).is_redirection());
+ assert!(status_code(399).is_redirection());
+
+ assert!(!status_code(299).is_redirection());
+ assert!(!status_code(400).is_redirection());
+}
+
+#[test]
+fn is_client_error() {
+ assert!(status_code(400).is_client_error());
+ assert!(status_code(499).is_client_error());
+
+ assert!(!status_code(399).is_client_error());
+ assert!(!status_code(500).is_client_error());
+}
+
+#[test]
+fn is_server_error() {
+ assert!(status_code(500).is_server_error());
+ assert!(status_code(599).is_server_error());
+
+ assert!(!status_code(499).is_server_error());
+ assert!(!status_code(600).is_server_error());
+}
+
+/// Helper method for readability
+fn status_code(status_code: u16) -> StatusCode {
+ StatusCode::from_u16(status_code).unwrap()
+}