use super::*; use tokio::sync::Notify; #[test] fn head_and_disconnect_cancel_requests_before_reusing_the_connection() { runtime() .run(async |scope| { let listener = net::listen("127.0.0.1", 0, scope).await.unwrap(); let incoming = listener.clone(); let active = Arc::new(AtomicUsize::new(0)); let running = active.clone(); let server = scope .spawn(move |child| async move { http::serve_live( &incoming, &Limits::default(), &http::LiveLimits::default(), &child, move |request, reply, _| { let active = active.clone(); async move { assert_eq!(active.fetch_add(1, Ordering::SeqCst), 0); let _running = Running(active); reply.start(200, vec![]).await.unwrap(); if request.method == "HEAD" { std::future::pending::<()>().await; } reply.write(b"data").await.unwrap(); std::future::pending::>().await } }, ) .await }) .unwrap(); let (mut sender, driver) = client(listener.port().unwrap(), scope).await; let response = sender.send_request(message("HEAD")).await.unwrap(); assert!( response .into_body() .collect() .await .unwrap() .to_bytes() .is_empty() ); assert_eq!(running.load(Ordering::SeqCst), 0); let response = sender.send_request(message("GET")).await.unwrap(); let mut body = response.into_body(); assert_eq!( body.frame().await.unwrap().unwrap().into_data().unwrap(), b"data"[..] ); drop(body); drop(sender); driver.wait().await.unwrap(); tokio::time::timeout(Duration::from_secs(2), async { while running.load(Ordering::SeqCst) != 0 { tokio::task::yield_now().await; } }) .await .unwrap(); listener.close().unwrap(); server.wait().await.unwrap().unwrap(); }) .unwrap(); } #[test] fn slow_peer_bounds_writer_and_parent_stop_drains_blocking_descendants() { for sse in [false, true] { slow_peer_case(sse); } } fn slow_peer_case(sse: bool) { runtime() .run(async |scope| { let listener = net::listen("127.0.0.1", 0, scope).await.unwrap(); let incoming = listener.clone(); let count = Arc::new(AtomicUsize::new(0)); let written = count.clone(); let active = Arc::new(AtomicUsize::new(0)); let running = active.clone(); let ready = Arc::new(Notify::new()); let started = ready.clone(); let server = scope .spawn(move |child| async move { http::serve_live( &incoming, &Limits { timeout_ms: 5000, ..Limits::default() }, &http::LiveLimits::default(), &child, move |_, reply, scope| { let written = written.clone(); let active = active.clone(); let ready = ready.clone(); async move { let worker = scope .spawn(move |child| async move { child .blocking(move || { active.fetch_add(1, Ordering::SeqCst); let _running = Running(active); ready.notify_one(); std::thread::sleep(Duration::from_millis(400)); }) .await }) .unwrap(); if sse { reply.sse_start(vec![]).await.unwrap(); } else { reply.start(200, vec![]).await.unwrap(); } let bytes = vec![0; 65536]; let event = http::Event { event: String::new(), data: "a".repeat(65528), id: None, retry_ms: None, }; for _ in 0..10000 { let result = if sse { reply.sse_send(&event).await } else { reply.write(&bytes).await }; result.map_err(|error| error.to_string())?; written.fetch_add(1, Ordering::SeqCst); } worker.wait().await.unwrap().unwrap(); Ok(()) } }, ) .await }) .unwrap(); let mut socket = tokio::net::TcpStream::connect(("127.0.0.1", listener.port().unwrap() as u16)) .await .unwrap(); use tokio::io::AsyncWriteExt; socket .write_all(b"GET / HTTP/1.1\r\nHost: fixture.test\r\n\r\n") .await .unwrap(); started.notified().await; tokio::time::sleep(Duration::from_millis(100)).await; assert!(count.load(Ordering::SeqCst) < 10000); server.stop().await.unwrap(); assert_eq!(running.load(Ordering::SeqCst), 0); listener.close().unwrap(); }) .unwrap(); } #[test] fn live_header_and_idle_deadlines_are_distinct_and_faults_truncate() { runtime() .run(async |scope| { for mode in ["headers", "idle", "fault", "missing"] { let gate = Arc::new(Semaphore::new(0)); let failed = gate.clone(); let listener = net::listen("127.0.0.1", 0, scope).await.unwrap(); let incoming = listener.clone(); let server = scope .spawn(move |child| async move { http::serve_live( &incoming, &Limits { timeout_ms: 100, ..Limits::default() }, &http::LiveLimits { idle_ms: 60, heartbeat_ms: 20, chunk_bytes: 64, }, &child, move |_, reply, _| { let gate = failed.clone(); async move { if mode == "missing" { return Ok(()); } if mode == "headers" { std::future::pending::<()>().await; } reply.start(200, vec![]).await.unwrap(); if mode == "idle" { std::future::pending::<()>().await; } reply.write(b"partial").await.unwrap(); let _permit = gate.acquire().await.unwrap(); Err("located handler failure".into()) } }, ) .await }) .unwrap(); let (mut sender, driver) = client(listener.port().unwrap(), scope).await; let response = sender.send_request(message("GET")).await.unwrap(); match mode { "headers" => assert_eq!(response.status(), 504), "missing" => assert_eq!(response.status(), 500), _ => { assert_eq!(response.status(), 200); let mut body = response.into_body(); if mode == "fault" { assert_eq!( body.frame().await.unwrap().unwrap().into_data().unwrap(), b"partial"[..] ); gate.add_permits(1); } assert!(body.collect().await.is_err()); } } drop(sender); driver.wait().await.unwrap(); listener.close().unwrap(); server.wait().await.unwrap().unwrap(); } }) .unwrap(); }