Abstract out NetworkStream
This introduces a new Trait, NetworkStream, which abstracts over the functionality provided by TcpStream so that it can be easily mocked and extended in testing and hyper can be used for other connection sources.
This commit is contained in:
committed by
Jonathan Reem
parent
a8d7b681da
commit
0285fc2acc
@@ -1,5 +1,4 @@
|
||||
//! Client Requests
|
||||
use std::io::net::tcp::TcpStream;
|
||||
use std::io::{BufferedWriter, IoResult};
|
||||
|
||||
use url::Url;
|
||||
@@ -7,6 +6,7 @@ use url::Url;
|
||||
use method;
|
||||
use header::Headers;
|
||||
use header::common::Host;
|
||||
use net::{NetworkStream, HttpStream};
|
||||
use rfc7230::LINE_ENDING;
|
||||
use version;
|
||||
use {HttpResult, HttpUriError};
|
||||
@@ -14,7 +14,7 @@ use super::{Response};
|
||||
|
||||
|
||||
/// A client request to a remote server.
|
||||
pub struct Request {
|
||||
pub struct Request<S = HttpStream> {
|
||||
/// The method of this request.
|
||||
pub method: method::Method,
|
||||
/// The headers that will be sent with this request.
|
||||
@@ -24,13 +24,13 @@ pub struct Request {
|
||||
/// The HTTP version of this request.
|
||||
pub version: version::HttpVersion,
|
||||
headers_written: bool,
|
||||
body: BufferedWriter<TcpStream>,
|
||||
body: BufferedWriter<S>,
|
||||
}
|
||||
|
||||
impl Request {
|
||||
impl<S: NetworkStream> Request<S> {
|
||||
|
||||
/// Create a new client request.
|
||||
pub fn new(method: method::Method, url: Url) -> HttpResult<Request> {
|
||||
pub fn new(method: method::Method, url: Url) -> HttpResult<Request<S>> {
|
||||
debug!("{} {}", method, url);
|
||||
let host = match url.serialize_host() {
|
||||
Some(host) => host,
|
||||
@@ -43,7 +43,7 @@ impl Request {
|
||||
};
|
||||
debug!("port={}", port);
|
||||
|
||||
let stream = try_io!(TcpStream::connect(host.as_slice(), port));
|
||||
let stream = try_io!(NetworkStream::connect(host.as_slice(), port));
|
||||
let stream = BufferedWriter::new(stream);
|
||||
let mut headers = Headers::new();
|
||||
headers.set(Host(host));
|
||||
@@ -82,16 +82,15 @@ impl Request {
|
||||
/// Completes writing the request, and returns a response to read from.
|
||||
///
|
||||
/// Consumes the Request.
|
||||
pub fn send(mut self) -> HttpResult<Response> {
|
||||
pub fn send(mut self) -> HttpResult<Response<S>> {
|
||||
try_io!(self.flush());
|
||||
let mut raw = self.body.unwrap();
|
||||
try_io!(raw.close_write());
|
||||
let raw = self.body.unwrap();
|
||||
Response::new(raw)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
impl Writer for Request {
|
||||
impl<S: NetworkStream> Writer for Request<S> {
|
||||
fn write(&mut self, msg: &[u8]) -> IoResult<()> {
|
||||
if !self.headers_written {
|
||||
try!(self.write_head());
|
||||
|
||||
@@ -1,33 +1,33 @@
|
||||
//! Client Responses
|
||||
use std::io::{BufferedReader, IoResult};
|
||||
use std::io::net::tcp::TcpStream;
|
||||
|
||||
use header;
|
||||
use header::common::{ContentLength, TransferEncoding};
|
||||
use header::common::transfer_encoding::Chunked;
|
||||
use net::{NetworkStream, HttpStream};
|
||||
use rfc7230::{read_status_line, HttpReader, SizedReader, ChunkedReader, EofReader};
|
||||
use status;
|
||||
use version;
|
||||
use {HttpResult};
|
||||
|
||||
/// A response for a client request to a remote server.
|
||||
pub struct Response {
|
||||
pub struct Response<S = HttpStream> {
|
||||
/// The status from the server.
|
||||
pub status: status::StatusCode,
|
||||
/// The headers from the server.
|
||||
pub headers: header::Headers,
|
||||
/// The HTTP version of this response from the server.
|
||||
pub version: version::HttpVersion,
|
||||
body: HttpReader<BufferedReader<TcpStream>>,
|
||||
body: HttpReader<BufferedReader<S>>,
|
||||
}
|
||||
|
||||
impl Response {
|
||||
impl<S: NetworkStream> Response<S> {
|
||||
|
||||
/// Creates a new response from a server.
|
||||
pub fn new(tcp: TcpStream) -> HttpResult<Response> {
|
||||
let mut tcp = BufferedReader::new(tcp);
|
||||
let (version, status) = try!(read_status_line(&mut tcp));
|
||||
let mut headers = try!(header::Headers::from_raw(&mut tcp));
|
||||
pub fn new(stream: S) -> HttpResult<Response<S>> {
|
||||
let mut stream = BufferedReader::new(stream);
|
||||
let (version, status) = try!(read_status_line(&mut stream));
|
||||
let mut headers = try!(header::Headers::from_raw(&mut stream));
|
||||
|
||||
debug!("{} {}", version, status);
|
||||
debug!("{}", headers);
|
||||
@@ -40,22 +40,22 @@ impl Response {
|
||||
};
|
||||
|
||||
if codings.contains(&Chunked) {
|
||||
ChunkedReader(tcp, None)
|
||||
ChunkedReader(stream, None)
|
||||
} else {
|
||||
debug!("not chucked. read till eof");
|
||||
EofReader(tcp)
|
||||
debug!("not chuncked. read till eof");
|
||||
EofReader(stream)
|
||||
}
|
||||
}
|
||||
None => unreachable!()
|
||||
}
|
||||
} else if headers.has::<ContentLength>() {
|
||||
match headers.get_ref::<ContentLength>() {
|
||||
Some(&ContentLength(len)) => SizedReader(tcp, len),
|
||||
Some(&ContentLength(len)) => SizedReader(stream, len),
|
||||
None => unreachable!()
|
||||
}
|
||||
} else {
|
||||
debug!("neither Transfer-Encoding nor Content-Length");
|
||||
EofReader(tcp)
|
||||
EofReader(stream)
|
||||
};
|
||||
|
||||
Ok(Response {
|
||||
@@ -67,7 +67,8 @@ impl Response {
|
||||
}
|
||||
}
|
||||
|
||||
impl Reader for Response {
|
||||
impl<S: NetworkStream> Reader for Response<S> {
|
||||
#[inline]
|
||||
fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> {
|
||||
self.body.read(buf)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user