1
0
mirror of https://github.com/actix/actix-extras.git synced 2024-11-28 17:52:40 +01:00
actix-extras/src/server/output.rs

761 lines
25 KiB
Rust
Raw Normal View History

2017-11-09 01:44:23 +01:00
use std::fmt::Write as FmtWrite;
2018-06-24 06:42:20 +02:00
use std::io::Write;
2017-11-09 01:44:23 +01:00
use std::str::FromStr;
2018-06-24 06:30:58 +02:00
use std::{cmp, fmt, io, mem};
2017-11-09 01:44:23 +01:00
2018-04-14 01:02:01 +02:00
#[cfg(feature = "brotli")]
2018-06-24 06:42:20 +02:00
use brotli2::write::BrotliEncoder;
use bytes::BytesMut;
2018-04-24 21:24:04 +02:00
#[cfg(feature = "flate2")]
use flate2::write::{GzEncoder, ZlibEncoder};
2018-04-24 21:24:04 +02:00
#[cfg(feature = "flate2")]
use flate2::Compression;
2018-07-04 17:01:27 +02:00
use http::header::{ACCEPT_ENCODING, CONTENT_LENGTH};
use http::{StatusCode, Version};
2017-11-07 01:23:58 +01:00
2018-07-04 17:01:27 +02:00
use super::message::InnerRequest;
2018-04-14 01:02:01 +02:00
use body::{Binary, Body};
use header::ContentEncoding;
2017-11-09 01:44:23 +01:00
use httpresponse::HttpResponse;
2018-02-25 09:43:00 +01:00
2018-06-25 06:58:04 +02:00
#[derive(Debug)]
pub(crate) enum ResponseLength {
Chunked,
Zero,
Length(usize),
Length64(u64),
None,
}
#[derive(Debug)]
pub(crate) struct ResponseInfo {
head: bool,
pub length: ResponseLength,
pub content_encoding: Option<&'static str>,
}
impl ResponseInfo {
pub fn new(head: bool) -> Self {
ResponseInfo {
head,
length: ResponseLength::None,
content_encoding: None,
}
}
}
2018-06-24 06:30:58 +02:00
#[derive(Debug)]
2018-06-24 04:54:01 +02:00
pub(crate) enum Output {
2018-06-24 18:05:44 +02:00
Empty(BytesMut),
2018-06-24 06:30:58 +02:00
Buffer(BytesMut),
2018-06-24 04:54:01 +02:00
Encoder(ContentEncoder),
TE(TransferEncoding),
2018-06-24 18:05:44 +02:00
Done,
2018-06-24 04:54:01 +02:00
}
impl Output {
2018-06-24 06:30:58 +02:00
pub fn take(&mut self) -> BytesMut {
2018-06-24 18:05:44 +02:00
match mem::replace(self, Output::Done) {
Output::Empty(bytes) => bytes,
2018-06-24 04:54:01 +02:00
Output::Buffer(bytes) => bytes,
2018-06-24 06:30:58 +02:00
Output::Encoder(mut enc) => enc.take_buf(),
Output::TE(mut te) => te.take(),
2018-06-24 18:05:44 +02:00
Output::Done => panic!(),
2018-06-24 04:54:01 +02:00
}
}
2018-06-24 06:30:58 +02:00
pub fn take_option(&mut self) -> Option<BytesMut> {
2018-06-24 18:05:44 +02:00
match mem::replace(self, Output::Done) {
Output::Empty(bytes) => Some(bytes),
2018-06-24 06:30:58 +02:00
Output::Buffer(bytes) => Some(bytes),
Output::Encoder(mut enc) => Some(enc.take_buf()),
Output::TE(mut te) => Some(te.take()),
2018-06-24 18:05:44 +02:00
Output::Done => None,
2018-06-24 06:30:58 +02:00
}
}
pub fn as_ref(&mut self) -> &BytesMut {
2018-06-24 04:54:01 +02:00
match self {
2018-06-24 18:05:44 +02:00
Output::Empty(ref mut bytes) => bytes,
2018-06-24 04:54:01 +02:00
Output::Buffer(ref mut bytes) => bytes,
Output::Encoder(ref mut enc) => enc.buf_ref(),
Output::TE(ref mut te) => te.buf_ref(),
2018-06-24 18:05:44 +02:00
Output::Done => panic!(),
2018-06-24 04:54:01 +02:00
}
}
2018-06-24 06:30:58 +02:00
pub fn as_mut(&mut self) -> &mut BytesMut {
2018-06-24 04:54:01 +02:00
match self {
2018-06-24 18:05:44 +02:00
Output::Empty(ref mut bytes) => bytes,
2018-06-24 06:30:58 +02:00
Output::Buffer(ref mut bytes) => bytes,
Output::Encoder(ref mut enc) => enc.buf_mut(),
Output::TE(ref mut te) => te.buf_mut(),
2018-06-24 18:05:44 +02:00
Output::Done => panic!(),
2018-06-24 04:54:01 +02:00
}
}
pub fn split_to(&mut self, cap: usize) -> BytesMut {
match self {
2018-06-24 18:05:44 +02:00
Output::Empty(ref mut bytes) => bytes.split_to(cap),
2018-06-24 04:54:01 +02:00
Output::Buffer(ref mut bytes) => bytes.split_to(cap),
Output::Encoder(ref mut enc) => enc.buf_mut().split_to(cap),
Output::TE(ref mut te) => te.buf_mut().split_to(cap),
2018-06-24 18:05:44 +02:00
Output::Done => BytesMut::new(),
2018-06-24 04:54:01 +02:00
}
}
pub fn len(&self) -> usize {
match self {
2018-06-24 18:05:44 +02:00
Output::Empty(ref bytes) => bytes.len(),
2018-06-24 04:54:01 +02:00
Output::Buffer(ref bytes) => bytes.len(),
Output::Encoder(ref enc) => enc.len(),
Output::TE(ref te) => te.len(),
2018-06-24 18:05:44 +02:00
Output::Done => 0,
2018-06-24 04:54:01 +02:00
}
}
pub fn is_empty(&self) -> bool {
match self {
2018-06-24 18:05:44 +02:00
Output::Empty(ref bytes) => bytes.is_empty(),
2018-06-24 04:54:01 +02:00
Output::Buffer(ref bytes) => bytes.is_empty(),
Output::Encoder(ref enc) => enc.is_empty(),
Output::TE(ref te) => te.is_empty(),
2018-06-24 18:05:44 +02:00
Output::Done => true,
2018-06-24 04:54:01 +02:00
}
}
pub fn write(&mut self, data: &[u8]) -> Result<(), io::Error> {
match self {
Output::Buffer(ref mut bytes) => {
bytes.extend_from_slice(data);
Ok(())
}
Output::Encoder(ref mut enc) => enc.write(data),
Output::TE(ref mut te) => te.encode(data).map(|_| ()),
2018-06-24 18:05:44 +02:00
Output::Empty(_) | Output::Done => Ok(()),
2018-06-24 04:54:01 +02:00
}
}
pub fn write_eof(&mut self) -> Result<bool, io::Error> {
match self {
Output::Buffer(_) => Ok(true),
Output::Encoder(ref mut enc) => enc.write_eof(),
Output::TE(ref mut te) => Ok(te.encode_eof()),
2018-06-24 18:05:44 +02:00
Output::Empty(_) | Output::Done => Ok(true),
2018-06-24 04:54:01 +02:00
}
}
2018-06-24 06:30:58 +02:00
2018-06-25 06:58:04 +02:00
pub(crate) fn for_server(
&mut self, info: &mut ResponseInfo, req: &InnerRequest, resp: &mut HttpResponse,
2018-04-14 01:02:01 +02:00
response_encoding: ContentEncoding,
2018-06-24 18:05:44 +02:00
) {
let buf = self.take();
2017-12-09 13:33:40 +01:00
let version = resp.version().unwrap_or_else(|| req.version);
2018-05-16 01:41:46 +02:00
let mut len = 0;
2018-05-17 21:23:37 +02:00
2018-05-16 01:41:46 +02:00
let has_body = match resp.body() {
2018-10-02 06:16:56 +02:00
Body::Empty => false,
Body::Binary(ref bin) => {
2018-05-16 01:41:46 +02:00
len = bin.len();
!(response_encoding == ContentEncoding::Auto && len < 96)
2018-04-14 01:02:01 +02:00
}
_ => true,
};
2017-11-09 01:44:23 +01:00
2018-04-14 01:02:01 +02:00
// Enable content encoding only if response does not contain Content-Encoding
// header
#[cfg(any(feature = "brotli", feature = "flate2"))]
2018-01-11 07:42:26 +01:00
let mut encoding = if has_body {
let encoding = match response_encoding {
2017-11-09 01:44:23 +01:00
ContentEncoding::Auto => {
// negotiate content-encoding
2017-12-09 13:33:40 +01:00
if let Some(val) = req.headers.get(ACCEPT_ENCODING) {
2017-11-09 01:44:23 +01:00
if let Ok(enc) = val.to_str() {
AcceptEncoding::parse(enc)
} else {
ContentEncoding::Identity
}
} else {
ContentEncoding::Identity
}
}
encoding => encoding,
};
2017-12-14 01:44:35 +01:00
if encoding.is_compression() {
2018-06-25 06:58:04 +02:00
info.content_encoding = Some(encoding.as_str());
2017-12-14 01:44:35 +01:00
}
2017-11-09 01:44:23 +01:00
encoding
} else {
ContentEncoding::Identity
};
#[cfg(not(any(feature = "brotli", feature = "flate2")))]
let mut encoding = ContentEncoding::Identity;
2017-11-09 01:44:23 +01:00
2018-06-24 18:05:44 +02:00
let transfer = match resp.body() {
2018-10-02 06:16:56 +02:00
Body::Empty => {
2018-10-09 00:30:59 +02:00
info.length = match resp.status() {
StatusCode::NO_CONTENT
| StatusCode::CONTINUE
| StatusCode::SWITCHING_PROTOCOLS
| StatusCode::PROCESSING => ResponseLength::None,
_ => ResponseLength::Zero,
};
2018-06-24 18:05:44 +02:00
*self = Output::Empty(buf);
return;
2018-04-14 01:02:01 +02:00
}
2018-10-02 06:16:56 +02:00
Body::Binary(_) => {
#[cfg(any(feature = "brotli", feature = "flate2"))]
2018-03-18 19:05:44 +01:00
{
if !(encoding == ContentEncoding::Identity
|| encoding == ContentEncoding::Auto)
{
2018-06-24 06:30:58 +02:00
let mut tmp = BytesMut::new();
2018-06-24 04:54:01 +02:00
let mut transfer = TransferEncoding::eof(tmp);
let mut enc = match encoding {
#[cfg(feature = "flate2")]
ContentEncoding::Deflate => ContentEncoder::Deflate(
ZlibEncoder::new(transfer, Compression::fast()),
),
#[cfg(feature = "flate2")]
ContentEncoding::Gzip => ContentEncoder::Gzip(
GzEncoder::new(transfer, Compression::fast()),
),
#[cfg(feature = "brotli")]
ContentEncoding::Br => {
ContentEncoder::Br(BrotliEncoder::new(transfer, 3))
}
ContentEncoding::Identity | ContentEncoding::Auto => {
unreachable!()
}
};
2018-05-16 01:41:46 +02:00
let bin = resp.replace_body(Body::Empty).binary();
2018-05-16 01:41:46 +02:00
// TODO return error!
let _ = enc.write(bin.as_ref());
let _ = enc.write_eof();
2018-06-24 04:54:01 +02:00
let body = enc.buf_mut().take();
len = body.len();
resp.replace_body(Binary::from(body));
}
2017-11-09 01:44:23 +01:00
}
2018-05-16 01:41:46 +02:00
2018-06-25 06:58:04 +02:00
info.length = ResponseLength::Length(len);
if info.head {
2018-06-24 18:05:44 +02:00
*self = Output::Empty(buf);
2018-01-21 01:12:38 +01:00
} else {
2018-06-24 18:05:44 +02:00
*self = Output::Buffer(buf);
2018-01-21 01:12:38 +01:00
}
2018-06-24 18:05:44 +02:00
return;
2017-11-09 01:44:23 +01:00
}
2018-10-02 06:16:56 +02:00
Body::Streaming(_) | Body::Actor(_) => {
2018-01-01 02:26:32 +01:00
if resp.upgrade() {
if version == Version::HTTP_2 {
error!("Connection upgrade is forbidden for HTTP/2");
}
if encoding != ContentEncoding::Identity {
encoding = ContentEncoding::Identity;
2018-06-25 06:58:04 +02:00
info.content_encoding.take();
2018-01-01 02:26:32 +01:00
}
2018-06-24 04:54:01 +02:00
TransferEncoding::eof(buf)
2017-11-09 01:44:23 +01:00
} else {
if !(encoding == ContentEncoding::Identity
|| encoding == ContentEncoding::Auto)
{
resp.headers_mut().remove(CONTENT_LENGTH);
}
2018-06-25 06:58:04 +02:00
Output::streaming_encoding(info, buf, version, resp)
2017-11-09 01:44:23 +01:00
}
}
};
2018-05-16 01:41:46 +02:00
// check for head response
2018-06-25 06:58:04 +02:00
if info.head {
2018-05-16 01:41:46 +02:00
resp.set_body(Body::Empty);
2018-06-24 18:05:44 +02:00
*self = Output::Empty(transfer.buf.unwrap());
return;
2018-01-21 01:12:38 +01:00
}
2017-11-09 01:44:23 +01:00
2018-06-24 04:54:01 +02:00
let enc = match encoding {
2018-04-24 21:24:04 +02:00
#[cfg(feature = "flate2")]
2018-08-23 18:48:01 +02:00
ContentEncoding::Deflate => {
ContentEncoder::Deflate(ZlibEncoder::new(transfer, Compression::fast()))
}
2018-04-24 21:24:04 +02:00
#[cfg(feature = "flate2")]
2018-04-14 01:02:01 +02:00
ContentEncoding::Gzip => {
ContentEncoder::Gzip(GzEncoder::new(transfer, Compression::fast()))
}
#[cfg(feature = "brotli")]
ContentEncoding::Br => ContentEncoder::Br(BrotliEncoder::new(transfer, 3)),
ContentEncoding::Identity | ContentEncoding::Auto => {
2018-06-24 18:05:44 +02:00
*self = Output::TE(transfer);
return;
2018-04-14 01:02:01 +02:00
}
2018-06-24 04:54:01 +02:00
};
2018-06-24 18:05:44 +02:00
*self = Output::Encoder(enc);
2017-11-09 01:44:23 +01:00
}
2018-01-12 00:26:46 +01:00
2018-04-14 01:02:01 +02:00
fn streaming_encoding(
2018-06-25 06:58:04 +02:00
info: &mut ResponseInfo, buf: BytesMut, version: Version,
resp: &mut HttpResponse,
2018-04-14 01:02:01 +02:00
) -> TransferEncoding {
match resp.chunked() {
Some(true) => {
// Enable transfer encoding
info.length = ResponseLength::Chunked;
if version == Version::HTTP_11 {
2018-06-24 04:54:01 +02:00
TransferEncoding::chunked(buf)
} else {
TransferEncoding::eof(buf)
}
2018-04-14 01:02:01 +02:00
}
2018-06-24 04:54:01 +02:00
Some(false) => TransferEncoding::eof(buf),
None => {
// if Content-Length is specified, then use it as length hint
let (len, chunked) =
if let Some(len) = resp.headers().get(CONTENT_LENGTH) {
// Content-Length
if let Ok(s) = len.to_str() {
if let Ok(len) = s.parse::<u64>() {
(Some(len), false)
} else {
error!("illegal Content-Length: {:?}", len);
(None, false)
}
2018-01-12 00:26:46 +01:00
} else {
error!("illegal Content-Length: {:?}", len);
(None, false)
}
} else {
(None, true)
};
2018-01-12 00:26:46 +01:00
if !chunked {
if let Some(len) = len {
2018-06-25 06:58:04 +02:00
info.length = ResponseLength::Length64(len);
2018-06-24 04:54:01 +02:00
TransferEncoding::length(len, buf)
} else {
2018-06-24 04:54:01 +02:00
TransferEncoding::eof(buf)
}
} else {
// Enable transfer encoding
info.length = ResponseLength::Chunked;
if version == Version::HTTP_11 {
TransferEncoding::chunked(buf)
} else {
TransferEncoding::eof(buf)
}
2018-01-12 00:26:46 +01:00
}
}
}
}
2017-11-09 01:44:23 +01:00
}
2018-06-24 18:05:44 +02:00
pub(crate) enum ContentEncoder {
#[cfg(feature = "flate2")]
Deflate(ZlibEncoder<TransferEncoding>),
2018-06-24 18:05:44 +02:00
#[cfg(feature = "flate2")]
Gzip(GzEncoder<TransferEncoding>),
#[cfg(feature = "brotli")]
Br(BrotliEncoder<TransferEncoding>),
Identity(TransferEncoding),
}
impl fmt::Debug for ContentEncoder {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
#[cfg(feature = "brotli")]
ContentEncoder::Br(_) => writeln!(f, "ContentEncoder(Brotli)"),
#[cfg(feature = "flate2")]
ContentEncoder::Deflate(_) => writeln!(f, "ContentEncoder(Deflate)"),
#[cfg(feature = "flate2")]
ContentEncoder::Gzip(_) => writeln!(f, "ContentEncoder(Gzip)"),
ContentEncoder::Identity(_) => writeln!(f, "ContentEncoder(Identity)"),
}
}
}
2017-11-09 01:44:23 +01:00
impl ContentEncoder {
2017-12-13 06:32:58 +01:00
#[inline]
2018-06-24 04:54:01 +02:00
pub fn len(&self) -> usize {
2017-11-09 01:44:23 +01:00
match *self {
2018-04-14 01:02:01 +02:00
#[cfg(feature = "brotli")]
2018-06-24 04:54:01 +02:00
ContentEncoder::Br(ref encoder) => encoder.get_ref().len(),
2018-04-24 21:24:04 +02:00
#[cfg(feature = "flate2")]
2018-06-24 04:54:01 +02:00
ContentEncoder::Deflate(ref encoder) => encoder.get_ref().len(),
2018-04-24 21:24:04 +02:00
#[cfg(feature = "flate2")]
2018-06-24 04:54:01 +02:00
ContentEncoder::Gzip(ref encoder) => encoder.get_ref().len(),
ContentEncoder::Identity(ref encoder) => encoder.len(),
}
}
#[inline]
pub fn is_empty(&self) -> bool {
match *self {
#[cfg(feature = "brotli")]
ContentEncoder::Br(ref encoder) => encoder.get_ref().is_empty(),
#[cfg(feature = "flate2")]
ContentEncoder::Deflate(ref encoder) => encoder.get_ref().is_empty(),
#[cfg(feature = "flate2")]
ContentEncoder::Gzip(ref encoder) => encoder.get_ref().is_empty(),
ContentEncoder::Identity(ref encoder) => encoder.is_empty(),
}
}
2018-06-24 06:30:58 +02:00
#[inline]
pub(crate) fn take_buf(&mut self) -> BytesMut {
match *self {
#[cfg(feature = "brotli")]
ContentEncoder::Br(ref mut encoder) => encoder.get_mut().take(),
#[cfg(feature = "flate2")]
ContentEncoder::Deflate(ref mut encoder) => encoder.get_mut().take(),
#[cfg(feature = "flate2")]
ContentEncoder::Gzip(ref mut encoder) => encoder.get_mut().take(),
ContentEncoder::Identity(ref mut encoder) => encoder.take(),
}
}
2018-06-24 04:54:01 +02:00
#[inline]
pub(crate) fn buf_mut(&mut self) -> &mut BytesMut {
match *self {
#[cfg(feature = "brotli")]
ContentEncoder::Br(ref mut encoder) => encoder.get_mut().buf_mut(),
#[cfg(feature = "flate2")]
ContentEncoder::Deflate(ref mut encoder) => encoder.get_mut().buf_mut(),
#[cfg(feature = "flate2")]
ContentEncoder::Gzip(ref mut encoder) => encoder.get_mut().buf_mut(),
ContentEncoder::Identity(ref mut encoder) => encoder.buf_mut(),
}
}
#[inline]
2018-06-24 06:30:58 +02:00
pub(crate) fn buf_ref(&mut self) -> &BytesMut {
2018-06-24 04:54:01 +02:00
match *self {
#[cfg(feature = "brotli")]
ContentEncoder::Br(ref mut encoder) => encoder.get_mut().buf_ref(),
#[cfg(feature = "flate2")]
ContentEncoder::Deflate(ref mut encoder) => encoder.get_mut().buf_ref(),
#[cfg(feature = "flate2")]
ContentEncoder::Gzip(ref mut encoder) => encoder.get_mut().buf_ref(),
ContentEncoder::Identity(ref mut encoder) => encoder.buf_ref(),
2017-11-09 01:44:23 +01:00
}
}
2018-10-02 06:16:56 +02:00
#[cfg_attr(feature = "cargo-clippy", allow(clippy::inline_always))]
2017-12-13 21:47:07 +01:00
#[inline(always)]
2018-05-16 01:41:46 +02:00
pub fn write_eof(&mut self) -> Result<bool, io::Error> {
let encoder =
2018-06-24 04:54:01 +02:00
mem::replace(self, ContentEncoder::Identity(TransferEncoding::empty()));
2017-11-09 01:44:23 +01:00
match encoder {
2018-04-14 01:02:01 +02:00
#[cfg(feature = "brotli")]
ContentEncoder::Br(encoder) => match encoder.finish() {
Ok(mut writer) => {
writer.encode_eof();
*self = ContentEncoder::Identity(writer);
2018-05-16 01:41:46 +02:00
Ok(true)
2017-11-09 01:44:23 +01:00
}
2018-04-14 01:02:01 +02:00
Err(err) => Err(err),
},
2018-04-24 21:24:04 +02:00
#[cfg(feature = "flate2")]
2018-04-14 01:02:01 +02:00
ContentEncoder::Gzip(encoder) => match encoder.finish() {
Ok(mut writer) => {
writer.encode_eof();
*self = ContentEncoder::Identity(writer);
2018-05-16 01:41:46 +02:00
Ok(true)
2017-11-09 01:44:23 +01:00
}
2018-04-14 01:02:01 +02:00
Err(err) => Err(err),
2017-11-09 01:44:23 +01:00
},
2018-04-24 21:24:04 +02:00
#[cfg(feature = "flate2")]
2018-04-14 01:02:01 +02:00
ContentEncoder::Deflate(encoder) => match encoder.finish() {
Ok(mut writer) => {
writer.encode_eof();
*self = ContentEncoder::Identity(writer);
2018-05-16 01:41:46 +02:00
Ok(true)
2017-11-09 01:44:23 +01:00
}
2018-04-14 01:02:01 +02:00
Err(err) => Err(err),
2017-11-09 01:44:23 +01:00
},
ContentEncoder::Identity(mut writer) => {
2018-05-16 01:41:46 +02:00
let res = writer.encode_eof();
2018-01-02 23:53:51 +01:00
*self = ContentEncoder::Identity(writer);
2018-05-16 01:41:46 +02:00
Ok(res)
2017-11-09 01:44:23 +01:00
}
}
}
2018-10-02 06:16:56 +02:00
#[cfg_attr(feature = "cargo-clippy", allow(clippy::inline_always))]
2017-12-13 21:47:07 +01:00
#[inline(always)]
pub fn write(&mut self, data: &[u8]) -> Result<(), io::Error> {
2017-11-09 01:44:23 +01:00
match *self {
2018-04-14 01:02:01 +02:00
#[cfg(feature = "brotli")]
ContentEncoder::Br(ref mut encoder) => match encoder.write_all(data) {
Ok(_) => Ok(()),
Err(err) => {
trace!("Error decoding br encoding: {}", err);
Err(err)
2017-11-09 01:44:23 +01:00
}
},
2018-04-24 21:24:04 +02:00
#[cfg(feature = "flate2")]
ContentEncoder::Gzip(ref mut encoder) => match encoder.write_all(data) {
Ok(_) => Ok(()),
Err(err) => {
trace!("Error decoding gzip encoding: {}", err);
Err(err)
2017-11-09 01:44:23 +01:00
}
},
2018-04-24 21:24:04 +02:00
#[cfg(feature = "flate2")]
ContentEncoder::Deflate(ref mut encoder) => match encoder.write_all(data) {
Ok(_) => Ok(()),
Err(err) => {
trace!("Error decoding deflate encoding: {}", err);
Err(err)
2017-11-09 01:44:23 +01:00
}
},
2017-11-09 01:44:23 +01:00
ContentEncoder::Identity(ref mut encoder) => {
2018-01-04 18:32:15 +01:00
encoder.encode(data)?;
2017-11-09 01:44:23 +01:00
Ok(())
}
}
}
}
/// Encoders to handle different Transfer-Encodings.
2018-06-24 04:54:01 +02:00
#[derive(Debug)]
2017-11-09 01:44:23 +01:00
pub(crate) struct TransferEncoding {
2018-06-24 06:30:58 +02:00
buf: Option<BytesMut>,
2017-11-09 01:44:23 +01:00
kind: TransferEncodingKind,
}
#[derive(Debug, PartialEq, Clone)]
enum TransferEncodingKind {
/// An Encoder for when Transfer-Encoding includes `chunked`.
Chunked(bool),
/// An Encoder for when Content-Length is set.
///
/// Enforces that the body is not longer than the Content-Length header.
Length(u64),
/// An Encoder for when Content-Length is not known.
///
2018-01-15 22:47:25 +01:00
/// Application decides when to stop writing.
2017-11-09 01:44:23 +01:00
Eof,
}
impl TransferEncoding {
2018-06-24 06:30:58 +02:00
fn take(&mut self) -> BytesMut {
self.buf.take().unwrap()
2018-06-24 04:54:01 +02:00
}
2018-06-24 06:30:58 +02:00
fn buf_ref(&mut self) -> &BytesMut {
2018-06-24 04:54:01 +02:00
self.buf.as_ref().unwrap()
}
fn len(&self) -> usize {
self.buf.as_ref().unwrap().len()
}
fn is_empty(&self) -> bool {
self.buf.as_ref().unwrap().is_empty()
}
fn buf_mut(&mut self) -> &mut BytesMut {
2018-06-24 06:30:58 +02:00
self.buf.as_mut().unwrap()
}
2017-12-13 06:32:58 +01:00
#[inline]
2018-06-24 04:54:01 +02:00
pub fn empty() -> TransferEncoding {
2017-11-09 01:44:23 +01:00
TransferEncoding {
2018-06-24 04:54:01 +02:00
buf: None,
2017-11-09 01:44:23 +01:00
kind: TransferEncodingKind::Eof,
}
}
2017-12-13 06:32:58 +01:00
#[inline]
2018-06-24 06:30:58 +02:00
pub fn eof(buf: BytesMut) -> TransferEncoding {
2017-11-09 01:44:23 +01:00
TransferEncoding {
2018-06-24 04:54:01 +02:00
buf: Some(buf),
kind: TransferEncodingKind::Eof,
2017-11-09 01:44:23 +01:00
}
}
2017-12-13 06:32:58 +01:00
#[inline]
2018-06-24 06:30:58 +02:00
pub fn chunked(buf: BytesMut) -> TransferEncoding {
2017-11-09 01:44:23 +01:00
TransferEncoding {
2018-06-24 04:54:01 +02:00
buf: Some(buf),
kind: TransferEncodingKind::Chunked(false),
2017-11-09 01:44:23 +01:00
}
}
2017-12-13 06:32:58 +01:00
#[inline]
2018-06-24 06:30:58 +02:00
pub fn length(len: u64, buf: BytesMut) -> TransferEncoding {
2018-06-24 04:54:01 +02:00
TransferEncoding {
buf: Some(buf),
kind: TransferEncodingKind::Length(len),
2017-11-09 01:44:23 +01:00
}
}
/// Encode message. Return `EOF` state of encoder
2017-12-14 01:44:35 +01:00
#[inline]
pub fn encode(&mut self, msg: &[u8]) -> io::Result<bool> {
2017-11-09 01:44:23 +01:00
match self.kind {
TransferEncodingKind::Eof => {
2018-01-15 02:00:28 +01:00
let eof = msg.is_empty();
2018-06-24 04:54:01 +02:00
self.buf.as_mut().unwrap().extend_from_slice(msg);
2018-01-15 02:00:28 +01:00
Ok(eof)
2018-04-14 01:02:01 +02:00
}
2017-11-09 01:44:23 +01:00
TransferEncodingKind::Chunked(ref mut eof) => {
if *eof {
2018-01-04 18:32:15 +01:00
return Ok(true);
2017-11-09 01:44:23 +01:00
}
if msg.is_empty() {
*eof = true;
2018-06-24 04:54:01 +02:00
self.buf.as_mut().unwrap().extend_from_slice(b"0\r\n\r\n");
2017-11-09 01:44:23 +01:00
} else {
2018-01-15 02:00:28 +01:00
let mut buf = BytesMut::new();
2018-04-09 23:25:30 +02:00
writeln!(&mut buf, "{:X}\r", msg.len())
2018-01-04 18:32:15 +01:00
.map_err(|e| io::Error::new(io::ErrorKind::Other, e))?;
2018-06-24 04:54:01 +02:00
let b = self.buf.as_mut().unwrap();
b.reserve(buf.len() + msg.len() + 2);
b.extend_from_slice(buf.as_ref());
b.extend_from_slice(msg);
b.extend_from_slice(b"\r\n");
2017-11-09 01:44:23 +01:00
}
2018-01-04 18:32:15 +01:00
Ok(*eof)
2018-04-14 01:02:01 +02:00
}
2017-11-09 01:44:23 +01:00
TransferEncodingKind::Length(ref mut remaining) => {
2018-01-21 01:12:38 +01:00
if *remaining > 0 {
if msg.is_empty() {
2018-04-14 01:02:01 +02:00
return Ok(*remaining == 0);
2018-01-21 01:12:38 +01:00
}
let len = cmp::min(*remaining, msg.len() as u64);
2018-06-24 04:54:01 +02:00
self.buf
.as_mut()
.unwrap()
.extend_from_slice(&msg[..len as usize]);
2017-11-09 01:44:23 +01:00
2018-01-21 01:12:38 +01:00
*remaining -= len as u64;
Ok(*remaining == 0)
} else {
Ok(true)
}
2018-04-14 01:02:01 +02:00
}
2017-11-09 01:44:23 +01:00
}
}
/// Encode eof. Return `EOF` state of encoder
2017-12-14 01:44:35 +01:00
#[inline]
2018-05-16 01:41:46 +02:00
pub fn encode_eof(&mut self) -> bool {
2017-11-09 01:44:23 +01:00
match self.kind {
2018-05-16 01:41:46 +02:00
TransferEncodingKind::Eof => true,
TransferEncodingKind::Length(rem) => rem == 0,
2017-11-09 01:44:23 +01:00
TransferEncodingKind::Chunked(ref mut eof) => {
if !*eof {
*eof = true;
2018-06-24 04:54:01 +02:00
self.buf.as_mut().unwrap().extend_from_slice(b"0\r\n\r\n");
2017-11-09 01:44:23 +01:00
}
2018-05-16 01:41:46 +02:00
true
2018-04-14 01:02:01 +02:00
}
2017-11-09 01:44:23 +01:00
}
}
}
impl io::Write for TransferEncoding {
2017-12-13 06:32:58 +01:00
#[inline]
2017-11-09 01:44:23 +01:00
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
2018-06-24 06:59:01 +02:00
if self.buf.is_some() {
self.encode(buf)?;
}
2017-11-09 01:44:23 +01:00
Ok(buf.len())
}
2017-12-13 06:32:58 +01:00
#[inline]
2017-11-09 01:44:23 +01:00
fn flush(&mut self) -> io::Result<()> {
Ok(())
}
}
struct AcceptEncoding {
encoding: ContentEncoding,
quality: f64,
}
impl Eq for AcceptEncoding {}
impl Ord for AcceptEncoding {
fn cmp(&self, other: &AcceptEncoding) -> cmp::Ordering {
if self.quality > other.quality {
cmp::Ordering::Less
} else if self.quality < other.quality {
cmp::Ordering::Greater
} else {
cmp::Ordering::Equal
}
}
}
impl PartialOrd for AcceptEncoding {
fn partial_cmp(&self, other: &AcceptEncoding) -> Option<cmp::Ordering> {
Some(self.cmp(other))
}
}
impl PartialEq for AcceptEncoding {
fn eq(&self, other: &AcceptEncoding) -> bool {
self.quality == other.quality
}
}
impl AcceptEncoding {
fn new(tag: &str) -> Option<AcceptEncoding> {
let parts: Vec<&str> = tag.split(';').collect();
let encoding = match parts.len() {
0 => return None,
_ => ContentEncoding::from(parts[0]),
};
let quality = match parts.len() {
2017-11-09 04:42:13 +01:00
1 => encoding.quality(),
2017-11-09 01:44:23 +01:00
_ => match f64::from_str(parts[1]) {
Ok(q) => q,
Err(_) => 0.0,
2018-04-14 01:02:01 +02:00
},
2017-11-09 01:44:23 +01:00
};
2018-05-16 01:41:46 +02:00
Some(AcceptEncoding { encoding, quality })
2017-11-09 01:44:23 +01:00
}
/// Parse a raw Accept-Encoding header value into an ordered list.
pub fn parse(raw: &str) -> ContentEncoding {
2018-05-17 21:20:20 +02:00
let mut encodings: Vec<_> = raw
.replace(' ', "")
2018-04-29 18:09:08 +02:00
.split(',')
.map(|l| AcceptEncoding::new(l))
.collect();
2017-11-09 01:44:23 +01:00
encodings.sort();
for enc in encodings {
if let Some(enc) = enc {
2018-04-14 01:02:01 +02:00
return enc.encoding;
2017-11-09 01:44:23 +01:00
}
}
ContentEncoding::Identity
}
}
2018-01-04 18:32:15 +01:00
#[cfg(test)]
mod tests {
use super::*;
2018-06-24 06:42:20 +02:00
use bytes::Bytes;
2018-01-04 18:32:15 +01:00
#[test]
fn test_chunked_te() {
2018-06-24 06:30:58 +02:00
let bytes = BytesMut::new();
2018-06-24 04:54:01 +02:00
let mut enc = TransferEncoding::chunked(bytes);
{
assert!(!enc.encode(b"test").ok().unwrap());
assert!(enc.encode(b"").ok().unwrap());
}
2018-04-14 01:02:01 +02:00
assert_eq!(
2018-06-24 04:54:01 +02:00
enc.buf_mut().take().freeze(),
2018-04-14 01:02:01 +02:00
Bytes::from_static(b"4\r\ntest\r\n0\r\n\r\n")
);
2018-01-04 18:32:15 +01:00
}
}