committed by
					
						 Sean McArthur
						Sean McArthur
					
				
			
			
				
	
			
			
			
						parent
						
							a22ae26cec
						
					
				
				
					commit
					d67dbc6028
				
			
							
								
								
									
										19
									
								
								src/net.rs
									
									
									
									
									
								
							
							
						
						
									
										19
									
								
								src/net.rs
									
									
									
									
									
								
							| @@ -1,6 +1,7 @@ | |||||||
| //! A collection of traits abstracting over Listeners and Streams. | //! A collection of traits abstracting over Listeners and Streams. | ||||||
| use std::io::{self, Read, Write}; | use std::io::{self, Read, Write}; | ||||||
| use std::net::{SocketAddr}; | use std::net::{SocketAddr}; | ||||||
|  | use std::option; | ||||||
|  |  | ||||||
| use rotor::mio::tcp::{TcpStream, TcpListener}; | use rotor::mio::tcp::{TcpStream, TcpListener}; | ||||||
| use rotor::mio::{Selector, Token, Evented, EventSet, PollOpt, TryAccept}; | use rotor::mio::{Selector, Token, Evented, EventSet, PollOpt, TryAccept}; | ||||||
| @@ -168,6 +169,15 @@ impl Evented for HttpListener { | |||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | impl IntoIterator for HttpListener { | ||||||
|  |     type Item = Self; | ||||||
|  |     type IntoIter = option::IntoIter<Self>; | ||||||
|  |  | ||||||
|  |     fn into_iter(self) -> Self::IntoIter { | ||||||
|  |         Some(self).into_iter() | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
| /// Deprecated | /// Deprecated | ||||||
| /// | /// | ||||||
| /// Use `SslClient` and `SslServer` instead. | /// Use `SslClient` and `SslServer` instead. | ||||||
| @@ -390,6 +400,15 @@ impl<S: SslServer> Evented for HttpsListener<S> { | |||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | impl<S: SslServer> IntoIterator for HttpsListener<S> { | ||||||
|  |     type Item = Self; | ||||||
|  |     type IntoIter = option::IntoIter<Self>; | ||||||
|  |  | ||||||
|  |     fn into_iter(self) -> Self::IntoIter { | ||||||
|  |         Some(self).into_iter() | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
| fn _assert_transport() { | fn _assert_transport() { | ||||||
|     fn _assert<T: Transport>() {} |     fn _assert<T: Transport>() {} | ||||||
|     _assert::<HttpsStream<HttpStream>>(); |     _assert::<HttpsStream<HttpStream>>(); | ||||||
|   | |||||||
| @@ -37,19 +37,26 @@ impl<A: Accept, H: HandlerFactory<A::Output>> fmt::Debug for ServerLoop<A, H> { | |||||||
|  |  | ||||||
| /// A Server that can accept incoming network requests. | /// A Server that can accept incoming network requests. | ||||||
| #[derive(Debug)] | #[derive(Debug)] | ||||||
| pub struct Server<T: Accept> { | pub struct Server<A> { | ||||||
|     listener: T, |     lead_listener: A, | ||||||
|  |     other_listeners: Vec<A>, | ||||||
|     keep_alive: bool, |     keep_alive: bool, | ||||||
|     idle_timeout: Option<Duration>, |     idle_timeout: Option<Duration>, | ||||||
|     max_sockets: usize, |     max_sockets: usize, | ||||||
| } | } | ||||||
|  |  | ||||||
| impl<T> Server<T> where T: Accept, T::Output: Transport { | impl<A: Accept> Server<A> { | ||||||
|     /// Creates a new server with the provided Listener. |     /// Creates a new Server from one or more Listeners. | ||||||
|     #[inline] |     /// | ||||||
|     pub fn new(listener: T) -> Server<T> { |     /// Panics if listeners is an empty iterator. | ||||||
|  |     pub fn new<I: IntoIterator<Item = A>>(listeners: I) -> Server<A> { | ||||||
|  |         let mut listeners = listeners.into_iter(); | ||||||
|  |         let lead_listener = listeners.next().expect("Server::new requires at least 1 listener"); | ||||||
|  |         let other_listeners = listeners.collect::<Vec<_>>(); | ||||||
|  |  | ||||||
|         Server { |         Server { | ||||||
|             listener: listener, |             lead_listener: lead_listener, | ||||||
|  |             other_listeners: other_listeners, | ||||||
|             keep_alive: true, |             keep_alive: true, | ||||||
|             idle_timeout: Some(Duration::from_secs(10)), |             idle_timeout: Some(Duration::from_secs(10)), | ||||||
|             max_sockets: 4096, |             max_sockets: 4096, | ||||||
| @@ -59,7 +66,7 @@ impl<T> Server<T> where T: Accept, T::Output: Transport { | |||||||
|     /// Enables or disables HTTP keep-alive. |     /// Enables or disables HTTP keep-alive. | ||||||
|     /// |     /// | ||||||
|     /// Default is true. |     /// Default is true. | ||||||
|     pub fn keep_alive(mut self, val: bool) -> Server<T> { |     pub fn keep_alive(mut self, val: bool) -> Server<A> { | ||||||
|         self.keep_alive = val; |         self.keep_alive = val; | ||||||
|         self |         self | ||||||
|     } |     } | ||||||
| @@ -67,7 +74,7 @@ impl<T> Server<T> where T: Accept, T::Output: Transport { | |||||||
|     /// Sets how long an idle connection will be kept before closing. |     /// Sets how long an idle connection will be kept before closing. | ||||||
|     /// |     /// | ||||||
|     /// Default is 10 seconds. |     /// Default is 10 seconds. | ||||||
|     pub fn idle_timeout(mut self, val: Option<Duration>) -> Server<T> { |     pub fn idle_timeout(mut self, val: Option<Duration>) -> Server<A> { | ||||||
|         self.idle_timeout = val; |         self.idle_timeout = val; | ||||||
|         self |         self | ||||||
|     } |     } | ||||||
| @@ -75,7 +82,7 @@ impl<T> Server<T> where T: Accept, T::Output: Transport { | |||||||
|     /// Sets the maximum open sockets for this Server. |     /// Sets the maximum open sockets for this Server. | ||||||
|     /// |     /// | ||||||
|     /// Default is 4096, but most servers can handle much more than this. |     /// Default is 4096, but most servers can handle much more than this. | ||||||
|     pub fn max_sockets(mut self, val: usize) -> Server<T> { |     pub fn max_sockets(mut self, val: usize) -> Server<A> { | ||||||
|         self.max_sockets = val; |         self.max_sockets = val; | ||||||
|         self |         self | ||||||
|     } |     } | ||||||
| @@ -105,33 +112,48 @@ impl<S: SslServer> Server<HttpsListener<S>> { | |||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| impl<A: Accept> Server<A> where A::Output: Transport  { | impl<A: Accept> Server<A> { | ||||||
|     /// Binds to a socket and starts handling connections. |     /// Binds to a socket and starts handling connections. | ||||||
|     pub fn handle<H>(self, factory: H) -> ::Result<(Listening, ServerLoop<A, H>)> |     pub fn handle<H>(self, factory: H) -> ::Result<(Listening, ServerLoop<A, H>)> | ||||||
|     where H: HandlerFactory<A::Output> { |     where H: HandlerFactory<A::Output> { | ||||||
|         let addr = try!(self.listener.local_addr()); |  | ||||||
|         let shutdown = Arc::new(AtomicBool::new(false)); |         let shutdown = Arc::new(AtomicBool::new(false)); | ||||||
|         let shutdown_rx = shutdown.clone(); |          | ||||||
|  |  | ||||||
|         let mut config = rotor::Config::new(); |         let mut config = rotor::Config::new(); | ||||||
|         config.slab_capacity(self.max_sockets); |         config.slab_capacity(self.max_sockets); | ||||||
|         config.mio().notify_capacity(self.max_sockets); |         config.mio().notify_capacity(self.max_sockets); | ||||||
|         let keep_alive = self.keep_alive; |         let keep_alive = self.keep_alive; | ||||||
|         let idle_timeout = self.idle_timeout; |         let idle_timeout = self.idle_timeout; | ||||||
|         let mut loop_ = rotor::Loop::new(&config).unwrap(); |         let mut loop_ = rotor::Loop::new(&config).unwrap(); | ||||||
|  |  | ||||||
|  |         let mut addrs = Vec::with_capacity(1 + self.other_listeners.len()); | ||||||
|  |  | ||||||
|  |         // Add the lead listener. This one handles shutdown messages. | ||||||
|         let mut notifier = None; |         let mut notifier = None; | ||||||
|         { |         { | ||||||
|             let notifier = &mut notifier; |             let notifier = &mut notifier; | ||||||
|  |             let listener = self.lead_listener; | ||||||
|  |             addrs.push(try!(listener.local_addr())); | ||||||
|  |             let shutdown_rx = shutdown.clone(); | ||||||
|             loop_.add_machine_with(move |scope| { |             loop_.add_machine_with(move |scope| { | ||||||
|                 *notifier = Some(scope.notifier()); |                 *notifier = Some(scope.notifier()); | ||||||
|                 rotor_try!(scope.register(&self.listener, EventSet::readable(), PollOpt::level())); |                 rotor_try!(scope.register(&listener, EventSet::readable(), PollOpt::level())); | ||||||
|                 rotor::Response::ok(ServerFsm::Listener::<A, H>(self.listener, shutdown_rx)) |                 rotor::Response::ok(ServerFsm::Listener(listener, shutdown_rx)) | ||||||
|             }).unwrap(); |             }).unwrap(); | ||||||
|         } |         } | ||||||
|         let notifier = notifier.expect("loop.add_machine failed"); |         let notifier = notifier.expect("loop.add_machine failed"); | ||||||
|  |  | ||||||
|  |         // Add the other listeners. | ||||||
|  |         for listener in self.other_listeners { | ||||||
|  |             addrs.push(try!(listener.local_addr())); | ||||||
|  |             let shutdown_rx = shutdown.clone(); | ||||||
|  |             loop_.add_machine_with(move |scope| { | ||||||
|  |                 rotor_try!(scope.register(&listener, EventSet::readable(), PollOpt::level())); | ||||||
|  |                 rotor::Response::ok(ServerFsm::Listener(listener, shutdown_rx)) | ||||||
|  |             }).unwrap(); | ||||||
|  |         } | ||||||
|  |  | ||||||
|         let listening = Listening { |         let listening = Listening { | ||||||
|             addr: addr, |             addrs: addrs, | ||||||
|             shutdown: (shutdown, notifier), |             shutdown: (shutdown, notifier), | ||||||
|         }; |         }; | ||||||
|         let server = ServerLoop { |         let server = ServerLoop { | ||||||
| @@ -299,14 +321,14 @@ where A: Accept, | |||||||
|  |  | ||||||
| /// A handle of the running server. | /// A handle of the running server. | ||||||
| pub struct Listening { | pub struct Listening { | ||||||
|     addr: SocketAddr, |     addrs: Vec<SocketAddr>, | ||||||
|     shutdown: (Arc<AtomicBool>, rotor::Notifier), |     shutdown: (Arc<AtomicBool>, rotor::Notifier), | ||||||
| } | } | ||||||
|  |  | ||||||
| impl fmt::Debug for Listening { | impl fmt::Debug for Listening { | ||||||
|     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | ||||||
|         f.debug_struct("Listening") |         f.debug_struct("Listening") | ||||||
|             .field("addr", &self.addr) |             .field("addrs", &self.addrs) | ||||||
|             .field("closed", &self.shutdown.0.load(Ordering::Relaxed)) |             .field("closed", &self.shutdown.0.load(Ordering::Relaxed)) | ||||||
|             .finish() |             .finish() | ||||||
|     } |     } | ||||||
| @@ -314,14 +336,20 @@ impl fmt::Debug for Listening { | |||||||
|  |  | ||||||
| impl fmt::Display for Listening { | impl fmt::Display for Listening { | ||||||
|     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | ||||||
|         fmt::Display::fmt(&self.addr, f) |         for (i, addr) in self.addrs().iter().enumerate() { | ||||||
|  |             if i > 1 { | ||||||
|  |                 try!(f.write_str(", ")); | ||||||
|  |             } | ||||||
|  |             try!(fmt::Display::fmt(addr, f)); | ||||||
|  |         } | ||||||
|  |         Ok(()) | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| impl Listening { | impl Listening { | ||||||
|     /// The address this server is listening on. |     /// The addresses this server is listening on. | ||||||
|     pub fn addr(&self) -> &SocketAddr { |     pub fn addrs(&self) -> &[SocketAddr] { | ||||||
|         &self.addr |         &self.addrs | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /// Stop the server from listening to its socket address. |     /// Stop the server from listening to its socket address. | ||||||
| @@ -375,8 +403,3 @@ where F: FnMut(http::Control) -> H, H: Handler<T>, T: Transport { | |||||||
|         self(ctrl) |         self(ctrl) | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| #[cfg(test)] |  | ||||||
| mod tests { |  | ||||||
|  |  | ||||||
| } |  | ||||||
|   | |||||||
| @@ -7,7 +7,7 @@ use std::sync::mpsc; | |||||||
| use std::time::Duration; | use std::time::Duration; | ||||||
|  |  | ||||||
| use hyper::{Next, Encoder, Decoder}; | use hyper::{Next, Encoder, Decoder}; | ||||||
| use hyper::net::HttpStream; | use hyper::net::{HttpListener, HttpStream}; | ||||||
| use hyper::server::{Server, Handler, Request, Response}; | use hyper::server::{Server, Handler, Request, Response}; | ||||||
|  |  | ||||||
| struct Serve { | struct Serve { | ||||||
| @@ -17,8 +17,14 @@ struct Serve { | |||||||
| } | } | ||||||
|  |  | ||||||
| impl Serve { | impl Serve { | ||||||
|  |     fn addrs(&self) -> &[SocketAddr] { | ||||||
|  |         self.listening.as_ref().unwrap().addrs() | ||||||
|  |     } | ||||||
|  |  | ||||||
|     fn addr(&self) -> &SocketAddr { |     fn addr(&self) -> &SocketAddr { | ||||||
|         self.listening.as_ref().unwrap().addr() |         let addrs = self.addrs(); | ||||||
|  |         assert!(addrs.len() == 1); | ||||||
|  |         &addrs[0] | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /* |     /* | ||||||
| @@ -161,11 +167,22 @@ fn serve() -> Serve { | |||||||
| } | } | ||||||
|  |  | ||||||
| fn serve_with_timeout(dur: Option<Duration>) -> Serve { | fn serve_with_timeout(dur: Option<Duration>) -> Serve { | ||||||
|  |     serve_n_with_timeout(1, dur) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | fn serve_n(n: u32) -> Serve { | ||||||
|  |     serve_n_with_timeout(n, None) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | fn serve_n_with_timeout(n: u32, dur: Option<Duration>) -> Serve { | ||||||
|     use std::thread; |     use std::thread; | ||||||
|  |  | ||||||
|     let (msg_tx, msg_rx) = mpsc::channel(); |     let (msg_tx, msg_rx) = mpsc::channel(); | ||||||
|     let (reply_tx, reply_rx) = mpsc::channel(); |     let (reply_tx, reply_rx) = mpsc::channel(); | ||||||
|     let (listening, server) = Server::http(&"127.0.0.1:0".parse().unwrap()).unwrap() |  | ||||||
|  |     let addr = "127.0.0.1:0".parse().unwrap(); | ||||||
|  |     let listeners = (0..n).map(|_| HttpListener::bind(&addr).unwrap()); | ||||||
|  |     let (listening, server) = Server::new(listeners) | ||||||
|         .handle(move |_| { |         .handle(move |_| { | ||||||
|             let mut replies = Vec::new(); |             let mut replies = Vec::new(); | ||||||
|             while let Ok(reply) = reply_rx.try_recv() { |             while let Ok(reply) = reply_rx.try_recv() { | ||||||
| @@ -180,7 +197,7 @@ fn serve_with_timeout(dur: Option<Duration>) -> Serve { | |||||||
|         }).unwrap(); |         }).unwrap(); | ||||||
|  |  | ||||||
|  |  | ||||||
|     let thread_name = format!("test-server-{}: {:?}", listening.addr(), dur); |     let thread_name = format!("test-server-{}: {:?}", listening, dur); | ||||||
|     thread::Builder::new().name(thread_name).spawn(move || { |     thread::Builder::new().name(thread_name).spawn(move || { | ||||||
|         server.run(); |         server.run(); | ||||||
|     }).unwrap(); |     }).unwrap(); | ||||||
| @@ -439,3 +456,26 @@ fn server_keep_alive() { | |||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | #[test] | ||||||
|  | fn server_get_with_body_three_listeners() { | ||||||
|  |     let server = serve_n(3); | ||||||
|  |     let addrs = server.addrs(); | ||||||
|  |     assert_eq!(addrs.len(), 3); | ||||||
|  |  | ||||||
|  |     for (i, addr) in addrs.iter().enumerate() { | ||||||
|  |         let mut req = TcpStream::connect(addr).unwrap(); | ||||||
|  |         write!(req, "\ | ||||||
|  |             GET / HTTP/1.1\r\n\ | ||||||
|  |             Host: example.domain\r\n\ | ||||||
|  |             Content-Length: 17\r\n\ | ||||||
|  |             \r\n\ | ||||||
|  |             I'm sending to {}.\r\n\ | ||||||
|  |         ", i).unwrap(); | ||||||
|  |         req.read(&mut [0; 256]).unwrap(); | ||||||
|  |  | ||||||
|  |         // note: doesnt include trailing \r\n, cause Content-Length wasn't 19 | ||||||
|  |         let comparison = format!("I'm sending to {}.", i).into_bytes(); | ||||||
|  |         assert_eq!(server.body(), comparison); | ||||||
|  |     } | ||||||
|  | } | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user