mirror of
https://github.com/servo/servo.git
synced 2025-08-07 06:25:32 +01:00
Handle URL without scheme (#30148)
* cleanup and move user input logix into servoshell * fix fmt * add more tests * rename sanitize_url and add location bar test for unix system * fmt and missing rename * check for host, fix test-error * remove println, add condtion for not-none * fmt * clean up * review update * fix build failure cause by embedder_traits::resources * add cfg target-os windows * fmt * use to_file_path() instead of path()
This commit is contained in:
parent
fe7bdb7e4b
commit
bbbdb77a7a
5 changed files with 184 additions and 24 deletions
|
@ -8,6 +8,7 @@ use std::cell::{Cell, RefCell, RefMut};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use std::time::Instant;
|
use std::time::Instant;
|
||||||
|
use std::{env, fs};
|
||||||
|
|
||||||
use gleam::gl;
|
use gleam::gl;
|
||||||
use log::{info, trace, warn};
|
use log::{info, trace, warn};
|
||||||
|
@ -71,7 +72,11 @@ impl App {
|
||||||
|
|
||||||
// Handle browser state.
|
// Handle browser state.
|
||||||
let browser = Browser::new(window.clone());
|
let browser = Browser::new(window.clone());
|
||||||
let initial_url = get_default_url(url);
|
let initial_url = get_default_url(
|
||||||
|
url.as_ref().map(String::as_str),
|
||||||
|
env::current_dir().unwrap(),
|
||||||
|
|path| fs::metadata(path).is_ok(),
|
||||||
|
);
|
||||||
|
|
||||||
let mut app = App {
|
let mut app = App {
|
||||||
event_queue: RefCell::new(vec![]),
|
event_queue: RefCell::new(vec![]),
|
||||||
|
|
|
@ -25,7 +25,7 @@ use servo::webrender_api::ScrollLocation;
|
||||||
use tinyfiledialogs::{self, MessageBoxIcon, OkCancel, YesNo};
|
use tinyfiledialogs::{self, MessageBoxIcon, OkCancel, YesNo};
|
||||||
|
|
||||||
use crate::keyutils::{CMD_OR_ALT, CMD_OR_CONTROL};
|
use crate::keyutils::{CMD_OR_ALT, CMD_OR_CONTROL};
|
||||||
use crate::parser::sanitize_url;
|
use crate::parser::location_bar_input_to_url;
|
||||||
use crate::window_trait::{WindowPortsMethods, LINE_HEIGHT};
|
use crate::window_trait::{WindowPortsMethods, LINE_HEIGHT};
|
||||||
|
|
||||||
pub struct Browser<Window: WindowPortsMethods + ?Sized> {
|
pub struct Browser<Window: WindowPortsMethods + ?Sized> {
|
||||||
|
@ -122,7 +122,7 @@ where
|
||||||
let title = "URL or search query";
|
let title = "URL or search query";
|
||||||
let input = tinyfiledialogs::input_box(title, title, &tiny_dialog_escape(&url));
|
let input = tinyfiledialogs::input_box(title, title, &tiny_dialog_escape(&url));
|
||||||
if let Some(input) = input {
|
if let Some(input) = input {
|
||||||
if let Some(url) = sanitize_url(&input) {
|
if let Some(url) = location_bar_input_to_url(&input) {
|
||||||
if let Some(id) = self.browser_id {
|
if let Some(id) = self.browser_id {
|
||||||
self.event_queue.push(EmbedderEvent::LoadUrl(id, url));
|
self.event_queue.push(EmbedderEvent::LoadUrl(id, url));
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,12 +11,12 @@ use euclid::Length;
|
||||||
use log::{trace, warn};
|
use log::{trace, warn};
|
||||||
use servo::compositing::windowing::EmbedderEvent;
|
use servo::compositing::windowing::EmbedderEvent;
|
||||||
use servo::servo_geometry::DeviceIndependentPixel;
|
use servo::servo_geometry::DeviceIndependentPixel;
|
||||||
use servo::servo_url::ServoUrl;
|
|
||||||
use servo::webrender_surfman::WebrenderSurfman;
|
use servo::webrender_surfman::WebrenderSurfman;
|
||||||
|
|
||||||
use crate::browser::Browser;
|
use crate::browser::Browser;
|
||||||
use crate::egui_glue::EguiGlow;
|
use crate::egui_glue::EguiGlow;
|
||||||
use crate::events_loop::EventsLoop;
|
use crate::events_loop::EventsLoop;
|
||||||
|
use crate::parser::location_bar_input_to_url;
|
||||||
use crate::window_trait::WindowPortsMethods;
|
use crate::window_trait::WindowPortsMethods;
|
||||||
|
|
||||||
pub struct Minibrowser {
|
pub struct Minibrowser {
|
||||||
|
@ -130,11 +130,12 @@ impl Minibrowser {
|
||||||
MinibrowserEvent::Go => {
|
MinibrowserEvent::Go => {
|
||||||
let browser_id = browser.browser_id().unwrap();
|
let browser_id = browser.browser_id().unwrap();
|
||||||
let location = self.location.borrow();
|
let location = self.location.borrow();
|
||||||
let Ok(url) = ServoUrl::parse(&location) else {
|
if let Some(url) = location_bar_input_to_url(&location.clone()) {
|
||||||
|
app_event_queue.push(EmbedderEvent::LoadUrl(browser_id, url));
|
||||||
|
} else {
|
||||||
warn!("failed to parse location");
|
warn!("failed to parse location");
|
||||||
break;
|
break;
|
||||||
};
|
}
|
||||||
app_event_queue.push(EmbedderEvent::LoadUrl(browser_id, url));
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,8 +2,7 @@
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
use std::env;
|
use std::path::{Path, PathBuf};
|
||||||
use std::path::Path;
|
|
||||||
|
|
||||||
use log::warn;
|
use log::warn;
|
||||||
use servo::net_traits::pub_domains::is_reg_domain;
|
use servo::net_traits::pub_domains::is_reg_domain;
|
||||||
|
@ -21,35 +20,57 @@ pub fn parse_url_or_filename(cwd: &Path, input: &str) -> Result<ServoUrl, ()> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_default_url(url_opt: Option<String>) -> ServoUrl {
|
pub fn get_default_url(
|
||||||
|
url_opt: Option<&str>,
|
||||||
|
cwd: impl AsRef<Path>,
|
||||||
|
exists: impl FnOnce(&PathBuf) -> bool,
|
||||||
|
) -> ServoUrl {
|
||||||
// If the url is not provided, we fallback to the homepage in prefs,
|
// If the url is not provided, we fallback to the homepage in prefs,
|
||||||
// or a blank page in case the homepage is not set either.
|
// or a blank page in case the homepage is not set either.
|
||||||
let cwd = env::current_dir().unwrap();
|
let mut new_url = None;
|
||||||
|
let cmdline_url = url_opt
|
||||||
|
.clone()
|
||||||
|
.map(|s| s.to_string())
|
||||||
|
.and_then(|url_string| {
|
||||||
|
parse_url_or_filename(cwd.as_ref(), &url_string)
|
||||||
|
.map_err(|error| {
|
||||||
|
warn!("URL parsing failed ({:?}).", error);
|
||||||
|
error
|
||||||
|
})
|
||||||
|
.ok()
|
||||||
|
});
|
||||||
|
|
||||||
let cmdline_url = url_opt.map(|s| s.to_string()).and_then(|url_string| {
|
if let Some(url) = cmdline_url.clone() {
|
||||||
parse_url_or_filename(&cwd, &url_string)
|
// Check if the URL path corresponds to a file
|
||||||
.map_err(|error| {
|
match (url.scheme(), url.host(), url.to_file_path()) {
|
||||||
warn!("URL parsing failed ({:?}).", error);
|
("file", None, Ok(ref path)) if exists(path) => {
|
||||||
error
|
new_url = cmdline_url;
|
||||||
})
|
},
|
||||||
.ok()
|
_ => {},
|
||||||
});
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if new_url.is_none() && !url_opt.is_none() {
|
||||||
|
new_url = location_bar_input_to_url(url_opt.unwrap());
|
||||||
|
}
|
||||||
|
|
||||||
let pref_url = {
|
let pref_url = {
|
||||||
let homepage_url = pref!(shell.homepage);
|
let homepage_url = pref!(shell.homepage);
|
||||||
parse_url_or_filename(&cwd, &homepage_url).ok()
|
parse_url_or_filename(cwd.as_ref(), &homepage_url).ok()
|
||||||
};
|
};
|
||||||
let blank_url = ServoUrl::parse("about:blank").ok();
|
let blank_url = ServoUrl::parse("about:blank").ok();
|
||||||
|
|
||||||
cmdline_url.or(pref_url).or(blank_url).unwrap()
|
new_url.or(pref_url).or(blank_url).unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn sanitize_url(request: &str) -> Option<ServoUrl> {
|
pub fn location_bar_input_to_url(request: &str) -> Option<ServoUrl> {
|
||||||
let request = request.trim();
|
let request = request.trim();
|
||||||
ServoUrl::parse(request)
|
ServoUrl::parse(request)
|
||||||
.ok()
|
.ok()
|
||||||
.or_else(|| {
|
.or_else(|| {
|
||||||
if request.contains('/') || is_reg_domain(request) {
|
if request.starts_with('/') {
|
||||||
|
ServoUrl::parse(&format!("file://{}", request)).ok()
|
||||||
|
} else if request.contains('/') || is_reg_domain(request) {
|
||||||
ServoUrl::parse(&format!("https://{}", request)).ok()
|
ServoUrl::parse(&format!("https://{}", request)).ok()
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
|
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
|
||||||
use crate::parser::parse_url_or_filename;
|
use crate::parser::{get_default_url, location_bar_input_to_url, parse_url_or_filename};
|
||||||
|
|
||||||
#[cfg(not(target_os = "windows"))]
|
#[cfg(not(target_os = "windows"))]
|
||||||
const FAKE_CWD: &'static str = "/fake/cwd";
|
const FAKE_CWD: &'static str = "/fake/cwd";
|
||||||
|
@ -85,3 +85,136 @@ fn test_argument_parsing_special() {
|
||||||
assert_eq!(url.query(), None);
|
assert_eq!(url.query(), None);
|
||||||
assert_eq!(url.fragment(), None);
|
assert_eq!(url.fragment(), None);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Helper function to test url
|
||||||
|
fn test_url(input: &str, location: &str, cmdline_if_exists: &str, cmdline_otherwise: &str) {
|
||||||
|
assert_eq!(
|
||||||
|
location_bar_input_to_url(input).unwrap().into_string(),
|
||||||
|
location
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
get_default_url(Some(input), FAKE_CWD, |_| true).into_string(),
|
||||||
|
cmdline_if_exists
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
get_default_url(Some(input), FAKE_CWD, |_| false).into_string(),
|
||||||
|
cmdline_otherwise
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[cfg(not(target_os = "windows"))]
|
||||||
|
fn test_cmdline_and_location_bar_url() {
|
||||||
|
test_url(
|
||||||
|
"data:text/html,a",
|
||||||
|
"data:text/html,a",
|
||||||
|
"data:text/html,a",
|
||||||
|
"data:text/html,a",
|
||||||
|
);
|
||||||
|
test_url(
|
||||||
|
"README.md",
|
||||||
|
"https://readme.md/",
|
||||||
|
"file:///fake/cwd/README.md",
|
||||||
|
"https://readme.md/",
|
||||||
|
);
|
||||||
|
test_url(
|
||||||
|
"nic.md",
|
||||||
|
"https://nic.md/",
|
||||||
|
"file:///fake/cwd/nic.md",
|
||||||
|
"https://nic.md/",
|
||||||
|
);
|
||||||
|
test_url(
|
||||||
|
"nic.md/ro",
|
||||||
|
"https://nic.md/ro",
|
||||||
|
"file:///fake/cwd/nic.md/ro",
|
||||||
|
"https://nic.md/ro",
|
||||||
|
);
|
||||||
|
test_url(
|
||||||
|
"foo.txt",
|
||||||
|
"https://foo.txt/",
|
||||||
|
"file:///fake/cwd/foo.txt",
|
||||||
|
"https://foo.txt/",
|
||||||
|
);
|
||||||
|
test_url(
|
||||||
|
"foo.txt/ro",
|
||||||
|
"https://foo.txt/ro",
|
||||||
|
"file:///fake/cwd/foo.txt/ro",
|
||||||
|
"https://foo.txt/ro",
|
||||||
|
);
|
||||||
|
test_url(
|
||||||
|
"resources/public_domains.txt",
|
||||||
|
"https://resources/public_domains.txt",
|
||||||
|
"file:///fake/cwd/resources/public_domains.txt",
|
||||||
|
"https://resources/public_domains.txt",
|
||||||
|
);
|
||||||
|
test_url(
|
||||||
|
"dragonfruit",
|
||||||
|
"https://duckduckgo.com/html/?q=dragonfruit",
|
||||||
|
"file:///fake/cwd/dragonfruit",
|
||||||
|
"https://duckduckgo.com/html/?q=dragonfruit",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[cfg(target_os = "windows")]
|
||||||
|
fn test_cmdline_and_location_bar_url() {
|
||||||
|
test_url(
|
||||||
|
"data:text/html,a",
|
||||||
|
"data:text/html,a",
|
||||||
|
"data:text/html,a",
|
||||||
|
"data:text/html,a",
|
||||||
|
);
|
||||||
|
test_url(
|
||||||
|
"README.md",
|
||||||
|
"https://readme.md/",
|
||||||
|
"file:///C:/fake/cwd/README.md",
|
||||||
|
"https://readme.md/",
|
||||||
|
);
|
||||||
|
test_url(
|
||||||
|
"nic.md",
|
||||||
|
"https://nic.md/",
|
||||||
|
"file:///C:/fake/cwd/nic.md",
|
||||||
|
"https://nic.md/",
|
||||||
|
);
|
||||||
|
test_url(
|
||||||
|
"nic.md/ro",
|
||||||
|
"https://nic.md/ro",
|
||||||
|
"file:///C:/fake/cwd/nic.md/ro",
|
||||||
|
"https://nic.md/ro",
|
||||||
|
);
|
||||||
|
test_url(
|
||||||
|
"foo.txt",
|
||||||
|
"https://foo.txt/",
|
||||||
|
"file:///C:/fake/cwd/foo.txt",
|
||||||
|
"https://foo.txt/",
|
||||||
|
);
|
||||||
|
test_url(
|
||||||
|
"foo.txt/ro",
|
||||||
|
"https://foo.txt/ro",
|
||||||
|
"file:///C:/fake/cwd/foo.txt/ro",
|
||||||
|
"https://foo.txt/ro",
|
||||||
|
);
|
||||||
|
test_url(
|
||||||
|
"resources/public_domains.txt",
|
||||||
|
"https://resources/public_domains.txt",
|
||||||
|
"file:///C:/fake/cwd/resources/public_domains.txt",
|
||||||
|
"https://resources/public_domains.txt",
|
||||||
|
);
|
||||||
|
test_url(
|
||||||
|
"dragonfruit",
|
||||||
|
"https://duckduckgo.com/html/?q=dragonfruit",
|
||||||
|
"file:///C:/fake/cwd/dragonfruit",
|
||||||
|
"https://duckduckgo.com/html/?q=dragonfruit",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(target_os = "linux")]
|
||||||
|
#[test]
|
||||||
|
fn test_cmd_and_location_bar_url() {
|
||||||
|
test_url(
|
||||||
|
"/dev/null",
|
||||||
|
"file:///dev/null",
|
||||||
|
"file:///dev/null",
|
||||||
|
"file:///dev/null",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue