use std::io::{self, BufRead, BufReader, Read, Write};
use std::net::TcpStream;
use std::thread;
use std::time::Duration;
use super::super::*;
fn dribble_body_respond(stream: &mut TcpStream) -> io::Result<()> {
let contents = [b'a'; 300];
let headers = format!(
"HTTP/1.1 200 OK\r\nContent-Length: {}\r\n\r\n",
contents.len() * 2
);
stream.write_all(headers.as_bytes())?;
for i in 0..contents.len() {
stream.write_all(&contents[i..i + 1])?;
stream.write_all(&[b'\n'; 1])?;
stream.flush()?;
thread::sleep(Duration::from_millis(10));
}
Ok(())
}
fn read_headers(stream: &TcpStream) {
for line in BufReader::new(stream).lines() {
let line = match line {
Ok(x) => x,
Err(_) => return,
};
if line == "" {
break;
}
}
}
fn start_dribble_body_server() -> u16 {
let listener = std::net::TcpListener::bind("localhost:0").unwrap();
let port = listener.local_addr().unwrap().port();
let dribble_handler = |mut stream: TcpStream| {
read_headers(&stream);
if let Err(e) = dribble_body_respond(&mut stream) {
eprintln!("sending dribble repsonse: {}", e);
}
};
thread::spawn(move || {
for stream in listener.incoming() {
thread::spawn(move || dribble_handler(stream.unwrap()));
}
});
port
}
fn get_and_expect_timeout(url: String) {
let agent = Agent::default().build();
let timeout = Duration::from_millis(500);
let resp = agent.get(&url).timeout(timeout).call();
let mut reader = resp.into_reader();
let mut bytes = vec![];
let result = reader.read_to_end(&mut bytes);
match result {
Err(io_error) => match io_error.kind() {
io::ErrorKind::WouldBlock => Ok(()),
io::ErrorKind::TimedOut => Ok(()),
_ => Err(format!("{:?}", io_error)),
},
Ok(_) => Err("successful response".to_string()),
}
.expect("expected timeout but got something else");
}
#[test]
fn overall_timeout_during_body() {
let port = start_dribble_body_server();
let url = format!("http://localhost:{}/", port);
get_and_expect_timeout(url);
}
fn dribble_headers_respond(stream: &mut TcpStream) -> io::Result<()> {
stream.write_all(b"HTTP/1.1 200 OK\r\nContent-Length: 0\r\n")?;
for _ in 0..30 {
stream.write_all(b"a: b\n")?;
stream.flush()?;
thread::sleep(Duration::from_millis(100));
}
Ok(())
}
fn start_dribble_headers_server() -> u16 {
let listener = std::net::TcpListener::bind("localhost:0").unwrap();
let port = listener.local_addr().unwrap().port();
let dribble_handler = |mut stream: TcpStream| {
read_headers(&stream);
if let Err(e) = dribble_headers_respond(&mut stream) {
eprintln!("sending dribble repsonse: {}", e);
}
};
thread::spawn(move || {
for stream in listener.incoming() {
thread::spawn(move || dribble_handler(stream.unwrap()));
}
});
port
}
#[test]
fn overall_timeout_during_headers() {
let port = start_dribble_headers_server();
let url = format!("http://localhost:{}/", port);
get_and_expect_timeout(url);
}