1use std::fmt::Display;
5
6use http::header::{GetAll, HeaderMap, HeaderValue, ValueIter};
7
8use ::Result;
9use super::{Header, RawLike};
10
11#[cfg(feature = "headers")]
12use std::convert::From;
13
14#[cfg(feature = "headers")]
15use http;
16
17#[cfg(feature = "headers")]
18use super::{Headers};
19
20pub trait StandardHeader: Header + Sized {
23 fn http_header_name() -> ::http::header::HeaderName;
25}
26
27pub trait TypedHeaders {
30 fn decode<H>(&self) -> Result<H>
38 where H: StandardHeader;
39
40 fn try_decode<H>(&self) -> Option<Result<H>>
48 where H: StandardHeader;
49
50 fn encode<H>(&mut self, value: &H)
56 where H: StandardHeader + Display;
57
58 fn encode_append<H>(&mut self, value: &H)
64 where H: StandardHeader + Display;
65}
66
67#[derive(Debug)]
69pub struct ValueMapIter<'a>(ValueIter<'a, HeaderValue>);
70
71impl TypedHeaders for HeaderMap {
72 fn decode<H>(&self) -> Result<H>
73 where H: StandardHeader
74 {
75 let vals = self.get_all(H::http_header_name());
76 H::parse_header(&vals)
77 }
78
79 fn try_decode<H>(&self) -> Option<Result<H>>
80 where H: StandardHeader
81 {
82 let hname = H::http_header_name();
83 if self.contains_key(&hname) {
84 let vals = self.get_all(&hname);
85 Some(H::parse_header(&vals))
86 } else {
87 None
88 }
89 }
90
91 fn encode<H>(&mut self, val: &H)
92 where H: StandardHeader + Display
93 {
94 self.insert(
95 H::http_header_name(),
96 val.to_string().parse().expect("header value"));
97 }
98
99 fn encode_append<H>(&mut self, val: &H)
100 where H: StandardHeader + Display
101 {
102 self.append(
103 H::http_header_name(),
104 val.to_string().parse().expect("header value"));
105 }
106}
107
108#[cfg(feature = "headers")]
109impl From<http::HeaderMap> for Headers {
110 fn from(header_map: http::HeaderMap) -> Headers {
111 Headers::from(&header_map)
112 }
113}
114
115#[cfg(feature = "headers")]
116impl<'a> From<&'a http::HeaderMap> for Headers {
117 fn from(header_map: &'a http::HeaderMap) -> Headers {
118 let mut headers = Headers::new();
119 for (name, value) in header_map.iter() {
120 headers.append_raw_str(name.as_str(), value.as_bytes());
121 }
122 headers
123 }
124}
125
126#[cfg(feature = "headers")]
127impl From<Headers> for http::HeaderMap {
128 #[inline]
129 fn from(headers: Headers) -> http::HeaderMap {
130 http::HeaderMap::from(&headers)
131 }
132}
133
134#[cfg(feature = "headers")]
135impl<'a> From<&'a Headers> for http::HeaderMap {
136 fn from(headers: &'a Headers) -> http::HeaderMap {
137 let mut hmap = http::HeaderMap::new();
138 for header in headers.iter() {
139 let name: http::header::HeaderName = header.name().parse()
140 .expect("convert invalid header name");
141 let entry = hmap.entry(name);
142 let mut value_iter = header.raw().iter().map(|line| {
143 http::header::HeaderValue::from_bytes(line)
144 .expect("convert invalid header value")
145 });
146 match entry {
147 http::header::Entry::Occupied(mut occupied) => {
148 for value in value_iter {
149 occupied.append(value);
150 }
151 },
152 http::header::Entry::Vacant(vacant) => {
153 if let Some(first_value) = value_iter.next() {
154 let mut occupied = vacant.insert_entry(first_value);
155 for value in value_iter {
156 occupied.append(value);
157 }
158 }
159 }
160 }
161 }
162 hmap
163 }
164}
165
166impl<'a> Iterator for ValueMapIter<'a> {
167 type Item = &'a [u8];
168
169 fn next(&mut self) -> Option<Self::Item> {
170 self.0.next().map(HeaderValue::as_bytes)
171 }
172}
173
174impl<'a> RawLike<'a> for GetAll<'a, HeaderValue> {
175 type IntoIter = ValueMapIter<'a>;
176
177 fn len(&'a self) -> usize {
178 self.iter().count()
179 }
180
181 fn one(&'a self) -> Option<&'a [u8]> {
182 let mut iter = self.iter();
183 if let Some(v) = iter.next() {
184 if iter.next().is_none() {
185 return Some(v.as_bytes());
186 }
187 }
188 None
189 }
190
191 fn iter(&'a self) -> ValueMapIter<'a> {
192 ValueMapIter(self.iter())
193 }
194}
195
196impl<'a> RawLike<'a> for &'a HeaderValue {
197 type IntoIter = ::std::iter::Once<&'a [u8]>;
198
199 fn len(&'a self) -> usize {
200 1
201 }
202
203 fn one(&'a self) -> Option<&'a [u8]> {
204 Some(self.as_bytes())
205 }
206
207 fn iter(&'a self) -> Self::IntoIter {
208 ::std::iter::once(self.as_bytes())
209 }
210}
211
212#[cfg(test)]
213mod tests {
214 use http;
215 use ::header::{
216 ContentEncoding, ContentLength, Encoding, ETag,
217 Header, Te, TypedHeaders};
218
219 #[cfg(feature = "headers")]
220 use ::header::{Headers, Host};
221
222 #[cfg(feature = "nightly")]
223 use test::Bencher;
224
225 #[cfg(feature = "nightly")]
226 use ::header::EntityTag;
227
228 #[test]
229 fn test_empty_decode() {
230 let hmap = http::HeaderMap::new();
231 let len = hmap.decode::<ContentLength>();
232 assert!(len.is_err());
233 }
234
235 #[test]
236 fn test_empty_decode_etag() {
237 let hmap = http::HeaderMap::new();
238 let len = hmap.decode::<ETag>();
239 assert!(len.is_err());
240 }
241
242 #[test]
243 fn test_empty_decode_te() {
244 let hmap = http::HeaderMap::new();
245 let te = hmap.decode::<Te>().unwrap();
246 assert_eq!(te, Te(vec![]));
247 }
248
249 #[test]
250 fn test_empty_decode_content_encoding() {
251 let hmap = http::HeaderMap::new();
252 let ce = hmap.decode::<ContentEncoding>().unwrap();
253 assert_eq!(ce, ContentEncoding(vec![]));
254 }
255
256 #[test]
257 fn test_empty_try_decode() {
258 let hmap = http::HeaderMap::new();
259 let len = hmap.try_decode::<ContentLength>();
260 assert!(len.is_none());
261 }
262
263 #[test]
264 fn test_empty_try_decode_te() {
265 let hmap = http::HeaderMap::new();
266 let te = hmap.try_decode::<Te>();
267 assert!(te.is_none());
268 }
269
270 #[test]
271 fn test_decode() {
272 let mut hmap = http::HeaderMap::new();
273 hmap.insert(http::header::CONTENT_LENGTH, "11".parse().unwrap());
274 let len: ContentLength = hmap.decode().unwrap();
275 assert_eq!(*len, 11);
276 }
277
278 #[test]
279 fn test_encode_decode() {
280 let mut hmap = http::HeaderMap::new();
281 hmap.encode(&ContentLength(11));
282 let len: ContentLength = hmap.decode().unwrap();
283 assert_eq!(*len, 11);
284 }
285
286 #[test]
287 fn test_empty_encode() {
288 let mut hmap = http::HeaderMap::new();
289 hmap.encode(&ContentEncoding(vec![]));
290 assert_eq!(hmap.len(), 1);
291 let ce: ContentEncoding = hmap.decode().unwrap();
292 assert_eq!(*ce, vec![]);
293 }
294
295 #[test]
296 fn test_empty_encode_2() {
297 let mut hmap = http::HeaderMap::new();
298 hmap.encode(&ContentEncoding(vec![]));
299 hmap.encode_append(&ContentEncoding(vec![]));
300 assert_eq!(hmap.len(), 2);
301 let ce: ContentEncoding = hmap.decode().unwrap();
302 assert_eq!(*ce, vec![]);
303 }
304
305 #[test]
306 fn test_encode_append() {
307 let mut hmap = http::HeaderMap::new();
308 hmap.encode_append(
309 &ContentEncoding(vec![Encoding::Identity]));
310 hmap.encode_append(
311 &ContentEncoding(vec![Encoding::Gzip, Encoding::Chunked]));
312 let ce: ContentEncoding = hmap.decode().unwrap();
313 assert_eq!(
314 *ce,
315 vec![Encoding::Identity, Encoding::Gzip, Encoding::Chunked]);
316 }
317
318 #[cfg(feature = "headers")]
319 fn raw_headers_sample() -> Headers {
320 let mut heads = Headers::new();
321
322 heads.set_raw("date", b"Thu, 02 May 2019 21:10:03 GMT".as_ref());
323 heads.set_raw("connection", b"Keep-Alive".as_ref());
324 heads.set_raw("accept-ranges", b"bytes".as_ref());
325 heads.set_raw("etag", b"\"1544639720\"".as_ref());
326 heads.set_raw("transfer-encoding", b"gzip".as_ref());
327 heads.append_raw("transfer-encoding", b"chunked".as_ref());
328 heads.set_raw("content-length", b"7050".as_ref());
329 heads.set_raw("content-type", b"text/css; charset=utf-8".as_ref());
330 heads.set_raw("last-modified", b"Wed, 12 Dec 2018 18:35:20 GMT".as_ref());
331 heads.set_raw("x-hello-human",
332 b"Say hello back! @getBootstrapCDN on Twitter".as_ref());
333 heads.set_raw("access-control-allow-origin", b"*".as_ref());
334 heads.set_raw("vary", b"Accept-Encoding".as_ref());
335 heads.set_raw("x-cache", b"HIT".as_ref());
336 heads.set_raw("timing-allow-origin", b"*".as_ref());
337 heads.set_raw("cache-control", b"public, max-age=31536000".as_ref());
338
339 heads
340 }
341
342 #[cfg(feature = "headers")]
343 #[test]
344 fn test_convert_mixed() {
345 let mut headers = Headers::new();
346 headers.set(ContentLength(11));
347 headers.set(Host::new("foo.bar", None));
348 headers.append_raw("x-foo", b"bar".to_vec());
349 headers.append_raw("x-foo", b"quux".to_vec());
350
351 let mut hmap = http::HeaderMap::new();
352 hmap.insert(http::header::CONTENT_LENGTH, "11".parse().unwrap());
353 hmap.insert(http::header::HOST, "foo.bar".parse().unwrap());
354 hmap.append("x-foo", "bar".parse().unwrap());
355 hmap.append("x-foo", "quux".parse().unwrap());
356
357 let headers2: Headers = hmap.clone().into();
358 let hmap2: http::HeaderMap = headers.clone().into();
359 assert_eq!(headers, headers2);
360 assert_eq!(headers2.len(), 3);
361 assert_eq!(hmap, hmap2);
362 assert_eq!(hmap2.len(), 4);
363 }
364
365 #[test]
366 #[cfg(feature = "headers")]
367 fn test_convert_sample() {
368 let headers = raw_headers_sample();
369 let hmap = http::HeaderMap::from(headers.clone());
370 let headers2 = Headers::from(hmap.clone());
371 let hmap2 = http::HeaderMap::from(headers2.clone());
372 assert_eq!(headers, headers2);
373 assert_eq!(headers2.len(), 14);
374 assert_eq!(hmap2, hmap);
375 assert_eq!(hmap2.len(), 15);
376 }
377
378 #[test]
379 #[cfg(feature = "headers")]
380 fn test_convert_by_ref() {
381 let headers = raw_headers_sample();
382 let hmap = http::HeaderMap::from(&headers);
383 let headers2 = Headers::from(&hmap);
384 let hmap2 = http::HeaderMap::from(&headers2);
385 assert_eq!(headers, headers2);
386 assert_eq!(headers2.len(), 14);
387 assert_eq!(hmap2, hmap);
388 assert_eq!(hmap2.len(), 15);
389 }
390
391 #[test]
392 fn test_value_parse() {
393 let mut hmap = http::HeaderMap::new();
394 hmap.insert(http::header::CONTENT_ENCODING,
395 "chunked, gzip".parse().unwrap());
396 let val = hmap.get(http::header::CONTENT_ENCODING).unwrap();
397 let ce = ContentEncoding::parse_header(&val).unwrap();
398 assert_eq!(ce, ContentEncoding(vec![Encoding::Chunked, Encoding::Gzip]))
399 }
400
401 #[test]
402 fn test_multi_value_parse() {
403 let mut hmap = http::HeaderMap::new();
404 hmap.insert(http::header::CONTENT_ENCODING,
405 "chunked, gzip".parse().unwrap());
406 hmap.append(http::header::CONTENT_ENCODING,
407 "br".parse().unwrap());
408
409 let vals = hmap.get_all(http::header::CONTENT_ENCODING);
410 let ce = ContentEncoding::parse_header(&vals).unwrap();
411 assert_eq!(
412 ce,
413 ContentEncoding(vec![
414 Encoding::Chunked, Encoding::Gzip, Encoding::Brotli
415 ])
416 )
417 }
418
419 #[cfg(feature = "nightly")]
420 #[bench]
421 fn bench_0_value_parse(b: &mut Bencher) {
422 let mut hmap = http::HeaderMap::new();
423 hmap.insert(http::header::CONTENT_ENCODING,
424 "chunked, gzip".parse().unwrap());
425 b.iter(|| {
426 let val = hmap.get(http::header::CONTENT_ENCODING).unwrap();
427 ContentEncoding::parse_header(&val).unwrap();
428 })
429 }
430
431 #[cfg(feature = "nightly")]
432 #[bench]
433 fn bench_0_value_parse_extra_str(b: &mut Bencher) {
434 use header::Raw;
435 let mut hmap = http::HeaderMap::new();
436 hmap.insert(http::header::CONTENT_ENCODING,
437 "chunked, gzip".parse().unwrap());
438 b.iter(|| {
439 let val = hmap.get(http::header::CONTENT_ENCODING).unwrap();
440 let r: Raw = val.to_str().unwrap().into();
441 ContentEncoding::parse_header(&r).unwrap();
442 })
443 }
444
445 #[cfg(feature = "nightly")]
446 #[bench]
447 fn bench_0_value_parse_int(b: &mut Bencher) {
448 let mut hmap = http::HeaderMap::new();
449 hmap.insert(http::header::CONTENT_LENGTH, "1024".parse().unwrap());
450 b.iter(|| {
451 let val = hmap.get(http::header::CONTENT_LENGTH).unwrap();
452 ContentLength::parse_header(&val).unwrap();
453 })
454 }
455
456 #[cfg(feature = "nightly")]
457 #[bench]
458 fn bench_1_get_parse_int(b: &mut Bencher) {
459 let mut hmap = http::HeaderMap::new();
460 hmap.insert(http::header::CONTENT_LENGTH, "11".parse().unwrap());
461 b.iter(|| {
462 let vals = hmap.get_all(http::header::CONTENT_LENGTH);
463 let len = ContentLength::parse_header(&vals).unwrap();
464 assert_eq!(*len, 11);
465 })
466 }
467
468 #[cfg(feature = "nightly")]
469 #[bench]
470 fn bench_1_get_parse_int_one(b: &mut Bencher) {
471 let mut hmap = http::HeaderMap::new();
472 hmap.insert(http::header::CONTENT_LENGTH, "11".parse().unwrap());
473 b.iter(|| {
474 let val = hmap.get(http::header::CONTENT_LENGTH).unwrap();
475 let len = ContentLength::parse_header(&val).unwrap();
476 assert_eq!(*len, 11);
477 })
478 }
479
480 #[cfg(feature = "nightly")]
481 #[bench]
482 fn bench_2_decode_int(b: &mut Bencher) {
483 let mut hmap = http::HeaderMap::new();
484 hmap.insert(http::header::CONTENT_LENGTH, "11".parse().unwrap());
485 b.iter(|| {
486 let len: ContentLength = hmap.decode().unwrap();
487 assert_eq!(*len, 11);
488 })
489 }
490
491 #[cfg(feature = "nightly")]
492 #[bench]
493 fn bench_2_try_decode_int(b: &mut Bencher) {
494 let mut hmap = http::HeaderMap::new();
495 hmap.insert(http::header::CONTENT_LENGTH, "11".parse().unwrap());
496 b.iter(|| {
497 let len: ContentLength = hmap.try_decode().unwrap().unwrap();
498 assert_eq!(*len, 11);
499 })
500 }
501
502 #[cfg(all(feature = "nightly", feature = "headers"))]
503 #[bench]
504 fn bench_3_get_orig_int(b: &mut Bencher) {
505 let mut hdrs = ::header::Headers::new();
506 hdrs.set_raw("content-length", "11");
507 b.iter(|| {
508 let len: &ContentLength = hdrs.get().unwrap();
509 assert_eq!(**len, 11);
510 })
511 }
512
513 #[cfg(feature = "nightly")]
514 #[bench]
515 fn bench_4_encode_int(b: &mut Bencher) {
516 b.iter(|| {
517 let mut hmap = http::HeaderMap::new();
518 hmap.encode(&ContentLength(11));
519 assert_eq!(hmap.len(), 1);
520 })
521 }
522
523 #[cfg(feature = "nightly")]
524 #[bench]
525 fn bench_4_encode_multi(b: &mut Bencher) {
526 b.iter(|| {
527 let mut hmap = http::HeaderMap::new();
528 hmap.encode(
529 &ContentEncoding(vec![Encoding::Identity]));
530 hmap.encode_append(
531 &ContentEncoding(vec![Encoding::Gzip, Encoding::Chunked]));
532 hmap.encode(&ContentLength(11));
533 hmap.encode(
534 &ETag(EntityTag::strong("pMMV3zmCrXr-n4ZZLR9".to_owned())));
535 assert_eq!(hmap.len(), 4);
536 })
537 }
538
539 #[cfg(all(feature = "nightly", feature = "headers"))]
540 #[bench]
541 fn bench_5_map_from_headers(b: &mut Bencher) {
542 let heads = raw_headers_sample();
543 b.iter(|| {
544 let hmap = http::HeaderMap::from(&heads);
545 assert_eq!(hmap.len(), 15);
546 })
547 }
548
549 #[cfg(all(feature = "nightly", feature = "headers"))]
550 #[bench]
551 fn bench_5_headers_from_map(b: &mut Bencher) {
552 let heads = raw_headers_sample();
553 let hmap: http::HeaderMap = heads.into();
554 b.iter(|| {
555 let heads = Headers::from(&hmap);
556 assert_eq!(heads.len(), 14);
557 })
558 }
559
560 #[cfg(all(feature = "nightly", feature = "headers"))]
561 #[bench]
562 fn bench_5_headers_from_map_by_value(b: &mut Bencher) {
563 let heads = raw_headers_sample();
564 let hmap: http::HeaderMap = heads.into();
565 b.iter(|| {
566 let heads = Headers::from(hmap.clone());
567 assert_eq!(heads.len(), 14);
568 })
569 }
570}