diff --git a/Cargo.toml b/Cargo.toml index 22b7b13a..0c4d3137 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -67,7 +67,7 @@ ssl = ["openssl", "actix-server/ssl", "awc/ssl"] rust-tls = ["rustls", "actix-server/rust-tls"] [dependencies] -actix-codec = "0.1.1" +actix-codec = "0.1.2" actix-service = "0.3.6" actix-utils = "0.3.4" actix-router = "0.1.2" diff --git a/actix-http/CHANGES.md b/actix-http/CHANGES.md index cca4560c..f5988afa 100644 --- a/actix-http/CHANGES.md +++ b/actix-http/CHANGES.md @@ -6,6 +6,12 @@ * Allow to use custom service for upgrade requests +* Added `h1::SendResponse` future. + +### Changed + +* MessageBody::length() renamed to MessageBody::size() for consistency + ## [0.1.0-alpha.4] - 2019-04-08 diff --git a/actix-http/src/body.rs b/actix-http/src/body.rs index 88b6c492..0652dd27 100644 --- a/actix-http/src/body.rs +++ b/actix-http/src/body.rs @@ -30,13 +30,13 @@ impl BodySize { /// Type that provides this trait can be streamed to a peer. pub trait MessageBody { - fn length(&self) -> BodySize; + fn size(&self) -> BodySize; fn poll_next(&mut self) -> Poll, Error>; } impl MessageBody for () { - fn length(&self) -> BodySize { + fn size(&self) -> BodySize { BodySize::Empty } @@ -46,8 +46,8 @@ impl MessageBody for () { } impl MessageBody for Box { - fn length(&self) -> BodySize { - self.as_ref().length() + fn size(&self) -> BodySize { + self.as_ref().size() } fn poll_next(&mut self) -> Poll, Error> { @@ -86,10 +86,10 @@ impl ResponseBody { } impl MessageBody for ResponseBody { - fn length(&self) -> BodySize { + fn size(&self) -> BodySize { match self { - ResponseBody::Body(ref body) => body.length(), - ResponseBody::Other(ref body) => body.length(), + ResponseBody::Body(ref body) => body.size(), + ResponseBody::Other(ref body) => body.size(), } } @@ -135,12 +135,12 @@ impl Body { } impl MessageBody for Body { - fn length(&self) -> BodySize { + fn size(&self) -> BodySize { match self { Body::None => BodySize::None, Body::Empty => BodySize::Empty, Body::Bytes(ref bin) => BodySize::Sized(bin.len()), - Body::Message(ref body) => body.length(), + Body::Message(ref body) => body.size(), } } @@ -185,7 +185,7 @@ impl fmt::Debug for Body { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { Body::None => write!(f, "Body::None"), - Body::Empty => write!(f, "Body::Zero"), + Body::Empty => write!(f, "Body::Empty"), Body::Bytes(ref b) => write!(f, "Body::Bytes({:?})", b), Body::Message(_) => write!(f, "Body::Message(_)"), } @@ -235,7 +235,7 @@ impl From for Body { } impl MessageBody for Bytes { - fn length(&self) -> BodySize { + fn size(&self) -> BodySize { BodySize::Sized(self.len()) } @@ -249,7 +249,7 @@ impl MessageBody for Bytes { } impl MessageBody for BytesMut { - fn length(&self) -> BodySize { + fn size(&self) -> BodySize { BodySize::Sized(self.len()) } @@ -265,7 +265,7 @@ impl MessageBody for BytesMut { } impl MessageBody for &'static str { - fn length(&self) -> BodySize { + fn size(&self) -> BodySize { BodySize::Sized(self.len()) } @@ -281,7 +281,7 @@ impl MessageBody for &'static str { } impl MessageBody for &'static [u8] { - fn length(&self) -> BodySize { + fn size(&self) -> BodySize { BodySize::Sized(self.len()) } @@ -297,7 +297,7 @@ impl MessageBody for &'static [u8] { } impl MessageBody for Vec { - fn length(&self) -> BodySize { + fn size(&self) -> BodySize { BodySize::Sized(self.len()) } @@ -314,7 +314,7 @@ impl MessageBody for Vec { } impl MessageBody for String { - fn length(&self) -> BodySize { + fn size(&self) -> BodySize { BodySize::Sized(self.len()) } @@ -354,7 +354,7 @@ where S: Stream, E: Into, { - fn length(&self) -> BodySize { + fn size(&self) -> BodySize { BodySize::Stream } @@ -383,7 +383,7 @@ impl MessageBody for SizedStream where S: Stream, { - fn length(&self) -> BodySize { + fn size(&self) -> BodySize { BodySize::Sized(self.size) } @@ -416,47 +416,117 @@ mod tests { #[test] fn test_static_str() { - assert_eq!(Body::from("").length(), BodySize::Sized(0)); - assert_eq!(Body::from("test").length(), BodySize::Sized(4)); + assert_eq!(Body::from("").size(), BodySize::Sized(0)); + assert_eq!(Body::from("test").size(), BodySize::Sized(4)); assert_eq!(Body::from("test").get_ref(), b"test"); + + assert_eq!("test".size(), BodySize::Sized(4)); + assert_eq!( + "test".poll_next().unwrap(), + Async::Ready(Some(Bytes::from("test"))) + ); } #[test] fn test_static_bytes() { - assert_eq!(Body::from(b"test".as_ref()).length(), BodySize::Sized(4)); + assert_eq!(Body::from(b"test".as_ref()).size(), BodySize::Sized(4)); assert_eq!(Body::from(b"test".as_ref()).get_ref(), b"test"); assert_eq!( - Body::from_slice(b"test".as_ref()).length(), + Body::from_slice(b"test".as_ref()).size(), BodySize::Sized(4) ); assert_eq!(Body::from_slice(b"test".as_ref()).get_ref(), b"test"); + + assert_eq!((&b"test"[..]).size(), BodySize::Sized(4)); + assert_eq!( + (&b"test"[..]).poll_next().unwrap(), + Async::Ready(Some(Bytes::from("test"))) + ); } #[test] fn test_vec() { - assert_eq!(Body::from(Vec::from("test")).length(), BodySize::Sized(4)); + assert_eq!(Body::from(Vec::from("test")).size(), BodySize::Sized(4)); assert_eq!(Body::from(Vec::from("test")).get_ref(), b"test"); + + assert_eq!(Vec::from("test").size(), BodySize::Sized(4)); + assert_eq!( + Vec::from("test").poll_next().unwrap(), + Async::Ready(Some(Bytes::from("test"))) + ); } #[test] fn test_bytes() { - assert_eq!(Body::from(Bytes::from("test")).length(), BodySize::Sized(4)); - assert_eq!(Body::from(Bytes::from("test")).get_ref(), b"test"); - } - - #[test] - fn test_string() { - let b = "test".to_owned(); - assert_eq!(Body::from(b.clone()).length(), BodySize::Sized(4)); + let mut b = Bytes::from("test"); + assert_eq!(Body::from(b.clone()).size(), BodySize::Sized(4)); assert_eq!(Body::from(b.clone()).get_ref(), b"test"); - assert_eq!(Body::from(&b).length(), BodySize::Sized(4)); - assert_eq!(Body::from(&b).get_ref(), b"test"); + + assert_eq!(b.size(), BodySize::Sized(4)); + assert_eq!( + b.poll_next().unwrap(), + Async::Ready(Some(Bytes::from("test"))) + ); } #[test] fn test_bytes_mut() { - let b = BytesMut::from("test"); - assert_eq!(Body::from(b.clone()).length(), BodySize::Sized(4)); - assert_eq!(Body::from(b).get_ref(), b"test"); + let mut b = BytesMut::from("test"); + assert_eq!(Body::from(b.clone()).size(), BodySize::Sized(4)); + assert_eq!(Body::from(b.clone()).get_ref(), b"test"); + + assert_eq!(b.size(), BodySize::Sized(4)); + assert_eq!( + b.poll_next().unwrap(), + Async::Ready(Some(Bytes::from("test"))) + ); + } + + #[test] + fn test_string() { + let mut b = "test".to_owned(); + assert_eq!(Body::from(b.clone()).size(), BodySize::Sized(4)); + assert_eq!(Body::from(b.clone()).get_ref(), b"test"); + assert_eq!(Body::from(&b).size(), BodySize::Sized(4)); + assert_eq!(Body::from(&b).get_ref(), b"test"); + + assert_eq!(b.size(), BodySize::Sized(4)); + assert_eq!( + b.poll_next().unwrap(), + Async::Ready(Some(Bytes::from("test"))) + ); + } + + #[test] + fn test_unit() { + assert_eq!(().size(), BodySize::Empty); + assert_eq!(().poll_next().unwrap(), Async::Ready(None)); + } + + #[test] + fn test_box() { + let mut val = Box::new(()); + assert_eq!(val.size(), BodySize::Empty); + assert_eq!(val.poll_next().unwrap(), Async::Ready(None)); + } + + #[test] + fn test_body_eq() { + assert!(Body::None == Body::None); + assert!(Body::None != Body::Empty); + assert!(Body::Empty == Body::Empty); + assert!(Body::Empty != Body::None); + assert!( + Body::Bytes(Bytes::from_static(b"1")) + == Body::Bytes(Bytes::from_static(b"1")) + ); + assert!(Body::Bytes(Bytes::from_static(b"1")) != Body::None); + } + + #[test] + fn test_body_debug() { + assert!(format!("{:?}", Body::None).contains("Body::None")); + assert!(format!("{:?}", Body::Empty).contains("Body::Empty")); + assert!(format!("{:?}", Body::Bytes(Bytes::from_static(b"1"))).contains("1")); } } diff --git a/actix-http/src/client/h1proto.rs b/actix-http/src/client/h1proto.rs index 3a8b119d..becc0752 100644 --- a/actix-http/src/client/h1proto.rs +++ b/actix-http/src/client/h1proto.rs @@ -55,14 +55,14 @@ where io: Some(io), }; - let len = body.length(); + let len = body.size(); // create Framed and send reqest Framed::new(io, h1::ClientCodec::default()) .send((head, len).into()) .from_err() // send request body - .and_then(move |framed| match body.length() { + .and_then(move |framed| match body.size() { BodySize::None | BodySize::Empty | BodySize::Sized(0) => { Either::A(ok(framed)) } diff --git a/actix-http/src/client/h2proto.rs b/actix-http/src/client/h2proto.rs index ec5beee6..91240268 100644 --- a/actix-http/src/client/h2proto.rs +++ b/actix-http/src/client/h2proto.rs @@ -27,9 +27,9 @@ where T: AsyncRead + AsyncWrite + 'static, B: MessageBody, { - trace!("Sending client request: {:?} {:?}", head, body.length()); + trace!("Sending client request: {:?} {:?}", head, body.size()); let head_req = head.method == Method::HEAD; - let length = body.length(); + let length = body.size(); let eof = match length { BodySize::None | BodySize::Empty | BodySize::Sized(0) => true, _ => false, diff --git a/actix-http/src/encoding/encoder.rs b/actix-http/src/encoding/encoder.rs index 6537379f..aabce292 100644 --- a/actix-http/src/encoding/encoder.rs +++ b/actix-http/src/encoding/encoder.rs @@ -79,12 +79,12 @@ enum EncoderBody { } impl MessageBody for Encoder { - fn length(&self) -> BodySize { + fn size(&self) -> BodySize { if self.encoder.is_none() { match self.body { - EncoderBody::Bytes(ref b) => b.length(), - EncoderBody::Stream(ref b) => b.length(), - EncoderBody::BoxedStream(ref b) => b.length(), + EncoderBody::Bytes(ref b) => b.size(), + EncoderBody::Stream(ref b) => b.size(), + EncoderBody::BoxedStream(ref b) => b.size(), } } else { BodySize::Stream diff --git a/actix-http/src/h1/dispatcher.rs b/actix-http/src/h1/dispatcher.rs index 8c0af007..cca181c9 100644 --- a/actix-http/src/h1/dispatcher.rs +++ b/actix-http/src/h1/dispatcher.rs @@ -320,7 +320,7 @@ where body: ResponseBody, ) -> Result, DispatchError> { self.codec - .encode(Message::Item((message, body.length())), &mut self.write_buf) + .encode(Message::Item((message, body.size())), &mut self.write_buf) .map_err(|err| { if let Some(mut payload) = self.payload.take() { payload.set_error(PayloadError::Incomplete(None)); @@ -329,7 +329,7 @@ where })?; self.flags.set(Flags::KEEPALIVE, self.codec.keepalive()); - match body.length() { + match body.size() { BodySize::None | BodySize::Empty => Ok(State::None), _ => Ok(State::SendPayload(body)), } diff --git a/actix-http/src/h1/mod.rs b/actix-http/src/h1/mod.rs index 58712278..0c85f076 100644 --- a/actix-http/src/h1/mod.rs +++ b/actix-http/src/h1/mod.rs @@ -10,6 +10,7 @@ mod expect; mod payload; mod service; mod upgrade; +mod utils; pub use self::client::{ClientCodec, ClientPayloadCodec}; pub use self::codec::Codec; @@ -18,6 +19,7 @@ pub use self::expect::ExpectHandler; pub use self::payload::Payload; pub use self::service::{H1Service, H1ServiceHandler, OneRequest}; pub use self::upgrade::UpgradeHandler; +pub use self::utils::SendResponse; #[derive(Debug)] /// Codec message diff --git a/actix-http/src/h1/utils.rs b/actix-http/src/h1/utils.rs new file mode 100644 index 00000000..fdc4cf0b --- /dev/null +++ b/actix-http/src/h1/utils.rs @@ -0,0 +1,92 @@ +use actix_codec::{AsyncRead, AsyncWrite, Framed}; +use futures::{Async, Future, Poll, Sink}; + +use crate::body::{BodySize, MessageBody, ResponseBody}; +use crate::error::Error; +use crate::h1::{Codec, Message}; +use crate::response::Response; + +/// Send http/1 response +pub struct SendResponse { + res: Option, BodySize)>>, + body: Option>, + framed: Option>, +} + +impl SendResponse +where + B: MessageBody, +{ + pub fn new(framed: Framed, response: Response) -> Self { + let (res, body) = response.into_parts(); + + SendResponse { + res: Some((res, body.size()).into()), + body: Some(body), + framed: Some(framed), + } + } +} + +impl Future for SendResponse +where + T: AsyncRead + AsyncWrite, + B: MessageBody, +{ + type Item = Framed; + type Error = Error; + + fn poll(&mut self) -> Poll { + loop { + let mut body_ready = self.body.is_some(); + let framed = self.framed.as_mut().unwrap(); + + // send body + if self.res.is_none() && self.body.is_some() { + while body_ready && self.body.is_some() && !framed.is_write_buf_full() { + match self.body.as_mut().unwrap().poll_next()? { + Async::Ready(item) => { + // body is done + if item.is_none() { + let _ = self.body.take(); + } + framed.force_send(Message::Chunk(item))?; + } + Async::NotReady => body_ready = false, + } + } + } + + // flush write buffer + if !framed.is_write_buf_empty() { + match framed.poll_complete()? { + Async::Ready(_) => { + if body_ready { + continue; + } else { + return Ok(Async::NotReady); + } + } + Async::NotReady => return Ok(Async::NotReady), + } + } + + // send response + if let Some(res) = self.res.take() { + framed.force_send(res)?; + continue; + } + + if self.body.is_some() { + if body_ready { + continue; + } else { + return Ok(Async::NotReady); + } + } else { + break; + } + } + Ok(Async::Ready(self.framed.take().unwrap())) + } +} diff --git a/actix-http/src/h2/dispatcher.rs b/actix-http/src/h2/dispatcher.rs index cbb74f60..de0b761f 100644 --- a/actix-http/src/h2/dispatcher.rs +++ b/actix-http/src/h2/dispatcher.rs @@ -153,10 +153,10 @@ where fn prepare_response( &self, head: &ResponseHead, - length: &mut BodySize, + size: &mut BodySize, ) -> http::Response<()> { let mut has_date = false; - let mut skip_len = length != &BodySize::Stream; + let mut skip_len = size != &BodySize::Stream; let mut res = http::Response::new(()); *res.status_mut() = head.status; @@ -166,14 +166,14 @@ where match head.status { http::StatusCode::NO_CONTENT | http::StatusCode::CONTINUE - | http::StatusCode::PROCESSING => *length = BodySize::None, + | http::StatusCode::PROCESSING => *size = BodySize::None, http::StatusCode::SWITCHING_PROTOCOLS => { skip_len = true; - *length = BodySize::Stream; + *size = BodySize::Stream; } _ => (), } - let _ = match length { + let _ = match size { BodySize::None | BodySize::Stream => None, BodySize::Empty => res .headers_mut() @@ -229,16 +229,15 @@ where let (res, body) = res.into().replace_body(()); let mut send = send.take().unwrap(); - let mut length = body.length(); - let h2_res = self.prepare_response(res.head(), &mut length); + let mut size = body.size(); + let h2_res = self.prepare_response(res.head(), &mut size); - let stream = send - .send_response(h2_res, length.is_eof()) - .map_err(|e| { + let stream = + send.send_response(h2_res, size.is_eof()).map_err(|e| { trace!("Error sending h2 response: {:?}", e); })?; - if length.is_eof() { + if size.is_eof() { Ok(Async::Ready(())) } else { self.state = ServiceResponseState::SendPayload(stream, body); @@ -251,16 +250,15 @@ where let (res, body) = res.replace_body(()); let mut send = send.take().unwrap(); - let mut length = body.length(); - let h2_res = self.prepare_response(res.head(), &mut length); + let mut size = body.size(); + let h2_res = self.prepare_response(res.head(), &mut size); - let stream = send - .send_response(h2_res, length.is_eof()) - .map_err(|e| { + let stream = + send.send_response(h2_res, size.is_eof()).map_err(|e| { trace!("Error sending h2 response: {:?}", e); })?; - if length.is_eof() { + if size.is_eof() { Ok(Async::Ready(())) } else { self.state = ServiceResponseState::SendPayload( diff --git a/actix-http/src/response.rs b/actix-http/src/response.rs index 330d33a4..95e4e789 100644 --- a/actix-http/src/response.rs +++ b/actix-http/src/response.rs @@ -210,6 +210,18 @@ impl Response { } } + /// Split response and body + pub fn into_parts(self) -> (Response<()>, ResponseBody) { + ( + Response { + head: self.head, + body: ResponseBody::Body(()), + error: self.error, + }, + self.body, + ) + } + /// Drop request's body pub fn drop_body(self) -> Response<()> { Response { @@ -264,7 +276,7 @@ impl fmt::Debug for Response { for (key, val) in self.head.headers.iter() { let _ = writeln!(f, " {:?}: {:?}", key, val); } - let _ = writeln!(f, " body: {:?}", self.body.length()); + let _ = writeln!(f, " body: {:?}", self.body.size()); res } } diff --git a/actix-web-codegen/src/route.rs b/actix-web-codegen/src/route.rs index 588debf8..e1a870db 100644 --- a/actix-web-codegen/src/route.rs +++ b/actix-web-codegen/src/route.rs @@ -3,7 +3,7 @@ extern crate proc_macro; use std::fmt; use proc_macro::TokenStream; -use quote::{quote}; +use quote::quote; enum ResourceType { Async, @@ -51,9 +51,13 @@ impl fmt::Display for Args { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let ast = &self.ast; let guards = format!(".guard(actix_web::guard::{}())", self.guard); - let guards = self.extra_guards.iter().fold(guards, |acc, val| format!("{}.guard(actix_web::guard::fn_guard({}))", acc, val)); + let guards = self.extra_guards.iter().fold(guards, |acc, val| { + format!("{}.guard(actix_web::guard::fn_guard({}))", acc, val) + }); - write!(f, " + write!( + f, + " #[allow(non_camel_case_types)] pub struct {name}; @@ -65,7 +69,13 @@ impl actix_web::dev::HttpServiceFactory

for {name} {{ actix_web::dev::HttpServiceFactory::register(resource, config) }} -}}", name=self.name, ast=quote!(#ast), path=self.path, guards=guards, to=self.resource_type) +}}", + name = self.name, + ast = quote!(#ast), + path = self.path, + guards = guards, + to = self.resource_type + ) } } @@ -73,33 +83,41 @@ fn guess_resource_type(typ: &syn::Type) -> ResourceType { let mut guess = ResourceType::Sync; match typ { - syn::Type::ImplTrait(typ) => for bound in typ.bounds.iter() { - match bound { - syn::TypeParamBound::Trait(bound) => { - for bound in bound.path.segments.iter() { - if bound.ident == "Future" { - guess = ResourceType::Async; - break; - } else if bound.ident == "Responder" { - guess = ResourceType::Sync; - break; + syn::Type::ImplTrait(typ) => { + for bound in typ.bounds.iter() { + match bound { + syn::TypeParamBound::Trait(bound) => { + for bound in bound.path.segments.iter() { + if bound.ident == "Future" { + guess = ResourceType::Async; + break; + } else if bound.ident == "Responder" { + guess = ResourceType::Sync; + break; + } } } - }, - _ => (), + _ => (), + } } - }, + } _ => (), } guess - } impl Args { - pub fn new(args: &Vec, input: TokenStream, guard: GuardType) -> Self { + pub fn new( + args: &Vec, + input: TokenStream, + guard: GuardType, + ) -> Self { if args.is_empty() { - panic!("invalid server definition, expected: #[{}(\"some path\")]", guard); + panic!( + "invalid server definition, expected: #[{}(\"some path\")]", + guard + ); } let ast: syn::ItemFn = syn::parse(input).expect("Parse input as function"); @@ -115,15 +133,20 @@ impl Args { } let fname = quote!(#fname).to_string(); path = Some(fname.as_str()[1..fname.len() - 1].to_owned()) - }, - syn::NestedMeta::Meta(syn::Meta::NameValue(ident)) => match ident.ident.to_string().to_lowercase().as_str() { - "guard" => match ident.lit { - syn::Lit::Str(ref text) => extra_guards.push(text.value()), - _ => panic!("Attribute guard expects literal string!"), - }, - attr => panic!("Unknown attribute key is specified: {}. Allowed: guard", attr) - }, - attr => panic!("Unknown attribute{:?}", attr) + } + syn::NestedMeta::Meta(syn::Meta::NameValue(ident)) => { + match ident.ident.to_string().to_lowercase().as_str() { + "guard" => match ident.lit { + syn::Lit::Str(ref text) => extra_guards.push(text.value()), + _ => panic!("Attribute guard expects literal string!"), + }, + attr => panic!( + "Unknown attribute key is specified: {}. Allowed: guard", + attr + ), + } + } + attr => panic!("Unknown attribute{:?}", attr), } } @@ -131,7 +154,9 @@ impl Args { ResourceType::Async } else { match ast.decl.output { - syn::ReturnType::Default => panic!("Function {} has no return type. Cannot be used as handler"), + syn::ReturnType::Default => { + panic!("Function {} has no return type. Cannot be used as handler") + } syn::ReturnType::Type(_, ref typ) => guess_resource_type(typ.as_ref()), } }; @@ -153,7 +178,7 @@ impl Args { match text.parse() { Ok(res) => res, - Err(error) => panic!("Error: {:?}\nGenerated code: {}", error, text) + Err(error) => panic!("Error: {:?}\nGenerated code: {}", error, text), } } } diff --git a/actix-web-codegen/tests/test_macro.rs b/actix-web-codegen/tests/test_macro.rs index b028f012..c27eefde 100644 --- a/actix-web-codegen/tests/test_macro.rs +++ b/actix-web-codegen/tests/test_macro.rs @@ -1,8 +1,8 @@ use actix_http::HttpService; use actix_http_test::TestServer; -use actix_web_codegen::get; use actix_web::{http, App, HttpResponse, Responder}; -use futures::{Future, future}; +use actix_web_codegen::get; +use futures::{future, Future}; //fn guard_head(head: &actix_web::dev::RequestHead) -> bool { // true @@ -15,16 +15,15 @@ fn test() -> impl Responder { } #[get("/test")] -fn auto_async() -> impl Future { +fn auto_async() -> impl Future { future::ok(HttpResponse::Ok().finish()) } #[get("/test")] -fn auto_sync() -> impl Future { +fn auto_sync() -> impl Future { future::ok(HttpResponse::Ok().finish()) } - #[test] fn test_body() { let mut srv = TestServer::new(|| HttpService::new(App::new().service(test))); diff --git a/src/middleware/logger.rs b/src/middleware/logger.rs index aaf38138..66ca150b 100644 --- a/src/middleware/logger.rs +++ b/src/middleware/logger.rs @@ -241,8 +241,8 @@ impl Drop for StreamLog { } impl MessageBody for StreamLog { - fn length(&self) -> BodySize { - self.body.length() + fn size(&self) -> BodySize { + self.body.size() } fn poll_next(&mut self) -> Poll, Error> { diff --git a/src/service.rs b/src/service.rs index f0ff0215..01875854 100644 --- a/src/service.rs +++ b/src/service.rs @@ -360,7 +360,7 @@ impl fmt::Debug for ServiceResponse { for (key, val) in self.response.head().headers.iter() { let _ = writeln!(f, " {:?}: {:?}", key, val); } - let _ = writeln!(f, " body: {:?}", self.response.body().length()); + let _ = writeln!(f, " body: {:?}", self.response.body().size()); res } }