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, Header)] 42 pub struct TransferEncoding(FlatCsv); 43 44 impl TransferEncoding { 45 /// Constructor for the most common Transfer-Encoding, `chunked`. chunked() -> TransferEncoding46 pub fn chunked() -> TransferEncoding { 47 TransferEncoding(HeaderValue::from_static("chunked").into()) 48 } 49 50 /// Returns whether this ends with the `chunked` encoding. is_chunked(&self) -> bool51 pub fn is_chunked(&self) -> bool { 52 self 53 .0 54 .value 55 //TODO(perf): use split and trim (not an actual method) on &[u8] 56 .to_str() 57 .map(|s| s 58 .split(',') 59 .next_back() 60 .map(|encoding| { 61 encoding.trim() == "chunked" 62 }) 63 .expect("split always has at least 1 item") 64 ) 65 .unwrap_or(false) 66 } 67 } 68 69 #[cfg(test)] 70 mod tests { 71 use super::TransferEncoding; 72 use super::super::test_decode; 73 74 #[test] chunked_is_chunked()75 fn chunked_is_chunked() { 76 assert!(TransferEncoding::chunked().is_chunked()); 77 } 78 79 #[test] decode_gzip_chunked_is_chunked()80 fn decode_gzip_chunked_is_chunked() { 81 let te = test_decode::<TransferEncoding>(&["gzip, chunked"]).unwrap(); 82 assert!(te.is_chunked()); 83 } 84 85 #[test] decode_chunked_gzip_is_not_chunked()86 fn decode_chunked_gzip_is_not_chunked() { 87 let te = test_decode::<TransferEncoding>(&["chunked, gzip"]).unwrap(); 88 assert!(!te.is_chunked()); 89 } 90 91 #[test] decode_notchunked_is_not_chunked()92 fn decode_notchunked_is_not_chunked() { 93 let te = test_decode::<TransferEncoding>(&["notchunked"]).unwrap(); 94 assert!(!te.is_chunked()); 95 } 96 97 #[test] decode_multiple_is_chunked()98 fn decode_multiple_is_chunked() { 99 let te = test_decode::<TransferEncoding>(&["gzip", "chunked"]).unwrap(); 100 assert!(te.is_chunked()); 101 } 102 } 103