diff options
18 files changed, 195 insertions, 263 deletions
diff --git a/crates/shirabe-php-shim/src/stream.rs b/crates/shirabe-php-shim/src/stream.rs index bd5e10af..216c68d4 100644 --- a/crates/shirabe-php-shim/src/stream.rs +++ b/crates/shirabe-php-shim/src/stream.rs @@ -84,9 +84,9 @@ pub fn stream_isatty(stream: PhpResource) -> bool { /// `STREAM_IS_URL`; this classifies by the scheme itself, so a registered custom wrapper claiming to /// be local (or vice versa) comes out differently than in PHP. pub fn stream_is_local(path: &str) -> bool { - match crate::parse_url(path, crate::PHP_URL_SCHEME) { - PhpMixed::String(scheme) => scheme.eq_ignore_ascii_case("file"), - _ => true, + match crate::parse_url(path).and_then(|url| url.scheme) { + Some(scheme) => scheme.eq_ignore_ascii_case("file"), + None => true, } } diff --git a/crates/shirabe-php-shim/src/url.rs b/crates/shirabe-php-shim/src/url.rs index c2ac725d..45920402 100644 --- a/crates/shirabe-php-shim/src/url.rs +++ b/crates/shirabe-php-shim/src/url.rs @@ -1,80 +1,40 @@ use crate::PhpMixed; use indexmap::IndexMap; -pub const PHP_URL_SCHEME: i64 = 0; -pub const PHP_URL_HOST: i64 = 1; -pub const PHP_URL_PORT: i64 = 2; -pub const PHP_URL_USER: i64 = 3; -pub const PHP_URL_PASS: i64 = 4; -pub const PHP_URL_PATH: i64 = 5; -pub const PHP_URL_QUERY: i64 = 6; -pub const PHP_URL_FRAGMENT: i64 = 7; - -pub fn parse_url(url: &str, component: i64) -> PhpMixed { - let all = parse_url_all(url); - let map = match all.as_array() { - Some(map) => map, - // parse_url_all already collapsed a malformed URL to false; propagate it. - None => return all, - }; - let key = match component { - PHP_URL_SCHEME => "scheme", - PHP_URL_HOST => "host", - PHP_URL_PORT => "port", - PHP_URL_USER => "user", - PHP_URL_PASS => "pass", - PHP_URL_PATH => "path", - PHP_URL_QUERY => "query", - PHP_URL_FRAGMENT => "fragment", - _ => return PhpMixed::Null, - }; - map.get(key).cloned().unwrap_or(PhpMixed::Null) +#[derive(Debug, Clone, Default, PartialEq, Eq)] +pub struct UrlComponents { + pub scheme: Option<String>, + pub host: Option<String>, + pub port: Option<i64>, + pub user: Option<String>, + pub pass: Option<String>, + pub path: Option<String>, + pub query: Option<String>, + pub fragment: Option<String>, } -pub fn parse_url_all(url: &str) -> PhpMixed { +/// PHP `parse_url()`. `None` for an invalid URL. +pub fn parse_url(url: &str) -> Option<UrlComponents> { // TODO(php-semantics): PHP's parse_url uses php_url_parse_ex, which accepts relative // and partial URLs and leaves an absent component absent. reqwest::Url // (WHATWG/RFC 3986) requires an absolute URL, lowercases the host of special // schemes, and normalizes the path (e.g. "http://host" yields path "/"). This // is therefore not a byte-for-byte compatible port of parse_url. - let parsed = match reqwest::Url::parse(url) { - Ok(parsed) => parsed, - Err(_) => return PhpMixed::Bool(false), - }; - let mut map: IndexMap<String, PhpMixed> = IndexMap::new(); - map.insert( - "scheme".to_string(), - PhpMixed::String(parsed.scheme().to_string()), - ); - if let Some(host) = parsed.host_str() { - map.insert("host".to_string(), PhpMixed::String(host.to_string())); - } - if let Some(port) = parsed.port() { - map.insert("port".to_string(), PhpMixed::Int(port as i64)); - } - if !parsed.username().is_empty() { - map.insert( - "user".to_string(), - PhpMixed::String(parsed.username().to_string()), - ); - } - if let Some(pass) = parsed.password() { - map.insert("pass".to_string(), PhpMixed::String(pass.to_string())); - } - let path = parsed.path(); - if !path.is_empty() { - map.insert("path".to_string(), PhpMixed::String(path.to_string())); - } - if let Some(query) = parsed.query() { - map.insert("query".to_string(), PhpMixed::String(query.to_string())); - } - if let Some(fragment) = parsed.fragment() { - map.insert( - "fragment".to_string(), - PhpMixed::String(fragment.to_string()), - ); - } - PhpMixed::Array(map) + let parsed = reqwest::Url::parse(url).ok()?; + Some(UrlComponents { + scheme: Some(parsed.scheme().to_string()), + host: parsed.host_str().map(str::to_string), + port: parsed.port().map(i64::from), + user: Some(parsed.username()) + .filter(|user| !user.is_empty()) + .map(str::to_string), + pass: parsed.password().map(str::to_string), + path: Some(parsed.path()) + .filter(|path| !path.is_empty()) + .map(str::to_string), + query: parsed.query().map(str::to_string), + fragment: parsed.fragment().map(str::to_string), + }) } pub fn http_build_query_mixed( diff --git a/crates/shirabe-symfony-filesystem/src/filesystem.rs b/crates/shirabe-symfony-filesystem/src/filesystem.rs index f8a88b02..9c2cb630 100644 --- a/crates/shirabe-symfony-filesystem/src/filesystem.rs +++ b/crates/shirabe-symfony-filesystem/src/filesystem.rs @@ -39,12 +39,8 @@ impl Filesystem { let mut do_copy = true; // PHP: !$overwriteNewerFiles && !parse_url($originFile, PHP_URL_HOST) && is_file($targetFile) - let origin_host = shirabe_php_shim::parse_url(origin_file, shirabe_php_shim::PHP_URL_HOST); - if matches!( - origin_host, - shirabe_php_shim::PhpMixed::Null | shirabe_php_shim::PhpMixed::Bool(false) - ) && shirabe_php_shim::is_file(target_file) - { + let origin_host = shirabe_php_shim::parse_url(origin_file).and_then(|url| url.host); + if origin_host.is_none() && shirabe_php_shim::is_file(target_file) { do_copy = shirabe_php_shim::filemtime(origin_file).unwrap_or(0) > shirabe_php_shim::filemtime(target_file).unwrap_or(0); } diff --git a/crates/shirabe/src/command/repository_command.rs b/crates/shirabe/src/command/repository_command.rs index ef75ffd0..4853d3d3 100644 --- a/crates/shirabe/src/command/repository_command.rs +++ b/crates/shirabe/src/command/repository_command.rs @@ -12,8 +12,8 @@ use crate::json::JsonFile; use indexmap::IndexMap; use shirabe_pcre::Preg; use shirabe_php_shim::{ - InvalidArgumentException, PHP_URL_HOST, PhpMixed, RuntimeException, impl_php_class, parse_url, - php_regex, strtolower, + InvalidArgumentException, PhpMixed, RuntimeException, impl_php_class, parse_url, php_regex, + strtolower, }; use shirabe_symfony_console::command::Command; use shirabe_symfony_console::input::InputInterface; @@ -64,9 +64,9 @@ impl RepositoryCommand { .get("url") .and_then(|v| v.as_string()) .map(|url| { - parse_url(url, PHP_URL_HOST) - .as_string() - .unwrap_or("") + parse_url(url) + .and_then(|parsed| parsed.host) + .unwrap_or_default() .ends_with("packagist.org") }) .unwrap_or(false); diff --git a/crates/shirabe/src/config.rs b/crates/shirabe/src/config.rs index be06bb21..5d990c55 100644 --- a/crates/shirabe/src/config.rs +++ b/crates/shirabe/src/config.rs @@ -10,8 +10,8 @@ use crate::io::io_interface; use indexmap::IndexMap; use shirabe_pcre::{CaptureKey, Preg}; use shirabe_php_shim::{ - E_USER_DEPRECATED, PHP_URL_HOST, PHP_URL_SCHEME, PhpMixed, RuntimeException, array_key_exists, - array_merge, array_search_mixed, array_unique, empty, filter_var_url, implode, in_array_loose, + E_USER_DEPRECATED, PhpMixed, RuntimeException, array_key_exists, array_merge, + array_search_mixed, array_unique, empty, filter_var_url, implode, in_array_loose, in_array_strict, intval, is_array, is_string, parse_url, php_regex, php_to_string, rtrim, strtolower, strtoupper, strtr, substr, trigger_error, }; @@ -1035,12 +1035,9 @@ impl Config { } // Extract scheme and throw exception on known insecure protocols - let scheme = parse_url(url, PHP_URL_SCHEME) - .as_string() - .map(|s| s.to_string()); - let hostname = parse_url(url, PHP_URL_HOST) - .as_string() - .map(|s| s.to_string()); + let parsed = parse_url(url); + let scheme = parsed.as_ref().and_then(|parsed| parsed.scheme.clone()); + let hostname = parsed.and_then(|parsed| parsed.host); if matches!(scheme.as_deref(), Some("http" | "git" | "ftp" | "svn")) { if self.get_with_flags("secure-http", 0)?.as_bool() == Some(true) { if scheme.as_deref() == Some("svn") { diff --git a/crates/shirabe/src/downloader/file_downloader.rs b/crates/shirabe/src/downloader/file_downloader.rs index 64b348e1..027205a0 100644 --- a/crates/shirabe/src/downloader/file_downloader.rs +++ b/crates/shirabe/src/downloader/file_downloader.rs @@ -27,10 +27,10 @@ use crate::util::sync_executor; use indexmap::IndexMap; use shirabe_php_shim::Catch as _; use shirabe_php_shim::{ - InvalidArgumentException, PATHINFO_BASENAME, PATHINFO_EXTENSION, PHP_URL_PATH, PhpMixed, - RuntimeException, UnexpectedValueException, array_search, file_exists, filesize, get_class, - hash, hash_file, impl_php_class, is_dir, is_executable, parse_url, pathinfo, realpath, rtrim, - spl_object_hash, strlen, strpos, strtr, trim, umask, usleep, + InvalidArgumentException, PATHINFO_BASENAME, PATHINFO_EXTENSION, PhpMixed, RuntimeException, + UnexpectedValueException, array_search, file_exists, filesize, get_class, hash, hash_file, + impl_php_class, is_dir, is_executable, parse_url, pathinfo, realpath, rtrim, spl_object_hash, + strlen, strpos, strtr, trim, umask, usleep, }; use std::sync::{LazyLock, Mutex}; @@ -259,12 +259,13 @@ impl FileDownloader { fn get_dist_path(&self, package: PackageInterfaceHandle, component: i64) -> String { pathinfo( - parse_url( - &strtr(&package.get_dist_url().unwrap_or_default(), "\\", "/"), - PHP_URL_PATH, - ) - .as_string() - .unwrap_or(""), + &parse_url(&strtr( + &package.get_dist_url().unwrap_or_default(), + "\\", + "/", + )) + .and_then(|url| url.path) + .unwrap_or_default(), component, ) } diff --git a/crates/shirabe/src/downloader/gzip_downloader.rs b/crates/shirabe/src/downloader/gzip_downloader.rs index 962c5bb8..ff229d38 100644 --- a/crates/shirabe/src/downloader/gzip_downloader.rs +++ b/crates/shirabe/src/downloader/gzip_downloader.rs @@ -14,8 +14,8 @@ use crate::util::Platform; use crate::util::ProcessExecutor; use indexmap::IndexMap; use shirabe_php_shim::{ - PATHINFO_FILENAME, PHP_URL_PATH, PhpMixed, RuntimeException, extension_loaded, fclose, fopen, - fwrite, gzclose, gzopen, gzread, impl_php_class, implode, parse_url, pathinfo, strtr, + PATHINFO_FILENAME, PhpMixed, RuntimeException, extension_loaded, fclose, fopen, fwrite, + gzclose, gzopen, gzread, impl_php_class, implode, parse_url, pathinfo, strtr, }; #[derive(Debug)] @@ -82,12 +82,13 @@ impl ArchiveDownloader for GzipDownloader { path: &str, ) -> anyhow::Result<Option<PhpMixed>> { let filename = pathinfo( - parse_url( - &strtr(&package.get_dist_url().unwrap_or_default(), "\\", "/"), - PHP_URL_PATH, - ) - .as_string() - .unwrap_or(""), + &parse_url(&strtr( + &package.get_dist_url().unwrap_or_default(), + "\\", + "/", + )) + .and_then(|url| url.path) + .unwrap_or_default(), PATHINFO_FILENAME, ); let target_filepath = std::path::Path::new(path) diff --git a/crates/shirabe/src/package/loader/validating_array_loader.rs b/crates/shirabe/src/package/loader/validating_array_loader.rs index 66123b58..6b9bea91 100644 --- a/crates/shirabe/src/package/loader/validating_array_loader.rs +++ b/crates/shirabe/src/package/loader/validating_array_loader.rs @@ -11,7 +11,7 @@ use shirabe_pcre::Preg; use shirabe_php_shim::{ CmpOp, E_USER_DEPRECATED, PHP_EOL, PhpMixed, array_intersect_key, array_values, filter_var_email, get_debug_type, is_array, is_bool, is_int, is_numeric, is_scalar, is_string, - json_encode, parse_url_all, php_regex, php_to_string, str_replace, strcasecmp, strtolower, + json_encode, parse_url, php_regex, php_to_string, str_replace, strcasecmp, strtolower, strtotime, substr, trigger_error, trim, var_export, }; use shirabe_semver::Intervals; @@ -299,24 +299,16 @@ impl ValidatingArrayLoader { return true; } - let bits = parse_url_all(value); - let bits_map = match bits { - PhpMixed::Array(m) => m, - _ => return false, + let Some(bits) = parse_url(value) else { + return false; }; - let scheme = bits_map - .get("scheme") - .and_then(|v| v.as_string()) - .unwrap_or(""); - let host = bits_map - .get("host") - .and_then(|v| v.as_string()) - .unwrap_or(""); + let scheme = bits.scheme.unwrap_or_default(); + let host = bits.host.unwrap_or_default(); if scheme.is_empty() || host.is_empty() { return false; } - if !schemes.contains(&scheme) { + if !schemes.contains(&scheme.as_str()) { return false; } diff --git a/crates/shirabe/src/repository/composer_repository.rs b/crates/shirabe/src/repository/composer_repository.rs index 03439a7b..614df9e3 100644 --- a/crates/shirabe/src/repository/composer_repository.rs +++ b/crates/shirabe/src/repository/composer_repository.rs @@ -42,7 +42,7 @@ use shirabe_php_shim::Catch as _; use shirabe_php_shim::{ AnyThrowable, CmpOp, InvalidArgumentException, LogicException, PHP_EOL, PhpMixed, RuntimeException, UnexpectedValueException, extension_loaded, hash, http_build_query_mixed, - json_decode, parse_url_all, php_regex, realpath, strtolower, strtr, urlencode, var_export, + json_decode, parse_url, php_regex, realpath, strtolower, strtr, urlencode, var_export, }; use shirabe_semver::CompilingMatcher; use shirabe_semver::constraint::AnyConstraint; @@ -207,13 +207,12 @@ impl ComposerRepository { .and_then(|v| v.as_string()) .unwrap_or("") .to_string(); - let url_bits = parse_url_all(&strtr(¤t_url, "\\", "/")); - let url_bits_arr = url_bits.as_array(); - let scheme_present = url_bits_arr - .and_then(|a| a.get("scheme")) - .and_then(|v| v.as_string()) - .is_some_and(|s| !s.is_empty()); - if url_bits_arr.is_none() || !scheme_present { + let url_bits = parse_url(&strtr(¤t_url, "\\", "/")); + let scheme_present = url_bits + .as_ref() + .and_then(|url_bits| url_bits.scheme.as_deref()) + .is_some_and(|scheme| !scheme.is_empty()); + if url_bits.is_none() || !scheme_present { return Err(UnexpectedValueException::new(format!( "Invalid url given for Composer repository: {}", current_url @@ -2100,13 +2099,11 @@ impl ComposerRepository { } pub fn get_packages_json_url(&self) -> String { - let json_url_parts = parse_url_all(&strtr(&self.url, "\\", "/")); + let json_url_parts = parse_url(&strtr(&self.url, "\\", "/")); let has_json = json_url_parts - .as_array() - .and_then(|a| a.get("path")) - .and_then(|v| v.as_string()) - .is_some_and(|p| p.contains(".json")); + .and_then(|json_url_parts| json_url_parts.path) + .is_some_and(|path| path.contains(".json")); if has_json { return self.url.clone(); } diff --git a/crates/shirabe/src/repository/vcs/github_driver.rs b/crates/shirabe/src/repository/vcs/github_driver.rs index 56ff3853..341d9f18 100644 --- a/crates/shirabe/src/repository/vcs/github_driver.rs +++ b/crates/shirabe/src/repository/vcs/github_driver.rs @@ -17,9 +17,9 @@ use indexmap::IndexMap; use shirabe_pcre::{CaptureKey, Preg}; use shirabe_php_shim::Catch as _; use shirabe_php_shim::{ - InvalidArgumentException, PhpMixed, RuntimeException, array_diff, array_key_exists, array_map, + InvalidArgumentException, PhpMixed, RuntimeException, array_diff, array_map, array_search_mixed, base64_decode, basename, empty, explode, extension_loaded, in_array_loose, - parse_url_all, php_regex, strpos, strtolower, substr, trim, urlencode, + parse_url, php_regex, strpos, strtolower, substr, trim, urlencode, }; #[derive(Debug)] @@ -666,19 +666,12 @@ impl GitHubDriver { ); } "custom" => { - let bits = parse_url_all(&item_url); - if matches!(bits, PhpMixed::Bool(false)) { + let Some(bits) = parse_url(&item_url) else { keys_to_remove.push(key_idx); continue; - } - - let bits_map = match bits { - PhpMixed::Array(m) => m, - _ => IndexMap::new(), }; - if !array_key_exists("scheme", &bits_map) - && !array_key_exists("host", &bits_map) - { + + if bits.scheme.is_none() && bits.host.is_none() { if Preg::is_match(php_regex!(r"{^[a-z0-9-]++\.[a-z]{2,3}$}"), &item_url) { result[key_idx].insert( "url".to_string(), diff --git a/crates/shirabe/src/util/auth_helper.rs b/crates/shirabe/src/util/auth_helper.rs index 2c2ee725..3b8aa2e7 100644 --- a/crates/shirabe/src/util/auth_helper.rs +++ b/crates/shirabe/src/util/auth_helper.rs @@ -11,9 +11,8 @@ use crate::util::GitLab; use indexmap::IndexMap; use shirabe_pcre::Preg; use shirabe_php_shim::{ - PHP_URL_HOST, PHP_URL_PATH, PHP_URL_SCHEME, PhpMixed, RuntimeException, base64_encode, explode, - in_array_loose, in_array_strict, is_array, is_string, json_decode, parse_url, php_regex, - str_replace, strpos, strtolower, substr, trim, + PhpMixed, RuntimeException, base64_encode, explode, in_array_loose, in_array_strict, is_array, + is_string, json_decode, parse_url, php_regex, str_replace, strpos, strtolower, substr, trim, }; #[derive(Debug)] @@ -257,11 +256,11 @@ impl AuthHelper { } } - let scheme = parse_url(url, PHP_URL_SCHEME); + let scheme = parse_url(url).and_then(|parsed| parsed.scheme); if !git_lab_util.authorize_oauth(origin) && (!self.io.is_interactive() || !git_lab_util.authorize_oauth_interactively( - scheme.as_string().unwrap_or(""), + scheme.as_deref().unwrap_or(""), origin, Some(&message), )?) @@ -632,16 +631,21 @@ impl AuthHelper { /// /// @return bool Whether the given URL is a public BitBucket download which requires no authentication. pub fn is_public_bit_bucket_download(&self, url_to_bit_bucket_file: &str) -> bool { - let domain = parse_url(url_to_bit_bucket_file, PHP_URL_HOST); - let domain_str = domain.as_string().unwrap_or(""); + let parsed = parse_url(url_to_bit_bucket_file); + let domain_str = parsed + .as_ref() + .and_then(|parsed| parsed.host.as_deref()) + .unwrap_or(""); if strpos(domain_str, "bitbucket.org").is_none() { // Bitbucket downloads are hosted on amazonaws. // We do not need to authenticate there at all return true; } - let path = parse_url(url_to_bit_bucket_file, PHP_URL_PATH); - let path_str = path.as_string().unwrap_or(""); + let path_str = parsed + .as_ref() + .and_then(|parsed| parsed.path.as_deref()) + .unwrap_or(""); // Path for a public download follows this pattern /{user}/{repo}/downloads/{whatever} // {@link https://blog.bitbucket.org/2009/04/12/new-feature-downloads/} diff --git a/crates/shirabe/src/util/http/curl_downloader.rs b/crates/shirabe/src/util/http/curl_downloader.rs index ff59266e..742e0fd3 100644 --- a/crates/shirabe/src/util/http/curl_downloader.rs +++ b/crates/shirabe/src/util/http/curl_downloader.rs @@ -628,22 +628,31 @@ impl CurlDownloader { if let Some(location_header) = response.inner.get_header("location") && !location_header.is_empty() { - if !parse_url(&location_header, shirabe_php_shim::PHP_URL_SCHEME).is_null() { + let location_parsed = parse_url(&location_header); + if location_parsed + .as_ref() + .and_then(|parsed| parsed.scheme.as_deref()) + .is_some_and(|scheme| !scheme.is_empty() && scheme != "0") + { // Absolute URL; e.g. https://example.com/composer target_url = location_header; - } else if !parse_url(&location_header, shirabe_php_shim::PHP_URL_HOST).is_null() { + } else if location_parsed + .as_ref() + .and_then(|parsed| parsed.host.as_deref()) + .is_some_and(|host| !host.is_empty() && host != "0") + { // Scheme relative; e.g. //example.com/foo target_url = format!( "{}:{}", - parse_url(url, shirabe_php_shim::PHP_URL_SCHEME) - .as_string() - .unwrap_or(""), + parse_url(url) + .and_then(|parsed| parsed.scheme) + .unwrap_or_default(), location_header ); } else if location_header.starts_with('/') { // Absolute path; e.g. /foo - let url_host = parse_url(url, shirabe_php_shim::PHP_URL_HOST); - let url_host_str = url_host.as_string().unwrap_or(""); + let url_host = parse_url(url).and_then(|parsed| parsed.host); + let url_host_str = url_host.as_deref().unwrap_or(""); target_url = Preg::replace( format!( r"{{^(.+(?://|@){}(?::\d+)?)(?:[/\?].*)?$}}", diff --git a/crates/shirabe/src/util/http/proxy_item.rs b/crates/shirabe/src/util/http/proxy_item.rs index 73948f88..288a384d 100644 --- a/crates/shirabe/src/util/http/proxy_item.rs +++ b/crates/shirabe/src/util/http/proxy_item.rs @@ -3,7 +3,7 @@ use crate::util::http::RequestProxy; use indexmap::IndexMap; use shirabe_php_shim::{ - PhpMixed, RuntimeException, base64_encode, parse_url_all, rawurldecode, strpbrk, + PhpMixed, RuntimeException, base64_encode, parse_url, rawurldecode, strpbrk, }; #[derive(Debug)] @@ -23,44 +23,34 @@ impl ProxyItem { return Err(RuntimeException::new(syntax_error)); } - let proxy_parsed = parse_url_all(&proxy_url); - let proxy = match proxy_parsed.as_array() { - None => { - return Err(RuntimeException::new(syntax_error)); - } - Some(a) => a.clone(), + let Some(proxy) = parse_url(&proxy_url) else { + return Err(RuntimeException::new(syntax_error)); }; - if !proxy.contains_key("host") { + let Some(host) = proxy.host else { return Err(RuntimeException::new(format!( "unable to find proxy host in {}", env_name ))); - } + }; - let scheme = if proxy.contains_key("scheme") { - format!( - "{}://", - proxy["scheme"].as_string().unwrap_or("").to_lowercase() - ) - } else { - "http://".to_string() + let scheme = match &proxy.scheme { + Some(scheme) => format!("{}://", scheme.to_lowercase()), + None => "http://".to_string(), }; let mut safe = String::new(); let mut curl_auth: Option<String> = None; let mut options_auth: Option<String> = None; - if proxy.contains_key("user") { + if let Some(user_raw) = &proxy.user { safe = "***".to_string(); - let user_raw = proxy["user"].as_string().unwrap_or(""); let auth_raw = rawurldecode(user_raw); - let mut user = user_raw.to_string(); + let mut user = user_raw.clone(); let mut auth = auth_raw; - if proxy.contains_key("pass") { - let pass_raw = proxy["pass"].as_string().unwrap_or(""); + if let Some(pass_raw) = &proxy.pass { safe += ":***"; user += &format!(":{}", pass_raw); auth += &format!(":{}", rawurldecode(pass_raw)); @@ -77,11 +67,10 @@ impl ProxyItem { } } - let host = proxy["host"].as_string().unwrap_or("").to_string(); let port: Option<i64>; - if proxy.contains_key("port") { - port = proxy["port"].as_int(); + if let Some(proxy_port) = proxy.port { + port = Some(proxy_port); } else if scheme == "http://" { port = Some(80); } else if scheme == "https://" { diff --git a/crates/shirabe/src/util/no_proxy_pattern.rs b/crates/shirabe/src/util/no_proxy_pattern.rs index 6d19637a..85e1f472 100644 --- a/crates/shirabe/src/util/no_proxy_pattern.rs +++ b/crates/shirabe/src/util/no_proxy_pattern.rs @@ -3,9 +3,8 @@ use indexmap::IndexMap; use shirabe_pcre::Preg; use shirabe_php_shim::{ - PHP_URL_HOST, PHP_URL_PORT, PHP_URL_SCHEME, PhpMixed, RuntimeException, array_key_exists, - empty, explode, filter_var_int_with_range, filter_var_ip, inet_pton, ltrim, parse_url, - php_regex, stripos, strlen, strpbrk, strpos, substr, substr_count, + RuntimeException, array_key_exists, explode, filter_var_int_with_range, filter_var_ip, + inet_pton, ltrim, parse_url, php_regex, stripos, strlen, strpbrk, strpos, substr, substr_count, }; /// Tests URLs against NO_PROXY patterns @@ -70,23 +69,26 @@ impl NoProxyPattern { /// Returns false is the url cannot be parsed, otherwise a data object fn get_url_data(&self, url: &str) -> anyhow::Result<Option<UrlData>> { - let host = parse_url(url, PHP_URL_HOST); - if empty(&host) { + let parsed = parse_url(url); + let Some(host_str) = parsed + .as_ref() + .and_then(|parsed| parsed.host.clone()) + .filter(|host| !host.is_empty() && host != "0") + else { return Ok(None); - } - let host_str = host.as_string().unwrap_or("").to_string(); + }; - let mut port_mixed = parse_url(url, PHP_URL_PORT); + let mut port = parsed.as_ref().and_then(|parsed| parsed.port); - if empty(&port_mixed) { - match parse_url(url, PHP_URL_SCHEME).as_string() { - Some("http") => port_mixed = PhpMixed::Int(80), - Some("https") => port_mixed = PhpMixed::Int(443), + if port.is_none_or(|port| port == 0) { + match parsed.as_ref().and_then(|parsed| parsed.scheme.as_deref()) { + Some("http") => port = Some(80), + Some("https") => port = Some(443), _ => {} } } - let port_int = port_mixed.as_int().unwrap_or(0); + let port_int = port.unwrap_or(0); let host_name = format!( "{}{}", host_str, diff --git a/crates/shirabe/src/util/remote_filesystem.rs b/crates/shirabe/src/util/remote_filesystem.rs index 1f0b1279..61165b28 100644 --- a/crates/shirabe/src/util/remote_filesystem.rs +++ b/crates/shirabe/src/util/remote_filesystem.rs @@ -16,12 +16,11 @@ use indexmap::IndexMap; use shirabe_pcre::{CaptureKey, Preg}; use shirabe_php_shim::Catch as _; use shirabe_php_shim::{ - PHP_URL_HOST, PHP_URL_PATH, PHP_URL_SCHEME, PhpMixed, RuntimeException, STREAM_NOTIFY_FAILURE, - STREAM_NOTIFY_FILE_SIZE_IS, STREAM_NOTIFY_PROGRESS, array_replace_recursive, base64_encode, - explode, extension_loaded, file_get_contents, file_get_contents5, file_put_contents, - filter_var_boolean, gethostbyname, http_clear_last_response_headers, - http_get_last_response_headers, ini_get, json_decode, parse_url, php_regex, preg_quote, strpos, - strtolower, strtr, substr, trim, zlib_decode, + PhpMixed, RuntimeException, STREAM_NOTIFY_FAILURE, STREAM_NOTIFY_FILE_SIZE_IS, + STREAM_NOTIFY_PROGRESS, array_replace_recursive, base64_encode, explode, extension_loaded, + file_get_contents, file_get_contents5, file_put_contents, filter_var_boolean, gethostbyname, + http_clear_last_response_headers, http_get_last_response_headers, ini_get, json_decode, + parse_url, php_regex, preg_quote, strpos, strtolower, strtr, substr, trim, zlib_decode, }; /// Result of `RemoteFilesystem::get` — string content, `true` (for copy), or `false`. @@ -180,10 +179,9 @@ impl RemoteFilesystem { file_name: Option<String>, progress: bool, ) -> anyhow::Result<GetResult> { - self.scheme = parse_url(&strtr(file_url, "\\", "/"), PHP_URL_SCHEME) - .as_string() - .unwrap_or("") - .to_string(); + self.scheme = parse_url(&strtr(file_url, "\\", "/")) + .and_then(|parsed| parsed.scheme) + .unwrap_or_default(); self.bytes_max = 0; self.origin_url = origin_url.to_string(); self.file_url = file_url.to_string(); @@ -471,9 +469,9 @@ impl RemoteFilesystem { && substr(&self.file_url, -4, None) == ".zip" && (location_header.is_none() || substr( - parse_url(location_header.as_deref().unwrap_or(""), PHP_URL_PATH) - .as_string() - .unwrap_or(""), + &parse_url(location_header.as_deref().unwrap_or("")) + .and_then(|parsed| parsed.path) + .unwrap_or_default(), -4, None, ) != ".zip") @@ -929,23 +927,23 @@ impl RemoteFilesystem { ) -> anyhow::Result<Option<String>> { let mut target_url: Option<String> = None; if let Some(location_header) = Response::find_header_value(response_headers, "location") { - if !parse_url(&location_header, PHP_URL_SCHEME) - .as_string() - .unwrap_or("") - .is_empty() + let location_parsed = parse_url(&location_header); + if location_parsed + .as_ref() + .and_then(|parsed| parsed.scheme.as_deref()) + .is_some_and(|scheme| !scheme.is_empty() && scheme != "0") { target_url = Some(location_header); - } else if parse_url(&location_header, PHP_URL_HOST) - .as_string() - .map(|s| !s.is_empty()) - .unwrap_or(false) + } else if location_parsed + .as_ref() + .and_then(|parsed| parsed.host.as_deref()) + .is_some_and(|host| !host.is_empty() && host != "0") { target_url = Some(format!("{}:{}", self.scheme, location_header)); } else if location_header.starts_with('/') { - let url_host = parse_url(&self.file_url, PHP_URL_HOST) - .as_string() - .unwrap_or("") - .to_string(); + let url_host = parse_url(&self.file_url) + .and_then(|parsed| parsed.host) + .unwrap_or_default(); target_url = Some(Preg::replace( format!( @@ -980,10 +978,9 @@ impl RemoteFilesystem { additional_options.insert("redirects".to_string(), PhpMixed::Int(self.redirects)); - let host = parse_url(&target_url, PHP_URL_HOST) - .as_string() - .unwrap_or("") - .to_string(); + let host = parse_url(&target_url) + .and_then(|parsed| parsed.host) + .unwrap_or_default(); let res = self.get( &host, &target_url, diff --git a/crates/shirabe/src/util/svn.rs b/crates/shirabe/src/util/svn.rs index bde2583d..9662c24d 100644 --- a/crates/shirabe/src/util/svn.rs +++ b/crates/shirabe/src/util/svn.rs @@ -9,8 +9,8 @@ use crate::util::ProcessExecutor; use indexmap::IndexMap; use shirabe_pcre::{CaptureKey, Preg}; use shirabe_php_shim::{ - LogicException, PHP_URL_HOST, PhpMixed, RuntimeException, empty, implode, parse_url, - parse_url_all, php_regex, stripos, strpos, trim, + LogicException, PhpMixed, RuntimeException, implode, parse_url, php_regex, stripos, strpos, + trim, }; use std::sync::Mutex; @@ -344,8 +344,8 @@ impl Svn { let auth_config = self.config.borrow_mut().get("http-basic"); - let host = parse_url(&self.url, PHP_URL_HOST); - let host_str = host.as_string().unwrap_or(""); + let host = parse_url(&self.url).and_then(|parsed| parsed.host); + let host_str = host.as_deref().unwrap_or(""); let auth_for_host = auth_config .as_array() .and_then(|m| m.get(host_str)) @@ -376,28 +376,21 @@ impl Svn { /// Create the auth params from the url fn create_auth_from_url(&mut self) -> bool { - let uri = parse_url_all(&self.url); - let uri_arr = match uri.as_array() { - Some(a) => a.clone(), - None => { - self.has_auth = Some(false); - return false; - } + let Some(uri) = parse_url(&self.url) else { + self.has_auth = Some(false); + return false; }; - let user_val = uri_arr.get("user").cloned().unwrap_or(PhpMixed::Null); - if empty(&user_val) { + let Some(user) = uri.user.filter(|user| !user.is_empty() && user != "0") else { self.has_auth = Some(false); return false; - } + }; - let pass_val = uri_arr.get("pass").cloned().unwrap_or(PhpMixed::Null); self.credentials = Some(SvnCredentials { - username: user_val.as_string().unwrap_or("").to_string(), - password: if !empty(&pass_val) { - pass_val.as_string().unwrap_or("").to_string() - } else { - String::new() - }, + username: user, + password: uri + .pass + .filter(|pass| !pass.is_empty() && pass != "0") + .unwrap_or_default(), }); self.has_auth = Some(true); diff --git a/crates/shirabe/src/util/url.rs b/crates/shirabe/src/util/url.rs index c7cbd228..ea9e4401 100644 --- a/crates/shirabe/src/util/url.rs +++ b/crates/shirabe/src/util/url.rs @@ -4,17 +4,14 @@ use crate::config::Config; use crate::util::GitHub; use indexmap::IndexMap; use shirabe_pcre::{CaptureKey, Preg}; -use shirabe_php_shim::{ - PHP_URL_HOST, PHP_URL_PORT, PhpMixed, in_array_strict, parse_url, php_regex, -}; +use shirabe_php_shim::{PhpMixed, in_array_strict, parse_url, php_regex}; pub struct Url; impl Url { pub fn update_dist_reference(config: &Config, mut url: String, r#ref: &str) -> String { - let host = parse_url(&url, PHP_URL_HOST) - .as_string() - .map(|s| s.to_string()) + let host = parse_url(&url) + .and_then(|parsed| parsed.host) .unwrap_or_default(); if host == "api.github.com" || host == "github.com" || host == "www.github.com" { @@ -121,11 +118,15 @@ impl Url { return url.to_string(); } - let mut origin = parse_url(url, PHP_URL_HOST) - .as_string() - .map(|s| s.to_string()) + let parsed = parse_url(url); + let mut origin = parsed + .as_ref() + .and_then(|parsed| parsed.host.clone()) .unwrap_or_default(); - if let Some(port) = parse_url(url, PHP_URL_PORT).as_int() { + if let Some(port) = parsed + .and_then(|parsed| parsed.port) + .filter(|port| *port != 0) + { origin = format!("{}:{}", origin, port); } diff --git a/crates/shirabe/tests/util/remote_filesystem_test.rs b/crates/shirabe/tests/util/remote_filesystem_test.rs index 6d21732f..d294c5d2 100644 --- a/crates/shirabe/tests/util/remote_filesystem_test.rs +++ b/crates/shirabe/tests/util/remote_filesystem_test.rs @@ -6,8 +6,8 @@ use indexmap::IndexMap; use shirabe::io::IOInterface; use shirabe::util::{GetResult, RemoteFilesystem}; use shirabe_php_shim::{ - PHP_URL_HOST, PhpMixed, STREAM_NOTIFY_FILE_SIZE_IS, STREAM_NOTIFY_PROGRESS, file_get_contents, - parse_url, strpos, unlink, + PhpMixed, STREAM_NOTIFY_FILE_SIZE_IS, STREAM_NOTIFY_PROGRESS, file_get_contents, parse_url, + strpos, unlink, }; // Mirrors RemoteFilesystemTest::getConfigMock: get('github-domains') and @@ -356,8 +356,8 @@ fn test_bit_bucket_public_download() { let io: std::rc::Rc<std::cell::RefCell<dyn IOInterface>> = std::rc::Rc::new(std::cell::RefCell::new(IOStub::new())); let mut rfs = RemoteFilesystem::new(io, config_mock(), IndexMap::new(), false, None); - let hostname = parse_url(url, PHP_URL_HOST); - let hostname = hostname.as_string().unwrap_or(""); + let hostname = parse_url(url).and_then(|parsed| parsed.host); + let hostname = hostname.as_deref().unwrap_or(""); let (result, _headers) = rfs .get_contents(hostname, url, false, IndexMap::new()) |
