Skip to content

Commit 02eb53b

Browse files
authored
fix: handle implicit resets at the right time (#833)
A stream whose ref count reaches zero while open should not immediately decrease the number of active streams, otherwise MAX_CONCURRENT_STREAMS isn't respected anymore.
1 parent e348cf3 commit 02eb53b

File tree

3 files changed

+142
-2
lines changed

3 files changed

+142
-2
lines changed

src/proto/streams/counts.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -229,7 +229,7 @@ impl Counts {
229229
}
230230
}
231231

232-
if stream.is_counted {
232+
if !stream.state.is_scheduled_reset() && stream.is_counted {
233233
tracing::trace!("dec_num_streams; stream={:?}", stream.id);
234234
// Decrement the number of active streams.
235235
self.dec_num_streams(&mut stream);

src/proto/streams/prioritize.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -685,8 +685,11 @@ impl Prioritize {
685685
}
686686

687687
pub fn clear_pending_send(&mut self, store: &mut Store, counts: &mut Counts) {
688-
while let Some(stream) = self.pending_send.pop(store) {
688+
while let Some(mut stream) = self.pending_send.pop(store) {
689689
let is_pending_reset = stream.is_pending_reset_expiration();
690+
if let Some(reason) = stream.state.get_scheduled_reset() {
691+
stream.set_reset(reason, Initiator::Library);
692+
}
690693
counts.transition_after(stream, is_pending_reset);
691694
}
692695
}

tests/h2-tests/tests/stream_states.rs

+137
Original file line numberDiff line numberDiff line change
@@ -1218,3 +1218,140 @@ async fn reset_new_stream_before_send() {
12181218

12191219
join(srv, client).await;
12201220
}
1221+
1222+
#[tokio::test]
1223+
async fn explicit_reset_with_max_concurrent_stream() {
1224+
h2_support::trace_init!();
1225+
1226+
let (io, mut srv) = mock::new();
1227+
1228+
let mock = async move {
1229+
let settings = srv
1230+
.assert_client_handshake_with_settings(frames::settings().max_concurrent_streams(1))
1231+
.await;
1232+
assert_default_settings!(settings);
1233+
1234+
srv.recv_frame(frames::headers(1).request("POST", "https://www.example.com/"))
1235+
.await;
1236+
srv.send_frame(frames::headers(1).response(200)).await;
1237+
1238+
srv.recv_frame(frames::reset(1).cancel()).await;
1239+
1240+
srv.recv_frame(
1241+
frames::headers(3)
1242+
.request("POST", "https://www.example.com/")
1243+
.eos(),
1244+
)
1245+
.await;
1246+
srv.send_frame(frames::headers(3).response(200)).await;
1247+
};
1248+
1249+
let h2 = async move {
1250+
let (mut client, mut h2) = client::handshake(io).await.unwrap();
1251+
1252+
{
1253+
let request = Request::builder()
1254+
.method(Method::POST)
1255+
.uri("https://www.example.com/")
1256+
.body(())
1257+
.unwrap();
1258+
1259+
let (resp, mut stream) = client.send_request(request, false).unwrap();
1260+
1261+
{
1262+
let resp = h2.drive(resp).await.unwrap();
1263+
assert_eq!(resp.status(), StatusCode::OK);
1264+
}
1265+
1266+
stream.send_reset(Reason::CANCEL);
1267+
};
1268+
1269+
{
1270+
let request = Request::builder()
1271+
.method(Method::POST)
1272+
.uri("https://www.example.com/")
1273+
.body(())
1274+
.unwrap();
1275+
1276+
let (resp, _) = client.send_request(request, true).unwrap();
1277+
1278+
{
1279+
let resp = h2.drive(resp).await.unwrap();
1280+
assert_eq!(resp.status(), StatusCode::OK);
1281+
}
1282+
};
1283+
1284+
h2.await.unwrap();
1285+
};
1286+
1287+
join(mock, h2).await;
1288+
}
1289+
1290+
#[tokio::test]
1291+
async fn implicit_cancel_with_max_concurrent_stream() {
1292+
h2_support::trace_init!();
1293+
1294+
let (io, mut srv) = mock::new();
1295+
1296+
let mock = async move {
1297+
let settings = srv
1298+
.assert_client_handshake_with_settings(frames::settings().max_concurrent_streams(1))
1299+
.await;
1300+
assert_default_settings!(settings);
1301+
1302+
srv.recv_frame(frames::headers(1).request("POST", "https://www.example.com/"))
1303+
.await;
1304+
srv.send_frame(frames::headers(1).response(200)).await;
1305+
1306+
srv.recv_frame(frames::reset(1).cancel()).await;
1307+
1308+
srv.recv_frame(
1309+
frames::headers(3)
1310+
.request("POST", "https://www.example.com/")
1311+
.eos(),
1312+
)
1313+
.await;
1314+
srv.send_frame(frames::headers(3).response(200)).await;
1315+
};
1316+
1317+
let h2 = async move {
1318+
let (mut client, mut h2) = client::handshake(io).await.unwrap();
1319+
1320+
{
1321+
let request = Request::builder()
1322+
.method(Method::POST)
1323+
.uri("https://www.example.com/")
1324+
.body(())
1325+
.unwrap();
1326+
1327+
let (resp, stream) = client.send_request(request, false).unwrap();
1328+
1329+
{
1330+
let resp = h2.drive(resp).await.unwrap();
1331+
assert_eq!(resp.status(), StatusCode::OK);
1332+
}
1333+
1334+
// This implicitly resets the stream with CANCEL.
1335+
drop(stream);
1336+
};
1337+
1338+
{
1339+
let request = Request::builder()
1340+
.method(Method::POST)
1341+
.uri("https://www.example.com/")
1342+
.body(())
1343+
.unwrap();
1344+
1345+
let (resp, _) = client.send_request(request, true).unwrap();
1346+
1347+
{
1348+
let resp = h2.drive(resp).await.unwrap();
1349+
assert_eq!(resp.status(), StatusCode::OK);
1350+
}
1351+
};
1352+
1353+
h2.await.unwrap();
1354+
};
1355+
1356+
join(mock, h2).await;
1357+
}

0 commit comments

Comments
 (0)