fix inverted split for DATA frame padding (#330)
This commit is contained in:
		
				
					committed by
					
						 Carl Lerche
						Carl Lerche
					
				
			
			
				
	
			
			
			
						parent
						
							1a8015da4a
						
					
				
				
					commit
					e656c42353
				
			| @@ -63,6 +63,18 @@ impl<T> Data<T> { | |||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     /// Returns whther the `PADDED` flag is set on this frame. | ||||||
|  |     #[cfg(feature = "unstable")] | ||||||
|  |     pub fn is_padded(&self) -> bool { | ||||||
|  |         self.flags.is_padded() | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /// Sets the value for the `PADDED` flag on this frame. | ||||||
|  |     #[cfg(feature = "unstable")] | ||||||
|  |     pub fn set_padded(&mut self) { | ||||||
|  |         self.flags.set_padded(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|     /// Returns a reference to this frame's payload. |     /// Returns a reference to this frame's payload. | ||||||
|     /// |     /// | ||||||
|     /// This does **not** include any padding that might have been originally |     /// This does **not** include any padding that might have been originally | ||||||
| @@ -192,6 +204,11 @@ impl DataFlags { | |||||||
|     fn is_padded(&self) -> bool { |     fn is_padded(&self) -> bool { | ||||||
|         self.0 & PADDED == PADDED |         self.0 & PADDED == PADDED | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     #[cfg(feature = "unstable")] | ||||||
|  |     fn set_padded(&mut self) { | ||||||
|  |         self.0 |= PADDED | ||||||
|  |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| impl Default for DataFlags { | impl Default for DataFlags { | ||||||
|   | |||||||
| @@ -15,7 +15,8 @@ use bytes::Bytes; | |||||||
| /// If the padded payload is invalid (e.g. the length of the padding is equal | /// If the padded payload is invalid (e.g. the length of the padding is equal | ||||||
| /// to the total length), returns `None`. | /// to the total length), returns `None`. | ||||||
| pub fn strip_padding(payload: &mut Bytes) -> Result<u8, Error> { | pub fn strip_padding(payload: &mut Bytes) -> Result<u8, Error> { | ||||||
|     if payload.len() == 0 { |     let payload_len = payload.len(); | ||||||
|  |     if payload_len == 0 { | ||||||
|         // If this is the case, the frame is invalid as no padding length can be |         // If this is the case, the frame is invalid as no padding length can be | ||||||
|         // extracted, even though the frame should be padded. |         // extracted, even though the frame should be padded. | ||||||
|         return Err(Error::TooMuchPadding); |         return Err(Error::TooMuchPadding); | ||||||
| @@ -23,14 +24,14 @@ pub fn strip_padding(payload: &mut Bytes) -> Result<u8, Error> { | |||||||
|  |  | ||||||
|     let pad_len = payload[0] as usize; |     let pad_len = payload[0] as usize; | ||||||
|  |  | ||||||
|     if pad_len >= payload.len() { |     if pad_len >= payload_len { | ||||||
|         // This is invalid: the padding length MUST be less than the |         // This is invalid: the padding length MUST be less than the | ||||||
|         // total frame size. |         // total frame size. | ||||||
|         return Err(Error::TooMuchPadding); |         return Err(Error::TooMuchPadding); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     let _ = payload.split_to(1); |     let _ = payload.split_to(1); | ||||||
|     let _ = payload.split_off(pad_len); |     let _ = payload.split_off(payload_len - pad_len - 1); | ||||||
|  |  | ||||||
|     Ok(pad_len as u8) |     Ok(pad_len as u8) | ||||||
| } | } | ||||||
|   | |||||||
| @@ -180,6 +180,11 @@ impl From<Mock<frame::Headers>> for SendFrame { | |||||||
| // Data helpers | // Data helpers | ||||||
|  |  | ||||||
| impl Mock<frame::Data> { | impl Mock<frame::Data> { | ||||||
|  |     pub fn padded(mut self) -> Self { | ||||||
|  |         self.0.set_padded(); | ||||||
|  |         self | ||||||
|  |     } | ||||||
|  |  | ||||||
|     pub fn eos(mut self) -> Self { |     pub fn eos(mut self) -> Self { | ||||||
|         self.0.set_end_stream(true); |         self.0.set_end_stream(true); | ||||||
|         self |         self | ||||||
| @@ -190,9 +195,13 @@ impl From<Mock<frame::Data>> for SendFrame { | |||||||
|     fn from(src: Mock<frame::Data>) -> Self { |     fn from(src: Mock<frame::Data>) -> Self { | ||||||
|         let id = src.0.stream_id(); |         let id = src.0.stream_id(); | ||||||
|         let eos = src.0.is_end_stream(); |         let eos = src.0.is_end_stream(); | ||||||
|  |         let is_padded = src.0.is_padded(); | ||||||
|         let payload = src.0.into_payload(); |         let payload = src.0.into_payload(); | ||||||
|         let mut frame = frame::Data::new(id, payload.into_buf()); |         let mut frame = frame::Data::new(id, payload.into_buf()); | ||||||
|         frame.set_end_stream(eos); |         frame.set_end_stream(eos); | ||||||
|  |         if is_padded { | ||||||
|  |             frame.set_padded(); | ||||||
|  |         } | ||||||
|         Frame::Data(frame) |         Frame::Data(frame) | ||||||
|     } |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -72,16 +72,16 @@ fn read_data_end_stream() { | |||||||
| fn read_data_padding() { | fn read_data_padding() { | ||||||
|     let mut codec = raw_codec! { |     let mut codec = raw_codec! { | ||||||
|         read => [ |         read => [ | ||||||
|             0, 0, 11, 0, 0x8, 0, 0, 0, 1, |             0, 0, 16, 0, 0x8, 0, 0, 0, 1, | ||||||
|             5,       // Pad length |             5,       // Pad length | ||||||
|             "hello", // Data |             "helloworld", // Data | ||||||
|             "world", // Padding |             "\0\0\0\0\0", // Padding | ||||||
|         ]; |         ]; | ||||||
|     }; |     }; | ||||||
|  |  | ||||||
|     let data = poll_frame!(Data, codec); |     let data = poll_frame!(Data, codec); | ||||||
|     assert_eq!(data.stream_id(), 1); |     assert_eq!(data.stream_id(), 1); | ||||||
|     assert_eq!(data.payload(), &b"hello"[..]); |     assert_eq!(data.payload(), &b"helloworld"[..]); | ||||||
|     assert!(!data.is_end_stream()); |     assert!(!data.is_end_stream()); | ||||||
|  |  | ||||||
|     assert_closed!(codec); |     assert_closed!(codec); | ||||||
|   | |||||||
| @@ -1361,3 +1361,60 @@ fn reset_stream_waiting_for_capacity() { | |||||||
|     client.join(srv).wait().unwrap(); |     client.join(srv).wait().unwrap(); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | #[test] | ||||||
|  | fn data_padding() { | ||||||
|  |     let _ = ::env_logger::try_init(); | ||||||
|  |     let (io, srv) = mock::new(); | ||||||
|  |  | ||||||
|  |     let mut body = Vec::new(); | ||||||
|  |     body.push(5); | ||||||
|  |     body.extend_from_slice(&[b'z'; 100][..]); | ||||||
|  |     body.extend_from_slice(&[b'0'; 5][..]); | ||||||
|  |  | ||||||
|  |     let srv = srv.assert_client_handshake() | ||||||
|  |         .unwrap() | ||||||
|  |         .recv_settings() | ||||||
|  |         .recv_frame( | ||||||
|  |             frames::headers(1) | ||||||
|  |                 .request("GET", "http://example.com/") | ||||||
|  |                 .eos() | ||||||
|  |         ) | ||||||
|  |         .send_frame( | ||||||
|  |             frames::headers(1) | ||||||
|  |                 .response(200) | ||||||
|  |                 .field("content-length", 100) | ||||||
|  |         ) | ||||||
|  |         .send_frame( | ||||||
|  |             frames::data(1, body) | ||||||
|  |                 .padded() | ||||||
|  |                 .eos() | ||||||
|  |         ) | ||||||
|  |         .close(); | ||||||
|  |  | ||||||
|  |     let h2 = client::handshake(io) | ||||||
|  |         .expect("handshake") | ||||||
|  |         .and_then(|(mut client, conn)| { | ||||||
|  |             let request = Request::builder() | ||||||
|  |                 .method(Method::GET) | ||||||
|  |                 .uri("http://example.com/") | ||||||
|  |                 .body(()) | ||||||
|  |                 .unwrap(); | ||||||
|  |  | ||||||
|  |             // first request is allowed | ||||||
|  |             let (response, _) = client.send_request(request, true).unwrap(); | ||||||
|  |             let fut = response | ||||||
|  |                 .and_then(|resp| { | ||||||
|  |                     assert_eq!(resp.status(), StatusCode::OK); | ||||||
|  |                     let body = resp.into_body(); | ||||||
|  |                     body.concat2() | ||||||
|  |                 }) | ||||||
|  |                 .map(|bytes| { | ||||||
|  |                     assert_eq!(bytes.len(), 100); | ||||||
|  |                 }); | ||||||
|  |             conn | ||||||
|  |                 .expect("client") | ||||||
|  |                 .join(fut.expect("response")) | ||||||
|  |         }); | ||||||
|  |  | ||||||
|  |     h2.join(srv).wait().expect("wait"); | ||||||
|  | } | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user