From d645ca681baf96684e74765ee53f4d62530fafbc Mon Sep 17 00:00:00 2001 From: Flavio Percoco Date: Sun, 6 Oct 2013 01:20:17 +0200 Subject: [PATCH] Implement `send` method to send content along with the request --- src/examples/client/client.rs | 42 ++++++++++++++++++++++++++++++----- src/libhttp/client/request.rs | 33 ++++++++++++++++++++++++--- 2 files changed, 66 insertions(+), 9 deletions(-) diff --git a/src/examples/client/client.rs b/src/examples/client/client.rs index 2e453fe..608e9f0 100644 --- a/src/examples/client/client.rs +++ b/src/examples/client/client.rs @@ -1,20 +1,19 @@ extern mod http; use http::client::RequestWriter; -use http::method::Get; +use http::method::{Get, Post}; use http::headers::HeaderEnum; use std::str; use std::rt::io::extensions::ReaderUtil; -use std::rt::io::net::ip::{SocketAddr, Ipv4Addr}; -fn main() { - let mut request = ~RequestWriter::new(Get, FromStr::from_str("http://localhost/example") +fn get_request() { + let request = ~RequestWriter::new(Get, FromStr::from_str("http://httpbin.org/get") .expect("Uh oh, that's *really* badly broken!")); - // Temporary measure, as hostname lookup is not yet supported in std::rt::io. - request.remote_addr = Some(SocketAddr { ip: Ipv4Addr(127, 0, 0, 1), port: 8001 }); + let mut response = match request.read_response() { Ok(response) => response, Err(_request) => fail!("This example can progress no further with no response :-("), }; + println("Yay! Started to get the response."); println!("Status: {}", response.status); println("Headers:"); @@ -25,3 +24,34 @@ fn main() { println("Response:"); println(str::from_utf8(response.read_to_end())); } + + +fn post_request() { + let mut request = ~RequestWriter::new(Post, FromStr::from_str("http://httpbin.org/post") + .expect("Uh oh, that's *really* badly broken!")); + + request.send(bytes!("Post It!")); + + let mut response = match request.read_response() { + Ok(response) => response, + Err(_request) => fail!("This example can progress no further with no response :-("), + }; + + println("Yay! Started to get the response."); + println!("Status: {}", response.status); + println("Headers:"); + for header in response.headers.iter() { + println!(" - {}: {}", header.header_name(), header.header_value()); + } + + print("\n"); + println("Response:"); + println(str::from_utf8(response.read_to_end())); +} + +fn main() { + + get_request(); + + post_request(); +} diff --git a/src/libhttp/client/request.rs b/src/libhttp/client/request.rs index e9ee9ae..8ad13be 100644 --- a/src/libhttp/client/request.rs +++ b/src/libhttp/client/request.rs @@ -166,10 +166,33 @@ impl RequestWriter { let s = format!("{} {} HTTP/1.0\r\n", self.method.to_str(), self.url.to_str()); self.stream.write(s.as_bytes()); + // `write_all` adds '\r\n' at the end, no + // need to terminate the headers section + // here. self.headers.write_all(&mut self.stream); self.headers_written = true; } + /// Send data to the remote server. + /// This method appends Content-Length + /// to headers and sends them. If headers + /// where already sent, it will send data + /// without the Content-Length. + // TODO: Implement chunked request, perhaps + // in a `send_chunked` method. + pub fn send(&mut self, buf: &[u8]) { + + // NOTE: Should we make this fail? + // If 'Content-Length' is not sent + // some servers won't read the request + // body. + if !self.headers_written { + self.headers.content_length = Some(buf.len()); + self.write_headers(); + } + self.write(buf); + } + // FIXME: ~self rather than self to work around a Rust bug in by-val self at present leading to // a segfault on calling construct(). pub fn read_response(~self) -> Result, ~RequestWriter> { @@ -185,9 +208,13 @@ impl RequestWriter { impl Writer for RequestWriter { fn write(&mut self, buf: &[u8]) { - if (!self.headers_written) { - self.write_headers(); - } + // No data must be sent before + // sending headers. Let's make + // sure that's the case. + self.try_write_headers(); + + // Now we're good to send + // some data. self.stream.write(buf); }