1
0
mirror of https://github.com/fafhrd91/actix-web synced 2025-02-16 17:53:40 +01:00
actix-web/src/server/output.rs

371 lines
10 KiB
Rust
Raw Normal View History

2018-10-04 21:14:18 -07:00
#![allow(unused_imports, unused_variables, dead_code)]
2017-11-08 16:44:23 -08:00
use std::fmt::Write as FmtWrite;
2018-06-24 10:42:20 +06:00
use std::io::Write;
2017-11-08 16:44:23 -08:00
use std::str::FromStr;
2018-06-24 10:30:58 +06:00
use std::{cmp, fmt, io, mem};
2017-11-08 16:44:23 -08:00
2018-10-04 23:39:11 -07:00
use bytes::{Bytes, BytesMut};
2018-10-04 16:22:00 -07:00
use http::header::{HeaderValue, ACCEPT_ENCODING, CONTENT_LENGTH};
use http::{StatusCode, Version};
2017-11-06 16:23:58 -08:00
2018-04-13 16:02:01 -07:00
use body::{Binary, Body};
use header::ContentEncoding;
2018-10-04 23:39:11 -07:00
use http::Method;
2017-11-08 16:44:23 -08:00
use httpresponse::HttpResponse;
2018-10-04 23:39:11 -07:00
use request::Request;
2018-10-04 16:22:00 -07:00
2018-06-25 10:58:04 +06: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,
2018-10-04 23:39:11 -07:00
pub te: TransferEncoding,
2018-06-25 10:58:04 +06:00
}
2018-10-04 23:39:11 -07:00
impl Default for ResponseInfo {
fn default() -> Self {
2018-06-25 10:58:04 +06:00
ResponseInfo {
2018-10-04 23:39:11 -07:00
head: false,
2018-06-25 10:58:04 +06:00
length: ResponseLength::None,
2018-10-04 23:39:11 -07:00
te: TransferEncoding::empty(),
2018-06-25 10:58:04 +06:00
}
}
}
2018-10-04 23:39:11 -07:00
impl ResponseInfo {
pub fn update(&mut self, resp: &mut HttpResponse, head: bool, version: Version) {
self.head = head;
2018-06-24 10:30:58 +06:00
2018-10-04 23:39:11 -07:00
let version = resp.version().unwrap_or_else(|| version);
2018-05-15 16:41:46 -07:00
let mut len = 0;
2018-05-17 12:23:37 -07:00
2018-05-15 16:41:46 -07:00
let has_body = match resp.body() {
2018-10-01 21:16:56 -07:00
Body::Empty => false,
Body::Binary(ref bin) => {
2018-05-15 16:41:46 -07:00
len = bin.len();
2018-10-04 23:39:11 -07:00
true
2018-04-13 16:02:01 -07:00
}
_ => true,
};
2017-11-08 16:44:23 -08:00
2018-10-04 23:39:11 -07:00
let has_body = match resp.body() {
Body::Empty => false,
_ => true,
2017-11-08 16:44:23 -08:00
};
2018-06-24 22:05:44 +06:00
let transfer = match resp.body() {
2018-10-01 21:16:56 -07:00
Body::Empty => {
2018-10-04 23:39:11 -07:00
if !self.head {
self.length = match resp.status() {
StatusCode::NO_CONTENT
| StatusCode::CONTINUE
| StatusCode::SWITCHING_PROTOCOLS
| StatusCode::PROCESSING => ResponseLength::None,
_ => ResponseLength::Zero,
};
2018-10-04 23:39:11 -07:00
} else {
self.length = ResponseLength::Zero;
2018-01-20 16:12:38 -08:00
}
2018-10-04 23:39:11 -07:00
TransferEncoding::empty()
2018-04-13 16:02:01 -07:00
}
2018-10-01 21:16:56 -07:00
Body::Binary(_) => {
2018-10-04 23:39:11 -07:00
self.length = ResponseLength::Length(len);
TransferEncoding::length(len as u64)
2017-11-08 16:44:23 -08:00
}
2018-10-04 17:00:27 -07:00
Body::Streaming(_) => {
2017-12-31 17:26:32 -08:00
if resp.upgrade() {
2018-10-04 23:39:11 -07:00
self.length = ResponseLength::None;
TransferEncoding::eof()
2017-11-08 16:44:23 -08:00
} else {
2018-10-04 23:39:11 -07:00
self.streaming_encoding(version, resp)
2017-11-08 16:44:23 -08:00
}
}
};
2018-05-15 16:41:46 -07:00
// check for head response
2018-10-04 23:39:11 -07:00
if self.head {
2018-05-15 16:41:46 -07:00
resp.set_body(Body::Empty);
2018-10-04 23:39:11 -07:00
} else {
self.te = transfer;
2018-01-20 16:12:38 -08:00
}
2017-11-08 16:44:23 -08:00
}
2018-01-11 15:26:46 -08:00
2018-04-13 16:02:01 -07:00
fn streaming_encoding(
2018-10-04 23:39:11 -07:00
&mut self, version: Version, resp: &mut HttpResponse,
2018-04-13 16:02:01 -07:00
) -> TransferEncoding {
match resp.chunked() {
Some(true) => {
// Enable transfer encoding
if version == Version::HTTP_2 {
2018-10-04 23:39:11 -07:00
self.length = ResponseLength::None;
TransferEncoding::eof()
} else {
2018-10-04 23:39:11 -07:00
self.length = ResponseLength::Chunked;
TransferEncoding::chunked()
}
2018-04-13 16:02:01 -07:00
}
2018-10-04 23:39:11 -07:00
Some(false) => TransferEncoding::eof(),
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-11 15:26:46 -08:00
} else {
error!("illegal Content-Length: {:?}", len);
(None, false)
}
} else {
(None, true)
};
2018-01-11 15:26:46 -08:00
if !chunked {
if let Some(len) = len {
2018-10-04 23:39:11 -07:00
self.length = ResponseLength::Length64(len);
TransferEncoding::length(len)
} else {
2018-10-04 23:39:11 -07:00
TransferEncoding::eof()
}
} else {
// Enable transfer encoding
match version {
Version::HTTP_11 => {
2018-10-04 23:39:11 -07:00
self.length = ResponseLength::Chunked;
TransferEncoding::chunked()
2018-04-13 16:02:01 -07:00
}
_ => {
2018-10-04 23:39:11 -07:00
self.length = ResponseLength::None;
TransferEncoding::eof()
}
}
2018-01-11 15:26:46 -08:00
}
}
}
}
2017-11-08 16:44:23 -08:00
}
/// Encoders to handle different Transfer-Encodings.
2018-06-24 08:54:01 +06:00
#[derive(Debug)]
2017-11-08 16:44:23 -08:00
pub(crate) struct TransferEncoding {
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-16 00:47:25 +03:00
/// Application decides when to stop writing.
2017-11-08 16:44:23 -08:00
Eof,
}
impl TransferEncoding {
2017-12-12 21:32:58 -08:00
#[inline]
2018-06-24 08:54:01 +06:00
pub fn empty() -> TransferEncoding {
2017-11-08 16:44:23 -08:00
TransferEncoding {
kind: TransferEncodingKind::Eof,
}
}
2017-12-12 21:32:58 -08:00
#[inline]
2018-10-04 23:39:11 -07:00
pub fn eof() -> TransferEncoding {
2017-11-08 16:44:23 -08:00
TransferEncoding {
2018-06-24 08:54:01 +06:00
kind: TransferEncodingKind::Eof,
2017-11-08 16:44:23 -08:00
}
}
2017-12-12 21:32:58 -08:00
#[inline]
2018-10-04 23:39:11 -07:00
pub fn chunked() -> TransferEncoding {
2017-11-08 16:44:23 -08:00
TransferEncoding {
2018-06-24 08:54:01 +06:00
kind: TransferEncodingKind::Chunked(false),
2017-11-08 16:44:23 -08:00
}
}
2017-12-12 21:32:58 -08:00
#[inline]
2018-10-04 23:39:11 -07:00
pub fn length(len: u64) -> TransferEncoding {
2018-06-24 08:54:01 +06:00
TransferEncoding {
kind: TransferEncodingKind::Length(len),
2017-11-08 16:44:23 -08:00
}
}
/// Encode message. Return `EOF` state of encoder
2017-12-13 16:44:35 -08:00
#[inline]
2018-10-04 23:39:11 -07:00
pub fn encode(&mut self, msg: &[u8], buf: &mut BytesMut) -> io::Result<bool> {
2017-11-08 16:44:23 -08:00
match self.kind {
TransferEncodingKind::Eof => {
2018-01-14 17:00:28 -08:00
let eof = msg.is_empty();
2018-10-04 23:39:11 -07:00
buf.extend_from_slice(msg);
2018-01-14 17:00:28 -08:00
Ok(eof)
2018-04-13 16:02:01 -07:00
}
2017-11-08 16:44:23 -08:00
TransferEncodingKind::Chunked(ref mut eof) => {
if *eof {
2018-01-04 09:32:15 -08:00
return Ok(true);
2017-11-08 16:44:23 -08:00
}
if msg.is_empty() {
*eof = true;
2018-10-04 23:39:11 -07:00
buf.extend_from_slice(b"0\r\n\r\n");
2017-11-08 16:44:23 -08:00
} else {
2018-10-04 23:39:11 -07:00
writeln!(buf.as_mut(), "{:X}\r", msg.len())
2018-01-04 09:32:15 -08:00
.map_err(|e| io::Error::new(io::ErrorKind::Other, e))?;
2018-10-04 23:39:11 -07:00
buf.reserve(msg.len() + 2);
buf.extend_from_slice(msg);
buf.extend_from_slice(b"\r\n");
2017-11-08 16:44:23 -08:00
}
2018-01-04 09:32:15 -08:00
Ok(*eof)
2018-04-13 16:02:01 -07:00
}
2017-11-08 16:44:23 -08:00
TransferEncodingKind::Length(ref mut remaining) => {
2018-01-20 16:12:38 -08:00
if *remaining > 0 {
if msg.is_empty() {
2018-04-13 16:02:01 -07:00
return Ok(*remaining == 0);
2018-01-20 16:12:38 -08:00
}
let len = cmp::min(*remaining, msg.len() as u64);
2018-10-04 23:39:11 -07:00
buf.extend_from_slice(&msg[..len as usize]);
2017-11-08 16:44:23 -08:00
2018-01-20 16:12:38 -08:00
*remaining -= len as u64;
Ok(*remaining == 0)
} else {
Ok(true)
}
2018-04-13 16:02:01 -07:00
}
2017-11-08 16:44:23 -08:00
}
}
/// Encode eof. Return `EOF` state of encoder
2017-12-13 16:44:35 -08:00
#[inline]
2018-10-04 23:39:11 -07:00
pub fn encode_eof(&mut self, buf: &mut BytesMut) -> bool {
2017-11-08 16:44:23 -08:00
match self.kind {
2018-05-15 16:41:46 -07:00
TransferEncodingKind::Eof => true,
TransferEncodingKind::Length(rem) => rem == 0,
2017-11-08 16:44:23 -08:00
TransferEncodingKind::Chunked(ref mut eof) => {
if !*eof {
*eof = true;
2018-10-04 23:39:11 -07:00
buf.extend_from_slice(b"0\r\n\r\n");
2017-11-08 16:44:23 -08:00
}
2018-05-15 16:41:46 -07:00
true
2018-04-13 16:02:01 -07:00
}
2017-11-08 16:44:23 -08:00
}
}
}
impl io::Write for TransferEncoding {
2017-12-12 21:32:58 -08:00
#[inline]
2017-11-08 16:44:23 -08:00
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
2018-10-04 23:39:11 -07:00
// if self.buf.is_some() {
// self.encode(buf)?;
// }
2017-11-08 16:44:23 -08:00
Ok(buf.len())
}
2017-12-12 21:32:58 -08:00
#[inline]
2017-11-08 16:44:23 -08: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-08 19:42:13 -08:00
1 => encoding.quality(),
2017-11-08 16:44:23 -08:00
_ => match f64::from_str(parts[1]) {
Ok(q) => q,
Err(_) => 0.0,
2018-04-13 16:02:01 -07:00
},
2017-11-08 16:44:23 -08:00
};
2018-05-15 16:41:46 -07:00
Some(AcceptEncoding { encoding, quality })
2017-11-08 16:44:23 -08:00
}
/// Parse a raw Accept-Encoding header value into an ordered list.
pub fn parse(raw: &str) -> ContentEncoding {
2018-05-17 12:20:20 -07:00
let mut encodings: Vec<_> = raw
.replace(' ', "")
2018-04-29 09:09:08 -07:00
.split(',')
.map(|l| AcceptEncoding::new(l))
.collect();
2017-11-08 16:44:23 -08:00
encodings.sort();
for enc in encodings {
if let Some(enc) = enc {
2018-04-13 16:02:01 -07:00
return enc.encoding;
2017-11-08 16:44:23 -08:00
}
}
ContentEncoding::Identity
}
}
2018-01-04 09:32:15 -08:00
#[cfg(test)]
mod tests {
use super::*;
2018-06-24 10:42:20 +06:00
use bytes::Bytes;
2018-01-04 09:32:15 -08:00
#[test]
fn test_chunked_te() {
2018-06-24 10:30:58 +06:00
let bytes = BytesMut::new();
2018-06-24 08:54:01 +06:00
let mut enc = TransferEncoding::chunked(bytes);
{
assert!(!enc.encode(b"test").ok().unwrap());
assert!(enc.encode(b"").ok().unwrap());
}
2018-04-13 16:02:01 -07:00
assert_eq!(
2018-06-24 08:54:01 +06:00
enc.buf_mut().take().freeze(),
2018-04-13 16:02:01 -07:00
Bytes::from_static(b"4\r\ntest\r\n0\r\n\r\n")
);
2018-01-04 09:32:15 -08:00
}
}