Ref count stream state and release when final (#73)
Previously, stream state was never released so that long-lived connections leaked memory. Now, stream states are reference-counted and freed from the stream slab when complete. Locally reset streams are retained so that received frames may be ignored.
This commit is contained in:
committed by
Oliver Gould
parent
daa54b9512
commit
5c0efcf8c4
@@ -149,6 +149,58 @@ fn send_headers_recv_data_single_frame() {
|
||||
h2.wait().unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn closed_streams_are_released() {
|
||||
let _ = ::env_logger::init();
|
||||
let (io, srv) = mock::new();
|
||||
|
||||
let h2 = Client::handshake(io).unwrap()
|
||||
.and_then(|mut h2| {
|
||||
let request = Request::get("https://example.com/")
|
||||
.body(()).unwrap();
|
||||
|
||||
// Send request
|
||||
let stream = h2.request(request, true).unwrap();
|
||||
h2.drive(stream)
|
||||
})
|
||||
.and_then(|(h2, response)| {
|
||||
assert_eq!(response.status(), StatusCode::NO_CONTENT);
|
||||
|
||||
// There are no active streams
|
||||
assert_eq!(0, h2.num_active_streams());
|
||||
|
||||
// The response contains a handle for the body. This keeps the
|
||||
// stream wired.
|
||||
assert_eq!(1, h2.num_wired_streams());
|
||||
|
||||
drop(response);
|
||||
|
||||
// The stream state is now free
|
||||
assert_eq!(0, h2.num_wired_streams());
|
||||
|
||||
Ok(())
|
||||
})
|
||||
;
|
||||
|
||||
let srv = srv.assert_client_handshake().unwrap()
|
||||
.recv_settings()
|
||||
.recv_frame(
|
||||
frames::headers(1)
|
||||
.request("GET", "https://example.com/")
|
||||
.eos()
|
||||
)
|
||||
.send_frame(
|
||||
frames::headers(1)
|
||||
.response(204)
|
||||
.eos()
|
||||
)
|
||||
.close()
|
||||
;
|
||||
|
||||
let _ = h2.join(srv)
|
||||
.wait().unwrap();
|
||||
}
|
||||
|
||||
/*
|
||||
#[test]
|
||||
fn send_data_after_headers_eos() {
|
||||
|
||||
@@ -71,23 +71,35 @@ impl<T, U> Future for Drive<T, U>
|
||||
type Error = ();
|
||||
|
||||
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
|
||||
match self.future.poll() {
|
||||
Ok(Async::Ready(val)) => {
|
||||
// Get the driver
|
||||
let driver = self.driver.take().unwrap();
|
||||
let mut looped = false;
|
||||
|
||||
return Ok((driver, val).into())
|
||||
loop {
|
||||
match self.future.poll() {
|
||||
Ok(Async::Ready(val)) => {
|
||||
// Get the driver
|
||||
let driver = self.driver.take().unwrap();
|
||||
|
||||
return Ok((driver, val).into())
|
||||
}
|
||||
Ok(_) => {}
|
||||
Err(e) => panic!("unexpected error; {:?}", e),
|
||||
}
|
||||
Ok(_) => {}
|
||||
Err(e) => panic!("unexpected error; {:?}", e),
|
||||
}
|
||||
|
||||
match self.driver.as_mut().unwrap().poll() {
|
||||
Ok(Async::Ready(_)) => panic!("driver resolved before future"),
|
||||
Ok(Async::NotReady) => {}
|
||||
Err(e) => panic!("unexpected error; {:?}", e),
|
||||
}
|
||||
match self.driver.as_mut().unwrap().poll() {
|
||||
Ok(Async::Ready(_)) => {
|
||||
if looped {
|
||||
// Try polling the future one last time
|
||||
panic!("driver resolved before future")
|
||||
} else {
|
||||
looped = true;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
Ok(Async::NotReady) => {}
|
||||
Err(e) => panic!("unexpected error; {:?}", e),
|
||||
}
|
||||
|
||||
Ok(Async::NotReady)
|
||||
return Ok(Async::NotReady);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user