1 use util::FlatCsv; 2 use HeaderValue; 3 4 /// `Transfer-Encoding` header, defined in 5 /// [RFC7230](http://tools.ietf.org/html/rfc7230#section-3.3.1) 6 /// 7 /// The `Transfer-Encoding` header field lists the transfer coding names 8 /// corresponding to the sequence of transfer codings that have been (or 9 /// will be) applied to the payload body in order to form the message 10 /// body. 11 /// 12 /// Note that setting this header will *remove* any previously set 13 /// `Content-Length` header, in accordance with 14 /// [RFC7230](http://tools.ietf.org/html/rfc7230#section-3.3.2): 15 /// 16 /// > A sender MUST NOT send a Content-Length header field in any message 17 /// > that contains a Transfer-Encoding header field. 18 /// 19 /// # ABNF 20 /// 21 /// ```text 22 /// Transfer-Encoding = 1#transfer-coding 23 /// ``` 24 /// 25 /// # Example values 26 /// 27 /// * `chunked` 28 /// * `gzip, chunked` 29 /// 30 /// # Example 31 /// 32 /// ``` 33 /// # extern crate headers; 34 /// use headers::TransferEncoding; 35 /// 36 /// let transfer = TransferEncoding::chunked(); 37 /// ``` 38 // This currently is just a `HeaderValue`, instead of a `Vec<Encoding>`, since 39 // the most common by far instance is simply the string `chunked`. It'd be a 40 // waste to need to allocate just for that. 41 #[derive(Clone, Debug)] 42 pub struct TransferEncoding(FlatCsv); 43 44 derive_header! { 45 TransferEncoding(_), 46 name: TRANSFER_ENCODING 47 } 48 49 impl TransferEncoding { 50 /// Constructor for the most common Transfer-Encoding, `chunked`. chunked() -> TransferEncoding51 pub fn chunked() -> TransferEncoding { 52 TransferEncoding(HeaderValue::from_static("chunked").into()) 53 } 54 55 /// Returns whether this ends with the `chunked` encoding. is_chunked(&self) -> bool56 pub fn is_chunked(&self) -> bool { 57 self.0 58 .value 59 //TODO(perf): use split and trim (not an actual method) on &[u8] 60 .to_str() 61 .map(|s| { 62 s.split(',') 63 .next_back() 64 .map(|encoding| encoding.trim() == "chunked") 65 .expect("split always has at least 1 item") 66 }) 67 .unwrap_or(false) 68 } 69 } 70 71 #[cfg(test)] 72 mod tests { 73 use super::super::test_decode; 74 use super::TransferEncoding; 75 76 #[test] chunked_is_chunked()77 fn chunked_is_chunked() { 78 assert!(TransferEncoding::chunked().is_chunked()); 79 } 80 81 #[test] decode_gzip_chunked_is_chunked()82 fn decode_gzip_chunked_is_chunked() { 83 let te = test_decode::<TransferEncoding>(&["gzip, chunked"]).unwrap(); 84 assert!(te.is_chunked()); 85 } 86 87 #[test] decode_chunked_gzip_is_not_chunked()88 fn decode_chunked_gzip_is_not_chunked() { 89 let te = test_decode::<TransferEncoding>(&["chunked, gzip"]).unwrap(); 90 assert!(!te.is_chunked()); 91 } 92 93 #[test] decode_notchunked_is_not_chunked()94 fn decode_notchunked_is_not_chunked() { 95 let te = test_decode::<TransferEncoding>(&["notchunked"]).unwrap(); 96 assert!(!te.is_chunked()); 97 } 98 99 #[test] decode_multiple_is_chunked()100 fn decode_multiple_is_chunked() { 101 let te = test_decode::<TransferEncoding>(&["gzip", "chunked"]).unwrap(); 102 assert!(te.is_chunked()); 103 } 104 } 105