use super::*; #[test] fn body_budgets_timeouts_invalid_messages_and_recovery_are_bounded() { runtime().run(async |scope| { let listener = net::listen("127.0.0.1", 0, scope).await.unwrap(); let port = listener.port().unwrap(); let incoming = listener.clone(); let server = scope.spawn(move |child| async move { let limits = Limits { body_bytes: 4, timeout_ms: 100, ..Limits::default() }; http::serve::<_, _, false>(&incoming, &limits, &child, route).await }).unwrap(); scope.blocking(move || { let query_only = format!("GET ?{} HTTP/1.1\r\nHost: t\r\n\r\n", "a".repeat(8163)); for (message, expected) in [ ("POST /echo HTTP/1.1\r\nHost: fixture.test\r\nContent-Length: 5\r\n\r\n12345", 413), ("POST /echo HTTP/1.1\r\nHost: fixture.test\r\nContent-Length: 4\r\n\r\n1", 408), ("GET /wait HTTP/1.1\r\nHost: fixture.test\r\n\r\n", 504), ("GET /echo HTTP/1.1\r\nHost: one\r\nHost: two\r\n\r\n", 400), (query_only.as_str(), 400), ] { let mut stream = connect(port); stream.get_mut().write_all(message.as_bytes()).unwrap(); assert_eq!(read_response(&mut stream, false).0, expected); assert_eq!(stream.read(&mut [0]).unwrap(), 0); } let mut stream = connect(port); stream.get_mut().write_all(b"GET / HTTP/1.1\r\nHost:").unwrap(); assert_eq!(stream.read(&mut [0]).unwrap(), 0); }).await.unwrap(); let response = http::send("127.0.0.1", port, request("/echo", b"ok"), &Limits::default()).await.unwrap(); assert_eq!(response.body.as_ref(), b"ok"); listener.close().unwrap(); server.wait().await.unwrap().unwrap(); }).unwrap(); } #[test] fn outgoing_contracts_reject_framing_injection_and_bad_limits() { runtime() .run(async |_| { for header in [ Header { name: "Content-Length".into(), value: b"0".to_vec().into(), }, Header { name: "Transfer-Encoding".into(), value: b"chunked".to_vec().into(), }, Header { name: "x-test".into(), value: b"a\r\nb".to_vec().into(), }, ] { let mut message = request("/", b""); message.headers.push(header); let error = http::send("127.0.0.1", 1, message, &Limits::default()) .await .unwrap_err(); assert!(!error.contains("connection failed"), "{error}"); } for limits in [ Limits { header_bytes: 0, ..Limits::default() }, Limits { body_bytes: -1, ..Limits::default() }, Limits { timeout_ms: 0, ..Limits::default() }, Limits { connections: 65537, ..Limits::default() }, ] { assert!( http::send("127.0.0.1", 1, request("/", b""), &limits) .await .is_err() ); } let long_target = format!("/{}", "x".repeat(8192)); for (method, target) in [ ("CONNECT", "/"), ("GET", "http://example.test/"), ("GET", "/#fragment"), ("GET", long_target.as_str()), ] { let mut message = request(target, b""); message.method = method.into(); let error = http::send("127.0.0.1", 1, message, &Limits::default()) .await .unwrap_err(); assert!(!error.contains("connection failed"), "{error}"); } }) .unwrap(); }