From fa0848d4216aa81e7b7619b7ce0a650356ee7ab7 Mon Sep 17 00:00:00 2001 From: Jonathan Reem Date: Sun, 18 Oct 2015 18:51:31 -0700 Subject: [PATCH] feat(server): Add hooks for HttpListener and HttpsListener to be started from existing listeners. This allows Servers to be started on existing TcpListeners. --- src/net.rs | 37 ++++++++++++++++++++++++------------- src/server/listener.rs | 2 +- src/server/mod.rs | 9 ++------- 3 files changed, 27 insertions(+), 21 deletions(-) diff --git a/src/net.rs b/src/net.rs index 98b6b41e34..892522c8a1 100644 --- a/src/net.rs +++ b/src/net.rs @@ -51,12 +51,15 @@ impl<'a, N: NetworkListener + 'a> Iterator for NetworkConnections<'a, N> { pub trait NetworkStream: Read + Write + Any + Send + Typeable { /// Get the remote address of the underlying connection. fn peer_addr(&mut self) -> io::Result; + /// Set the maximum time to wait for a read to complete. #[cfg(feature = "timeouts")] fn set_read_timeout(&self, dur: Option) -> io::Result<()>; + /// Set the maximum time to wait for a write to complete. #[cfg(feature = "timeouts")] fn set_write_timeout(&self, dur: Option) -> io::Result<()>; + /// This will be called when Stream should no longer be kept alive. #[inline] fn close(&mut self, _how: Shutdown) -> io::Result<()> { @@ -66,9 +69,8 @@ pub trait NetworkStream: Read + Write + Any + Send + Typeable { // Unsure about name and implementation... #[doc(hidden)] - fn set_previous_response_expected_no_content(&mut self, _expected: bool) { - - } + fn set_previous_response_expected_no_content(&mut self, _expected: bool) { } + #[doc(hidden)] fn previous_response_expected_no_content(&self) -> bool { false @@ -79,6 +81,7 @@ pub trait NetworkStream: Read + Write + Any + Send + Typeable { pub trait NetworkConnector { /// Type of Stream to create type Stream: Into>; + /// Connect to a remote address. fn connect(&self, host: &str, port: u16, scheme: &str) -> ::Result; } @@ -215,13 +218,17 @@ impl Clone for HttpListener { } } -impl HttpListener { +impl From for HttpListener { + fn from(listener: TcpListener) -> HttpListener { + HttpListener(listener) + } +} +impl HttpListener { /// Start listening to an address over HTTP. pub fn new(addr: To) -> ::Result { Ok(HttpListener(try!(TcpListener::bind(addr)))) } - } impl NetworkListener for HttpListener { @@ -382,17 +389,17 @@ impl NetworkConnector for HttpConnector { /// A closure as a connector used to generate TcpStreams per request /// /// # Example -/// +/// /// Basic example: -/// +/// /// ```norun /// Client::with_connector(|addr: &str, port: u16, scheme: &str| { /// TcpStream::connect(&(addr, port)) /// }); /// ``` -/// +/// /// Example using TcpBuilder from the net2 crate if you want to configure your source socket: -/// +/// /// ```norun /// Client::with_connector(|addr: &str, port: u16, scheme: &str| { /// let b = try!(TcpBuilder::new_v4()); @@ -499,7 +506,6 @@ pub struct HttpsListener { } impl HttpsListener { - /// Start listening to an address over HTTPS. pub fn new(addr: To, ssl: S) -> ::Result> { HttpListener::new(addr).map(|l| HttpsListener { @@ -508,6 +514,13 @@ impl HttpsListener { }) } + /// Construct an HttpsListener from a bound `TcpListener`. + pub fn with_listener(listener: HttpListener, ssl: S) -> HttpsListener { + HttpsListener { + listener: listener, + ssl: ssl + } + } } impl NetworkListener for HttpsListener { @@ -576,7 +589,6 @@ mod openssl { use openssl::x509::X509FileType; use super::{NetworkStream, HttpStream}; - /// An implementation of `Ssl` for OpenSSL. /// /// # Example @@ -678,7 +690,6 @@ mod tests { let mock = stream.downcast::().ok().unwrap(); assert_eq!(mock, Box::new(MockStream::new())); - } #[test] @@ -688,6 +699,6 @@ mod tests { let mock = unsafe { stream.downcast_unchecked::() }; assert_eq!(mock, Box::new(MockStream::new())); - } } + diff --git a/src/server/listener.rs b/src/server/listener.rs index a6b86d7992..16c58905d2 100644 --- a/src/server/listener.rs +++ b/src/server/listener.rs @@ -42,7 +42,6 @@ impl ListenerPool { fn spawn_with(supervisor: mpsc::Sender<()>, work: Arc, mut acceptor: A) where A: NetworkListener + Send + 'static, F: Fn(::Stream) + Send + Sync + 'static { - thread::spawn(move || { let _sentinel = Sentinel::new(supervisor, ()); @@ -77,3 +76,4 @@ impl Drop for Sentinel { let _ = self.supervisor.send(self.value.take().unwrap()); } } + diff --git a/src/server/mod.rs b/src/server/mod.rs index 9bf8aac116..7eb6c7fe8f 100644 --- a/src/server/mod.rs +++ b/src/server/mod.rs @@ -194,8 +194,6 @@ impl Server { pub fn set_write_timeout(&mut self, dur: Option) { self.timeouts.write = dur; } - - } impl Server { @@ -219,6 +217,7 @@ impl Server { pub fn handle(self, handler: H) -> ::Result { self.handle_threads(handler, num_cpus::get() * 5 / 4) } + /// Binds to a socket and starts handling connections with the provided /// number of threads. pub fn handle_threads(self, handler: H, @@ -228,8 +227,7 @@ impl Server { } fn handle(mut server: Server, handler: H, threads: usize) -> ::Result -where H: Handler + 'static, -L: NetworkListener + Send + 'static { +where H: Handler + 'static, L: NetworkListener + Send + 'static { let socket = try!(server.listener.local_addr()); debug!("threads = {:?}", threads); @@ -251,7 +249,6 @@ struct Worker { } impl Worker { - fn new(handler: H, timeouts: Timeouts) -> Worker { Worker { handler: handler, @@ -299,7 +296,6 @@ impl Worker { self.set_write_timeout(s, self.timeouts.write) } - #[cfg(not(feature = "timeouts"))] fn set_write_timeout(&self, _s: &NetworkStream, _timeout: Option) -> io::Result<()> { Ok(()) @@ -339,7 +335,6 @@ impl Worker { } }; - if !self.handle_expect(&req, wrt) { return false; }