ruffle/web/src/navigator.rs

445 lines
16 KiB
Rust
Raw Normal View History

//! Navigator backend for web
use crate::SocketProxy;
2023-07-29 11:39:33 +00:00
use async_channel::Receiver;
use futures_util::{SinkExt, StreamExt};
use gloo_net::websocket::{futures::WebSocket, Message};
use js_sys::{Array, ArrayBuffer, Uint8Array};
use ruffle_core::backend::navigator::{
core: Refactor & improve NavigatorBackend implementations All NavigatorBackend implementations have been refactored, resulting in improved code quality, less duplicated code, more consistent and easier to understand procedures, additional error handling and better error messages. A resolve_url method has been added to the NavigatorBackend trait. It takes a URL and and resolves it to the actual URL from which a file can be fetched (including handling of relative links and pre-processing). It has been implemented in each NavigatorBackend implementation. Duplicated code has been put into new public functions in core/src/backend/navigator.rs which are called by all NavigatorBackend implementations. ExternalNavigatorBackend: - The navigate_to_url and fetch methods have been adapted to use resolve_url, removing redundant code. - Error handling has been added in case that the URL can't be converted to a PathBuf. - A TODO about differences between the flash player fetch and the Ruffle fetch implementation has been added. WebNavigatorBackend: - The previous resolve_url method exclusively to the WebNavigatorBackend has been replaced by the new resolve_url method. It is used by navigate_to_url and fetch. - resolve_url now always pre-processes the URL if it's valid (even if no base_url exists) and explicitly returns whether the URL can be parsed. - navigate_to_url now traces an explanatory error each if the URL can't be parsed or is local. - fetch now returns an explanatory error each if the URL can't be parsed or is local (previously, a vague "Got JS error" has been returned). TestNavigatorBackend & NullNavigatorBackend: - fetch pre-processes the URL now (using the resolve_url implementation). - If the URL isn't local, an explanatory error is returned (previously, it was just an "Invalid URL" error). - If the URL can't be parsed, an explanatory error with the reason is returned (previously, it was just an "Invalid URL" error). Additionally, error messages in all NavigatorBackend implementations have been improved and made more consistent, e.g. if a local file can't be read.
2023-05-22 15:01:50 +00:00
async_return, create_fetch_error, create_specific_fetch_error, ErrorResponse, NavigationMethod,
NavigatorBackend, OpenURLMode, OwnedFuture, Request, SuccessResponse,
};
use ruffle_core::config::NetworkingAccessMode;
use ruffle_core::indexmap::IndexMap;
use ruffle_core::loader::Error;
use ruffle_core::socket::{ConnectionState, SocketAction, SocketHandle};
2023-07-29 11:39:33 +00:00
use std::sync::mpsc::Sender;
2023-07-15 15:20:21 +00:00
use std::sync::Arc;
2023-07-17 15:18:01 +00:00
use std::time::Duration;
use tracing_subscriber::layer::Layered;
use tracing_subscriber::Registry;
use tracing_wasm::WASMLayer;
core: Refactor & improve NavigatorBackend implementations All NavigatorBackend implementations have been refactored, resulting in improved code quality, less duplicated code, more consistent and easier to understand procedures, additional error handling and better error messages. A resolve_url method has been added to the NavigatorBackend trait. It takes a URL and and resolves it to the actual URL from which a file can be fetched (including handling of relative links and pre-processing). It has been implemented in each NavigatorBackend implementation. Duplicated code has been put into new public functions in core/src/backend/navigator.rs which are called by all NavigatorBackend implementations. ExternalNavigatorBackend: - The navigate_to_url and fetch methods have been adapted to use resolve_url, removing redundant code. - Error handling has been added in case that the URL can't be converted to a PathBuf. - A TODO about differences between the flash player fetch and the Ruffle fetch implementation has been added. WebNavigatorBackend: - The previous resolve_url method exclusively to the WebNavigatorBackend has been replaced by the new resolve_url method. It is used by navigate_to_url and fetch. - resolve_url now always pre-processes the URL if it's valid (even if no base_url exists) and explicitly returns whether the URL can be parsed. - navigate_to_url now traces an explanatory error each if the URL can't be parsed or is local. - fetch now returns an explanatory error each if the URL can't be parsed or is local (previously, a vague "Got JS error" has been returned). TestNavigatorBackend & NullNavigatorBackend: - fetch pre-processes the URL now (using the resolve_url implementation). - If the URL isn't local, an explanatory error is returned (previously, it was just an "Invalid URL" error). - If the URL can't be parsed, an explanatory error with the reason is returned (previously, it was just an "Invalid URL" error). Additionally, error messages in all NavigatorBackend implementations have been improved and made more consistent, e.g. if a local file can't be read.
2023-05-22 15:01:50 +00:00
use url::{ParseError, Url};
2019-09-04 02:15:03 +00:00
use wasm_bindgen::JsCast;
2019-11-09 02:10:21 +00:00
use wasm_bindgen_futures::{spawn_local, JsFuture};
use web_sys::{
window, Blob, BlobPropertyBag, HtmlFormElement, HtmlInputElement, Request as WebRequest,
RequestInit, Response as WebResponse,
};
pub struct WebNavigatorBackend {
log_subscriber: Arc<Layered<WASMLayer, Registry>>,
allow_script_access: bool,
allow_networking: NetworkingAccessMode,
upgrade_to_https: bool,
base_url: Option<Url>,
open_url_mode: OpenURLMode,
socket_proxies: Vec<SocketProxy>,
}
impl WebNavigatorBackend {
pub fn new(
allow_script_access: bool,
allow_networking: NetworkingAccessMode,
upgrade_to_https: bool,
base_url: Option<String>,
log_subscriber: Arc<Layered<WASMLayer, Registry>>,
open_url_mode: OpenURLMode,
socket_proxies: Vec<SocketProxy>,
) -> Self {
let window = web_sys::window().expect("window()");
// Upgrade to HTTPS takes effect if the current page is hosted on HTTPS.
let upgrade_to_https =
upgrade_to_https && window.location().protocol().expect("protocol()") == "https:";
// Retrieve and parse `document.baseURI`.
let document_base_uri = || {
let document = window.document().expect("document()");
if let Ok(Some(base_uri)) = document.base_uri() {
return Url::parse(&base_uri).ok();
}
None
};
let base_url = if let Some(mut base_url) = base_url {
// Adding trailing slash so `Url::parse` will not drop the last part.
if !base_url.ends_with('/') {
base_url.push('/');
2021-09-07 04:44:24 +00:00
}
Url::parse(&base_url)
.ok()
.or_else(|| document_base_uri().and_then(|base_uri| base_uri.join(&base_url).ok()))
} else {
document_base_uri()
};
if base_url.is_none() {
2023-01-04 11:33:10 +00:00
tracing::error!("Could not get base URL for base directory inference.");
2021-09-07 04:44:24 +00:00
}
Self {
allow_script_access,
allow_networking,
upgrade_to_https,
base_url,
log_subscriber,
open_url_mode,
socket_proxies,
}
}
}
impl NavigatorBackend for WebNavigatorBackend {
2019-09-17 03:37:11 +00:00
fn navigate_to_url(
&self,
url: &str,
target: &str,
vars_method: Option<(NavigationMethod, IndexMap<String, String>)>,
2019-09-17 03:37:11 +00:00
) {
// If the URL is empty, ignore the request.
2021-03-21 06:02:57 +00:00
if url.is_empty() {
return;
}
core: Refactor & improve NavigatorBackend implementations All NavigatorBackend implementations have been refactored, resulting in improved code quality, less duplicated code, more consistent and easier to understand procedures, additional error handling and better error messages. A resolve_url method has been added to the NavigatorBackend trait. It takes a URL and and resolves it to the actual URL from which a file can be fetched (including handling of relative links and pre-processing). It has been implemented in each NavigatorBackend implementation. Duplicated code has been put into new public functions in core/src/backend/navigator.rs which are called by all NavigatorBackend implementations. ExternalNavigatorBackend: - The navigate_to_url and fetch methods have been adapted to use resolve_url, removing redundant code. - Error handling has been added in case that the URL can't be converted to a PathBuf. - A TODO about differences between the flash player fetch and the Ruffle fetch implementation has been added. WebNavigatorBackend: - The previous resolve_url method exclusively to the WebNavigatorBackend has been replaced by the new resolve_url method. It is used by navigate_to_url and fetch. - resolve_url now always pre-processes the URL if it's valid (even if no base_url exists) and explicitly returns whether the URL can be parsed. - navigate_to_url now traces an explanatory error each if the URL can't be parsed or is local. - fetch now returns an explanatory error each if the URL can't be parsed or is local (previously, a vague "Got JS error" has been returned). TestNavigatorBackend & NullNavigatorBackend: - fetch pre-processes the URL now (using the resolve_url implementation). - If the URL isn't local, an explanatory error is returned (previously, it was just an "Invalid URL" error). - If the URL can't be parsed, an explanatory error with the reason is returned (previously, it was just an "Invalid URL" error). Additionally, error messages in all NavigatorBackend implementations have been improved and made more consistent, e.g. if a local file can't be read.
2023-05-22 15:01:50 +00:00
let url = match self.resolve_url(url) {
Ok(url) => {
if url.scheme() == "file" {
tracing::error!(
"Can't open the local URL {} on WASM target",
url.to_string()
);
return;
} else {
url
}
}
Err(e) => {
tracing::error!(
"Could not parse URL because of {}, the corrupt URL was: {}",
e,
url
);
return;
}
};
// If `allowNetworking` is set to `internal` or `none`, block all `navigate_to_url` calls.
if self.allow_networking != NetworkingAccessMode::All {
tracing::warn!("SWF tried to open a URL, but opening URLs is not allowed");
return;
}
// If `allowScriptAccess` is disabled, reject the `javascript:` scheme.
// Also reject any attempt to open a URL when `target` is a keyword that affects the current tab.
core: Refactor & improve NavigatorBackend implementations All NavigatorBackend implementations have been refactored, resulting in improved code quality, less duplicated code, more consistent and easier to understand procedures, additional error handling and better error messages. A resolve_url method has been added to the NavigatorBackend trait. It takes a URL and and resolves it to the actual URL from which a file can be fetched (including handling of relative links and pre-processing). It has been implemented in each NavigatorBackend implementation. Duplicated code has been put into new public functions in core/src/backend/navigator.rs which are called by all NavigatorBackend implementations. ExternalNavigatorBackend: - The navigate_to_url and fetch methods have been adapted to use resolve_url, removing redundant code. - Error handling has been added in case that the URL can't be converted to a PathBuf. - A TODO about differences between the flash player fetch and the Ruffle fetch implementation has been added. WebNavigatorBackend: - The previous resolve_url method exclusively to the WebNavigatorBackend has been replaced by the new resolve_url method. It is used by navigate_to_url and fetch. - resolve_url now always pre-processes the URL if it's valid (even if no base_url exists) and explicitly returns whether the URL can be parsed. - navigate_to_url now traces an explanatory error each if the URL can't be parsed or is local. - fetch now returns an explanatory error each if the URL can't be parsed or is local (previously, a vague "Got JS error" has been returned). TestNavigatorBackend & NullNavigatorBackend: - fetch pre-processes the URL now (using the resolve_url implementation). - If the URL isn't local, an explanatory error is returned (previously, it was just an "Invalid URL" error). - If the URL can't be parsed, an explanatory error with the reason is returned (previously, it was just an "Invalid URL" error). Additionally, error messages in all NavigatorBackend implementations have been improved and made more consistent, e.g. if a local file can't be read.
2023-05-22 15:01:50 +00:00
if !self.allow_script_access {
if url.scheme() == "javascript" {
tracing::warn!("SWF tried to run a script, but script access is not allowed");
return;
} else {
match target.to_lowercase().as_str() {
"_parent" | "_self" | "_top" | "" => {
tracing::warn!("SWF tried to open a URL, but opening URLs in the current tab is prevented by script access");
return;
}
core: Refactor & improve NavigatorBackend implementations All NavigatorBackend implementations have been refactored, resulting in improved code quality, less duplicated code, more consistent and easier to understand procedures, additional error handling and better error messages. A resolve_url method has been added to the NavigatorBackend trait. It takes a URL and and resolves it to the actual URL from which a file can be fetched (including handling of relative links and pre-processing). It has been implemented in each NavigatorBackend implementation. Duplicated code has been put into new public functions in core/src/backend/navigator.rs which are called by all NavigatorBackend implementations. ExternalNavigatorBackend: - The navigate_to_url and fetch methods have been adapted to use resolve_url, removing redundant code. - Error handling has been added in case that the URL can't be converted to a PathBuf. - A TODO about differences between the flash player fetch and the Ruffle fetch implementation has been added. WebNavigatorBackend: - The previous resolve_url method exclusively to the WebNavigatorBackend has been replaced by the new resolve_url method. It is used by navigate_to_url and fetch. - resolve_url now always pre-processes the URL if it's valid (even if no base_url exists) and explicitly returns whether the URL can be parsed. - navigate_to_url now traces an explanatory error each if the URL can't be parsed or is local. - fetch now returns an explanatory error each if the URL can't be parsed or is local (previously, a vague "Got JS error" has been returned). TestNavigatorBackend & NullNavigatorBackend: - fetch pre-processes the URL now (using the resolve_url implementation). - If the URL isn't local, an explanatory error is returned (previously, it was just an "Invalid URL" error). - If the URL can't be parsed, an explanatory error with the reason is returned (previously, it was just an "Invalid URL" error). Additionally, error messages in all NavigatorBackend implementations have been improved and made more consistent, e.g. if a local file can't be read.
2023-05-22 15:01:50 +00:00
_ => (),
}
2021-03-21 06:02:57 +00:00
}
core: Refactor & improve NavigatorBackend implementations All NavigatorBackend implementations have been refactored, resulting in improved code quality, less duplicated code, more consistent and easier to understand procedures, additional error handling and better error messages. A resolve_url method has been added to the NavigatorBackend trait. It takes a URL and and resolves it to the actual URL from which a file can be fetched (including handling of relative links and pre-processing). It has been implemented in each NavigatorBackend implementation. Duplicated code has been put into new public functions in core/src/backend/navigator.rs which are called by all NavigatorBackend implementations. ExternalNavigatorBackend: - The navigate_to_url and fetch methods have been adapted to use resolve_url, removing redundant code. - Error handling has been added in case that the URL can't be converted to a PathBuf. - A TODO about differences between the flash player fetch and the Ruffle fetch implementation has been added. WebNavigatorBackend: - The previous resolve_url method exclusively to the WebNavigatorBackend has been replaced by the new resolve_url method. It is used by navigate_to_url and fetch. - resolve_url now always pre-processes the URL if it's valid (even if no base_url exists) and explicitly returns whether the URL can be parsed. - navigate_to_url now traces an explanatory error each if the URL can't be parsed or is local. - fetch now returns an explanatory error each if the URL can't be parsed or is local (previously, a vague "Got JS error" has been returned). TestNavigatorBackend & NullNavigatorBackend: - fetch pre-processes the URL now (using the resolve_url implementation). - If the URL isn't local, an explanatory error is returned (previously, it was just an "Invalid URL" error). - If the URL can't be parsed, an explanatory error with the reason is returned (previously, it was just an "Invalid URL" error). Additionally, error messages in all NavigatorBackend implementations have been improved and made more consistent, e.g. if a local file can't be read.
2023-05-22 15:01:50 +00:00
}
core: Add navigate_to_url call configuration options New configuration options (changing the navigate_to_url call handling) have been added. The default behaviour has been changed as well. A NavigateWebsiteHandlingMode enum has been added to Ruffle (in Rust and Typescript). It contains the values "Allow", "Confirm" and "Deny" and describes how navigate_to_url website calls should be handled. Allow means that all website calls are allowed, Confirm means that a confirmation window opens with each website call and Deny means that all website calls are denied. A respective navigate_website_handling_mode variable has been added to the desktop CLI and to the JS config. The default value is "Confirm" in each. The variable is given to the navigator (ExternalNavigatorBackend or WebNavigatorBackend, depending on the platform) and is saved in it. On each navigate_to_url website call, the respective navigator is now checking navigate_website_handling_mode and acts correspondingly (allows it, opens a confirmation window or denies it). This changes the default behaviour of Ruffle from allowing all website calls to opening a confirmation window with each website call. On Safari, the confirm window can cause the background music to stop, but this seems to be an issue with Safari. Closes #838. Additionally, an allow_javascript_calls variable (which defaults to false) has been added to the desktop CLI. The variable is given to the desktop navigator and is saved in it. If a navigate_to_url javascript call is executed on desktop, the navigator is now checking allow_javascript_calls and acts correspondingly (allows it or denies it). This changes the default behaviour of Ruffle on desktop to not allowing javascript calls. Closes #9316.
2023-04-09 16:27:20 +00:00
let window = window().expect("window()");
core: Refactor & improve NavigatorBackend implementations All NavigatorBackend implementations have been refactored, resulting in improved code quality, less duplicated code, more consistent and easier to understand procedures, additional error handling and better error messages. A resolve_url method has been added to the NavigatorBackend trait. It takes a URL and and resolves it to the actual URL from which a file can be fetched (including handling of relative links and pre-processing). It has been implemented in each NavigatorBackend implementation. Duplicated code has been put into new public functions in core/src/backend/navigator.rs which are called by all NavigatorBackend implementations. ExternalNavigatorBackend: - The navigate_to_url and fetch methods have been adapted to use resolve_url, removing redundant code. - Error handling has been added in case that the URL can't be converted to a PathBuf. - A TODO about differences between the flash player fetch and the Ruffle fetch implementation has been added. WebNavigatorBackend: - The previous resolve_url method exclusively to the WebNavigatorBackend has been replaced by the new resolve_url method. It is used by navigate_to_url and fetch. - resolve_url now always pre-processes the URL if it's valid (even if no base_url exists) and explicitly returns whether the URL can be parsed. - navigate_to_url now traces an explanatory error each if the URL can't be parsed or is local. - fetch now returns an explanatory error each if the URL can't be parsed or is local (previously, a vague "Got JS error" has been returned). TestNavigatorBackend & NullNavigatorBackend: - fetch pre-processes the URL now (using the resolve_url implementation). - If the URL isn't local, an explanatory error is returned (previously, it was just an "Invalid URL" error). - If the URL can't be parsed, an explanatory error with the reason is returned (previously, it was just an "Invalid URL" error). Additionally, error messages in all NavigatorBackend implementations have been improved and made more consistent, e.g. if a local file can't be read.
2023-05-22 15:01:50 +00:00
if url.scheme() != "javascript" {
if self.open_url_mode == OpenURLMode::Confirm {
let message = format!("The SWF file wants to open the website {}", &url);
// TODO: Add a checkbox with a GUI toolkit
core: Add navigate_to_url call configuration options New configuration options (changing the navigate_to_url call handling) have been added. The default behaviour has been changed as well. A NavigateWebsiteHandlingMode enum has been added to Ruffle (in Rust and Typescript). It contains the values "Allow", "Confirm" and "Deny" and describes how navigate_to_url website calls should be handled. Allow means that all website calls are allowed, Confirm means that a confirmation window opens with each website call and Deny means that all website calls are denied. A respective navigate_website_handling_mode variable has been added to the desktop CLI and to the JS config. The default value is "Confirm" in each. The variable is given to the navigator (ExternalNavigatorBackend or WebNavigatorBackend, depending on the platform) and is saved in it. On each navigate_to_url website call, the respective navigator is now checking navigate_website_handling_mode and acts correspondingly (allows it, opens a confirmation window or denies it). This changes the default behaviour of Ruffle from allowing all website calls to opening a confirmation window with each website call. On Safari, the confirm window can cause the background music to stop, but this seems to be an issue with Safari. Closes #838. Additionally, an allow_javascript_calls variable (which defaults to false) has been added to the desktop CLI. The variable is given to the desktop navigator and is saved in it. If a navigate_to_url javascript call is executed on desktop, the navigator is now checking allow_javascript_calls and acts correspondingly (allows it or denies it). This changes the default behaviour of Ruffle on desktop to not allowing javascript calls. Closes #9316.
2023-04-09 16:27:20 +00:00
let confirm = window
.confirm_with_message(&message)
.expect("confirm_with_message()");
if !confirm {
tracing::info!(
"SWF tried to open a website, but the user declined the request"
);
return;
}
} else if self.open_url_mode == OpenURLMode::Deny {
core: Add navigate_to_url call configuration options New configuration options (changing the navigate_to_url call handling) have been added. The default behaviour has been changed as well. A NavigateWebsiteHandlingMode enum has been added to Ruffle (in Rust and Typescript). It contains the values "Allow", "Confirm" and "Deny" and describes how navigate_to_url website calls should be handled. Allow means that all website calls are allowed, Confirm means that a confirmation window opens with each website call and Deny means that all website calls are denied. A respective navigate_website_handling_mode variable has been added to the desktop CLI and to the JS config. The default value is "Confirm" in each. The variable is given to the navigator (ExternalNavigatorBackend or WebNavigatorBackend, depending on the platform) and is saved in it. On each navigate_to_url website call, the respective navigator is now checking navigate_website_handling_mode and acts correspondingly (allows it, opens a confirmation window or denies it). This changes the default behaviour of Ruffle from allowing all website calls to opening a confirmation window with each website call. On Safari, the confirm window can cause the background music to stop, but this seems to be an issue with Safari. Closes #838. Additionally, an allow_javascript_calls variable (which defaults to false) has been added to the desktop CLI. The variable is given to the desktop navigator and is saved in it. If a navigate_to_url javascript call is executed on desktop, the navigator is now checking allow_javascript_calls and acts correspondingly (allows it or denies it). This changes the default behaviour of Ruffle on desktop to not allowing javascript calls. Closes #9316.
2023-04-09 16:27:20 +00:00
tracing::warn!("SWF tried to open a website, but opening a website is not allowed");
return;
}
// If the user confirmed or if in `Allow` mode, open the website.
}
// TODO: Should we return a result for failed opens? Does Flash care?
match vars_method {
Some((navmethod, formvars)) => {
let document = window.document().expect("document()");
let body = match document.body() {
Some(body) => body,
None => return,
};
let form: HtmlFormElement = document
.create_element("form")
.expect("create_element() must succeed")
.dyn_into()
.expect("create_element(\"form\") didn't give us a form");
form.set_method(&navmethod.to_string());
core: Refactor & improve NavigatorBackend implementations All NavigatorBackend implementations have been refactored, resulting in improved code quality, less duplicated code, more consistent and easier to understand procedures, additional error handling and better error messages. A resolve_url method has been added to the NavigatorBackend trait. It takes a URL and and resolves it to the actual URL from which a file can be fetched (including handling of relative links and pre-processing). It has been implemented in each NavigatorBackend implementation. Duplicated code has been put into new public functions in core/src/backend/navigator.rs which are called by all NavigatorBackend implementations. ExternalNavigatorBackend: - The navigate_to_url and fetch methods have been adapted to use resolve_url, removing redundant code. - Error handling has been added in case that the URL can't be converted to a PathBuf. - A TODO about differences between the flash player fetch and the Ruffle fetch implementation has been added. WebNavigatorBackend: - The previous resolve_url method exclusively to the WebNavigatorBackend has been replaced by the new resolve_url method. It is used by navigate_to_url and fetch. - resolve_url now always pre-processes the URL if it's valid (even if no base_url exists) and explicitly returns whether the URL can be parsed. - navigate_to_url now traces an explanatory error each if the URL can't be parsed or is local. - fetch now returns an explanatory error each if the URL can't be parsed or is local (previously, a vague "Got JS error" has been returned). TestNavigatorBackend & NullNavigatorBackend: - fetch pre-processes the URL now (using the resolve_url implementation). - If the URL isn't local, an explanatory error is returned (previously, it was just an "Invalid URL" error). - If the URL can't be parsed, an explanatory error with the reason is returned (previously, it was just an "Invalid URL" error). Additionally, error messages in all NavigatorBackend implementations have been improved and made more consistent, e.g. if a local file can't be read.
2023-05-22 15:01:50 +00:00
form.set_action(url.as_str());
if !target.is_empty() {
form.set_target(target);
}
2021-01-10 14:04:31 +00:00
for (key, value) in formvars {
let hidden: HtmlInputElement = document
.create_element("input")
.expect("create_element() must succeed")
.dyn_into()
.expect("create_element(\"input\") didn't give us an input");
2021-01-10 14:04:31 +00:00
hidden.set_type("hidden");
hidden.set_name(&key);
hidden.set_value(&value);
let _ = form.append_child(&hidden);
}
let _ = body.append_child(&form);
let _ = form.submit();
}
None => {
if target.is_empty() {
core: Refactor & improve NavigatorBackend implementations All NavigatorBackend implementations have been refactored, resulting in improved code quality, less duplicated code, more consistent and easier to understand procedures, additional error handling and better error messages. A resolve_url method has been added to the NavigatorBackend trait. It takes a URL and and resolves it to the actual URL from which a file can be fetched (including handling of relative links and pre-processing). It has been implemented in each NavigatorBackend implementation. Duplicated code has been put into new public functions in core/src/backend/navigator.rs which are called by all NavigatorBackend implementations. ExternalNavigatorBackend: - The navigate_to_url and fetch methods have been adapted to use resolve_url, removing redundant code. - Error handling has been added in case that the URL can't be converted to a PathBuf. - A TODO about differences between the flash player fetch and the Ruffle fetch implementation has been added. WebNavigatorBackend: - The previous resolve_url method exclusively to the WebNavigatorBackend has been replaced by the new resolve_url method. It is used by navigate_to_url and fetch. - resolve_url now always pre-processes the URL if it's valid (even if no base_url exists) and explicitly returns whether the URL can be parsed. - navigate_to_url now traces an explanatory error each if the URL can't be parsed or is local. - fetch now returns an explanatory error each if the URL can't be parsed or is local (previously, a vague "Got JS error" has been returned). TestNavigatorBackend & NullNavigatorBackend: - fetch pre-processes the URL now (using the resolve_url implementation). - If the URL isn't local, an explanatory error is returned (previously, it was just an "Invalid URL" error). - If the URL can't be parsed, an explanatory error with the reason is returned (previously, it was just an "Invalid URL" error). Additionally, error messages in all NavigatorBackend implementations have been improved and made more consistent, e.g. if a local file can't be read.
2023-05-22 15:01:50 +00:00
let _ = window.location().assign(url.as_str());
} else {
core: Refactor & improve NavigatorBackend implementations All NavigatorBackend implementations have been refactored, resulting in improved code quality, less duplicated code, more consistent and easier to understand procedures, additional error handling and better error messages. A resolve_url method has been added to the NavigatorBackend trait. It takes a URL and and resolves it to the actual URL from which a file can be fetched (including handling of relative links and pre-processing). It has been implemented in each NavigatorBackend implementation. Duplicated code has been put into new public functions in core/src/backend/navigator.rs which are called by all NavigatorBackend implementations. ExternalNavigatorBackend: - The navigate_to_url and fetch methods have been adapted to use resolve_url, removing redundant code. - Error handling has been added in case that the URL can't be converted to a PathBuf. - A TODO about differences between the flash player fetch and the Ruffle fetch implementation has been added. WebNavigatorBackend: - The previous resolve_url method exclusively to the WebNavigatorBackend has been replaced by the new resolve_url method. It is used by navigate_to_url and fetch. - resolve_url now always pre-processes the URL if it's valid (even if no base_url exists) and explicitly returns whether the URL can be parsed. - navigate_to_url now traces an explanatory error each if the URL can't be parsed or is local. - fetch now returns an explanatory error each if the URL can't be parsed or is local (previously, a vague "Got JS error" has been returned). TestNavigatorBackend & NullNavigatorBackend: - fetch pre-processes the URL now (using the resolve_url implementation). - If the URL isn't local, an explanatory error is returned (previously, it was just an "Invalid URL" error). - If the URL can't be parsed, an explanatory error with the reason is returned (previously, it was just an "Invalid URL" error). Additionally, error messages in all NavigatorBackend implementations have been improved and made more consistent, e.g. if a local file can't be read.
2023-05-22 15:01:50 +00:00
let _ = window.open_with_url_and_target(url.as_str(), target);
}
}
};
2021-01-10 14:04:31 +00:00
}
fn fetch(&self, request: Request) -> OwnedFuture<SuccessResponse, ErrorResponse> {
core: Refactor & improve NavigatorBackend implementations All NavigatorBackend implementations have been refactored, resulting in improved code quality, less duplicated code, more consistent and easier to understand procedures, additional error handling and better error messages. A resolve_url method has been added to the NavigatorBackend trait. It takes a URL and and resolves it to the actual URL from which a file can be fetched (including handling of relative links and pre-processing). It has been implemented in each NavigatorBackend implementation. Duplicated code has been put into new public functions in core/src/backend/navigator.rs which are called by all NavigatorBackend implementations. ExternalNavigatorBackend: - The navigate_to_url and fetch methods have been adapted to use resolve_url, removing redundant code. - Error handling has been added in case that the URL can't be converted to a PathBuf. - A TODO about differences between the flash player fetch and the Ruffle fetch implementation has been added. WebNavigatorBackend: - The previous resolve_url method exclusively to the WebNavigatorBackend has been replaced by the new resolve_url method. It is used by navigate_to_url and fetch. - resolve_url now always pre-processes the URL if it's valid (even if no base_url exists) and explicitly returns whether the URL can be parsed. - navigate_to_url now traces an explanatory error each if the URL can't be parsed or is local. - fetch now returns an explanatory error each if the URL can't be parsed or is local (previously, a vague "Got JS error" has been returned). TestNavigatorBackend & NullNavigatorBackend: - fetch pre-processes the URL now (using the resolve_url implementation). - If the URL isn't local, an explanatory error is returned (previously, it was just an "Invalid URL" error). - If the URL can't be parsed, an explanatory error with the reason is returned (previously, it was just an "Invalid URL" error). Additionally, error messages in all NavigatorBackend implementations have been improved and made more consistent, e.g. if a local file can't be read.
2023-05-22 15:01:50 +00:00
let url = match self.resolve_url(request.url()) {
Ok(url) => {
if url.scheme() == "file" {
return async_return(create_specific_fetch_error(
"WASM target can't fetch local URL",
url.as_str(),
"",
));
} else {
url
}
}
Err(e) => {
return async_return(create_fetch_error(request.url(), e));
}
};
2019-11-09 02:10:21 +00:00
Box::pin(async move {
let mut init = RequestInit::new();
2023-04-22 14:08:10 +00:00
init.method(&request.method().to_string());
if let Some((data, mime)) = request.body() {
let blob = Blob::new_with_buffer_source_sequence_and_options(
&Array::from_iter([Uint8Array::from(data.as_slice()).buffer()]),
BlobPropertyBag::new().type_(mime),
)
.map_err(|_| ErrorResponse {
core: Refactor & improve NavigatorBackend implementations All NavigatorBackend implementations have been refactored, resulting in improved code quality, less duplicated code, more consistent and easier to understand procedures, additional error handling and better error messages. A resolve_url method has been added to the NavigatorBackend trait. It takes a URL and and resolves it to the actual URL from which a file can be fetched (including handling of relative links and pre-processing). It has been implemented in each NavigatorBackend implementation. Duplicated code has been put into new public functions in core/src/backend/navigator.rs which are called by all NavigatorBackend implementations. ExternalNavigatorBackend: - The navigate_to_url and fetch methods have been adapted to use resolve_url, removing redundant code. - Error handling has been added in case that the URL can't be converted to a PathBuf. - A TODO about differences between the flash player fetch and the Ruffle fetch implementation has been added. WebNavigatorBackend: - The previous resolve_url method exclusively to the WebNavigatorBackend has been replaced by the new resolve_url method. It is used by navigate_to_url and fetch. - resolve_url now always pre-processes the URL if it's valid (even if no base_url exists) and explicitly returns whether the URL can be parsed. - navigate_to_url now traces an explanatory error each if the URL can't be parsed or is local. - fetch now returns an explanatory error each if the URL can't be parsed or is local (previously, a vague "Got JS error" has been returned). TestNavigatorBackend & NullNavigatorBackend: - fetch pre-processes the URL now (using the resolve_url implementation). - If the URL isn't local, an explanatory error is returned (previously, it was just an "Invalid URL" error). - If the URL can't be parsed, an explanatory error with the reason is returned (previously, it was just an "Invalid URL" error). Additionally, error messages in all NavigatorBackend implementations have been improved and made more consistent, e.g. if a local file can't be read.
2023-05-22 15:01:50 +00:00
url: url.to_string(),
error: Error::FetchError("Got JS error".to_string()),
})?
.dyn_into()
.map_err(|_| ErrorResponse {
core: Refactor & improve NavigatorBackend implementations All NavigatorBackend implementations have been refactored, resulting in improved code quality, less duplicated code, more consistent and easier to understand procedures, additional error handling and better error messages. A resolve_url method has been added to the NavigatorBackend trait. It takes a URL and and resolves it to the actual URL from which a file can be fetched (including handling of relative links and pre-processing). It has been implemented in each NavigatorBackend implementation. Duplicated code has been put into new public functions in core/src/backend/navigator.rs which are called by all NavigatorBackend implementations. ExternalNavigatorBackend: - The navigate_to_url and fetch methods have been adapted to use resolve_url, removing redundant code. - Error handling has been added in case that the URL can't be converted to a PathBuf. - A TODO about differences between the flash player fetch and the Ruffle fetch implementation has been added. WebNavigatorBackend: - The previous resolve_url method exclusively to the WebNavigatorBackend has been replaced by the new resolve_url method. It is used by navigate_to_url and fetch. - resolve_url now always pre-processes the URL if it's valid (even if no base_url exists) and explicitly returns whether the URL can be parsed. - navigate_to_url now traces an explanatory error each if the URL can't be parsed or is local. - fetch now returns an explanatory error each if the URL can't be parsed or is local (previously, a vague "Got JS error" has been returned). TestNavigatorBackend & NullNavigatorBackend: - fetch pre-processes the URL now (using the resolve_url implementation). - If the URL isn't local, an explanatory error is returned (previously, it was just an "Invalid URL" error). - If the URL can't be parsed, an explanatory error with the reason is returned (previously, it was just an "Invalid URL" error). Additionally, error messages in all NavigatorBackend implementations have been improved and made more consistent, e.g. if a local file can't be read.
2023-05-22 15:01:50 +00:00
url: url.to_string(),
error: Error::FetchError("Got JS error".to_string()),
})?;
init.body(Some(&blob));
}
core: Refactor & improve NavigatorBackend implementations All NavigatorBackend implementations have been refactored, resulting in improved code quality, less duplicated code, more consistent and easier to understand procedures, additional error handling and better error messages. A resolve_url method has been added to the NavigatorBackend trait. It takes a URL and and resolves it to the actual URL from which a file can be fetched (including handling of relative links and pre-processing). It has been implemented in each NavigatorBackend implementation. Duplicated code has been put into new public functions in core/src/backend/navigator.rs which are called by all NavigatorBackend implementations. ExternalNavigatorBackend: - The navigate_to_url and fetch methods have been adapted to use resolve_url, removing redundant code. - Error handling has been added in case that the URL can't be converted to a PathBuf. - A TODO about differences between the flash player fetch and the Ruffle fetch implementation has been added. WebNavigatorBackend: - The previous resolve_url method exclusively to the WebNavigatorBackend has been replaced by the new resolve_url method. It is used by navigate_to_url and fetch. - resolve_url now always pre-processes the URL if it's valid (even if no base_url exists) and explicitly returns whether the URL can be parsed. - navigate_to_url now traces an explanatory error each if the URL can't be parsed or is local. - fetch now returns an explanatory error each if the URL can't be parsed or is local (previously, a vague "Got JS error" has been returned). TestNavigatorBackend & NullNavigatorBackend: - fetch pre-processes the URL now (using the resolve_url implementation). - If the URL isn't local, an explanatory error is returned (previously, it was just an "Invalid URL" error). - If the URL can't be parsed, an explanatory error with the reason is returned (previously, it was just an "Invalid URL" error). Additionally, error messages in all NavigatorBackend implementations have been improved and made more consistent, e.g. if a local file can't be read.
2023-05-22 15:01:50 +00:00
let web_request = match WebRequest::new_with_str_and_init(url.as_str(), &init) {
Ok(web_request) => web_request,
Err(_) => {
return create_specific_fetch_error(
"Unable to create request for",
url.as_str(),
"",
)
}
};
let headers = web_request.headers();
for (header_name, header_val) in request.headers() {
headers
.set(header_name, header_val)
.map_err(|_| ErrorResponse {
core: Refactor & improve NavigatorBackend implementations All NavigatorBackend implementations have been refactored, resulting in improved code quality, less duplicated code, more consistent and easier to understand procedures, additional error handling and better error messages. A resolve_url method has been added to the NavigatorBackend trait. It takes a URL and and resolves it to the actual URL from which a file can be fetched (including handling of relative links and pre-processing). It has been implemented in each NavigatorBackend implementation. Duplicated code has been put into new public functions in core/src/backend/navigator.rs which are called by all NavigatorBackend implementations. ExternalNavigatorBackend: - The navigate_to_url and fetch methods have been adapted to use resolve_url, removing redundant code. - Error handling has been added in case that the URL can't be converted to a PathBuf. - A TODO about differences between the flash player fetch and the Ruffle fetch implementation has been added. WebNavigatorBackend: - The previous resolve_url method exclusively to the WebNavigatorBackend has been replaced by the new resolve_url method. It is used by navigate_to_url and fetch. - resolve_url now always pre-processes the URL if it's valid (even if no base_url exists) and explicitly returns whether the URL can be parsed. - navigate_to_url now traces an explanatory error each if the URL can't be parsed or is local. - fetch now returns an explanatory error each if the URL can't be parsed or is local (previously, a vague "Got JS error" has been returned). TestNavigatorBackend & NullNavigatorBackend: - fetch pre-processes the URL now (using the resolve_url implementation). - If the URL isn't local, an explanatory error is returned (previously, it was just an "Invalid URL" error). - If the URL can't be parsed, an explanatory error with the reason is returned (previously, it was just an "Invalid URL" error). Additionally, error messages in all NavigatorBackend implementations have been improved and made more consistent, e.g. if a local file can't be read.
2023-05-22 15:01:50 +00:00
url: url.to_string(),
error: Error::FetchError("Got JS error".to_string()),
})?;
}
let window = web_sys::window().expect("window()");
let fetchval = JsFuture::from(window.fetch_with_request(&web_request))
.await
.map_err(|_| ErrorResponse {
core: Refactor & improve NavigatorBackend implementations All NavigatorBackend implementations have been refactored, resulting in improved code quality, less duplicated code, more consistent and easier to understand procedures, additional error handling and better error messages. A resolve_url method has been added to the NavigatorBackend trait. It takes a URL and and resolves it to the actual URL from which a file can be fetched (including handling of relative links and pre-processing). It has been implemented in each NavigatorBackend implementation. Duplicated code has been put into new public functions in core/src/backend/navigator.rs which are called by all NavigatorBackend implementations. ExternalNavigatorBackend: - The navigate_to_url and fetch methods have been adapted to use resolve_url, removing redundant code. - Error handling has been added in case that the URL can't be converted to a PathBuf. - A TODO about differences between the flash player fetch and the Ruffle fetch implementation has been added. WebNavigatorBackend: - The previous resolve_url method exclusively to the WebNavigatorBackend has been replaced by the new resolve_url method. It is used by navigate_to_url and fetch. - resolve_url now always pre-processes the URL if it's valid (even if no base_url exists) and explicitly returns whether the URL can be parsed. - navigate_to_url now traces an explanatory error each if the URL can't be parsed or is local. - fetch now returns an explanatory error each if the URL can't be parsed or is local (previously, a vague "Got JS error" has been returned). TestNavigatorBackend & NullNavigatorBackend: - fetch pre-processes the URL now (using the resolve_url implementation). - If the URL isn't local, an explanatory error is returned (previously, it was just an "Invalid URL" error). - If the URL can't be parsed, an explanatory error with the reason is returned (previously, it was just an "Invalid URL" error). Additionally, error messages in all NavigatorBackend implementations have been improved and made more consistent, e.g. if a local file can't be read.
2023-05-22 15:01:50 +00:00
url: url.to_string(),
error: Error::FetchError("Got JS error".to_string()),
})?;
let response: WebResponse = fetchval.dyn_into().map_err(|_| ErrorResponse {
core: Refactor & improve NavigatorBackend implementations All NavigatorBackend implementations have been refactored, resulting in improved code quality, less duplicated code, more consistent and easier to understand procedures, additional error handling and better error messages. A resolve_url method has been added to the NavigatorBackend trait. It takes a URL and and resolves it to the actual URL from which a file can be fetched (including handling of relative links and pre-processing). It has been implemented in each NavigatorBackend implementation. Duplicated code has been put into new public functions in core/src/backend/navigator.rs which are called by all NavigatorBackend implementations. ExternalNavigatorBackend: - The navigate_to_url and fetch methods have been adapted to use resolve_url, removing redundant code. - Error handling has been added in case that the URL can't be converted to a PathBuf. - A TODO about differences between the flash player fetch and the Ruffle fetch implementation has been added. WebNavigatorBackend: - The previous resolve_url method exclusively to the WebNavigatorBackend has been replaced by the new resolve_url method. It is used by navigate_to_url and fetch. - resolve_url now always pre-processes the URL if it's valid (even if no base_url exists) and explicitly returns whether the URL can be parsed. - navigate_to_url now traces an explanatory error each if the URL can't be parsed or is local. - fetch now returns an explanatory error each if the URL can't be parsed or is local (previously, a vague "Got JS error" has been returned). TestNavigatorBackend & NullNavigatorBackend: - fetch pre-processes the URL now (using the resolve_url implementation). - If the URL isn't local, an explanatory error is returned (previously, it was just an "Invalid URL" error). - If the URL can't be parsed, an explanatory error with the reason is returned (previously, it was just an "Invalid URL" error). Additionally, error messages in all NavigatorBackend implementations have been improved and made more consistent, e.g. if a local file can't be read.
2023-05-22 15:01:50 +00:00
url: url.to_string(),
error: Error::FetchError("Fetch result wasn't a WebResponse".to_string()),
})?;
let url = response.url();
let status = response.status();
let redirected = response.redirected();
if !response.ok() {
let error = Error::HttpNotOk(
format!("HTTP status is not ok, got {}", response.status_text()),
status,
redirected,
);
return Err(ErrorResponse { url, error });
}
2021-03-27 19:43:43 +00:00
let body: ArrayBuffer = JsFuture::from(response.array_buffer().map_err(|_| {
ErrorResponse {
url: url.clone(),
error: Error::FetchError("Got JS error".to_string()),
}
})?)
.await
.map_err(|_| ErrorResponse {
url: url.clone(),
error: Error::FetchError(
"Could not allocate array buffer for response".to_string(),
),
})?
.dyn_into()
.map_err(|_| ErrorResponse {
url: url.clone(),
error: Error::FetchError("array_buffer result wasn't an ArrayBuffer".to_string()),
})?;
let body = Uint8Array::new(&body).to_vec();
Ok(SuccessResponse {
url,
body,
status,
redirected,
})
2019-11-09 02:10:21 +00:00
})
}
core: Refactor & improve NavigatorBackend implementations All NavigatorBackend implementations have been refactored, resulting in improved code quality, less duplicated code, more consistent and easier to understand procedures, additional error handling and better error messages. A resolve_url method has been added to the NavigatorBackend trait. It takes a URL and and resolves it to the actual URL from which a file can be fetched (including handling of relative links and pre-processing). It has been implemented in each NavigatorBackend implementation. Duplicated code has been put into new public functions in core/src/backend/navigator.rs which are called by all NavigatorBackend implementations. ExternalNavigatorBackend: - The navigate_to_url and fetch methods have been adapted to use resolve_url, removing redundant code. - Error handling has been added in case that the URL can't be converted to a PathBuf. - A TODO about differences between the flash player fetch and the Ruffle fetch implementation has been added. WebNavigatorBackend: - The previous resolve_url method exclusively to the WebNavigatorBackend has been replaced by the new resolve_url method. It is used by navigate_to_url and fetch. - resolve_url now always pre-processes the URL if it's valid (even if no base_url exists) and explicitly returns whether the URL can be parsed. - navigate_to_url now traces an explanatory error each if the URL can't be parsed or is local. - fetch now returns an explanatory error each if the URL can't be parsed or is local (previously, a vague "Got JS error" has been returned). TestNavigatorBackend & NullNavigatorBackend: - fetch pre-processes the URL now (using the resolve_url implementation). - If the URL isn't local, an explanatory error is returned (previously, it was just an "Invalid URL" error). - If the URL can't be parsed, an explanatory error with the reason is returned (previously, it was just an "Invalid URL" error). Additionally, error messages in all NavigatorBackend implementations have been improved and made more consistent, e.g. if a local file can't be read.
2023-05-22 15:01:50 +00:00
fn resolve_url(&self, url: &str) -> Result<Url, ParseError> {
if let Some(base_url) = &self.base_url {
match base_url.join(url) {
Ok(full_url) => Ok(self.pre_process_url(full_url)),
Err(error) => Err(error),
}
} else {
match Url::parse(url) {
Ok(parsed_url) => Ok(self.pre_process_url(parsed_url)),
Err(error) => Err(error),
}
}
}
fn spawn_future(&mut self, future: OwnedFuture<(), Error>) {
let subscriber = self.log_subscriber.clone();
spawn_local(async move {
let _subscriber = tracing::subscriber::set_default(subscriber);
if let Err(e) = future.await {
2023-01-04 11:33:10 +00:00
tracing::error!("Asynchronous error occurred: {}", e);
}
})
}
fn pre_process_url(&self, mut url: Url) -> Url {
if self.upgrade_to_https && url.scheme() == "http" && url.set_scheme("https").is_err() {
2023-01-04 11:33:10 +00:00
tracing::error!("Url::set_scheme failed on: {}", url);
}
url
}
2023-07-14 22:15:16 +00:00
2023-07-15 14:55:20 +00:00
fn connect_socket(
&mut self,
host: String,
port: u16,
// NOTE: WebSocket does not allow specifying a timeout, so this goes unused.
_timeout: Duration,
2023-07-15 14:55:20 +00:00
handle: SocketHandle,
receiver: Receiver<Vec<u8>>,
2023-07-15 14:55:20 +00:00
sender: Sender<SocketAction>,
) {
2023-09-07 21:32:24 +00:00
let Some(proxy) = self
.socket_proxies
2023-09-07 21:32:24 +00:00
.iter()
.find(|x| x.host == host && x.port == port)
else {
tracing::warn!("Missing WebSocket proxy for host {}, port {}", host, port);
sender
.send(SocketAction::Connect(handle, ConnectionState::Failed))
.expect("working channel send");
return;
};
tracing::info!("Connecting to {}", proxy.proxy_url);
let ws = match WebSocket::open(&proxy.proxy_url) {
2023-09-07 21:32:24 +00:00
Ok(x) => x,
Err(e) => {
tracing::error!("Failed to create WebSocket, reason {:?}", e);
sender
.send(SocketAction::Connect(handle, ConnectionState::Failed))
.expect("working channel send");
return;
}
};
let (mut sink, mut stream) = ws.split();
sender
.send(SocketAction::Connect(handle, ConnectionState::Connected))
.expect("working channel send");
// Spawn future to handle incoming messages.
let stream_sender = sender.clone();
self.spawn_future(Box::pin(async move {
while let Some(msg) = stream.next().await {
match msg {
Ok(Message::Bytes(buf)) => stream_sender
.send(SocketAction::Data(handle, buf))
.expect("working channel send"),
Ok(_) => tracing::warn!("Server sent unexpected text message"),
Err(_) => {
stream_sender
.send(SocketAction::Close(handle))
.expect("working channel send");
return Ok(());
}
}
}
Ok(())
}));
// Spawn future to handle outgoing messages.
self.spawn_future(Box::pin(async move {
while let Ok(msg) = receiver.recv().await {
if let Err(e) = sink.send(Message::Bytes(msg)).await {
tracing::warn!("Failed to send message to WebSocket {}", e);
sender
.send(SocketAction::Close(handle))
.expect("working channel send");
}
}
Ok(())
}));
2023-07-14 22:15:16 +00:00
}
2019-09-17 03:37:11 +00:00
}