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(); } }