From 1a076d1bc7e8fb9c58904b0cec879dcf0fbce97b Mon Sep 17 00:00:00 2001 From: Mike Dilger Date: Wed, 22 Apr 2015 11:25:07 +1200 Subject: [PATCH 1/3] feat(net): add https_using_context for user-supplied SslContext --- src/net.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/net.rs b/src/net.rs index eb4ceca1..30ec4dc9 100644 --- a/src/net.rs +++ b/src/net.rs @@ -164,6 +164,11 @@ impl HttpListener { try!(ssl_context.set_certificate_file(cert, X509FileType::PEM).map_err(lift_ssl_error)); try!(ssl_context.set_private_key_file(key, X509FileType::PEM).map_err(lift_ssl_error)); ssl_context.set_verify(SSL_VERIFY_NONE, None); + HttpListener::https_with_context(addr, ssl_context) + } + + /// Start listening to an address of HTTPS using the given SslContext + pub fn https_with_context(addr: To, ssl_context: SslContext) -> io::Result { Ok(HttpListener::Https(try!(TcpListener::bind(addr)), Arc::new(ssl_context))) } } From fef04d282f9a19409ab931b678807dd071f7b60d Mon Sep 17 00:00:00 2001 From: Mike Dilger Date: Sun, 26 Apr 2015 20:59:04 +1200 Subject: [PATCH 2/3] refactor(server): make with_listener a free function Allow a Server to operate without requiring the entire Server struct to move into the with_listener function (instead only the handler function needs to move). This, allows other members to not move, or move separately, which will be needed for the next commit. See #471 --- src/server/mod.rs | 34 +++++++++++++++++++--------------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/src/server/mod.rs b/src/server/mod.rs index 5574a5ed..bbe6631b 100644 --- a/src/server/mod.rs +++ b/src/server/mod.rs @@ -103,7 +103,7 @@ impl<'a, H: Handler + 'static> Server<'a, H, HttpListener> { Some((cert, key)) => HttpListener::https(addr, cert, key), None => HttpListener::http(addr) }); - self.with_listener(listener, threads) + with_listener(self.handler, listener, threads) } /// Binds to a socket and starts handling connections. @@ -117,23 +117,27 @@ H: Handler + 'static, L: NetworkListener + Send + 'static, S: NetworkStream + Clone + Send> Server<'a, H, L> { /// Creates a new server that will handle `HttpStream`s. - pub fn with_listener(self, mut listener: L, threads: usize) -> HttpResult { - let socket = try!(listener.local_addr()); - let handler = self.handler; - - debug!("threads = {:?}", threads); - let pool = ListenerPool::new(listener.clone()); - let work = move |mut stream| handle_connection(&mut stream, &handler); - - let guard = thread::spawn(move || pool.accept(work, threads)); - - Ok(Listening { - _guard: Some(guard), - socket: socket, - }) + pub fn with_listener(self, listener: L, threads: usize) -> HttpResult { + with_listener(self.handler, listener, threads) } } +fn with_listener(handler: H, mut listener: L, threads: usize) -> HttpResult +where H: Handler + 'static, +L: NetworkListener + Send + 'static { + let socket = try!(listener.local_addr()); + + debug!("threads = {:?}", threads); + let pool = ListenerPool::new(listener.clone()); + let work = move |mut stream| handle_connection(&mut stream, &handler); + + let guard = thread::spawn(move || pool.accept(work, threads)); + + Ok(Listening { + _guard: Some(guard), + socket: socket, + }) +} fn handle_connection<'h, S, H>(mut stream: &mut S, handler: &'h H) where S: NetworkStream + Clone, H: Handler { From 3a1a24270dd13e22ef59120d66d327528949d5e0 Mon Sep 17 00:00:00 2001 From: Mike Dilger Date: Sun, 26 Apr 2015 21:10:43 +1200 Subject: [PATCH 3/3] feat(server): allow consumer to supply an SslContext Closes #471 --- src/server/mod.rs | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/src/server/mod.rs b/src/server/mod.rs index bbe6631b..84773dc8 100644 --- a/src/server/mod.rs +++ b/src/server/mod.rs @@ -26,6 +26,7 @@ use std::path::Path; use std::thread::{self, JoinHandle}; use num_cpus; +use openssl::ssl::SslContext; pub use self::request::Request; pub use self::response::Response; @@ -50,6 +51,12 @@ pub mod response; mod listener; +#[derive(Debug)] +enum SslConfig<'a> { + CertAndKey(&'a Path, &'a Path), + Context(SslContext), +} + /// A server can listen on a TCP socket. /// /// Once listening, it will create a `Request`/`Response` pair for each @@ -57,7 +64,7 @@ mod listener; #[derive(Debug)] pub struct Server<'a, H: Handler, L = HttpListener> { handler: H, - ssl: Option<(&'a Path, &'a Path)>, + ssl: Option>, _marker: PhantomData } @@ -90,7 +97,15 @@ impl<'a, H: Handler + 'static> Server<'a, H, HttpListener> { pub fn https(handler: H, cert: &'a Path, key: &'a Path) -> Server<'a, H, HttpListener> { Server { handler: handler, - ssl: Some((cert, key)), + ssl: Some(SslConfig::CertAndKey(cert, key)), + _marker: PhantomData + } + } + /// Creates a new server that will handler `HttpStreams`s using a TLS connection defined by an SslContext. + pub fn https_with_context(handler: H, ssl_context: SslContext) -> Server<'a, H, HttpListener> { + Server { + handler: handler, + ssl: Some(SslConfig::Context(ssl_context)), _marker: PhantomData } } @@ -100,7 +115,8 @@ impl<'a, H: Handler + 'static> Server<'a, H, HttpListener> { /// Binds to a socket, and starts handling connections using a task pool. pub fn listen_threads(self, addr: T, threads: usize) -> HttpResult { let listener = try!(match self.ssl { - Some((cert, key)) => HttpListener::https(addr, cert, key), + Some(SslConfig::CertAndKey(cert, key)) => HttpListener::https(addr, cert, key), + Some(SslConfig::Context(ssl_context)) => HttpListener::https_with_context(addr, ssl_context), None => HttpListener::http(addr) }); with_listener(self.handler, listener, threads)