diff --git a/core/lib/src/response/mod.rs b/core/lib/src/response/mod.rs index 82b26a3dc5..44ec2e2efe 100644 --- a/core/lib/src/response/mod.rs +++ b/core/lib/src/response/mod.rs @@ -30,7 +30,6 @@ crate mod flash; pub mod content; pub mod status; -pub mod writable; pub use self::response::{Response, ResponseBuilder, Body, DEFAULT_CHUNK_SIZE}; pub use self::responder::Responder; @@ -38,8 +37,6 @@ pub use self::redirect::Redirect; pub use self::flash::Flash; pub use self::named_file::NamedFile; pub use self::stream::Stream; -pub use self::writable::Writable; - #[doc(inline)] pub use self::content::Content; /// Type alias for the `Result` of a `Responder::respond` call. diff --git a/core/lib/src/response/response.rs b/core/lib/src/response/response.rs index fb5c186be3..bb081e6e3f 100644 --- a/core/lib/src/response/response.rs +++ b/core/lib/src/response/response.rs @@ -1,9 +1,8 @@ -use http::{ContentType, Cookie, Header, HeaderMap, Status}; -use request::Request; -use response::Responder; -use std::{fmt, io, str}; +use std::{io, fmt, str}; use std::borrow::Cow; -use super::writable::Writable; + +use response::Responder; +use http::{Header, HeaderMap, Status, ContentType, Cookie}; /// The default size, in bytes, of a chunk for streamed responses. pub const DEFAULT_CHUNK_SIZE: u64 = 4096; @@ -60,13 +59,13 @@ impl Body { } } -impl Body { +impl Body { /// Attempts to read `self` into a `Vec` and returns it. If reading fails, /// returns `None`. pub fn into_bytes(self) -> Option> { let mut vec = Vec::new(); let mut body = self.into_inner(); - if let Err(e) = body.write(Box::new(&mut vec)) { + if let Err(e) = body.read_to_end(&mut vec) { error_!("Error reading body: {:?}", e); return None; } @@ -351,7 +350,7 @@ impl<'r> ResponseBuilder<'r> { /// ``` #[inline(always)] pub fn sized_body(&mut self, body: B) -> &mut ResponseBuilder<'r> - where B: Writable + io::Seek + 'r + where B: io::Read + io::Seek + 'r { self.response.set_sized_body(body); self @@ -377,7 +376,7 @@ impl<'r> ResponseBuilder<'r> { /// ``` #[inline(always)] pub fn streamed_body(&mut self, body: B) -> &mut ResponseBuilder<'r> - where B: Writable + 'r + where B: io::Read + 'r { self.response.set_streamed_body(body); self @@ -403,8 +402,8 @@ impl<'r> ResponseBuilder<'r> { /// # } /// ``` #[inline(always)] - pub fn chunked_body(&mut self, body: B, chunk_size: u64) - -> &mut ResponseBuilder<'r> + pub fn chunked_body(&mut self, body: B, chunk_size: u64) + -> &mut ResponseBuilder<'r> { self.response.set_chunked_body(body, chunk_size); self @@ -426,8 +425,8 @@ impl<'r> ResponseBuilder<'r> { /// .finalize(); /// ``` #[inline(always)] - pub fn raw_body(&mut self, body: Body) - -> &mut ResponseBuilder<'r> + pub fn raw_body(&mut self, body: Body) + -> &mut ResponseBuilder<'r> { self.response.set_raw_body(body); self @@ -561,7 +560,7 @@ impl<'r> ResponseBuilder<'r> { pub struct Response<'r> { status: Option, headers: HeaderMap<'r>, - body: Option>>, + body: Option>>, } impl<'r> Response<'r> { @@ -890,7 +889,7 @@ impl<'r> Response<'r> { /// assert_eq!(response.body_string(), Some("Hello, world!".to_string())); /// ``` #[inline(always)] - pub fn body(&mut self) -> Option> { + pub fn body(&mut self) -> Option> { // Looks crazy, right? Needed so Rust infers lifetime correctly. Weird. match self.body.as_mut() { Some(body) => Some(match body.as_mut() { @@ -967,7 +966,7 @@ impl<'r> Response<'r> { /// assert!(response.body().is_none()); /// ``` #[inline(always)] - pub fn take_body(&mut self) -> Option>> { + pub fn take_body(&mut self) -> Option>> { self.body.take() } @@ -1005,7 +1004,7 @@ impl<'r> Response<'r> { /// ``` #[inline] pub fn set_sized_body(&mut self, mut body: B) - where B: Writable + io::Seek + 'r + where B: io::Read + io::Seek + 'r { let size = body.seek(io::SeekFrom::End(0)) .expect("Attempted to retrieve size by seeking, but failed."); @@ -1030,7 +1029,7 @@ impl<'r> Response<'r> { /// assert_eq!(response.body_string(), Some("aaaaa".to_string())); /// ``` #[inline(always)] - pub fn set_streamed_body(&mut self, body: B) where B: Writable + 'r { + pub fn set_streamed_body(&mut self, body: B) where B: io::Read + 'r { self.set_chunked_body(body, DEFAULT_CHUNK_SIZE); } @@ -1049,7 +1048,7 @@ impl<'r> Response<'r> { /// ``` #[inline(always)] pub fn set_chunked_body(&mut self, body: B, chunk_size: u64) - where B: Writable + 'r { + where B: io::Read + 'r { self.body = Some(Body::Chunked(Box::new(body), chunk_size)); } @@ -1071,7 +1070,7 @@ impl<'r> Response<'r> { /// assert_eq!(response.body_string(), Some("Hello!".to_string())); /// ``` #[inline(always)] - pub fn set_raw_body(&mut self, body: Body) { + pub fn set_raw_body(&mut self, body: Body) { self.body = Some(match body { Body::Sized(b, n) => Body::Sized(Box::new(b.take(n)), n), Body::Chunked(b, n) => Body::Chunked(Box::new(b), n), @@ -1192,6 +1191,8 @@ impl<'r> fmt::Debug for Response<'r> { } } +use request::Request; + impl<'r> Responder<'r> for Response<'r> { /// This is the identity implementation. It simply returns `Ok(self)`. fn respond_to(self, _: &Request) -> Result, Status> { diff --git a/core/lib/src/response/stream.rs b/core/lib/src/response/stream.rs index 583efa670a..58293d5977 100644 --- a/core/lib/src/response/stream.rs +++ b/core/lib/src/response/stream.rs @@ -1,8 +1,8 @@ +use std::io::Read; use std::fmt::{self, Debug}; use request::Request; use response::{Response, Responder, DEFAULT_CHUNK_SIZE}; -use response::Writable; use http::Status; /// Streams a response to a client from an arbitrary `Read`er type. @@ -11,9 +11,9 @@ use http::Status; /// 4KiB. This means that at most 4KiB are stored in memory while the response /// is being sent. This type should be used when sending responses that are /// arbitrarily large in size, such as when streaming from a local socket. -pub struct Stream(T, u64); +pub struct Stream(T, u64); -impl Stream { +impl Stream { /// Create a new stream from the given `reader` and sets the chunk size for /// each streamed chunk to `chunk_size` bytes. /// @@ -34,7 +34,7 @@ impl Stream { } } -impl Debug for Stream { +impl Debug for Stream { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "Stream({:?})", self.0) } @@ -54,7 +54,7 @@ impl Debug for Stream { /// # #[allow(unused_variables)] /// let response = Stream::from(io::stdin()); /// ``` -impl From for Stream { +impl From for Stream { fn from(reader: T) -> Self { Stream(reader, DEFAULT_CHUNK_SIZE) } @@ -68,7 +68,7 @@ impl From for Stream { /// If reading from the input stream fails at any point during the response, the /// response is abandoned, and the response ends abruptly. An error is printed /// to the console with an indication of what went wrong. -impl<'r, T: Writable + 'r> Responder<'r> for Stream { +impl<'r, T: Read + 'r> Responder<'r> for Stream { fn respond_to(self, _: &Request) -> Result, Status> { Response::build().chunked_body(self.0, self.1).ok() } diff --git a/core/lib/src/response/writable.rs b/core/lib/src/response/writable.rs deleted file mode 100644 index 5b8ffb65dd..0000000000 --- a/core/lib/src/response/writable.rs +++ /dev/null @@ -1,57 +0,0 @@ -use std::io::{copy, Read, Result, Write}; - -/// Trait implemented by types that can be written to an io::Writer -pub trait Writable { - /// Write the object to the given writer - fn write<'r>( - &mut self, - // The box is needed in order to make the function callable from a trait object (E0038) - destination: Box<&mut (Write + 'r)>, - ) -> Result<()>; - - /// Write the object to the given writer, with a `chunk_size` hint - /// indicating the preferred number of bytes to write at a time. - /// - /// The default implementation ignores the chunk_size. - fn write_chunked<'r>( - &mut self, - destination: Box<&mut (Write + 'r)>, - chunk_size: usize, - ) -> Result<()> { - self.write(destination) - } - - /// Return a new writable that writes only the first `size` bytes of the current object - fn take(self, size: usize) -> Take - where Self: Sized { - Take { source: self, size } - } -} - -impl Writable for T { - fn write<'r>(&mut self, destination: Box<&mut (Write + 'r)>) -> Result<()> { - copy(self, &mut *destination).map(|_size| ()) - } - - fn write_chunked<'r>(&mut self, destination: Box<&mut (Write + 'r)>, chunk_size: usize) -> Result<()> { - let mut buffer = vec![0u8; chunk_size]; - loop { - match self.read(&mut buffer)? { - 0 => break, - n => { (*destination).write(&buffer[..n]); } - } - } - Ok(()) - } -} - -/// The first n bytes of a writable -struct Take { source: W, size: usize } - -impl Writable for Take { - fn write<'r>(&mut self, destination: Box<&mut (Write + 'r)>) -> Result<()> { - let mut buffer = vec![0u8; self.size]; - self.source.write(&mut buffer)?; - (*destination).write_all(&mut buffer) - } -} \ No newline at end of file diff --git a/core/lib/src/rocket.rs b/core/lib/src/rocket.rs index 13559a395e..70b7be058b 100644 --- a/core/lib/src/rocket.rs +++ b/core/lib/src/rocket.rs @@ -145,7 +145,7 @@ impl Rocket { Some(Body::Sized(body, size)) => { hyp_res.headers_mut().set(header::ContentLength(size)); let mut stream = hyp_res.start()?; - body.write(Box::new(&mut stream))?; + io::copy(body, &mut stream)?; stream.end() } Some(Body::Chunked(mut body, chunk_size)) => { @@ -158,7 +158,13 @@ impl Rocket { // The buffer stores the current chunk being written out. let mut buffer = vec![0; chunk_size as usize]; let mut stream = hyp_res.start()?; - body.write_chunked(Box::new(&mut stream), chunk_size as usize); + loop { + match body.read_max(&mut buffer)? { + 0 => break, + n => stream.write_all(&buffer[..n])?, + } + } + stream.end() } } @@ -801,4 +807,4 @@ impl Rocket { pub fn config(&self) -> &Config { &self.config } -} \ No newline at end of file +}