core: Add error for loading invalid SWF files and display as appropriate

This commit is contained in:
Daniel Jacobs 2024-01-16 11:05:05 -05:00
parent 5765177ba7
commit 8f2292c2c7
8 changed files with 37 additions and 16 deletions

View File

@ -81,7 +81,7 @@ pub trait UiBackend: Downcast {
/// Displays a message about an error during root movie download. /// Displays a message about an error during root movie download.
/// In particular, on web this can be a CORS error, which we can sidestep /// In particular, on web this can be a CORS error, which we can sidestep
/// by providing a direct .swf link instead. /// by providing a direct .swf link instead.
fn display_root_movie_download_failed_message(&self); fn display_root_movie_download_failed_message(&self, _invalid_swf: bool);
// Unused, but kept in case we need it later. // Unused, but kept in case we need it later.
fn message(&self, message: &str); fn message(&self, message: &str);
@ -275,7 +275,7 @@ impl UiBackend for NullUiBackend {
Ok(()) Ok(())
} }
fn display_root_movie_download_failed_message(&self) {} fn display_root_movie_download_failed_message(&self, _invalid_swf: bool) {}
fn message(&self, _message: &str) {} fn message(&self, _message: &str) {}

View File

@ -821,7 +821,7 @@ impl<'gc> Loader<'gc> {
.lock() .lock()
.unwrap() .unwrap()
.ui() .ui()
.display_root_movie_download_failed_message(); .display_root_movie_download_failed_message(false);
error.error error.error
})?; })?;
@ -844,7 +844,7 @@ impl<'gc> Loader<'gc> {
.lock() .lock()
.unwrap() .unwrap()
.ui() .ui()
.display_root_movie_download_failed_message(); .display_root_movie_download_failed_message(true);
error error
})?; })?;
on_metadata(movie.header()); on_metadata(movie.header());

View File

@ -196,7 +196,7 @@ impl UiBackend for DesktopUiBackend {
Ok(()) Ok(())
} }
fn display_root_movie_download_failed_message(&self) { fn display_root_movie_download_failed_message(&self, _invalid_swf: bool) {
let dialog = MessageDialog::new() let dialog = MessageDialog::new()
.set_level(MessageLevel::Warning) .set_level(MessageLevel::Warning)
.set_title("Ruffle - Load failed") .set_title("Ruffle - Load failed")

View File

@ -113,7 +113,7 @@ impl UiBackend for TestUiBackend {
Ok(()) Ok(())
} }
fn display_root_movie_download_failed_message(&self) {} fn display_root_movie_download_failed_message(&self, _invalid_swf: bool) {}
fn message(&self, _message: &str) {} fn message(&self, _message: &str) {}

View File

@ -35,6 +35,7 @@ enum PanicError {
WasmMimeType, WasmMimeType,
WasmNotFound, WasmNotFound,
WasmDisabledMicrosoftEdge, WasmDisabledMicrosoftEdge,
InvalidSwf,
SwfFetchError, SwfFetchError,
SwfCors, SwfCors,
} }
@ -2114,6 +2115,10 @@ export class RufflePlayer extends HTMLElement {
new PanicLinkInfo(), new PanicLinkInfo(),
]); ]);
break; break;
case PanicError.InvalidSwf:
errorBody = textAsParagraphs("error-invalid-swf");
errorFooter = this.createErrorFooter([new PanicLinkInfo()]);
break;
case PanicError.SwfFetchError: case PanicError.SwfFetchError:
errorBody = textAsParagraphs("error-swf-fetch"); errorBody = textAsParagraphs("error-swf-fetch");
errorFooter = this.createErrorFooter([new PanicLinkInfo()]); errorFooter = this.createErrorFooter([new PanicLinkInfo()]);
@ -2244,10 +2249,14 @@ export class RufflePlayer extends HTMLElement {
this.destroy(); this.destroy();
} }
protected displayRootMovieDownloadFailedMessage(): void { protected displayRootMovieDownloadFailedMessage(invalidSwf: boolean): void {
const openInNewTab = this.loadedConfig?.openInNewTab; const openInNewTab = this.loadedConfig?.openInNewTab;
if (openInNewTab && window.location.origin !== this.swfUrl!.origin) { if (
const url = new URL(this.swfUrl!); openInNewTab &&
this.swfUrl &&
window.location.origin !== this.swfUrl.origin
) {
const url = new URL(this.swfUrl);
if (this.loadedConfig?.parameters) { if (this.loadedConfig?.parameters) {
const parameters = sanitizeParameters( const parameters = sanitizeParameters(
this.loadedConfig?.parameters, this.loadedConfig?.parameters,
@ -2275,10 +2284,12 @@ export class RufflePlayer extends HTMLElement {
this.container.prepend(div); this.container.prepend(div);
} else { } else {
const error = new Error("Failed to fetch: " + this.swfUrl); const error = new Error("Failed to fetch: " + this.swfUrl);
if (!this.swfUrl!.protocol.includes("http")) { if (this.swfUrl && !this.swfUrl.protocol.includes("http")) {
error.ruffleIndexError = PanicError.FileProtocol; error.ruffleIndexError = PanicError.FileProtocol;
} else if (invalidSwf) {
error.ruffleIndexError = PanicError.InvalidSwf;
} else if ( } else if (
window.location.origin === this.swfUrl!.origin || window.location.origin === this.swfUrl?.origin ||
// The extension's internal player page is not restricted by CORS // The extension's internal player page is not restricted by CORS
window.location.protocol.includes("extension") window.location.protocol.includes("extension")
) { ) {

View File

@ -30,6 +30,9 @@ error-wasm-mime-type =
Ruffle has encountered a major issue whilst trying to initialize. Ruffle has encountered a major issue whilst trying to initialize.
This web server is not serving ".wasm" files with the correct MIME type. This web server is not serving ".wasm" files with the correct MIME type.
If you are the server administrator, please consult the Ruffle wiki for help. If you are the server administrator, please consult the Ruffle wiki for help.
error-invalid-swf =
Ruffle cannot parse the requested file.
The most likely reason is that the requested file is not a valid SWF.
error-swf-fetch = error-swf-fetch =
Ruffle failed to load the Flash SWF file. Ruffle failed to load the Flash SWF file.
The most likely reason is that the file no longer exists, so there is nothing for Ruffle to load. The most likely reason is that the file no longer exists, so there is nothing for Ruffle to load.

View File

@ -105,7 +105,7 @@ extern "C" {
fn panic(this: &JavascriptPlayer, error: &JsError); fn panic(this: &JavascriptPlayer, error: &JsError);
#[wasm_bindgen(method, js_name = "displayRootMovieDownloadFailedMessage")] #[wasm_bindgen(method, js_name = "displayRootMovieDownloadFailedMessage")]
fn display_root_movie_download_failed_message(this: &JavascriptPlayer); fn display_root_movie_download_failed_message(this: &JavascriptPlayer, invalid_swf: bool);
#[wasm_bindgen(method, js_name = "displayMessage")] #[wasm_bindgen(method, js_name = "displayMessage")]
fn display_message(this: &JavascriptPlayer, message: &str); fn display_message(this: &JavascriptPlayer, message: &str);
@ -401,8 +401,14 @@ impl Ruffle {
segments.push(&swf_name); segments.push(&swf_name);
} }
let mut movie = SwfMovie::from_data(&swf_data.to_vec(), url.to_string(), None) let mut movie =
.map_err(|e| format!("Error loading movie: {e}"))?; SwfMovie::from_data(&swf_data.to_vec(), url.to_string(), None).map_err(|e| {
let _ = self.with_core_mut(|core| {
core.ui_mut()
.display_root_movie_download_failed_message(true);
});
format!("Error loading movie: {e}")
})?;
movie.append_parameters(parse_movie_parameters(&parameters)); movie.append_parameters(parse_movie_parameters(&parameters));
self.on_metadata(movie.header()); self.on_metadata(movie.header());

View File

@ -240,8 +240,9 @@ impl UiBackend for WebUiBackend {
} }
} }
fn display_root_movie_download_failed_message(&self) { fn display_root_movie_download_failed_message(&self, invalid_swf: bool) {
self.js_player.display_root_movie_download_failed_message() self.js_player
.display_root_movie_download_failed_message(invalid_swf)
} }
fn message(&self, message: &str) { fn message(&self, message: &str) {