1
0
Fork 0
mirror of https://github.com/actix/actix-web.git synced 2024-06-02 21:39:26 +00:00

simplify h1 codec messages

This commit is contained in:
Nikolay Kim 2018-10-09 10:36:40 -07:00
parent cb78d9d41a
commit 1407bf4f7f
5 changed files with 90 additions and 100 deletions

View file

@ -1,4 +1,4 @@
# Actix http [![Build Status](https://travis-ci.org/fafhrd91/actix-http.svg?branch=master)](https://travis-ci.org/fafhrd91/actix-http) [![Build status](https://ci.appveyor.com/api/projects/status/kkdb4yce7qhm5w85/branch/master?svg=true)](https://ci.appveyor.com/project/fafhrd91/actix-web-hdy9d/branch/master) [![codecov](https://codecov.io/gh/fafhrd91/actix-http/branch/master/graph/badge.svg)](https://codecov.io/gh/fafhrd91/actix-http) [![crates.io](https://meritbadge.herokuapp.com/actix-web)](https://crates.io/crates/actix-web) [![Join the chat at https://gitter.im/actix/actix](https://badges.gitter.im/actix/actix.svg)](https://gitter.im/actix/actix?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
# Actix http [![Build Status](https://travis-ci.org/fafhrd91/actix-http.svg?branch=master)](https://travis-ci.org/fafhrd91/actix-http) [![Build status](https://ci.appveyor.com/api/projects/status/bwq6923pblqg55gk/branch/master?svg=true)](https://ci.appveyor.com/project/fafhrd91/actix-http/branch/master) [![codecov](https://codecov.io/gh/fafhrd91/actix-http/branch/master/graph/badge.svg)](https://codecov.io/gh/fafhrd91/actix-http) [![crates.io](https://meritbadge.herokuapp.com/actix-web)](https://crates.io/crates/actix-web) [![Join the chat at https://gitter.im/actix/actix](https://badges.gitter.im/actix/actix.svg)](https://gitter.im/actix/actix?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
Actix http

View file

@ -32,20 +32,16 @@ pub enum OutMessage {
/// Http response message
Response(Response),
/// Payload chunk
Payload(Option<Binary>),
Chunk(Option<Binary>),
}
/// Incoming http/1 request
#[derive(Debug)]
pub enum InMessage {
/// Request
Message(Request),
/// Request with payload
MessageWithPayload(Request),
Message { req: Request, payload: bool },
/// Payload chunk
Chunk(Bytes),
/// End of payload
Eof,
Chunk(Option<Bytes>),
}
/// HTTP/1 Codec
@ -246,8 +242,8 @@ impl Decoder for Codec {
fn decode(&mut self, src: &mut BytesMut) -> Result<Option<Self::Item>, Self::Error> {
if self.payload.is_some() {
Ok(match self.payload.as_mut().unwrap().decode(src)? {
Some(PayloadItem::Chunk(chunk)) => Some(InMessage::Chunk(chunk)),
Some(PayloadItem::Eof) => Some(InMessage::Eof),
Some(PayloadItem::Chunk(chunk)) => Some(InMessage::Chunk(Some(chunk))),
Some(PayloadItem::Eof) => Some(InMessage::Chunk(None)),
None => None,
})
} else if let Some((req, payload)) = self.decoder.decode(src)? {
@ -258,11 +254,10 @@ impl Decoder for Codec {
self.flags.set(Flags::KEEPALIVE, req.keep_alive());
}
self.payload = payload;
if self.payload.is_some() {
Ok(Some(InMessage::MessageWithPayload(req)))
} else {
Ok(Some(InMessage::Message(req)))
}
Ok(Some(InMessage::Message {
req,
payload: self.payload.is_some(),
}))
} else {
Ok(None)
}
@ -280,10 +275,10 @@ impl Encoder for Codec {
OutMessage::Response(res) => {
self.encode_response(res, dst)?;
}
OutMessage::Payload(Some(bytes)) => {
OutMessage::Chunk(Some(bytes)) => {
self.te.encode(bytes.as_ref(), dst)?;
}
OutMessage::Payload(None) => {
OutMessage::Chunk(None) => {
self.te.encode_eof(dst)?;
}
}

View file

@ -488,14 +488,13 @@ mod tests {
impl InMessage {
fn message(self) -> Request {
match self {
InMessage::Message(msg) => msg,
InMessage::MessageWithPayload(msg) => msg,
InMessage::Message { req, payload: _ } => req,
_ => panic!("error"),
}
}
fn is_payload(&self) -> bool {
match *self {
InMessage::MessageWithPayload(_) => true,
InMessage::Message { req: _, payload } => payload,
_ => panic!("error"),
}
}

View file

@ -211,7 +211,7 @@ where
Body::Empty => Some(State::None),
Body::Binary(bin) => Some(State::SendPayload(
None,
Some(OutMessage::Payload(bin.into())),
Some(OutMessage::Chunk(bin.into())),
)),
Body::Streaming(stream) => {
Some(State::SendPayload(Some(stream), None))
@ -248,7 +248,7 @@ where
match stream.poll() {
Ok(Async::Ready(Some(item))) => match self
.framed
.start_send(OutMessage::Payload(Some(item.into())))
.start_send(OutMessage::Chunk(Some(item.into())))
{
Ok(AsyncSink::Ready) => {
self.flags.remove(Flags::FLUSHED);
@ -262,7 +262,7 @@ where
},
Ok(Async::Ready(None)) => Some(State::SendPayload(
None,
Some(OutMessage::Payload(None)),
Some(OutMessage::Chunk(None)),
)),
Ok(Async::NotReady) => return Ok(()),
// Err(err) => return Err(DispatchError::Io(err)),
@ -305,89 +305,85 @@ where
}
}
/// Process one incoming message
fn one_message(&mut self, msg: InMessage) -> Result<(), DispatchError<S::Error>> {
self.flags.insert(Flags::STARTED);
match msg {
InMessage::Message(msg) => {
// handle request early
if self.state.is_empty() {
self.state = self.handle_request(msg)?;
} else {
self.messages.push_back(Message::Item(msg));
}
}
InMessage::MessageWithPayload(msg) => {
// payload
let (ps, pl) = Payload::new(false);
*msg.inner.payload.borrow_mut() = Some(pl);
self.payload = Some(ps);
self.messages.push_back(Message::Item(msg));
}
InMessage::Chunk(chunk) => {
if let Some(ref mut payload) = self.payload {
payload.feed_data(chunk);
} else {
error!("Internal server error: unexpected payload chunk");
self.flags.insert(Flags::DISCONNECTED);
self.messages.push_back(Message::Error(
Response::InternalServerError().finish(),
));
self.error = Some(DispatchError::InternalError);
}
}
InMessage::Eof => {
if let Some(mut payload) = self.payload.take() {
payload.feed_eof();
} else {
error!("Internal server error: unexpected eof");
self.flags.insert(Flags::DISCONNECTED);
self.messages.push_back(Message::Error(
Response::InternalServerError().finish(),
));
self.error = Some(DispatchError::InternalError);
}
}
/// Process one incoming requests
pub(self) fn poll_request(&mut self) -> Result<bool, DispatchError<S::Error>> {
// limit a mount of non processed requests
if self.messages.len() >= MAX_PIPELINED_MESSAGES {
return Ok(false);
}
Ok(())
}
pub(self) fn poll_request(&mut self) -> Result<bool, DispatchError<S::Error>> {
let mut updated = false;
'outer: loop {
match self.framed.poll() {
Ok(Async::Ready(Some(msg))) => {
updated = true;
self.flags.insert(Flags::STARTED);
if self.messages.len() < MAX_PIPELINED_MESSAGES {
'outer: loop {
match self.framed.poll() {
Ok(Async::Ready(Some(msg))) => {
updated = true;
self.one_message(msg)?;
}
Ok(Async::Ready(None)) => {
self.client_disconnected();
break;
}
Ok(Async::NotReady) => break,
Err(ParseError::Io(e)) => {
self.client_disconnected();
self.error = Some(DispatchError::Io(e));
break;
}
Err(e) => {
if let Some(mut payload) = self.payload.take() {
payload.set_error(PayloadError::EncodingCorrupted);
match msg {
InMessage::Message { req, payload } => {
if payload {
let (ps, pl) = Payload::new(false);
*req.inner.payload.borrow_mut() = Some(pl);
self.payload = Some(ps);
}
// handle request early
if self.state.is_empty() {
self.state = self.handle_request(req)?;
} else {
self.messages.push_back(Message::Item(req));
}
}
InMessage::Chunk(Some(chunk)) => {
if let Some(ref mut payload) = self.payload {
payload.feed_data(chunk);
} else {
error!(
"Internal server error: unexpected payload chunk"
);
self.flags.insert(Flags::DISCONNECTED);
self.messages.push_back(Message::Error(
Response::InternalServerError().finish(),
));
self.error = Some(DispatchError::InternalError);
}
}
InMessage::Chunk(None) => {
if let Some(mut payload) = self.payload.take() {
payload.feed_eof();
} else {
error!("Internal server error: unexpected eof");
self.flags.insert(Flags::DISCONNECTED);
self.messages.push_back(Message::Error(
Response::InternalServerError().finish(),
));
self.error = Some(DispatchError::InternalError);
}
}
// Malformed requests should be responded with 400
self.messages
.push_back(Message::Error(Response::BadRequest().finish()));
self.flags.insert(Flags::DISCONNECTED);
self.error = Some(e.into());
break;
}
}
Ok(Async::Ready(None)) => {
self.client_disconnected();
break;
}
Ok(Async::NotReady) => break,
Err(ParseError::Io(e)) => {
self.client_disconnected();
self.error = Some(DispatchError::Io(e));
break;
}
Err(e) => {
if let Some(mut payload) = self.payload.take() {
payload.set_error(PayloadError::EncodingCorrupted);
}
// Malformed requests should be responded with 400
self.messages
.push_back(Message::Error(Response::BadRequest().finish()));
self.flags.insert(Flags::DISCONNECTED);
self.error = Some(e.into());
break;
}
}
}

View file

@ -40,7 +40,7 @@ fn test_simple() {
.and_then(TakeItem::new().map_err(|_| ()))
.and_then(|(req, framed): (_, Framed<_, _>)| {
// validate request
if let Some(h1::InMessage::MessageWithPayload(req)) = req {
if let Some(h1::InMessage::Message { req, payload: _ }) = req {
match ws::handshake(&req) {
Err(e) => {
// validation failed