mirror of
https://github.com/storytold/lightcraft.git
synced 2026-10-24 10:09:01 -06:00
Merge PR #2410: Match URL schemes case-insensitively in Url::parse and Url::join
crates/fetch/src/http.rs: keeps #2406's remove_dot_segments and #2410's strip_scheme helpers; tests keep all three PRs' cases
This commit is contained in:
@@ -89,6 +89,12 @@ fn remove_dot_segments(path: &str) -> String {
|
||||
result
|
||||
}
|
||||
|
||||
/// `s` without the leading `prefix`, matched ASCII case-insensitively (RFC 3986 §3.1).
|
||||
fn strip_scheme<'a>(s: &'a str, prefix: &str) -> Option<&'a str> {
|
||||
let head = s.get(..prefix.len())?;
|
||||
head.eq_ignore_ascii_case(prefix).then(|| s.get(prefix.len()..).unwrap_or_default())
|
||||
}
|
||||
|
||||
impl Url {
|
||||
pub fn parse(s: &str) -> Result<Url, HttpError> {
|
||||
let bad = |why: &str| HttpError::BadUrl(why.to_string());
|
||||
@@ -99,9 +105,9 @@ impl Url {
|
||||
if s.chars().any(|c| c.is_control() || c == ' ') {
|
||||
return Err(bad("contains spaces or control characters"));
|
||||
}
|
||||
let (tls, rest) = if let Some(r) = s.strip_prefix("https://") {
|
||||
let (tls, rest) = if let Some(r) = strip_scheme(s, "https://") {
|
||||
(true, r)
|
||||
} else if let Some(r) = s.strip_prefix("http://") {
|
||||
} else if let Some(r) = strip_scheme(s, "http://") {
|
||||
(false, r)
|
||||
} else {
|
||||
return Err(bad("only http:// and https:// are supported"));
|
||||
@@ -144,7 +150,7 @@ impl Url {
|
||||
/// `Location` of a redirect, resolved against this URL.
|
||||
pub fn join(&self, location: &str) -> Result<Url, HttpError> {
|
||||
let l = location.trim();
|
||||
if l.starts_with("http://") || l.starts_with("https://") {
|
||||
if strip_scheme(l, "http://").is_some() || strip_scheme(l, "https://").is_some() {
|
||||
let url = Url::parse(l)?;
|
||||
if self.tls && !url.tls {
|
||||
return Err(HttpError::BadUrl("redirect from https to http refused".into()));
|
||||
@@ -670,6 +676,15 @@ mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn url_scheme_is_matched_case_insensitively() {
|
||||
let u = Url::parse("HTTPS://A.example/z").unwrap();
|
||||
assert_eq!((u.tls, u.host.as_str(), u.port, u.path.as_str()), (true, "a.example", 443, "/z"));
|
||||
assert!(Url::parse("Http://a.example/").is_ok());
|
||||
let j = Url::parse("https://a.example/start").unwrap().join("HTTPS://cdn.example/file").unwrap();
|
||||
assert_eq!((j.tls, j.host.as_str(), j.path.as_str()), (true, "cdn.example", "/file"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parses_urls() {
|
||||
let u = Url::parse("https://cdn.example.com/models/sam3/model.safetensors?sig=1#x").unwrap();
|
||||
|
||||
Reference in New Issue
Block a user