240 lines
8.1 KiB
Rust
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();
|
|
}
|
|
}
|