| @@ -7,7 +7,7 @@ use method; | ||||
| use method::Method::{Get, Post, Delete, Put, Patch, Head, Options}; | ||||
| use header::Headers; | ||||
| use header::common::{mod, Host}; | ||||
| use net::{NetworkStream, NetworkConnector, HttpStream, Fresh, Streaming}; | ||||
| use net::{NetworkStream, NetworkConnector, HttpConnector, Fresh, Streaming}; | ||||
| use HttpError::HttpUriError; | ||||
| use http::{HttpWriter, LINE_ENDING}; | ||||
| use http::HttpWriter::{ThroughWriter, ChunkedWriter, SizedWriter, EmptyWriter}; | ||||
| @@ -42,11 +42,12 @@ impl<W> Request<W> { | ||||
| impl Request<Fresh> { | ||||
|     /// Create a new client request. | ||||
|     pub fn new(method: method::Method, url: Url) -> HttpResult<Request<Fresh>> { | ||||
|         Request::with_stream::<HttpStream>(method, url) | ||||
|         let mut conn = HttpConnector; | ||||
|         Request::with_connector(method, url, &mut conn) | ||||
|     } | ||||
|  | ||||
|     /// Create a new client request with a specific underlying NetworkStream. | ||||
|     pub fn with_stream<S: NetworkConnector>(method: method::Method, url: Url) -> HttpResult<Request<Fresh>> { | ||||
|     pub fn with_connector<C: NetworkConnector<S>, S: NetworkStream>(method: method::Method, url: Url, connector: &mut C) -> HttpResult<Request<Fresh>> { | ||||
|         debug!("{} {}", method, url); | ||||
|         let host = match url.serialize_host() { | ||||
|             Some(host) => host, | ||||
| @@ -59,7 +60,7 @@ impl Request<Fresh> { | ||||
|         }; | ||||
|         debug!("port={}", port); | ||||
|  | ||||
|         let stream: S = try!(NetworkConnector::connect((host[], port), url.scheme.as_slice())); | ||||
|         let stream: S = try!(connector.connect((host[], port), &*url.scheme)); | ||||
|         let stream = ThroughWriter(BufferedWriter::new(box stream as Box<NetworkStream + Send>)); | ||||
|  | ||||
|         let mut headers = Headers::new(); | ||||
| @@ -210,13 +211,13 @@ mod tests { | ||||
|     use std::str::from_utf8; | ||||
|     use url::Url; | ||||
|     use method::Method::{Get, Head}; | ||||
|     use mock::MockStream; | ||||
|     use mock::{MockStream, MockConnector}; | ||||
|     use super::Request; | ||||
|  | ||||
|     #[test] | ||||
|     fn test_get_empty_body() { | ||||
|         let req = Request::with_stream::<MockStream>( | ||||
|             Get, Url::parse("http://example.dom").unwrap() | ||||
|         let req = Request::with_connector( | ||||
|             Get, Url::parse("http://example.dom").unwrap(), &mut MockConnector | ||||
|         ).unwrap(); | ||||
|         let req = req.start().unwrap(); | ||||
|         let stream = *req.body.end().unwrap().into_inner().downcast::<MockStream>().unwrap(); | ||||
| @@ -228,8 +229,8 @@ mod tests { | ||||
|  | ||||
|     #[test] | ||||
|     fn test_head_empty_body() { | ||||
|         let req = Request::with_stream::<MockStream>( | ||||
|             Head, Url::parse("http://example.dom").unwrap() | ||||
|         let req = Request::with_connector( | ||||
|             Head, Url::parse("http://example.dom").unwrap(), &mut MockConnector | ||||
|         ).unwrap(); | ||||
|         let req = req.start().unwrap(); | ||||
|         let stream = *req.body.end().unwrap().into_inner().downcast::<MockStream>().unwrap(); | ||||
|   | ||||
							
								
								
									
										25
									
								
								src/http.rs
									
									
									
									
									
								
							
							
						
						
									
										25
									
								
								src/http.rs
									
									
									
									
									
								
							| @@ -190,6 +190,31 @@ impl<W: Writer> HttpWriter<W> { | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /// Access the inner Writer. | ||||
|     #[inline] | ||||
|     pub fn get_ref<'a>(&'a self) -> &'a W { | ||||
|         match *self { | ||||
|             ThroughWriter(ref w) => w, | ||||
|             ChunkedWriter(ref w) => w, | ||||
|             SizedWriter(ref w, _) => w, | ||||
|             EmptyWriter(ref w) => w, | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /// Access the inner Writer mutably. | ||||
|     /// | ||||
|     /// Warning: You should not write to this directly, as you can corrupt | ||||
|     /// the state. | ||||
|     #[inline] | ||||
|     pub fn get_mut<'a>(&'a mut self) -> &'a mut W { | ||||
|         match *self { | ||||
|             ThroughWriter(ref mut w) => w, | ||||
|             ChunkedWriter(ref mut w) => w, | ||||
|             SizedWriter(ref mut w, _) => w, | ||||
|             EmptyWriter(ref mut w) => w, | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /// Ends the HttpWriter, and returns the underlying Writer. | ||||
|     /// | ||||
|     /// A final `write()` is called with an empty message, and then flushed. | ||||
|   | ||||
| @@ -61,14 +61,15 @@ impl Writer for MockStream { | ||||
| } | ||||
|  | ||||
| impl NetworkStream for MockStream { | ||||
|  | ||||
|     fn peer_name(&mut self) -> IoResult<SocketAddr> { | ||||
|         Ok(from_str("127.0.0.1:1337").unwrap()) | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl NetworkConnector for MockStream { | ||||
|     fn connect<To: ToSocketAddr>(_addr: To, _scheme: &str) -> IoResult<MockStream> { | ||||
| pub struct MockConnector; | ||||
|  | ||||
| impl NetworkConnector<MockStream> for MockConnector { | ||||
|     fn connect<To: ToSocketAddr>(&mut self, _addr: To, _scheme: &str) -> IoResult<MockStream> { | ||||
|         Ok(MockStream::new()) | ||||
|     } | ||||
| } | ||||
|   | ||||
							
								
								
									
										34
									
								
								src/net.rs
									
									
									
									
									
								
							
							
						
						
									
										34
									
								
								src/net.rs
									
									
									
									
									
								
							| @@ -9,7 +9,6 @@ use std::io::net::ip::{SocketAddr, ToSocketAddr}; | ||||
| use std::io::net::tcp::{TcpStream, TcpListener, TcpAcceptor}; | ||||
| use std::mem::{mod, transmute, transmute_copy}; | ||||
| use std::raw::{mod, TraitObject}; | ||||
| use std::sync::{Arc, Mutex}; | ||||
|  | ||||
| use uany::UncheckedBoxAnyDowncast; | ||||
| use openssl::ssl::{SslStream, SslContext}; | ||||
| @@ -53,9 +52,9 @@ pub trait NetworkStream: Stream + Any + Clone + Send { | ||||
| } | ||||
|  | ||||
| /// A connector creates a NetworkStream. | ||||
| pub trait NetworkConnector: NetworkStream { | ||||
| pub trait NetworkConnector<S: NetworkStream> { | ||||
|     /// Connect to a remote address. | ||||
|     fn connect<To: ToSocketAddr>(addr: To, scheme: &str) -> IoResult<Self>; | ||||
|     fn connect<To: ToSocketAddr>(&mut self, addr: To, scheme: &str) -> IoResult<S>; | ||||
| } | ||||
|  | ||||
| impl fmt::Show for Box<NetworkStream + Send> { | ||||
| @@ -189,11 +188,7 @@ pub enum HttpStream { | ||||
|     /// A stream over the HTTP protocol. | ||||
|     Http(TcpStream), | ||||
|     /// A stream over the HTTP protocol, protected by SSL. | ||||
|     // You may be asking wtf an Arc and Mutex? That's because SslStream | ||||
|     // doesn't implement Clone, and we need Clone to use the stream for | ||||
|     // both the Request and Response. | ||||
|     // FIXME: https://github.com/sfackler/rust-openssl/issues/6 | ||||
|     Https(Arc<Mutex<SslStream<TcpStream>>>, SocketAddr), | ||||
|     Https(SslStream<TcpStream>), | ||||
| } | ||||
|  | ||||
| impl Reader for HttpStream { | ||||
| @@ -201,7 +196,7 @@ impl Reader for HttpStream { | ||||
|     fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> { | ||||
|         match *self { | ||||
|             Http(ref mut inner) => inner.read(buf), | ||||
|             Https(ref mut inner, _) => inner.lock().read(buf) | ||||
|             Https(ref mut inner) => inner.read(buf) | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -211,30 +206,32 @@ impl Writer for HttpStream { | ||||
|     fn write(&mut self, msg: &[u8]) -> IoResult<()> { | ||||
|         match *self { | ||||
|             Http(ref mut inner) => inner.write(msg), | ||||
|             Https(ref mut inner, _) => inner.lock().write(msg) | ||||
|             Https(ref mut inner) => inner.write(msg) | ||||
|         } | ||||
|     } | ||||
|     #[inline] | ||||
|     fn flush(&mut self) -> IoResult<()> { | ||||
|         match *self { | ||||
|             Http(ref mut inner) => inner.flush(), | ||||
|             Https(ref mut inner, _) => inner.lock().flush(), | ||||
|             Https(ref mut inner) => inner.flush(), | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
|  | ||||
| impl NetworkStream for HttpStream { | ||||
|     fn peer_name(&mut self) -> IoResult<SocketAddr> { | ||||
|         match *self { | ||||
|             Http(ref mut inner) => inner.peer_name(), | ||||
|             Https(_, addr) => Ok(addr) | ||||
|             Https(ref mut inner) => inner.get_mut().peer_name() | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl NetworkConnector for HttpStream { | ||||
|     fn connect<To: ToSocketAddr>(addr: To, scheme: &str) -> IoResult<HttpStream> { | ||||
| /// A connector that will produce HttpStreams. | ||||
| pub struct HttpConnector; | ||||
|  | ||||
| impl NetworkConnector<HttpStream> for HttpConnector { | ||||
|     fn connect<To: ToSocketAddr>(&mut self, addr: To, scheme: &str) -> IoResult<HttpStream> { | ||||
|         match scheme { | ||||
|             "http" => { | ||||
|                 debug!("http scheme"); | ||||
| @@ -242,13 +239,10 @@ impl NetworkConnector for HttpStream { | ||||
|             }, | ||||
|             "https" => { | ||||
|                 debug!("https scheme"); | ||||
|                 let mut stream = try!(TcpStream::connect(addr)); | ||||
|                 // we can't access the tcp stream once it's wrapped in an | ||||
|                 // SslStream, so grab the ip address now, just in case. | ||||
|                 let peer_addr = try!(stream.peer_name()); | ||||
|                 let stream = try!(TcpStream::connect(addr)); | ||||
|                 let context = try!(SslContext::new(Sslv23).map_err(lift_ssl_error)); | ||||
|                 let stream = try!(SslStream::new(&context, stream).map_err(lift_ssl_error)); | ||||
|                 Ok(Https(Arc::new(Mutex::new(stream)), peer_addr)) | ||||
|                 Ok(Https(stream)) | ||||
|             }, | ||||
|             _ => { | ||||
|                 Err(IoError { | ||||
|   | ||||
		Reference in New Issue
	
	Block a user