Bug 821726 - allow bypassing script cache when using loadSubscript, r=bholley

This commit is contained in:
Gijs Kruitbosch 2013-11-05 16:35:41 +01:00
parent c9c4a1d06f
commit a0af27438c
6 changed files with 115 additions and 20 deletions

View File

@ -6,14 +6,14 @@
#include "nsISupports.idl"
[scriptable, uuid(837d0211-c448-4bb8-a9bf-922ba33b9d37)]
[scriptable, uuid(b21f1579-d994-4e99-a85d-a685140f3ec1)]
interface mozIJSSubScriptLoader : nsISupports
{
/**
* This method should only be called from JS!
* In JS, the signature looks like:
* rv loadSubScript (url [, obj] [, charset]);
* @param url the url if the sub-script, it MUST be either a file:,
* @param url the url of the sub-script, it MUST be either a file:,
* resource:, or chrome: url, and MUST be local.
* @param obj an optional object to evaluate the script onto, it
* defaults to the global object of the caller.
@ -24,4 +24,19 @@ interface mozIJSSubScriptLoader : nsISupports
*/
[implicit_jscontext]
jsval loadSubScript(in AString url, [optional] in jsval obj, [optional] in AString charset);
/**
* This method should only be called from JS!
* In JS, the signature looks like:
* rv = loadSubScript (url, optionsObject)
* @param url the url of the sub-script, it MUST be either a file:,
* resource:, or chrome: url, and MUST be local.
* @param optionsObject an object with parameters. Valid parameters are:
* - charset: specifying the character encoding of the file (default: ASCII)
* - target: an object to evaluate onto (default: global object of the caller)
* - ignoreCache: if set to true, will bypass the cache for reading the file.
* @retval rv the value returned by the sub-script
*/
[implicit_jscontext]
jsval loadSubScriptWithOptions(in AString url, in jsval options);
};

View File

@ -24,12 +24,36 @@
#include "js/OldDebugAPI.h"
#include "nsJSPrincipals.h"
#include "xpcpublic.h" // For xpc::SystemErrorReporter
#include "xpcprivate.h" // For xpc::OptionsBase
#include "mozilla/scache/StartupCache.h"
#include "mozilla/scache/StartupCacheUtils.h"
using namespace mozilla::scache;
using namespace JS;
using namespace xpc;
class MOZ_STACK_CLASS LoadSubScriptOptions : public OptionsBase {
public:
LoadSubScriptOptions(JSContext *cx = xpc_GetSafeJSContext(),
JSObject *options = nullptr)
: OptionsBase(cx, options)
, target(cx)
, charset(NullString())
, ignoreCache(false)
{ }
virtual bool Parse() {
return ParseObject("target", &target) &&
ParseString("charset", charset) &&
ParseBoolean("ignoreCache", &ignoreCache);
}
RootedObject target;
nsString charset;
bool ignoreCache;
};
/* load() error msgs, XXX localize? */
#define LOAD_ERROR_NOSERVICE "Error creating IO Service."
@ -172,10 +196,34 @@ mozJSSubScriptLoader::LoadSubScript(const nsAString& url,
* synchronously.
* target_obj: Optional object to eval the script onto (defaults to context
* global)
* charset: Optional character set to use for reading
* returns: Whatever jsval the script pointed to by the url returns.
* Should ONLY (O N L Y !) be called from JavaScript code.
*/
LoadSubScriptOptions options(cx);
options.charset = charset;
options.target = targetArg.isObject() ? &targetArg.toObject() : nullptr;
return DoLoadSubScriptWithOptions(url, options, cx, retval);
}
NS_IMETHODIMP
mozJSSubScriptLoader::LoadSubScriptWithOptions(const nsAString& url, const Value& optionsVal,
JSContext* cx, Value* retval)
{
if (!optionsVal.isObject())
return NS_ERROR_INVALID_ARG;
LoadSubScriptOptions options(cx, &optionsVal.toObject());
if (!options.Parse())
return NS_ERROR_INVALID_ARG;
return DoLoadSubScriptWithOptions(url, options, cx, retval);
}
nsresult
mozJSSubScriptLoader::DoLoadSubScriptWithOptions(const nsAString& url,
LoadSubScriptOptions& options,
JSContext* cx, Value* retval)
{
nsresult rv = NS_OK;
/* set the system principal if it's not here already */
@ -195,17 +243,12 @@ mozJSSubScriptLoader::LoadSubScript(const nsAString& url,
rv = loader->FindTargetObject(cx, &targetObj);
NS_ENSURE_SUCCESS(rv, rv);
bool reusingGlobal = !JS_IsGlobalObject(targetObj);
// We base reusingGlobal off of what the loader told us, but we may not
// actually be using that object.
RootedValue target(cx, targetArg);
RootedObject passedObj(cx);
if (!JS_ValueToObject(cx, target, &passedObj))
return NS_ERROR_ILLEGAL_VALUE;
bool reusingGlobal = !JS_IsGlobalObject(targetObj);
if (passedObj)
targetObj = passedObj;
if (options.target)
targetObj = options.target;
// Remember an object out of the calling compartment so that we
// can properly wrap the result later.
@ -292,10 +335,10 @@ mozJSSubScriptLoader::LoadSubScript(const nsAString& url,
RootedFunction function(cx);
script = nullptr;
if (cache)
if (cache && !options.ignoreCache)
rv = ReadCachedScript(cache, cachePath, cx, mSystemPrincipal, &script);
if (!script) {
rv = ReadScript(uri, cx, targetObj, charset,
rv = ReadScript(uri, cx, targetObj, options.charset,
static_cast<const char*>(uriStr.get()), serv,
principal, reusingGlobal, script.address(), function.address());
writeScript = !!script;

View File

@ -9,6 +9,7 @@
class nsIPrincipal;
class nsIURI;
class LoadSubScriptOptions;
#define MOZ_JSSUBSCRIPTLOADER_CID \
{ /* 829814d6-1dd2-11b2-8e08-82fa0a339b00 */ \
@ -37,5 +38,9 @@ private:
bool reuseGlobal, JSScript **scriptp,
JSFunction **functionp);
nsresult DoLoadSubScriptWithOptions(const nsAString& url,
LoadSubScriptOptions& options,
JSContext* cx, JS::Value* retval);
nsCOMPtr<nsIPrincipal> mSystemPrincipal;
};

View File

@ -1277,7 +1277,7 @@ GetExpandedPrincipal(JSContext *cx, HandleObject arrayObj, nsIExpandedPrincipal
}
/*
* Helper that tries to get a property form the options object.
* Helper that tries to get a property from the options object.
*/
bool
OptionsBase::ParseValue(const char *name, MutableHandleValue prop, bool *aFound)
@ -1296,7 +1296,7 @@ OptionsBase::ParseValue(const char *name, MutableHandleValue prop, bool *aFound)
}
/*
* Helper that tries to get a boolean property form the options object.
* Helper that tries to get a boolean property from the options object.
*/
bool
OptionsBase::ParseBoolean(const char *name, bool *prop)
@ -1320,7 +1320,7 @@ OptionsBase::ParseBoolean(const char *name, bool *prop)
}
/*
* Helper that tries to get an object property form the options object.
* Helper that tries to get an object property from the options object.
*/
bool
OptionsBase::ParseObject(const char *name, MutableHandleObject prop)
@ -1342,7 +1342,7 @@ OptionsBase::ParseObject(const char *name, MutableHandleObject prop)
}
/*
* Helper that tries to get a string property form the options object.
* Helper that tries to get a string property from the options object.
*/
bool
OptionsBase::ParseString(const char *name, nsCString &prop)
@ -1367,7 +1367,32 @@ OptionsBase::ParseString(const char *name, nsCString &prop)
}
/*
* Helper that tries to get jsid property form the options object.
* Helper that tries to get a string property from the options object.
*/
bool
OptionsBase::ParseString(const char *name, nsString &prop)
{
RootedValue value(mCx);
bool found;
bool ok = ParseValue(name, &value, &found);
NS_ENSURE_TRUE(ok, false);
if (!found)
return true;
if (!value.isString()) {
JS_ReportError(mCx, "Expected a string value for property %s", name);
return false;
}
nsDependentJSString strVal;
strVal.init(mCx, value.toString());
prop = strVal;
return true;
}
/*
* Helper that tries to get jsid property from the options object.
*/
bool
OptionsBase::ParseId(const char *name, MutableHandleId prop)

View File

@ -3620,7 +3620,7 @@ IsSandbox(JSObject *obj);
class MOZ_STACK_CLASS OptionsBase {
public:
OptionsBase(JSContext *cx = xpc_GetSafeJSContext(),
JS::HandleObject options = JS::NullPtr())
JSObject *options = nullptr)
: mCx(cx)
, mObject(cx, options)
{ }
@ -3632,6 +3632,7 @@ protected:
bool ParseBoolean(const char *name, bool *prop);
bool ParseObject(const char *name, JS::MutableHandleObject prop);
bool ParseString(const char *name, nsCString &prop);
bool ParseString(const char *name, nsString &prop);
bool ParseId(const char* name, JS::MutableHandleId id);
JSContext *mCx;
@ -3641,7 +3642,7 @@ protected:
class MOZ_STACK_CLASS SandboxOptions : public OptionsBase {
public:
SandboxOptions(JSContext *cx = xpc_GetSafeJSContext(),
JS::HandleObject options = JS::NullPtr())
JSObject *options = nullptr)
: OptionsBase(cx, options)
, wantXrays(true)
, wantComponents(true)
@ -3669,7 +3670,7 @@ protected:
class MOZ_STACK_CLASS CreateObjectInOptions : public OptionsBase {
public:
CreateObjectInOptions(JSContext *cx = xpc_GetSafeJSContext(),
JS::HandleObject options = JS::NullPtr())
JSObject* options = nullptr)
: OptionsBase(cx, options)
, defineAs(cx, JSID_VOID)
{ }

View File

@ -51,6 +51,12 @@ isnot(src.indexOf("return"), -1, "subscript of a subscript should have source");
ns = {};
Services.scriptloader.loadSubScript(resolvedBase + "utf8_subscript.js", ns, "UTF-8");
src = ns.f.toSource();
isnot(src.indexOf("return 42;"), -1, "encoded subscript should have correct source");
ns = {};
Services.scriptloader.loadSubScriptWithOptions(resolvedBase + "utf8_subscript.js",
{target: ns, charset: "UTF-8", ignoreCache: true});
src = ns.f.toSource();
isnot(src.indexOf("return 42;"), -1, "encoded subscript should have correct source");
]]></script>
</window>