Notify send_tasks when there is a connection error (#231)
This commit is contained in:
		
				
					committed by
					
						 Carl Lerche
						Carl Lerche
					
				
			
			
				
	
			
			
			
						parent
						
							ad90f9b97b
						
					
				
				
					commit
					e3c6e0c590
				
			| @@ -699,9 +699,6 @@ impl Prioritize { | |||||||
|  |  | ||||||
|                 counts.inc_num_send_streams(); |                 counts.inc_num_send_streams(); | ||||||
|                 self.pending_send.push(&mut stream); |                 self.pending_send.push(&mut stream); | ||||||
|                 if let Some(task) = stream.open_task.take() { |  | ||||||
|                     task.notify(); |  | ||||||
|                 } |  | ||||||
|             } else { |             } else { | ||||||
|                 return; |                 return; | ||||||
|             } |             } | ||||||
|   | |||||||
| @@ -595,6 +595,7 @@ impl Recv { | |||||||
|     ) -> Result<(), RecvError> { |     ) -> Result<(), RecvError> { | ||||||
|         // Notify the stream |         // Notify the stream | ||||||
|         stream.state.recv_reset(frame.reason()); |         stream.state.recv_reset(frame.reason()); | ||||||
|  |         stream.notify_send(); | ||||||
|         stream.notify_recv(); |         stream.notify_recv(); | ||||||
|         Ok(()) |         Ok(()) | ||||||
|     } |     } | ||||||
| @@ -605,6 +606,7 @@ impl Recv { | |||||||
|         stream.state.recv_err(err); |         stream.state.recv_err(err); | ||||||
|  |  | ||||||
|         // If a receiver is waiting, notify it |         // If a receiver is waiting, notify it | ||||||
|  |         stream.notify_send(); | ||||||
|         stream.notify_recv(); |         stream.notify_recv(); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -64,9 +64,6 @@ pub(super) struct Stream { | |||||||
|     /// Set to true when the stream is pending to be opened |     /// Set to true when the stream is pending to be opened | ||||||
|     pub is_pending_open: bool, |     pub is_pending_open: bool, | ||||||
|  |  | ||||||
|     /// Task tracking when stream can be "opened", or initially sent to socket. |  | ||||||
|     pub open_task: Option<task::Task>, |  | ||||||
|  |  | ||||||
|     // ===== Fields related to receiving ===== |     // ===== Fields related to receiving ===== | ||||||
|     /// Next node in the accept linked list |     /// Next node in the accept linked list | ||||||
|     pub next_pending_accept: Option<store::Key>, |     pub next_pending_accept: Option<store::Key>, | ||||||
| @@ -168,7 +165,6 @@ impl Stream { | |||||||
|             send_capacity_inc: false, |             send_capacity_inc: false, | ||||||
|             is_pending_open: false, |             is_pending_open: false, | ||||||
|             next_open: None, |             next_open: None, | ||||||
|             open_task: None, |  | ||||||
|  |  | ||||||
|             // ===== Fields related to receiving ===== |             // ===== Fields related to receiving ===== | ||||||
|             next_pending_accept: None, |             next_pending_accept: None, | ||||||
|   | |||||||
| @@ -282,6 +282,84 @@ fn request_over_max_concurrent_streams_errors() { | |||||||
|     h2.join(srv).wait().expect("wait"); |     h2.join(srv).wait().expect("wait"); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | #[test] | ||||||
|  | fn send_request_poll_ready_when_connection_error() { | ||||||
|  |     let _ = ::env_logger::try_init(); | ||||||
|  |     let (io, srv) = mock::new(); | ||||||
|  |  | ||||||
|  |  | ||||||
|  |     let srv = srv.assert_client_handshake_with_settings(frames::settings() | ||||||
|  |                 // super tiny server | ||||||
|  |                 .max_concurrent_streams(1)) | ||||||
|  |         .unwrap() | ||||||
|  |         .recv_settings() | ||||||
|  |         .recv_frame( | ||||||
|  |             frames::headers(1) | ||||||
|  |                 .request("POST", "https://example.com/") | ||||||
|  |                 .eos(), | ||||||
|  |         ) | ||||||
|  |         .send_frame(frames::headers(1).response(200).eos()) | ||||||
|  |         .recv_frame(frames::headers(3).request("POST", "https://example.com/").eos()) | ||||||
|  |         .send_frame(frames::headers(8).response(200).eos()) | ||||||
|  |         //.recv_frame(frames::headers(5).request("POST", "https://example.com/").eos()) | ||||||
|  |         .close(); | ||||||
|  |  | ||||||
|  |     let h2 = client::handshake(io) | ||||||
|  |         .expect("handshake") | ||||||
|  |         .and_then(|(mut client, h2)| { | ||||||
|  |             // we send a simple req here just to drive the connection so we can | ||||||
|  |             // receive the server settings. | ||||||
|  |             let request = Request::builder() | ||||||
|  |                 .method(Method::POST) | ||||||
|  |                 .uri("https://example.com/") | ||||||
|  |                 .body(()) | ||||||
|  |                 .unwrap(); | ||||||
|  |  | ||||||
|  |             // first request is allowed | ||||||
|  |             let (response, _) = client.send_request(request, true).unwrap(); | ||||||
|  |             h2.drive(response).map(move |(h2, _)| (client, h2)) | ||||||
|  |         }) | ||||||
|  |         .and_then(|(mut client, h2)| { | ||||||
|  |             let request = Request::builder() | ||||||
|  |                 .method(Method::POST) | ||||||
|  |                 .uri("https://example.com/") | ||||||
|  |                 .body(()) | ||||||
|  |                 .unwrap(); | ||||||
|  |  | ||||||
|  |             // first request is allowed | ||||||
|  |             let (resp1, _) = client.send_request(request, true).unwrap(); | ||||||
|  |  | ||||||
|  |             let request = Request::builder() | ||||||
|  |                 .method(Method::POST) | ||||||
|  |                 .uri("https://example.com/") | ||||||
|  |                 .body(()) | ||||||
|  |                 .unwrap(); | ||||||
|  |  | ||||||
|  |             // second request is put into pending_open | ||||||
|  |             let (resp2, _) = client.send_request(request, true).unwrap(); | ||||||
|  |  | ||||||
|  |             // third stream is over max concurrent | ||||||
|  |             let until_ready = futures::future::poll_fn(move || { | ||||||
|  |                 client.poll_ready() | ||||||
|  |             }).expect_err("client poll_ready").then(|_| Ok(())); | ||||||
|  |  | ||||||
|  |             // a FuturesUnordered is used on purpose! | ||||||
|  |             // | ||||||
|  |             // We don't want a join, since any of the other futures notifying | ||||||
|  |             // will make the until_ready future polled again, but we are | ||||||
|  |             // specifically testing that until_ready gets notified on its own. | ||||||
|  |             let mut unordered = futures::stream::FuturesUnordered::<Box<Future<Item=(), Error=()>>>::new(); | ||||||
|  |             unordered.push(Box::new(until_ready)); | ||||||
|  |             unordered.push(Box::new(h2.expect_err("client conn").then(|_| Ok(())))); | ||||||
|  |             unordered.push(Box::new(resp1.expect_err("req1").then(|_| Ok(())))); | ||||||
|  |             unordered.push(Box::new(resp2.expect_err("req2").then(|_| Ok(())))); | ||||||
|  |  | ||||||
|  |             unordered.for_each(|_| Ok(())) | ||||||
|  |         }); | ||||||
|  |  | ||||||
|  |     h2.join(srv).wait().expect("wait"); | ||||||
|  | } | ||||||
|  |  | ||||||
| #[test] | #[test] | ||||||
| fn http_11_request_without_scheme_or_authority() { | fn http_11_request_without_scheme_or_authority() { | ||||||
|     let _ = ::env_logger::try_init(); |     let _ = ::env_logger::try_init(); | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user