Notify send_tasks when there is a connection error (#231)
This commit is contained in:
committed by
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