1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90
use std::ascii::AsciiExt; use std::slice::Iter as SliceIter; use httparse::Header; use enums::{Status}; use client::Head; /// Iterator over all meaningful headers for the response /// /// This iterator is created by `Head::headers`. And iterates over all /// headers except hop-by-hop ones. /// /// Note: duplicate headers are not glued together neither they are sorted pub struct HeaderIter<'a> { head: &'a Head<'a>, iter: SliceIter<'a, Header<'a>>, } impl<'a> Head<'a> { /// Returns status if it is one of the supported statuses otherwise None /// /// Note: this method does not consider "reason" string at all just /// status code. Which is fine as specification states. pub fn status(&self) -> Option<Status> { Status::from(self.code) } /// Returns raw status code and reason as received even /// /// This returns something even if `status()` returned `None`. /// /// Note: the reason string may not match the status code or may even be /// an empty string. pub fn raw_status(&self) -> (u16, &'a str) { (self.code, self.reason) } /// Iterator over the headers of HTTP request /// /// This iterator strips the following kinds of headers: /// /// 1. Hop-by-hop headers (`Connection` itself, and ones it enumerates) /// 2. `Content-Length` and `Transfer-Encoding` /// /// You may use `all_headers()` if you really need to access to all of /// them (mostly useful for debugging puproses). But you may want to /// consider: /// /// 1. Payload size can be fetched using `body_length()` method. Note: /// this also includes cases where length is implicitly set to zero. /// 2. `Connection` header might be discovered with `connection_close()` /// or `connection_header()` pub fn headers(&self) -> HeaderIter { HeaderIter { head: self, iter: self.headers.iter(), } } /// All headers of HTTP request /// /// Unlike `self.headers()` this does include hop-by-hop headers. This /// method is here just for completeness, you shouldn't need it. pub fn all_headers(&self) -> &'a [Header<'a>] { self.headers } } impl<'a> Iterator for HeaderIter<'a> { type Item = (&'a str, &'a [u8]); fn next(&mut self) -> Option<(&'a str, &'a [u8])> { while let Some(header) = self.iter.next() { if header.name.eq_ignore_ascii_case("Connection") || header.name.eq_ignore_ascii_case("Transfer-Encoding") || header.name.eq_ignore_ascii_case("Content-Length") { continue; } if let Some(ref conn) = self.head.connection_header { let mut conn_headers = conn.split(',').map(|x| x.trim()); if conn_headers.any(|x| x.eq_ignore_ascii_case(header.name)) { continue; } } return Some((header.name, header.value)); } return None; } }