///|
/// Result of the intentionally small RFC 3986 URI-reference syntax check.
pub struct UriReferenceInfo {
absolute : Bool
relative : Bool
} derive(Eq, Debug)
///|
pub fn UriReferenceInfo::is_absolute(self : UriReferenceInfo) -> Bool {
self.absolute
}
///|
pub fn UriReferenceInfo::is_relative(self : UriReferenceInfo) -> Bool {
self.relative
}
///|
/// Validate the syntax needed by RFC 9457 without resolving or dereferencing.
pub fn validate_uri_reference(
value : String,
) -> Result[UriReferenceInfo, ProblemError] {
let chars = value.to_array()
let mut colon = -1
let mut boundary = chars.length()
for i = 0; i < chars.length(); i = i + 1 {
let code = chars[i].to_int()
if code <= 0x20 || code == 0x7F {
return Err(
problem_error(
Uri,
InvalidUriReference,
"URI-reference contains space or control character",
),
)
}
if chars[i] == '%' {
if i + 2 >= chars.length() ||
!is_hex(chars[i + 1]) ||
!is_hex(chars[i + 2]) {
return Err(
problem_error(
Uri,
InvalidPercentEncoding,
"malformed percent encoding",
),
)
}
}
if chars[i] == '/' || chars[i] == '?' || chars[i] == '#' {
if boundary == chars.length() {
boundary = i
}
} else if chars[i] == ':' && colon < 0 {
colon = i
}
}
let absolute = colon >= 0 && colon < boundary
if absolute && !valid_scheme(chars, colon) {
return Err(
problem_error(Uri, InvalidUriReference, "invalid URI scheme syntax"),
)
}
Ok({ absolute, relative: !absolute })
}
///|
pub fn is_absolute_uri_reference(value : String) -> Bool {
match validate_uri_reference(value) {
Ok(info) => info.is_absolute()
Err(_) => false
}
}
///|
fn valid_scheme(chars : Array[Char], colon : Int) -> Bool {
if colon <= 0 || !is_alpha(chars[0]) {
return false
}
for i = 1; i < colon; i = i + 1 {
let c = chars[i]
if !is_alpha(c) && !is_digit(c) && c != '+' && c != '-' && c != '.' {
return false
}
}
true
}
///|
fn is_alpha(c : Char) -> Bool {
(c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z')
}
///|
fn is_digit(c : Char) -> Bool {
c >= '0' && c <= '9'
}
///|
fn is_hex(c : Char) -> Bool {
is_digit(c) || (c >= 'A' && c <= 'F') || (c >= 'a' && c <= 'f')
}