use crate::{
mise::{Request, Response},
routes::{ProcessorResponse, RouteMethod},
};
use http_by_chunks::{ConverterTo, HttpByChunks};
use mio::Registry;
use serde_json::Value;
use std::{
collections::VecDeque,
io::{ErrorKind, Read, Write},
net::{Shutdown, SocketAddr},
};
use tracing::{error, warn};
pub(crate) struct Connection {
socket: mio::net::TcpStream,
addr: SocketAddr,
closed: bool,
read_buffer: Vec<u8>,
static_read_buf: [u8; 4096],
cur_request: HttpByChunks<'static, Value>,
queued_requests: VecDeque<Request>,
write_buffer: Vec<u8>,
}
struct JsonConverter;
impl ConverterTo<Value> for JsonConverter {
fn convert(&self, buf: &[u8]) -> Value {
serde_json::from_slice(buf).unwrap_or(Value::Null)
}
}
static JSON_CONVERTER: JsonConverter = JsonConverter;
impl From<(mio::net::TcpStream, SocketAddr)> for Connection {
fn from(value: (mio::net::TcpStream, SocketAddr)) -> Self {
Self {
socket: value.0,
addr: value.1,
closed: false,
read_buffer: vec![],
static_read_buf: [0; 4096],
cur_request: HttpByChunks::<Value>::new(&JSON_CONVERTER),
queued_requests: VecDeque::new(),
write_buffer: vec![],
}
}
}
impl Connection {
pub(crate) fn write_buffer(&mut self) -> bool {
if self.write_buffer.is_empty() {
return false;
}
let count = match self.socket.write(&self.write_buffer) {
Ok(0) => {
return false;
}
Ok(x) => x,
Err(e) if e.kind() == ErrorKind::WouldBlock => {
return false;
}
Err(e) if e.kind() == ErrorKind::Interrupted => {
return false;
}
Err(e) if is_connection_closed(e.kind()) => {
let _ = self.socket.shutdown(Shutdown::Both);
self.closed = true;
return false;
}
Err(e) => {
error!("{e}");
return false;
}
};
self.write_buffer = self.write_buffer[count..].to_vec();
true
}
pub(crate) fn read_buffer(&mut self) -> bool {
let count = match self.socket.read(&mut self.static_read_buf) {
Ok(0) => {
return false;
}
Ok(x) => x,
Err(e) if e.kind() == ErrorKind::WouldBlock => {
return false;
}
Err(e) if e.kind() == ErrorKind::Interrupted => {
return false;
}
Err(e) if is_connection_closed(e.kind()) => {
self.closed = true;
return false;
}
Err(e) => {
error!("{e}");
return false;
}
};
self.read_buffer
.extend_from_slice(&self.static_read_buf[..count]);
self.append_buffer_and_push_in_queue();
true
}
fn append_buffer_and_push_in_queue(&mut self) {
if self.read_buffer.is_empty() {
return;
}
self.append_buffer_once();
while !self.closed
&& let Some(res) = self.cur_request.build_request()
{
match res {
Ok(request) => {
self.queued_requests.push_back(Request(request));
}
Err(e) => warn!("Unparseable request ({e}), skipping"),
}
self.cur_request = HttpByChunks::<Value>::new(&JSON_CONVERTER);
if self.read_buffer.is_empty() {
return;
}
self.append_buffer_once();
}
}
fn append_buffer_once(&mut self) {
self.read_buffer = self.cur_request.append(&self.read_buffer).to_vec();
if self.is_pipe_broken() {
warn!(
"The request is broken beyond repair (lost sequentiality), closing connection ({}).",
self.addr
);
let _ = self.socket.shutdown(Shutdown::Both);
self.closed = true;
}
}
fn is_pipe_broken(&self) -> bool {
let Some(m) = self.cur_request.request_method() else {
return false;
};
let Some(u) = self.cur_request.request_uri() else {
return false;
};
if RouteMethod::try_from(m).is_err() {
warn!("Invalid/unsupported method: {m}");
return true;
}
if let Err(e) = http::Request::builder().method(m).uri(u).body(()) {
warn!("Invalid request built: {e}");
return true;
}
false
}
pub(crate) fn pop_request(&mut self) -> Option<Request> {
self.queued_requests.pop_front()
}
pub(crate) fn send_response(&mut self, resp: ProcessorResponse) {
match resp {
ProcessorResponse::Json(resp) => self.send_response_json(&resp),
ProcessorResponse::Text(txt) => {
self.write_buffer.extend_from_slice(
format!(
"HTTP/1.1 200 OK\r\nContent-length:{}\r\n\r\n{}",
txt.len(),
txt
)
.as_bytes(),
);
}
}
}
fn send_response_json(&mut self, resp: &Response) {
let mut output: Vec<u8> = vec![];
output.extend_from_slice(
format!(
"HTTP/1.1 {} {}\r\n",
resp.0.status().as_str(),
resp.0.status().canonical_reason().unwrap_or("")
)
.as_bytes(),
);
for h in resp.0.headers() {
output.extend_from_slice(
format!(
"{}: {}\r\n",
h.0,
h.1.to_str().expect("Could not translate header value")
)
.as_bytes(),
);
}
let body = resp.0.body();
let bin = serde_json::to_vec(body).expect("Could not serialize json");
output.extend_from_slice(format!("Content-Length: {}\r\n\r\n", bin.len()).as_bytes());
output.extend_from_slice(&bin);
self.write_buffer.extend_from_slice(&output);
}
pub(crate) fn is_closed(&self) -> bool {
self.closed
}
pub(crate) fn unregister(&mut self, reg: &Registry) {
let _ = reg.deregister(&mut self.socket);
}
}
fn is_connection_closed(kind: ErrorKind) -> bool {
kind == ErrorKind::BrokenPipe
|| kind == ErrorKind::ConnectionRefused
|| kind == ErrorKind::ConnectionReset
|| kind == ErrorKind::HostUnreachable
|| kind == ErrorKind::NetworkUnreachable
|| kind == ErrorKind::ConnectionAborted
|| kind == ErrorKind::NotConnected
|| kind == ErrorKind::NetworkDown
|| kind == ErrorKind::BrokenPipe
|| kind == ErrorKind::UnexpectedEof
}