core: Introduce `Request`

Which holds both a URL and what was `RequestOptions` formerly.
This commit is contained in:
relrelb 2022-06-11 11:55:17 +03:00 committed by relrelb
parent 115f15806e
commit f643048c1c
13 changed files with 133 additions and 144 deletions

View File

@ -7,7 +7,7 @@ use crate::avm1::scope::Scope;
use crate::avm1::{ use crate::avm1::{
fscommand, globals, scope, skip_actions, start_drag, ArrayObject, ScriptObject, Value, fscommand, globals, scope, skip_actions, start_drag, ArrayObject, ScriptObject, Value,
}; };
use crate::backend::navigator::{NavigationMethod, RequestOptions}; use crate::backend::navigator::{NavigationMethod, Request};
use crate::context::UpdateContext; use crate::context::UpdateContext;
use crate::display_object::{DisplayObject, MovieClip, TDisplayObject, TDisplayObjectContainer}; use crate::display_object::{DisplayObject, MovieClip, TDisplayObject, TDisplayObjectContainer};
use crate::ecma_conversions::f64_to_wrapping_u32; use crate::ecma_conversions::f64_to_wrapping_u32;
@ -1154,8 +1154,7 @@ impl<'a, 'gc, 'gc_context> Activation<'a, 'gc, 'gc_context> {
let future = self.context.load_manager.load_movie_into_clip( let future = self.context.load_manager.load_movie_into_clip(
self.context.player.clone(), self.context.player.clone(),
level, level,
&url, Request::get(url),
RequestOptions::get(),
None, None,
None, None,
); );
@ -1246,15 +1245,14 @@ impl<'a, 'gc, 'gc_context> Activation<'a, 'gc, 'gc_context> {
.unwrap() .unwrap()
.object() .object()
.coerce_to_object(self); .coerce_to_object(self);
let (url, opts) = self.locals_into_request_options( let request = self.locals_into_request(
&url, url,
NavigationMethod::from_send_vars_method(action.send_vars_method()), NavigationMethod::from_send_vars_method(action.send_vars_method()),
); );
let future = self.context.load_manager.load_form_into_object( let future = self.context.load_manager.load_form_into_object(
self.context.player.clone(), self.context.player.clone(),
target_obj, target_obj,
&url, request,
opts,
); );
self.context.navigator.spawn_future(future); self.context.navigator.spawn_future(future);
} }
@ -1263,22 +1261,20 @@ impl<'a, 'gc, 'gc_context> Activation<'a, 'gc, 'gc_context> {
} else if action.is_target_sprite() { } else if action.is_target_sprite() {
// `loadMovie`, `unloadMovie` or `unloadMovieNum` call. // `loadMovie`, `unloadMovie` or `unloadMovieNum` call.
if let Some(clip_target) = clip_target { if let Some(clip_target) = clip_target {
let (url, opts) = self.locals_into_request_options(
&url,
NavigationMethod::from_send_vars_method(action.send_vars_method()),
);
if url.is_empty() { if url.is_empty() {
// Blank URL on movie loads = unload! // Blank URL on movie loads = unload!
if let Some(mut mc) = clip_target.as_movie_clip() { if let Some(mut mc) = clip_target.as_movie_clip() {
mc.replace_with_movie(self.context.gc_context, None) mc.replace_with_movie(self.context.gc_context, None)
} }
} else { } else {
let request = self.locals_into_request(
url,
NavigationMethod::from_send_vars_method(action.send_vars_method()),
);
let future = self.context.load_manager.load_movie_into_clip( let future = self.context.load_manager.load_movie_into_clip(
self.context.player.clone(), self.context.player.clone(),
clip_target, clip_target,
&url, request,
opts,
None, None,
None, None,
); );
@ -1292,8 +1288,7 @@ impl<'a, 'gc, 'gc_context> Activation<'a, 'gc, 'gc_context> {
let future = self.context.load_manager.load_movie_into_clip( let future = self.context.load_manager.load_movie_into_clip(
self.context.player.clone(), self.context.player.clone(),
clip_target, clip_target,
&url.to_utf8_lossy(), Request::get(url.to_utf8_lossy().into_owned()),
RequestOptions::get(),
None, None,
None, None,
); );
@ -2295,14 +2290,14 @@ impl<'a, 'gc, 'gc_context> Activation<'a, 'gc, 'gc_context> {
form_values form_values
} }
/// Construct request options for a fetch operation that may sends object properties as /// Construct a request for a fetch operation that may send object properties as form data in
/// form data in the request body or URL. /// the request body or URL.
pub fn object_into_request_options<'c>( pub fn object_into_request(
&mut self, &mut self,
object: Object<'gc>, object: Object<'gc>,
url: &'c WStr, url: AvmString<'gc>,
method: Option<NavigationMethod>, method: Option<NavigationMethod>,
) -> (Cow<'c, str>, RequestOptions) { ) -> Request {
match method { match method {
Some(method) => { Some(method) => {
let vars = self.object_into_form_values(object); let vars = self.object_into_form_values(object);
@ -2311,24 +2306,20 @@ impl<'a, 'gc, 'gc_context> Activation<'a, 'gc, 'gc_context> {
.finish(); .finish();
match method { match method {
NavigationMethod::Get if url.find(b'?').is_none() => ( NavigationMethod::Get if !url.contains(b'?') => {
Cow::Owned(format!("{}?{}", url, qstring)), Request::get(format!("{}?{}", url, qstring))
RequestOptions::get(), }
), NavigationMethod::Get => Request::get(format!("{}&{}", url, qstring)),
NavigationMethod::Get => ( NavigationMethod::Post => Request::post(
Cow::Owned(format!("{}&{}", url, qstring)), url.to_utf8_lossy().into_owned(),
RequestOptions::get(), Some((
),
NavigationMethod::Post => (
url.to_utf8_lossy(),
RequestOptions::post(Some((
qstring.as_bytes().to_owned(), qstring.as_bytes().to_owned(),
"application/x-www-form-urlencoded".to_string(), "application/x-www-form-urlencoded".to_string(),
))), )),
), ),
} }
} }
None => (url.to_utf8_lossy(), RequestOptions::get()), None => Request::get(url.to_utf8_lossy().into_owned()),
} }
} }
@ -2344,16 +2335,16 @@ impl<'a, 'gc, 'gc_context> Activation<'a, 'gc, 'gc_context> {
self.object_into_form_values(locals) self.object_into_form_values(locals)
} }
/// Construct request options for a fetch operation that may send locals as /// Construct a request for a fetch operation that may send locals as form data in the request
/// form data in the request body or URL. /// body or URL.
pub fn locals_into_request_options<'c>( pub fn locals_into_request(
&mut self, &mut self,
url: &'c WStr, url: AvmString<'gc>,
method: Option<NavigationMethod>, method: Option<NavigationMethod>,
) -> (Cow<'c, str>, RequestOptions) { ) -> Request {
let scope = self.scope_cell(); let scope = self.scope_cell();
let locals = scope.read().locals_cell(); let locals = scope.read().locals_cell();
self.object_into_request_options(locals, url, method) self.object_into_request(locals, url, method)
} }
/// Resolves a target value to a display object, relative to a starting display object. /// Resolves a target value to a display object, relative to a starting display object.

View File

@ -8,7 +8,7 @@ use crate::avm1::property::Attribute;
use crate::avm1::property_decl::{define_properties_on, Declaration}; use crate::avm1::property_decl::{define_properties_on, Declaration};
use crate::avm1::{Object, ScriptObject, TObject, Value}; use crate::avm1::{Object, ScriptObject, TObject, Value};
use crate::avm_warn; use crate::avm_warn;
use crate::backend::navigator::{NavigationMethod, RequestOptions}; use crate::backend::navigator::{NavigationMethod, Request};
use crate::string::AvmString; use crate::string::AvmString;
use gc_arena::MutationContext; use gc_arena::MutationContext;
@ -102,7 +102,7 @@ fn load<'gc>(
None => return Ok(false.into()), None => return Ok(false.into()),
}; };
spawn_load_var_fetch(activation, this, &url, None)?; spawn_load_var_fetch(activation, this, url, None)?;
Ok(true.into()) Ok(true.into())
} }
@ -215,7 +215,7 @@ fn send_and_load<'gc>(
.coerce_to_string(activation)?; .coerce_to_string(activation)?;
let method = NavigationMethod::from_method_str(&method_name).unwrap_or(NavigationMethod::Post); let method = NavigationMethod::from_method_str(&method_name).unwrap_or(NavigationMethod::Post);
spawn_load_var_fetch(activation, target, &url, Some((this, method)))?; spawn_load_var_fetch(activation, target, url, Some((this, method)))?;
Ok(true.into()) Ok(true.into())
} }
@ -254,22 +254,21 @@ fn to_string<'gc>(
fn spawn_load_var_fetch<'gc>( fn spawn_load_var_fetch<'gc>(
activation: &mut Activation<'_, 'gc, '_>, activation: &mut Activation<'_, 'gc, '_>,
loader_object: Object<'gc>, loader_object: Object<'gc>,
url: &AvmString, url: AvmString<'gc>,
send_object: Option<(Object<'gc>, NavigationMethod)>, send_object: Option<(Object<'gc>, NavigationMethod)>,
) -> Result<Value<'gc>, Error<'gc>> { ) -> Result<Value<'gc>, Error<'gc>> {
let (url, request_options) = if let Some((send_object, method)) = send_object { let request = if let Some((send_object, method)) = send_object {
// Send properties from `send_object`. // Send properties from `send_object`.
activation.object_into_request_options(send_object, url, Some(method)) activation.object_into_request(send_object, url, Some(method))
} else { } else {
// Not sending any parameters. // Not sending any parameters.
(url.to_utf8_lossy(), RequestOptions::get()) Request::get(url.to_utf8_lossy().into_owned())
}; };
let future = activation.context.load_manager.load_form_into_load_vars( let future = activation.context.load_manager.load_form_into_load_vars(
activation.context.player.clone(), activation.context.player.clone(),
loader_object, loader_object,
&url, request,
request_options,
); );
activation.context.navigator.spawn_future(future); activation.context.navigator.spawn_future(future);

View File

@ -1320,12 +1320,11 @@ fn load_movie<'gc>(
let url = url_val.coerce_to_string(activation)?; let url = url_val.coerce_to_string(activation)?;
let method = args.get(1).cloned().unwrap_or(Value::Undefined); let method = args.get(1).cloned().unwrap_or(Value::Undefined);
let method = NavigationMethod::from_method_str(&method.coerce_to_string(activation)?); let method = NavigationMethod::from_method_str(&method.coerce_to_string(activation)?);
let (url, opts) = activation.locals_into_request_options(&url, method); let request = activation.locals_into_request(url, method);
let future = activation.context.load_manager.load_movie_into_clip( let future = activation.context.load_manager.load_movie_into_clip(
activation.context.player.clone(), activation.context.player.clone(),
DisplayObject::MovieClip(target), DisplayObject::MovieClip(target),
&url, request,
opts,
None, None,
None, None,
); );
@ -1343,13 +1342,12 @@ fn load_variables<'gc>(
let url = url_val.coerce_to_string(activation)?; let url = url_val.coerce_to_string(activation)?;
let method = args.get(1).cloned().unwrap_or(Value::Undefined); let method = args.get(1).cloned().unwrap_or(Value::Undefined);
let method = NavigationMethod::from_method_str(&method.coerce_to_string(activation)?); let method = NavigationMethod::from_method_str(&method.coerce_to_string(activation)?);
let (url, opts) = activation.locals_into_request_options(&url, method); let request = activation.locals_into_request(url, method);
let target = target.object().coerce_to_object(activation); let target = target.object().coerce_to_object(activation);
let future = activation.context.load_manager.load_form_into_object( let future = activation.context.load_manager.load_form_into_object(
activation.context.player.clone(), activation.context.player.clone(),
target, target,
&url, request,
opts,
); );
activation.context.navigator.spawn_future(future); activation.context.navigator.spawn_future(future);

View File

@ -8,7 +8,7 @@ use crate::avm1::object::TObject;
use crate::avm1::property::Attribute; use crate::avm1::property::Attribute;
use crate::avm1::property_decl::{define_properties_on, Declaration}; use crate::avm1::property_decl::{define_properties_on, Declaration};
use crate::avm1::{ArrayObject, Object, Value}; use crate::avm1::{ArrayObject, Object, Value};
use crate::backend::navigator::RequestOptions; use crate::backend::navigator::Request;
use crate::display_object::{TDisplayObject, TDisplayObjectContainer}; use crate::display_object::{TDisplayObject, TDisplayObjectContainer};
use gc_arena::MutationContext; use gc_arena::MutationContext;
@ -61,8 +61,7 @@ fn load_clip<'gc>(
let future = activation.context.load_manager.load_movie_into_clip( let future = activation.context.load_manager.load_movie_into_clip(
activation.context.player.clone(), activation.context.player.clone(),
target, target,
&url.to_utf8_lossy(), Request::get(url.to_utf8_lossy().into_owned()),
RequestOptions::get(),
None, None,
Some(this), Some(this),
); );

View File

@ -7,8 +7,8 @@ use crate::avm1::object::xml_object::XmlObject;
use crate::avm1::property_decl::{define_properties_on, Declaration}; use crate::avm1::property_decl::{define_properties_on, Declaration};
use crate::avm1::{Object, TObject, Value}; use crate::avm1::{Object, TObject, Value};
use crate::avm_warn; use crate::avm_warn;
use crate::backend::navigator::RequestOptions; use crate::backend::navigator::Request;
use crate::string::WStr; use crate::string::AvmString;
use crate::xml::{XmlNode, ELEMENT_NODE, TEXT_NODE}; use crate::xml::{XmlNode, ELEMENT_NODE, TEXT_NODE};
use gc_arena::MutationContext; use gc_arena::MutationContext;
@ -134,7 +134,7 @@ fn send_and_load<'gc>(
if let Some(document) = this.as_xml() { if let Some(document) = this.as_xml() {
let url = url_val.coerce_to_string(activation)?; let url = url_val.coerce_to_string(activation)?;
spawn_xml_fetch(activation, this, target, &url, Some(document.as_node()))?; spawn_xml_fetch(activation, this, target, url, Some(document.as_node()))?;
} }
Ok(Value::Undefined) Ok(Value::Undefined)
} }
@ -152,7 +152,7 @@ fn load<'gc>(
if let Some(_document) = this.as_xml() { if let Some(_document) = this.as_xml() {
let url = url_val.coerce_to_string(activation)?; let url = url_val.coerce_to_string(activation)?;
spawn_xml_fetch(activation, this, this, &url, None)?; spawn_xml_fetch(activation, this, this, url, None)?;
Ok(true.into()) Ok(true.into())
} else { } else {
@ -252,19 +252,24 @@ fn spawn_xml_fetch<'gc>(
activation: &mut Activation<'_, 'gc, '_>, activation: &mut Activation<'_, 'gc, '_>,
this: Object<'gc>, this: Object<'gc>,
loader_object: Object<'gc>, loader_object: Object<'gc>,
url: &WStr, url: AvmString<'gc>,
send_object: Option<XmlNode<'gc>>, send_object: Option<XmlNode<'gc>>,
) -> Result<Value<'gc>, Error<'gc>> { ) -> Result<Value<'gc>, Error<'gc>> {
let request_options = if let Some(node) = send_object { let url = url.to_utf8_lossy().into_owned();
let request = if let Some(node) = send_object {
// Send `node` as string. // Send `node` as string.
let string = node.into_string(activation)?; let string = node.into_string(activation)?;
RequestOptions::post(Some(( Request::post(
url,
Some((
string.to_utf8_lossy().into_owned().into_bytes(), string.to_utf8_lossy().into_owned().into_bytes(),
"application/x-www-form-urlencoded".to_string(), "application/x-www-form-urlencoded".to_string(),
))) )),
)
} else { } else {
// Not sending any parameters. // Not sending any parameters.
RequestOptions::get() Request::get(url)
}; };
this.set("loaded", false.into(), activation)?; this.set("loaded", false.into(), activation)?;
@ -272,8 +277,7 @@ fn spawn_xml_fetch<'gc>(
let future = activation.context.load_manager.load_form_into_load_vars( let future = activation.context.load_manager.load_form_into_load_vars(
activation.context.player.clone(), activation.context.player.clone(),
loader_object, loader_object,
&url.to_utf8_lossy(), request,
request_options,
); );
activation.context.navigator.spawn_future(future); activation.context.navigator.spawn_future(future);

View File

@ -7,7 +7,7 @@ use crate::avm2::names::{Multiname, Namespace, QName};
use crate::avm2::object::TObject; use crate::avm2::object::TObject;
use crate::avm2::value::Value; use crate::avm2::value::Value;
use crate::avm2::{Error, Object}; use crate::avm2::{Error, Object};
use crate::backend::navigator::RequestOptions; use crate::backend::navigator::Request;
use crate::loader::DataFormat; use crate::loader::DataFormat;
use gc_arena::{GcCell, MutationContext}; use gc_arena::{GcCell, MutationContext};
@ -130,14 +130,11 @@ fn spawn_fetch<'gc>(
.get_property(&QName::dynamic_name("url").into(), activation)? .get_property(&QName::dynamic_name("url").into(), activation)?
.coerce_to_string(activation)?; .coerce_to_string(activation)?;
let url = url.to_utf8_lossy();
let future = activation.context.load_manager.load_data_into_url_loader( let future = activation.context.load_manager.load_data_into_url_loader(
activation.context.player.clone(), activation.context.player.clone(),
loader_object, loader_object,
&url,
// FIXME - get these from the `URLRequest` // FIXME - get these from the `URLRequest`
RequestOptions::get(), Request::get(url.to_utf8_lossy().into_owned()),
data_format, data_format,
); );
activation.context.navigator.spawn_future(future); activation.context.navigator.spawn_future(future);

View File

@ -54,8 +54,11 @@ impl NavigationMethod {
} }
} }
/// Represents request options to be sent as part of a fetch. /// A fetch request.
pub struct RequestOptions { pub struct Request {
/// The URL of the request.
url: String,
/// The HTTP method to be used to make the request. /// The HTTP method to be used to make the request.
method: NavigationMethod, method: NavigationMethod,
@ -66,23 +69,30 @@ pub struct RequestOptions {
body: Option<(Vec<u8>, String)>, body: Option<(Vec<u8>, String)>,
} }
impl RequestOptions { impl Request {
/// Construct request options for a GET request. /// Construct a GET request.
pub fn get() -> Self { pub fn get(url: String) -> Self {
Self { Self {
url,
method: NavigationMethod::Get, method: NavigationMethod::Get,
body: None, body: None,
} }
} }
/// Construct request options for a POST request. /// Construct a POST request.
pub fn post(body: Option<(Vec<u8>, String)>) -> Self { pub fn post(url: String, body: Option<(Vec<u8>, String)>) -> Self {
Self { Self {
url,
method: NavigationMethod::Post, method: NavigationMethod::Post,
body, body,
} }
} }
/// Retrieve the URL of this request.
pub fn url(&self) -> &str {
&self.url
}
/// Retrieve the navigation method for this request. /// Retrieve the navigation method for this request.
pub fn method(&self) -> NavigationMethod { pub fn method(&self) -> NavigationMethod {
self.method self.method
@ -138,8 +148,8 @@ pub trait NavigatorBackend {
vars_method: Option<(NavigationMethod, IndexMap<String, String>)>, vars_method: Option<(NavigationMethod, IndexMap<String, String>)>,
); );
/// Fetch data at a given URL and return it some time in the future. /// Fetch data and return it some time in the future.
fn fetch(&self, url: &str, request_options: RequestOptions) -> OwnedFuture<Response, Error>; fn fetch(&self, request: Request) -> OwnedFuture<Response, Error>;
/// Arrange for a future to be run at some point in the... well, future. /// Arrange for a future to be run at some point in the... well, future.
/// ///
@ -280,9 +290,9 @@ impl NavigatorBackend for NullNavigatorBackend {
) { ) {
} }
fn fetch(&self, url: &str, _opts: RequestOptions) -> OwnedFuture<Response, Error> { fn fetch(&self, request: Request) -> OwnedFuture<Response, Error> {
let mut path = self.relative_base_path.clone(); let mut path = self.relative_base_path.clone();
path.push(url); path.push(request.url);
Box::pin(async move { Box::pin(async move {
let url = Self::url_from_file_path(&path) let url = Self::url_from_file_path(&path)

View File

@ -11,7 +11,7 @@ use crate::avm2::{
Activation as Avm2Activation, Avm2, Domain as Avm2Domain, Event as Avm2Event, Activation as Avm2Activation, Avm2, Domain as Avm2Domain, Event as Avm2Event,
EventData as Avm2EventData, Object as Avm2Object, QName, Value as Avm2Value, EventData as Avm2EventData, Object as Avm2Object, QName, Value as Avm2Value,
}; };
use crate::backend::navigator::{OwnedFuture, RequestOptions}; use crate::backend::navigator::{OwnedFuture, Request};
use crate::backend::render::{determine_jpeg_tag_format, JpegTagFormat}; use crate::backend::render::{determine_jpeg_tag_format, JpegTagFormat};
use crate::context::{ActionQueue, ActionType, UpdateContext}; use crate::context::{ActionQueue, ActionType, UpdateContext};
use crate::display_object::{ use crate::display_object::{
@ -189,15 +189,14 @@ impl<'gc> LoadManager<'gc> {
pub fn load_root_movie( pub fn load_root_movie(
&mut self, &mut self,
player: Weak<Mutex<Player>>, player: Weak<Mutex<Player>>,
url: &str, request: Request,
options: RequestOptions,
parameters: Vec<(String, String)>, parameters: Vec<(String, String)>,
on_metadata: Box<dyn FnOnce(&swf::HeaderExt)>, on_metadata: Box<dyn FnOnce(&swf::HeaderExt)>,
) -> OwnedFuture<(), Error> { ) -> OwnedFuture<(), Error> {
let loader = Loader::RootMovie { self_handle: None }; let loader = Loader::RootMovie { self_handle: None };
let handle = self.add_loader(loader); let handle = self.add_loader(loader);
let loader = self.get_loader_mut(handle).unwrap(); let loader = self.get_loader_mut(handle).unwrap();
loader.root_movie_loader(player, url.to_owned(), options, parameters, on_metadata) loader.root_movie_loader(player, request, parameters, on_metadata)
} }
/// Kick off a movie clip load. /// Kick off a movie clip load.
@ -207,8 +206,7 @@ impl<'gc> LoadManager<'gc> {
&mut self, &mut self,
player: Weak<Mutex<Player>>, player: Weak<Mutex<Player>>,
target_clip: DisplayObject<'gc>, target_clip: DisplayObject<'gc>,
url: &str, request: Request,
options: RequestOptions,
loader_url: Option<String>, loader_url: Option<String>,
target_broadcaster: Option<Object<'gc>>, target_broadcaster: Option<Object<'gc>>,
) -> OwnedFuture<(), Error> { ) -> OwnedFuture<(), Error> {
@ -220,7 +218,7 @@ impl<'gc> LoadManager<'gc> {
}; };
let handle = self.add_loader(loader); let handle = self.add_loader(loader);
let loader = self.get_loader_mut(handle).unwrap(); let loader = self.get_loader_mut(handle).unwrap();
loader.movie_loader(player, url.to_owned(), options, loader_url) loader.movie_loader(player, request, loader_url)
} }
/// Indicates that a movie clip has initialized (ran its first frame). /// Indicates that a movie clip has initialized (ran its first frame).
@ -247,8 +245,7 @@ impl<'gc> LoadManager<'gc> {
&mut self, &mut self,
player: Weak<Mutex<Player>>, player: Weak<Mutex<Player>>,
target_object: Object<'gc>, target_object: Object<'gc>,
url: &str, request: Request,
options: RequestOptions,
) -> OwnedFuture<(), Error> { ) -> OwnedFuture<(), Error> {
let loader = Loader::Form { let loader = Loader::Form {
self_handle: None, self_handle: None,
@ -256,7 +253,7 @@ impl<'gc> LoadManager<'gc> {
}; };
let handle = self.add_loader(loader); let handle = self.add_loader(loader);
let loader = self.get_loader_mut(handle).unwrap(); let loader = self.get_loader_mut(handle).unwrap();
loader.form_loader(player, url.to_owned(), options) loader.form_loader(player, request)
} }
/// Kick off a form data load into an AVM1 object. /// Kick off a form data load into an AVM1 object.
@ -266,8 +263,7 @@ impl<'gc> LoadManager<'gc> {
&mut self, &mut self,
player: Weak<Mutex<Player>>, player: Weak<Mutex<Player>>,
target_object: Object<'gc>, target_object: Object<'gc>,
url: &str, request: Request,
options: RequestOptions,
) -> OwnedFuture<(), Error> { ) -> OwnedFuture<(), Error> {
let loader = Loader::LoadVars { let loader = Loader::LoadVars {
self_handle: None, self_handle: None,
@ -275,7 +271,7 @@ impl<'gc> LoadManager<'gc> {
}; };
let handle = self.add_loader(loader); let handle = self.add_loader(loader);
let loader = self.get_loader_mut(handle).unwrap(); let loader = self.get_loader_mut(handle).unwrap();
loader.load_vars_loader(player, url.to_owned(), options) loader.load_vars_loader(player, request)
} }
/// Kick off a data load into a `URLLoader`, updating /// Kick off a data load into a `URLLoader`, updating
@ -286,8 +282,7 @@ impl<'gc> LoadManager<'gc> {
&mut self, &mut self,
player: Weak<Mutex<Player>>, player: Weak<Mutex<Player>>,
target_object: Avm2Object<'gc>, target_object: Avm2Object<'gc>,
url: &str, request: Request,
options: RequestOptions,
data_format: DataFormat, data_format: DataFormat,
) -> OwnedFuture<(), Error> { ) -> OwnedFuture<(), Error> {
let loader = Loader::LoadURLLoader { let loader = Loader::LoadURLLoader {
@ -296,7 +291,7 @@ impl<'gc> LoadManager<'gc> {
}; };
let handle = self.add_loader(loader); let handle = self.add_loader(loader);
let loader = self.get_loader_mut(handle).unwrap(); let loader = self.get_loader_mut(handle).unwrap();
loader.load_url_loader(player, url.to_owned(), options, data_format) loader.load_url_loader(player, request, data_format)
} }
} }
@ -390,8 +385,7 @@ impl<'gc> Loader<'gc> {
fn root_movie_loader( fn root_movie_loader(
&mut self, &mut self,
player: Weak<Mutex<Player>>, player: Weak<Mutex<Player>>,
url: String, request: Request,
options: RequestOptions,
parameters: Vec<(String, String)>, parameters: Vec<(String, String)>,
on_metadata: Box<dyn FnOnce(&swf::HeaderExt)>, on_metadata: Box<dyn FnOnce(&swf::HeaderExt)>,
) -> OwnedFuture<(), Error> { ) -> OwnedFuture<(), Error> {
@ -407,7 +401,7 @@ impl<'gc> Loader<'gc> {
.expect("Could not upgrade weak reference to player"); .expect("Could not upgrade weak reference to player");
Box::pin(async move { Box::pin(async move {
let fetch = player.lock().unwrap().navigator().fetch(&url, options); let fetch = player.lock().unwrap().navigator().fetch(request);
let response = fetch.await.map_err(|error| { let response = fetch.await.map_err(|error| {
player player
@ -436,8 +430,7 @@ impl<'gc> Loader<'gc> {
fn movie_loader( fn movie_loader(
&mut self, &mut self,
player: Weak<Mutex<Player>>, player: Weak<Mutex<Player>>,
url: String, request: Request,
options: RequestOptions,
loader_url: Option<String>, loader_url: Option<String>,
) -> OwnedFuture<(), Error> { ) -> OwnedFuture<(), Error> {
let handle = match self { let handle = match self {
@ -450,7 +443,7 @@ impl<'gc> Loader<'gc> {
.expect("Could not upgrade weak reference to player"); .expect("Could not upgrade weak reference to player");
Box::pin(async move { Box::pin(async move {
let fetch = player.lock().unwrap().navigator().fetch(&url, options); let fetch = player.lock().unwrap().navigator().fetch(request);
let mut replacing_root_movie = false; let mut replacing_root_movie = false;
player.lock().unwrap().update(|uc| -> Result<(), Error> { player.lock().unwrap().update(|uc| -> Result<(), Error> {
@ -545,8 +538,7 @@ impl<'gc> Loader<'gc> {
fn form_loader( fn form_loader(
&mut self, &mut self,
player: Weak<Mutex<Player>>, player: Weak<Mutex<Player>>,
url: String, request: Request,
options: RequestOptions,
) -> OwnedFuture<(), Error> { ) -> OwnedFuture<(), Error> {
let handle = match self { let handle = match self {
Loader::Form { self_handle, .. } => self_handle.expect("Loader not self-introduced"), Loader::Form { self_handle, .. } => self_handle.expect("Loader not self-introduced"),
@ -558,7 +550,7 @@ impl<'gc> Loader<'gc> {
.expect("Could not upgrade weak reference to player"); .expect("Could not upgrade weak reference to player");
Box::pin(async move { Box::pin(async move {
let fetch = player.lock().unwrap().navigator().fetch(&url, options); let fetch = player.lock().unwrap().navigator().fetch(request);
let response = fetch.await?; let response = fetch.await?;
@ -607,8 +599,7 @@ impl<'gc> Loader<'gc> {
fn load_vars_loader( fn load_vars_loader(
&mut self, &mut self,
player: Weak<Mutex<Player>>, player: Weak<Mutex<Player>>,
url: String, request: Request,
options: RequestOptions,
) -> OwnedFuture<(), Error> { ) -> OwnedFuture<(), Error> {
let handle = match self { let handle = match self {
Loader::LoadVars { self_handle, .. } => { Loader::LoadVars { self_handle, .. } => {
@ -622,7 +613,7 @@ impl<'gc> Loader<'gc> {
.expect("Could not upgrade weak reference to player"); .expect("Could not upgrade weak reference to player");
Box::pin(async move { Box::pin(async move {
let fetch = player.lock().unwrap().navigator().fetch(&url, options); let fetch = player.lock().unwrap().navigator().fetch(request);
let data = fetch.await; let data = fetch.await;
@ -689,8 +680,7 @@ impl<'gc> Loader<'gc> {
fn load_url_loader( fn load_url_loader(
&mut self, &mut self,
player: Weak<Mutex<Player>>, player: Weak<Mutex<Player>>,
url: String, request: Request,
options: RequestOptions,
data_format: DataFormat, data_format: DataFormat,
) -> OwnedFuture<(), Error> { ) -> OwnedFuture<(), Error> {
let handle = match self { let handle = match self {
@ -705,7 +695,7 @@ impl<'gc> Loader<'gc> {
.expect("Could not upgrade weak reference to player"); .expect("Could not upgrade weak reference to player");
Box::pin(async move { Box::pin(async move {
let fetch = player.lock().unwrap().navigator().fetch(&url, options); let fetch = player.lock().unwrap().navigator().fetch(request);
let response = fetch.await; let response = fetch.await;
player.lock().unwrap().update(|uc| { player.lock().unwrap().update(|uc| {

View File

@ -8,7 +8,7 @@ use crate::avm2::{Activation as Avm2Activation, Avm2, Domain as Avm2Domain};
use crate::backend::{ use crate::backend::{
audio::{AudioBackend, AudioManager}, audio::{AudioBackend, AudioManager},
log::LogBackend, log::LogBackend,
navigator::{NavigatorBackend, RequestOptions}, navigator::{NavigatorBackend, Request},
render::RenderBackend, render::RenderBackend,
storage::StorageBackend, storage::StorageBackend,
ui::{InputManager, MouseCursor, UiBackend}, ui::{InputManager, MouseCursor, UiBackend},
@ -242,15 +242,14 @@ impl Player {
/// off. /// off.
pub fn fetch_root_movie( pub fn fetch_root_movie(
&mut self, &mut self,
movie_url: &str, movie_url: String,
parameters: Vec<(String, String)>, parameters: Vec<(String, String)>,
on_metadata: Box<dyn FnOnce(&swf::HeaderExt)>, on_metadata: Box<dyn FnOnce(&swf::HeaderExt)>,
) { ) {
self.mutate_with_update_context(|context| { self.mutate_with_update_context(|context| {
let future = context.load_manager.load_root_movie( let future = context.load_manager.load_root_movie(
context.player.clone(), context.player.clone(),
movie_url, Request::get(movie_url),
RequestOptions::get(),
parameters, parameters,
on_metadata, on_metadata,
); );

View File

@ -249,14 +249,14 @@ impl App {
let player = builder.build(); let player = builder.build();
if let Some(movie_url) = &movie_url { if let Some(movie_url) = movie_url {
let event_loop_proxy = event_loop.create_proxy(); let event_loop_proxy = event_loop.create_proxy();
let on_metadata = move |swf_header: &ruffle_core::swf::HeaderExt| { let on_metadata = move |swf_header: &ruffle_core::swf::HeaderExt| {
let _ = event_loop_proxy.send_event(RuffleEvent::OnMetadata(swf_header.clone())); let _ = event_loop_proxy.send_event(RuffleEvent::OnMetadata(swf_header.clone()));
}; };
player.lock().unwrap().fetch_root_movie( player.lock().unwrap().fetch_root_movie(
movie_url.as_str(), movie_url.as_str().to_owned(),
parse_parameters(&opt).collect(), parse_parameters(&opt).collect(),
Box::new(on_metadata), Box::new(on_metadata),
); );

View File

@ -1,9 +1,11 @@
//! Navigator backend for web //! Navigator backend for web
use crate::custom_event::RuffleEvent; use crate::custom_event::RuffleEvent;
use isahc::{config::RedirectPolicy, prelude::*, AsyncReadResponseExt, HttpClient, Request}; use isahc::{
config::RedirectPolicy, prelude::*, AsyncReadResponseExt, HttpClient, Request as IsahcRequest,
};
use ruffle_core::backend::navigator::{ use ruffle_core::backend::navigator::{
NavigationMethod, NavigatorBackend, OwnedFuture, RequestOptions, Response, NavigationMethod, NavigatorBackend, OwnedFuture, Request, Response,
}; };
use ruffle_core::indexmap::IndexMap; use ruffle_core::indexmap::IndexMap;
use ruffle_core::loader::Error; use ruffle_core::loader::Error;
@ -103,12 +105,12 @@ impl NavigatorBackend for ExternalNavigatorBackend {
}; };
} }
fn fetch(&self, url: &str, options: RequestOptions) -> OwnedFuture<Response, Error> { fn fetch(&self, request: Request) -> OwnedFuture<Response, Error> {
// TODO: honor sandbox type (local-with-filesystem, local-with-network, remote, ...) // TODO: honor sandbox type (local-with-filesystem, local-with-network, remote, ...)
let full_url = match self.movie_url.join(url) { let full_url = match self.movie_url.join(request.url()) {
Ok(url) => url, Ok(url) => url,
Err(e) => { Err(e) => {
let msg = format!("Invalid URL {}: {}", url, e); let msg = format!("Invalid URL {}: {}", request.url(), e);
return Box::pin(async move { Err(Error::FetchError(msg)) }); return Box::pin(async move { Err(Error::FetchError(msg)) });
} }
}; };
@ -152,13 +154,13 @@ impl NavigatorBackend for ExternalNavigatorBackend {
let client = let client =
client.ok_or_else(|| Error::FetchError("Network unavailable".to_string()))?; client.ok_or_else(|| Error::FetchError("Network unavailable".to_string()))?;
let request = match options.method() { let isahc_request = match request.method() {
NavigationMethod::Get => Request::get(processed_url.to_string()), NavigationMethod::Get => IsahcRequest::get(processed_url.to_string()),
NavigationMethod::Post => Request::post(processed_url.to_string()), NavigationMethod::Post => IsahcRequest::post(processed_url.to_string()),
}; };
let (body_data, _) = options.body().clone().unwrap_or_default(); let (body_data, _) = request.body().clone().unwrap_or_default();
let body = request let body = isahc_request
.body(body_data) .body(body_data)
.map_err(|e| Error::FetchError(e.to_string()))?; .map_err(|e| Error::FetchError(e.to_string()))?;

View File

@ -219,7 +219,7 @@ impl Ruffle {
/// Stream an arbitrary movie file from (presumably) the Internet. /// Stream an arbitrary movie file from (presumably) the Internet.
/// ///
/// This method should only be called once per player. /// This method should only be called once per player.
pub fn stream_from(&mut self, movie_url: &str, parameters: &JsValue) -> Result<(), JsValue> { pub fn stream_from(&mut self, movie_url: String, parameters: &JsValue) -> Result<(), JsValue> {
let _ = self.with_core_mut(|core| { let _ = self.with_core_mut(|core| {
let parameters_to_load = parse_movie_parameters(parameters); let parameters_to_load = parse_movie_parameters(parameters);

View File

@ -1,8 +1,7 @@
//! Navigator backend for web //! Navigator backend for web
use js_sys::{Array, ArrayBuffer, Uint8Array}; use js_sys::{Array, ArrayBuffer, Uint8Array};
use ruffle_core::backend::navigator::{ use ruffle_core::backend::navigator::{
url_from_relative_url, NavigationMethod, NavigatorBackend, OwnedFuture, RequestOptions, url_from_relative_url, NavigationMethod, NavigatorBackend, OwnedFuture, Request, Response,
Response,
}; };
use ruffle_core::indexmap::IndexMap; use ruffle_core::indexmap::IndexMap;
use ruffle_core::loader::Error; use ruffle_core::loader::Error;
@ -11,7 +10,8 @@ use url::Url;
use wasm_bindgen::JsCast; use wasm_bindgen::JsCast;
use wasm_bindgen_futures::{spawn_local, JsFuture}; use wasm_bindgen_futures::{spawn_local, JsFuture};
use web_sys::{ use web_sys::{
window, Blob, BlobPropertyBag, Document, Request, RequestInit, Response as WebResponse, window, Blob, BlobPropertyBag, Document, Request as WebRequest, RequestInit,
Response as WebResponse,
}; };
pub struct WebNavigatorBackend { pub struct WebNavigatorBackend {
@ -173,22 +173,22 @@ impl NavigatorBackend for WebNavigatorBackend {
} }
} }
fn fetch(&self, url: &str, options: RequestOptions) -> OwnedFuture<Response, Error> { fn fetch(&self, request: Request) -> OwnedFuture<Response, Error> {
let url = if let Ok(parsed_url) = Url::parse(url) { let url = if let Ok(parsed_url) = Url::parse(request.url()) {
self.pre_process_url(parsed_url).to_string() self.pre_process_url(parsed_url).to_string()
} else { } else {
self.resolve_relative_url(url).to_string() self.resolve_relative_url(request.url()).to_string()
}; };
Box::pin(async move { Box::pin(async move {
let mut init = RequestInit::new(); let mut init = RequestInit::new();
init.method(match options.method() { init.method(match request.method() {
NavigationMethod::Get => "GET", NavigationMethod::Get => "GET",
NavigationMethod::Post => "POST", NavigationMethod::Post => "POST",
}); });
if let Some((data, mime)) = options.body() { if let Some((data, mime)) = request.body() {
let arraydata = ArrayBuffer::new(data.len() as u32); let arraydata = ArrayBuffer::new(data.len() as u32);
let u8data = Uint8Array::new(&arraydata); let u8data = Uint8Array::new(&arraydata);
@ -211,7 +211,7 @@ impl NavigatorBackend for WebNavigatorBackend {
init.body(Some(&datablob)); init.body(Some(&datablob));
} }
let request = Request::new_with_str_and_init(&url, &init) let request = WebRequest::new_with_str_and_init(&url, &init)
.map_err(|_| Error::FetchError(format!("Unable to create request for {}", url)))?; .map_err(|_| Error::FetchError(format!("Unable to create request for {}", url)))?;
let window = web_sys::window().unwrap(); let window = web_sys::window().unwrap();