Misc protocol fixes
* Verify contiuation frame stream ID * Fix sending RST_STREAM in certain cases.
This commit is contained in:
		| @@ -133,6 +133,11 @@ impl<T> FramedRead<T> { | ||||
|  | ||||
|                 match partial.frame { | ||||
|                     Continuable::Headers(mut frame) => { | ||||
|                         // The stream identifiers must match | ||||
|                         if frame.stream_id() != head.stream_id() { | ||||
|                             return Err(ProtocolError.into()); | ||||
|                         } | ||||
|  | ||||
|                         frame.load_hpack(partial.buf, &mut self.hpack)?; | ||||
|                         frame.into() | ||||
|                     } | ||||
|   | ||||
| @@ -1,4 +1,5 @@ | ||||
| use super::*; | ||||
| use super::store::Resolve; | ||||
|  | ||||
| use bytes::buf::Take; | ||||
| use futures::Sink; | ||||
| @@ -179,13 +180,23 @@ impl<B> Prioritize<B> | ||||
|     { | ||||
|         // Update the connection's window | ||||
|         self.flow.inc_window(inc)?; | ||||
|  | ||||
|         self.assign_connection_capacity(inc, store); | ||||
|         Ok(()) | ||||
|     } | ||||
|  | ||||
|     pub fn assign_connection_capacity<R>(&mut self, | ||||
|                                          inc: WindowSize, | ||||
|                                          store: &mut R) | ||||
|         where R: Resolve<B> | ||||
|     { | ||||
|         self.flow.assign_capacity(inc); | ||||
|  | ||||
|         // Assign newly acquired capacity to streams pending capacity. | ||||
|         while self.flow.available() > 0 { | ||||
|             let mut stream = match self.pending_capacity.pop(store) { | ||||
|                 Some(stream) => stream, | ||||
|                 None => return Ok(()), | ||||
|                 None => return, | ||||
|             }; | ||||
|  | ||||
|             // Try to assign capacity to the stream. This will also re-queue the | ||||
| @@ -193,8 +204,6 @@ impl<B> Prioritize<B> | ||||
|             // the capacity request. | ||||
|             self.try_assign_capacity(&mut stream); | ||||
|         } | ||||
|  | ||||
|         Ok(()) | ||||
|     } | ||||
|  | ||||
|     /// Request capacity to send data | ||||
|   | ||||
| @@ -101,7 +101,10 @@ impl<B> Send<B> where B: Buf { | ||||
|         Ok(()) | ||||
|     } | ||||
|  | ||||
|     pub fn send_reset(&mut self, reason: Reason, | ||||
|     /// This is called by the user to send a reset and should not be called | ||||
|     /// by internal state transitions. Use `reset_stream` for that. | ||||
|     pub fn send_reset(&mut self, | ||||
|                       reason: Reason, | ||||
|                       stream: &mut store::Ptr<B>, | ||||
|                       task: &mut Option<Task>) | ||||
|         -> Result<(), ConnectionError> | ||||
| @@ -111,17 +114,44 @@ impl<B> Send<B> where B: Buf { | ||||
|             return Err(InactiveStreamId.into()) | ||||
|         } | ||||
|  | ||||
|         stream.state.send_reset(reason)?; | ||||
|         self.reset_stream(reason, stream, task); | ||||
|         Ok(()) | ||||
|     } | ||||
|  | ||||
|     fn reset_stream(&mut self, | ||||
|                     reason: Reason, | ||||
|                     stream: &mut store::Ptr<B>, | ||||
|                     task: &mut Option<Task>) | ||||
|     { | ||||
|         if stream.state.is_reset() { | ||||
|             // Don't double reset | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         // If closed AND the send queue is flushed, then the stream cannot be | ||||
|         // reset either | ||||
|         if stream.state.is_closed() && stream.pending_send.is_empty() { | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         // Transition the state | ||||
|         stream.state.set_reset(reason); | ||||
|  | ||||
|         // Clear all pending outbound frames | ||||
|         self.prioritize.clear_queue(stream); | ||||
|  | ||||
|         // Reclaim all capacity assigned to the stream and re-assign it to the | ||||
|         // connection | ||||
|         let available = stream.send_flow.available(); | ||||
|         stream.send_flow.claim_capacity(available); | ||||
|  | ||||
|         let frame = frame::Reset::new(stream.id, reason); | ||||
|  | ||||
|         // TODO: This could impact connection level flow control. | ||||
|         self.prioritize.clear_queue(stream); | ||||
|  | ||||
|         trace!("send_reset -- queueing; frame={:?}", frame); | ||||
|         self.prioritize.queue_frame(frame.into(), stream, task); | ||||
|  | ||||
|         Ok(()) | ||||
|         // Re-assign all capacity to the connection | ||||
|         self.prioritize.assign_connection_capacity(available, stream); | ||||
|     } | ||||
|  | ||||
|     pub fn send_data(&mut self, | ||||
| @@ -210,7 +240,7 @@ impl<B> Send<B> where B: Buf { | ||||
|     { | ||||
|         if let Err(e) = self.prioritize.recv_stream_window_update(sz, stream) { | ||||
|             debug!("recv_stream_window_update !!; err={:?}", e); | ||||
|             self.send_reset(FlowControlError.into(), stream, task)?; | ||||
|             self.reset_stream(FlowControlError.into(), stream, task); | ||||
|         } | ||||
|  | ||||
|         Ok(()) | ||||
|   | ||||
| @@ -241,16 +241,17 @@ impl State { | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /// Indicates that the local side will not send more data to the local. | ||||
|     pub fn send_reset(&mut self, reason: Reason) -> Result<(), ConnectionError> { | ||||
|     /// Set the stream state to reset | ||||
|     pub fn set_reset(&mut self, reason: Reason) { | ||||
|         debug_assert!(!self.is_reset()); | ||||
|         self.inner = Closed(Some(Cause::Proto(reason))); | ||||
|     } | ||||
|  | ||||
|     /// Returns true if the stream is already reset. | ||||
|     pub fn is_reset(&self) -> bool { | ||||
|         match self.inner { | ||||
|             Idle => Err(ProtocolError.into()), | ||||
|             Closed(..) => Ok(()), | ||||
|             _ => { | ||||
|                 trace!("send_reset: => Closed"); | ||||
|                 self.inner = Closed(Some(Cause::Proto(reason))); | ||||
|                 Ok(()) | ||||
|             } | ||||
|             Closed(Some(_)) => true, | ||||
|             _ => false, | ||||
|         } | ||||
|     } | ||||
|  | ||||
|   | ||||
| @@ -62,6 +62,10 @@ pub(super) struct VacantEntry<'a, B: 'a> { | ||||
|     slab: &'a mut slab::Slab<Stream<B>>, | ||||
| } | ||||
|  | ||||
| pub(super) trait Resolve<B> { | ||||
|     fn resolve(&mut self, key: Key) -> Ptr<B>; | ||||
| } | ||||
|  | ||||
| // ===== impl Store ===== | ||||
|  | ||||
| impl<B> Store<B> { | ||||
| @@ -72,13 +76,6 @@ impl<B> Store<B> { | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     pub fn resolve(&mut self, key: Key) -> Ptr<B> { | ||||
|         Ptr { | ||||
|             key: key, | ||||
|             slab: &mut self.slab, | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     pub fn find_mut(&mut self, id: &StreamId) -> Option<Ptr<B>> { | ||||
|         if let Some(&key) = self.ids.get(id) { | ||||
|             Some(Ptr { | ||||
| @@ -132,6 +129,15 @@ impl<B> Store<B> { | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl<B> Resolve<B> for Store<B> { | ||||
|     fn resolve(&mut self, key: Key) -> Ptr<B> { | ||||
|         Ptr { | ||||
|             key: key, | ||||
|             slab: &mut self.slab, | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl<B> ops::Index<Key> for Store<B> { | ||||
|     type Output = Stream<B>; | ||||
|  | ||||
| @@ -209,7 +215,8 @@ impl<B, N> Queue<B, N> | ||||
|         true | ||||
|     } | ||||
|  | ||||
|     pub fn pop<'a>(&mut self, store: &'a mut Store<B>) -> Option<store::Ptr<'a, B>> | ||||
|     pub fn pop<'a, R>(&mut self, store: &'a mut R) -> Option<store::Ptr<'a, B>> | ||||
|         where R: Resolve<B> | ||||
|     { | ||||
|         if let Some(mut idxs) = self.indices { | ||||
|             let mut stream = store.resolve(idxs.head); | ||||
| @@ -238,8 +245,10 @@ impl<'a, B: 'a> Ptr<'a, B> { | ||||
|     pub fn key(&self) -> Key { | ||||
|         self.key | ||||
|     } | ||||
| } | ||||
|  | ||||
|     pub fn resolve(&mut self, key: Key) -> Ptr<B> { | ||||
| impl<'a, B: 'a> Resolve<B> for Ptr<'a, B> { | ||||
|     fn resolve(&mut self, key: Key) -> Ptr<B> { | ||||
|         Ptr { | ||||
|             key: key, | ||||
|             slab: &mut *self.slab, | ||||
|   | ||||
| @@ -1,6 +1,7 @@ | ||||
| use {client, server, HeaderMap}; | ||||
| use proto::*; | ||||
| use super::*; | ||||
| use super::store::Resolve; | ||||
|  | ||||
| use std::sync::{Arc, Mutex}; | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user