///|
fn is_ascii_url_boundary(ch : Char) -> Bool {
ch == '/' || ch == '?' || ch == '#'
}
///|
fn is_url_scheme_start(ch : Char) -> Bool {
ch.is_ascii_alphabetic()
}
///|
fn is_url_scheme_char(ch : Char) -> Bool {
ch.is_ascii_alphabetic() ||
(ch >= '0' && ch <= '9') ||
ch == '+' ||
ch == '-' ||
ch == '.'
}
///|
fn is_url_ignored_scheme_char(ch : Char) -> Bool {
let code = ch.to_int()
code <= 0x20 || code == 0x7F
}
///|
fn string_contains_forbidden_url_char(value : StringView) -> Bool {
for ch in value {
let code = ch.to_int()
if code < 0x20 || code == 0x7F || ch == '\\' {
return true
}
}
false
}
///|
fn normalize_url_for_checking(value : StringView) -> String {
let out = StringBuilder::new(size_hint=value.length())
for ch in value {
if !is_url_ignored_scheme_char(ch) {
out.write_char(ch)
}
}
out.to_string()
}
///|
fn extract_url_scheme(value : StringView) -> String? {
let out = StringBuilder::new()
let mut pos = 0
let mut saw_scheme_char = false
while pos < value.length() {
let ch = value.get_char(pos).unwrap()
if is_ascii_url_boundary(ch) {
return None
} else if ch == ':' {
if saw_scheme_char {
return Some(out.to_string())
} else {
return None
}
} else if is_url_ignored_scheme_char(ch) {
pos += ch.utf16_len()
} else {
if !saw_scheme_char {
if !is_url_scheme_start(ch) {
return None
}
saw_scheme_char = true
} else if !is_url_scheme_char(ch) {
return None
}
if ch.is_ascii_uppercase() {
out.write_char(ch.to_ascii_lowercase())
} else {
out.write_char(ch)
}
pos += ch.utf16_len()
}
}
None
}
///|
fn url_scheme_prefix_is_valid(value : StringView, end : Int) -> Bool {
let mut pos = 0
let mut saw_scheme_char = false
while pos < end {
let ch = value.get_char(pos).unwrap()
if is_url_ignored_scheme_char(ch) {
pos += ch.utf16_len()
} else {
if !saw_scheme_char {
if !is_url_scheme_start(ch) {
return false
}
saw_scheme_char = true
} else if !is_url_scheme_char(ch) {
return false
}
pos += ch.utf16_len()
}
}
saw_scheme_char
}
///|
fn has_invalid_scheme_like_prefix(value : StringView) -> Bool {
let mut pos = 0
while pos < value.length() {
let ch = value.get_char(pos).unwrap()
match ch {
':' =>
if pos == 0 {
return false
} else {
return !url_scheme_prefix_is_valid(value, pos)
}
_ if is_ascii_url_boundary(ch) => return false
_ => pos += ch.utf16_len()
}
}
false
}