1 use http::header::*;
2 use http::*;
3 
4 use quickcheck::{Arbitrary, Gen, QuickCheck, TestResult};
5 use rand::rngs::StdRng;
6 use rand::seq::SliceRandom;
7 use rand::{Rng, SeedableRng};
8 
9 use std::collections::HashMap;
10 
11 #[test]
header_map_fuzz()12 fn header_map_fuzz() {
13     fn prop(fuzz: Fuzz) -> TestResult {
14         fuzz.run();
15         TestResult::from_bool(true)
16     }
17 
18     QuickCheck::new().quickcheck(prop as fn(Fuzz) -> TestResult)
19 }
20 
21 #[derive(Debug, Clone)]
22 #[allow(dead_code)]
23 struct Fuzz {
24     // The magic seed that makes the test case reproducible
25     seed: [u8; 32],
26 
27     // Actions to perform
28     steps: Vec<Step>,
29 
30     // Number of steps to drop
31     reduce: usize,
32 }
33 
34 #[derive(Debug)]
35 struct Weight {
36     insert: usize,
37     remove: usize,
38     append: usize,
39 }
40 
41 #[derive(Debug, Clone)]
42 struct Step {
43     action: Action,
44     expect: AltMap,
45 }
46 
47 #[derive(Debug, Clone)]
48 enum Action {
49     Insert {
50         name: HeaderName,         // Name to insert
51         val: HeaderValue,         // Value to insert
52         old: Option<HeaderValue>, // Old value
53     },
54     Append {
55         name: HeaderName,
56         val: HeaderValue,
57         ret: bool,
58     },
59     Remove {
60         name: HeaderName,         // Name to remove
61         val: Option<HeaderValue>, // Value to get
62     },
63 }
64 
65 // An alternate implementation of HeaderMap backed by HashMap
66 #[derive(Debug, Clone, Default)]
67 struct AltMap {
68     map: HashMap<HeaderName, Vec<HeaderValue>>,
69 }
70 
71 impl Fuzz {
new(seed: [u8; 32]) -> Fuzz72     fn new(seed: [u8; 32]) -> Fuzz {
73         // Seed the RNG
74         let mut rng = StdRng::from_seed(seed);
75 
76         let mut steps = vec![];
77         let mut expect = AltMap::default();
78         let num = rng.gen_range(5, 500);
79 
80         let weight = Weight {
81             insert: rng.gen_range(1, 10),
82             remove: rng.gen_range(1, 10),
83             append: rng.gen_range(1, 10),
84         };
85 
86         while steps.len() < num {
87             steps.push(expect.gen_step(&weight, &mut rng));
88         }
89 
90         Fuzz {
91             seed: seed,
92             steps: steps,
93             reduce: 0,
94         }
95     }
96 
run(self)97     fn run(self) {
98         // Create a new header map
99         let mut map = HeaderMap::new();
100 
101         // Number of steps to perform
102         let take = self.steps.len() - self.reduce;
103 
104         for step in self.steps.into_iter().take(take) {
105             step.action.apply(&mut map);
106 
107             step.expect.assert_identical(&map);
108         }
109     }
110 }
111 
112 impl Arbitrary for Fuzz {
arbitrary<G: Gen>(g: &mut G) -> Self113     fn arbitrary<G: Gen>(g: &mut G) -> Self {
114         Fuzz::new(Rng::gen(g))
115     }
116 }
117 
118 impl AltMap {
gen_step(&mut self, weight: &Weight, rng: &mut StdRng) -> Step119     fn gen_step(&mut self, weight: &Weight, rng: &mut StdRng) -> Step {
120         let action = self.gen_action(weight, rng);
121 
122         Step {
123             action: action,
124             expect: self.clone(),
125         }
126     }
127 
128     /// This will also apply the action against `self`
gen_action(&mut self, weight: &Weight, rng: &mut StdRng) -> Action129     fn gen_action(&mut self, weight: &Weight, rng: &mut StdRng) -> Action {
130         let sum = weight.insert + weight.remove + weight.append;
131 
132         let mut num = rng.gen_range(0, sum);
133 
134         if num < weight.insert {
135             return self.gen_insert(rng);
136         }
137 
138         num -= weight.insert;
139 
140         if num < weight.remove {
141             return self.gen_remove(rng);
142         }
143 
144         num -= weight.remove;
145 
146         if num < weight.append {
147             return self.gen_append(rng);
148         }
149 
150         unreachable!();
151     }
152 
gen_insert(&mut self, rng: &mut StdRng) -> Action153     fn gen_insert(&mut self, rng: &mut StdRng) -> Action {
154         let name = self.gen_name(4, rng);
155         let val = gen_header_value(rng);
156         let old = self.insert(name.clone(), val.clone());
157 
158         Action::Insert {
159             name: name,
160             val: val,
161             old: old,
162         }
163     }
164 
gen_remove(&mut self, rng: &mut StdRng) -> Action165     fn gen_remove(&mut self, rng: &mut StdRng) -> Action {
166         let name = self.gen_name(-4, rng);
167         let val = self.remove(&name);
168 
169         Action::Remove {
170             name: name,
171             val: val,
172         }
173     }
174 
gen_append(&mut self, rng: &mut StdRng) -> Action175     fn gen_append(&mut self, rng: &mut StdRng) -> Action {
176         let name = self.gen_name(-5, rng);
177         let val = gen_header_value(rng);
178 
179         let vals = self.map.entry(name.clone()).or_insert(vec![]);
180 
181         let ret = !vals.is_empty();
182         vals.push(val.clone());
183 
184         Action::Append {
185             name: name,
186             val: val,
187             ret: ret,
188         }
189     }
190 
191     /// Negative numbers weigh finding an existing header higher
gen_name(&self, weight: i32, rng: &mut StdRng) -> HeaderName192     fn gen_name(&self, weight: i32, rng: &mut StdRng) -> HeaderName {
193         let mut existing = rng.gen_ratio(1, weight.abs() as u32);
194 
195         if weight < 0 {
196             existing = !existing;
197         }
198 
199         if existing {
200             // Existing header
201             if let Some(name) = self.find_random_name(rng) {
202                 name
203             } else {
204                 gen_header_name(rng)
205             }
206         } else {
207             gen_header_name(rng)
208         }
209     }
210 
find_random_name(&self, rng: &mut StdRng) -> Option<HeaderName>211     fn find_random_name(&self, rng: &mut StdRng) -> Option<HeaderName> {
212         if self.map.is_empty() {
213             None
214         } else {
215             let n = rng.gen_range(0, self.map.len());
216             self.map.keys().nth(n).map(Clone::clone)
217         }
218     }
219 
insert(&mut self, name: HeaderName, val: HeaderValue) -> Option<HeaderValue>220     fn insert(&mut self, name: HeaderName, val: HeaderValue) -> Option<HeaderValue> {
221         let old = self.map.insert(name, vec![val]);
222         old.and_then(|v| v.into_iter().next())
223     }
224 
remove(&mut self, name: &HeaderName) -> Option<HeaderValue>225     fn remove(&mut self, name: &HeaderName) -> Option<HeaderValue> {
226         self.map.remove(name).and_then(|v| v.into_iter().next())
227     }
228 
assert_identical(&self, other: &HeaderMap<HeaderValue>)229     fn assert_identical(&self, other: &HeaderMap<HeaderValue>) {
230         assert_eq!(self.map.len(), other.keys_len());
231 
232         for (key, val) in &self.map {
233             // Test get
234             assert_eq!(other.get(key), val.get(0));
235 
236             // Test get_all
237             let vals = other.get_all(key);
238             let actual: Vec<_> = vals.iter().collect();
239             assert_eq!(&actual[..], &val[..]);
240         }
241     }
242 }
243 
244 impl Action {
apply(self, map: &mut HeaderMap<HeaderValue>)245     fn apply(self, map: &mut HeaderMap<HeaderValue>) {
246         match self {
247             Action::Insert { name, val, old } => {
248                 let actual = map.insert(name, val);
249                 assert_eq!(actual, old);
250             }
251             Action::Remove { name, val } => {
252                 // Just to help track the state, load all associated values.
253                 let _ = map.get_all(&name).iter().collect::<Vec<_>>();
254 
255                 let actual = map.remove(&name);
256                 assert_eq!(actual, val);
257             }
258             Action::Append { name, val, ret } => {
259                 assert_eq!(ret, map.append(name, val));
260             }
261         }
262     }
263 }
264 
gen_header_name(g: &mut StdRng) -> HeaderName265 fn gen_header_name(g: &mut StdRng) -> HeaderName {
266     const STANDARD_HEADERS: &'static [HeaderName] = &[
267         header::ACCEPT,
268         header::ACCEPT_CHARSET,
269         header::ACCEPT_ENCODING,
270         header::ACCEPT_LANGUAGE,
271         header::ACCEPT_RANGES,
272         header::ACCESS_CONTROL_ALLOW_CREDENTIALS,
273         header::ACCESS_CONTROL_ALLOW_HEADERS,
274         header::ACCESS_CONTROL_ALLOW_METHODS,
275         header::ACCESS_CONTROL_ALLOW_ORIGIN,
276         header::ACCESS_CONTROL_EXPOSE_HEADERS,
277         header::ACCESS_CONTROL_MAX_AGE,
278         header::ACCESS_CONTROL_REQUEST_HEADERS,
279         header::ACCESS_CONTROL_REQUEST_METHOD,
280         header::AGE,
281         header::ALLOW,
282         header::ALT_SVC,
283         header::AUTHORIZATION,
284         header::CACHE_CONTROL,
285         header::CACHE_STATUS,
286         header::CDN_CACHE_CONTROL,
287         header::CONNECTION,
288         header::CONTENT_DISPOSITION,
289         header::CONTENT_ENCODING,
290         header::CONTENT_LANGUAGE,
291         header::CONTENT_LENGTH,
292         header::CONTENT_LOCATION,
293         header::CONTENT_RANGE,
294         header::CONTENT_SECURITY_POLICY,
295         header::CONTENT_SECURITY_POLICY_REPORT_ONLY,
296         header::CONTENT_TYPE,
297         header::COOKIE,
298         header::DNT,
299         header::DATE,
300         header::ETAG,
301         header::EXPECT,
302         header::EXPIRES,
303         header::FORWARDED,
304         header::FROM,
305         header::HOST,
306         header::IF_MATCH,
307         header::IF_MODIFIED_SINCE,
308         header::IF_NONE_MATCH,
309         header::IF_RANGE,
310         header::IF_UNMODIFIED_SINCE,
311         header::LAST_MODIFIED,
312         header::LINK,
313         header::LOCATION,
314         header::MAX_FORWARDS,
315         header::ORIGIN,
316         header::PRAGMA,
317         header::PROXY_AUTHENTICATE,
318         header::PROXY_AUTHORIZATION,
319         header::PUBLIC_KEY_PINS,
320         header::PUBLIC_KEY_PINS_REPORT_ONLY,
321         header::RANGE,
322         header::REFERER,
323         header::REFERRER_POLICY,
324         header::REFRESH,
325         header::RETRY_AFTER,
326         header::SEC_WEBSOCKET_ACCEPT,
327         header::SEC_WEBSOCKET_EXTENSIONS,
328         header::SEC_WEBSOCKET_KEY,
329         header::SEC_WEBSOCKET_PROTOCOL,
330         header::SEC_WEBSOCKET_VERSION,
331         header::SERVER,
332         header::SET_COOKIE,
333         header::STRICT_TRANSPORT_SECURITY,
334         header::TE,
335         header::TRAILER,
336         header::TRANSFER_ENCODING,
337         header::UPGRADE,
338         header::UPGRADE_INSECURE_REQUESTS,
339         header::USER_AGENT,
340         header::VARY,
341         header::VIA,
342         header::WARNING,
343         header::WWW_AUTHENTICATE,
344         header::X_CONTENT_TYPE_OPTIONS,
345         header::X_DNS_PREFETCH_CONTROL,
346         header::X_FRAME_OPTIONS,
347         header::X_XSS_PROTECTION,
348     ];
349 
350     if g.gen_ratio(1, 2) {
351         STANDARD_HEADERS.choose(g).unwrap().clone()
352     } else {
353         let value = gen_string(g, 1, 25);
354         HeaderName::from_bytes(value.as_bytes()).unwrap()
355     }
356 }
357 
gen_header_value(g: &mut StdRng) -> HeaderValue358 fn gen_header_value(g: &mut StdRng) -> HeaderValue {
359     let value = gen_string(g, 0, 70);
360     HeaderValue::from_bytes(value.as_bytes()).unwrap()
361 }
362 
gen_string(g: &mut StdRng, min: usize, max: usize) -> String363 fn gen_string(g: &mut StdRng, min: usize, max: usize) -> String {
364     let bytes: Vec<_> = (min..max)
365         .map(|_| {
366             // Chars to pick from
367             b"ABCDEFGHIJKLMNOPQRSTUVabcdefghilpqrstuvwxyz----"
368                 .choose(g)
369                 .unwrap()
370                 .clone()
371         })
372         .collect();
373 
374     String::from_utf8(bytes).unwrap()
375 }
376