mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-28 07:13:20 +00:00
Bug 1290021 - Implement a prototype version of Houdini "Worklets Level 1" spec - part 4 - cache for the imports, r=smaug
--HG-- rename : dom/worklet/tests/file_basic.html => dom/worklet/tests/file_import_with_cache.html rename : dom/worklet/tests/test_basic.html => dom/worklet/tests/test_import_with_cache.html
This commit is contained in:
parent
f8cf3b6565
commit
1c9916b76f
@ -21,7 +21,8 @@
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
namespace {
|
||||
// ---------------------------------------------------------------------------
|
||||
// WorkletFetchHandler
|
||||
|
||||
class WorkletFetchHandler : public PromiseNativeHandler
|
||||
, public nsIStreamLoaderObserver
|
||||
@ -32,6 +33,8 @@ public:
|
||||
static already_AddRefed<Promise>
|
||||
Fetch(Worklet* aWorklet, const nsAString& aModuleURL, ErrorResult& aRv)
|
||||
{
|
||||
MOZ_ASSERT(aWorklet);
|
||||
|
||||
nsCOMPtr<nsIGlobalObject> global =
|
||||
do_QueryInterface(aWorklet->GetParentObject());
|
||||
MOZ_ASSERT(global);
|
||||
@ -41,6 +44,40 @@ public:
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsPIDOMWindowInner> window = aWorklet->GetParentObject();
|
||||
MOZ_ASSERT(window);
|
||||
|
||||
nsCOMPtr<nsIDocument> doc;
|
||||
doc = window->GetExtantDoc();
|
||||
if (!doc) {
|
||||
promise->MaybeReject(NS_ERROR_FAILURE);
|
||||
return promise.forget();
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIURI> baseURI = doc->GetBaseURI();
|
||||
nsCOMPtr<nsIURI> resolvedURI;
|
||||
nsresult rv = NS_NewURI(getter_AddRefs(resolvedURI), aModuleURL, nullptr, baseURI);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
promise->MaybeReject(rv);
|
||||
return promise.forget();
|
||||
}
|
||||
|
||||
nsAutoCString spec;
|
||||
rv = resolvedURI->GetSpec(spec);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
promise->MaybeReject(rv);
|
||||
return promise.forget();
|
||||
}
|
||||
|
||||
// Maybe we already have an handler for this URI
|
||||
{
|
||||
WorkletFetchHandler* handler = aWorklet->GetImportFetchHandler(spec);
|
||||
if (handler) {
|
||||
handler->AddPromise(promise);
|
||||
return promise.forget();
|
||||
}
|
||||
}
|
||||
|
||||
RequestOrUSVString request;
|
||||
request.SetAsUSVString().Rebind(aModuleURL.Data(), aModuleURL.Length());
|
||||
|
||||
@ -56,6 +93,7 @@ public:
|
||||
new WorkletFetchHandler(aWorklet, aModuleURL, promise);
|
||||
fetchPromise->AppendNativeHandler(handler);
|
||||
|
||||
aWorklet->AddImportFetchHandler(spec, handler);
|
||||
return promise.forget();
|
||||
}
|
||||
|
||||
@ -63,46 +101,46 @@ public:
|
||||
ResolvedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue) override
|
||||
{
|
||||
if (!aValue.isObject()) {
|
||||
mPromise->MaybeReject(NS_ERROR_FAILURE);
|
||||
RejectPromises(NS_ERROR_FAILURE);
|
||||
return;
|
||||
}
|
||||
|
||||
RefPtr<Response> response;
|
||||
nsresult rv = UNWRAP_OBJECT(Response, &aValue.toObject(), response);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
mPromise->MaybeReject(rv);
|
||||
RejectPromises(NS_ERROR_FAILURE);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!response->Ok()) {
|
||||
mPromise->MaybeReject(NS_ERROR_DOM_NETWORK_ERR);
|
||||
RejectPromises(NS_ERROR_DOM_NETWORK_ERR);
|
||||
return;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIInputStream> inputStream;
|
||||
response->GetBody(getter_AddRefs(inputStream));
|
||||
if (!inputStream) {
|
||||
mPromise->MaybeReject(NS_ERROR_DOM_NETWORK_ERR);
|
||||
RejectPromises(NS_ERROR_DOM_NETWORK_ERR);
|
||||
return;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIInputStreamPump> pump;
|
||||
rv = NS_NewInputStreamPump(getter_AddRefs(pump), inputStream);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
mPromise->MaybeReject(rv);
|
||||
RejectPromises(rv);
|
||||
return;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIStreamLoader> loader;
|
||||
rv = NS_NewStreamLoader(getter_AddRefs(loader), this);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
mPromise->MaybeReject(rv);
|
||||
RejectPromises(rv);
|
||||
return;
|
||||
}
|
||||
|
||||
rv = pump->AsyncRead(loader, nullptr);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
mPromise->MaybeReject(rv);
|
||||
RejectPromises(rv);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -125,7 +163,7 @@ public:
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
if (NS_FAILED(aStatus)) {
|
||||
mPromise->MaybeReject(aStatus);
|
||||
RejectPromises(aStatus);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -136,7 +174,7 @@ public:
|
||||
NS_LITERAL_STRING("UTF-8"), nullptr,
|
||||
scriptTextBuf, scriptTextLength);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
mPromise->MaybeReject(rv);
|
||||
RejectPromises(rv);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -172,41 +210,107 @@ public:
|
||||
if (!JS::Evaluate(cx, compileOptions, buffer, &unused)) {
|
||||
ErrorResult error;
|
||||
error.StealExceptionFromJSContext(cx);
|
||||
mPromise->MaybeReject(error);
|
||||
RejectPromises(error.StealNSResult());
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// All done.
|
||||
mPromise->MaybeResolveWithUndefined();
|
||||
ResolvePromises();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
virtual void
|
||||
RejectedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue) override
|
||||
{
|
||||
mPromise->MaybeReject(aCx, aValue);
|
||||
RejectPromises(NS_ERROR_DOM_NETWORK_ERR);
|
||||
}
|
||||
|
||||
private:
|
||||
WorkletFetchHandler(Worklet* aWorklet, const nsAString& aURL,
|
||||
Promise* aPromise)
|
||||
: mWorklet(aWorklet)
|
||||
, mPromise(aPromise)
|
||||
, mStatus(ePending)
|
||||
, mErrorStatus(NS_OK)
|
||||
, mURL(aURL)
|
||||
{}
|
||||
{
|
||||
MOZ_ASSERT(aWorklet);
|
||||
MOZ_ASSERT(aPromise);
|
||||
|
||||
mPromises.AppendElement(aPromise);
|
||||
}
|
||||
|
||||
~WorkletFetchHandler()
|
||||
{}
|
||||
|
||||
void
|
||||
AddPromise(Promise* aPromise)
|
||||
{
|
||||
MOZ_ASSERT(aPromise);
|
||||
|
||||
switch (mStatus) {
|
||||
case ePending:
|
||||
mPromises.AppendElement(aPromise);
|
||||
return;
|
||||
|
||||
case eRejected:
|
||||
MOZ_ASSERT(NS_FAILED(mErrorStatus));
|
||||
aPromise->MaybeReject(mErrorStatus);
|
||||
return;
|
||||
|
||||
case eResolved:
|
||||
aPromise->MaybeResolveWithUndefined();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
RejectPromises(nsresult aResult)
|
||||
{
|
||||
MOZ_ASSERT(mStatus == ePending);
|
||||
MOZ_ASSERT(NS_FAILED(aResult));
|
||||
|
||||
for (uint32_t i = 0; i < mPromises.Length(); ++i) {
|
||||
mPromises[i]->MaybeReject(aResult);
|
||||
}
|
||||
mPromises.Clear();
|
||||
|
||||
mStatus = eRejected;
|
||||
mErrorStatus = aResult;
|
||||
mWorklet = nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
ResolvePromises()
|
||||
{
|
||||
MOZ_ASSERT(mStatus == ePending);
|
||||
|
||||
for (uint32_t i = 0; i < mPromises.Length(); ++i) {
|
||||
mPromises[i]->MaybeResolveWithUndefined();
|
||||
}
|
||||
mPromises.Clear();
|
||||
|
||||
mStatus = eResolved;
|
||||
mWorklet = nullptr;
|
||||
}
|
||||
|
||||
RefPtr<Worklet> mWorklet;
|
||||
RefPtr<Promise> mPromise;
|
||||
nsTArray<RefPtr<Promise>> mPromises;
|
||||
|
||||
enum {
|
||||
ePending,
|
||||
eRejected,
|
||||
eResolved
|
||||
} mStatus;
|
||||
|
||||
nsresult mErrorStatus;
|
||||
|
||||
nsString mURL;
|
||||
};
|
||||
|
||||
NS_IMPL_ISUPPORTS(WorkletFetchHandler, nsIStreamLoaderObserver)
|
||||
|
||||
} // anonymous namespace
|
||||
// ---------------------------------------------------------------------------
|
||||
// Worklet
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(Worklet, mWindow, mScope)
|
||||
NS_IMPL_CYCLE_COLLECTING_ADDREF(Worklet)
|
||||
@ -263,5 +367,21 @@ Worklet::GetOrCreateGlobalScope(JSContext* aCx)
|
||||
return mScope;
|
||||
}
|
||||
|
||||
WorkletFetchHandler*
|
||||
Worklet::GetImportFetchHandler(const nsACString& aURI)
|
||||
{
|
||||
return mImportHandlers.GetWeak(aURI);
|
||||
}
|
||||
|
||||
void
|
||||
Worklet::AddImportFetchHandler(const nsACString& aURI,
|
||||
WorkletFetchHandler* aHandler)
|
||||
{
|
||||
MOZ_ASSERT(aHandler);
|
||||
MOZ_ASSERT(!mImportHandlers.GetWeak(aURI));
|
||||
|
||||
mImportHandlers.Put(aURI, aHandler);
|
||||
}
|
||||
|
||||
} // dom namespace
|
||||
} // mozilla namespace
|
||||
|
@ -9,6 +9,7 @@
|
||||
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/ErrorResult.h"
|
||||
#include "nsRefPtrHashtable.h"
|
||||
#include "nsWrapperCache.h"
|
||||
#include "nsCOMPtr.h"
|
||||
|
||||
@ -20,6 +21,7 @@ namespace dom {
|
||||
|
||||
class Promise;
|
||||
class WorkletGlobalScope;
|
||||
class WorkletFetchHandler;
|
||||
|
||||
class Worklet final : public nsISupports
|
||||
, public nsWrapperCache
|
||||
@ -47,10 +49,19 @@ public:
|
||||
private:
|
||||
~Worklet();
|
||||
|
||||
WorkletFetchHandler*
|
||||
GetImportFetchHandler(const nsACString& aURI);
|
||||
|
||||
void
|
||||
AddImportFetchHandler(const nsACString& aURI, WorkletFetchHandler* aHandler);
|
||||
|
||||
nsCOMPtr<nsPIDOMWindowInner> mWindow;
|
||||
nsCOMPtr<nsIPrincipal> mPrincipal;
|
||||
|
||||
RefPtr<WorkletGlobalScope> mScope;
|
||||
nsRefPtrHashtable<nsCStringHashKey, WorkletFetchHandler> mImportHandlers;
|
||||
|
||||
friend class WorkletFetchHandler;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
|
@ -13,10 +13,21 @@ setupTest();
|
||||
var worklet = window.createWorklet();
|
||||
ok(!!worklet, "We have a Worklet");
|
||||
|
||||
// First loading
|
||||
worklet.import("common.js")
|
||||
.then(() => {
|
||||
ok(true, "Import should load a resource.");
|
||||
})
|
||||
|
||||
// Second loading - same file
|
||||
.then(() => {
|
||||
return worklet.import("common.js")
|
||||
})
|
||||
.then(() => {
|
||||
ok(true, "Import should load a resource.");
|
||||
})
|
||||
|
||||
// 3rd loading - a network error
|
||||
.then(() => {
|
||||
return worklet.import("404.js");
|
||||
})
|
||||
@ -24,7 +35,20 @@ worklet.import("common.js")
|
||||
ok(false, "The loading should fail.");
|
||||
}, () => {
|
||||
ok(true, "The loading should fail.");
|
||||
}).then(() => {
|
||||
})
|
||||
|
||||
// 4th loading - a network error
|
||||
.then(() => {
|
||||
return worklet.import("404.js");
|
||||
})
|
||||
.then(() => {
|
||||
ok(false, "The loading should fail.");
|
||||
}, () => {
|
||||
ok(true, "The loading should fail.");
|
||||
})
|
||||
|
||||
// done
|
||||
.then(() => {
|
||||
SimpleTest.finish();
|
||||
});
|
||||
|
||||
|
43
dom/worklet/tests/file_import_with_cache.html
Normal file
43
dom/worklet/tests/file_import_with_cache.html
Normal file
@ -0,0 +1,43 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Test for Worklet</title>
|
||||
<script type="application/javascript" src="common.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<script type="application/javascript">
|
||||
|
||||
setupTest();
|
||||
|
||||
var worklet = window.createWorklet();
|
||||
ok(!!worklet, "We have a Worklet");
|
||||
|
||||
function loading() {
|
||||
worklet.import("server_import_with_cache.sjs")
|
||||
.then(() => {
|
||||
ok(true, "Import should load a resource.");
|
||||
}, () => {
|
||||
ok(false, "Import should load a resource.");
|
||||
})
|
||||
.then(() => {
|
||||
done();
|
||||
});
|
||||
}
|
||||
|
||||
var count = 0;
|
||||
const MAX = 10;
|
||||
|
||||
function done() {
|
||||
if (++count == MAX) {
|
||||
SimpleTest.finish();
|
||||
}
|
||||
}
|
||||
|
||||
for (var i = 0; i < MAX; ++i) {
|
||||
loading();
|
||||
}
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
@ -6,3 +6,5 @@ support-files =
|
||||
support-files=file_basic.html
|
||||
[test_console.html]
|
||||
support-files=file_console.html worklet_console.js
|
||||
[test_import_with_cache.html]
|
||||
support-files=file_import_with_cache.html server_import_with_cache.sjs
|
||||
|
13
dom/worklet/tests/server_import_with_cache.sjs
Normal file
13
dom/worklet/tests/server_import_with_cache.sjs
Normal file
@ -0,0 +1,13 @@
|
||||
function handleRequest(request, response)
|
||||
{
|
||||
response.setHeader("Content-Type", "text/javascript", false);
|
||||
|
||||
var state = getState("alreadySent");
|
||||
if (!state) {
|
||||
setState("alreadySent", "1");
|
||||
} else {
|
||||
response.setStatusLine('1.1', 404, "Not Found");
|
||||
}
|
||||
|
||||
response.write("42");
|
||||
}
|
21
dom/worklet/tests/test_import_with_cache.html
Normal file
21
dom/worklet/tests/test_import_with_cache.html
Normal file
@ -0,0 +1,21 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Test for Worklet</title>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
<script type="application/javascript" src="common.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<script type="application/javascript">
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
SpecialPowers.pushPrefEnv(
|
||||
{"set": [["dom.worklet.testing.enabled", true],
|
||||
["dom.worklet.enabled", true]]},
|
||||
function() { loadTest("file_import_with_cache.html"); });
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
Loading…
Reference in New Issue
Block a user