Merge pull request #857 from hyperium/client-timeout-panic
fix(client): handle when DNS resolves after a timeout triggers
This commit is contained in:
		| @@ -48,7 +48,7 @@ impl hyper::client::Handler<HttpStream> for Dump { | |||||||
|             Err(e) => match e.kind() { |             Err(e) => match e.kind() { | ||||||
|                 io::ErrorKind::WouldBlock => Next::read(), |                 io::ErrorKind::WouldBlock => Next::read(), | ||||||
|                 _ => { |                 _ => { | ||||||
|                     println!("ERROR: {}", e); |                     println!("ERROR:example: {}", e); | ||||||
|                     Next::end() |                     Next::end() | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
| @@ -56,7 +56,7 @@ impl hyper::client::Handler<HttpStream> for Dump { | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     fn on_error(&mut self, err: hyper::Error) -> Next { |     fn on_error(&mut self, err: hyper::Error) -> Next { | ||||||
|         println!("ERROR: {}", err); |         println!("ERROR:example: {}", err); | ||||||
|         Next::remove() |         Next::remove() | ||||||
|     } |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -16,7 +16,7 @@ pub trait Connect { | |||||||
|     /// Type of Transport to create |     /// Type of Transport to create | ||||||
|     type Output: Transport; |     type Output: Transport; | ||||||
|     /// The key used to determine if an existing socket can be used. |     /// The key used to determine if an existing socket can be used. | ||||||
|     type Key: Eq + Hash + Clone; |     type Key: Eq + Hash + Clone + fmt::Debug; | ||||||
|     /// Returns the key based off the Url. |     /// Returns the key based off the Url. | ||||||
|     fn key(&self, &Url) -> Option<Self::Key>; |     fn key(&self, &Url) -> Option<Self::Key>; | ||||||
|     /// Connect to a remote address. |     /// Connect to a remote address. | ||||||
| @@ -96,10 +96,12 @@ impl Connect for HttpConnector { | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     fn connected(&mut self) -> Option<(Self::Key, io::Result<HttpStream>)> { |     fn connected(&mut self) -> Option<(Self::Key, io::Result<HttpStream>)> { | ||||||
|         let (host, addr) = match self.dns.as_ref().expect("dns workers lost").resolved() { |         let (host, addrs) = match self.dns.as_ref().expect("dns workers lost").resolved() { | ||||||
|             Ok(res) => res, |             Ok(res) => res, | ||||||
|             Err(_) => return None |             Err(_) => return None | ||||||
|         }; |         }; | ||||||
|  |         //TODO: try all addrs | ||||||
|  |         let addr = addrs.and_then(|mut addrs| Ok(addrs.next().unwrap())); | ||||||
|         debug!("Http::resolved <- ({:?}, {:?})", host, addr); |         debug!("Http::resolved <- ({:?}, {:?})", host, addr); | ||||||
|         if let Entry::Occupied(mut entry) = self.resolving.entry(host) { |         if let Entry::Occupied(mut entry) = self.resolving.entry(host) { | ||||||
|             let resolved = entry.get_mut().remove(0); |             let resolved = entry.get_mut().remove(0); | ||||||
|   | |||||||
| @@ -1,6 +1,7 @@ | |||||||
| use std::io; | use std::io; | ||||||
| use std::net::{IpAddr, ToSocketAddrs}; | use std::net::{IpAddr, SocketAddr, ToSocketAddrs}; | ||||||
| use std::thread; | use std::thread; | ||||||
|  | use std::vec; | ||||||
|  |  | ||||||
| use ::spmc; | use ::spmc; | ||||||
|  |  | ||||||
| @@ -11,7 +12,19 @@ pub struct Dns { | |||||||
|     rx: channel::Receiver<Answer>, |     rx: channel::Receiver<Answer>, | ||||||
| } | } | ||||||
|  |  | ||||||
| pub type Answer = (String, io::Result<IpAddr>); | pub type Answer = (String, io::Result<IpAddrs>); | ||||||
|  |  | ||||||
|  | pub struct IpAddrs { | ||||||
|  |     iter: vec::IntoIter<SocketAddr>, | ||||||
|  | } | ||||||
|  |  | ||||||
|  | impl Iterator for IpAddrs { | ||||||
|  |     type Item = IpAddr; | ||||||
|  |     #[inline] | ||||||
|  |     fn next(&mut self) -> Option<IpAddr> { | ||||||
|  |         self.iter.next().map(|addr| addr.ip()) | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
| impl Dns { | impl Dns { | ||||||
|     pub fn new(notify: (channel::Sender<Answer>, channel::Receiver<Answer>), threads: usize) -> Dns { |     pub fn new(notify: (channel::Sender<Answer>, channel::Receiver<Answer>), threads: usize) -> Dns { | ||||||
| @@ -26,7 +39,7 @@ impl Dns { | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     pub fn resolve<T: Into<String>>(&self, hostname: T) { |     pub fn resolve<T: Into<String>>(&self, hostname: T) { | ||||||
|         self.tx.send(hostname.into()).expect("Workers all died horribly"); |         self.tx.send(hostname.into()).expect("DNS workers all died unexpectedly"); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     pub fn resolved(&self) -> Result<Answer, channel::TryRecvError> { |     pub fn resolved(&self) -> Result<Answer, channel::TryRecvError> { | ||||||
| @@ -41,9 +54,8 @@ fn work(rx: spmc::Receiver<String>, notify: channel::Sender<Answer>) { | |||||||
|         let notify = worker.notify.as_ref().expect("Worker lost notify"); |         let notify = worker.notify.as_ref().expect("Worker lost notify"); | ||||||
|         while let Ok(host) = rx.recv() { |         while let Ok(host) = rx.recv() { | ||||||
|             debug!("resolve {:?}", host); |             debug!("resolve {:?}", host); | ||||||
|             let res = match (&*host, 80).to_socket_addrs().map(|mut i| i.next()) { |             let res = match (&*host, 80).to_socket_addrs().map(|i| IpAddrs{ iter: i }) { | ||||||
|                 Ok(Some(addr)) => (host, Ok(addr.ip())), |                 Ok(addrs) => (host, Ok(addrs)), | ||||||
|                 Ok(None) => (host, Err(io::Error::new(io::ErrorKind::Other, "no addresses found"))), |  | ||||||
|                 Err(e) => (host, Err(e)) |                 Err(e) => (host, Err(e)) | ||||||
|             }; |             }; | ||||||
|  |  | ||||||
|   | |||||||
| @@ -30,7 +30,6 @@ mod response; | |||||||
|  |  | ||||||
| /// A Client to make outgoing HTTP requests. | /// A Client to make outgoing HTTP requests. | ||||||
| pub struct Client<H> { | pub struct Client<H> { | ||||||
|     //handle: Option<thread::JoinHandle<()>>, |  | ||||||
|     tx: http::channel::Sender<Notify<H>>, |     tx: http::channel::Sender<Notify<H>>, | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -64,16 +63,6 @@ impl<H> Client<H> { | |||||||
|     pub fn configure() -> Config<DefaultConnector> { |     pub fn configure() -> Config<DefaultConnector> { | ||||||
|         Config::default() |         Config::default() | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /*TODO |  | ||||||
|     pub fn http() -> Config<HttpConnector> { |  | ||||||
|  |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     pub fn https() -> Config<HttpsConnector> { |  | ||||||
|  |  | ||||||
|     } |  | ||||||
|     */ |  | ||||||
| } | } | ||||||
|  |  | ||||||
| impl<H: Handler<<DefaultConnector as Connect>::Output>> Client<H> { | impl<H: Handler<<DefaultConnector as Connect>::Output>> Client<H> { | ||||||
| @@ -243,14 +232,6 @@ impl<H> fmt::Display for ClientError<H> { | |||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| /* |  | ||||||
| impl Drop for Client { |  | ||||||
|     fn drop(&mut self) { |  | ||||||
|         self.handle.take().map(|handle| handle.join()); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| */ |  | ||||||
|  |  | ||||||
| /// A trait to react to client events that happen for each message. | /// A trait to react to client events that happen for each message. | ||||||
| /// | /// | ||||||
| /// Each event handler returns it's desired `Next` action. | /// Each event handler returns it's desired `Next` action. | ||||||
| @@ -338,15 +319,16 @@ struct Context<K, H> { | |||||||
| } | } | ||||||
|  |  | ||||||
| impl<K: http::Key, H> Context<K, H> { | impl<K: http::Key, H> Context<K, H> { | ||||||
|     fn pop_queue(&mut self, key: &K) -> Queued<H> { |     fn pop_queue(&mut self, key: &K) -> Option<Queued<H>> { | ||||||
|         let mut should_remove = false; |         let mut should_remove = false; | ||||||
|         let queued = { |         let queued = { | ||||||
|             let mut vec = self.queue.get_mut(key).expect("handler not in queue for key"); |             self.queue.get_mut(key).map(|vec| { | ||||||
|             let queued = vec.remove(0); |                 let queued = vec.remove(0); | ||||||
|             if vec.is_empty() { |                 if vec.is_empty() { | ||||||
|                 should_remove = true; |                     should_remove = true; | ||||||
|             } |                 } | ||||||
|             queued |                 queued | ||||||
|  |             }) | ||||||
|         }; |         }; | ||||||
|         if should_remove { |         if should_remove { | ||||||
|             self.queue.remove(key); |             self.queue.remove(key); | ||||||
| @@ -379,16 +361,22 @@ impl<K: http::Key, H> Context<K, H> { | |||||||
| impl<K: http::Key, H: Handler<T>, T: Transport> http::MessageHandlerFactory<K, T> for Context<K, H> { | impl<K: http::Key, H: Handler<T>, T: Transport> http::MessageHandlerFactory<K, T> for Context<K, H> { | ||||||
|     type Output = Message<H, T>; |     type Output = Message<H, T>; | ||||||
|  |  | ||||||
|     fn create(&mut self, seed: http::Seed<K>) -> Self::Output { |     fn create(&mut self, seed: http::Seed<K>) -> Option<Self::Output> { | ||||||
|         let key = seed.key(); |         let key = seed.key(); | ||||||
|         let queued = self.pop_queue(key); |         self.pop_queue(key).map(|queued| { | ||||||
|         let (url, mut handler) = (queued.url, queued.handler); |             let (url, mut handler) = (queued.url, queued.handler); | ||||||
|         handler.on_control(seed.control()); |             handler.on_control(seed.control()); | ||||||
|         Message { |  | ||||||
|             handler: handler, |             Message { | ||||||
|             url: Some(url), |                 handler: handler, | ||||||
|             _marker: PhantomData, |                 url: Some(url), | ||||||
|         } |                 _marker: PhantomData, | ||||||
|  |             } | ||||||
|  |         }) | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     fn keep_alive_interest(&self) -> Next { | ||||||
|  |         Next::wait() | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -402,6 +390,7 @@ where C: Connect, | |||||||
|       C::Output: Transport, |       C::Output: Transport, | ||||||
|       H: Handler<C::Output> { |       H: Handler<C::Output> { | ||||||
|     Connector(C, http::channel::Receiver<Notify<H>>), |     Connector(C, http::channel::Receiver<Notify<H>>), | ||||||
|  |     Connecting((C::Key, C::Output)), | ||||||
|     Socket(http::Conn<C::Key, C::Output, Message<H, C::Output>>) |     Socket(http::Conn<C::Key, C::Output, Message<H, C::Output>>) | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -415,6 +404,7 @@ where | |||||||
|  |  | ||||||
| impl<C, H> rotor::Machine for ClientFsm<C, H> | impl<C, H> rotor::Machine for ClientFsm<C, H> | ||||||
| where C: Connect, | where C: Connect, | ||||||
|  |       C::Key: fmt::Debug, | ||||||
|       C::Output: Transport, |       C::Output: Transport, | ||||||
|       H: Handler<C::Output> { |       H: Handler<C::Output> { | ||||||
|     type Context = Context<C::Key, H>; |     type Context = Context<C::Key, H>; | ||||||
| @@ -422,24 +412,47 @@ where C: Connect, | |||||||
|  |  | ||||||
|     fn create(seed: Self::Seed, scope: &mut Scope<Self::Context>) -> rotor::Response<Self, rotor::Void> { |     fn create(seed: Self::Seed, scope: &mut Scope<Self::Context>) -> rotor::Response<Self, rotor::Void> { | ||||||
|         rotor_try!(scope.register(&seed.1, EventSet::writable(), PollOpt::level())); |         rotor_try!(scope.register(&seed.1, EventSet::writable(), PollOpt::level())); | ||||||
|         rotor::Response::ok( |         rotor::Response::ok(ClientFsm::Connecting(seed)) | ||||||
|             ClientFsm::Socket( |  | ||||||
|                 http::Conn::new(seed.0, seed.1, scope.notifier()) |  | ||||||
|                     .keep_alive(scope.keep_alive) |  | ||||||
|             ) |  | ||||||
|         ) |  | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     fn ready(self, events: EventSet, scope: &mut Scope<Self::Context>) -> rotor::Response<Self, Self::Seed> { |     fn ready(self, events: EventSet, scope: &mut Scope<Self::Context>) -> rotor::Response<Self, Self::Seed> { | ||||||
|         match self { |         match self { | ||||||
|             ClientFsm::Connector(..) => { |  | ||||||
|                 unreachable!("Connector can never be ready") |  | ||||||
|             }, |  | ||||||
|             ClientFsm::Socket(conn) => { |             ClientFsm::Socket(conn) => { | ||||||
|                 let res = conn.ready(events, scope); |                 let res = conn.ready(events, scope); | ||||||
|                 let now = scope.now(); |                 let now = scope.now(); | ||||||
|                 scope.conn_response(res, now) |                 scope.conn_response(res, now) | ||||||
|  |             }, | ||||||
|  |             ClientFsm::Connecting(mut seed) => { | ||||||
|  |                 if events.is_error() || events.is_hup() { | ||||||
|  |                     if let Some(err) = seed.1.take_socket_error().err() { | ||||||
|  |                         debug!("error while connecting: {:?}", err); | ||||||
|  |                         scope.pop_queue(&seed.0).map(move |mut queued| queued.handler.on_error(::Error::Io(err))); | ||||||
|  |                         rotor::Response::done() | ||||||
|  |                     } else { | ||||||
|  |                         trace!("connecting is_error, but no socket error"); | ||||||
|  |                         rotor::Response::ok(ClientFsm::Connecting(seed)) | ||||||
|  |                     } | ||||||
|  |                 } else if events.is_writable() { | ||||||
|  |                     if scope.queue.contains_key(&seed.0) { | ||||||
|  |                         trace!("connected and writable {:?}", seed.0); | ||||||
|  |                         rotor::Response::ok( | ||||||
|  |                             ClientFsm::Socket( | ||||||
|  |                                 http::Conn::new(seed.0, seed.1, Next::write().timeout(scope.connect_timeout), scope.notifier()) | ||||||
|  |                                     .keep_alive(scope.keep_alive) | ||||||
|  |                             ) | ||||||
|  |                         ) | ||||||
|  |                     } else { | ||||||
|  |                         trace!("connected, but queued handler is gone: {:?}", seed.0); // probably took too long connecting | ||||||
|  |                         rotor::Response::done() | ||||||
|  |                     } | ||||||
|  |                 } else { | ||||||
|  |                     // spurious? | ||||||
|  |                     rotor::Response::ok(ClientFsm::Connecting(seed)) | ||||||
|  |                 } | ||||||
|             } |             } | ||||||
|  |             ClientFsm::Connector(..) => { | ||||||
|  |                 unreachable!("Connector can never be ready") | ||||||
|  |             }, | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @@ -477,6 +490,7 @@ where C: Connect, | |||||||
|                     None => rotor::Response::ok(self) |                     None => rotor::Response::ok(self) | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|  |             ClientFsm::Connecting(..) => unreachable!(), | ||||||
|             ClientFsm::Socket(conn) => { |             ClientFsm::Socket(conn) => { | ||||||
|                 let res = conn.timeout(scope); |                 let res = conn.timeout(scope); | ||||||
|                 let now = scope.now(); |                 let now = scope.now(); | ||||||
| @@ -494,13 +508,15 @@ where C: Connect, | |||||||
|                 let res = conn.wakeup(scope); |                 let res = conn.wakeup(scope); | ||||||
|                 let now = scope.now(); |                 let now = scope.now(); | ||||||
|                 scope.conn_response(res, now) |                 scope.conn_response(res, now) | ||||||
|             } |             }, | ||||||
|  |             ClientFsm::Connecting(..) => unreachable!("connecting sockets should not be woken up") | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| impl<C, H> ClientFsm<C, H> | impl<C, H> ClientFsm<C, H> | ||||||
| where C: Connect, | where C: Connect, | ||||||
|  |       C::Key: fmt::Debug, | ||||||
|       C::Output: Transport, |       C::Output: Transport, | ||||||
|       H: Handler<C::Output> { |       H: Handler<C::Output> { | ||||||
|     fn connect(self, scope: &mut rotor::Scope<<Self as rotor::Machine>::Context>) -> rotor::Response<Self, <Self as rotor::Machine>::Seed> { |     fn connect(self, scope: &mut rotor::Scope<<Self as rotor::Machine>::Context>) -> rotor::Response<Self, <Self as rotor::Machine>::Seed> { | ||||||
| @@ -509,13 +525,12 @@ where C: Connect, | |||||||
|                 if let Some((key, res)) = connector.connected() { |                 if let Some((key, res)) = connector.connected() { | ||||||
|                     match res { |                     match res { | ||||||
|                         Ok(socket) => { |                         Ok(socket) => { | ||||||
|                             trace!("connected"); |                             trace!("connecting {:?}", key); | ||||||
|                             return rotor::Response::spawn(ClientFsm::Connector(connector, rx), (key, socket)); |                             return rotor::Response::spawn(ClientFsm::Connector(connector, rx), (key, socket)); | ||||||
|                         }, |                         }, | ||||||
|                         Err(e) => { |                         Err(e) => { | ||||||
|                             trace!("connected error = {:?}", e); |                             trace!("connect error = {:?}", e); | ||||||
|                             let mut queued = scope.pop_queue(&key); |                             scope.pop_queue(&key).map(|mut queued| queued.handler.on_error(::Error::Io(e))); | ||||||
|                             let _ = queued.handler.on_error(::Error::Io(e)); |  | ||||||
|                         } |                         } | ||||||
|                     } |                     } | ||||||
|                 } |                 } | ||||||
|   | |||||||
| @@ -163,7 +163,10 @@ impl<K: Key, T: Transport, H: MessageHandler<T>> ConnInner<K, T, H> { | |||||||
|                     Ok(decoder) => { |                     Ok(decoder) => { | ||||||
|                         trace!("decoder = {:?}", decoder); |                         trace!("decoder = {:?}", decoder); | ||||||
|                         let keep_alive = self.keep_alive_enabled && head.should_keep_alive(); |                         let keep_alive = self.keep_alive_enabled && head.should_keep_alive(); | ||||||
|                         let mut handler = scope.create(Seed(&self.key, &self.ctrl.0)); |                         let mut handler = match scope.create(Seed(&self.key, &self.ctrl.0)) { | ||||||
|  |                             Some(handler) => handler, | ||||||
|  |                             None => unreachable!() | ||||||
|  |                         }; | ||||||
|                         let next = handler.on_incoming(head, &self.transport); |                         let next = handler.on_incoming(head, &self.transport); | ||||||
|                         trace!("handler.on_incoming() -> {:?}", next); |                         trace!("handler.on_incoming() -> {:?}", next); | ||||||
|  |  | ||||||
| @@ -276,7 +279,7 @@ impl<K: Key, T: Transport, H: MessageHandler<T>> ConnInner<K, T, H> { | |||||||
|                 }; |                 }; | ||||||
|                 let mut s = State::Http1(http1); |                 let mut s = State::Http1(http1); | ||||||
|                 if let Some(next) = next { |                 if let Some(next) = next { | ||||||
|                     s.update(next); |                     s.update(next, &**scope); | ||||||
|                 } |                 } | ||||||
|                 trace!("Conn.on_readable State::Http1 completed, new state = State::{:?}", s); |                 trace!("Conn.on_readable State::Http1 completed, new state = State::{:?}", s); | ||||||
|  |  | ||||||
| @@ -304,7 +307,13 @@ impl<K: Key, T: Transport, H: MessageHandler<T>> ConnInner<K, T, H> { | |||||||
|                 // this could be a Client request, which writes first, so pay |                 // this could be a Client request, which writes first, so pay | ||||||
|                 // attention to the version written here, which will adjust |                 // attention to the version written here, which will adjust | ||||||
|                 // our internal state to Http1 or Http2 |                 // our internal state to Http1 or Http2 | ||||||
|                 let mut handler = scope.create(Seed(&self.key, &self.ctrl.0)); |                 let mut handler = match scope.create(Seed(&self.key, &self.ctrl.0)) { | ||||||
|  |                     Some(handler) => handler, | ||||||
|  |                     None => { | ||||||
|  |                         trace!("could not create handler {:?}", self.key); | ||||||
|  |                         return State::Closed; | ||||||
|  |                     } | ||||||
|  |                 }; | ||||||
|                 let mut head = http::MessageHead::default(); |                 let mut head = http::MessageHead::default(); | ||||||
|                 let interest = handler.on_outgoing(&mut head); |                 let interest = handler.on_outgoing(&mut head); | ||||||
|                 if head.version == HttpVersion::Http11 { |                 if head.version == HttpVersion::Http11 { | ||||||
| @@ -427,7 +436,7 @@ impl<K: Key, T: Transport, H: MessageHandler<T>> ConnInner<K, T, H> { | |||||||
|         }; |         }; | ||||||
|  |  | ||||||
|         if let Some(next) = next { |         if let Some(next) = next { | ||||||
|             state.update(next); |             state.update(next, &**scope); | ||||||
|         } |         } | ||||||
|         state |         state | ||||||
|     } |     } | ||||||
| @@ -439,7 +448,7 @@ impl<K: Key, T: Transport, H: MessageHandler<T>> ConnInner<K, T, H> { | |||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     fn on_error(&mut self, err: ::Error) { |     fn on_error<F>(&mut self, err: ::Error, factory: &F) where F: MessageHandlerFactory<K, T> { | ||||||
|         debug!("on_error err = {:?}", err); |         debug!("on_error err = {:?}", err); | ||||||
|         trace!("on_error state = {:?}", self.state); |         trace!("on_error state = {:?}", self.state); | ||||||
|         let next = match self.state { |         let next = match self.state { | ||||||
| @@ -447,7 +456,7 @@ impl<K: Key, T: Transport, H: MessageHandler<T>> ConnInner<K, T, H> { | |||||||
|             State::Http1(ref mut http1) => http1.handler.on_error(err), |             State::Http1(ref mut http1) => http1.handler.on_error(err), | ||||||
|             State::Closed => Next::remove(), |             State::Closed => Next::remove(), | ||||||
|         }; |         }; | ||||||
|         self.state.update(next); |         self.state.update(next, factory); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     fn on_readable<F>(&mut self, scope: &mut Scope<F>) |     fn on_readable<F>(&mut self, scope: &mut Scope<F>) | ||||||
| @@ -477,15 +486,15 @@ impl<K: Key, T: Transport, H: MessageHandler<T>> ConnInner<K, T, H> { | |||||||
| } | } | ||||||
|  |  | ||||||
| impl<K: Key, T: Transport, H: MessageHandler<T>> Conn<K, T, H> { | impl<K: Key, T: Transport, H: MessageHandler<T>> Conn<K, T, H> { | ||||||
|     pub fn new(key: K, transport: T, notify: rotor::Notifier) -> Conn<K, T, H> { |     pub fn new(key: K, transport: T, next: Next, notify: rotor::Notifier) -> Conn<K, T, H> { | ||||||
|         Conn(Box::new(ConnInner { |         Conn(Box::new(ConnInner { | ||||||
|             buf: Buffer::new(), |             buf: Buffer::new(), | ||||||
|             ctrl: channel::new(notify), |             ctrl: channel::new(notify), | ||||||
|             keep_alive_enabled: true, |             keep_alive_enabled: true, | ||||||
|             key: key, |             key: key, | ||||||
|             state: State::Init { |             state: State::Init { | ||||||
|                 interest: H::Message::initial_interest().interest, |                 interest: next.interest, | ||||||
|                 timeout: None, |                 timeout: next.timeout, | ||||||
|             }, |             }, | ||||||
|             transport: transport, |             transport: transport, | ||||||
|         })) |         })) | ||||||
| @@ -506,7 +515,7 @@ impl<K: Key, T: Transport, H: MessageHandler<T>> Conn<K, T, H> { | |||||||
|                     trace!("is_error, but not socket error"); |                     trace!("is_error, but not socket error"); | ||||||
|                     // spurious? |                     // spurious? | ||||||
|                 }, |                 }, | ||||||
|                 Err(e) => self.0.on_error(e.into()) |                 Err(e) => self.0.on_error(e.into(), &**scope) | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|  |  | ||||||
| @@ -570,7 +579,7 @@ impl<K: Key, T: Transport, H: MessageHandler<T>> Conn<K, T, H> { | |||||||
|             }, |             }, | ||||||
|             Err(e) => { |             Err(e) => { | ||||||
|                 trace!("error reregistering: {:?}", e); |                 trace!("error reregistering: {:?}", e); | ||||||
|                 self.0.on_error(e.into()); |                 self.0.on_error(e.into(), &**scope); | ||||||
|                 None |                 None | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
| @@ -580,7 +589,7 @@ impl<K: Key, T: Transport, H: MessageHandler<T>> Conn<K, T, H> { | |||||||
|     where F: MessageHandlerFactory<K, T, Output=H> { |     where F: MessageHandlerFactory<K, T, Output=H> { | ||||||
|         while let Ok(next) = self.0.ctrl.1.try_recv() { |         while let Ok(next) = self.0.ctrl.1.try_recv() { | ||||||
|             trace!("woke up with {:?}", next); |             trace!("woke up with {:?}", next); | ||||||
|             self.0.state.update(next); |             self.0.state.update(next, &**scope); | ||||||
|         } |         } | ||||||
|         self.ready(EventSet::readable() | EventSet::writable(), scope) |         self.ready(EventSet::readable() | EventSet::writable(), scope) | ||||||
|     } |     } | ||||||
| @@ -588,7 +597,7 @@ impl<K: Key, T: Transport, H: MessageHandler<T>> Conn<K, T, H> { | |||||||
|     pub fn timeout<F>(mut self, scope: &mut Scope<F>) -> Option<(Self, Option<Duration>)> |     pub fn timeout<F>(mut self, scope: &mut Scope<F>) -> Option<(Self, Option<Duration>)> | ||||||
|     where F: MessageHandlerFactory<K, T, Output=H> { |     where F: MessageHandlerFactory<K, T, Output=H> { | ||||||
|         //TODO: check if this was a spurious timeout? |         //TODO: check if this was a spurious timeout? | ||||||
|         self.0.on_error(::Error::Timeout); |         self.0.on_error(::Error::Timeout, &**scope); | ||||||
|         self.ready(EventSet::none(), scope) |         self.ready(EventSet::none(), scope) | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @@ -660,7 +669,7 @@ impl<H: MessageHandler<T>, T: Transport> fmt::Debug for State<H, T> { | |||||||
| } | } | ||||||
|  |  | ||||||
| impl<H: MessageHandler<T>, T: Transport> State<H, T> { | impl<H: MessageHandler<T>, T: Transport> State<H, T> { | ||||||
|     fn update(&mut self, next: Next) { |     fn update<F, K>(&mut self, next: Next, factory: &F) where F: MessageHandlerFactory<K, T>, K: Key { | ||||||
|         let timeout = next.timeout; |         let timeout = next.timeout; | ||||||
|         let state = mem::replace(self, State::Closed); |         let state = mem::replace(self, State::Closed); | ||||||
|         let new_state = match (state, next.interest) { |         let new_state = match (state, next.interest) { | ||||||
| @@ -730,10 +739,10 @@ impl<H: MessageHandler<T>, T: Transport> State<H, T> { | |||||||
|                 }; |                 }; | ||||||
|                 match (reading, writing) { |                 match (reading, writing) { | ||||||
|                     (Reading::KeepAlive, Writing::KeepAlive) => { |                     (Reading::KeepAlive, Writing::KeepAlive) => { | ||||||
|                         //XXX keepalive |                         let next = factory.keep_alive_interest(); | ||||||
|                         State::Init { |                         State::Init { | ||||||
|                         interest: H::Message::keep_alive_interest().interest, |                             interest: next.interest, | ||||||
|                             timeout: None, |                             timeout: next.timeout, | ||||||
|                         } |                         } | ||||||
|                     }, |                     }, | ||||||
|                     (reading, Writing::Chunk(chunk)) => { |                     (reading, Writing::Chunk(chunk)) => { | ||||||
| @@ -848,6 +857,10 @@ impl<H: MessageHandler<T>, T: Transport> State<H, T> { | |||||||
|             } |             } | ||||||
|         }; |         }; | ||||||
|         let new_state = match new_state { |         let new_state = match new_state { | ||||||
|  |             State::Init { interest, .. } => State::Init { | ||||||
|  |                 timeout: timeout, | ||||||
|  |                 interest: interest, | ||||||
|  |             }, | ||||||
|             State::Http1(mut http1) => { |             State::Http1(mut http1) => { | ||||||
|                 http1.timeout = timeout; |                 http1.timeout = timeout; | ||||||
|                 State::Http1(http1) |                 State::Http1(http1) | ||||||
| @@ -943,22 +956,13 @@ impl<'a, K: Key + 'a> Seed<'a, K> { | |||||||
| pub trait MessageHandlerFactory<K: Key, T: Transport> { | pub trait MessageHandlerFactory<K: Key, T: Transport> { | ||||||
|     type Output: MessageHandler<T>; |     type Output: MessageHandler<T>; | ||||||
|  |  | ||||||
|     fn create(&mut self, seed: Seed<K>) -> Self::Output; |     fn create(&mut self, seed: Seed<K>) -> Option<Self::Output>; | ||||||
|  |  | ||||||
|  |     fn keep_alive_interest(&self) -> Next; | ||||||
| } | } | ||||||
|  |  | ||||||
| impl<F, K, H, T> MessageHandlerFactory<K, T> for F | pub trait Key: Eq + Hash + Clone + fmt::Debug {} | ||||||
| where F: FnMut(Seed<K>) -> H, | impl<T: Eq + Hash + Clone + fmt::Debug> Key for T {} | ||||||
|       K: Key, |  | ||||||
|       H: MessageHandler<T>, |  | ||||||
|       T: Transport { |  | ||||||
|     type Output = H; |  | ||||||
|     fn create(&mut self, seed: Seed<K>) -> H { |  | ||||||
|         self(seed) |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| pub trait Key: Eq + Hash + Clone {} |  | ||||||
| impl<T: Eq + Hash + Clone> Key for T {} |  | ||||||
|  |  | ||||||
| #[cfg(test)] | #[cfg(test)] | ||||||
| mod tests { | mod tests { | ||||||
|   | |||||||
| @@ -4,7 +4,7 @@ use std::io::Write; | |||||||
| use httparse; | use httparse; | ||||||
|  |  | ||||||
| use header::{self, Headers, ContentLength, TransferEncoding}; | use header::{self, Headers, ContentLength, TransferEncoding}; | ||||||
| use http::{MessageHead, RawStatus, Http1Message, ParseResult, Next, ServerMessage, ClientMessage, Next_, RequestLine}; | use http::{MessageHead, RawStatus, Http1Message, ParseResult, ServerMessage, ClientMessage, RequestLine}; | ||||||
| use http::h1::{Encoder, Decoder}; | use http::h1::{Encoder, Decoder}; | ||||||
| use method::Method; | use method::Method; | ||||||
| use status::StatusCode; | use status::StatusCode; | ||||||
| @@ -27,14 +27,6 @@ impl Http1Message for ServerMessage { | |||||||
|     type Incoming = RequestLine; |     type Incoming = RequestLine; | ||||||
|     type Outgoing = StatusCode; |     type Outgoing = StatusCode; | ||||||
|  |  | ||||||
|     fn initial_interest() -> Next { |  | ||||||
|         Next::new(Next_::Read) |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     fn keep_alive_interest() -> Next { |  | ||||||
|         Next::new(Next_::Read) |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     fn parse(buf: &[u8]) -> ParseResult<RequestLine> { |     fn parse(buf: &[u8]) -> ParseResult<RequestLine> { | ||||||
|         let mut headers = [httparse::EMPTY_HEADER; MAX_HEADERS]; |         let mut headers = [httparse::EMPTY_HEADER; MAX_HEADERS]; | ||||||
|         trace!("Request.parse([Header; {}], [u8; {}])", headers.len(), buf.len()); |         trace!("Request.parse([Header; {}], [u8; {}])", headers.len(), buf.len()); | ||||||
| @@ -113,15 +105,6 @@ impl Http1Message for ClientMessage { | |||||||
|     type Incoming = RawStatus; |     type Incoming = RawStatus; | ||||||
|     type Outgoing = RequestLine; |     type Outgoing = RequestLine; | ||||||
|  |  | ||||||
|  |  | ||||||
|     fn initial_interest() -> Next { |  | ||||||
|         Next::new(Next_::Write) |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     fn keep_alive_interest() -> Next { |  | ||||||
|         Next::new(Next_::Wait) |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     fn parse(buf: &[u8]) -> ParseResult<RawStatus> { |     fn parse(buf: &[u8]) -> ParseResult<RawStatus> { | ||||||
|         let mut headers = [httparse::EMPTY_HEADER; MAX_HEADERS]; |         let mut headers = [httparse::EMPTY_HEADER; MAX_HEADERS]; | ||||||
|         trace!("Response.parse([Header; {}], [u8; {}])", headers.len(), buf.len()); |         trace!("Response.parse([Header; {}], [u8; {}])", headers.len(), buf.len()); | ||||||
|   | |||||||
| @@ -280,13 +280,9 @@ pub enum ClientMessage {} | |||||||
| pub trait Http1Message { | pub trait Http1Message { | ||||||
|     type Incoming; |     type Incoming; | ||||||
|     type Outgoing: Default; |     type Outgoing: Default; | ||||||
|     //TODO: replace with associated const when stable |  | ||||||
|     fn initial_interest() -> Next; |  | ||||||
|     fn keep_alive_interest() -> Next; |  | ||||||
|     fn parse(bytes: &[u8]) -> ParseResult<Self::Incoming>; |     fn parse(bytes: &[u8]) -> ParseResult<Self::Incoming>; | ||||||
|     fn decoder(head: &MessageHead<Self::Incoming>) -> ::Result<h1::Decoder>; |     fn decoder(head: &MessageHead<Self::Incoming>) -> ::Result<h1::Decoder>; | ||||||
|     fn encode(head: MessageHead<Self::Outgoing>, dst: &mut Vec<u8>) -> h1::Encoder; |     fn encode(head: MessageHead<Self::Outgoing>, dst: &mut Vec<u8>) -> h1::Encoder; | ||||||
|  |  | ||||||
| } | } | ||||||
|  |  | ||||||
| /// Used to signal desired events when working with asynchronous IO. | /// Used to signal desired events when working with asynchronous IO. | ||||||
|   | |||||||
| @@ -167,8 +167,12 @@ struct Context<F> { | |||||||
| impl<F: HandlerFactory<T>, T: Transport> http::MessageHandlerFactory<(), T> for Context<F> { | impl<F: HandlerFactory<T>, T: Transport> http::MessageHandlerFactory<(), T> for Context<F> { | ||||||
|     type Output = message::Message<F::Output, T>; |     type Output = message::Message<F::Output, T>; | ||||||
|  |  | ||||||
|     fn create(&mut self, seed: http::Seed<()>) -> Self::Output { |     fn create(&mut self, seed: http::Seed<()>) -> Option<Self::Output> { | ||||||
|         message::Message::new(self.factory.create(seed.control())) |         Some(message::Message::new(self.factory.create(seed.control()))) | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     fn keep_alive_interest(&self) -> Next { | ||||||
|  |         Next::read() | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -191,7 +195,7 @@ where A: Accept, | |||||||
|         rotor_try!(scope.register(&seed, EventSet::readable(), PollOpt::level())); |         rotor_try!(scope.register(&seed, EventSet::readable(), PollOpt::level())); | ||||||
|         rotor::Response::ok( |         rotor::Response::ok( | ||||||
|             ServerFsm::Conn( |             ServerFsm::Conn( | ||||||
|                 http::Conn::new((), seed, scope.notifier()) |                 http::Conn::new((), seed, Next::read(), scope.notifier()) | ||||||
|                     .keep_alive(scope.keep_alive) |                     .keep_alive(scope.keep_alive) | ||||||
|             ) |             ) | ||||||
|         ) |         ) | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user