1
0
mirror of https://github.com/fafhrd91/actix-web synced 2024-11-25 08:52:42 +01:00
actix-web/src/client/parser.rs

223 lines
7.5 KiB
Rust
Raw Normal View History

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
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;
#[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),
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
}
if stream_finished {
2018-04-14 01:02:01 +02:00
return Err(PayloadError::Incomplete);
}
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) => {
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)
}
}