mirror of
https://github.com/actix/actix-extras.git
synced 2024-11-28 01:32:57 +01:00
simplify h1 codec messages
This commit is contained in:
parent
cb78d9d41a
commit
1407bf4f7f
@ -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
|
Actix http
|
||||||
|
|
||||||
|
@ -32,20 +32,16 @@ pub enum OutMessage {
|
|||||||
/// Http response message
|
/// Http response message
|
||||||
Response(Response),
|
Response(Response),
|
||||||
/// Payload chunk
|
/// Payload chunk
|
||||||
Payload(Option<Binary>),
|
Chunk(Option<Binary>),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Incoming http/1 request
|
/// Incoming http/1 request
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum InMessage {
|
pub enum InMessage {
|
||||||
/// Request
|
/// Request
|
||||||
Message(Request),
|
Message { req: Request, payload: bool },
|
||||||
/// Request with payload
|
|
||||||
MessageWithPayload(Request),
|
|
||||||
/// Payload chunk
|
/// Payload chunk
|
||||||
Chunk(Bytes),
|
Chunk(Option<Bytes>),
|
||||||
/// End of payload
|
|
||||||
Eof,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// HTTP/1 Codec
|
/// HTTP/1 Codec
|
||||||
@ -246,8 +242,8 @@ impl Decoder for Codec {
|
|||||||
fn decode(&mut self, src: &mut BytesMut) -> Result<Option<Self::Item>, Self::Error> {
|
fn decode(&mut self, src: &mut BytesMut) -> Result<Option<Self::Item>, Self::Error> {
|
||||||
if self.payload.is_some() {
|
if self.payload.is_some() {
|
||||||
Ok(match self.payload.as_mut().unwrap().decode(src)? {
|
Ok(match self.payload.as_mut().unwrap().decode(src)? {
|
||||||
Some(PayloadItem::Chunk(chunk)) => Some(InMessage::Chunk(chunk)),
|
Some(PayloadItem::Chunk(chunk)) => Some(InMessage::Chunk(Some(chunk))),
|
||||||
Some(PayloadItem::Eof) => Some(InMessage::Eof),
|
Some(PayloadItem::Eof) => Some(InMessage::Chunk(None)),
|
||||||
None => None,
|
None => None,
|
||||||
})
|
})
|
||||||
} else if let Some((req, payload)) = self.decoder.decode(src)? {
|
} 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.flags.set(Flags::KEEPALIVE, req.keep_alive());
|
||||||
}
|
}
|
||||||
self.payload = payload;
|
self.payload = payload;
|
||||||
if self.payload.is_some() {
|
Ok(Some(InMessage::Message {
|
||||||
Ok(Some(InMessage::MessageWithPayload(req)))
|
req,
|
||||||
} else {
|
payload: self.payload.is_some(),
|
||||||
Ok(Some(InMessage::Message(req)))
|
}))
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
Ok(None)
|
Ok(None)
|
||||||
}
|
}
|
||||||
@ -280,10 +275,10 @@ impl Encoder for Codec {
|
|||||||
OutMessage::Response(res) => {
|
OutMessage::Response(res) => {
|
||||||
self.encode_response(res, dst)?;
|
self.encode_response(res, dst)?;
|
||||||
}
|
}
|
||||||
OutMessage::Payload(Some(bytes)) => {
|
OutMessage::Chunk(Some(bytes)) => {
|
||||||
self.te.encode(bytes.as_ref(), dst)?;
|
self.te.encode(bytes.as_ref(), dst)?;
|
||||||
}
|
}
|
||||||
OutMessage::Payload(None) => {
|
OutMessage::Chunk(None) => {
|
||||||
self.te.encode_eof(dst)?;
|
self.te.encode_eof(dst)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -488,14 +488,13 @@ mod tests {
|
|||||||
impl InMessage {
|
impl InMessage {
|
||||||
fn message(self) -> Request {
|
fn message(self) -> Request {
|
||||||
match self {
|
match self {
|
||||||
InMessage::Message(msg) => msg,
|
InMessage::Message { req, payload: _ } => req,
|
||||||
InMessage::MessageWithPayload(msg) => msg,
|
|
||||||
_ => panic!("error"),
|
_ => panic!("error"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn is_payload(&self) -> bool {
|
fn is_payload(&self) -> bool {
|
||||||
match *self {
|
match *self {
|
||||||
InMessage::MessageWithPayload(_) => true,
|
InMessage::Message { req: _, payload } => payload,
|
||||||
_ => panic!("error"),
|
_ => panic!("error"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -211,7 +211,7 @@ where
|
|||||||
Body::Empty => Some(State::None),
|
Body::Empty => Some(State::None),
|
||||||
Body::Binary(bin) => Some(State::SendPayload(
|
Body::Binary(bin) => Some(State::SendPayload(
|
||||||
None,
|
None,
|
||||||
Some(OutMessage::Payload(bin.into())),
|
Some(OutMessage::Chunk(bin.into())),
|
||||||
)),
|
)),
|
||||||
Body::Streaming(stream) => {
|
Body::Streaming(stream) => {
|
||||||
Some(State::SendPayload(Some(stream), None))
|
Some(State::SendPayload(Some(stream), None))
|
||||||
@ -248,7 +248,7 @@ where
|
|||||||
match stream.poll() {
|
match stream.poll() {
|
||||||
Ok(Async::Ready(Some(item))) => match self
|
Ok(Async::Ready(Some(item))) => match self
|
||||||
.framed
|
.framed
|
||||||
.start_send(OutMessage::Payload(Some(item.into())))
|
.start_send(OutMessage::Chunk(Some(item.into())))
|
||||||
{
|
{
|
||||||
Ok(AsyncSink::Ready) => {
|
Ok(AsyncSink::Ready) => {
|
||||||
self.flags.remove(Flags::FLUSHED);
|
self.flags.remove(Flags::FLUSHED);
|
||||||
@ -262,7 +262,7 @@ where
|
|||||||
},
|
},
|
||||||
Ok(Async::Ready(None)) => Some(State::SendPayload(
|
Ok(Async::Ready(None)) => Some(State::SendPayload(
|
||||||
None,
|
None,
|
||||||
Some(OutMessage::Payload(None)),
|
Some(OutMessage::Chunk(None)),
|
||||||
)),
|
)),
|
||||||
Ok(Async::NotReady) => return Ok(()),
|
Ok(Async::NotReady) => return Ok(()),
|
||||||
// Err(err) => return Err(DispatchError::Io(err)),
|
// Err(err) => return Err(DispatchError::Io(err)),
|
||||||
@ -305,89 +305,85 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Process one incoming message
|
/// Process one incoming requests
|
||||||
fn one_message(&mut self, msg: InMessage) -> Result<(), DispatchError<S::Error>> {
|
pub(self) fn poll_request(&mut self) -> Result<bool, DispatchError<S::Error>> {
|
||||||
self.flags.insert(Flags::STARTED);
|
// limit a mount of non processed requests
|
||||||
|
if self.messages.len() >= MAX_PIPELINED_MESSAGES {
|
||||||
match msg {
|
return Ok(false);
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(self) fn poll_request(&mut self) -> Result<bool, DispatchError<S::Error>> {
|
|
||||||
let mut updated = false;
|
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 {
|
match msg {
|
||||||
'outer: loop {
|
InMessage::Message { req, payload } => {
|
||||||
match self.framed.poll() {
|
if payload {
|
||||||
Ok(Async::Ready(Some(msg))) => {
|
let (ps, pl) = Payload::new(false);
|
||||||
updated = true;
|
*req.inner.payload.borrow_mut() = Some(pl);
|
||||||
self.one_message(msg)?;
|
self.payload = Some(ps);
|
||||||
}
|
}
|
||||||
Ok(Async::Ready(None)) => {
|
|
||||||
self.client_disconnected();
|
// handle request early
|
||||||
break;
|
if self.state.is_empty() {
|
||||||
}
|
self.state = self.handle_request(req)?;
|
||||||
Ok(Async::NotReady) => break,
|
} else {
|
||||||
Err(ParseError::Io(e)) => {
|
self.messages.push_back(Message::Item(req));
|
||||||
self.client_disconnected();
|
}
|
||||||
self.error = Some(DispatchError::Io(e));
|
}
|
||||||
break;
|
InMessage::Chunk(Some(chunk)) => {
|
||||||
}
|
if let Some(ref mut payload) = self.payload {
|
||||||
Err(e) => {
|
payload.feed_data(chunk);
|
||||||
if let Some(mut payload) = self.payload.take() {
|
} else {
|
||||||
payload.set_error(PayloadError::EncodingCorrupted);
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -40,7 +40,7 @@ fn test_simple() {
|
|||||||
.and_then(TakeItem::new().map_err(|_| ()))
|
.and_then(TakeItem::new().map_err(|_| ()))
|
||||||
.and_then(|(req, framed): (_, Framed<_, _>)| {
|
.and_then(|(req, framed): (_, Framed<_, _>)| {
|
||||||
// validate request
|
// validate request
|
||||||
if let Some(h1::InMessage::MessageWithPayload(req)) = req {
|
if let Some(h1::InMessage::Message { req, payload: _ }) = req {
|
||||||
match ws::handshake(&req) {
|
match ws::handshake(&req) {
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
// validation failed
|
// validation failed
|
||||||
|
Loading…
Reference in New Issue
Block a user