@@ -1,118 +1,7 @@
|
|||||||
pub use self::decode::Decoder;
|
pub use self::decode::Decoder;
|
||||||
pub use self::encode::Encoder;
|
pub use self::encode::Encoder;
|
||||||
|
|
||||||
pub use self::parse::parse;
|
|
||||||
|
|
||||||
mod decode;
|
mod decode;
|
||||||
mod encode;
|
mod encode;
|
||||||
pub mod parse;
|
pub mod parse;
|
||||||
|
|
||||||
/*
|
|
||||||
fn should_have_response_body(method: &Method, status: u16) -> bool {
|
|
||||||
trace!("should_have_response_body({:?}, {})", method, status);
|
|
||||||
match (method, status) {
|
|
||||||
(&Method::Head, _) |
|
|
||||||
(_, 100...199) |
|
|
||||||
(_, 204) |
|
|
||||||
(_, 304) |
|
|
||||||
(&Method::Connect, 200...299) => false,
|
|
||||||
_ => true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
/*
|
|
||||||
const MAX_INVALID_RESPONSE_BYTES: usize = 1024 * 128;
|
|
||||||
impl HttpMessage for Http11Message {
|
|
||||||
|
|
||||||
fn get_incoming(&mut self) -> ::Result<ResponseHead> {
|
|
||||||
unimplemented!();
|
|
||||||
/*
|
|
||||||
try!(self.flush_outgoing());
|
|
||||||
let stream = match self.stream.take() {
|
|
||||||
Some(stream) => stream,
|
|
||||||
None => {
|
|
||||||
// The message was already in the reading state...
|
|
||||||
// TODO Decide what happens in case we try to get a new incoming at that point
|
|
||||||
return Err(From::from(
|
|
||||||
io::Error::new(io::ErrorKind::Other,
|
|
||||||
"Read already in progress")));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let expected_no_content = stream.previous_response_expected_no_content();
|
|
||||||
trace!("previous_response_expected_no_content = {}", expected_no_content);
|
|
||||||
|
|
||||||
let mut stream = BufReader::new(stream);
|
|
||||||
|
|
||||||
let mut invalid_bytes_read = 0;
|
|
||||||
let head;
|
|
||||||
loop {
|
|
||||||
head = match parse_response(&mut stream) {
|
|
||||||
Ok(head) => head,
|
|
||||||
Err(::Error::Version)
|
|
||||||
if expected_no_content && invalid_bytes_read < MAX_INVALID_RESPONSE_BYTES => {
|
|
||||||
trace!("expected_no_content, found content");
|
|
||||||
invalid_bytes_read += 1;
|
|
||||||
stream.consume(1);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
Err(e) => {
|
|
||||||
self.stream = Some(stream.into_inner());
|
|
||||||
return Err(e);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
let raw_status = head.subject;
|
|
||||||
let headers = head.headers;
|
|
||||||
|
|
||||||
let method = self.method.take().unwrap_or(Method::Get);
|
|
||||||
|
|
||||||
let is_empty = !should_have_response_body(&method, raw_status.0);
|
|
||||||
stream.get_mut().set_previous_response_expected_no_content(is_empty);
|
|
||||||
// According to https://tools.ietf.org/html/rfc7230#section-3.3.3
|
|
||||||
// 1. HEAD responses, and Status 1xx, 204, and 304 cannot have a body.
|
|
||||||
// 2. Status 2xx to a CONNECT cannot have a body.
|
|
||||||
// 3. Transfer-Encoding: chunked has a chunked body.
|
|
||||||
// 4. If multiple differing Content-Length headers or invalid, close connection.
|
|
||||||
// 5. Content-Length header has a sized body.
|
|
||||||
// 6. Not Client.
|
|
||||||
// 7. Read till EOF.
|
|
||||||
self.reader = Some(if is_empty {
|
|
||||||
SizedReader(stream, 0)
|
|
||||||
} else {
|
|
||||||
if let Some(&TransferEncoding(ref codings)) = headers.get() {
|
|
||||||
if codings.last() == Some(&Chunked) {
|
|
||||||
ChunkedReader(stream, None)
|
|
||||||
} else {
|
|
||||||
trace!("not chunked. read till eof");
|
|
||||||
EofReader(stream)
|
|
||||||
}
|
|
||||||
} else if let Some(&ContentLength(len)) = headers.get() {
|
|
||||||
SizedReader(stream, len)
|
|
||||||
} else if headers.has::<ContentLength>() {
|
|
||||||
trace!("illegal Content-Length: {:?}", headers.get_raw("Content-Length"));
|
|
||||||
return Err(Error::Header);
|
|
||||||
} else {
|
|
||||||
trace!("neither Transfer-Encoding nor Content-Length");
|
|
||||||
EofReader(stream)
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
trace!("Http11Message.reader = {:?}", self.reader);
|
|
||||||
|
|
||||||
|
|
||||||
Ok(ResponseHead {
|
|
||||||
headers: headers,
|
|
||||||
raw_status: raw_status,
|
|
||||||
version: head.version,
|
|
||||||
})
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -15,19 +15,15 @@ use version::HttpVersion::{Http10, Http11};
|
|||||||
const MAX_HEADERS: usize = 100;
|
const MAX_HEADERS: usize = 100;
|
||||||
const AVERAGE_HEADER_SIZE: usize = 30; // totally scientific
|
const AVERAGE_HEADER_SIZE: usize = 30; // totally scientific
|
||||||
|
|
||||||
pub fn parse<T: Http1Transaction<Incoming=I>, I>(buf: &mut BytesMut) -> ParseResult<I> {
|
|
||||||
if buf.len() == 0 {
|
|
||||||
return Ok(None);
|
|
||||||
}
|
|
||||||
trace!("parse({:?})", buf);
|
|
||||||
<T as Http1Transaction>::parse(buf)
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Http1Transaction for ServerTransaction {
|
impl Http1Transaction for ServerTransaction {
|
||||||
type Incoming = RequestLine;
|
type Incoming = RequestLine;
|
||||||
type Outgoing = StatusCode;
|
type Outgoing = StatusCode;
|
||||||
|
|
||||||
fn parse(buf: &mut BytesMut) -> ParseResult<RequestLine> {
|
fn parse(buf: &mut BytesMut) -> ParseResult<RequestLine> {
|
||||||
|
if buf.len() == 0 {
|
||||||
|
return Ok(None);
|
||||||
|
}
|
||||||
|
trace!("parse({:?})", buf);
|
||||||
let mut headers_indices = [HeaderIndices {
|
let mut headers_indices = [HeaderIndices {
|
||||||
name: (0, 0),
|
name: (0, 0),
|
||||||
value: (0, 0)
|
value: (0, 0)
|
||||||
@@ -145,6 +141,10 @@ impl Http1Transaction for ClientTransaction {
|
|||||||
type Outgoing = RequestLine;
|
type Outgoing = RequestLine;
|
||||||
|
|
||||||
fn parse(buf: &mut BytesMut) -> ParseResult<RawStatus> {
|
fn parse(buf: &mut BytesMut) -> ParseResult<RawStatus> {
|
||||||
|
if buf.len() == 0 {
|
||||||
|
return Ok(None);
|
||||||
|
}
|
||||||
|
trace!("parse({:?})", buf);
|
||||||
let mut headers_indices = [HeaderIndices {
|
let mut headers_indices = [HeaderIndices {
|
||||||
name: (0, 0),
|
name: (0, 0),
|
||||||
value: (0, 0)
|
value: (0, 0)
|
||||||
@@ -332,9 +332,8 @@ fn extend(dst: &mut Vec<u8>, data: &[u8]) {
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use http;
|
use http::{ServerTransaction, ClientTransaction, Http1Transaction};
|
||||||
use bytes::BytesMut;
|
use bytes::BytesMut;
|
||||||
use super::{parse};
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_parse_request() {
|
fn test_parse_request() {
|
||||||
@@ -342,7 +341,7 @@ mod tests {
|
|||||||
let _ = pretty_env_logger::init();
|
let _ = pretty_env_logger::init();
|
||||||
let mut raw = BytesMut::from(b"GET /echo HTTP/1.1\r\nHost: hyper.rs\r\n\r\n".to_vec());
|
let mut raw = BytesMut::from(b"GET /echo HTTP/1.1\r\nHost: hyper.rs\r\n\r\n".to_vec());
|
||||||
let expected_len = raw.len();
|
let expected_len = raw.len();
|
||||||
let (req, len) = parse::<http::ServerTransaction, _>(&mut raw).unwrap().unwrap();
|
let (req, len) = ServerTransaction::parse(&mut raw).unwrap().unwrap();
|
||||||
assert_eq!(len, expected_len);
|
assert_eq!(len, expected_len);
|
||||||
assert_eq!(req.subject.0, ::Method::Get);
|
assert_eq!(req.subject.0, ::Method::Get);
|
||||||
assert_eq!(req.subject.1, "/echo");
|
assert_eq!(req.subject.1, "/echo");
|
||||||
@@ -358,7 +357,7 @@ mod tests {
|
|||||||
let _ = pretty_env_logger::init();
|
let _ = pretty_env_logger::init();
|
||||||
let mut raw = BytesMut::from(b"HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n".to_vec());
|
let mut raw = BytesMut::from(b"HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n".to_vec());
|
||||||
let expected_len = raw.len();
|
let expected_len = raw.len();
|
||||||
let (req, len) = parse::<http::ClientTransaction, _>(&mut raw).unwrap().unwrap();
|
let (req, len) = ClientTransaction::parse(&mut raw).unwrap().unwrap();
|
||||||
assert_eq!(len, expected_len);
|
assert_eq!(len, expected_len);
|
||||||
assert_eq!(req.subject.0, 200);
|
assert_eq!(req.subject.0, 200);
|
||||||
assert_eq!(req.subject.1, "OK");
|
assert_eq!(req.subject.1, "OK");
|
||||||
@@ -370,16 +369,16 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_parse_request_errors() {
|
fn test_parse_request_errors() {
|
||||||
let mut raw = BytesMut::from(b"GET htt:p// HTTP/1.1\r\nHost: hyper.rs\r\n\r\n".to_vec());
|
let mut raw = BytesMut::from(b"GET htt:p// HTTP/1.1\r\nHost: hyper.rs\r\n\r\n".to_vec());
|
||||||
parse::<http::ServerTransaction, _>(&mut raw).unwrap_err();
|
ServerTransaction::parse(&mut raw).unwrap_err();
|
||||||
}
|
}
|
||||||
#[test]
|
#[test]
|
||||||
fn test_parse_raw_status() {
|
fn test_parse_raw_status() {
|
||||||
let mut raw = BytesMut::from(b"HTTP/1.1 200 OK\r\n\r\n".to_vec());
|
let mut raw = BytesMut::from(b"HTTP/1.1 200 OK\r\n\r\n".to_vec());
|
||||||
let (res, _) = parse::<http::ClientTransaction, _>(&mut raw).unwrap().unwrap();
|
let (res, _) = ClientTransaction::parse(&mut raw).unwrap().unwrap();
|
||||||
assert_eq!(res.subject.1, "OK");
|
assert_eq!(res.subject.1, "OK");
|
||||||
|
|
||||||
let mut raw = BytesMut::from(b"HTTP/1.1 200 Howdy\r\n\r\n".to_vec());
|
let mut raw = BytesMut::from(b"HTTP/1.1 200 Howdy\r\n\r\n".to_vec());
|
||||||
let (res, _) = parse::<http::ClientTransaction, _>(&mut raw).unwrap().unwrap();
|
let (res, _) = ClientTransaction::parse(&mut raw).unwrap().unwrap();
|
||||||
assert_eq!(res.subject.1, "Howdy");
|
assert_eq!(res.subject.1, "Howdy");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -412,7 +411,7 @@ mod tests {
|
|||||||
|
|
||||||
b.bytes = len as u64;
|
b.bytes = len as u64;
|
||||||
b.iter(|| {
|
b.iter(|| {
|
||||||
parse::<http::ServerTransaction, _>(&mut raw).unwrap();
|
ServerTransaction::parse(&mut raw).unwrap();
|
||||||
restart(&mut raw, len);
|
restart(&mut raw, len);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ use std::ptr;
|
|||||||
|
|
||||||
use tokio_io::{AsyncRead, AsyncWrite};
|
use tokio_io::{AsyncRead, AsyncWrite};
|
||||||
|
|
||||||
use http::{Http1Transaction, h1, MessageHead, ParseResult, DebugTruncate};
|
use http::{Http1Transaction, MessageHead, DebugTruncate};
|
||||||
use bytes::{BytesMut, Bytes};
|
use bytes::{BytesMut, Bytes};
|
||||||
|
|
||||||
const INIT_BUFFER_SIZE: usize = 8192;
|
const INIT_BUFFER_SIZE: usize = 8192;
|
||||||
@@ -56,7 +56,7 @@ impl<T: AsyncRead + AsyncWrite> Buffered<T> {
|
|||||||
|
|
||||||
pub fn parse<S: Http1Transaction>(&mut self) -> ::Result<Option<MessageHead<S::Incoming>>> {
|
pub fn parse<S: Http1Transaction>(&mut self) -> ::Result<Option<MessageHead<S::Incoming>>> {
|
||||||
loop {
|
loop {
|
||||||
match try!(parse::<S, _>(&mut self.read_buf)) {
|
match try!(S::parse(&mut self.read_buf)) {
|
||||||
Some(head) => {
|
Some(head) => {
|
||||||
//trace!("parsed {} bytes out of {}", len, self.read_buf.len());
|
//trace!("parsed {} bytes out of {}", len, self.read_buf.len());
|
||||||
return Ok(Some(head.0))
|
return Ok(Some(head.0))
|
||||||
@@ -68,7 +68,6 @@ impl<T: AsyncRead + AsyncWrite> Buffered<T> {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
self.reserve_read_buf();
|
|
||||||
match self.read_from_io() {
|
match self.read_from_io() {
|
||||||
Ok(0) => {
|
Ok(0) => {
|
||||||
trace!("parse eof");
|
trace!("parse eof");
|
||||||
@@ -88,8 +87,17 @@ impl<T: AsyncRead + AsyncWrite> Buffered<T> {
|
|||||||
|
|
||||||
fn read_from_io(&mut self) -> io::Result<usize> {
|
fn read_from_io(&mut self) -> io::Result<usize> {
|
||||||
use bytes::BufMut;
|
use bytes::BufMut;
|
||||||
|
// TODO: Investigate if we still need these unsafe blocks
|
||||||
|
if self.read_buf.remaining_mut() < INIT_BUFFER_SIZE {
|
||||||
|
self.read_buf.reserve(INIT_BUFFER_SIZE);
|
||||||
|
unsafe { // Zero out unused memory
|
||||||
|
let buf = self.read_buf.bytes_mut();
|
||||||
|
let len = buf.len();
|
||||||
|
ptr::write_bytes(buf.as_mut_ptr(), 0, len);
|
||||||
|
}
|
||||||
|
}
|
||||||
self.read_blocked = false;
|
self.read_blocked = false;
|
||||||
unsafe {
|
unsafe { // Can we use AsyncRead::read_buf instead?
|
||||||
let n = match self.io.read(self.read_buf.bytes_mut()) {
|
let n = match self.io.read(self.read_buf.bytes_mut()) {
|
||||||
Ok(n) => n,
|
Ok(n) => n,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
@@ -104,19 +112,6 @@ impl<T: AsyncRead + AsyncWrite> Buffered<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn reserve_read_buf(&mut self) {
|
|
||||||
use bytes::BufMut;
|
|
||||||
if self.read_buf.remaining_mut() >= INIT_BUFFER_SIZE {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
self.read_buf.reserve(INIT_BUFFER_SIZE);
|
|
||||||
unsafe {
|
|
||||||
let buf = self.read_buf.bytes_mut();
|
|
||||||
let len = buf.len();
|
|
||||||
ptr::write_bytes(buf.as_mut_ptr(), 0, len);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn buffer<B: AsRef<[u8]>>(&mut self, buf: B) -> usize {
|
pub fn buffer<B: AsRef<[u8]>>(&mut self, buf: B) -> usize {
|
||||||
self.write_buf.buffer(buf.as_ref())
|
self.write_buf.buffer(buf.as_ref())
|
||||||
}
|
}
|
||||||
@@ -151,10 +146,6 @@ impl<T: Write> Write for Buffered<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse<T: Http1Transaction<Incoming=I>, I>(rdr: &mut BytesMut) -> ParseResult<I> {
|
|
||||||
h1::parse::<T, I>(rdr)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait MemRead {
|
pub trait MemRead {
|
||||||
fn read_mem(&mut self, len: usize) -> io::Result<Bytes>;
|
fn read_mem(&mut self, len: usize) -> io::Result<Bytes>;
|
||||||
}
|
}
|
||||||
@@ -167,7 +158,6 @@ impl<T: AsyncRead + AsyncWrite> MemRead for Buffered<T> {
|
|||||||
trace!("Buffered.read_mem read_buf is not empty, slicing {}", n);
|
trace!("Buffered.read_mem read_buf is not empty, slicing {}", n);
|
||||||
Ok(self.read_buf.split_to(n).freeze())
|
Ok(self.read_buf.split_to(n).freeze())
|
||||||
} else {
|
} else {
|
||||||
self.reserve_read_buf();
|
|
||||||
let n = try!(self.read_from_io());
|
let n = try!(self.read_from_io());
|
||||||
Ok(self.read_buf.split_to(::std::cmp::min(len, n)).freeze())
|
Ok(self.read_buf.split_to(::std::cmp::min(len, n)).freeze())
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user