use crate::message::http_value::{HttpContentType, HttpMethod};
#[derive(Debug, Clone)]
pub struct HttpSafety {
max_body_size: Option<usize>,
allowed_methods: Option<Vec<HttpMethod>>,
allowed_content_types: Option<Vec<HttpContentType>>,
max_header_size: Option<usize>,
max_line_length: Option<usize>,
max_headers: Option<usize>,
}
const DEFAULT_MAX_BODY_SIZE: usize = 10 * 1024 * 1024; const DEFAULT_MAX_HEADER_SIZE: usize = 1024 * 1024; const DEFAULT_MAX_LINE_LENGTH: usize = 1024 * 64; const DEFAULT_MAX_HEADERS: usize = 100;
impl HttpSafety {
pub fn new() -> Self {
Self {
max_body_size: None,
allowed_methods: None,
allowed_content_types: None,
max_header_size: None,
max_line_length: None,
max_headers: None,
}
}
fn effective_max_body_size(&self) -> usize {
self.max_body_size.unwrap_or(DEFAULT_MAX_BODY_SIZE)
}
fn effective_max_header_size(&self) -> usize {
self.max_header_size.unwrap_or(DEFAULT_MAX_HEADER_SIZE)
}
fn effective_max_line_length(&self) -> usize {
self.max_line_length.unwrap_or(DEFAULT_MAX_LINE_LENGTH)
}
fn effective_max_headers(&self) -> usize {
self.max_headers.unwrap_or(DEFAULT_MAX_HEADERS)
}
pub fn max_body_size(&self) -> Option<usize> {
self.max_body_size
}
pub fn set_max_body_size(&mut self, size: Option<usize>) {
self.max_body_size = size;
}
pub fn effective_body_size(&self) -> usize {
self.effective_max_body_size()
}
pub fn check_body_size(&self, size: usize) -> bool {
size <= self.effective_max_body_size()
}
pub fn allowed_methods(&self) -> Option<&[HttpMethod]> {
self.allowed_methods.as_deref()
}
pub fn set_allowed_methods(&mut self, methods: Option<Vec<HttpMethod>>) {
self.allowed_methods = methods;
}
pub fn add_method(&mut self, method: HttpMethod) {
let methods = self.allowed_methods.get_or_insert_with(Vec::new);
if !methods.contains(&method) {
methods.push(method);
}
}
pub fn check_method(&self, method: &HttpMethod) -> bool {
match &self.allowed_methods {
Some(methods) => methods.contains(method),
None => true, }
}
pub fn allowed_content_types(&self) -> Option<&[HttpContentType]> {
self.allowed_content_types.as_deref()
}
pub fn set_allowed_content_types(&mut self, types: Option<Vec<HttpContentType>>) {
self.allowed_content_types = types;
}
pub fn add_content_type(&mut self, content_type: HttpContentType) {
let types = self.allowed_content_types.get_or_insert_with(Vec::new);
if !types.contains(&content_type) {
types.push(content_type);
}
}
pub fn check_content_type(&self, content_type: &HttpContentType) -> bool {
match &self.allowed_content_types {
Some(types) => types.contains(content_type),
None => true, }
}
pub fn max_header_size(&self) -> Option<usize> {
self.max_header_size
}
pub fn set_max_header_size(&mut self, size: Option<usize>) {
self.max_header_size = size;
}
pub fn effective_header_size(&self) -> usize {
self.effective_max_header_size()
}
pub fn check_header_size(&self, size: usize) -> bool {
size <= self.effective_max_header_size()
}
pub fn max_line_length(&self) -> Option<usize> {
self.max_line_length
}
pub fn set_max_line_length(&mut self, size: Option<usize>) {
self.max_line_length = size;
}
pub fn effective_line_length(&self) -> usize {
self.effective_max_line_length()
}
pub fn check_line_length(&self, size: usize) -> bool {
size <= self.effective_max_line_length()
}
pub fn max_headers(&self) -> Option<usize> {
self.max_headers
}
pub fn set_max_headers(&mut self, size: Option<usize>) {
self.max_headers = size;
}
pub fn effective_headers_count(&self) -> usize {
self.effective_max_headers()
}
pub fn check_headers_count(&self, count: usize) -> bool {
count <= self.effective_max_headers()
}
pub fn update(&mut self, source: &HttpSafety) {
if source.max_body_size.is_some() {
self.max_body_size = source.max_body_size;
}
if source.allowed_methods.is_some() {
self.allowed_methods = source.allowed_methods.clone();
}
if source.allowed_content_types.is_some() {
self.allowed_content_types = source.allowed_content_types.clone();
}
if source.max_header_size.is_some() {
self.max_header_size = source.max_header_size;
}
if source.max_line_length.is_some() {
self.max_line_length = source.max_line_length;
}
if source.max_headers.is_some() {
self.max_headers = source.max_headers;
}
}
pub fn merge(&mut self, other: &HttpSafety) {
self.max_body_size = Some(
self.effective_max_body_size()
.min(other.effective_max_body_size()),
);
self.max_header_size = Some(
self.effective_max_header_size()
.min(other.effective_max_header_size()),
);
self.max_line_length = Some(
self.effective_max_line_length()
.min(other.effective_max_line_length()),
);
self.max_headers = Some(
self.effective_max_headers()
.min(other.effective_max_headers()),
);
self.allowed_methods = match (&self.allowed_methods, &other.allowed_methods) {
(Some(a), Some(b)) => Some(a.iter().filter(|m| b.contains(m)).cloned().collect()),
(Some(_), None) => self.allowed_methods.clone(),
(None, Some(_)) => other.allowed_methods.clone(),
(None, None) => None,
};
self.allowed_content_types =
match (&self.allowed_content_types, &other.allowed_content_types) {
(Some(a), Some(b)) => Some(a.iter().filter(|ct| b.contains(ct)).cloned().collect()),
(Some(_), None) => self.allowed_content_types.clone(),
(None, Some(_)) => other.allowed_content_types.clone(),
(None, None) => None,
};
}
pub fn with_max_body_size(mut self, size: usize) -> Self {
self.set_max_body_size(Some(size));
self
}
pub fn with_allowed_method(mut self, method: HttpMethod) -> Self {
self.add_method(method);
self
}
pub fn with_allowed_methods(mut self, methods: Vec<HttpMethod>) -> Self {
self.set_allowed_methods(Some(methods));
self
}
pub fn with_allowed_content_type(mut self, content_type: HttpContentType) -> Self {
self.add_content_type(content_type);
self
}
pub fn with_allowed_content_types(mut self, types: Vec<HttpContentType>) -> Self {
self.set_allowed_content_types(Some(types));
self
}
pub fn with_max_header_size(mut self, size: usize) -> Self {
self.set_max_header_size(Some(size));
self
}
pub fn with_max_line_length(mut self, size: usize) -> Self {
self.set_max_line_length(Some(size));
self
}
pub fn with_max_headers(mut self, size: usize) -> Self {
self.set_max_headers(Some(size));
self
}
}
impl Default for HttpSafety {
fn default() -> Self {
Self::new()
}
}
impl Default for &HttpSafety {
fn default() -> Self {
static DEFAULT_SAFETY: HttpSafety = HttpSafety {
max_body_size: None,
allowed_methods: None,
allowed_content_types: None,
max_header_size: None,
max_line_length: None,
max_headers: None,
};
&DEFAULT_SAFETY
}
}