diff options
Diffstat (limited to 'third_party/rust/headers/src/common/transfer_encoding.rs')
-rw-r--r-- | third_party/rust/headers/src/common/transfer_encoding.rs | 104 |
1 files changed, 104 insertions, 0 deletions
diff --git a/third_party/rust/headers/src/common/transfer_encoding.rs b/third_party/rust/headers/src/common/transfer_encoding.rs new file mode 100644 index 0000000000..c3c49b15f1 --- /dev/null +++ b/third_party/rust/headers/src/common/transfer_encoding.rs @@ -0,0 +1,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()); + } +} |