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

196 lines
6.8 KiB
Rust
Raw Normal View History

2018-01-28 07:03:03 +01:00
use std::mem;
use httparse;
use http::{Version, HttpTryFrom, HeaderMap, StatusCode};
use http::header::{self, HeaderName, HeaderValue};
2018-03-03 21:17:26 +01:00
use bytes::{Bytes, BytesMut};
2018-01-28 07:03:03 +01:00
use futures::{Poll, Async};
use error::{ParseError, PayloadError};
use server::{utils, IoStream};
use server::h1::{Decoder, chunked};
use super::ClientResponse;
use super::response::ClientMessage;
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-02-19 12:11:11 +01:00
decoder: Option<Decoder>,
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
#[fail(display="Server disconnected")]
2018-01-28 07:03:03 +01:00
Disconnect,
2018-02-19 22:18:18 +01:00
#[fail(display="{}", _0)]
Error(#[cause] ParseError),
2018-01-28 07:03:03 +01:00
}
impl HttpResponseParser {
pub fn parse<T>(&mut self, io: &mut T, buf: &mut BytesMut)
-> Poll<ClientResponse, HttpResponseParserError>
where T: IoStream
{
// 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-01-28 07:03:03 +01:00
match utils::read_from_io(io, buf) {
Ok(Async::Ready(0)) =>
return Err(HttpResponseParserError::Disconnect),
2018-01-28 07:03:03 +01:00
Ok(Async::Ready(_)) => (),
Ok(Async::NotReady) =>
return Ok(Async::NotReady),
Err(err) =>
return Err(HttpResponseParserError::Error(err.into()))
}
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));
},
Async::NotReady => {
if buf.capacity() >= MAX_BUFFER_SIZE {
return Err(HttpResponseParserError::Error(ParseError::TooLarge));
}
2018-03-03 21:17:26 +01:00
match utils::read_from_io(io, buf) {
Ok(Async::Ready(0)) =>
return Err(HttpResponseParserError::Disconnect),
Ok(Async::Ready(_)) => (),
Ok(Async::NotReady) => return Ok(Async::NotReady),
Err(err) =>
return Err(HttpResponseParserError::Error(err.into())),
2018-01-28 07:03:03 +01:00
}
},
}
}
}
2018-02-19 12:11:11 +01:00
pub fn parse_payload<T>(&mut self, io: &mut T, buf: &mut BytesMut)
-> Poll<Option<Bytes>, PayloadError>
where T: IoStream
{
2018-02-24 05:29:35 +01:00
if self.decoder.is_some() {
2018-03-03 21:17:26 +01:00
loop {
// read payload
let not_ready = match utils::read_from_io(io, buf) {
Ok(Async::Ready(0)) => {
if buf.is_empty() {
return Err(PayloadError::Incomplete)
}
true
2018-02-24 05:29:35 +01:00
}
2018-03-03 21:17:26 +01:00
Err(err) => return Err(err.into()),
Ok(Async::NotReady) => true,
_ => false,
};
2018-02-24 05:29:35 +01:00
2018-03-03 21:17:26 +01:00
match self.decoder.as_mut().unwrap().decode(buf) {
Ok(Async::Ready(Some(b))) =>
return Ok(Async::Ready(Some(b))),
Ok(Async::Ready(None)) => {
self.decoder.take();
return Ok(Async::Ready(None))
}
Ok(Async::NotReady) => {
if not_ready {
return Ok(Async::NotReady)
}
}
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
}
}
fn parse_message(buf: &mut BytesMut)
-> Poll<(ClientResponse, Option<Decoder>), ParseError>
2018-02-24 05:29:35 +01:00
{
2018-01-28 07:03:03 +01:00
// Parse http message
let bytes_ptr = buf.as_ref().as_ptr() as usize;
let mut headers: [httparse::Header; MAX_HEADERS] =
unsafe{mem::uninitialized()};
let (len, version, status, headers_len) = {
let b = unsafe{ let b: &[u8] = buf; mem::transmute(b) };
let mut resp = httparse::Response::new(&mut headers);
match resp.parse(b)? {
httparse::Status::Complete(len) => {
let version = if resp.version.unwrap() == 1 {
Version::HTTP_11
} else {
Version::HTTP_10
};
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();
for header in headers[..headers_len].iter() {
2018-03-17 04:56:23 +01:00
let n_start = header.name.as_ptr() as usize - bytes_ptr;
let n_end = n_start + header.name.len();
if let Ok(name) = HeaderName::try_from(slice.slice(n_start, n_end)) {
2018-01-28 07:03:03 +01:00
let v_start = header.value.as_ptr() as usize - bytes_ptr;
let v_end = v_start + header.value.len();
let value = unsafe {
HeaderValue::from_shared_unchecked(slice.slice(v_start, v_end)) };
hdrs.append(name, value);
} else {
return Err(ParseError::Header)
}
}
2018-02-26 22:58:23 +01:00
let decoder = if status == StatusCode::SWITCHING_PROTOCOLS {
Some(Decoder::eof())
} 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>() {
Some(Decoder::length(len))
} else {
debug!("illegal Content-Length: {:?}", len);
return Err(ParseError::Header)
}
} else {
debug!("illegal Content-Length: {:?}", len);
return Err(ParseError::Header)
}
} else if chunked(&hdrs)? {
// Chunked encoding
Some(Decoder::chunked())
} else {
None
};
if let Some(decoder) = decoder {
Ok(Async::Ready(
(ClientResponse::new(
2018-02-26 23:33:56 +01:00
ClientMessage{status, version,
2018-02-19 12:11:11 +01:00
headers: hdrs, cookies: None}), Some(decoder))))
2018-01-28 07:03:03 +01:00
} else {
Ok(Async::Ready(
(ClientResponse::new(
2018-02-26 23:33:56 +01:00
ClientMessage{status, version,
2018-02-19 12:11:11 +01:00
headers: hdrs, cookies: None}), None)))
2018-01-28 07:03:03 +01:00
}
}
}