use std::io::{Read, Write, BufRead, BufReader, ErrorKind};
use std::net::TcpStream;
use crate::{
net::{
Error,
Result,
HttpData
},
parser::Builder
};
const CAPACITY: usize = 512;
pub struct Connection {
stream: Option<TcpStream>,
readed: bool,
writed: bool
}
impl Connection {
pub(crate) fn new(stream: TcpStream) -> Self {
Self {
stream: Some(stream),
readed: false,
writed: false
}
}
pub fn connect(ip: &str) -> Result<Connection> {
let stream = match TcpStream::connect(ip) {
Ok(stream) => stream,
Err(_) => return Err(Error::ConnectionError)
};
Ok(Self::new(stream))
}
pub fn parse_incoming(&mut self) -> Result<HttpData> {
if self.readed {
return Err(Error::UnableToRead);
}
let mut buf = BufReader::new(self.stream.take().unwrap());
let mut vec = Vec::with_capacity(CAPACITY);
while let Ok(n) = buf.read_until('\n' as u8, &mut vec) {
if n <= 2 {
break;
}
}
let mut parsed = match HttpData::parse(&vec) {
Ok(parsed) => parsed,
Err(_) => return Err(Error::BadRequest)
};
let headers = parsed.headers();
parsed.set_content(match headers.get("Content-Length") {
Some(lenght) => {
let lenght: usize = match String::from_utf8_lossy(lenght).parse() {
Ok(i) => i,
Err(_) => return Err(Error::BadRequest)
};
let mut vec = vec![0u8; lenght];
if let Err(_) = buf.read_exact(&mut vec) {
return Err(Error::BadRequest);
}
Some(vec)
}
None => {
None
}
});
self.stream = Some(buf.into_inner());
self.readed = true;
Ok(parsed)
}
pub fn write_builder<T>(&mut self, response: T) -> Result<()>
where T: Builder
{
if self.writed {
return Err(Error::UnableToWrite);
}
let mut stream = self.stream.take().unwrap();
let response = response.build();
if let Err(_) = stream.write_all(&response) {
return Err(Error::UnableToWrite);
}
if let Err(e) = stream.flush() {
return match e.kind() {
ErrorKind::ConnectionAborted => Err(Error::ConnectionLost),
_ => Err(Error::ConnectionError)
}
}
self.stream = Some(stream);
self.writed = true;
Ok(())
}
}