fix(client): handle when DNS resolves after a timeout triggers
Closes #848
This commit is contained in:
		| @@ -163,7 +163,10 @@ impl<K: Key, T: Transport, H: MessageHandler<T>> ConnInner<K, T, H> { | ||||
|                     Ok(decoder) => { | ||||
|                         trace!("decoder = {:?}", decoder); | ||||
|                         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); | ||||
|                         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); | ||||
|                 if let Some(next) = next { | ||||
|                     s.update(next); | ||||
|                     s.update(next, &**scope); | ||||
|                 } | ||||
|                 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 | ||||
|                 // attention to the version written here, which will adjust | ||||
|                 // 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 interest = handler.on_outgoing(&mut head); | ||||
|                 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 { | ||||
|             state.update(next); | ||||
|             state.update(next, &**scope); | ||||
|         } | ||||
|         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); | ||||
|         trace!("on_error state = {:?}", 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::Closed => Next::remove(), | ||||
|         }; | ||||
|         self.state.update(next); | ||||
|         self.state.update(next, factory); | ||||
|     } | ||||
|  | ||||
|     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> { | ||||
|     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 { | ||||
|             buf: Buffer::new(), | ||||
|             ctrl: channel::new(notify), | ||||
|             keep_alive_enabled: true, | ||||
|             key: key, | ||||
|             state: State::Init { | ||||
|                 interest: H::Message::initial_interest().interest, | ||||
|                 timeout: None, | ||||
|                 interest: next.interest, | ||||
|                 timeout: next.timeout, | ||||
|             }, | ||||
|             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"); | ||||
|                     // 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) => { | ||||
|                 trace!("error reregistering: {:?}", e); | ||||
|                 self.0.on_error(e.into()); | ||||
|                 self.0.on_error(e.into(), &**scope); | ||||
|                 None | ||||
|             } | ||||
|         } | ||||
| @@ -580,7 +589,7 @@ impl<K: Key, T: Transport, H: MessageHandler<T>> Conn<K, T, H> { | ||||
|     where F: MessageHandlerFactory<K, T, Output=H> { | ||||
|         while let Ok(next) = self.0.ctrl.1.try_recv() { | ||||
|             trace!("woke up with {:?}", next); | ||||
|             self.0.state.update(next); | ||||
|             self.0.state.update(next, &**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>)> | ||||
|     where F: MessageHandlerFactory<K, T, Output=H> { | ||||
|         //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) | ||||
|     } | ||||
|  | ||||
| @@ -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> { | ||||
|     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 state = mem::replace(self, State::Closed); | ||||
|         let new_state = match (state, next.interest) { | ||||
| @@ -730,10 +739,10 @@ impl<H: MessageHandler<T>, T: Transport> State<H, T> { | ||||
|                 }; | ||||
|                 match (reading, writing) { | ||||
|                     (Reading::KeepAlive, Writing::KeepAlive) => { | ||||
|                         //XXX keepalive | ||||
|                         let next = factory.keep_alive_interest(); | ||||
|                         State::Init { | ||||
|                         interest: H::Message::keep_alive_interest().interest, | ||||
|                             timeout: None, | ||||
|                             interest: next.interest, | ||||
|                             timeout: next.timeout, | ||||
|                         } | ||||
|                     }, | ||||
|                     (reading, Writing::Chunk(chunk)) => { | ||||
| @@ -848,6 +857,10 @@ impl<H: MessageHandler<T>, T: Transport> State<H, T> { | ||||
|             } | ||||
|         }; | ||||
|         let new_state = match new_state { | ||||
|             State::Init { interest, .. } => State::Init { | ||||
|                 timeout: timeout, | ||||
|                 interest: interest, | ||||
|             }, | ||||
|             State::Http1(mut http1) => { | ||||
|                 http1.timeout = timeout; | ||||
|                 State::Http1(http1) | ||||
| @@ -943,22 +956,13 @@ impl<'a, K: Key + 'a> Seed<'a, K> { | ||||
| pub trait MessageHandlerFactory<K: Key, T: Transport> { | ||||
|     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 | ||||
| where F: FnMut(Seed<K>) -> H, | ||||
|       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 {} | ||||
| pub trait Key: Eq + Hash + Clone + fmt::Debug {} | ||||
| impl<T: Eq + Hash + Clone + fmt::Debug> Key for T {} | ||||
|  | ||||
| #[cfg(test)] | ||||
| mod tests { | ||||
|   | ||||
| @@ -4,7 +4,7 @@ use std::io::Write; | ||||
| use httparse; | ||||
|  | ||||
| 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 method::Method; | ||||
| use status::StatusCode; | ||||
| @@ -27,14 +27,6 @@ impl Http1Message for ServerMessage { | ||||
|     type Incoming = RequestLine; | ||||
|     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> { | ||||
|         let mut headers = [httparse::EMPTY_HEADER; MAX_HEADERS]; | ||||
|         trace!("Request.parse([Header; {}], [u8; {}])", headers.len(), buf.len()); | ||||
| @@ -113,15 +105,6 @@ impl Http1Message for ClientMessage { | ||||
|     type Incoming = RawStatus; | ||||
|     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> { | ||||
|         let mut headers = [httparse::EMPTY_HEADER; MAX_HEADERS]; | ||||
|         trace!("Response.parse([Header; {}], [u8; {}])", headers.len(), buf.len()); | ||||
|   | ||||
| @@ -280,13 +280,9 @@ pub enum ClientMessage {} | ||||
| pub trait Http1Message { | ||||
|     type Incoming; | ||||
|     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 decoder(head: &MessageHead<Self::Incoming>) -> ::Result<h1::Decoder>; | ||||
|     fn encode(head: MessageHead<Self::Outgoing>, dst: &mut Vec<u8>) -> h1::Encoder; | ||||
|  | ||||
| } | ||||
|  | ||||
| /// Used to signal desired events when working with asynchronous IO. | ||||
|   | ||||
		Reference in New Issue
	
	Block a user