use poolio::{PanicSwitch, ThreadPool};
use std::io::prelude::*;
use std::net::TcpListener;
use std::net::TcpStream;
use std::thread;
use std::time::Duration;
const SIZE: usize = 4;
#[test]
fn test_http() {
const ADDR: &str = "127.0.0.1:7878";
thread::spawn(|| http_server(ADDR));
let pool = threadpool::ThreadPool::new(SIZE);
for _ in 0..10 {
pool.execute(|| http_client(ADDR, &Method::Get));
pool.execute(|| http_client(ADDR, &Method::Head));
pool.execute(|| http_client(ADDR, &Method::Put));
}
}
enum Method {
Get,
Head,
Put,
}
fn http_client(addr: &str, method: &Method) {
let mut stream = TcpStream::connect(addr).unwrap();
let request = match method {
Method::Get => request("GET", "/"),
Method::Head => request("HEAD", "/"),
Method::Put => request("PUT", "/"),
};
stream.write_all(request.as_bytes()).unwrap();
stream.flush().unwrap();
let mut buffer = [0; 1024];
let _ = stream.read(&mut buffer).unwrap();
let ok = b"HTTP/1.1 200 OK\r\n";
let err = b"HTTP/1.1 404 NOT FOUND\r\n";
match method {
Method::Put | Method::Get => assert!(buffer.starts_with(ok)),
Method::Head => assert!(buffer.starts_with(err)),
};
}
fn request(method: &str, url: &str) -> String {
let request = format!("{} {} HTTP/1.1", method, url);
let headers = "";
let body = "";
format!("{}\r\n{}\r\n{}", request, headers, body)
}
fn http_server(addr: &str) {
let pool = ThreadPool::new(SIZE, PanicSwitch::Respawn).unwrap();
let listener = TcpListener::bind(addr).unwrap();
for stream in listener.incoming() {
let stream = stream.unwrap();
pool.execute(|| {
handle_connection(stream);
});
}
}
fn handle_connection(mut stream: TcpStream) {
let mut buffer = [0; 1024];
let _ = stream.read(&mut buffer).unwrap();
let get = b"GET / HTTP/1.1\r\n";
let put = b"PUT / HTTP/1.1\r\n";
let response = if buffer.starts_with(get) {
response("HTTP/1.1 200 OK")
} else if buffer.starts_with(put) {
thread::sleep(Duration::from_secs(1));
response("HTTP/1.1 200 OK")
} else {
response("HTTP/1.1 404 NOT FOUND")
};
stream.write_all(response.as_bytes()).unwrap();
stream.flush().unwrap();
}
fn response(status: &str) -> String {
let headers = "";
let body = "";
format!("{}\r\n{}\r\n{}", status, headers, body)
}