1
0
mirror of https://github.com/actix/actix-extras.git synced 2024-11-24 16:02:59 +01:00
actix-extras/src/server/encoding.rs

869 lines
27 KiB
Rust
Raw Normal View History

2017-11-09 01:44:23 +01:00
use std::fmt::Write as FmtWrite;
2018-04-14 01:02:01 +02:00
use std::io::{Read, Write};
2017-11-09 01:44:23 +01:00
use std::str::FromStr;
2018-04-14 01:02:01 +02:00
use std::{cmp, io, mem};
2017-11-09 01:44:23 +01:00
2018-04-14 01:02:01 +02:00
#[cfg(feature = "brotli")]
use brotli2::write::{BrotliDecoder, BrotliEncoder};
use bytes::{BufMut, Bytes, BytesMut};
2017-11-09 01:44:23 +01:00
use flate2::Compression;
2018-01-12 21:31:33 +01:00
use flate2::read::GzDecoder;
2018-04-14 01:02:01 +02:00
use flate2::write::{DeflateDecoder, DeflateEncoder, GzEncoder};
2018-04-23 00:28:04 +02:00
use http::header::{HeaderMap, HeaderValue, ACCEPT_ENCODING,
2018-04-14 01:02:01 +02:00
CONTENT_ENCODING, CONTENT_LENGTH, TRANSFER_ENCODING};
use http::{HttpTryFrom, Method, Version};
2017-11-07 01:23:58 +01:00
2018-04-14 01:02:01 +02:00
use body::{Binary, Body};
2017-11-16 07:06:28 +01:00
use error::PayloadError;
2018-04-14 01:02:01 +02:00
use header::ContentEncoding;
use httprequest::HttpInnerMessage;
2017-11-09 01:44:23 +01:00
use httpresponse::HttpResponse;
2018-04-14 01:02:01 +02:00
use payload::{PayloadSender, PayloadStatus, PayloadWriter};
2017-11-07 01:23:58 +01:00
2018-01-15 02:00:28 +01:00
use super::shared::SharedBytes;
2017-11-07 01:23:58 +01:00
pub(crate) enum PayloadType {
Sender(PayloadSender),
2017-11-27 02:30:35 +01:00
Encoding(Box<EncodedPayload>),
2017-11-07 01:23:58 +01:00
}
impl PayloadType {
pub fn new(headers: &HeaderMap, sender: PayloadSender) -> PayloadType {
// check content-encoding
let enc = if let Some(enc) = headers.get(CONTENT_ENCODING) {
if let Ok(enc) = enc.to_str() {
ContentEncoding::from(enc)
} else {
ContentEncoding::Auto
}
} else {
ContentEncoding::Auto
};
match enc {
2018-04-14 01:02:01 +02:00
ContentEncoding::Auto | ContentEncoding::Identity => {
PayloadType::Sender(sender)
}
2017-11-27 02:30:35 +01:00
_ => PayloadType::Encoding(Box::new(EncodedPayload::new(sender, enc))),
2017-11-07 01:23:58 +01:00
}
}
}
impl PayloadWriter for PayloadType {
2018-02-10 01:20:10 +01:00
#[inline]
2017-11-07 01:23:58 +01:00
fn set_error(&mut self, err: PayloadError) {
match *self {
PayloadType::Sender(ref mut sender) => sender.set_error(err),
PayloadType::Encoding(ref mut enc) => enc.set_error(err),
}
}
2018-02-10 01:20:10 +01:00
#[inline]
2017-11-07 01:23:58 +01:00
fn feed_eof(&mut self) {
match *self {
PayloadType::Sender(ref mut sender) => sender.feed_eof(),
PayloadType::Encoding(ref mut enc) => enc.feed_eof(),
}
}
2018-02-10 01:20:10 +01:00
#[inline]
2017-11-07 01:23:58 +01:00
fn feed_data(&mut self, data: Bytes) {
match *self {
PayloadType::Sender(ref mut sender) => sender.feed_data(data),
PayloadType::Encoding(ref mut enc) => enc.feed_data(data),
}
}
2018-02-10 01:20:10 +01:00
#[inline]
fn need_read(&self) -> PayloadStatus {
2017-11-07 01:23:58 +01:00
match *self {
2018-02-27 05:07:22 +01:00
PayloadType::Sender(ref sender) => sender.need_read(),
PayloadType::Encoding(ref enc) => enc.need_read(),
2017-11-07 01:23:58 +01:00
}
}
}
/// Payload wrapper with content decompression support
pub(crate) struct EncodedPayload {
inner: PayloadSender,
error: bool,
payload: PayloadStream,
}
impl EncodedPayload {
pub fn new(inner: PayloadSender, enc: ContentEncoding) -> EncodedPayload {
2018-04-14 01:02:01 +02:00
EncodedPayload {
inner,
error: false,
payload: PayloadStream::new(enc),
}
}
}
impl PayloadWriter for EncodedPayload {
fn set_error(&mut self, err: PayloadError) {
self.inner.set_error(err)
}
fn feed_eof(&mut self) {
if !self.error {
match self.payload.feed_eof() {
Err(err) => {
self.error = true;
self.set_error(PayloadError::Io(err));
2018-04-14 01:02:01 +02:00
}
Ok(value) => {
if let Some(b) = value {
self.inner.feed_data(b);
}
self.inner.feed_eof();
}
}
}
}
fn feed_data(&mut self, data: Bytes) {
if self.error {
2018-04-14 01:02:01 +02:00
return;
}
match self.payload.feed_data(data) {
Ok(Some(b)) => self.inner.feed_data(b),
Ok(None) => (),
Err(e) => {
self.error = true;
self.set_error(e.into());
}
}
}
#[inline]
fn need_read(&self) -> PayloadStatus {
self.inner.need_read()
}
}
2018-02-24 05:29:35 +01:00
pub(crate) enum Decoder {
Deflate(Box<DeflateDecoder<Writer>>),
2018-01-12 21:31:33 +01:00
Gzip(Option<Box<GzDecoder<Wrapper>>>),
2018-04-14 01:02:01 +02:00
#[cfg(feature = "brotli")]
Br(Box<BrotliDecoder<Writer>>),
2017-11-07 01:23:58 +01:00
Identity,
}
2018-01-12 21:31:33 +01:00
// should go after write::GzDecoder get implemented
#[derive(Debug)]
2018-02-24 05:29:35 +01:00
pub(crate) struct Wrapper {
pub buf: BytesMut,
pub eof: bool,
2018-01-12 21:31:33 +01:00
}
impl io::Read for Wrapper {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
let len = cmp::min(buf.len(), self.buf.len());
buf[..len].copy_from_slice(&self.buf[..len]);
self.buf.split_to(len);
if len == 0 {
if self.eof {
Ok(0)
} else {
Err(io::Error::new(io::ErrorKind::WouldBlock, ""))
}
} else {
Ok(len)
}
}
}
impl io::Write for Wrapper {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
self.buf.extend_from_slice(buf);
Ok(buf.len())
}
fn flush(&mut self) -> io::Result<()> {
Ok(())
}
}
pub(crate) struct Writer {
buf: BytesMut,
}
impl Writer {
fn new() -> Writer {
2018-04-14 01:02:01 +02:00
Writer {
buf: BytesMut::with_capacity(8192),
}
}
fn take(&mut self) -> Bytes {
self.buf.take().freeze()
}
}
impl io::Write for Writer {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
self.buf.extend_from_slice(buf);
Ok(buf.len())
}
fn flush(&mut self) -> io::Result<()> {
Ok(())
}
}
2018-02-25 09:43:00 +01:00
/// Payload stream with decompression support
pub(crate) struct PayloadStream {
2017-11-07 01:23:58 +01:00
decoder: Decoder,
2018-01-12 21:31:33 +01:00
dst: BytesMut,
2017-11-07 01:23:58 +01:00
}
2018-02-25 09:43:00 +01:00
impl PayloadStream {
pub fn new(enc: ContentEncoding) -> PayloadStream {
2017-11-07 01:23:58 +01:00
let dec = match enc {
2018-04-14 01:02:01 +02:00
#[cfg(feature = "brotli")]
ContentEncoding::Br => {
Decoder::Br(Box::new(BrotliDecoder::new(Writer::new())))
}
ContentEncoding::Deflate => {
Decoder::Deflate(Box::new(DeflateDecoder::new(Writer::new())))
}
2018-01-12 21:31:33 +01:00
ContentEncoding::Gzip => Decoder::Gzip(None),
2017-11-07 01:23:58 +01:00
_ => Decoder::Identity,
};
2018-04-14 01:02:01 +02:00
PayloadStream {
decoder: dec,
dst: BytesMut::new(),
}
2017-11-07 01:23:58 +01:00
}
}
2018-02-25 09:43:00 +01:00
impl PayloadStream {
pub fn feed_eof(&mut self) -> io::Result<Option<Bytes>> {
match self.decoder {
2018-04-14 01:02:01 +02:00
#[cfg(feature = "brotli")]
Decoder::Br(ref mut decoder) => match decoder.finish() {
Ok(mut writer) => {
let b = writer.take();
if !b.is_empty() {
Ok(Some(b))
} else {
Ok(None)
}
2017-11-07 01:23:58 +01:00
}
2018-04-14 01:02:01 +02:00
Err(e) => Err(e),
2017-11-08 00:59:37 +01:00
},
2017-11-07 01:23:58 +01:00
Decoder::Gzip(ref mut decoder) => {
2018-01-12 21:31:33 +01:00
if let Some(ref mut decoder) = *decoder {
decoder.as_mut().get_mut().eof = true;
2018-03-06 20:02:03 +01:00
self.dst.reserve(8192);
2018-04-14 01:02:01 +02:00
match decoder.read(unsafe { self.dst.bytes_mut() }) {
Ok(n) => {
unsafe { self.dst.advance_mut(n) };
return Ok(Some(self.dst.take().freeze()));
2017-11-07 01:23:58 +01:00
}
2018-04-14 01:02:01 +02:00
Err(e) => return Err(e),
2018-01-12 21:31:33 +01:00
}
} else {
2018-02-25 09:43:00 +01:00
Ok(None)
2017-11-07 01:23:58 +01:00
}
2018-04-14 01:02:01 +02:00
}
Decoder::Deflate(ref mut decoder) => match decoder.try_finish() {
Ok(_) => {
let b = decoder.get_mut().take();
if !b.is_empty() {
Ok(Some(b))
} else {
Ok(None)
}
2017-11-07 01:23:58 +01:00
}
2018-04-14 01:02:01 +02:00
Err(e) => Err(e),
2017-11-07 01:23:58 +01:00
},
2018-02-25 09:43:00 +01:00
Decoder::Identity => Ok(None),
2017-11-07 01:23:58 +01:00
}
}
2018-02-25 09:43:00 +01:00
pub fn feed_data(&mut self, data: Bytes) -> io::Result<Option<Bytes>> {
2017-11-07 01:23:58 +01:00
match self.decoder {
2018-04-14 01:02:01 +02:00
#[cfg(feature = "brotli")]
Decoder::Br(ref mut decoder) => match decoder.write_all(&data) {
Ok(_) => {
decoder.flush()?;
let b = decoder.get_mut().take();
if !b.is_empty() {
Ok(Some(b))
} else {
Ok(None)
}
2017-11-07 01:23:58 +01:00
}
2018-04-14 01:02:01 +02:00
Err(e) => Err(e),
2018-02-25 09:43:00 +01:00
},
2017-11-07 01:23:58 +01:00
Decoder::Gzip(ref mut decoder) => {
2018-01-12 21:31:33 +01:00
if decoder.is_none() {
2018-04-14 01:02:01 +02:00
*decoder = Some(Box::new(GzDecoder::new(Wrapper {
buf: BytesMut::from(data),
eof: false,
})));
2018-01-12 21:31:33 +01:00
} else {
let _ = decoder.as_mut().unwrap().write(&data);
}
loop {
self.dst.reserve(8192);
2018-04-14 01:02:01 +02:00
match decoder
.as_mut()
.as_mut()
.unwrap()
.read(unsafe { self.dst.bytes_mut() })
2018-03-06 20:02:03 +01:00
{
2018-04-14 01:02:01 +02:00
Ok(n) => {
2018-03-06 20:02:03 +01:00
if n != 0 {
2018-04-14 01:02:01 +02:00
unsafe { self.dst.advance_mut(n) };
2018-03-06 20:02:03 +01:00
}
2018-01-12 21:31:33 +01:00
if n == 0 {
return Ok(Some(self.dst.take().freeze()));
2018-01-12 21:31:33 +01:00
}
}
Err(e) => {
2018-04-14 01:02:01 +02:00
if e.kind() == io::ErrorKind::WouldBlock
&& !self.dst.is_empty()
2018-03-06 20:02:03 +01:00
{
return Ok(Some(self.dst.take().freeze()));
}
2018-04-14 01:02:01 +02:00
return Err(e);
}
2017-11-07 01:23:58 +01:00
}
}
2018-04-14 01:02:01 +02:00
}
Decoder::Deflate(ref mut decoder) => match decoder.write_all(&data) {
Ok(_) => {
decoder.flush()?;
let b = decoder.get_mut().take();
if !b.is_empty() {
Ok(Some(b))
} else {
Ok(None)
}
2018-02-25 09:43:00 +01:00
}
2018-04-14 01:02:01 +02:00
Err(e) => Err(e),
2018-02-25 09:43:00 +01:00
},
Decoder::Identity => Ok(Some(data)),
}
}
}
pub(crate) enum ContentEncoder {
Deflate(DeflateEncoder<TransferEncoding>),
Gzip(GzEncoder<TransferEncoding>),
2018-04-14 01:02:01 +02:00
#[cfg(feature = "brotli")]
2018-02-25 09:43:00 +01:00
Br(BrotliEncoder<TransferEncoding>),
Identity(TransferEncoding),
}
2017-11-09 01:44:23 +01:00
2018-02-25 09:43:00 +01:00
impl ContentEncoder {
pub fn empty(bytes: SharedBytes) -> ContentEncoder {
ContentEncoder::Identity(TransferEncoding::eof(bytes))
2017-12-15 04:34:31 +01:00
}
2018-04-14 01:02:01 +02:00
pub fn for_server(
buf: SharedBytes, req: &HttpInnerMessage, resp: &mut HttpResponse,
response_encoding: ContentEncoding,
) -> ContentEncoder {
2017-12-09 13:33:40 +01:00
let version = resp.version().unwrap_or_else(|| req.version);
2018-03-18 19:05:44 +01:00
let is_head = req.method == Method::HEAD;
let mut body = resp.replace_body(Body::Empty);
let has_body = match body {
Body::Empty => false,
2018-04-14 01:02:01 +02:00
Body::Binary(ref bin) => {
!(response_encoding == ContentEncoding::Auto && bin.len() < 96)
}
_ => 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
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() {
resp.headers_mut().insert(
2018-04-14 01:02:01 +02:00
CONTENT_ENCODING,
HeaderValue::from_static(encoding.as_str()),
);
2017-12-14 01:44:35 +01:00
}
2017-11-09 01:44:23 +01:00
encoding
} else {
ContentEncoding::Identity
};
2018-01-21 01:12:38 +01:00
let mut transfer = match body {
2017-11-09 01:44:23 +01:00
Body::Empty => {
2018-01-21 01:12:38 +01:00
if req.method != Method::HEAD {
resp.headers_mut().remove(CONTENT_LENGTH);
}
TransferEncoding::length(0, buf)
2018-04-14 01:02:01 +02:00
}
Body::Binary(ref mut bytes) => {
2018-03-18 19:05:44 +01:00
if !(encoding == ContentEncoding::Identity
2018-04-14 01:02:01 +02:00
|| encoding == ContentEncoding::Auto)
2018-03-18 19:05:44 +01:00
{
2018-01-11 07:42:26 +01:00
let tmp = SharedBytes::default();
let transfer = TransferEncoding::eof(tmp.clone());
let mut enc = match encoding {
ContentEncoding::Deflate => ContentEncoder::Deflate(
2018-04-14 01:02:01 +02:00
DeflateEncoder::new(transfer, Compression::fast()),
),
ContentEncoding::Gzip => ContentEncoder::Gzip(GzEncoder::new(
transfer,
Compression::fast(),
)),
#[cfg(feature = "brotli")]
ContentEncoding::Br => {
ContentEncoder::Br(BrotliEncoder::new(transfer, 3))
}
ContentEncoding::Identity => ContentEncoder::Identity(transfer),
2018-04-14 01:02:01 +02:00
ContentEncoding::Auto => unreachable!(),
};
// TODO return error!
2018-01-14 23:40:39 +01:00
let _ = enc.write(bytes.clone());
let _ = enc.write_eof();
2018-01-15 02:00:28 +01:00
*bytes = Binary::from(tmp.take());
encoding = ContentEncoding::Identity;
2017-11-09 01:44:23 +01:00
}
2018-03-18 19:05:44 +01:00
if is_head {
2018-01-21 01:12:38 +01:00
let mut b = BytesMut::new();
2018-03-06 09:43:25 +01:00
let _ = write!(b, "{}", bytes.len());
2018-01-21 01:12:38 +01:00
resp.headers_mut().insert(
2018-04-14 01:02:01 +02:00
CONTENT_LENGTH,
HeaderValue::try_from(b.freeze()).unwrap(),
);
2018-01-21 01:12:38 +01:00
} else {
2018-03-18 19:05:44 +01:00
// resp.headers_mut().remove(CONTENT_LENGTH);
2018-01-21 01:12:38 +01:00
}
2017-12-16 16:29:15 +01:00
TransferEncoding::eof(buf)
2017-11-09 01:44:23 +01:00
}
2018-01-01 02:26:32 +01:00
Body::Streaming(_) | Body::Actor(_) => {
if resp.upgrade() {
if version == Version::HTTP_2 {
error!("Connection upgrade is forbidden for HTTP/2");
}
if encoding != ContentEncoding::Identity {
encoding = ContentEncoding::Identity;
resp.headers_mut().remove(CONTENT_ENCODING);
}
TransferEncoding::eof(buf)
2017-11-09 01:44:23 +01:00
} else {
2018-02-25 09:43:00 +01:00
ContentEncoder::streaming_encoding(buf, version, resp)
2017-11-09 01:44:23 +01:00
}
}
};
2018-01-21 01:12:38 +01:00
//
2018-03-18 19:05:44 +01:00
if is_head {
2018-01-21 01:12:38 +01:00
transfer.kind = TransferEncodingKind::Length(0);
} else {
resp.replace_body(body);
}
2017-11-09 01:44:23 +01:00
2018-02-25 09:43:00 +01:00
match encoding {
2018-04-14 01:02:01 +02:00
ContentEncoding::Deflate => ContentEncoder::Deflate(DeflateEncoder::new(
transfer,
Compression::fast(),
)),
ContentEncoding::Gzip => {
ContentEncoder::Gzip(GzEncoder::new(transfer, Compression::fast()))
}
#[cfg(feature = "brotli")]
ContentEncoding::Br => ContentEncoder::Br(BrotliEncoder::new(transfer, 3)),
ContentEncoding::Identity | ContentEncoding::Auto => {
ContentEncoder::Identity(transfer)
}
2018-02-25 09:43:00 +01:00
}
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(
buf: SharedBytes, version: Version, resp: &mut HttpResponse
) -> TransferEncoding {
match resp.chunked() {
Some(true) => {
// Enable transfer encoding
resp.headers_mut().remove(CONTENT_LENGTH);
if version == Version::HTTP_2 {
resp.headers_mut().remove(TRANSFER_ENCODING);
TransferEncoding::eof(buf)
} else {
2018-04-14 01:02:01 +02:00
resp.headers_mut()
.insert(TRANSFER_ENCODING, HeaderValue::from_static("chunked"));
TransferEncoding::chunked(buf)
}
2018-04-14 01:02: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 {
TransferEncoding::length(len, buf)
} else {
TransferEncoding::eof(buf)
}
} else {
// Enable transfer encoding
match version {
Version::HTTP_11 => {
resp.headers_mut().insert(
2018-04-14 01:02:01 +02:00
TRANSFER_ENCODING,
HeaderValue::from_static("chunked"),
);
TransferEncoding::chunked(buf)
2018-04-14 01:02:01 +02:00
}
_ => {
resp.headers_mut().remove(TRANSFER_ENCODING);
TransferEncoding::eof(buf)
}
}
2018-01-12 00:26:46 +01:00
}
}
}
}
2017-11-09 01:44:23 +01:00
}
impl ContentEncoder {
2017-12-13 06:32:58 +01:00
#[inline]
2017-11-09 01:44:23 +01:00
pub fn is_eof(&self) -> bool {
match *self {
2018-04-14 01:02:01 +02:00
#[cfg(feature = "brotli")]
2018-01-15 04:28:34 +01:00
ContentEncoder::Br(ref encoder) => encoder.get_ref().is_eof(),
ContentEncoder::Deflate(ref encoder) => encoder.get_ref().is_eof(),
ContentEncoder::Gzip(ref encoder) => encoder.get_ref().is_eof(),
ContentEncoder::Identity(ref encoder) => encoder.is_eof(),
2017-11-09 01:44:23 +01:00
}
}
2017-12-14 01:44:35 +01:00
#[cfg_attr(feature = "cargo-clippy", allow(inline_always))]
2017-12-13 21:47:07 +01:00
#[inline(always)]
2017-11-09 01:44:23 +01:00
pub fn write_eof(&mut self) -> Result<(), io::Error> {
2017-12-15 04:34:31 +01:00
let encoder = mem::replace(
2018-04-14 01:02:01 +02:00
self,
ContentEncoder::Identity(TransferEncoding::eof(SharedBytes::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);
Ok(())
2017-11-09 01:44:23 +01:00
}
2018-04-14 01:02:01 +02:00
Err(err) => Err(err),
},
ContentEncoder::Gzip(encoder) => match encoder.finish() {
Ok(mut writer) => {
writer.encode_eof();
*self = ContentEncoder::Identity(writer);
Ok(())
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-14 01:02:01 +02:00
ContentEncoder::Deflate(encoder) => match encoder.finish() {
Ok(mut writer) => {
writer.encode_eof();
*self = ContentEncoder::Identity(writer);
Ok(())
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) => {
writer.encode_eof();
2018-01-02 23:53:51 +01:00
*self = ContentEncoder::Identity(writer);
2017-11-09 01:44:23 +01:00
Ok(())
}
}
}
2017-12-14 01:44:35 +01:00
#[cfg_attr(feature = "cargo-clippy", allow(inline_always))]
2017-12-13 21:47:07 +01:00
#[inline(always)]
2018-01-14 23:40:39 +01:00
pub fn write(&mut self, data: Binary) -> Result<(), io::Error> {
2017-11-09 01:44:23 +01:00
match *self {
2018-04-14 01:02:01 +02:00
#[cfg(feature = "brotli")]
2017-11-09 01:44:23 +01:00
ContentEncoder::Br(ref mut encoder) => {
2018-03-06 20:02:03 +01:00
match encoder.write_all(data.as_ref()) {
Ok(_) => Ok(()),
2017-11-09 01:44:23 +01:00
Err(err) => {
trace!("Error decoding br encoding: {}", err);
Err(err)
2018-04-14 01:02:01 +02:00
}
2017-11-09 01:44:23 +01:00
}
2018-04-14 01:02:01 +02:00
}
2017-11-09 01:44:23 +01:00
ContentEncoder::Gzip(ref mut encoder) => {
2018-03-06 20:02:03 +01:00
match encoder.write_all(data.as_ref()) {
Ok(_) => Ok(()),
2017-11-09 01:44:23 +01:00
Err(err) => {
2017-12-13 06:32:58 +01:00
trace!("Error decoding gzip encoding: {}", err);
2017-11-09 01:44:23 +01:00
Err(err)
2018-04-14 01:02:01 +02:00
}
2017-11-09 01:44:23 +01:00
}
}
ContentEncoder::Deflate(ref mut encoder) => {
2018-03-06 20:02:03 +01:00
match encoder.write_all(data.as_ref()) {
Ok(_) => Ok(()),
2017-11-09 01:44:23 +01:00
Err(err) => {
trace!("Error decoding deflate encoding: {}", err);
Err(err)
2018-04-14 01:02:01 +02: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.
#[derive(Debug, Clone)]
pub(crate) struct TransferEncoding {
kind: TransferEncodingKind,
2017-12-15 04:34:31 +01:00
buffer: SharedBytes,
2017-11-09 01:44:23 +01:00
}
#[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 {
2017-12-13 06:32:58 +01:00
#[inline]
2017-12-15 04:34:31 +01:00
pub fn eof(bytes: SharedBytes) -> TransferEncoding {
2017-11-09 01:44:23 +01:00
TransferEncoding {
kind: TransferEncodingKind::Eof,
2017-12-15 04:34:31 +01:00
buffer: bytes,
2017-11-09 01:44:23 +01:00
}
}
2017-12-13 06:32:58 +01:00
#[inline]
2017-12-15 04:34:31 +01:00
pub fn chunked(bytes: SharedBytes) -> TransferEncoding {
2017-11-09 01:44:23 +01:00
TransferEncoding {
kind: TransferEncodingKind::Chunked(false),
2017-12-15 04:34:31 +01:00
buffer: bytes,
2017-11-09 01:44:23 +01:00
}
}
2017-12-13 06:32:58 +01:00
#[inline]
2017-12-15 04:34:31 +01:00
pub fn length(len: u64, bytes: SharedBytes) -> TransferEncoding {
2017-11-09 01:44:23 +01:00
TransferEncoding {
kind: TransferEncodingKind::Length(len),
2017-12-15 04:34:31 +01:00
buffer: bytes,
2017-11-09 01:44:23 +01:00
}
}
2017-12-13 06:32:58 +01:00
#[inline]
2017-11-09 01:44:23 +01:00
pub fn is_eof(&self) -> bool {
match self.kind {
TransferEncodingKind::Eof => true,
2018-01-11 06:02:28 +01:00
TransferEncodingKind::Chunked(ref eof) => *eof,
TransferEncodingKind::Length(ref remaining) => *remaining == 0,
2017-11-09 01:44:23 +01:00
}
}
/// Encode message. Return `EOF` state of encoder
2017-12-14 01:44:35 +01:00
#[inline]
2018-01-15 02:00:28 +01:00
pub fn encode(&mut self, mut msg: Binary) -> 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();
self.buffer.extend(msg);
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-01-15 02:00:28 +01:00
self.buffer.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-01-15 04:28:34 +01:00
self.buffer.reserve(buf.len() + msg.len() + 2);
2018-01-15 02:00:28 +01:00
self.buffer.extend(buf.into());
self.buffer.extend(msg);
self.buffer.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-04-14 01:02:01 +02:00
self.buffer
.extend(msg.take().split_to(len as usize).into());
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]
2017-11-09 01:44:23 +01:00
pub fn encode_eof(&mut self) {
match self.kind {
TransferEncodingKind::Eof | TransferEncodingKind::Length(_) => (),
TransferEncodingKind::Chunked(ref mut eof) => {
if !*eof {
*eof = true;
2018-01-15 02:00:28 +01:00
self.buffer.extend_from_slice(b"0\r\n\r\n");
2017-11-09 01:44:23 +01:00
}
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-01-14 23:40:39 +01:00
self.encode(Binary::from_slice(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-04-14 01:02:01 +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-04-14 01:02:01 +02:00
let mut encodings: Vec<_> = raw.replace(' ', "")
.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::*;
#[test]
fn test_chunked_te() {
let bytes = SharedBytes::default();
let mut enc = TransferEncoding::chunked(bytes.clone());
2018-04-14 01:02:01 +02:00
assert!(!enc.encode(Binary::from(b"test".as_ref()))
.ok()
.unwrap());
2018-01-14 23:58:58 +01:00
assert!(enc.encode(Binary::from(b"".as_ref())).ok().unwrap());
2018-04-14 01:02:01 +02:00
assert_eq!(
bytes.get_mut().take().freeze(),
Bytes::from_static(b"4\r\ntest\r\n0\r\n\r\n")
);
2018-01-04 18:32:15 +01:00
}
}