2018-06-23 08:28:55 +02:00
|
|
|
use std::mem;
|
|
|
|
|
2018-03-03 21:17:26 +01:00
|
|
|
use bytes::{Bytes, BytesMut};
|
2018-04-14 01:02:01 +02:00
|
|
|
use futures::{Async, Poll};
|
|
|
|
use http::header::{self, HeaderName, HeaderValue};
|
2018-06-23 08:28:55 +02:00
|
|
|
use http::{HeaderMap, StatusCode, Version};
|
2018-04-14 01:02:01 +02:00
|
|
|
use httparse;
|
2018-01-28 07:03:03 +01:00
|
|
|
|
|
|
|
use error::{ParseError, PayloadError};
|
|
|
|
|
2018-06-23 08:28:55 +02:00
|
|
|
use server::h1decoder::{EncodingDecoder, HeaderIndex};
|
2018-06-22 05:01:20 +02:00
|
|
|
use server::IoStream;
|
2018-01-28 07:03:03 +01:00
|
|
|
|
2018-01-29 23:44:25 +01:00
|
|
|
use super::response::ClientMessage;
|
2018-04-29 07:20:32 +02:00
|
|
|
use super::ClientResponse;
|
2018-01-28 07:03:03 +01:00
|
|
|
|
|
|
|
const MAX_BUFFER_SIZE: usize = 131_072;
|
|
|
|
const MAX_HEADERS: usize = 96;
|
|
|
|
|
2018-01-29 20:39:26 +01:00
|
|
|
#[derive(Default)]
|
2018-01-28 07:03:03 +01:00
|
|
|
pub struct HttpResponseParser {
|
2018-04-29 07:20:32 +02:00
|
|
|
decoder: Option<EncodingDecoder>,
|
2018-01-28 07:03:03 +01:00
|
|
|
}
|
|
|
|
|
2018-02-19 22:18:18 +01:00
|
|
|
#[derive(Debug, Fail)]
|
2018-01-28 07:03:03 +01:00
|
|
|
pub enum HttpResponseParserError {
|
2018-02-19 22:18:18 +01:00
|
|
|
/// Server disconnected
|
2018-04-14 01:02:01 +02:00
|
|
|
#[fail(display = "Server disconnected")]
|
2018-01-28 07:03:03 +01:00
|
|
|
Disconnect,
|
2018-04-14 01:02:01 +02:00
|
|
|
#[fail(display = "{}", _0)]
|
2018-02-19 22:18:18 +01:00
|
|
|
Error(#[cause] ParseError),
|
2018-01-28 07:03:03 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
impl HttpResponseParser {
|
2018-04-14 01:02:01 +02:00
|
|
|
pub fn parse<T>(
|
2018-04-29 07:20:32 +02:00
|
|
|
&mut self, io: &mut T, buf: &mut BytesMut,
|
2018-04-14 01:02:01 +02:00
|
|
|
) -> Poll<ClientResponse, HttpResponseParserError>
|
|
|
|
where
|
|
|
|
T: IoStream,
|
2018-01-28 07:03:03 +01:00
|
|
|
{
|
|
|
|
// if buf is empty parse_message will always return NotReady, let's avoid that
|
2018-03-03 21:17:26 +01:00
|
|
|
if buf.is_empty() {
|
2018-06-22 05:01:20 +02:00
|
|
|
match io.read_available(buf) {
|
2018-06-22 07:30:40 +02:00
|
|
|
Ok(Async::Ready(true)) => {
|
|
|
|
return Err(HttpResponseParserError::Disconnect)
|
|
|
|
}
|
|
|
|
Ok(Async::Ready(false)) => (),
|
2018-04-14 01:02:01 +02:00
|
|
|
Ok(Async::NotReady) => return Ok(Async::NotReady),
|
|
|
|
Err(err) => return Err(HttpResponseParserError::Error(err.into())),
|
2018-01-28 07:03:03 +01:00
|
|
|
}
|
2018-03-03 21:17:26 +01:00
|
|
|
}
|
2018-01-28 07:03:03 +01:00
|
|
|
|
|
|
|
loop {
|
2018-03-03 21:17:26 +01:00
|
|
|
match HttpResponseParser::parse_message(buf)
|
|
|
|
.map_err(HttpResponseParserError::Error)?
|
|
|
|
{
|
2018-01-28 07:03:03 +01:00
|
|
|
Async::Ready((msg, decoder)) => {
|
2018-02-19 12:11:11 +01:00
|
|
|
self.decoder = decoder;
|
2018-01-28 07:03:03 +01:00
|
|
|
return Ok(Async::Ready(msg));
|
2018-04-14 01:02:01 +02:00
|
|
|
}
|
2018-01-28 07:03:03 +01:00
|
|
|
Async::NotReady => {
|
|
|
|
if buf.capacity() >= MAX_BUFFER_SIZE {
|
|
|
|
return Err(HttpResponseParserError::Error(ParseError::TooLarge));
|
|
|
|
}
|
2018-06-22 05:01:20 +02:00
|
|
|
match io.read_available(buf) {
|
2018-06-22 07:30:40 +02:00
|
|
|
Ok(Async::Ready(true)) => {
|
2018-04-14 01:02:01 +02:00
|
|
|
return Err(HttpResponseParserError::Disconnect)
|
|
|
|
}
|
2018-06-22 07:30:40 +02:00
|
|
|
Ok(Async::Ready(false)) => (),
|
2018-03-03 21:17:26 +01:00
|
|
|
Ok(Async::NotReady) => return Ok(Async::NotReady),
|
2018-04-14 01:02:01 +02:00
|
|
|
Err(err) => {
|
|
|
|
return Err(HttpResponseParserError::Error(err.into()))
|
|
|
|
}
|
2018-01-28 07:03:03 +01:00
|
|
|
}
|
2018-04-14 01:02:01 +02:00
|
|
|
}
|
2018-01-28 07:03:03 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-04-14 01:02:01 +02:00
|
|
|
pub fn parse_payload<T>(
|
2018-04-29 07:20:32 +02:00
|
|
|
&mut self, io: &mut T, buf: &mut BytesMut,
|
2018-04-14 01:02:01 +02:00
|
|
|
) -> Poll<Option<Bytes>, PayloadError>
|
|
|
|
where
|
|
|
|
T: IoStream,
|
2018-02-19 12:11:11 +01:00
|
|
|
{
|
2018-02-24 05:29:35 +01:00
|
|
|
if self.decoder.is_some() {
|
2018-03-03 21:17:26 +01:00
|
|
|
loop {
|
|
|
|
// read payload
|
2018-06-22 05:01:20 +02:00
|
|
|
let (not_ready, stream_finished) = match io.read_available(buf) {
|
2018-06-22 07:30:40 +02:00
|
|
|
Ok(Async::Ready(true)) => (false, true),
|
|
|
|
Ok(Async::Ready(false)) => (false, false),
|
2018-04-12 09:47:32 +02:00
|
|
|
Ok(Async::NotReady) => (true, false),
|
2018-06-22 07:30:40 +02:00
|
|
|
Err(err) => return Err(err.into()),
|
2018-03-03 21:17:26 +01:00
|
|
|
};
|
2018-02-24 05:29:35 +01:00
|
|
|
|
2018-03-03 21:17:26 +01:00
|
|
|
match self.decoder.as_mut().unwrap().decode(buf) {
|
2018-04-14 01:02:01 +02:00
|
|
|
Ok(Async::Ready(Some(b))) => return Ok(Async::Ready(Some(b))),
|
2018-03-03 21:17:26 +01:00
|
|
|
Ok(Async::Ready(None)) => {
|
|
|
|
self.decoder.take();
|
2018-04-14 01:02:01 +02:00
|
|
|
return Ok(Async::Ready(None));
|
2018-03-03 21:17:26 +01:00
|
|
|
}
|
|
|
|
Ok(Async::NotReady) => {
|
|
|
|
if not_ready {
|
2018-04-14 01:02:01 +02:00
|
|
|
return Ok(Async::NotReady);
|
2018-03-03 21:17:26 +01:00
|
|
|
}
|
2018-04-12 09:47:32 +02:00
|
|
|
if stream_finished {
|
2018-04-14 01:02:01 +02:00
|
|
|
return Err(PayloadError::Incomplete);
|
2018-04-12 09:47:32 +02:00
|
|
|
}
|
2018-03-03 21:17:26 +01:00
|
|
|
}
|
|
|
|
Err(err) => return Err(err.into()),
|
2018-02-24 05:29:35 +01:00
|
|
|
}
|
|
|
|
}
|
2018-01-30 00:45:37 +01:00
|
|
|
} else {
|
2018-02-19 12:11:11 +01:00
|
|
|
Ok(Async::Ready(None))
|
2018-01-30 00:45:37 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-04-14 01:02:01 +02:00
|
|
|
fn parse_message(
|
2018-04-29 07:20:32 +02:00
|
|
|
buf: &mut BytesMut,
|
|
|
|
) -> Poll<(ClientResponse, Option<EncodingDecoder>), ParseError> {
|
2018-06-23 08:28:55 +02:00
|
|
|
// Unsafe: we read only this data only after httparse parses headers into.
|
|
|
|
// performance bump for pipeline benchmarks.
|
|
|
|
let mut headers: [HeaderIndex; MAX_HEADERS] = unsafe { mem::uninitialized() };
|
2018-01-28 07:03:03 +01:00
|
|
|
|
|
|
|
let (len, version, status, headers_len) = {
|
2018-06-23 08:28:55 +02:00
|
|
|
let mut parsed: [httparse::Header; MAX_HEADERS] =
|
|
|
|
unsafe { mem::uninitialized() };
|
|
|
|
|
|
|
|
let mut resp = httparse::Response::new(&mut parsed);
|
|
|
|
match resp.parse(buf)? {
|
2018-01-28 07:03:03 +01:00
|
|
|
httparse::Status::Complete(len) => {
|
2018-03-23 02:08:12 +01:00
|
|
|
let version = if resp.version.unwrap_or(1) == 1 {
|
2018-01-28 07:03:03 +01:00
|
|
|
Version::HTTP_11
|
|
|
|
} else {
|
|
|
|
Version::HTTP_10
|
|
|
|
};
|
2018-06-23 08:28:55 +02:00
|
|
|
HeaderIndex::record(buf, resp.headers, &mut headers);
|
2018-01-28 07:03:03 +01:00
|
|
|
let status = StatusCode::from_u16(resp.code.unwrap())
|
|
|
|
.map_err(|_| ParseError::Status)?;
|
|
|
|
|
|
|
|
(len, version, status, resp.headers.len())
|
|
|
|
}
|
|
|
|
httparse::Status::Partial => return Ok(Async::NotReady),
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
let slice = buf.split_to(len).freeze();
|
|
|
|
|
|
|
|
// convert headers
|
|
|
|
let mut hdrs = HeaderMap::new();
|
2018-06-23 08:28:55 +02:00
|
|
|
for idx in headers[..headers_len].iter() {
|
|
|
|
if let Ok(name) = HeaderName::from_bytes(&slice[idx.name.0..idx.name.1]) {
|
|
|
|
// Unsafe: httparse check header value for valid utf-8
|
2018-01-28 07:03:03 +01:00
|
|
|
let value = unsafe {
|
2018-06-23 08:28:55 +02:00
|
|
|
HeaderValue::from_shared_unchecked(
|
|
|
|
slice.slice(idx.value.0, idx.value.1),
|
|
|
|
)
|
2018-04-14 01:02:01 +02:00
|
|
|
};
|
2018-01-28 07:03:03 +01:00
|
|
|
hdrs.append(name, value);
|
|
|
|
} else {
|
2018-04-14 01:02:01 +02:00
|
|
|
return Err(ParseError::Header);
|
2018-01-28 07:03:03 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-02-26 22:58:23 +01:00
|
|
|
let decoder = if status == StatusCode::SWITCHING_PROTOCOLS {
|
2018-04-29 07:20:32 +02:00
|
|
|
Some(EncodingDecoder::eof())
|
2018-02-26 22:58:23 +01:00
|
|
|
} else if let Some(len) = hdrs.get(header::CONTENT_LENGTH) {
|
2018-01-28 07:03:03 +01:00
|
|
|
// Content-Length
|
|
|
|
if let Ok(s) = len.to_str() {
|
|
|
|
if let Ok(len) = s.parse::<u64>() {
|
2018-04-29 07:20:32 +02:00
|
|
|
Some(EncodingDecoder::length(len))
|
2018-01-28 07:03:03 +01:00
|
|
|
} else {
|
|
|
|
debug!("illegal Content-Length: {:?}", len);
|
2018-04-14 01:02:01 +02:00
|
|
|
return Err(ParseError::Header);
|
2018-01-28 07:03:03 +01:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
debug!("illegal Content-Length: {:?}", len);
|
2018-04-14 01:02:01 +02:00
|
|
|
return Err(ParseError::Header);
|
2018-01-28 07:03:03 +01:00
|
|
|
}
|
|
|
|
} else if chunked(&hdrs)? {
|
|
|
|
// Chunked encoding
|
2018-04-29 07:20:32 +02:00
|
|
|
Some(EncodingDecoder::chunked())
|
2018-01-28 07:03:03 +01:00
|
|
|
} else {
|
|
|
|
None
|
|
|
|
};
|
|
|
|
|
|
|
|
if let Some(decoder) = decoder {
|
2018-04-14 01:02:01 +02:00
|
|
|
Ok(Async::Ready((
|
|
|
|
ClientResponse::new(ClientMessage {
|
|
|
|
status,
|
|
|
|
version,
|
|
|
|
headers: hdrs,
|
|
|
|
cookies: None,
|
|
|
|
}),
|
|
|
|
Some(decoder),
|
|
|
|
)))
|
2018-01-28 07:03:03 +01:00
|
|
|
} else {
|
2018-04-14 01:02:01 +02:00
|
|
|
Ok(Async::Ready((
|
|
|
|
ClientResponse::new(ClientMessage {
|
|
|
|
status,
|
|
|
|
version,
|
|
|
|
headers: hdrs,
|
|
|
|
cookies: None,
|
|
|
|
}),
|
|
|
|
None,
|
|
|
|
)))
|
2018-01-28 07:03:03 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2018-04-29 07:20:32 +02:00
|
|
|
|
|
|
|
/// Check if request has chunked transfer encoding
|
|
|
|
pub fn chunked(headers: &HeaderMap) -> Result<bool, ParseError> {
|
|
|
|
if let Some(encodings) = headers.get(header::TRANSFER_ENCODING) {
|
|
|
|
if let Ok(s) = encodings.to_str() {
|
|
|
|
Ok(s.to_lowercase().contains("chunked"))
|
|
|
|
} else {
|
|
|
|
Err(ParseError::Header)
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
Ok(false)
|
|
|
|
}
|
|
|
|
}
|