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 91 92 93 94 95 96 97 98 99 100 101 102 103 104
use util::FlatCsv;
use HeaderValue;
/// `Transfer-Encoding` header, defined in
/// [RFC7230](http://tools.ietf.org/html/rfc7230#section-3.3.1)
///
/// The `Transfer-Encoding` header field lists the transfer coding names
/// corresponding to the sequence of transfer codings that have been (or
/// will be) applied to the payload body in order to form the message
/// body.
///
/// Note that setting this header will *remove* any previously set
/// `Content-Length` header, in accordance with
/// [RFC7230](http://tools.ietf.org/html/rfc7230#section-3.3.2):
///
/// > A sender MUST NOT send a Content-Length header field in any message
/// > that contains a Transfer-Encoding header field.
///
/// # ABNF
///
/// ```text
/// Transfer-Encoding = 1#transfer-coding
/// ```
///
/// # Example values
///
/// * `chunked`
/// * `gzip, chunked`
///
/// # Example
///
/// ```
/// # extern crate headers;
/// use headers::TransferEncoding;
///
/// let transfer = TransferEncoding::chunked();
/// ```
// This currently is just a `HeaderValue`, instead of a `Vec<Encoding>`, since
// the most common by far instance is simply the string `chunked`. It'd be a
// waste to need to allocate just for that.
#[derive(Clone, Debug)]
pub struct TransferEncoding(FlatCsv);
derive_header! {
TransferEncoding(_),
name: TRANSFER_ENCODING
}
impl TransferEncoding {
/// Constructor for the most common Transfer-Encoding, `chunked`.
pub fn chunked() -> TransferEncoding {
TransferEncoding(HeaderValue::from_static("chunked").into())
}
/// Returns whether this ends with the `chunked` encoding.
pub fn is_chunked(&self) -> bool {
self.0
.value
//TODO(perf): use split and trim (not an actual method) on &[u8]
.to_str()
.map(|s| {
s.split(',')
.next_back()
.map(|encoding| encoding.trim() == "chunked")
.expect("split always has at least 1 item")
})
.unwrap_or(false)
}
}
#[cfg(test)]
mod tests {
use super::super::test_decode;
use super::TransferEncoding;
#[test]
fn chunked_is_chunked() {
assert!(TransferEncoding::chunked().is_chunked());
}
#[test]
fn decode_gzip_chunked_is_chunked() {
let te = test_decode::<TransferEncoding>(&["gzip, chunked"]).unwrap();
assert!(te.is_chunked());
}
#[test]
fn decode_chunked_gzip_is_not_chunked() {
let te = test_decode::<TransferEncoding>(&["chunked, gzip"]).unwrap();
assert!(!te.is_chunked());
}
#[test]
fn decode_notchunked_is_not_chunked() {
let te = test_decode::<TransferEncoding>(&["notchunked"]).unwrap();
assert!(!te.is_chunked());
}
#[test]
fn decode_multiple_is_chunked() {
let te = test_decode::<TransferEncoding>(&["gzip", "chunked"]).unwrap();
assert!(te.is_chunked());
}
}