|
|
|
@ -1,4 +1,4 @@
|
|
|
|
|
use crate::{Request, Result};
|
|
|
|
|
use crate::{color, Request, Result};
|
|
|
|
|
use gophermap::{GopherMenu, ItemType};
|
|
|
|
|
use std::{
|
|
|
|
|
fs,
|
|
|
|
@ -28,14 +28,30 @@ pub fn start(host: &str, port: u16, root: &str) -> Result<()> {
|
|
|
|
|
let full_root_path = fs::canonicalize(&root)?.to_string_lossy().to_string();
|
|
|
|
|
let pool = ThreadPool::new(MAX_WORKERS);
|
|
|
|
|
|
|
|
|
|
println!("-> Listening on {} at {}", addr, full_root_path);
|
|
|
|
|
println!(
|
|
|
|
|
"{}┬ Listening {}on {}{}{} at {}{}{}",
|
|
|
|
|
color::Yellow,
|
|
|
|
|
color::Reset,
|
|
|
|
|
color::Yellow,
|
|
|
|
|
addr,
|
|
|
|
|
color::Reset,
|
|
|
|
|
color::Blue,
|
|
|
|
|
full_root_path,
|
|
|
|
|
color::Reset
|
|
|
|
|
);
|
|
|
|
|
for stream in listener.incoming() {
|
|
|
|
|
let stream = stream?;
|
|
|
|
|
println!("-> Connection from: {}", stream.peer_addr()?);
|
|
|
|
|
println!(
|
|
|
|
|
"{}┌ Connection{} from {}{}",
|
|
|
|
|
color::Green,
|
|
|
|
|
color::Reset,
|
|
|
|
|
color::Magenta,
|
|
|
|
|
stream.peer_addr()?
|
|
|
|
|
);
|
|
|
|
|
let req = Request::from(host, port, root)?;
|
|
|
|
|
pool.execute(move || {
|
|
|
|
|
if let Err(e) = accept(stream, req) {
|
|
|
|
|
eprintln!("-! {}", e);
|
|
|
|
|
eprintln!("{}└ {}{}", color::Red, e, color::Reset);
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
@ -47,7 +63,14 @@ fn accept(stream: TcpStream, mut req: Request) -> Result<()> {
|
|
|
|
|
let reader = BufReader::new(&stream);
|
|
|
|
|
let mut lines = reader.lines();
|
|
|
|
|
if let Some(Ok(line)) = lines.next() {
|
|
|
|
|
println!("-> Client sent: {:?}", line);
|
|
|
|
|
println!(
|
|
|
|
|
"{}│{} Client sent:\t{}{:?}{}",
|
|
|
|
|
color::Green,
|
|
|
|
|
color::Reset,
|
|
|
|
|
color::Cyan,
|
|
|
|
|
line,
|
|
|
|
|
color::Reset
|
|
|
|
|
);
|
|
|
|
|
req.parse_request(&line);
|
|
|
|
|
write_response(&stream, req)?;
|
|
|
|
|
}
|
|
|
|
@ -168,6 +191,15 @@ where
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
menu.end()?;
|
|
|
|
|
println!(
|
|
|
|
|
"{}│{} Server reply:\t{}DIR {}{}{}",
|
|
|
|
|
color::Green,
|
|
|
|
|
color::Reset,
|
|
|
|
|
color::Yellow,
|
|
|
|
|
color::Bold,
|
|
|
|
|
req.relative_file_path(),
|
|
|
|
|
color::Reset,
|
|
|
|
|
);
|
|
|
|
|
Ok(())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -176,8 +208,18 @@ fn write_file<'a, W>(mut w: &'a W, req: Request) -> Result<()>
|
|
|
|
|
where
|
|
|
|
|
&'a W: Write,
|
|
|
|
|
{
|
|
|
|
|
let mut f = fs::File::open(&req.file_path())?;
|
|
|
|
|
let path = req.file_path();
|
|
|
|
|
let mut f = fs::File::open(&path)?;
|
|
|
|
|
io::copy(&mut f, &mut w)?;
|
|
|
|
|
println!(
|
|
|
|
|
"{}│{} Server reply:\t{}FILE {}{}{}",
|
|
|
|
|
color::Green,
|
|
|
|
|
color::Reset,
|
|
|
|
|
color::Yellow,
|
|
|
|
|
color::Bold,
|
|
|
|
|
req.relative_file_path(),
|
|
|
|
|
color::Reset,
|
|
|
|
|
);
|
|
|
|
|
Ok(())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -192,7 +234,7 @@ where
|
|
|
|
|
let reader = if is_executable(&path) {
|
|
|
|
|
shell(&path, &[&req.query, &req.host, &req.port.to_string()])?
|
|
|
|
|
} else {
|
|
|
|
|
fs::read_to_string(path)?
|
|
|
|
|
fs::read_to_string(&path)?
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
for line in reader.lines() {
|
|
|
|
@ -213,6 +255,15 @@ where
|
|
|
|
|
line.push_str("\r\n");
|
|
|
|
|
w.write_all(line.as_bytes())?;
|
|
|
|
|
}
|
|
|
|
|
println!(
|
|
|
|
|
"{}│{} Server reply:\t{}MAP {}{}{}",
|
|
|
|
|
color::Green,
|
|
|
|
|
color::Reset,
|
|
|
|
|
color::Yellow,
|
|
|
|
|
color::Bold,
|
|
|
|
|
req.relative_file_path(),
|
|
|
|
|
color::Reset,
|
|
|
|
|
);
|
|
|
|
|
Ok(())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -221,6 +272,13 @@ where
|
|
|
|
|
&'a W: Write,
|
|
|
|
|
{
|
|
|
|
|
let line = format!("3Not Found: {}\t/\tnone\t70\r\n", req.selector);
|
|
|
|
|
println!(
|
|
|
|
|
"{}│ Not found: {}{}{}",
|
|
|
|
|
color::Red,
|
|
|
|
|
color::Cyan,
|
|
|
|
|
req.relative_file_path(),
|
|
|
|
|
color::Reset,
|
|
|
|
|
);
|
|
|
|
|
w.write_all(line.as_bytes())?;
|
|
|
|
|
Ok(())
|
|
|
|
|
}
|
|
|
|
|