From f1587243c264af76aa731162687c3ba752b8a42e Mon Sep 17 00:00:00 2001 From: Nikolay Kim Date: Mon, 5 Nov 2018 19:32:03 -0800 Subject: [PATCH] fix body decoding --- Cargo.toml | 1 + src/h1/codec.rs | 63 +++++++++++++++++++++++++++++++++++++++++++- src/h1/decoder.rs | 11 -------- src/h1/dispatcher.rs | 2 ++ src/h1/mod.rs | 29 ++++++++++++++++++++ 5 files changed, 94 insertions(+), 12 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 87e705f7..23499bbf 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -37,6 +37,7 @@ cell = ["actix-net/cell"] [dependencies] actix = "0.7.5" #actix-net = "0.1.1" +#actix-net = { path="../actix-net/" } actix-net = { git="https://github.com/actix/actix-net.git" } base64 = "0.9" diff --git a/src/h1/codec.rs b/src/h1/codec.rs index 7cc516d6..dd1e27e0 100644 --- a/src/h1/codec.rs +++ b/src/h1/codec.rs @@ -42,6 +42,12 @@ pub struct Codec { te: ResponseEncoder, } +impl Default for Codec { + fn default() -> Self { + Codec::new(ServiceConfig::default()) + } +} + impl fmt::Debug for Codec { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "h1::Codec({:?})", self.flags) @@ -247,7 +253,10 @@ impl Decoder for Codec { if self.payload.is_some() { Ok(match self.payload.as_mut().unwrap().decode(src)? { Some(PayloadItem::Chunk(chunk)) => Some(Message::Chunk(Some(chunk))), - Some(PayloadItem::Eof) => Some(Message::Chunk(None)), + Some(PayloadItem::Eof) => { + self.payload.take(); + Some(Message::Chunk(None)) + } None => None, }) } else if self.flags.contains(Flags::UNHANDLED) { @@ -297,3 +306,55 @@ impl Encoder for Codec { Ok(()) } } + +#[cfg(test)] +mod tests { + use std::{cmp, io}; + + use bytes::{Buf, Bytes, BytesMut}; + use http::{Method, Version}; + use tokio_io::{AsyncRead, AsyncWrite}; + + use super::*; + use error::ParseError; + use h1::Message; + use httpmessage::HttpMessage; + use request::Request; + + #[test] + fn test_http_request_chunked_payload_and_next_message() { + let mut codec = Codec::default(); + + let mut buf = BytesMut::from( + "GET /test HTTP/1.1\r\n\ + transfer-encoding: chunked\r\n\r\n", + ); + let item = codec.decode(&mut buf).unwrap().unwrap(); + let req = item.message(); + + assert_eq!(req.method(), Method::GET); + assert!(req.chunked().unwrap()); + + buf.extend( + b"4\r\ndata\r\n4\r\nline\r\n0\r\n\r\n\ + POST /test2 HTTP/1.1\r\n\ + transfer-encoding: chunked\r\n\r\n" + .iter(), + ); + + let msg = codec.decode(&mut buf).unwrap().unwrap(); + assert_eq!(msg.chunk().as_ref(), b"data"); + + let msg = codec.decode(&mut buf).unwrap().unwrap(); + assert_eq!(msg.chunk().as_ref(), b"line"); + + let msg = codec.decode(&mut buf).unwrap().unwrap(); + assert!(msg.eof()); + + // decode next message + let item = codec.decode(&mut buf).unwrap().unwrap(); + let req = item.message(); + assert_eq!(*req.method(), Method::POST); + assert!(req.chunked().unwrap()); + } +} diff --git a/src/h1/decoder.rs b/src/h1/decoder.rs index e8d07af1..cfa0879d 100644 --- a/src/h1/decoder.rs +++ b/src/h1/decoder.rs @@ -648,9 +648,7 @@ mod tests { use super::*; use error::ParseError; - use h1::Message; use httpmessage::HttpMessage; - use request::Request; impl PayloadType { fn unwrap(self) -> PayloadDecoder { @@ -668,15 +666,6 @@ mod tests { } } - impl Message { - fn message(self) -> Request { - match self { - Message::Item(req) => req, - _ => panic!("error"), - } - } - } - impl PayloadItem { fn chunk(self) -> Bytes { match self { diff --git a/src/h1/dispatcher.rs b/src/h1/dispatcher.rs index 513c1961..fb30d881 100644 --- a/src/h1/dispatcher.rs +++ b/src/h1/dispatcher.rs @@ -370,6 +370,7 @@ where Response::InternalServerError().finish(), )); self.error = Some(DispatchError::InternalError); + break; } } Message::Chunk(None) => { @@ -382,6 +383,7 @@ where Response::InternalServerError().finish(), )); self.error = Some(DispatchError::InternalError); + break; } } } diff --git a/src/h1/mod.rs b/src/h1/mod.rs index c33b193f..e7377177 100644 --- a/src/h1/mod.rs +++ b/src/h1/mod.rs @@ -46,3 +46,32 @@ pub enum MessageType { Payload, Unhandled, } + +#[cfg(test)] +mod tests { + use super::*; + + impl Message { + pub fn message(self) -> Request { + match self { + Message::Item(req) => req, + _ => panic!("error"), + } + } + + pub fn chunk(self) -> Bytes { + match self { + Message::Chunk(Some(data)) => data, + _ => panic!("error"), + } + } + + pub fn eof(self) -> bool { + match self { + Message::Chunk(None) => true, + Message::Chunk(Some(_)) => false, + _ => panic!("error"), + } + } + } +}