feat: complete Epic 1 production foundation
This commit is contained in:
@@ -1,3 +1,11 @@
|
||||
use std::net::IpAddr;
|
||||
|
||||
pub(crate) struct ParsedList<T> {
|
||||
pub(crate) items: Vec<T>,
|
||||
pub(crate) invalid: bool,
|
||||
pub(crate) out_of_range: bool,
|
||||
}
|
||||
|
||||
pub(crate) fn valid_percent_encoding(value: &str) -> bool {
|
||||
let bytes = value.as_bytes();
|
||||
let mut index = 0;
|
||||
@@ -40,3 +48,64 @@ pub(crate) fn valid_database_identifier(value: &str) -> bool {
|
||||
.bytes()
|
||||
.all(|byte| byte.is_ascii_alphanumeric() || matches!(byte, b'_' | b'-' | b'.'))
|
||||
}
|
||||
|
||||
pub(crate) fn parse_host_list(raw: &str) -> ParsedList<String> {
|
||||
let mut result = ParsedList {
|
||||
items: Vec::new(),
|
||||
invalid: false,
|
||||
out_of_range: raw.len() > 16_384,
|
||||
};
|
||||
if result.out_of_range {
|
||||
return result;
|
||||
}
|
||||
for item in raw.split(',') {
|
||||
let item = item.trim().to_ascii_lowercase();
|
||||
let base = item.strip_prefix("*.").unwrap_or(&item);
|
||||
let valid_ip = !item.starts_with("*.") && base.parse::<IpAddr>().is_ok();
|
||||
if item.is_empty()
|
||||
|| item.len() > 253
|
||||
|| item.contains('/')
|
||||
|| item.contains(char::is_whitespace)
|
||||
|| base.is_empty()
|
||||
|| (!valid_ip && base.contains(':'))
|
||||
|| (item.starts_with("*.") && base.parse::<IpAddr>().is_ok())
|
||||
{
|
||||
result.invalid = true;
|
||||
continue;
|
||||
}
|
||||
if !result.items.contains(&item) {
|
||||
result.items.push(item);
|
||||
}
|
||||
}
|
||||
if result.items.len() > 256 {
|
||||
result.out_of_range = true;
|
||||
result.items.truncate(256);
|
||||
}
|
||||
result
|
||||
}
|
||||
|
||||
pub(crate) fn parse_ip_list(raw: &str) -> ParsedList<IpAddr> {
|
||||
let mut result = ParsedList {
|
||||
items: Vec::new(),
|
||||
invalid: false,
|
||||
out_of_range: raw.len() > 4096,
|
||||
};
|
||||
if result.out_of_range {
|
||||
return result;
|
||||
}
|
||||
for item in raw.split(',').map(str::trim) {
|
||||
match item.parse::<IpAddr>() {
|
||||
Ok(value) if !result.items.contains(&value) => result.items.push(value),
|
||||
Ok(_) => {}
|
||||
Err(_) => result.invalid = true,
|
||||
}
|
||||
}
|
||||
if result.items.is_empty() {
|
||||
result.invalid = true;
|
||||
}
|
||||
if result.items.len() > 64 {
|
||||
result.out_of_range = true;
|
||||
result.items.truncate(64);
|
||||
}
|
||||
result
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user