Files
core/test/rust/runtime/http/streaming/download.rs
T
2026-11-03 03:32:07 +00:00

240 lines
8.1 KiB
Rust

use super::*;
#[test]
fn headers_return_before_body_and_download_ignores_buffered_total_limit() {
let (opened, permit) = std::sync::mpsc::channel();
let (port, server) = peer(move |listener| {
let mut socket = accept(&listener);
headers(&mut socket);
socket
.get_mut()
.write_all(
b"HTTP/1.1 200 OK\r\nContent-Length: 100003\r\nX-Test: one\r\nX-Test: two\r\n\r\n",
)
.unwrap();
permit.recv_timeout(Duration::from_secs(2)).unwrap();
socket.get_mut().write_all(&vec![b'x'; 100003]).unwrap();
assert_eq!(socket.read(&mut [0]).unwrap(), 0);
});
runtime()
.run(async |scope| {
let client = client(
scope,
port,
&Limits {
body_bytes: 1,
..Default::default()
},
&PoolLimits {
chunk_bytes: 7,
..Default::default()
},
);
let response = client.open(message(), event).await.unwrap();
assert_eq!(
response
.headers
.iter()
.filter(|header| header.name == "x-test")
.count(),
2
);
opened.send(()).unwrap();
let body = collect(&response.body, 7).await;
assert_eq!(body, vec![b'x'; 100003]);
assert!(response.body.next().await.unwrap().is_none());
client.close().await.unwrap();
})
.unwrap();
server.join().unwrap();
}
#[test]
fn unread_body_holds_slot_and_idle_clock_starts_after_eof() {
let (port, server) = peer(|listener| {
let mut socket = accept(&listener);
for _ in 0..2 {
headers(&mut socket);
socket
.get_mut()
.write_all(b"HTTP/1.1 200 OK\r\nContent-Length: 6\r\n\r\nabcdef")
.unwrap();
}
let start = std::time::Instant::now();
assert_eq!(socket.read(&mut [0]).unwrap(), 0);
assert!(start.elapsed() < Duration::from_secs(1));
});
runtime()
.run(async |scope| {
let client = client(
scope,
port,
&Limits {
connections: 1,
timeout_ms: 80,
..Default::default()
},
&PoolLimits {
idle_ms: 20,
chunk_bytes: 2,
..Default::default()
},
);
let response = client.open(message(), event).await.unwrap();
assert!(
client
.open(message(), event)
.await
.unwrap_err()
.contains("timed out")
);
assert_eq!(collect(&response.body, 2).await, b"abcdef");
assert_eq!(
client.request(message()).await.unwrap().body.as_ref(),
b"abcdef"
);
tokio::time::sleep(Duration::from_millis(80)).await;
client.close().await.unwrap();
})
.unwrap();
server.join().unwrap();
}
#[test]
fn early_close_of_buffered_frame_closes_http1_and_next_request_reconnects() {
let (port, server) = peer(|listener| {
let mut first = accept(&listener);
headers(&mut first);
first
.get_mut()
.write_all(b"HTTP/1.1 200 OK\r\nContent-Length: 6\r\n\r\nabcdef")
.unwrap();
assert_eq!(first.read(&mut [0]).unwrap(), 0);
let mut second = accept(&listener);
headers(&mut second);
second
.get_mut()
.write_all(b"HTTP/1.1 200 OK\r\nContent-Length: 2\r\n\r\nok")
.unwrap();
});
runtime()
.run(async |scope| {
let client = client(
scope,
port,
&Limits {
connections: 1,
..Default::default()
},
&PoolLimits::default(),
);
let response = client.open(message(), event).await.unwrap();
let alias = response.body.clone();
tokio::time::sleep(Duration::from_millis(30)).await;
response.body.close();
assert!(alias.next().await.unwrap().is_none());
assert_eq!(
client.request(message()).await.unwrap().body.as_ref(),
b"ok"
);
client.close().await.unwrap();
})
.unwrap();
server.join().unwrap();
}
#[test]
fn read_timeout_and_protocol_failure_emit_one_error_then_eof() {
for body in [
b"".as_slice(),
b"3\r\nabc\r\n0\r\nX-End: bad\r\n\r\n",
b"invalid\r\n",
] {
let (port, server) = peer(move |listener| {
let mut socket = accept(&listener);
headers(&mut socket);
socket
.get_mut()
.write_all(b"HTTP/1.1 200 OK\r\nTransfer-Encoding: chunked\r\n\r\n")
.unwrap();
socket.get_mut().write_all(body).unwrap();
let _ = socket.read(&mut [0]);
});
runtime()
.run(async |scope| {
let client = client(
scope,
port,
&Limits::default(),
&PoolLimits {
read_ms: 40,
..Default::default()
},
);
let response = client.open(message(), event).await.unwrap();
let mut failures = 0;
while let Some(item) = response.body.next().await.unwrap() {
failures += usize::from(item.is_err());
}
assert_eq!(failures, 1);
assert!(response.body.next().await.unwrap().is_none());
client.close().await.unwrap();
})
.unwrap();
server.join().unwrap();
}
}
#[test]
fn cancelling_consumer_closes_body_and_pool_close_wakes_body_and_slot_waiters() {
for cancel in [true, false] {
let (port, server) = peer(|listener| {
let mut socket = accept(&listener);
headers(&mut socket);
socket
.get_mut()
.write_all(b"HTTP/1.1 200 OK\r\nContent-Length: 20\r\n\r\n")
.unwrap();
assert_eq!(socket.read(&mut [0]).unwrap(), 0);
});
runtime()
.run(async |scope| {
let client = client(
scope,
port,
&Limits {
connections: 1,
..Default::default()
},
&PoolLimits::default(),
);
let response = client.open(message(), event).await.unwrap();
let alias = response.body.clone();
if cancel {
let consume = async {
let _owner = alias.close_on_drop();
alias.next().await
};
assert!(
tokio::time::timeout(Duration::from_millis(20), consume)
.await
.is_err()
);
assert!(response.body.next().await.unwrap().is_none());
} else {
let (item, waiting, ()) =
tokio::join!(response.body.next(), client.open(message(), event), async {
tokio::time::sleep(Duration::from_millis(20)).await;
client.close().await.unwrap();
});
assert!(item.unwrap().unwrap().unwrap_err().contains("closed"));
assert!(waiting.unwrap_err().contains("closed"));
assert!(response.body.next().await.unwrap().is_none());
}
client.close().await.unwrap();
})
.unwrap();
server.join().unwrap();
}
}