use anyhow::{Error, Result};
use regex::Regex;
use std::collections::HashMap;
use std::net::SocketAddr;
use crate::exceptions::Exception;
pub fn length(bytes: &[u8]) -> Result<[u8; 4], Exception> {
let size = bytes.len() as u32;
if size > 2048 {
return Err(Exception::DataTooLarge {
size: size as usize,
});
}
Ok(size.to_be_bytes())
}
pub struct OblivionPath {
protocol: String,
host: String,
port: String,
entrance: String,
}
impl OblivionPath {
pub fn new(path: &str) -> Result<Self> {
let re = Regex::new(
r"^(?P<protocol>oblivion)?(?:://)?(?P<host>[^:/]+)(:(?P<port>\d+))?(?P<entrance>.+)?$",
)?;
if let Some(captures) = re.captures(path) {
let mut extracted_values: HashMap<&str, Option<&str>> = HashMap::new();
for capture_name in re.capture_names().flatten() {
let value = captures.name(capture_name).map(|m| m.as_str());
extracted_values.insert(capture_name, value);
}
let protocol = match extracted_values.get("protocol").unwrap() {
Some(result) => result.to_string(),
None => "oblivion".to_string(),
};
let host = match extracted_values.get("host").unwrap() {
Some(result) => result.to_string(),
None => "oblivion".to_string(),
};
let port = match extracted_values.get("port").unwrap() {
Some(result) => result.to_string(),
None => "80".to_string(),
};
let entrance = match extracted_values.get("entrance").unwrap() {
Some(result) => result.to_string(),
None => "/".to_string(),
};
Ok(Self {
protocol,
host,
port,
entrance,
})
} else {
Err(Error::from(Exception::InvalidOblivion {
entrance: path.to_string(),
}))
}
}
pub fn get_protocol(&self) -> &str {
&self.protocol
}
pub fn get_entrance(&self) -> &str {
&self.entrance
}
pub fn get_host(&self) -> &str {
&self.host
}
pub fn get_port(&self) -> &str {
&self.port
}
}
#[derive(Debug, Default)]
pub struct OblivionRequest {
pub(crate) method: String,
pub(crate) entrance: String,
protocol: String,
version: String,
remote_addr: String,
remote_port: u16,
pub(crate) aes_key: Option<[u8; 16]>,
}
impl OblivionRequest {
pub fn new(header: &str) -> Result<Self, Exception> {
let (mut method, mut entrance, mut protocol, mut version) =
(String::new(), String::new(), String::new(), String::new());
header
.split_whitespace()
.enumerate()
.try_for_each(|(index, part)| {
match index {
0 => method = part.to_string(),
1 => entrance = part.to_string(),
2 => {
let parts: Vec<&str> = part.split("/").collect();
if parts.len() == 2 {
protocol = parts[0].to_string();
version = parts[1].to_string();
} else {
return Err(Exception::InvalidHeader(header.to_string()));
}
}
_ => return Err(Exception::InvalidHeader(header.to_string())),
};
Ok(())
})?;
Ok(Self {
method,
entrance,
protocol,
version,
remote_addr: String::new(),
remote_port: 0,
aes_key: None,
})
}
pub fn set_remote_peer(&mut self, peer: &SocketAddr) {
self.remote_addr = peer.ip().to_string();
self.remote_port = peer.port();
}
pub fn get_method(&mut self) -> &str {
&self.method
}
pub fn get_entrance(&mut self) -> &str {
&self.entrance
}
pub fn get_protocol(&mut self) -> &str {
&self.protocol
}
pub fn get_version(&self) -> &str {
&self.version
}
pub fn get_ip(&self) -> &str {
&self.remote_addr
}
}