Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
web: Fix cors issues with http (close ruffle-rs#1486)
  • Loading branch information
SamMorrowDrums committed Dec 11, 2020
1 parent 83fcd7b commit 23e666e
Show file tree
Hide file tree
Showing 7 changed files with 82 additions and 16 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<'a>(&self, url: &'a str) -> Cow<'a, str>;
}

/// 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<'a>(&self, url: &'a str) -> Cow<'a, str> {
url.into()
}
}
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
44 changes: 34 additions & 10 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,9 +100,9 @@ impl NavigatorBackend for ExternalNavigatorBackend {
}
}

parsed_url.into_string()
self.pre_process_url(parsed_url.as_str()).to_string()
}
None => url,
None => self.pre_process_url(url.as_str()).to_string(),
};

match webbrowser::open(&modified_url) {
Expand All @@ -107,25 +111,33 @@ impl NavigatorBackend for ExternalNavigatorBackend {
};
}

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 = match Url::parse(&self.pre_process_url(full_url.as_str())) {
Ok(parsed_url) => parsed_url,
Err(e) => {
log::warn!(
"Could not parse pre_processed URL because of {}, the source URL was: {}",
e,
full_url.as_str()
);
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 +155,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 +177,14 @@ impl NavigatorBackend for ExternalNavigatorBackend {
url.into()
}
}

fn pre_process_url<'a>(&self, url: &'a str) -> Cow<'a, str> {
if self.upgrade_to_https && url.starts_with("http://") {
url.replace("http://", "https://").into()
} else {
url.into()
}
}
}

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 @@ -313,7 +313,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
16 changes: 13 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 @@ -15,16 +14,18 @@ use web_sys::{window, Blob, BlobPropertyBag, Performance, Request, RequestInit,
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 +38,7 @@ impl NavigatorBackend for WebNavigatorBackend {
vars_method: Option<(NavigationMethod, IndexMap<String, String>)>,
) {
if let Some(window) = window() {
let url = self.pre_process_url(&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 +97,7 @@ impl NavigatorBackend for WebNavigatorBackend {
}

fn fetch(&self, url: &str, options: RequestOptions) -> OwnedFuture<Vec<u8>, Error> {
let url = url.to_string();
let url = self.pre_process_url(url).to_string();
Box::pin(async move {
let mut init = RequestInit::new();

Expand Down Expand Up @@ -172,4 +174,12 @@ impl NavigatorBackend for WebNavigatorBackend {

url.into()
}

fn pre_process_url<'a>(&self, url: &'a str) -> Cow<'a, str> {
if self.upgrade_to_https && url.starts_with("http://") {
url.replace("http://", "https://").into()
} else {
url.into()
}
}
}

0 comments on commit 23e666e

Please sign in to comment.