feat(server): re-design Server as higher-level API
				
					
				
			The `hyper::Server` is now a proper higher-level API for running HTTP servers. There is a related `hyper::server::Builder` type, to construct a `Server`. All other types (`Http`, `Serve`, etc) were moved into the "lower-level" `hyper::server::conn` module. The `Server` is a `Future` representing a listening HTTP server. Options needed to build one are set on the `Builder`. As `Server` is just a `Future`, it no longer owns a thread-blocking executor, and can thus be run next to other servers, clients, or what-have-you. Closes #1322 Closes #1263 BREAKING CHANGE: The `Server` is no longer created from `Http::bind`, nor is it `run`. It is a `Future` that must be polled by an `Executor`. The `hyper::server::Http` type has move to `hyper::server::conn::Http`.
This commit is contained in:
		
							
								
								
									
										234
									
								
								src/server/tcp.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										234
									
								
								src/server/tcp.rs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,234 @@ | ||||
| use std::fmt; | ||||
| use std::io; | ||||
| use std::net::{SocketAddr, TcpListener as StdTcpListener}; | ||||
| use std::time::Duration; | ||||
|  | ||||
| use futures::{Async, Future, Poll, Stream}; | ||||
| use futures_timer::Delay; | ||||
| //TODO: change to tokio_tcp::net::TcpListener | ||||
| use tokio::net::TcpListener; | ||||
| use tokio::reactor::Handle; | ||||
|  | ||||
| use self::addr_stream::AddrStream; | ||||
|  | ||||
| /// A stream of connections from binding to an address. | ||||
| #[must_use = "streams do nothing unless polled"] | ||||
| pub struct AddrIncoming { | ||||
|     addr: SocketAddr, | ||||
|     listener: TcpListener, | ||||
|     sleep_on_errors: bool, | ||||
|     tcp_keepalive_timeout: Option<Duration>, | ||||
|     tcp_nodelay: bool, | ||||
|     timeout: Option<Delay>, | ||||
| } | ||||
|  | ||||
| impl AddrIncoming { | ||||
|     pub(super) fn new(addr: &SocketAddr, handle: Option<&Handle>) -> ::Result<AddrIncoming> { | ||||
|         let listener = if let Some(handle) = handle { | ||||
|             let std_listener = StdTcpListener::bind(addr) | ||||
|                 .map_err(::Error::new_listen)?; | ||||
|             TcpListener::from_std(std_listener, handle) | ||||
|                 .map_err(::Error::new_listen)? | ||||
|         } else { | ||||
|             TcpListener::bind(addr).map_err(::Error::new_listen)? | ||||
|         }; | ||||
|  | ||||
|         let addr = listener.local_addr().map_err(::Error::new_listen)?; | ||||
|  | ||||
|         Ok(AddrIncoming { | ||||
|             addr: addr, | ||||
|             listener: listener, | ||||
|             sleep_on_errors: true, | ||||
|             tcp_keepalive_timeout: None, | ||||
|             tcp_nodelay: false, | ||||
|             timeout: None, | ||||
|         }) | ||||
|     } | ||||
|  | ||||
|     /// Get the local address bound to this listener. | ||||
|     pub fn local_addr(&self) -> SocketAddr { | ||||
|         self.addr | ||||
|     } | ||||
|  | ||||
|     /// Set whether TCP keepalive messages are enabled on accepted connections. | ||||
|     /// | ||||
|     /// If `None` is specified, keepalive is disabled, otherwise the duration | ||||
|     /// specified will be the time to remain idle before sending TCP keepalive | ||||
|     /// probes. | ||||
|     pub fn set_keepalive(&mut self, keepalive: Option<Duration>) -> &mut Self { | ||||
|         self.tcp_keepalive_timeout = keepalive; | ||||
|         self | ||||
|     } | ||||
|  | ||||
|     /// Set the value of `TCP_NODELAY` option for accepted connections. | ||||
|     pub fn set_nodelay(&mut self, enabled: bool) -> &mut Self { | ||||
|         self.tcp_nodelay = enabled; | ||||
|         self | ||||
|     } | ||||
|  | ||||
|     /// Set whether to sleep on accept errors. | ||||
|     /// | ||||
|     /// A possible scenario is that the process has hit the max open files | ||||
|     /// allowed, and so trying to accept a new connection will fail with | ||||
|     /// `EMFILE`. In some cases, it's preferable to just wait for some time, if | ||||
|     /// the application will likely close some files (or connections), and try | ||||
|     /// to accept the connection again. If this option is `true`, the error | ||||
|     /// will be logged at the `error` level, since it is still a big deal, | ||||
|     /// and then the listener will sleep for 1 second. | ||||
|     /// | ||||
|     /// In other cases, hitting the max open files should be treat similarly | ||||
|     /// to being out-of-memory, and simply error (and shutdown). Setting | ||||
|     /// this option to `false` will allow that. | ||||
|     /// | ||||
|     /// Default is `true`. | ||||
|     pub fn set_sleep_on_errors(&mut self, val: bool) { | ||||
|         self.sleep_on_errors = val; | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl Stream for AddrIncoming { | ||||
|     // currently unnameable... | ||||
|     type Item = AddrStream; | ||||
|     type Error = ::std::io::Error; | ||||
|  | ||||
|     fn poll(&mut self) -> Poll<Option<Self::Item>, Self::Error> { | ||||
|         // Check if a previous timeout is active that was set by IO errors. | ||||
|         if let Some(ref mut to) = self.timeout { | ||||
|             match to.poll().expect("timeout never fails") { | ||||
|                 Async::Ready(_) => {} | ||||
|                 Async::NotReady => return Ok(Async::NotReady), | ||||
|             } | ||||
|         } | ||||
|         self.timeout = None; | ||||
|         loop { | ||||
|             match self.listener.poll_accept() { | ||||
|                 Ok(Async::Ready((socket, addr))) => { | ||||
|                     if let Some(dur) = self.tcp_keepalive_timeout { | ||||
|                         if let Err(e) = socket.set_keepalive(Some(dur)) { | ||||
|                             trace!("error trying to set TCP keepalive: {}", e); | ||||
|                         } | ||||
|                     } | ||||
|                     if let Err(e) = socket.set_nodelay(self.tcp_nodelay) { | ||||
|                         trace!("error trying to set TCP nodelay: {}", e); | ||||
|                     } | ||||
|                     return Ok(Async::Ready(Some(AddrStream::new(socket, addr)))); | ||||
|                 }, | ||||
|                 Ok(Async::NotReady) => return Ok(Async::NotReady), | ||||
|                 Err(ref e) if self.sleep_on_errors => { | ||||
|                     // Connection errors can be ignored directly, continue by | ||||
|                     // accepting the next request. | ||||
|                     if is_connection_error(e) { | ||||
|                         debug!("accepted connection already errored: {}", e); | ||||
|                         continue; | ||||
|                     } | ||||
|                     // Sleep 1s. | ||||
|                     let delay = Duration::from_secs(1); | ||||
|                     error!("accept error: {}", e); | ||||
|                     let mut timeout = Delay::new(delay); | ||||
|                     let result = timeout.poll() | ||||
|                         .expect("timeout never fails"); | ||||
|                     match result { | ||||
|                         Async::Ready(()) => continue, | ||||
|                         Async::NotReady => { | ||||
|                             self.timeout = Some(timeout); | ||||
|                             return Ok(Async::NotReady); | ||||
|                         } | ||||
|                     } | ||||
|                 }, | ||||
|                 Err(e) => return Err(e), | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| /// This function defines errors that are per-connection. Which basically | ||||
| /// means that if we get this error from `accept()` system call it means | ||||
| /// next connection might be ready to be accepted. | ||||
| /// | ||||
| /// All other errors will incur a timeout before next `accept()` is performed. | ||||
| /// The timeout is useful to handle resource exhaustion errors like ENFILE | ||||
| /// and EMFILE. Otherwise, could enter into tight loop. | ||||
| fn is_connection_error(e: &io::Error) -> bool { | ||||
|     e.kind() == io::ErrorKind::ConnectionRefused || | ||||
|     e.kind() == io::ErrorKind::ConnectionAborted || | ||||
|     e.kind() == io::ErrorKind::ConnectionReset | ||||
| } | ||||
|  | ||||
| impl fmt::Debug for AddrIncoming { | ||||
|     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | ||||
|         f.debug_struct("AddrIncoming") | ||||
|             .field("addr", &self.addr) | ||||
|             .field("sleep_on_errors", &self.sleep_on_errors) | ||||
|             .field("tcp_keepalive_timeout", &self.tcp_keepalive_timeout) | ||||
|             .field("tcp_nodelay", &self.tcp_nodelay) | ||||
|             .finish() | ||||
|     } | ||||
| } | ||||
|  | ||||
| mod addr_stream { | ||||
|     use std::io::{self, Read, Write}; | ||||
|     use std::net::SocketAddr; | ||||
|     use bytes::{Buf, BufMut}; | ||||
|     use futures::Poll; | ||||
|     use tokio::net::TcpStream; | ||||
|     use tokio_io::{AsyncRead, AsyncWrite}; | ||||
|  | ||||
|  | ||||
|     #[derive(Debug)] | ||||
|     pub struct AddrStream { | ||||
|         inner: TcpStream, | ||||
|         pub(super) remote_addr: SocketAddr, | ||||
|     } | ||||
|  | ||||
|     impl AddrStream { | ||||
|         pub(super) fn new(tcp: TcpStream, addr: SocketAddr) -> AddrStream { | ||||
|             AddrStream { | ||||
|                 inner: tcp, | ||||
|                 remote_addr: addr, | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     impl Read for AddrStream { | ||||
|         #[inline] | ||||
|         fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { | ||||
|             self.inner.read(buf) | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     impl Write for AddrStream { | ||||
|         #[inline] | ||||
|         fn write(&mut self, buf: &[u8]) -> io::Result<usize> { | ||||
|             self.inner.write(buf) | ||||
|         } | ||||
|  | ||||
|         #[inline] | ||||
|         fn flush(&mut self ) -> io::Result<()> { | ||||
|             self.inner.flush() | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     impl AsyncRead for AddrStream { | ||||
|         #[inline] | ||||
|         unsafe fn prepare_uninitialized_buffer(&self, buf: &mut [u8]) -> bool { | ||||
|             self.inner.prepare_uninitialized_buffer(buf) | ||||
|         } | ||||
|  | ||||
|         #[inline] | ||||
|         fn read_buf<B: BufMut>(&mut self, buf: &mut B) -> Poll<usize, io::Error> { | ||||
|             self.inner.read_buf(buf) | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     impl AsyncWrite for AddrStream { | ||||
|         #[inline] | ||||
|         fn shutdown(&mut self) -> Poll<(), io::Error> { | ||||
|             AsyncWrite::shutdown(&mut self.inner) | ||||
|         } | ||||
|  | ||||
|         #[inline] | ||||
|         fn write_buf<B: Buf>(&mut self, buf: &mut B) -> Poll<usize, io::Error> { | ||||
|             self.inner.write_buf(buf) | ||||
|         } | ||||
|     } | ||||
| } | ||||
		Reference in New Issue
	
	Block a user