diff --git a/examples/client.rs b/examples/client.rs index e728cd6c..b7869489 100644 --- a/examples/client.rs +++ b/examples/client.rs @@ -32,8 +32,8 @@ fn main() { }; let mut res = req - .start().ok().expect("Error writing Headers.") - .send().ok().expect("Error sending Request."); + .start().unwrap() // failure: Error writing Headers + .send().unwrap(); // failure: Error reading Response head. println!("Response: {}", res.status); println!("{}", res.headers); diff --git a/src/client/request.rs b/src/client/request.rs index 396fb7a9..2fc11ea8 100644 --- a/src/client/request.rs +++ b/src/client/request.rs @@ -112,7 +112,6 @@ impl Request { try_io!(write!(self.body, "{} {} {}", self.method, uri, self.version)) try_io!(self.body.write(LINE_ENDING)); - debug!("{}", self.headers); let mut chunked = true; let mut len = 0; @@ -142,10 +141,8 @@ impl Request { } } - for (name, header) in self.headers.iter() { - try_io!(write!(self.body, "{}: {}", name, header)); - try_io!(self.body.write(LINE_ENDING)); - } + debug!("headers [\n{}]", self.headers); + try_io!(write!(self.body, "{}", self.headers)); try_io!(self.body.write(LINE_ENDING)); diff --git a/src/header/mod.rs b/src/header/mod.rs index b726f879..938c41d7 100644 --- a/src/header/mod.rs +++ b/src/header/mod.rs @@ -17,7 +17,7 @@ use std::sync::RWLock; use uany::{UncheckedAnyDowncast, UncheckedAnyMutDowncast}; use typeable::Typeable; -use http::read_header; +use http::{read_header, LineEnding}; use {HttpResult}; /// Common Headers @@ -244,11 +244,10 @@ impl Headers { impl fmt::Show for Headers { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - try!("Headers {\n".fmt(fmt)); for (k, v) in self.iter() { - try!(write!(fmt, "\t{}: {}\n", k, v)); + try!(write!(fmt, "{}: {}{}", k, v, LineEnding)); } - "}".fmt(fmt) + Ok(()) } } @@ -349,7 +348,7 @@ mod tests { use mime::{Mime, Text, Plain}; use super::CaseInsensitive; use super::{Headers, Header}; - use super::common::{ContentLength, ContentType, Accept}; + use super::common::{ContentLength, ContentType, Accept, Host}; fn mem(s: &str) -> MemReader { MemReader::new(s.as_bytes().to_vec()) @@ -443,5 +442,20 @@ mod tests { *headers.get_mut::().unwrap() = ContentLength(20); assert_eq!(*headers.get::().unwrap(), ContentLength(20)); } + + #[test] + fn test_headers_show() { + let mut headers = Headers::new(); + headers.set(ContentLength(15)); + headers.set(Host("foo.bar".into_string())); + + let s = headers.to_string(); + // hashmap's iterators have arbitrary order, so we must sort first + let mut pieces = s[].split_str("\r\n").collect::>(); + pieces.sort(); + let s = pieces.into_iter().rev().collect::>().connect("\r\n"); + assert_eq!(s[], "Host: foo.bar\r\nContent-Length: 15\r\n"); + + } } diff --git a/src/http.rs b/src/http.rs index 31ce12b7..a57d9526 100644 --- a/src/http.rs +++ b/src/http.rs @@ -1,5 +1,6 @@ //! Pieces pertaining to the HTTP message protocol. use std::cmp::min; +use std::fmt; use std::io::{mod, Reader, IoResult}; use std::u16; @@ -211,6 +212,21 @@ pub const LF: u8 = b'\n'; pub const STAR: u8 = b'*'; pub const LINE_ENDING: &'static [u8] = &[CR, LF]; +/// A `Show`able struct to easily write line endings to a formatter. +pub struct LineEnding; + +impl fmt::Show for LineEnding { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fmt.write(LINE_ENDING) + } +} + +impl AsSlice for LineEnding { + fn as_slice(&self) -> &[u8] { + LINE_ENDING + } +} + /// Determines if byte is a token char. /// /// > ```notrust diff --git a/src/server/response.rs b/src/server/response.rs index a6eba9dc..19cdcf24 100644 --- a/src/server/response.rs +++ b/src/server/response.rs @@ -97,11 +97,9 @@ impl Response { } } - for (name, header) in self.headers.iter() { - debug!("header {}: {}", name, header); - try!(write!(self.body, "{}: {}", name, header)); - try!(self.body.write(LINE_ENDING)); - } + + debug!("headers [\n{}]", self.headers); + try!(write!(self.body, "{}", self.headers)); try!(self.body.write(LINE_ENDING));