summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNew Tobin Paradigm <email@mattatobin.com>2018-04-12 10:49:23 -0400
committerGitHub <noreply@github.com>2018-04-12 10:49:23 -0400
commit4c2e77404f43040ce7a9f0d9052448b3f23a8c28 (patch)
treed7161a645a98f38dd18797cc80581446929f99c7
parenta0968fc6a86c8ab1abfa83d3c1986fadf3ec2766 (diff)
parent9f7f0f1172d67ab29e4f72eb1b34ab6f4bb231b1 (diff)
downloadUXP-4c2e77404f43040ce7a9f0d9052448b3f23a8c28.tar
UXP-4c2e77404f43040ce7a9f0d9052448b3f23a8c28.tar.gz
UXP-4c2e77404f43040ce7a9f0d9052448b3f23a8c28.tar.lz
UXP-4c2e77404f43040ce7a9f0d9052448b3f23a8c28.tar.xz
UXP-4c2e77404f43040ce7a9f0d9052448b3f23a8c28.zip
Merge pull request #126 from janekptacijarabaci/js_X-Content-Type-Options_nosniff_json_1
Align XCTO: nosniff allowed script MIME types with the spec
-rw-r--r--dom/base/nsContentUtils.cpp20
-rw-r--r--dom/base/nsContentUtils.h7
-rwxr-xr-xdom/events/Event.cpp15
-rwxr-xr-xdom/events/Event.h4
-rw-r--r--dom/security/test/csp/file_child-src_worker-redirect.html7
-rw-r--r--dom/security/test/general/test_block_script_wrong_mime.html6
-rw-r--r--dom/workers/WorkerPrivate.cpp133
-rw-r--r--dom/workers/WorkerPrivate.h3
-rw-r--r--dom/workers/test/test_404.html1
-rw-r--r--dom/workers/test/test_bug1036484.html1
-rw-r--r--dom/workers/test/test_loadError.html8
-rw-r--r--netwerk/protocol/http/nsHttpChannel.cpp2
-rw-r--r--testing/web-platform/meta/fetch/nosniff/worker.html.ini3
-rw-r--r--testing/web-platform/tests/fetch/nosniff/script.html4
-rw-r--r--testing/web-platform/tests/workers/Worker_cross_origin_security_err.htm2
-rw-r--r--testing/web-platform/tests/workers/constructors/SharedWorker/same-origin.html2
-rw-r--r--testing/web-platform/tests/workers/constructors/Worker/same-origin.html2
17 files changed, 149 insertions, 71 deletions
diff --git a/dom/base/nsContentUtils.cpp b/dom/base/nsContentUtils.cpp
index 02c6bf1de..ef87a250e 100644
--- a/dom/base/nsContentUtils.cpp
+++ b/dom/base/nsContentUtils.cpp
@@ -3717,11 +3717,15 @@ nsContentUtils::IsChildOfSameType(nsIDocument* aDoc)
}
bool
-nsContentUtils::IsScriptType(const nsACString& aContentType)
+nsContentUtils::IsPlainTextType(const nsACString& aContentType)
{
// NOTE: if you add a type here, add it to the CONTENTDLF_CATEGORIES
// define in nsContentDLF.h as well.
- return aContentType.EqualsLiteral(APPLICATION_JAVASCRIPT) ||
+ return aContentType.EqualsLiteral(TEXT_PLAIN) ||
+ aContentType.EqualsLiteral(TEXT_CSS) ||
+ aContentType.EqualsLiteral(TEXT_CACHE_MANIFEST) ||
+ aContentType.EqualsLiteral(TEXT_VTT) ||
+ aContentType.EqualsLiteral(APPLICATION_JAVASCRIPT) ||
aContentType.EqualsLiteral(APPLICATION_XJAVASCRIPT) ||
aContentType.EqualsLiteral(TEXT_ECMASCRIPT) ||
aContentType.EqualsLiteral(APPLICATION_ECMASCRIPT) ||
@@ -3731,18 +3735,6 @@ nsContentUtils::IsScriptType(const nsACString& aContentType)
}
bool
-nsContentUtils::IsPlainTextType(const nsACString& aContentType)
-{
- // NOTE: if you add a type here, add it to the CONTENTDLF_CATEGORIES
- // define in nsContentDLF.h as well.
- return aContentType.EqualsLiteral(TEXT_PLAIN) ||
- aContentType.EqualsLiteral(TEXT_CSS) ||
- aContentType.EqualsLiteral(TEXT_CACHE_MANIFEST) ||
- aContentType.EqualsLiteral(TEXT_VTT) ||
- IsScriptType(aContentType);
-}
-
-bool
nsContentUtils::GetWrapperSafeScriptFilename(nsIDocument* aDocument,
nsIURI* aURI,
nsACString& aScriptURI,
diff --git a/dom/base/nsContentUtils.h b/dom/base/nsContentUtils.h
index 0a293d73e..0932f451e 100644
--- a/dom/base/nsContentUtils.h
+++ b/dom/base/nsContentUtils.h
@@ -1018,12 +1018,7 @@ public:
static bool IsChildOfSameType(nsIDocument* aDoc);
/**
- '* Returns true if the content-type is any of the supported script types.
- */
- static bool IsScriptType(const nsACString& aContentType);
-
- /**
- '* Returns true if the content-type will be rendered as plain-text.
+ * Returns true if the content-type will be rendered as plain-text.
*/
static bool IsPlainTextType(const nsACString& aContentType);
diff --git a/dom/events/Event.cpp b/dom/events/Event.cpp
index 2af34136e..2546a81ad 100755
--- a/dom/events/Event.cpp
+++ b/dom/events/Event.cpp
@@ -412,8 +412,17 @@ Event::Constructor(const GlobalObject& aGlobal,
ErrorResult& aRv)
{
nsCOMPtr<mozilla::dom::EventTarget> t = do_QueryInterface(aGlobal.GetAsSupports());
- RefPtr<Event> e = new Event(t, nullptr, nullptr);
- bool trusted = e->Init(t);
+ return Constructor(t, aType, aParam);
+}
+
+// static
+already_AddRefed<Event>
+Event::Constructor(EventTarget* aEventTarget,
+ const nsAString& aType,
+ const EventInit& aParam)
+{
+ RefPtr<Event> e = new Event(aEventTarget, nullptr, nullptr);
+ bool trusted = e->Init(aEventTarget);
e->InitEvent(aType, aParam.mBubbles, aParam.mCancelable);
e->SetTrusted(trusted);
e->SetComposed(aParam.mComposed);
@@ -1209,7 +1218,7 @@ Event::Deserialize(const IPC::Message* aMsg, PickleIterator* aIter)
}
NS_IMETHODIMP_(void)
-Event::SetOwner(mozilla::dom::EventTarget* aOwner)
+Event::SetOwner(EventTarget* aOwner)
{
mOwner = nullptr;
diff --git a/dom/events/Event.h b/dom/events/Event.h
index c28226e8a..0817aa809 100755
--- a/dom/events/Event.h
+++ b/dom/events/Event.h
@@ -142,6 +142,10 @@ public:
LayoutDeviceIntPoint aPoint,
CSSIntPoint aDefaultPoint);
+ static already_AddRefed<Event> Constructor(EventTarget* aEventTarget,
+ const nsAString& aType,
+ const EventInit& aParam);
+
static already_AddRefed<Event> Constructor(const GlobalObject& aGlobal,
const nsAString& aType,
const EventInit& aParam,
diff --git a/dom/security/test/csp/file_child-src_worker-redirect.html b/dom/security/test/csp/file_child-src_worker-redirect.html
index 188f173b8..b0029935c 100644
--- a/dom/security/test/csp/file_child-src_worker-redirect.html
+++ b/dom/security/test/csp/file_child-src_worker-redirect.html
@@ -23,11 +23,8 @@
);
worker.onerror = function(error) {
- var msg = error.message;
- if (msg.match(/^NetworkError/) || msg.match(/Failed to load worker script/)) {
- // this means CSP blocked it
- msg = "blocked";
- }
+ // this means CSP blocked it
+ var msg = !("message" in error) ? "blocked" : e.message;
window.parent.postMessage({id:page_id, message:msg}, 'http://mochi.test:8888');
error.preventDefault();
};
diff --git a/dom/security/test/general/test_block_script_wrong_mime.html b/dom/security/test/general/test_block_script_wrong_mime.html
index f4da9c577..34d4b621b 100644
--- a/dom/security/test/general/test_block_script_wrong_mime.html
+++ b/dom/security/test/general/test_block_script_wrong_mime.html
@@ -53,9 +53,6 @@ function testWorker([mime, shouldLoad]) {
};
worker.onerror = (error) => {
ok(!shouldLoad, `worker with wrong mime '${mime}' should be blocked`);
- let msg = error.message;
- ok(msg.match(/^NetworkError/) || msg.match(/Failed to load worker script/),
- "should gets correct error message");
error.preventDefault();
resolve();
}
@@ -74,9 +71,6 @@ function testWorkerImportScripts([mime, shouldLoad]) {
};
worker.onerror = (error) => {
ok(!shouldLoad, `worker/importScripts with wrong mime '${mime}' should be blocked`);
- let msg = error.message;
- ok(msg.match(/^NetworkError/) || msg.match(/Failed to load worker script/),
- "should gets correct error message");
error.preventDefault();
resolve();
}
diff --git a/dom/workers/WorkerPrivate.cpp b/dom/workers/WorkerPrivate.cpp
index c2ab4aca3..bd8a33032 100644
--- a/dom/workers/WorkerPrivate.cpp
+++ b/dom/workers/WorkerPrivate.cpp
@@ -495,6 +495,82 @@ private:
}
};
+class ReportCompileErrorRunnable final : public WorkerRunnable
+{
+public:
+ static void
+ CreateAndDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate)
+ {
+ MOZ_ASSERT(aWorkerPrivate);
+ aWorkerPrivate->AssertIsOnWorkerThread();
+
+ RefPtr<ReportCompileErrorRunnable> runnable =
+ new ReportCompileErrorRunnable(aCx, aWorkerPrivate);
+ runnable->Dispatch();
+ }
+
+private:
+ ReportCompileErrorRunnable(JSContext* aCx, WorkerPrivate* aWorkerPrivate)
+ : WorkerRunnable(aWorkerPrivate, ParentThreadUnchangedBusyCount)
+ {
+ aWorkerPrivate->AssertIsOnWorkerThread();
+ }
+
+ void
+ PostDispatch(WorkerPrivate* aWorkerPrivate, bool aDispatchResult) override
+ {
+ aWorkerPrivate->AssertIsOnWorkerThread();
+
+ // Dispatch may fail if the worker was canceled, no need to report that as
+ // an error, so don't call base class PostDispatch.
+ }
+
+ bool
+ WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override
+ {
+ if (aWorkerPrivate->IsFrozen() ||
+ aWorkerPrivate->IsParentWindowPaused()) {
+ MOZ_ASSERT(!IsDebuggerRunnable());
+ aWorkerPrivate->QueueRunnable(this);
+ return true;
+ }
+
+ if (aWorkerPrivate->IsSharedWorker()) {
+ aWorkerPrivate->BroadcastErrorToSharedWorkers(aCx, EmptyString(),
+ EmptyString(),
+ EmptyString(), 0, 0,
+ JSREPORT_ERROR,
+ /* isErrorEvent */ false);
+ return true;
+ }
+
+ if (aWorkerPrivate->IsServiceWorker()) {
+ RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
+ if (swm) {
+ swm->HandleError(aCx, aWorkerPrivate->GetPrincipal(),
+ aWorkerPrivate->WorkerName(),
+ aWorkerPrivate->ScriptURL(),
+ EmptyString(), EmptyString(), EmptyString(),
+ 0, 0, JSREPORT_ERROR, JSEXN_ERR);
+ }
+ return true;
+ }
+
+ if (!aWorkerPrivate->IsAcceptingEvents()) {
+ return true;
+ }
+
+ RefPtr<Event> event =
+ Event::Constructor(aWorkerPrivate, NS_LITERAL_STRING("error"),
+ EventInit());
+ event->SetTrusted(true);
+
+ nsEventStatus status = nsEventStatus_eIgnore;
+ aWorkerPrivate->DispatchDOMEvent(nullptr, event, nullptr, &status);
+ return true;
+ }
+};
+
class CompileScriptRunnable final : public WorkerRunnable
{
nsString mScriptURL;
@@ -538,9 +614,15 @@ private:
}
// Make sure to propagate exceptions from rv onto aCx, so that they will get
- // reported after we return. We do this for all failures on rv, because now
- // we're using rv to track all the state we care about.
- //
+ // reported after we return. We want to propagate just JS exceptions,
+ // because all the other errors are handled when the script is loaded.
+ // See: https://dom.spec.whatwg.org/#concept-event-fire
+ if (rv.Failed() && !rv.IsJSException()) {
+ ReportCompileErrorRunnable::CreateAndDispatch(aCx, aWorkerPrivate);
+ rv.SuppressException();
+ return false;
+ }
+
// This is a little dumb, but aCx is in the null compartment here because we
// set it up that way in our Run(), since we had not created the global at
// that point yet. So we need to enter the compartment of our global,
@@ -1171,7 +1253,8 @@ private:
if (aWorkerPrivate->IsSharedWorker()) {
aWorkerPrivate->BroadcastErrorToSharedWorkers(aCx, mMessage, mFilename,
mLine, mLineNumber,
- mColumnNumber, mFlags);
+ mColumnNumber, mFlags,
+ /* isErrorEvent */ true);
return true;
}
@@ -3250,7 +3333,8 @@ WorkerPrivateParent<Derived>::BroadcastErrorToSharedWorkers(
const nsAString& aLine,
uint32_t aLineNumber,
uint32_t aColumnNumber,
- uint32_t aFlags)
+ uint32_t aFlags,
+ bool aIsErrorEvent)
{
AssertIsOnMainThread();
@@ -3281,31 +3365,42 @@ WorkerPrivateParent<Derived>::BroadcastErrorToSharedWorkers(
// May be null.
nsPIDOMWindowInner* window = sharedWorker->GetOwner();
- RootedDictionary<ErrorEventInit> errorInit(aCx);
- errorInit.mBubbles = false;
- errorInit.mCancelable = true;
- errorInit.mMessage = aMessage;
- errorInit.mFilename = aFilename;
- errorInit.mLineno = aLineNumber;
- errorInit.mColno = aColumnNumber;
-
- RefPtr<ErrorEvent> errorEvent =
- ErrorEvent::Constructor(sharedWorker, NS_LITERAL_STRING("error"),
- errorInit);
- if (!errorEvent) {
+ RefPtr<Event> event;
+
+ if (aIsErrorEvent) {
+ RootedDictionary<ErrorEventInit> errorInit(aCx);
+ errorInit.mBubbles = false;
+ errorInit.mCancelable = true;
+ errorInit.mMessage = aMessage;
+ errorInit.mFilename = aFilename;
+ errorInit.mLineno = aLineNumber;
+ errorInit.mColno = aColumnNumber;
+
+ event = ErrorEvent::Constructor(sharedWorker, NS_LITERAL_STRING("error"),
+ errorInit);
+ } else {
+ event = Event::Constructor(sharedWorker, NS_LITERAL_STRING("error"),
+ EventInit());
+ }
+
+ if (!event) {
ThrowAndReport(window, NS_ERROR_UNEXPECTED);
continue;
}
- errorEvent->SetTrusted(true);
+ event->SetTrusted(true);
bool defaultActionEnabled;
- nsresult rv = sharedWorker->DispatchEvent(errorEvent, &defaultActionEnabled);
+ nsresult rv = sharedWorker->DispatchEvent(event, &defaultActionEnabled);
if (NS_FAILED(rv)) {
ThrowAndReport(window, rv);
continue;
}
+ if (!aIsErrorEvent) {
+ continue;
+ }
+
if (defaultActionEnabled) {
// Add the owning window to our list so that we will fire an error event
// at it later.
diff --git a/dom/workers/WorkerPrivate.h b/dom/workers/WorkerPrivate.h
index 8008f30e5..465c0f9a3 100644
--- a/dom/workers/WorkerPrivate.h
+++ b/dom/workers/WorkerPrivate.h
@@ -408,7 +408,8 @@ public:
const nsAString& aLine,
uint32_t aLineNumber,
uint32_t aColumnNumber,
- uint32_t aFlags);
+ uint32_t aFlags,
+ bool aIsErrorEvent);
void
WorkerScriptLoaded();
diff --git a/dom/workers/test/test_404.html b/dom/workers/test/test_404.html
index e2e83a35e..15e5ded68 100644
--- a/dom/workers/test/test_404.html
+++ b/dom/workers/test/test_404.html
@@ -25,7 +25,6 @@ Tests of DOM Worker Threads
worker.onerror = function(event) {
is(event.target, worker);
- is(event.message, 'NetworkError: Failed to load worker script at "nonexistent_worker.js"');
event.preventDefault();
SimpleTest.finish();
};
diff --git a/dom/workers/test/test_bug1036484.html b/dom/workers/test/test_bug1036484.html
index 17b9d490f..49c31bbc9 100644
--- a/dom/workers/test/test_bug1036484.html
+++ b/dom/workers/test/test_bug1036484.html
@@ -25,7 +25,6 @@ function test(script) {
worker.onerror = function(event) {
is(event.target, worker);
- ok(event.message.startsWith("NetworkError: Failed to load worker script"))
event.preventDefault();
runTests();
};
diff --git a/dom/workers/test/test_loadError.html b/dom/workers/test/test_loadError.html
index dc109b796..b9a215d11 100644
--- a/dom/workers/test/test_loadError.html
+++ b/dom/workers/test/test_loadError.html
@@ -13,15 +13,13 @@
<script class="testbody" type="text/javascript">
"use strict";
-var loadErrorMessage = 'SecurityError: Failed to load worker script at "about:blank"';
-
function nextTest() {
(function(){
function workerfunc() {
var subworker = new Worker("about:blank");
subworker.onerror = function(e) {
e.preventDefault();
- postMessage(e.message);
+ postMessage("ERROR");
}
}
var b = new Blob([workerfunc+'workerfunc();']);
@@ -37,7 +35,7 @@ function nextTest() {
return;
}
w.onmessage = function(e) {
- is(e.data, loadErrorMessage,
+ is(e.data, "ERROR",
"Should catch the error when loading inner script");
if (++i < 2) callworker(i);
else SimpleTest.finish();
@@ -54,8 +52,6 @@ try {
var worker = new Worker("about:blank");
worker.onerror = function(e) {
e.preventDefault();
- is(e.message, loadErrorMessage,
- "Should get the right error from the toplevel script");
nextTest();
}
diff --git a/netwerk/protocol/http/nsHttpChannel.cpp b/netwerk/protocol/http/nsHttpChannel.cpp
index ce0f45dab..94b0d9bf9 100644
--- a/netwerk/protocol/http/nsHttpChannel.cpp
+++ b/netwerk/protocol/http/nsHttpChannel.cpp
@@ -1152,7 +1152,7 @@ ProcessXCTO(nsIURI* aURI, nsHttpResponseHead* aResponseHead, nsILoadInfo* aLoadI
}
if (aLoadInfo->GetExternalContentPolicyType() == nsIContentPolicy::TYPE_SCRIPT) {
- if (nsContentUtils::IsScriptType(contentType)) {
+ if (nsContentUtils::IsJavascriptMIMEType(NS_ConvertUTF8toUTF16(contentType))) {
return NS_OK;
}
ReportTypeBlocking(aURI, aLoadInfo, "MimeTypeMismatch");
diff --git a/testing/web-platform/meta/fetch/nosniff/worker.html.ini b/testing/web-platform/meta/fetch/nosniff/worker.html.ini
deleted file mode 100644
index 011ad15b8..000000000
--- a/testing/web-platform/meta/fetch/nosniff/worker.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[worker.html]
- type: testharness
- expected: ERROR
diff --git a/testing/web-platform/tests/fetch/nosniff/script.html b/testing/web-platform/tests/fetch/nosniff/script.html
index 667f3c99a..c5c5167f5 100644
--- a/testing/web-platform/tests/fetch/nosniff/script.html
+++ b/testing/web-platform/tests/fetch/nosniff/script.html
@@ -4,8 +4,8 @@
<script>
var log = function() {}, // see comment below
p = function() {}, // see comment below
- fails = ["", "?type=", "?type=x", "?type=x/x"],
- passes = ["?type=text/javascript", "?type=text/ecmascript", "?type=text/ecmascript;blah"]
+ fails = ["", "?type=", "?type=x", "?type=x/x", "?type=text/json"],
+ passes = ["?type=text/javascript", "?type=text/ecmascript", "?type=text/ecmascript;blah", "?type=text/javascript1.0"]
// Ideally we'd also check whether the scripts in fact execute, but that would involve
// timers and might get a bit racy without cross-browser support for the execute events.
diff --git a/testing/web-platform/tests/workers/Worker_cross_origin_security_err.htm b/testing/web-platform/tests/workers/Worker_cross_origin_security_err.htm
index 647a8b81e..d57dc29d5 100644
--- a/testing/web-platform/tests/workers/Worker_cross_origin_security_err.htm
+++ b/testing/web-platform/tests/workers/Worker_cross_origin_security_err.htm
@@ -8,7 +8,7 @@ async_test(function(t) {
try {
var w = new Worker("ftp://example.org/support/WorkerBasic.js");
w.onerror = t.step_func_done(function(e) {
- assert_true(e instanceof ErrorEvent);
+ assert_true(e instanceof Event);
});
} catch (e) {
t.step_func_done(function(e) { assert_true(true); });
diff --git a/testing/web-platform/tests/workers/constructors/SharedWorker/same-origin.html b/testing/web-platform/tests/workers/constructors/SharedWorker/same-origin.html
index 2e0dd8db3..78d53164e 100644
--- a/testing/web-platform/tests/workers/constructors/SharedWorker/same-origin.html
+++ b/testing/web-platform/tests/workers/constructors/SharedWorker/same-origin.html
@@ -16,7 +16,7 @@ function testSharedWorkerHelper(t, script) {
try {
var worker = new SharedWorker(script, '');
worker.onerror = t.step_func_done(function(e) {
- assert_true(e instanceof ErrorEvent);
+ assert_true(e instanceof Event);
});
} catch (e) {
t.step_func_done(function(e) { assert_true(true); });
diff --git a/testing/web-platform/tests/workers/constructors/Worker/same-origin.html b/testing/web-platform/tests/workers/constructors/Worker/same-origin.html
index 9b0148da3..bbc4382d0 100644
--- a/testing/web-platform/tests/workers/constructors/Worker/same-origin.html
+++ b/testing/web-platform/tests/workers/constructors/Worker/same-origin.html
@@ -14,7 +14,7 @@ function testSharedWorkerHelper(t, script) {
try {
var worker = new SharedWorker(script, '');
worker.onerror = t.step_func_done(function(e) {
- assert_true(e instanceof ErrorEvent);
+ assert_true(e instanceof Event);
});
} catch (e) {
t.step_func_done(function(e) { assert_true(true); });