Skip to content

Commit

Permalink
web: Fix cors issues with http (close #1486)
Browse files Browse the repository at this point in the history
  • Loading branch information
SamMorrowDrums authored and Herschel committed Dec 14, 2020
1 parent 8f34023 commit c4d7b24
Show file tree
Hide file tree
Showing 7 changed files with 86 additions and 18 deletions.
10 changes: 10 additions & 0 deletions core/src/backend/navigator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,12 @@ pub trait NavigatorBackend {
/// current document's base URL, while the most obvious base for a desktop
/// client would be the file-URL form of the current path.
fn resolve_relative_url<'a>(&mut self, url: &'a str) -> Cow<'a, str>;

/// Handle any context specific pre-processing
///
/// Changing http -> https for example. This function may alter any part of the
/// URL (generally only if configured to do so by the user).
fn pre_process_url(&self, url: Url) -> Url;
}

/// A null implementation of an event loop that only supports blocking.
Expand Down Expand Up @@ -378,4 +384,8 @@ impl NavigatorBackend for NullNavigatorBackend {
url.into()
}
}

fn pre_process_url(&self, url: Url) -> Url {
url
}
}
5 changes: 5 additions & 0 deletions desktop/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,10 @@ struct Opt {
/// (Optional) Proxy to use when loading movies via URL
#[clap(long, case_insensitive = true)]
proxy: Option<Url>,

/// (Optional) Replace all embedded http URLs with https
#[clap(long, case_insensitive = true, takes_value = false)]
upgrade_to_https: bool,
}

#[cfg(feature = "render_trace")]
Expand Down Expand Up @@ -207,6 +211,7 @@ fn run_player(opt: Opt) -> Result<(), Box<dyn std::error::Error>> {
chan,
event_loop.create_proxy(),
opt.proxy,
opt.upgrade_to_https,
)); //TODO: actually implement this backend type
let input = Box::new(input::WinitInputBackend::new(window.clone()));
let storage = Box::new(DiskStorageBackend::new(
Expand Down
40 changes: 28 additions & 12 deletions desktop/src/navigator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ pub struct ExternalNavigatorBackend {

// Client to use for network requests
client: Option<Rc<HttpClient>>,

upgrade_to_https: bool,
}

impl ExternalNavigatorBackend {
Expand All @@ -44,6 +46,7 @@ impl ExternalNavigatorBackend {
channel: Sender<OwnedFuture<(), Error>>,
event_loop: EventLoopProxy<RuffleEvent>,
proxy: Option<Url>,
upgrade_to_https: bool,
) -> Self {
let proxy = proxy.and_then(|url| url.as_str().parse().ok());
let builder = HttpClient::builder()
Expand All @@ -58,6 +61,7 @@ impl ExternalNavigatorBackend {
client,
movie_url,
start_time: Instant::now(),
upgrade_to_https,
}
}
}
Expand Down Expand Up @@ -96,36 +100,37 @@ impl NavigatorBackend for ExternalNavigatorBackend {
}
}

parsed_url.into_string()
parsed_url
}
None => url,
None => parsed_url,
};

match webbrowser::open(&modified_url) {
let processed_url = self.pre_process_url(modified_url);

match webbrowser::open(&processed_url.to_string()) {
Ok(_output) => {}
Err(e) => log::error!("Could not open URL {}: {}", modified_url, e),
Err(e) => log::error!("Could not open URL {}: {}", processed_url.as_str(), e),
};
}

fn time_since_launch(&mut self) -> Duration {
Instant::now().duration_since(self.start_time)
}

fn fetch(&self, url: &str, options: RequestOptions) -> OwnedFuture<Vec<u8>, Error> {
// TODO: honor sandbox type (local-with-filesystem, local-with-network, remote, ...)
let full_url = self.movie_url.clone().join(url).unwrap();

let processed_url = self.pre_process_url(full_url);

let client = self.client.clone();
match full_url.scheme() {

match processed_url.scheme() {
"file" => Box::pin(async move {
fs::read(full_url.to_file_path().unwrap()).map_err(Error::NetworkError)
fs::read(processed_url.to_file_path().unwrap()).map_err(Error::NetworkError)
}),
_ => Box::pin(async move {
let client = client.ok_or(Error::NetworkUnavailable)?;

let request = match options.method() {
NavigationMethod::GET => Request::get(full_url.to_string()),
NavigationMethod::POST => Request::post(full_url.to_string()),
NavigationMethod::GET => Request::get(processed_url.to_string()),
NavigationMethod::POST => Request::post(processed_url.to_string()),
};

let (body_data, _) = options.body().clone().unwrap_or_default();
Expand All @@ -143,6 +148,10 @@ impl NavigatorBackend for ExternalNavigatorBackend {
}
}

fn time_since_launch(&mut self) -> Duration {
Instant::now().duration_since(self.start_time)
}

fn spawn_future(&mut self, future: OwnedFuture<(), Error>) {
self.channel.send(future).expect("working channel send");

Expand All @@ -161,6 +170,13 @@ impl NavigatorBackend for ExternalNavigatorBackend {
url.into()
}
}

fn pre_process_url(&self, mut url: Url) -> Url {
if self.upgrade_to_https && url.scheme() == "http" && url.set_scheme("https").is_err() {
log::error!("Url::set_scheme failed on: {}", url);
}
url
}
}

fn response_to_bytes(res: Response<Body>) -> Result<Vec<u8>, std::io::Error> {
Expand Down
13 changes: 13 additions & 0 deletions web/packages/core/src/load-options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,19 @@ export interface BaseLoadOptions {
* @default UnmuteOverlay.Visible
*/
unmuteOverlay?: UnmuteOverlay;

/**
* Whether or not to auto-upgrade all embedded URLs to https.
*
* Flash content that embeds http urls will be blocked from
* accessing those urls by the browser when Ruffle is loaded
* in a https context. Set to `true` to automatically change
* `http://` to `https://` for all embedded URLs when Ruffle is
* loaded in an https context.
*
* @default true
*/
upgradeToHttps?: boolean;
}

/**
Expand Down
4 changes: 3 additions & 1 deletion web/packages/core/src/ruffle-player.ts
Original file line number Diff line number Diff line change
Expand Up @@ -314,7 +314,9 @@ export class RufflePlayer extends HTMLElement {
this.instance = new ruffleConstructor(
this.container,
this,
this.allowScriptAccess
this.allowScriptAccess,
config.upgradeToHttps !== false &&
window.location.protocol === "https:"
);
console.log("New Ruffle instance created.");

Expand Down
6 changes: 4 additions & 2 deletions web/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -115,14 +115,15 @@ impl Ruffle {
parent: HtmlElement,
js_player: JavascriptPlayer,
allow_script_access: bool,
upgrade_to_https: bool,
) -> Result<Ruffle, JsValue> {
if RUFFLE_GLOBAL_PANIC.is_completed() {
// If an actual panic happened, then we can't trust the state it left us in.
// Prevent future players from loading so that they can inform the user about the error.
return Err("Ruffle is panicking!".into());
}
set_panic_handler();
Ruffle::new_internal(parent, js_player, allow_script_access)
Ruffle::new_internal(parent, js_player, allow_script_access, upgrade_to_https)
.map_err(|_| "Error creating player".into())
}

Expand Down Expand Up @@ -284,6 +285,7 @@ impl Ruffle {
parent: HtmlElement,
js_player: JavascriptPlayer,
allow_script_access: bool,
upgrade_to_https: bool,
) -> Result<Ruffle, Box<dyn Error>> {
let _ = console_log::init_with_level(log::Level::Trace);

Expand All @@ -296,7 +298,7 @@ impl Ruffle {
.into_js_result()?;

let audio = Box::new(WebAudioBackend::new()?);
let navigator = Box::new(WebNavigatorBackend::new());
let navigator = Box::new(WebNavigatorBackend::new(upgrade_to_https));
let input = Box::new(WebInputBackend::new(&canvas));
let locale = Box::new(WebLocaleBackend::new());

Expand Down
26 changes: 23 additions & 3 deletions web/src/navigator.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
//! Navigator backend for web

use js_sys::{Array, ArrayBuffer, Uint8Array};
use ruffle_core::backend::navigator::{
url_from_relative_url, NavigationMethod, NavigatorBackend, OwnedFuture, RequestOptions,
Expand All @@ -8,23 +7,26 @@ use ruffle_core::indexmap::IndexMap;
use ruffle_core::loader::Error;
use std::borrow::Cow;
use std::time::Duration;
use url::Url;
use wasm_bindgen::JsCast;
use wasm_bindgen_futures::{spawn_local, JsFuture};
use web_sys::{window, Blob, BlobPropertyBag, Performance, Request, RequestInit, Response};

pub struct WebNavigatorBackend {
performance: Performance,
start_time: f64,
upgrade_to_https: bool,
}

impl WebNavigatorBackend {
pub fn new() -> Self {
pub fn new(upgrade_to_https: bool) -> Self {
let window = web_sys::window().expect("window()");
let performance = window.performance().expect("window.performance()");

WebNavigatorBackend {
start_time: performance.now(),
performance,
upgrade_to_https,
}
}
}
Expand All @@ -37,6 +39,12 @@ impl NavigatorBackend for WebNavigatorBackend {
vars_method: Option<(NavigationMethod, IndexMap<String, String>)>,
) {
if let Some(window) = window() {
let url = if let Ok(parsed_url) = Url::parse(&url) {
self.pre_process_url(parsed_url).to_string()
} else {
url.to_string()
};

//TODO: Should we return a result for failed opens? Does Flash care?
#[allow(unused_must_use)]
match (vars_method, window_spec) {
Expand Down Expand Up @@ -95,7 +103,12 @@ impl NavigatorBackend for WebNavigatorBackend {
}

fn fetch(&self, url: &str, options: RequestOptions) -> OwnedFuture<Vec<u8>, Error> {
let url = url.to_string();
let url = if let Ok(parsed_url) = Url::parse(url) {
self.pre_process_url(parsed_url).to_string()
} else {
url.to_string()
};

Box::pin(async move {
let mut init = RequestInit::new();

Expand Down Expand Up @@ -172,4 +185,11 @@ impl NavigatorBackend for WebNavigatorBackend {

url.into()
}

fn pre_process_url(&self, mut url: Url) -> Url {
if self.upgrade_to_https && url.scheme() == "http" && url.set_scheme("https").is_err() {
log::error!("Url::set_scheme failed on: {}", url);
}
url
}
}

0 comments on commit c4d7b24

Please sign in to comment.