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};
|
2018-10-03 00:15:48 +08:00
|
|
|
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
|
|
|
}
|
2017-11-29 19:18:37 -08: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() {
|
2018-10-03 00:15:48 +08:00
|
|
|
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 {
|
2018-01-13 16:17:33 -08:00
|
|
|
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()
|
2018-01-13 16:17:33 -08:00
|
|
|
} else {
|
2018-10-04 23:39:11 -07:00
|
|
|
self.length = ResponseLength::Chunked;
|
|
|
|
TransferEncoding::chunked()
|
2018-01-13 16:17:33 -08:00
|
|
|
}
|
2018-04-13 16:02:01 -07:00
|
|
|
}
|
2018-10-04 23:39:11 -07:00
|
|
|
Some(false) => TransferEncoding::eof(),
|
2018-01-13 16:17:33 -08:00
|
|
|
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 {
|
2018-01-13 16:17:33 -08:00
|
|
|
(None, true)
|
|
|
|
};
|
2018-01-11 15:26:46 -08:00
|
|
|
|
2018-01-13 16:17:33 -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)
|
2018-01-13 16:17:33 -08:00
|
|
|
} else {
|
2018-10-04 23:39:11 -07:00
|
|
|
TransferEncoding::eof()
|
2018-01-13 12:46:43 -08:00
|
|
|
}
|
2018-01-13 16:17:33 -08:00
|
|
|
} 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-01-13 16:17:33 -08:00
|
|
|
_ => {
|
2018-10-04 23:39:11 -07:00
|
|
|
self.length = ResponseLength::None;
|
|
|
|
TransferEncoding::eof()
|
2018-01-13 16:17:33 -08:00
|
|
|
}
|
|
|
|
}
|
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-05-29 16:32:39 -07:00
|
|
|
|
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-05-29 16:32:39 -07:00
|
|
|
|
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);
|
2018-05-29 16:32:39 -07:00
|
|
|
{
|
|
|
|
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
|
|
|
}
|
|
|
|
}
|