implementation
This commit is contained in:
106
src/client/request.rs
Normal file
106
src/client/request.rs
Normal file
@@ -0,0 +1,106 @@
|
||||
//! # Client Requests
|
||||
use std::io::net::tcp::TcpStream;
|
||||
use std::io::IoResult;
|
||||
|
||||
use url::Url;
|
||||
|
||||
use method;
|
||||
use header::{Headers, Host};
|
||||
use rfc7230::LINE_ENDING;
|
||||
use version;
|
||||
use {HttpResult, HttpUriError};
|
||||
use super::{Response};
|
||||
|
||||
|
||||
/// A client request to a remote server.
|
||||
pub struct Request {
|
||||
/// The method of this request.
|
||||
pub method: method::Method,
|
||||
/// The headers that will be sent with this request.
|
||||
pub headers: Headers,
|
||||
/// The target URI for this request.
|
||||
pub url: Url,
|
||||
/// The HTTP version of this request.
|
||||
pub version: version::HttpVersion,
|
||||
headers_written: bool,
|
||||
body: TcpStream,
|
||||
}
|
||||
|
||||
impl Request {
|
||||
|
||||
/// Create a new client request.
|
||||
pub fn new(method: method::Method, url: Url) -> HttpResult<Request> {
|
||||
debug!("{} {}", method, url);
|
||||
let host = match url.serialize_host() {
|
||||
Some(host) => host,
|
||||
None => return Err(HttpUriError)
|
||||
};
|
||||
debug!("host={}", host);
|
||||
let port = match url.port_or_default() {
|
||||
Some(port) => port,
|
||||
None => return Err(HttpUriError)
|
||||
};
|
||||
debug!("port={}", port);
|
||||
|
||||
let stream = try_io!(TcpStream::connect(host.as_slice(), port));
|
||||
let mut headers = Headers::new();
|
||||
headers.set(Host(host));
|
||||
Ok(Request {
|
||||
method: method,
|
||||
headers: headers,
|
||||
url: url,
|
||||
version: version::Http11,
|
||||
headers_written: false,
|
||||
body: stream
|
||||
})
|
||||
}
|
||||
|
||||
fn write_head(&mut self) -> IoResult<()> {
|
||||
if self.headers_written {
|
||||
debug!("headers previsouly written, nooping");
|
||||
return Ok(());
|
||||
}
|
||||
self.headers_written = true;
|
||||
|
||||
let uri = self.url.serialize_path().unwrap();
|
||||
debug!("writing head: {} {} {}", self.method, uri, self.version);
|
||||
try!(write!(self.body, "{} {} {}", self.method, uri, self.version))
|
||||
try!(self.body.write(LINE_ENDING));
|
||||
|
||||
debug!("{}", self.headers);
|
||||
|
||||
for (name, header) in self.headers.iter() {
|
||||
try!(write!(self.body, "{}: {}", name, header));
|
||||
try!(self.body.write(LINE_ENDING));
|
||||
}
|
||||
|
||||
self.body.write(LINE_ENDING)
|
||||
}
|
||||
|
||||
/// Completes writing the request, and returns a response to read from.
|
||||
///
|
||||
/// Consumes the Request.
|
||||
pub fn send(mut self) -> HttpResult<Response> {
|
||||
try_io!(self.flush());
|
||||
try_io!(self.body.close_write());
|
||||
Response::new(self.body)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
impl Writer for Request {
|
||||
fn write(&mut self, msg: &[u8]) -> IoResult<()> {
|
||||
if !self.headers_written {
|
||||
try!(self.write_head());
|
||||
}
|
||||
self.body.write(msg)
|
||||
}
|
||||
|
||||
fn flush(&mut self) -> IoResult<()> {
|
||||
if !self.headers_written {
|
||||
try!(self.write_head());
|
||||
}
|
||||
self.body.flush()
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user