Merge inbound to m-c. a=merge

CLOSED TREE
This commit is contained in:
Ryan VanderMeulen 2014-12-17 20:53:20 -05:00
commit d2ebc2ac1b
186 changed files with 5768 additions and 3362 deletions

View File

@ -5684,9 +5684,11 @@ function handleLinkClick(event, href, linkNode) {
}
urlSecurityCheck(href, doc.nodePrincipal);
openLinkIn(href, where, { referrerURI: referrerURI,
charset: doc.characterSet,
allowMixedContent: persistAllowMixedContentInChildTab });
let params = { charset: doc.characterSet,
allowMixedContent: persistAllowMixedContentInChildTab };
if (!BrowserUtils.linkHasNoReferrer(linkNode))
params.referrerURI = referrerURI;
openLinkIn(href, where, params);
event.preventDefault();
return true;
}

View File

@ -579,6 +579,7 @@ let ClickEventHandler = {
event.preventDefault(); // Need to prevent the pageload.
}
}
json.noReferrer = BrowserUtils.linkHasNoReferrer(node)
}
sendAsyncMessage("Content:Click", json);

View File

@ -5,6 +5,7 @@
Components.utils.import("resource://gre/modules/PrivateBrowsingUtils.jsm");
Components.utils.import("resource://gre/modules/InlineSpellChecker.jsm");
Components.utils.import("resource://gre/modules/BrowserUtils.jsm");
var gContextMenuContentData = null;
@ -857,13 +858,20 @@ nsContextMenu.prototype = {
return aNode.spellcheck;
},
_openLinkInParameters : function (doc, extra) {
let params = { charset: doc.characterSet };
if (!BrowserUtils.linkHasNoReferrer(this.link))
params.referrerURI = document.documentURIObject;
for (let p in extra)
params[p] = extra[p];
return params;
},
// Open linked-to URL in a new window.
openLink : function () {
var doc = this.target.ownerDocument;
urlSecurityCheck(this.linkURL, this._unremotePrincipal(doc.nodePrincipal));
openLinkIn(this.linkURL, "window",
{ charset: doc.characterSet,
referrerURI: doc.documentURIObject });
openLinkIn(this.linkURL, "window", this._openLinkInParameters(doc));
},
// Open linked-to URL in a new private window.
@ -871,9 +879,7 @@ nsContextMenu.prototype = {
var doc = this.target.ownerDocument;
urlSecurityCheck(this.linkURL, this._unremotePrincipal(doc.nodePrincipal));
openLinkIn(this.linkURL, "window",
{ charset: doc.characterSet,
referrerURI: doc.documentURIObject,
private: true });
this._openLinkInParameters(doc, { private: true }));
},
// Open linked-to URL in a new tab.
@ -897,19 +903,17 @@ nsContextMenu.prototype = {
catch (e) { }
}
openLinkIn(this.linkURL, "tab",
{ charset: doc.characterSet,
referrerURI: referrerURI,
allowMixedContent: persistAllowMixedContentInChildTab });
let params = this._openLinkInParameters(doc, {
allowMixedContent: persistAllowMixedContentInChildTab,
});
openLinkIn(this.linkURL, "tab", params);
},
// open URL in current tab
openLinkInCurrent: function() {
var doc = this.target.ownerDocument;
urlSecurityCheck(this.linkURL, this._unremotePrincipal(doc.nodePrincipal));
openLinkIn(this.linkURL, "current",
{ charset: doc.characterSet,
referrerURI: doc.documentURIObject });
openLinkIn(this.linkURL, "current", this._openLinkInParameters(doc));
},
// Open frame in a new tab.

View File

@ -0,0 +1,6 @@
. "$topsrcdir/browser/config/mozconfigs/linux64/nightly"
MOZ_CODE_COVERAGE=1
export CFLAGS="-fprofile-arcs -ftest-coverage"
export CXXFLAGS="-fprofile-arcs -ftest-coverage"
export LDFLAGS="-fprofile-arcs -ftest-coverage -lgcov"

View File

@ -1,3 +1,4 @@
/* -*- mode: js; indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
@ -67,8 +68,10 @@ let ContentClick = {
// Todo(903022): code for where == save
window.openLinkIn(json.href, where, { referrerURI: browser.documentURI,
charset: browser.characterSet });
let params = { charset: browser.characterSet };
if (!json.noReferrer)
params.referrerURI = browser.documentURI;
window.openLinkIn(json.href, where, params);
// Mark the page as a user followed link. This is done so that history can
// distinguish automatic embed visits from user activated ones. For example

View File

@ -96,6 +96,9 @@ if __name__ == '__main__':
parser.add_argument("--upload-output", required=True,
action="store", dest="upload_output",
help="Path to the text output of 'make upload'")
parser.add_argument("--upload-files", required=True, nargs="+",
action="store", dest="upload_files",
help="List of files to be uploaded.")
args = parser.parse_args()
json_data = getMarProperties(args.complete_mar_file)
@ -112,5 +115,7 @@ if __name__ == '__main__':
# useful for balrog.
json_data['partialInfo'] = getPartialInfo(json_data)
json_data['uploadFiles'] = args.upload_files
with open('mach_build_properties.json', 'w') as outfile:
json.dump(json_data, outfile, indent=4)

View File

@ -12,6 +12,10 @@ endif
endif
include $(topsrcdir)/toolkit/mozapps/installer/package-name.mk
include $(topsrcdir)/toolkit/mozapps/installer/upload-files.mk
# Clear out DIST_FILES if it was set by upload-files.mk (for Android builds)
DIST_FILES =
# Log file from the 'make upload' step. We need this to parse out the URLs of
# the uploaded files.
@ -86,7 +90,7 @@ automation/l10n-check: automation/pretty-l10n-check
automation/update-packaging: automation/pretty-update-packaging
automation/build: $(addprefix automation/,$(MOZ_AUTOMATION_TIERS))
$(PYTHON) $(topsrcdir)/build/gen_mach_buildprops.py --complete-mar-file $(DIST)/$(COMPLETE_MAR) $(addprefix --partial-mar-file ,$(wildcard $(DIST)/$(PARTIAL_MAR))) --upload-output $(AUTOMATION_UPLOAD_OUTPUT)
$(PYTHON) $(topsrcdir)/build/gen_mach_buildprops.py --complete-mar-file $(DIST)/$(COMPLETE_MAR) $(addprefix --partial-mar-file ,$(wildcard $(DIST)/$(PARTIAL_MAR))) --upload-output $(AUTOMATION_UPLOAD_OUTPUT) --upload-files $(abspath $(UPLOAD_FILES))
# We need the log from make upload to grep it for urls in order to set
# properties.

View File

@ -494,12 +494,7 @@ case "$target" in
AC_DEFINE(_CRT_SECURE_NO_WARNINGS)
AC_DEFINE(_CRT_NONSTDC_NO_WARNINGS)
if test "$_CC_MAJOR_VERSION" = "16"; then
_CC_SUITE=10
MSVS_VERSION=2010
MSVC_C_RUNTIME_DLL=msvcr100.dll
MSVC_CXX_RUNTIME_DLL=msvcp100.dll
elif test "$_CC_MAJOR_VERSION" = "17"; then
if test "$_CC_MAJOR_VERSION" = "17"; then
_CC_SUITE=11
MSVS_VERSION=2012
MSVC_C_RUNTIME_DLL=msvcr110.dll

View File

@ -304,7 +304,7 @@ FindJSContext(nsIGlobalObject* aGlobalObject)
AutoJSAPI::AutoJSAPI()
: mCx(nullptr)
, mOwnErrorReporting(false)
, mOldDontReportUncaught(false)
, mOldAutoJSAPIOwnsErrorReporting(false)
{
}
@ -312,7 +312,7 @@ AutoJSAPI::~AutoJSAPI()
{
if (mOwnErrorReporting) {
MOZ_ASSERT(NS_IsMainThread(), "See corresponding assertion in TakeOwnershipOfErrorReporting()");
JS::ContextOptionsRef(cx()).setDontReportUncaught(mOldDontReportUncaught);
JS::ContextOptionsRef(cx()).setAutoJSAPIOwnsErrorReporting(mOldAutoJSAPIOwnsErrorReporting);
if (HasException()) {
@ -377,7 +377,7 @@ AutoJSAPI::AutoJSAPI(nsIGlobalObject* aGlobalObject,
bool aIsMainThread,
JSContext* aCx)
: mOwnErrorReporting(false)
, mOldDontReportUncaught(false)
, mOldAutoJSAPIOwnsErrorReporting(false)
{
MOZ_ASSERT(aGlobalObject);
MOZ_ASSERT(aGlobalObject->GetGlobalJSObject(), "Must have a JS global");
@ -472,11 +472,12 @@ AutoJSAPI::InitWithLegacyErrorReporting(nsGlobalWindow* aWindow)
return InitWithLegacyErrorReporting(static_cast<nsIGlobalObject*>(aWindow));
}
// Even with dontReportUncaught, the JS engine still sends warning reports
// to the JSErrorReporter as soon as they are generated. These go directly to
// the console, so we can handle them easily here.
// Even with autoJSAPIOwnsErrorReporting, the JS engine still sends warning
// reports to the JSErrorReporter as soon as they are generated. These go
// directly to the console, so we can handle them easily here.
//
// Eventually, SpiderMonkey will have a special-purpose callback for warnings only.
// Eventually, SpiderMonkey will have a special-purpose callback for warnings
// only.
void
WarningOnlyErrorReporter(JSContext* aCx, const char* aMessage, JSErrorReport* aRep)
{
@ -496,8 +497,8 @@ AutoJSAPI::TakeOwnershipOfErrorReporting()
mOwnErrorReporting = true;
JSRuntime *rt = JS_GetRuntime(cx());
mOldDontReportUncaught = JS::ContextOptionsRef(cx()).dontReportUncaught();
JS::ContextOptionsRef(cx()).setDontReportUncaught(true);
mOldAutoJSAPIOwnsErrorReporting = JS::ContextOptionsRef(cx()).autoJSAPIOwnsErrorReporting();
JS::ContextOptionsRef(cx()).setAutoJSAPIOwnsErrorReporting(true);
JS_SetErrorReporter(rt, WarningOnlyErrorReporter);
}

View File

@ -307,7 +307,7 @@ private:
// Track state between the old and new error reporting modes.
bool mOwnErrorReporting;
bool mOldDontReportUncaught;
bool mOldAutoJSAPIOwnsErrorReporting;
Maybe<JSErrorReporter> mOldErrorReporter;
void InitInternal(JSObject* aGlobal, JSContext* aCx, bool aIsMainThread);

View File

@ -1440,6 +1440,8 @@ nsDOMStyleSheetSetList::nsDOMStyleSheetSetList(nsIDocument* aDocument)
void
nsDOMStyleSheetSetList::EnsureFresh()
{
MOZ_ASSERT(NS_IsMainThread());
mNames.Clear();
if (!mDocument) {
@ -2985,6 +2987,33 @@ nsDocument::InitCSP(nsIChannel* aChannel)
}
}
// ----- Set up any Referrer Policy specified by CSP
bool hasReferrerPolicy = false;
uint32_t referrerPolicy = mozilla::net::RP_Default;
rv = csp->GetReferrerPolicy(&referrerPolicy, &hasReferrerPolicy);
NS_ENSURE_SUCCESS(rv, rv);
if (hasReferrerPolicy) {
// Referrer policy spec (section 6.1) says that once the referrer policy
// is set, any future attempts to change it result in No-Referrer.
if (!mReferrerPolicySet) {
mReferrerPolicy = static_cast<ReferrerPolicy>(referrerPolicy);
mReferrerPolicySet = true;
} else if (mReferrerPolicy != referrerPolicy) {
mReferrerPolicy = mozilla::net::RP_No_Referrer;
#ifdef PR_LOGGING
{
PR_LOG(gCspPRLog, PR_LOG_DEBUG, ("%s %s",
"CSP wants to set referrer, but nsDocument"
"already has it set. No referrers will be sent"));
}
#endif
}
// Referrer Policy is set separately for the speculative parser in
// nsHTMLDocument::StartDocumentLoad() so there's nothing to do here for
// speculative loads.
}
rv = principal->SetCsp(csp);
NS_ENSURE_SUCCESS(rv, rv);
#ifdef PR_LOGGING

View File

@ -172,7 +172,6 @@
#include "nsFrameLoader.h"
#include "nsISupportsPrimitives.h"
#include "nsXPCOMCID.h"
#include "mozIThirdPartyUtil.h"
#include "prlog.h"
#include "prenv.h"
#include "prprf.h"
@ -260,6 +259,7 @@ using namespace mozilla::dom;
using namespace mozilla::dom::ipc;
using mozilla::TimeStamp;
using mozilla::TimeDuration;
using mozilla::dom::indexedDB::IDBFactory;
nsGlobalWindow::WindowByIdTable *nsGlobalWindow::sWindowsById = nullptr;
bool nsGlobalWindow::sWarnedAboutWindowInternal = false;
@ -10584,71 +10584,11 @@ nsGlobalWindow::GetLocalStorage(nsISupports** aLocalStorage)
return rv.ErrorCode();
}
static bool
GetIndexedDBEnabledForAboutURI(nsIURI *aURI)
{
nsCOMPtr<nsIAboutModule> module;
nsresult rv = NS_GetAboutModule(aURI, getter_AddRefs(module));
NS_ENSURE_SUCCESS(rv, false);
uint32_t flags;
rv = module->GetURIFlags(aURI, &flags);
NS_ENSURE_SUCCESS(rv, false);
return flags & nsIAboutModule::ENABLE_INDEXED_DB;
}
mozilla::dom::indexedDB::IDBFactory*
IDBFactory*
nsGlobalWindow::GetIndexedDB(ErrorResult& aError)
{
using mozilla::dom::indexedDB::IDBFactory;
if (!mIndexedDB) {
// If the document has the sandboxed origin flag set
// don't allow access to indexedDB.
if (mDoc && (mDoc->GetSandboxFlags() & SANDBOXED_ORIGIN)) {
aError.Throw(NS_ERROR_DOM_SECURITY_ERR);
return nullptr;
}
if (!IsChromeWindow()) {
// Whitelist about:home, since it doesn't have a base domain it would not
// pass the thirdPartyUtil check, though it should be able to use
// indexedDB.
bool skipThirdPartyCheck = false;
nsIPrincipal *principal = GetPrincipal();
if (principal) {
nsCOMPtr<nsIURI> uri;
principal->GetURI(getter_AddRefs(uri));
if (uri) {
bool isAbout = false;
if (NS_SUCCEEDED(uri->SchemeIs("about", &isAbout)) && isAbout) {
skipThirdPartyCheck = GetIndexedDBEnabledForAboutURI(uri);
}
}
}
if (!skipThirdPartyCheck) {
nsCOMPtr<mozIThirdPartyUtil> thirdPartyUtil =
do_GetService(THIRDPARTYUTIL_CONTRACTID);
if (!thirdPartyUtil) {
aError.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
return nullptr;
}
bool isThirdParty;
aError = thirdPartyUtil->IsThirdPartyWindow(this, nullptr,
&isThirdParty);
if (aError.Failed() || isThirdParty) {
NS_WARN_IF_FALSE(aError.Failed(),
"IndexedDB is not permitted in a third-party window.");
return nullptr;
}
}
}
// This may be null if being created from a file.
// This may keep mIndexedDB null without setting an error.
aError = IDBFactory::CreateForWindow(this, getter_AddRefs(mIndexedDB));
}

View File

@ -0,0 +1,55 @@
<!DOCTYPE HTML>
<html>
<head>
<title>Subframe test for bug 965727</title>
<script type="text/javascript">
// we can get the ID out of the querystring.
var args = document.location.search.substring(1).split('&');
var id = "unknown";
for (var i=0; i < args.length; i++) {
var arg = unescape(args[i]);
if (arg.indexOf('=') > 0 && arg.indexOf('id') == 0) {
id = arg.split('=')[1].trim();
}
}
var results = {
'id': id,
'referrer': document.location.href,
'results': {
'sameorigin': false,
'crossorigin': false,
'downgrade': false
}
};
// this is called back by each script load.
var postResult = function(loadType, referrerLevel, referrer) {
results.results[loadType] = referrerLevel;
// and then check if all three have loaded.
for (var id in results.results) {
if (!results.results[id]) {
return;
}
}
//finished if we don't return early
window.parent.postMessage(JSON.stringify(results), "*");
console.log(JSON.stringify(results));
}
</script>
</head>
<body>
Testing ...
<script src="https://example.com/tests/dom/base/test/csp/referrerdirective.sjs?type=sameorigin&"
onerror="postResult('sameorigin', 'error');"></script>
<script src="https://test2.example.com/tests/dom/base/test/csp/referrerdirective.sjs?type=crossorigin&"
onerror="postResult('crossorigin', 'error');"></script>
<script src="http://example.com/tests/dom/base/test/csp/referrerdirective.sjs?type=downgrade&"
onerror="postResult('downgrade', 'error');"></script>
</body>
</html>

View File

@ -103,6 +103,8 @@ support-files =
file_form-action.html
file_worker_redirect.html
file_worker_redirect.sjs
file_csp_referrerdirective.html
referrerdirective.sjs
[test_base-uri.html]
[test_connect-src.html]
@ -149,4 +151,6 @@ skip-if = buildapp == 'b2g' # intermittent orange (bug 1028490)
[test_subframe_run_js_if_allowed.html]
[test_leading_wildcard.html]
[test_multi_policy_injection_bypass.html]
[test_CSP_referrerdirective.html]
skip-if = buildapp == 'b2g' #no ssl support
[test_worker_redirect.html]

View File

@ -0,0 +1,36 @@
// Used for bug 965727 to serve up really simple scripts reflecting the
// referrer sent to load this back to the loader.
function handleRequest(request, response) {
// skip speculative loads.
var splits = request.queryString.split('&');
var params = {};
splits.forEach(function(v) {
let parts = v.split('=');
params[parts[0]] = unescape(parts[1]);
});
var loadType = params['type'];
var referrerLevel = 'error';
if (request.hasHeader('Referer')) {
var referrer = request.getHeader('Referer');
if (referrer.indexOf("file_csp_testserver.sjs") > -1) {
referrerLevel = "full";
} else {
referrerLevel = "origin";
}
} else {
referrerLevel = 'none';
}
var theScript = 'window.postResult("' + loadType + '", "' + referrerLevel + '");';
response.setHeader('Content-Type', 'application/javascript; charset=utf-8', false);
response.setHeader('Cache-Control', 'no-cache', false);
if (request.method != "OPTIONS") {
response.write(theScript);
}
}

View File

@ -0,0 +1,125 @@
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=965727
-->
<head>
<meta charset="utf-8">
<title>Test for Content Security Policy referrer Directive (Bug 965727)</title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<div id="content" style="display: none">
</div>
<pre id="test">
<script class="testbody" type="application/javascript">
/*
* This tests various referrer policies and the referrer-sending behavior when
* requesting scripts in different ways:
* - cross-origin (https://example.com -> https://test2.example.com)
* - same-origin (https://example.com -> https://example.com)
* - downgrade (https://example.com -> http://example.com)
*
* Each test creates an iframe that loads scripts for each of the checks. If
* the scripts are blocked, the test fails (they should run). When loaded,
* each script updates a results object in the test page, and then when the
* test page has finished loading all the scripts, it postMessages back to this
* page. Once all tests are done, the results are checked.
*/
var testData = {
'default': { 'csp': "script-src * 'unsafe-inline'; referrer default",
'expected': { 'sameorigin': 'full',
'crossorigin': 'full',
'downgrade': 'none' }},
'origin': { 'csp': "script-src * 'unsafe-inline'; referrer origin",
'expected': { 'sameorigin': 'origin',
'crossorigin': 'origin',
'downgrade': 'origin' }},
'origin-when-crossorigin': { 'csp': "script-src * 'unsafe-inline'; referrer origin-when-crossorigin",
'expected': { 'sameorigin': 'full',
'crossorigin': 'origin',
'downgrade': 'none' }},
'unsafe-url': { 'csp': "script-src * 'unsafe-inline'; referrer unsafe-url",
'expected': { 'sameorigin': 'full',
'crossorigin': 'full',
'downgrade': 'full' }},
'none': { 'csp': "script-src * 'unsafe-inline'; referrer no-referrer",
'expected': { 'sameorigin': 'none',
'crossorigin': 'none',
'downgrade': 'none' }},
};
var referrerDirectiveTests = {
// called via postMessage when one of the iframes is done running.
onIframeComplete: function(event) {
try {
var results = JSON.parse(event.data);
ok(results.hasOwnProperty('id'), "'id' property required in posted message " + event.data);
ok(testData.hasOwnProperty(results['id']), "Test " + results['id'] + " must be expected.");
// check all the various load types' referrers.
var expected = testData[results['id']].expected;
for (var t in expected) {
is(results.results[t], expected[t],
" referrer must match expected for " + t + " in " + results['id']);
}
testData[results['id']]['complete'] = true;
} catch(e) {
// fail -- should always be JSON
ok(false, "failed to parse posted message + " + event.data);
// have to end as well since not all messages were valid.
SimpleTest.finish();
}
referrerDirectiveTests.checkForCompletion();
},
// checks to see if all the parallel tests are done and validates results.
checkForCompletion: function() {
for (var id in testData) {
if (!testData[id].hasOwnProperty('complete')) {
return;
}
}
SimpleTest.finish();
}
};
SimpleTest.waitForExplicitFinish();
// have to disable mixed content blocking to test https->http referrers.
SpecialPowers.pushPrefEnv({
'set': [['security.mixed_content.block_active_content', false],
['security.mixed_content.block_display_content', false]]
},
function() {
// each of the iframes we create will call us back when its contents are loaded.
window.addEventListener("message", referrerDirectiveTests.onIframeComplete.bind(window), false);
// one iframe created for each test case
for (var id in testData) {
var elt = document.createElement("iframe");
elt.src = "https://example.com/tests/dom/base/test/csp/file_csp_testserver.sjs?" +
"id=" + id +
"&csp=" + escape(testData[id]['csp']) +
"&file=tests/dom/base/test/csp/file_csp_referrerdirective.html";
document.getElementById("content").appendChild(elt);
}
});
</script>
</pre>
</body>
</html>

View File

@ -0,0 +1,29 @@
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>Test for DataStore</title>
</head>
<body>
<div id="container"></div>
<script type="application/javascript;version=1.7">
var messages = [];
var worker = new Worker("file_worker_close.js");
worker.onmessage = function(event) {
messages.push(event.data)
if (event.data == 'DONE') {
worker.terminate();
// Fire message to the test_basic_worker.html.
for (var i = 0; i < messages.length; i++) {
alert(messages[i]);
}
}
}
</script>
</body>
</html>

View File

@ -0,0 +1,18 @@
function is(a, b, msg) {
postMessage((a == b ? 'OK' : 'KO')+ ' ' + msg)
}
var store;
navigator.getDataStores('foo').then(function(stores) {
is(stores.length, 1, "getDataStores('foo') returns 1 element");
is(stores[0].name, 'foo', 'The dataStore.name is foo');
is(stores[0].readOnly, false, 'The dataStore foo is not in readonly');
store = stores[0];
postMessage('DONE');
});
onclose = function() {
for (var i = 0; i < 100; ++i) {
store.get(123);
}
}

View File

@ -32,6 +32,8 @@ support-files =
file_bug1008044.html
file_bug957086.html
file_notify_system_message.html
file_worker_close.html
file_worker_close.js
[test_app_install.html]
skip-if = toolkit == 'gonk' # embed-apps doesn't work in the mochitest app
@ -59,3 +61,4 @@ skip-if = (toolkit == 'android' && processor == 'x86') #x86 only bug 936226
[test_bug1058108.html]
[test_notify_system_message.html]
skip-if = buildapp == 'mulet' || buildapp == 'b2g' || toolkit == 'android' || toolkit == 'win' #bug 1053662 - Timeout prone
[test_worker_close.html]

View File

@ -0,0 +1,130 @@
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>Test for DataStore - Worker.onclose</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<div id="container"></div>
<script type="application/javascript;version=1.7">
var gHostedManifestURL = 'http://test/tests/dom/datastore/tests/file_app.sjs?testToken=file_worker_close.html';
var gApp;
function cbError() {
ok(false, "Error callback invoked");
finish();
}
function installApp() {
var request = navigator.mozApps.install(gHostedManifestURL);
request.onerror = cbError;
request.onsuccess = function() {
gApp = request.result;
runTest();
}
}
function uninstallApp() {
// Uninstall the app.
var request = navigator.mozApps.mgmt.uninstall(gApp);
request.onerror = cbError;
request.onsuccess = function() {
// All done.
info("All done");
runTest();
}
}
function testApp() {
var ifr = document.createElement('iframe');
ifr.setAttribute('mozbrowser', 'true');
ifr.setAttribute('mozapp', gApp.manifestURL);
ifr.setAttribute('src', gApp.manifest.launch_path);
var domParent = document.getElementById('container');
// Set us up to listen for messages from the app.
var listener = function(e) {
var message = e.detail.message;
if (/^OK/.exec(message)) {
ok(true, "Message from app: " + message);
} else if (/KO/.exec(message)) {
ok(false, "Message from app: " + message);
} else if (/DONE/.exec(message)) {
ok(true, "Messaging from app complete");
ifr.removeEventListener('mozbrowsershowmodalprompt', listener);
domParent.removeChild(ifr);
runTest();
}
}
// This event is triggered when the app calls "alert".
ifr.addEventListener('mozbrowsershowmodalprompt', listener, false);
domParent.appendChild(ifr);
}
var tests = [
// Permissions
function() {
SpecialPowers.pushPermissions(
[{ "type": "browser", "allow": 1, "context": document },
{ "type": "embed-apps", "allow": 1, "context": document },
{ "type": "webapps-manage", "allow": 1, "context": document }], runTest);
},
// Preferences
function() {
SpecialPowers.pushPrefEnv({"set": [["dom.datastore.enabled", true],
["dom.datastore.sysMsgOnChangeShortTimeoutSec", 1],
["dom.datastore.sysMsgOnChangeLongTimeoutSec", 3],
["dom.testing.ignore_ipc_principal", true],
["dom.testing.datastore_enabled_for_hosted_apps", true]]}, runTest);
},
function() {
if (SpecialPowers.isMainProcess()) {
SpecialPowers.Cu.import("resource://gre/modules/DataStoreChangeNotifier.jsm");
}
SpecialPowers.setAllAppsLaunchable(true);
SpecialPowers.setBoolPref("dom.mozBrowserFramesEnabled", true);
runTest();
},
// No confirmation needed when an app is installed
function() {
SpecialPowers.autoConfirmAppInstall(() =>
SpecialPowers.autoConfirmAppUninstall(runTest));
},
// Installing the app
installApp,
// Run tests in app
testApp,
// Uninstall the app
uninstallApp
];
function runTest() {
if (!tests.length) {
finish();
return;
}
var test = tests.shift();
test();
}
function finish() {
SimpleTest.finish();
}
SimpleTest.waitForExplicitFinish();
runTest();
</script>
</body>
</html>

View File

@ -214,8 +214,8 @@ public:
};
WorkerFetchResolver::WorkerFetchResolver(WorkerPrivate* aWorkerPrivate, Promise* aPromise)
: mPromiseProxy(new PromiseWorkerProxy(aWorkerPrivate, aPromise))
{
mPromiseProxy = PromiseWorkerProxy::Create(aWorkerPrivate, aPromise);
}
WorkerFetchResolver::~WorkerFetchResolver()

View File

@ -14,6 +14,8 @@
#include "nsWrapperCacheInlines.h"
#include "mozilla/dom/HTMLPropertiesCollectionBinding.h"
#include "jsapi.h"
#include "MainThreadUtils.h"
#include "mozilla/Assertions.h"
namespace mozilla {
namespace dom {
@ -509,6 +511,8 @@ NS_INTERFACE_MAP_END_INHERITING(DOMStringList)
void
PropertyStringList::EnsureFresh()
{
MOZ_ASSERT(NS_IsMainThread());
mCollection->EnsureFresh();
}

View File

@ -673,10 +673,15 @@ nsHTMLDocument::StartDocumentLoad(const char* aCommand,
nsCOMPtr<nsIWyciwygChannel> wyciwygChannel;
// For error reporting
// For error reporting and referrer policy setting
nsHtml5TreeOpExecutor* executor = nullptr;
if (loadAsHtml5) {
executor = static_cast<nsHtml5TreeOpExecutor*> (mParser->GetContentSink());
if (mReferrerPolicySet) {
// CSP may have set the referrer policy, so a speculative parser should
// start with the new referrer policy.
executor->SetSpeculationReferrerPolicy(static_cast<ReferrerPolicy>(mReferrerPolicy));
}
}
if (!IsHTML() || !docShell) { // no docshell for text/html XHR
@ -1641,6 +1646,15 @@ nsHTMLDocument::Open(JSContext* cx,
mParserAborted = false;
mParser = nsHtml5Module::NewHtml5Parser();
nsHtml5Module::Initialize(mParser, this, uri, shell, channel);
if (mReferrerPolicySet) {
// CSP may have set the referrer policy, so a speculative parser should
// start with the new referrer policy.
nsHtml5TreeOpExecutor* executor = nullptr;
executor = static_cast<nsHtml5TreeOpExecutor*> (mParser->GetContentSink());
if (executor && mReferrerPolicySet) {
executor->SetSpeculationReferrerPolicy(static_cast<ReferrerPolicy>(mReferrerPolicy));
}
}
// This will be propagated to the parser when someone actually calls write()
SetContentTypeInternal(contentType);

View File

@ -18,6 +18,7 @@
#include "IndexedDatabaseInlines.h"
#include "mozilla/BasicEvents.h"
#include "mozilla/Maybe.h"
#include "mozilla/TypeTraits.h"
#include "mozilla/dom/PermissionMessageUtils.h"
#include "mozilla/dom/TabChild.h"
#include "mozilla/dom/indexedDB/PBackgroundIDBDatabaseFileChild.h"
@ -187,7 +188,9 @@ class MOZ_STACK_CLASS ResultHelper MOZ_FINAL
union
{
nsISupports* mISupports;
IDBDatabase* mDatabase;
IDBCursor* mCursor;
IDBMutableFile* mMutableFile;
StructuredCloneReadInfo* mStructuredClone;
const nsTArray<StructuredCloneReadInfo>* mStructuredCloneArray;
const Key* mKey;
@ -198,7 +201,9 @@ class MOZ_STACK_CLASS ResultHelper MOZ_FINAL
enum
{
ResultTypeISupports,
ResultTypeDatabase,
ResultTypeCursor,
ResultTypeMutableFile,
ResultTypeStructuredClone,
ResultTypeStructuredCloneArray,
ResultTypeKey,
@ -210,16 +215,39 @@ class MOZ_STACK_CLASS ResultHelper MOZ_FINAL
public:
ResultHelper(IDBRequest* aRequest,
IDBTransaction* aTransaction,
nsISupports* aResult)
IDBDatabase* aResult)
: mRequest(aRequest)
, mAutoTransaction(aTransaction)
, mResultType(ResultTypeISupports)
, mResultType(ResultTypeDatabase)
{
MOZ_ASSERT(NS_IsMainThread(), "This won't work off the main thread!");
MOZ_ASSERT(aRequest);
MOZ_ASSERT(aResult);
mResult.mISupports = aResult;
mResult.mDatabase = aResult;
}
ResultHelper(IDBRequest* aRequest,
IDBTransaction* aTransaction,
IDBCursor* aResult)
: mRequest(aRequest)
, mAutoTransaction(aTransaction)
, mResultType(ResultTypeCursor)
{
MOZ_ASSERT(aRequest);
mResult.mCursor = aResult;
}
ResultHelper(IDBRequest* aRequest,
IDBTransaction* aTransaction,
IDBMutableFile* aResult)
: mRequest(aRequest)
, mAutoTransaction(aTransaction)
, mResultType(ResultTypeMutableFile)
{
MOZ_ASSERT(aRequest);
mResult.mMutableFile = aResult;
}
ResultHelper(IDBRequest* aRequest,
@ -318,8 +346,14 @@ public:
MOZ_ASSERT(mRequest);
switch (mResultType) {
case ResultTypeISupports:
return GetResult(aCx, mResult.mISupports, aResult);
case ResultTypeDatabase:
return GetResult(aCx, mResult.mDatabase, aResult);
case ResultTypeCursor:
return GetResult(aCx, mResult.mCursor, aResult);
case ResultTypeMutableFile:
return GetResult(aCx, mResult.mMutableFile, aResult);
case ResultTypeStructuredClone:
return GetResult(aCx, mResult.mStructuredClone, aResult);
@ -349,20 +383,22 @@ public:
}
private:
nsresult
template <class T>
typename EnableIf<IsSame<T, IDBDatabase>::value ||
IsSame<T, IDBCursor>::value ||
IsSame<T, IDBMutableFile>::value,
nsresult>::Type
GetResult(JSContext* aCx,
nsISupports* aSupports,
T* aDOMObject,
JS::MutableHandle<JS::Value> aResult)
{
MOZ_ASSERT(NS_IsMainThread(), "This won't work off the main thread!");
if (!aSupports) {
if (!aDOMObject) {
aResult.setNull();
return NS_OK;
}
nsresult rv = nsContentUtils::WrapNative(aCx, aSupports, aResult);
if (NS_WARN_IF(NS_FAILED(rv))) {
bool ok = GetOrCreateDOMReflector(aCx, aDOMObject, aResult);
if (NS_WARN_IF(!ok)) {
IDB_REPORT_INTERNAL_ERR();
return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
}
@ -609,9 +645,7 @@ DispatchErrorEvent(IDBRequest* aRequest,
nsDependentString(kErrorEventType),
eDoesBubble,
eCancelable);
if (NS_WARN_IF(!errorEvent)) {
return;
}
MOZ_ASSERT(errorEvent);
aEvent = errorEvent;
}
@ -687,9 +721,7 @@ DispatchSuccessEvent(ResultHelper* aResultHelper,
nsDependentString(kSuccessEventType),
eDoesNotBubble,
eNotCancelable);
if (NS_WARN_IF(!successEvent)) {
return;
}
MOZ_ASSERT(successEvent);
aEvent = successEvent;
}
@ -987,8 +1019,7 @@ BackgroundFactoryRequestChild::HandleResponse(
IDBDatabase* database = databaseActor->GetDOMObject();
MOZ_ASSERT(database);
ResultHelper helper(mRequest, nullptr,
static_cast<IDBWrapperCache*>(database));
ResultHelper helper(mRequest, nullptr, database);
DispatchSuccessEvent(&helper);
@ -1009,9 +1040,7 @@ BackgroundFactoryRequestChild::HandleResponse(
IDBVersionChangeEvent::Create(mRequest,
nsDependentString(kSuccessEventType),
aResponse.previousVersion());
if (NS_WARN_IF(!successEvent)) {
return false;
}
MOZ_ASSERT(successEvent);
DispatchSuccessEvent(&helper, successEvent);
@ -1026,6 +1055,13 @@ BackgroundFactoryRequestChild::ActorDestroy(ActorDestroyReason aWhy)
MaybeCollectGarbageOnIPCMessage();
NoteActorDestroyed();
if (aWhy != Deletion) {
IDBOpenDBRequest* openRequest = GetOpenDBRequest();
if (openRequest) {
openRequest->NoteComplete();
}
}
}
bool
@ -1037,21 +1073,35 @@ BackgroundFactoryRequestChild::Recv__delete__(
MaybeCollectGarbageOnIPCMessage();
bool result;
switch (aResponse.type()) {
case FactoryRequestResponse::Tnsresult:
return HandleResponse(aResponse.get_nsresult());
result = HandleResponse(aResponse.get_nsresult());
break;
case FactoryRequestResponse::TOpenDatabaseRequestResponse:
return HandleResponse(aResponse.get_OpenDatabaseRequestResponse());
result = HandleResponse(aResponse.get_OpenDatabaseRequestResponse());
break;
case FactoryRequestResponse::TDeleteDatabaseRequestResponse:
return HandleResponse(aResponse.get_DeleteDatabaseRequestResponse());
result = HandleResponse(aResponse.get_DeleteDatabaseRequestResponse());
break;
default:
MOZ_CRASH("Unknown response type!");
}
MOZ_CRASH("Should never get here!");
IDBOpenDBRequest* request = GetOpenDBRequest();
MOZ_ASSERT(request);
request->NoteComplete();
if (NS_WARN_IF(!result)) {
return false;
}
return true;
}
bool
@ -1121,16 +1171,14 @@ BackgroundFactoryRequestChild::RecvBlocked(const uint64_t& aCurrentVersion)
if (mIsDeleteOp) {
blockedEvent =
IDBVersionChangeEvent::Create(mRequest, type, aCurrentVersion);
MOZ_ASSERT(blockedEvent);
} else {
blockedEvent =
IDBVersionChangeEvent::Create(mRequest,
type,
aCurrentVersion,
mRequestedVersion);
}
if (NS_WARN_IF(!blockedEvent)) {
return false;
MOZ_ASSERT(blockedEvent);
}
nsRefPtr<IDBRequest> kungFuDeathGrip = mRequest;
@ -1315,7 +1363,7 @@ BackgroundDatabaseChild::RecvPBackgroundIDBVersionChangeTransactionConstructor(
EnsureDOMObject();
auto actor = static_cast<BackgroundVersionChangeTransactionChild*>(aActor);
auto* actor = static_cast<BackgroundVersionChangeTransactionChild*>(aActor);
nsRefPtr<IDBOpenDBRequest> request = mOpenRequestActor->GetOpenDBRequest();
MOZ_ASSERT(request);
@ -1327,7 +1375,15 @@ BackgroundDatabaseChild::RecvPBackgroundIDBVersionChangeTransactionConstructor(
aNextObjectStoreId,
aNextIndexId);
if (NS_WARN_IF(!transaction)) {
return false;
// This can happen if we receive events after a worker has begun its
// shutdown process.
MOZ_ASSERT(!NS_IsMainThread());
// Report this to the console.
IDB_REPORT_INTERNAL_ERR();
MOZ_ALWAYS_TRUE(aActor->SendDeleteMe());
return true;
}
transaction->AssertIsOnOwningThread();
@ -1343,12 +1399,9 @@ BackgroundDatabaseChild::RecvPBackgroundIDBVersionChangeTransactionConstructor(
nsDependentString(kUpgradeNeededEventType),
aCurrentVersion,
aRequestedVersion);
if (NS_WARN_IF(!upgradeNeededEvent)) {
return false;
}
MOZ_ASSERT(upgradeNeededEvent);
ResultHelper helper(request, transaction,
static_cast<IDBWrapperCache*>(mDatabase));
ResultHelper helper(request, transaction, mDatabase);
DispatchSuccessEvent(&helper, upgradeNeededEvent);
@ -1411,6 +1464,7 @@ BackgroundDatabaseChild::RecvVersionChange(const uint64_t& aOldVersion,
case NullableVersion::Tnull_t:
versionChangeEvent =
IDBVersionChangeEvent::Create(mDatabase, type, aOldVersion);
MOZ_ASSERT(versionChangeEvent);
break;
case NullableVersion::Tuint64_t:
@ -1419,16 +1473,13 @@ BackgroundDatabaseChild::RecvVersionChange(const uint64_t& aOldVersion,
type,
aOldVersion,
aNewVersion.get_uint64_t());
MOZ_ASSERT(versionChangeEvent);
break;
default:
MOZ_CRASH("Should never get here!");
}
if (NS_WARN_IF(!versionChangeEvent)) {
return false;
}
IDB_LOG_MARK("IndexedDB %s: Child : Firing \"versionchange\" event",
"IndexedDB %s: C: IDBDatabase \"versionchange\" event",
IDB_LOG_ID_STRING());
@ -1670,11 +1721,12 @@ BackgroundVersionChangeTransactionChild::AssertIsOnOwningThread() const
#endif // DEBUG
void
BackgroundVersionChangeTransactionChild::SendDeleteMeInternal()
BackgroundVersionChangeTransactionChild::SendDeleteMeInternal(
bool aFailedConstructor)
{
AssertIsOnOwningThread();
if (mTransaction) {
if (mTransaction || aFailedConstructor) {
NoteActorDestroyed();
MOZ_ALWAYS_TRUE(PBackgroundIDBVersionChangeTransactionChild::
@ -2014,13 +2066,14 @@ BackgroundRequestChild::Recv__delete__(const RequestResponse& aResponse)
******************************************************************************/
class BackgroundCursorChild::DelayedDeleteRunnable MOZ_FINAL
: public nsIRunnable
: public nsICancelableRunnable
{
BackgroundCursorChild* mActor;
nsRefPtr<IDBRequest> mRequest;
public:
explicit DelayedDeleteRunnable(BackgroundCursorChild* aActor)
explicit
DelayedDeleteRunnable(BackgroundCursorChild* aActor)
: mActor(aActor)
, mRequest(aActor->mRequest)
{
@ -2037,6 +2090,7 @@ private:
{ }
NS_DECL_NSIRUNNABLE
NS_DECL_NSICANCELABLERUNNABLE
};
BackgroundCursorChild::BackgroundCursorChild(IDBRequest* aRequest,
@ -2405,7 +2459,8 @@ DispatchMutableFileResult(IDBRequest* aRequest,
}
NS_IMPL_ISUPPORTS(BackgroundCursorChild::DelayedDeleteRunnable,
nsIRunnable)
nsIRunnable,
nsICancelableRunnable)
NS_IMETHODIMP
BackgroundCursorChild::
@ -2423,6 +2478,20 @@ DelayedDeleteRunnable::Run()
return NS_OK;
}
NS_IMETHODIMP
BackgroundCursorChild::
DelayedDeleteRunnable::Cancel()
{
if (NS_WARN_IF(!mActor)) {
return NS_ERROR_UNEXPECTED;
}
// This must always run to clean up our state.
Run();
return NS_OK;
}
} // namespace indexedDB
} // namespace dom
} // namespace mozilla

View File

@ -514,7 +514,7 @@ public:
#endif
void
SendDeleteMeInternal();
SendDeleteMeInternal(bool aFailedConstructor);
private:
// Only created by BackgroundDatabaseChild.

View File

@ -7821,13 +7821,8 @@ bool
NormalTransaction::SendCompleteNotification(nsresult aResult)
{
AssertIsOnBackgroundThread();
MOZ_ASSERT(!IsActorDestroyed());
if (NS_WARN_IF(!SendComplete(aResult))) {
return false;
}
return true;
return IsActorDestroyed() || !NS_WARN_IF(!SendComplete(aResult));
}
void
@ -8106,7 +8101,6 @@ VersionChangeTransaction::SendCompleteNotification(nsresult aResult)
{
AssertIsOnBackgroundThread();
MOZ_ASSERT(mOpenDatabaseOp);
MOZ_ASSERT(!IsActorDestroyed());
nsRefPtr<OpenDatabaseOp> openDatabaseOp;
mOpenDatabaseOp.swap(openDatabaseOp);
@ -8117,7 +8111,7 @@ VersionChangeTransaction::SendCompleteNotification(nsresult aResult)
openDatabaseOp->mState = OpenDatabaseOp::State_SendingResults;
bool result = SendComplete(aResult);
bool result = IsActorDestroyed() || !NS_WARN_IF(!SendComplete(aResult));
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(openDatabaseOp->Run()));
@ -10550,10 +10544,23 @@ FactoryOp::Open()
return NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR;
}
// This has to be started on the main thread currently.
if (NS_WARN_IF(!IndexedDatabaseManager::GetOrCreate())) {
IDB_REPORT_INTERNAL_ERR();
return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
{
// These services have to be started on the main thread currently.
if (NS_WARN_IF(!IndexedDatabaseManager::GetOrCreate())) {
IDB_REPORT_INTERNAL_ERR();
return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
}
nsCOMPtr<mozIStorageService> ss;
if (NS_WARN_IF(!(ss = do_GetService(MOZ_STORAGE_SERVICE_CONTRACTID)))) {
IDB_REPORT_INTERNAL_ERR();
return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
}
if (NS_WARN_IF(!QuotaManager::GetOrCreate())) {
IDB_REPORT_INTERNAL_ERR();
return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
}
}
const DatabaseMetadata& metadata = mCommonParams.metadata();
@ -11936,8 +11943,7 @@ OpenDatabaseOp::SendResults()
mVersionChangeTransaction = nullptr;
}
if (!IsActorDestroyed() &&
(!mDatabase || !mDatabase->IsInvalidated())) {
if (!IsActorDestroyed()) {
FactoryRequestResponse response;
if (NS_SUCCEEDED(mResultCode)) {
@ -11977,6 +11983,10 @@ OpenDatabaseOp::SendResults()
DatabaseOfflineStorage::UnregisterOnOwningThread(mOfflineStorage.forget());
}
// Make sure to release the database on this thread.
nsRefPtr<Database> database;
mDatabase.swap(database);
FinishSendResults();
}
@ -13377,9 +13387,7 @@ CommitOp::TransactionFinishedAfterUnblock()
mTransaction->ReleaseBackgroundThreadObjects();
if (!mTransaction->IsActorDestroyed()) {
mTransaction->SendCompleteNotification(ClampResultCode(mResultCode));
}
mTransaction->SendCompleteNotification(ClampResultCode(mResultCode));
mTransaction->GetDatabase()->UnregisterTransaction(mTransaction);

View File

@ -67,6 +67,29 @@ const char kCycleCollectionObserverTopic[] = "cycle-collector-end";
const char kMemoryPressureObserverTopic[] = "memory-pressure";
const char kWindowObserverTopic[] = "inner-window-destroyed";
class CancelableRunnableWrapper MOZ_FINAL
: public nsICancelableRunnable
{
nsCOMPtr<nsIRunnable> mRunnable;
public:
explicit
CancelableRunnableWrapper(nsIRunnable* aRunnable)
: mRunnable(aRunnable)
{
MOZ_ASSERT(aRunnable);
}
NS_DECL_ISUPPORTS
private:
~CancelableRunnableWrapper()
{ }
NS_DECL_NSIRUNNABLE
NS_DECL_NSICANCELABLERUNNABLE
};
// XXX This should either be ported to PBackground or removed someday.
class CreateFileHelper MOZ_FINAL
: public nsRunnable
@ -156,6 +179,46 @@ private:
} // anonymous namespace
class IDBDatabase::LogWarningRunnable MOZ_FINAL
: public nsRunnable
{
nsCString mMessageName;
nsString mFilename;
uint32_t mLineNumber;
uint64_t mInnerWindowID;
bool mIsChrome;
public:
LogWarningRunnable(const char* aMessageName,
const nsAString& aFilename,
uint32_t aLineNumber,
bool aIsChrome,
uint64_t aInnerWindowID)
: mMessageName(aMessageName)
, mFilename(aFilename)
, mLineNumber(aLineNumber)
, mInnerWindowID(aInnerWindowID)
, mIsChrome(aIsChrome)
{
MOZ_ASSERT(!NS_IsMainThread());
}
static void
LogWarning(const char* aMessageName,
const nsAString& aFilename,
uint32_t aLineNumber,
bool aIsChrome,
uint64_t aInnerWindowID);
NS_DECL_ISUPPORTS_INHERITED
private:
~LogWarningRunnable()
{ }
NS_DECL_NSIRUNNABLE
};
class IDBDatabase::Observer MOZ_FINAL
: public nsIObserver
{
@ -680,7 +743,11 @@ IDBDatabase::Transaction(const Sequence<nsString>& aStoreNames,
nsRefPtr<IDBTransaction> transaction =
IDBTransaction::Create(this, sortedStoreNames, mode);
MOZ_ASSERT(transaction);
if (NS_WARN_IF(!transaction)) {
IDB_REPORT_INTERNAL_ERR();
aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
return nullptr;
}
BackgroundTransactionChild* actor =
new BackgroundTransactionChild(transaction);
@ -1006,6 +1073,12 @@ IDBDatabase::DelayedMaybeExpireFileActors()
/* aExpireAll */ false);
MOZ_ASSERT(runnable);
if (!NS_IsMainThread()) {
// Wrap as a nsICancelableRunnable to make workers happy.
nsCOMPtr<nsIRunnable> cancelable = new CancelableRunnableWrapper(runnable);
cancelable.swap(runnable);
}
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(NS_DispatchToCurrentThread(runnable)));
}
@ -1170,10 +1243,9 @@ IDBDatabase::NoteFinishedMutableFile(IDBMutableFile* aMutableFile)
void
IDBDatabase::InvalidateMutableFiles()
{
MOZ_ASSERT(NS_IsMainThread());
if (!mLiveMutableFiles.IsEmpty()) {
MOZ_ASSERT(IndexedDatabaseManager::IsMainProcess());
MOZ_ASSERT(NS_IsMainThread());
for (uint32_t count = mLiveMutableFiles.Length(), index = 0;
index < count;
@ -1205,55 +1277,21 @@ IDBDatabase::LogWarning(const char* aMessageName,
AssertIsOnOwningThread();
MOZ_ASSERT(aMessageName);
// For now this is main-thread only.
MOZ_ASSERT(NS_IsMainThread());
nsXPIDLString localizedMessage;
if (NS_WARN_IF(NS_FAILED(
nsContentUtils::GetLocalizedString(nsContentUtils::eDOM_PROPERTIES,
aMessageName,
localizedMessage)))) {
return;
}
nsAutoCString category;
if (mFactory->IsChrome()) {
category.AssignLiteral("chrome ");
if (NS_IsMainThread()) {
LogWarningRunnable::LogWarning(aMessageName,
aFilename,
aLineNumber,
mFactory->IsChrome(),
mFactory->InnerWindowID());
} else {
category.AssignLiteral("content ");
nsRefPtr<LogWarningRunnable> runnable =
new LogWarningRunnable(aMessageName,
aFilename,
aLineNumber,
mFactory->IsChrome(),
mFactory->InnerWindowID());
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(NS_DispatchToMainThread(runnable)));
}
category.AppendLiteral("javascript");
nsCOMPtr<nsIConsoleService> consoleService =
do_GetService(NS_CONSOLESERVICE_CONTRACTID);
MOZ_ASSERT(consoleService);
nsCOMPtr<nsIScriptError> scriptError =
do_CreateInstance(NS_SCRIPTERROR_CONTRACTID);
MOZ_ASSERT(consoleService);
if (mFactory->GetParentObject()) {
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(
scriptError->InitWithWindowID(localizedMessage,
aFilename,
/* aSourceLine */ EmptyString(),
aLineNumber,
/* aColumnNumber */ 0,
nsIScriptError::warningFlag,
category,
mFactory->InnerWindowID())));
} else {
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(
scriptError->Init(localizedMessage,
aFilename,
/* aSourceLine */ EmptyString(),
aLineNumber,
/* aColumnNumber */ 0,
nsIScriptError::warningFlag,
category.get())));
}
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(consoleService->LogMessage(scriptError)));
}
NS_IMPL_ADDREF_INHERITED(IDBDatabase, IDBWrapperCache)
@ -1295,7 +1333,13 @@ IDBDatabase::LastRelease()
nsresult
IDBDatabase::PostHandleEvent(EventChainPostVisitor& aVisitor)
{
return IndexedDatabaseManager::FireWindowOnError(GetOwner(), aVisitor);
nsresult rv =
IndexedDatabaseManager::CommonPostHandleEvent(this, mFactory, aVisitor);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
return NS_OK;
}
JSObject*
@ -1304,6 +1348,32 @@ IDBDatabase::WrapObject(JSContext* aCx)
return IDBDatabaseBinding::Wrap(aCx, this);
}
NS_IMPL_ISUPPORTS(CancelableRunnableWrapper, nsIRunnable, nsICancelableRunnable)
NS_IMETHODIMP
CancelableRunnableWrapper::Run()
{
nsCOMPtr<nsIRunnable> runnable;
mRunnable.swap(runnable);
if (runnable) {
return runnable->Run();
}
return NS_OK;
}
NS_IMETHODIMP
CancelableRunnableWrapper::Cancel()
{
if (mRunnable) {
mRunnable = nullptr;
return NS_OK;
}
return NS_ERROR_UNEXPECTED;
}
CreateFileHelper::CreateFileHelper(IDBDatabase* aDatabase,
IDBRequest* aRequest,
const nsAString& aName,
@ -1486,6 +1556,84 @@ CreateFileHelper::Run()
return NS_OK;
}
// static
void
IDBDatabase::
LogWarningRunnable::LogWarning(const char* aMessageName,
const nsAString& aFilename,
uint32_t aLineNumber,
bool aIsChrome,
uint64_t aInnerWindowID)
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(aMessageName);
nsXPIDLString localizedMessage;
if (NS_WARN_IF(NS_FAILED(
nsContentUtils::GetLocalizedString(nsContentUtils::eDOM_PROPERTIES,
aMessageName,
localizedMessage)))) {
return;
}
nsAutoCString category;
if (aIsChrome) {
category.AssignLiteral("chrome ");
} else {
category.AssignLiteral("content ");
}
category.AppendLiteral("javascript");
nsCOMPtr<nsIConsoleService> consoleService =
do_GetService(NS_CONSOLESERVICE_CONTRACTID);
MOZ_ASSERT(consoleService);
nsCOMPtr<nsIScriptError> scriptError =
do_CreateInstance(NS_SCRIPTERROR_CONTRACTID);
MOZ_ASSERT(consoleService);
if (aInnerWindowID) {
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(
scriptError->InitWithWindowID(localizedMessage,
aFilename,
/* aSourceLine */ EmptyString(),
aLineNumber,
/* aColumnNumber */ 0,
nsIScriptError::warningFlag,
category,
aInnerWindowID)));
} else {
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(
scriptError->Init(localizedMessage,
aFilename,
/* aSourceLine */ EmptyString(),
aLineNumber,
/* aColumnNumber */ 0,
nsIScriptError::warningFlag,
category.get())));
}
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(consoleService->LogMessage(scriptError)));
}
NS_IMPL_ISUPPORTS_INHERITED0(IDBDatabase::LogWarningRunnable, nsRunnable)
NS_IMETHODIMP
IDBDatabase::
LogWarningRunnable::Run()
{
MOZ_ASSERT(NS_IsMainThread());
LogWarning(mMessageName.get(),
mFilename,
mLineNumber,
mIsChrome,
mInnerWindowID);
return NS_OK;
}
NS_IMPL_ISUPPORTS(IDBDatabase::Observer, nsIObserver)
NS_IMETHODIMP

View File

@ -52,6 +52,9 @@ class IDBDatabase MOZ_FINAL
typedef mozilla::dom::StorageType StorageType;
typedef mozilla::dom::quota::PersistenceType PersistenceType;
class LogWarningRunnable;
friend class LogWarningRunnable;
class Observer;
friend class Observer;

View File

@ -33,18 +33,12 @@ CreateGenericEvent(EventTarget* aOwner,
Bubbles aBubbles,
Cancelable aCancelable)
{
nsCOMPtr<nsIDOMEvent> event;
nsresult rv = NS_NewDOMEvent(getter_AddRefs(event), aOwner, nullptr, nullptr);
if (NS_WARN_IF(NS_FAILED(rv))) {
return nullptr;
}
nsRefPtr<Event> event = new Event(aOwner, nullptr, nullptr);
rv = event->InitEvent(aType,
aBubbles == eDoesBubble ? true : false,
aCancelable == eCancelable ? true : false);
if (NS_WARN_IF(NS_FAILED(rv))) {
return nullptr;
}
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(
event->InitEvent(aType,
aBubbles == eDoesBubble ? true : false,
aCancelable == eCancelable ? true : false)));
event->SetTrusted(true);
@ -64,10 +58,7 @@ IDBVersionChangeEvent::CreateInternal(EventTarget* aOwner,
event->mNewVersion.SetValue(aNewVersion.Value());
}
nsresult rv = event->InitEvent(aType, false, false);
if (NS_WARN_IF(NS_FAILED(rv))) {
return nullptr;
}
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(event->InitEvent(aType, false, false)));
event->SetTrusted(true);

View File

@ -18,12 +18,18 @@
#include "mozilla/ipc/BackgroundUtils.h"
#include "mozilla/ipc/PBackground.h"
#include "mozilla/ipc/PBackgroundChild.h"
#include "mozIThirdPartyUtil.h"
#include "nsAboutProtocolUtils.h"
#include "nsContentUtils.h"
#include "nsGlobalWindow.h"
#include "nsIAboutModule.h"
#include "nsIIPCBackgroundChildCreateCallback.h"
#include "nsILoadContext.h"
#include "nsIPrincipal.h"
#include "nsIURI.h"
#include "nsIUUIDGenerator.h"
#include "nsIWebNavigation.h"
#include "nsSandboxFlags.h"
#include "nsServiceManagerUtils.h"
#include "ProfilerHelpers.h"
#include "ReportInternalError.h"
@ -46,33 +52,6 @@ namespace {
const char kPrefIndexedDBEnabled[] = "dom.indexedDB.enabled";
nsresult
GetPrincipalInfoFromPrincipal(nsIPrincipal* aPrincipal,
PrincipalInfo* aPrincipalInfo)
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(aPrincipal);
MOZ_ASSERT(aPrincipalInfo);
bool isNullPrincipal;
nsresult rv = aPrincipal->GetIsNullPrincipal(&isNullPrincipal);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
if (isNullPrincipal) {
NS_WARNING("IndexedDB not supported from this principal!");
IDB_REPORT_INTERNAL_ERR();
return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
}
rv = PrincipalToPrincipalInfo(aPrincipal, aPrincipalInfo);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
return NS_OK;
}
} // anonymous namespace
class IDBFactory::BackgroundCreateCallback MOZ_FINAL
@ -155,44 +134,43 @@ IDBFactory::CreateForWindow(nsPIDOMWindow* aWindow,
return NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR;
}
nsCOMPtr<nsIScriptObjectPrincipal> sop = do_QueryInterface(aWindow);
if (NS_WARN_IF(!sop)) {
IDB_REPORT_INTERNAL_ERR();
return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
}
nsCOMPtr<nsIPrincipal> principal = sop->GetPrincipal();
if (NS_WARN_IF(!principal)) {
IDB_REPORT_INTERNAL_ERR();
return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
}
nsAutoPtr<PrincipalInfo> principalInfo(new PrincipalInfo());
if (NS_WARN_IF(NS_FAILED(GetPrincipalInfoFromPrincipal(principal,
principalInfo)))) {
// Not allowed.
nsCOMPtr<nsIPrincipal> principal;
nsresult rv = AllowedForWindowInternal(aWindow, getter_AddRefs(principal));
if (rv == NS_ERROR_DOM_NOT_SUPPORTED_ERR) {
NS_WARNING("IndexedDB is not permitted in a third-party window.");
*aFactory = nullptr;
return NS_OK;
}
IndexedDatabaseManager* mgr = IndexedDatabaseManager::GetOrCreate();
if (NS_WARN_IF(!mgr)) {
if (NS_WARN_IF(NS_FAILED(rv))) {
if (rv == NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR) {
IDB_REPORT_INTERNAL_ERR();
}
return rv;
}
MOZ_ASSERT(principal);
nsAutoPtr<PrincipalInfo> principalInfo(new PrincipalInfo());
rv = PrincipalToPrincipalInfo(principal, principalInfo);
if (NS_WARN_IF(NS_FAILED(rv))) {
IDB_REPORT_INTERNAL_ERR();
return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
}
MOZ_ASSERT(principalInfo->type() == PrincipalInfo::TContentPrincipalInfo ||
principalInfo->type() == PrincipalInfo::TSystemPrincipalInfo);
nsCOMPtr<nsIWebNavigation> webNav = do_GetInterface(aWindow);
nsCOMPtr<nsILoadContext> loadContext = do_QueryInterface(webNav);
bool privateBrowsingMode = loadContext && loadContext->UsePrivateBrowsing();
nsRefPtr<IDBFactory> factory = new IDBFactory();
factory->mPrincipalInfo = Move(principalInfo);
factory->mWindow = aWindow;
factory->mTabChild = TabChild::GetFrom(aWindow);
factory->mInnerWindowID = aWindow->WindowID();
factory->mPrivateBrowsingMode = privateBrowsingMode;
factory->mPrivateBrowsingMode =
loadContext && loadContext->UsePrivateBrowsing();
factory.forget(aFactory);
return NS_OK;
@ -211,7 +189,7 @@ IDBFactory::CreateForChromeJS(JSContext* aCx,
new PrincipalInfo(SystemPrincipalInfo()));
nsresult rv =
CreateForJSInternal(aCx, aOwningObject, principalInfo, aFactory);
CreateForMainThreadJSInternal(aCx, aOwningObject, principalInfo, aFactory);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
@ -221,6 +199,7 @@ IDBFactory::CreateForChromeJS(JSContext* aCx,
return NS_OK;
}
// static
nsresult
IDBFactory::CreateForDatastore(JSContext* aCx,
JS::Handle<JSObject*> aOwningObject,
@ -235,7 +214,7 @@ IDBFactory::CreateForDatastore(JSContext* aCx,
new PrincipalInfo(SystemPrincipalInfo()));
nsresult rv =
CreateForJSInternal(aCx, aOwningObject, principalInfo, aFactory);
CreateForMainThreadJSInternal(aCx, aOwningObject, principalInfo, aFactory);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
@ -247,22 +226,42 @@ IDBFactory::CreateForDatastore(JSContext* aCx,
// static
nsresult
IDBFactory::CreateForJSInternal(JSContext* aCx,
JS::Handle<JSObject*> aOwningObject,
nsAutoPtr<PrincipalInfo>& aPrincipalInfo,
IDBFactory** aFactory)
IDBFactory::CreateForWorker(JSContext* aCx,
JS::Handle<JSObject*> aOwningObject,
const PrincipalInfo& aPrincipalInfo,
uint64_t aInnerWindowID,
IDBFactory** aFactory)
{
MOZ_ASSERT(aCx);
MOZ_ASSERT(aOwningObject);
MOZ_ASSERT(aPrincipalInfo);
MOZ_ASSERT(aFactory);
MOZ_ASSERT(JS_GetGlobalForObject(aCx, aOwningObject) == aOwningObject,
"Not a global object!");
MOZ_ASSERT(!NS_IsMainThread());
MOZ_ASSERT(aPrincipalInfo.type() != PrincipalInfo::T__None);
if (!NS_IsMainThread()) {
MOZ_CRASH("Not yet supported off the main thread!");
nsAutoPtr<PrincipalInfo> principalInfo(new PrincipalInfo(aPrincipalInfo));
nsresult rv =
CreateForJSInternal(aCx,
aOwningObject,
principalInfo,
aInnerWindowID,
aFactory);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
MOZ_ASSERT(!principalInfo);
return NS_OK;
}
// static
nsresult
IDBFactory::CreateForMainThreadJSInternal(
JSContext* aCx,
JS::Handle<JSObject*> aOwningObject,
nsAutoPtr<PrincipalInfo>& aPrincipalInfo,
IDBFactory** aFactory)
{
MOZ_ASSERT(NS_IsMainThread());
if (NS_WARN_IF(!Preferences::GetBool(kPrefIndexedDBEnabled, false))) {
*aFactory = nullptr;
return NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR;
@ -274,15 +273,152 @@ IDBFactory::CreateForJSInternal(JSContext* aCx,
return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
}
nsresult rv =
CreateForJSInternal(aCx,
aOwningObject,
aPrincipalInfo,
/* aInnerWindowID */ 0,
aFactory);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
return NS_OK;
}
// static
nsresult
IDBFactory::CreateForJSInternal(JSContext* aCx,
JS::Handle<JSObject*> aOwningObject,
nsAutoPtr<PrincipalInfo>& aPrincipalInfo,
uint64_t aInnerWindowID,
IDBFactory** aFactory)
{
MOZ_ASSERT(aCx);
MOZ_ASSERT(aOwningObject);
MOZ_ASSERT(aPrincipalInfo);
MOZ_ASSERT(aPrincipalInfo->type() != PrincipalInfo::T__None);
MOZ_ASSERT(aFactory);
MOZ_ASSERT(JS_GetGlobalForObject(aCx, aOwningObject) == aOwningObject,
"Not a global object!");
if (aPrincipalInfo->type() != PrincipalInfo::TContentPrincipalInfo &&
aPrincipalInfo->type() != PrincipalInfo::TSystemPrincipalInfo) {
NS_WARNING("IndexedDB not allowed for this principal!");
*aFactory = nullptr;
return NS_OK;
}
nsRefPtr<IDBFactory> factory = new IDBFactory();
factory->mPrincipalInfo = aPrincipalInfo.forget();
factory->mOwningObject = aOwningObject;
mozilla::HoldJSObjects(factory.get());
factory->mInnerWindowID = aInnerWindowID;
factory.forget(aFactory);
return NS_OK;
}
// static
bool
IDBFactory::AllowedForWindow(nsPIDOMWindow* aWindow)
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(aWindow);
MOZ_ASSERT(aWindow->IsInnerWindow());
nsCOMPtr<nsIPrincipal> principal;
nsresult rv = AllowedForWindowInternal(aWindow, getter_AddRefs(principal));
if (NS_WARN_IF(NS_FAILED(rv))) {
return false;
}
return true;
}
// static
nsresult
IDBFactory::AllowedForWindowInternal(nsPIDOMWindow* aWindow,
nsIPrincipal** aPrincipal)
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(aWindow);
MOZ_ASSERT(aWindow->IsInnerWindow());
if (NS_WARN_IF(!IndexedDatabaseManager::GetOrCreate())) {
return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
}
nsIDocument* document = aWindow->GetExtantDoc();
if (document->GetSandboxFlags() & SANDBOXED_ORIGIN) {
return NS_ERROR_DOM_SECURITY_ERR;
}
nsCOMPtr<nsIScriptObjectPrincipal> sop = do_QueryInterface(aWindow);
MOZ_ASSERT(sop);
nsCOMPtr<nsIPrincipal> principal = sop->GetPrincipal();
if (NS_WARN_IF(!principal)) {
return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
}
if (nsContentUtils::IsSystemPrincipal(principal)) {
principal.forget(aPrincipal);
return NS_OK;
}
bool isNullPrincipal;
if (NS_WARN_IF(NS_FAILED(principal->GetIsNullPrincipal(&isNullPrincipal))) ||
isNullPrincipal) {
return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
}
// Whitelist about:home, since it doesn't have a base domain it would not
// pass the ThirdPartyUtil check, though it should be able to use indexedDB.
bool skipThirdPartyCheck = false;
nsCOMPtr<nsIURI> uri;
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(principal->GetURI(getter_AddRefs(uri))));
bool isAbout;
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(uri->SchemeIs("about", &isAbout)));
if (isAbout) {
nsCOMPtr<nsIAboutModule> module;
if (NS_SUCCEEDED(NS_GetAboutModule(uri, getter_AddRefs(module)))) {
uint32_t flags;
if (NS_SUCCEEDED(module->GetURIFlags(uri, &flags))) {
skipThirdPartyCheck = flags & nsIAboutModule::ENABLE_INDEXED_DB;
} else {
NS_WARNING("GetURIFlags failed!");
}
} else {
NS_WARNING("NS_GetAboutModule failed!");
}
}
if (!skipThirdPartyCheck) {
nsCOMPtr<mozIThirdPartyUtil> thirdPartyUtil =
do_GetService(THIRDPARTYUTIL_CONTRACTID);
MOZ_ASSERT(thirdPartyUtil);
bool isThirdParty;
if (NS_WARN_IF(NS_FAILED(
thirdPartyUtil->IsThirdPartyWindow(aWindow,
nullptr,
&isThirdParty)))) {
return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
}
if (isThirdParty) {
return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
}
}
principal.forget(aPrincipal);
return NS_OK;
}
#ifdef DEBUG
void
@ -468,8 +604,15 @@ IDBFactory::OpenInternal(nsIPrincipal* aPrincipal,
}
MOZ_ASSERT(nsContentUtils::IsCallerChrome());
if (NS_WARN_IF(NS_FAILED(GetPrincipalInfoFromPrincipal(aPrincipal,
&principalInfo)))) {
if (NS_WARN_IF(NS_FAILED(PrincipalToPrincipalInfo(aPrincipal,
&principalInfo)))) {
IDB_REPORT_INTERNAL_ERR();
aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
return nullptr;
}
if (principalInfo.type() != PrincipalInfo::TContentPrincipalInfo &&
principalInfo.type() != PrincipalInfo::TSystemPrincipalInfo) {
IDB_REPORT_INTERNAL_ERR();
aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
return nullptr;
@ -626,8 +769,6 @@ IDBFactory::BackgroundActorCreated(PBackgroundChild* aBackgroundActor,
{
BackgroundFactoryChild* actor = new BackgroundFactoryChild(this);
MOZ_ASSERT(NS_IsMainThread(), "Fix this windowId stuff for workers!");
mBackgroundActor =
static_cast<BackgroundFactoryChild*>(
aBackgroundActor->SendPBackgroundIDBFactoryConstructor(actor,

View File

@ -35,6 +35,7 @@ class PrincipalInfo;
namespace dom {
struct IDBOpenDBOptions;
template <typename> class Optional;
class TabChild;
namespace indexedDB {
@ -94,6 +95,16 @@ public:
JS::Handle<JSObject*> aOwningObject,
IDBFactory** aFactory);
static nsresult
CreateForWorker(JSContext* aCx,
JS::Handle<JSObject*> aOwningObject,
const PrincipalInfo& aPrincipalInfo,
uint64_t aInnerWindowID,
IDBFactory** aFactory);
static bool
AllowedForWindow(nsPIDOMWindow* aWindow);
void
AssertIsOnOwningThread() const
#ifdef DEBUG
@ -197,12 +208,23 @@ private:
IDBFactory();
~IDBFactory();
static nsresult
CreateForMainThreadJSInternal(JSContext* aCx,
JS::Handle<JSObject*> aOwningObject,
nsAutoPtr<PrincipalInfo>& aPrincipalInfo,
IDBFactory** aFactory);
static nsresult
CreateForJSInternal(JSContext* aCx,
JS::Handle<JSObject*> aOwningObject,
nsAutoPtr<PrincipalInfo>& aPrincipalInfo,
uint64_t aInnerWindowID,
IDBFactory** aFactory);
static nsresult
AllowedForWindowInternal(nsPIDOMWindow* aWindow,
nsIPrincipal** aPrincipal);
already_AddRefed<IDBOpenDBRequest>
OpenInternal(nsIPrincipal* aPrincipal,
const nsAString& aName,

View File

@ -43,6 +43,8 @@
#include "nsCOMPtr.h"
#include "ProfilerHelpers.h"
#include "ReportInternalError.h"
#include "WorkerPrivate.h"
#include "WorkerScope.h"
// Include this last to avoid path problems on Windows.
#include "ActorsChild.h"
@ -52,6 +54,7 @@ namespace dom {
namespace indexedDB {
using namespace mozilla::dom::quota;
using namespace mozilla::dom::workers;
using namespace mozilla::ipc;
struct IDBObjectStore::StructuredCloneWriteInfo
@ -295,8 +298,6 @@ StructuredCloneWriteCallback(JSContext* aCx,
return true;
}
MOZ_ASSERT(NS_IsMainThread(), "This can't work off the main thread!");
{
File* blob = nullptr;
if (NS_SUCCEEDED(UNWRAP_OBJECT(Blob, aObj, blob))) {
@ -605,16 +606,23 @@ public:
aData.tag == SCTAG_DOM_BLOB);
MOZ_ASSERT(aFile.mFile);
MOZ_ASSERT(NS_IsMainThread(),
"This wrapping currently only works on the main thread!");
// It can happen that this IDB is chrome code, so there is no parent, but
// still we want to set a correct parent for the new File object.
nsCOMPtr<nsISupports> parent;
if (aDatabase && aDatabase->GetParentObject()) {
parent = aDatabase->GetParentObject();
if (NS_IsMainThread()) {
if (aDatabase && aDatabase->GetParentObject()) {
parent = aDatabase->GetParentObject();
} else {
parent = xpc::NativeGlobal(JS::CurrentGlobalOrNull(aCx));
}
} else {
parent = xpc::NativeGlobal(JS::CurrentGlobalOrNull(aCx));
WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate();
MOZ_ASSERT(workerPrivate);
WorkerGlobalScope* globalScope = workerPrivate->GlobalScope();
MOZ_ASSERT(globalScope);
parent = do_QueryObject(globalScope);
}
MOZ_ASSERT(parent);
@ -974,9 +982,6 @@ IDBObjectStore::ClearCloneReadInfo(StructuredCloneReadInfo& aReadInfo)
return;
}
// If there's something to clear, we should be on the main thread.
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
ClearStructuredCloneBuffer(aReadInfo.mCloneBuffer);
aReadInfo.mFiles.Clear();
}
@ -1515,8 +1520,6 @@ IDBObjectStore::GetKeyPath(JSContext* aCx,
JS::MutableHandle<JS::Value> aResult,
ErrorResult& aRv)
{
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
if (!mCachedKeyPath.isUndefined()) {
JS::ExposeValueToActiveJS(mCachedKeyPath);
aResult.set(mCachedKeyPath);

View File

@ -14,9 +14,11 @@
#include "IDBIndex.h"
#include "IDBObjectStore.h"
#include "IDBTransaction.h"
#include "IndexedDatabaseManager.h"
#include "mozilla/ContentEvents.h"
#include "mozilla/ErrorResult.h"
#include "mozilla/EventDispatcher.h"
#include "mozilla/Move.h"
#include "mozilla/dom/DOMError.h"
#include "mozilla/dom/ErrorEventBinding.h"
#include "mozilla/dom/IDBOpenDBRequestBinding.h"
@ -28,6 +30,8 @@
#include "nsPIDOMWindow.h"
#include "nsString.h"
#include "ReportInternalError.h"
#include "WorkerFeature.h"
#include "WorkerPrivate.h"
// Include this last to avoid path problems on Windows.
#include "ActorsChild.h"
@ -36,6 +40,7 @@ namespace mozilla {
namespace dom {
namespace indexedDB {
using namespace mozilla::dom::workers;
using namespace mozilla::ipc;
IDBRequest::IDBRequest(IDBDatabase* aDatabase)
@ -223,9 +228,7 @@ IDBRequest::DispatchNonTransactionError(nsresult aErrorCode)
nsDependentString(kErrorEventType),
eDoesBubble,
eCancelable);
if (NS_WARN_IF(!event)) {
return;
}
MOZ_ASSERT(event);
bool ignored;
if (NS_FAILED(DispatchEvent(event, &ignored))) {
@ -259,6 +262,15 @@ IDBRequest::GetErrorCode() const
return mErrorCode;
}
DOMError*
IDBRequest::GetErrorAfterResult() const
{
AssertIsOnOwningThread();
MOZ_ASSERT(mHaveResultOrErrorCode);
return mError;
}
#endif // DEBUG
void
@ -419,6 +431,36 @@ IDBRequest::PreHandleEvent(EventChainPreVisitor& aVisitor)
return NS_OK;
}
class IDBOpenDBRequest::WorkerFeature MOZ_FINAL
: public mozilla::dom::workers::WorkerFeature
{
WorkerPrivate* mWorkerPrivate;
public:
explicit
WorkerFeature(WorkerPrivate* aWorkerPrivate)
: mWorkerPrivate(aWorkerPrivate)
{
MOZ_ASSERT(aWorkerPrivate);
aWorkerPrivate->AssertIsOnWorkerThread();
MOZ_COUNT_CTOR(IDBOpenDBRequest::WorkerFeature);
}
~WorkerFeature()
{
mWorkerPrivate->AssertIsOnWorkerThread();
MOZ_COUNT_DTOR(IDBOpenDBRequest::WorkerFeature);
mWorkerPrivate->RemoveFeature(mWorkerPrivate->GetJSContext(), this);
}
private:
virtual bool
Notify(JSContext* aCx, Status aStatus) MOZ_OVERRIDE;
};
IDBOpenDBRequest::IDBOpenDBRequest(IDBFactory* aFactory, nsPIDOMWindow* aOwner)
: IDBRequest(aOwner)
, mFactory(aFactory)
@ -467,6 +509,23 @@ IDBOpenDBRequest::CreateForJS(IDBFactory* aFactory,
request->SetScriptOwner(aScriptOwner);
if (!NS_IsMainThread()) {
WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate();
MOZ_ASSERT(workerPrivate);
workerPrivate->AssertIsOnWorkerThread();
JSContext* cx = workerPrivate->GetJSContext();
MOZ_ASSERT(cx);
nsAutoPtr<WorkerFeature> feature(new WorkerFeature(workerPrivate));
if (NS_WARN_IF(!workerPrivate->AddFeature(cx, feature))) {
return nullptr;
}
request->mWorkerFeature = Move(feature);
}
return request.forget();
}
@ -480,6 +539,17 @@ IDBOpenDBRequest::SetTransaction(IDBTransaction* aTransaction)
mTransaction = aTransaction;
}
void
IDBOpenDBRequest::NoteComplete()
{
AssertIsOnOwningThread();
MOZ_ASSERT_IF(!NS_IsMainThread(), mWorkerFeature);
// If we have a WorkerFeature installed on the worker then nulling this out
// will uninstall it from the worker.
mWorkerFeature = nullptr;
}
NS_IMPL_CYCLE_COLLECTION_CLASS(IDBOpenDBRequest)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(IDBOpenDBRequest,
@ -501,10 +571,13 @@ NS_IMPL_RELEASE_INHERITED(IDBOpenDBRequest, IDBRequest)
nsresult
IDBOpenDBRequest::PostHandleEvent(EventChainPostVisitor& aVisitor)
{
// XXX Fix me!
MOZ_ASSERT(NS_IsMainThread());
nsresult rv =
IndexedDatabaseManager::CommonPostHandleEvent(this, mFactory, aVisitor);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
return IndexedDatabaseManager::FireWindowOnError(GetOwner(), aVisitor);
return NS_OK;
}
JSObject*
@ -515,6 +588,20 @@ IDBOpenDBRequest::WrapObject(JSContext* aCx)
return IDBOpenDBRequestBinding::Wrap(aCx, this);
}
bool
IDBOpenDBRequest::
WorkerFeature::Notify(JSContext* aCx, Status aStatus)
{
MOZ_ASSERT(mWorkerPrivate);
mWorkerPrivate->AssertIsOnWorkerThread();
MOZ_ASSERT(aStatus > Running);
// There's nothing we can really do here at the moment...
NS_WARNING("Worker closing but IndexedDB is waiting to open a database!");
return true;
}
} // namespace indexedDB
} // namespace dom
} // namespace mozilla

View File

@ -114,6 +114,16 @@ public:
}
#endif
DOMError*
GetErrorAfterResult() const
#ifdef DEBUG
;
#else
{
return mError;
}
#endif
DOMError*
GetError(ErrorResult& aRv);
@ -212,9 +222,13 @@ protected:
class IDBOpenDBRequest MOZ_FINAL
: public IDBRequest
{
class WorkerFeature;
// Only touched on the owning thread.
nsRefPtr<IDBFactory> mFactory;
nsAutoPtr<WorkerFeature> mWorkerFeature;
public:
static already_AddRefed<IDBOpenDBRequest>
CreateForWindow(IDBFactory* aFactory,
@ -228,16 +242,13 @@ public:
void
SetTransaction(IDBTransaction* aTransaction);
void
NoteComplete();
// nsIDOMEventTarget
virtual nsresult
PostHandleEvent(EventChainPostVisitor& aVisitor) MOZ_OVERRIDE;
DOMError*
GetError(ErrorResult& aRv)
{
return IDBRequest::GetError(aRv);
}
IDBFactory*
Factory() const
{

View File

@ -24,6 +24,8 @@
#include "nsWidgetsCID.h"
#include "ProfilerHelpers.h"
#include "ReportInternalError.h"
#include "WorkerFeature.h"
#include "WorkerPrivate.h"
// Include this last to avoid path problems on Windows.
#include "ActorsChild.h"
@ -32,14 +34,75 @@ namespace mozilla {
namespace dom {
namespace indexedDB {
using namespace mozilla::dom::workers;
using namespace mozilla::ipc;
namespace {
NS_DEFINE_CID(kAppShellCID, NS_APPSHELL_CID);
bool
RunBeforeNextEvent(IDBTransaction* aTransaction)
{
MOZ_ASSERT(aTransaction);
if (NS_IsMainThread()) {
nsCOMPtr<nsIAppShell> appShell = do_GetService(kAppShellCID);
MOZ_ASSERT(appShell);
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(appShell->RunBeforeNextEvent(aTransaction)));
return true;
}
WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate();
MOZ_ASSERT(workerPrivate);
if (NS_WARN_IF(!workerPrivate->RunBeforeNextEvent(aTransaction))) {
return false;
}
return true;
}
} // anonymous namespace
class IDBTransaction::WorkerFeature MOZ_FINAL
: public mozilla::dom::workers::WorkerFeature
{
WorkerPrivate* mWorkerPrivate;
// The IDBTransaction owns this object so we only need a weak reference back
// to it.
IDBTransaction* mTransaction;
public:
WorkerFeature(WorkerPrivate* aWorkerPrivate, IDBTransaction* aTransaction)
: mWorkerPrivate(aWorkerPrivate)
, mTransaction(aTransaction)
{
MOZ_ASSERT(aWorkerPrivate);
MOZ_ASSERT(aTransaction);
aWorkerPrivate->AssertIsOnWorkerThread();
aTransaction->AssertIsOnOwningThread();
MOZ_COUNT_CTOR(IDBTransaction::WorkerFeature);
}
~WorkerFeature()
{
mWorkerPrivate->AssertIsOnWorkerThread();
MOZ_COUNT_DTOR(IDBTransaction::WorkerFeature);
mWorkerPrivate->RemoveFeature(mWorkerPrivate->GetJSContext(), this);
}
private:
virtual bool
Notify(JSContext* aCx, Status aStatus) MOZ_OVERRIDE;
};
IDBTransaction::IDBTransaction(IDBDatabase* aDatabase,
const nsTArray<nsString>& aObjectStoreNames,
Mode aMode)
@ -55,6 +118,7 @@ IDBTransaction::IDBTransaction(IDBDatabase* aDatabase,
, mReadyState(IDBTransaction::INITIAL)
, mMode(aMode)
, mCreating(false)
, mRegistered(false)
, mAbortedByScript(false)
#ifdef DEBUG
, mSentCommitOrAbort(false)
@ -110,11 +174,16 @@ IDBTransaction::~IDBTransaction()
mBackgroundActor.mNormalBackgroundActor,
mFiredCompleteOrAbort);
mDatabase->UnregisterTransaction(this);
if (mRegistered) {
mDatabase->UnregisterTransaction(this);
#ifdef DEBUG
mRegistered = false;
#endif
}
if (mMode == VERSION_CHANGE) {
if (auto* actor = mBackgroundActor.mVersionChangeBackgroundActor) {
actor->SendDeleteMeInternal();
actor->SendDeleteMeInternal(/* aFailedConstructor */ false);
MOZ_ASSERT(!mBackgroundActor.mVersionChangeBackgroundActor,
"SendDeleteMeInternal should have cleared!");
@ -151,22 +220,24 @@ IDBTransaction::CreateVersionChange(
&transaction->mLineNo);
transaction->SetScriptOwner(aDatabase->GetScriptOwner());
transaction->mBackgroundActor.mVersionChangeBackgroundActor = aActor;
transaction->mNextObjectStoreId = aNextObjectStoreId;
transaction->mNextIndexId = aNextIndexId;
// XXX Fix!
MOZ_ASSERT(NS_IsMainThread(), "This won't work on non-main threads!");
nsCOMPtr<nsIAppShell> appShell = do_GetService(kAppShellCID);
if (NS_WARN_IF(!appShell) ||
NS_WARN_IF(NS_FAILED(appShell->RunBeforeNextEvent(transaction)))) {
if (NS_WARN_IF(!RunBeforeNextEvent(transaction))) {
MOZ_ASSERT(!NS_IsMainThread());
#ifdef DEBUG
// Silence assertions.
transaction->mSentCommitOrAbort = true;
#endif
aActor->SendDeleteMeInternal(/* aFailedConstructor */ true);
return nullptr;
}
transaction->mBackgroundActor.mVersionChangeBackgroundActor = aActor;
transaction->mNextObjectStoreId = aNextObjectStoreId;
transaction->mNextIndexId = aNextIndexId;
transaction->mCreating = true;
aDatabase->RegisterTransaction(transaction);
transaction->mRegistered = true;
return transaction.forget();
}
@ -188,18 +259,28 @@ IDBTransaction::Create(IDBDatabase* aDatabase,
transaction->SetScriptOwner(aDatabase->GetScriptOwner());
// XXX Fix!
MOZ_ASSERT(NS_IsMainThread(), "This won't work on non-main threads!");
nsCOMPtr<nsIAppShell> appShell = do_GetService(kAppShellCID);
if (NS_WARN_IF(!appShell) ||
NS_WARN_IF(NS_FAILED(appShell->RunBeforeNextEvent(transaction)))) {
if (NS_WARN_IF(!RunBeforeNextEvent(transaction))) {
MOZ_ASSERT(!NS_IsMainThread());
return nullptr;
}
transaction->mCreating = true;
aDatabase->RegisterTransaction(transaction);
transaction->mRegistered = true;
if (!NS_IsMainThread()) {
WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate();
MOZ_ASSERT(workerPrivate);
workerPrivate->AssertIsOnWorkerThread();
JSContext* cx = workerPrivate->GetJSContext();
MOZ_ASSERT(cx);
transaction->mWorkerFeature = new WorkerFeature(workerPrivate, transaction);
MOZ_ALWAYS_TRUE(workerPrivate->AddFeature(cx, transaction->mWorkerFeature));
}
return transaction.forget();
}
@ -679,12 +760,16 @@ IDBTransaction::FireCompleteOrAbortEvents(nsresult aResult)
mFiredCompleteOrAbort = true;
#endif
// Make sure we drop the WorkerFeature when this function completes.
nsAutoPtr<WorkerFeature> workerFeature = Move(mWorkerFeature);
nsCOMPtr<nsIDOMEvent> event;
if (NS_SUCCEEDED(aResult)) {
event = CreateGenericEvent(this,
nsDependentString(kCompleteEventType),
eDoesNotBubble,
eNotCancelable);
MOZ_ASSERT(event);
} else {
if (!mError && !mAbortedByScript) {
mError = new DOMError(GetOwner(), aResult);
@ -694,10 +779,7 @@ IDBTransaction::FireCompleteOrAbortEvents(nsresult aResult)
nsDependentString(kAbortEventType),
eDoesBubble,
eNotCancelable);
}
if (NS_WARN_IF(!event)) {
return;
MOZ_ASSERT(event);
}
if (NS_SUCCEEDED(mAbortCode)) {
@ -910,6 +992,27 @@ IDBTransaction::Run()
return NS_OK;
}
bool
IDBTransaction::
WorkerFeature::Notify(JSContext* aCx, Status aStatus)
{
MOZ_ASSERT(mWorkerPrivate);
mWorkerPrivate->AssertIsOnWorkerThread();
MOZ_ASSERT(aStatus > Running);
if (mTransaction && aStatus > Terminating) {
mTransaction->AssertIsOnOwningThread();
nsRefPtr<IDBTransaction> transaction = mTransaction;
mTransaction = nullptr;
IDB_REPORT_INTERNAL_ERR();
transaction->AbortInternal(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR, nullptr);
}
return true;
}
} // namespace indexedDB
} // namespace dom
} // namespace mozilla

View File

@ -49,6 +49,9 @@ class IDBTransaction MOZ_FINAL
: public IDBWrapperCache
, public nsIRunnable
{
class WorkerFeature;
friend class WorkerFeature;
public:
enum Mode
{
@ -74,6 +77,7 @@ private:
nsTArray<nsString> mObjectStoreNames;
nsTArray<nsRefPtr<IDBObjectStore>> mObjectStores;
nsTArray<nsRefPtr<IDBObjectStore>> mDeletedObjectStores;
nsAutoPtr<WorkerFeature> mWorkerFeature;
// Tagged with mMode. If mMode is VERSION_CHANGE then mBackgroundActor will be
// a BackgroundVersionChangeTransactionChild. Otherwise it will be a
@ -99,6 +103,7 @@ private:
Mode mMode;
bool mCreating;
bool mRegistered;
bool mAbortedByScript;
#ifdef DEBUG

View File

@ -16,21 +16,22 @@
#include "mozilla/ClearOnShutdown.h"
#include "mozilla/CondVar.h"
#include "mozilla/ContentEvents.h"
#include "mozilla/EventDispatcher.h"
#include "mozilla/Preferences.h"
#include "mozilla/Services.h"
#include "mozilla/dom/ContentChild.h"
#include "mozilla/dom/DOMError.h"
#include "mozilla/dom/ErrorEvent.h"
#include "mozilla/dom/ErrorEventBinding.h"
#include "mozilla/dom/PBlobChild.h"
#include "mozilla/dom/quota/OriginOrPatternString.h"
#include "mozilla/dom/quota/QuotaManager.h"
#include "mozilla/dom/quota/Utilities.h"
#include "mozilla/dom/TabContext.h"
#include "mozilla/EventDispatcher.h"
#include "mozilla/ipc/BackgroundChild.h"
#include "mozilla/ipc/PBackgroundChild.h"
#include "mozilla/Services.h"
#include "mozilla/Preferences.h"
#include "mozilla/storage.h"
#include "nsContentUtils.h"
#include "nsGlobalWindow.h"
#include "nsThreadUtils.h"
#include "prlog.h"
@ -39,6 +40,8 @@
#include "IDBKeyRange.h"
#include "IDBRequest.h"
#include "ProfilerHelpers.h"
#include "WorkerScope.h"
#include "WorkerPrivate.h"
// Bindings for ResolveConstructors
#include "mozilla/dom/IDBCursorBinding.h"
@ -65,6 +68,7 @@ namespace dom {
namespace indexedDB {
using namespace mozilla::dom::quota;
using namespace mozilla::dom::workers;
class FileManagerInfo
{
@ -116,6 +120,7 @@ namespace {
#define IDB_PREF_BRANCH_ROOT "dom.indexedDB."
const char kTestingPref[] = IDB_PREF_BRANCH_ROOT "testing";
const char kPrefExperimental[] = IDB_PREF_BRANCH_ROOT "experimental";
#define IDB_PREF_LOGGING_BRANCH_ROOT IDB_PREF_BRANCH_ROOT "logging."
@ -130,11 +135,12 @@ const char kPrefLoggingProfiler[] =
#undef IDB_PREF_LOGGING_BRANCH_ROOT
#undef IDB_PREF_BRANCH_ROOT
mozilla::StaticRefPtr<IndexedDatabaseManager> gDBManager;
StaticRefPtr<IndexedDatabaseManager> gDBManager;
mozilla::Atomic<bool> gInitialized(false);
mozilla::Atomic<bool> gClosed(false);
mozilla::Atomic<bool> gTestingMode(false);
Atomic<bool> gInitialized(false);
Atomic<bool> gClosed(false);
Atomic<bool> gTestingMode(false);
Atomic<bool> gExperimentalFeaturesEnabled(false);
class AsyncDeleteFileRunnable MOZ_FINAL : public nsIRunnable
{
@ -198,13 +204,12 @@ private:
};
void
TestingPrefChangedCallback(const char* aPrefName, void* aClosure)
AtomicBoolPrefChangedCallback(const char* aPrefName, void* aClosure)
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(!strcmp(aPrefName, kTestingPref));
MOZ_ASSERT(!aClosure);
MOZ_ASSERT(aClosure);
gTestingMode = Preferences::GetBool(aPrefName);
*static_cast<Atomic<bool>*>(aClosure) = Preferences::GetBool(aPrefName);
}
} // anonymous namespace
@ -297,18 +302,9 @@ IndexedDatabaseManager::Init()
{
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
// Make sure that the quota manager is up.
QuotaManager* qm = QuotaManager::GetOrCreate();
NS_ENSURE_STATE(qm);
// During Init() we can't yet call IsMainProcess(), just check sIsMainProcess
// directly.
if (sIsMainProcess) {
// Must initialize the storage service on the main thread.
nsCOMPtr<mozIStorageService> ss =
do_GetService(MOZ_STORAGE_SERVICE_CONTRACTID);
NS_ENSURE_STATE(ss);
nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
NS_ENSURE_STATE(obs);
@ -317,8 +313,12 @@ IndexedDatabaseManager::Init()
NS_ENSURE_SUCCESS(rv, rv);
}
Preferences::RegisterCallbackAndCall(TestingPrefChangedCallback,
kTestingPref);
Preferences::RegisterCallbackAndCall(AtomicBoolPrefChangedCallback,
kTestingPref,
&gTestingMode);
Preferences::RegisterCallbackAndCall(AtomicBoolPrefChangedCallback,
kPrefExperimental,
&gExperimentalFeaturesEnabled);
// By default IndexedDB uses SQLite with PRAGMA synchronous = NORMAL. This
// guarantees (unlike synchronous = OFF) atomicity and consistency, but not
@ -349,7 +349,12 @@ IndexedDatabaseManager::Destroy()
NS_ERROR("Shutdown more than once?!");
}
Preferences::UnregisterCallback(TestingPrefChangedCallback, kTestingPref);
Preferences::UnregisterCallback(AtomicBoolPrefChangedCallback,
kTestingPref,
&gTestingMode);
Preferences::UnregisterCallback(AtomicBoolPrefChangedCallback,
kPrefExperimental,
&gExperimentalFeaturesEnabled);
Preferences::UnregisterCallback(LoggingModePrefChangedCallback,
kPrefLoggingDetails);
@ -365,13 +370,14 @@ IndexedDatabaseManager::Destroy()
// static
nsresult
IndexedDatabaseManager::FireWindowOnError(nsPIDOMWindow* aOwner,
EventChainPostVisitor& aVisitor)
IndexedDatabaseManager::CommonPostHandleEvent(
DOMEventTargetHelper* aEventTarget,
IDBFactory* aFactory,
EventChainPostVisitor& aVisitor)
{
NS_ENSURE_TRUE(aVisitor.mDOMEvent, NS_ERROR_UNEXPECTED);
if (!aOwner) {
return NS_OK;
}
MOZ_ASSERT(aEventTarget);
MOZ_ASSERT(aFactory);
MOZ_ASSERT(aVisitor.mDOMEvent);
if (aVisitor.mEventStatus == nsEventStatus_eConsumeNoDefault) {
return NS_OK;
@ -379,23 +385,25 @@ IndexedDatabaseManager::FireWindowOnError(nsPIDOMWindow* aOwner,
nsString type;
nsresult rv = aVisitor.mDOMEvent->GetType(type);
NS_ENSURE_SUCCESS(rv, rv);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
if (nsDependentString(kErrorEventType) != type) {
NS_NAMED_LITERAL_STRING(errorType, "error");
MOZ_ASSERT(nsDependentString(kErrorEventType) == errorType);
if (type != errorType) {
return NS_OK;
}
nsCOMPtr<EventTarget> eventTarget =
aVisitor.mDOMEvent->InternalDOMEvent()->GetTarget();
MOZ_ASSERT(eventTarget);
IDBRequest* request = static_cast<IDBRequest*>(eventTarget.get());
NS_ENSURE_TRUE(request, NS_ERROR_UNEXPECTED);
auto* request = static_cast<IDBRequest*>(eventTarget.get());
ErrorResult ret;
nsRefPtr<DOMError> error = request->GetError(ret);
if (ret.Failed()) {
return ret.ErrorCode();
}
nsRefPtr<DOMError> error = request->GetErrorAfterResult();
nsString errorName;
if (error) {
@ -410,40 +418,91 @@ IndexedDatabaseManager::FireWindowOnError(nsPIDOMWindow* aOwner,
init.mCancelable = true;
init.mBubbles = true;
nsCOMPtr<nsIScriptGlobalObject> sgo(do_QueryInterface(aOwner));
NS_ASSERTION(sgo, "How can this happen?!");
nsEventStatus status = nsEventStatus_eIgnore;
if (NS_FAILED(sgo->HandleScriptError(init, &status))) {
NS_WARNING("Failed to dispatch script error event");
status = nsEventStatus_eIgnore;
if (NS_IsMainThread()) {
if (nsPIDOMWindow* window = aEventTarget->GetOwner()) {
nsCOMPtr<nsIScriptGlobalObject> sgo = do_QueryInterface(window);
MOZ_ASSERT(sgo);
if (NS_WARN_IF(NS_FAILED(sgo->HandleScriptError(init, &status)))) {
status = nsEventStatus_eIgnore;
}
} else {
// We don't fire error events at any global for non-window JS on the main
// thread.
}
} else {
// Not on the main thread, must be in a worker.
WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate();
MOZ_ASSERT(workerPrivate);
nsRefPtr<WorkerGlobalScope> globalScope = workerPrivate->GlobalScope();
MOZ_ASSERT(globalScope);
nsRefPtr<ErrorEvent> errorEvent =
ErrorEvent::Constructor(globalScope, errorType, init);
MOZ_ASSERT(errorEvent);
errorEvent->SetTrusted(true);
auto* target = static_cast<EventTarget*>(globalScope.get());
if (NS_WARN_IF(NS_FAILED(
EventDispatcher::DispatchDOMEvent(target,
/* aWidgetEvent */ nullptr,
errorEvent,
/* aPresContext */ nullptr,
&status)))) {
status = nsEventStatus_eIgnore;
}
}
bool preventDefaultCalled = status == nsEventStatus_eConsumeNoDefault;
if (preventDefaultCalled) {
if (status == nsEventStatus_eConsumeNoDefault) {
return NS_OK;
}
// Log an error to the error console.
nsCOMPtr<nsIScriptError> scriptError =
do_CreateInstance(NS_SCRIPTERROR_CONTRACTID, &rv);
NS_ENSURE_SUCCESS(rv, rv);
nsAutoCString category;
if (aFactory->IsChrome()) {
category.AssignLiteral("chrome ");
} else {
category.AssignLiteral("content ");
}
category.AppendLiteral("javascript");
if (NS_FAILED(scriptError->InitWithWindowID(errorName,
init.mFilename,
EmptyString(), init.mLineno,
0, 0,
"IndexedDB",
aOwner->WindowID()))) {
NS_WARNING("Failed to init script error!");
return NS_ERROR_FAILURE;
// Log the error to the error console.
nsCOMPtr<nsIConsoleService> consoleService =
do_GetService(NS_CONSOLESERVICE_CONTRACTID);
MOZ_ASSERT(consoleService);
nsCOMPtr<nsIScriptError> scriptError =
do_CreateInstance(NS_SCRIPTERROR_CONTRACTID);
MOZ_ASSERT(consoleService);
if (uint64_t innerWindowID = aFactory->InnerWindowID()) {
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(
scriptError->InitWithWindowID(errorName,
init.mFilename,
/* aSourceLine */ EmptyString(),
init.mLineno,
/* aColumnNumber */ 0,
nsIScriptError::errorFlag,
category,
innerWindowID)));
} else {
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(
scriptError->Init(errorName,
init.mFilename,
/* aSourceLine */ EmptyString(),
init.mLineno,
/* aColumnNumber */ 0,
nsIScriptError::errorFlag,
category.get())));
}
nsCOMPtr<nsIConsoleService> consoleService =
do_GetService(NS_CONSOLESERVICE_CONTRACTID, &rv);
NS_ENSURE_SUCCESS(rv, rv);
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(consoleService->LogMessage(scriptError)));
return consoleService->LogMessage(scriptError);
return NS_OK;
}
// static
@ -475,6 +534,12 @@ IndexedDatabaseManager::DefineIndexedDB(JSContext* aCx,
MOZ_ASSERT(js::GetObjectClass(aGlobal)->flags & JSCLASS_DOM_GLOBAL,
"Passed object is not a global object!");
// We need to ensure that the manager has been created already here so that we
// load preferences that may control which properties are exposed.
if (NS_WARN_IF(!GetOrCreate())) {
return false;
}
if (!IDBCursorBinding::GetConstructorObject(aCx, aGlobal) ||
!IDBCursorWithValueBinding::GetConstructorObject(aCx, aGlobal) ||
!IDBDatabaseBinding::GetConstructorObject(aCx, aGlobal) ||
@ -582,6 +647,24 @@ IndexedDatabaseManager::FullSynchronous()
return sFullSynchronousMode;
}
// static
bool
IndexedDatabaseManager::ExperimentalFeaturesEnabled(JSContext* aCx,
JSObject* aGlobal)
{
if (NS_IsMainThread()) {
if (NS_WARN_IF(!GetOrCreate())) {
return false;
}
} else {
MOZ_ASSERT(Get(),
"ExperimentalFeaturesEnabled() called off the main thread "
"before indexedDB has been initialized!");
}
return gExperimentalFeaturesEnabled;
}
already_AddRefed<FileManager>
IndexedDatabaseManager::GetFileManager(PersistenceType aPersistenceType,
const nsACString& aOrigin,

View File

@ -21,6 +21,7 @@ struct PRLogModuleInfo;
namespace mozilla {
class DOMEventTargetHelper;
class EventChainPostVisitor;
namespace dom {
@ -31,6 +32,7 @@ namespace indexedDB {
class FileManager;
class FileManagerInfo;
class IDBFactory;
class IndexedDatabaseManager MOZ_FINAL : public nsIObserver
{
@ -106,6 +108,9 @@ public:
}
#endif
static bool
ExperimentalFeaturesEnabled(JSContext* aCx, JSObject* aGlobal);
already_AddRefed<FileManager>
GetFileManager(PersistenceType aPersistenceType,
const nsACString& aOrigin,
@ -153,8 +158,9 @@ public:
}
static nsresult
FireWindowOnError(nsPIDOMWindow* aOwner,
EventChainPostVisitor& aVisitor);
CommonPostHandleEvent(DOMEventTargetHelper* aEventTarget,
IDBFactory* aFactory,
EventChainPostVisitor& aVisitor);
static bool
TabContextMayAccessOrigin(const mozilla::dom::TabContext& aContext,

View File

@ -94,6 +94,7 @@ LOCAL_INCLUDES += [
'/db/sqlite3/src',
'/dom/base',
'/dom/storage',
'/dom/workers',
'/ipc/glue',
'/xpcom/build',
]

View File

@ -44,39 +44,167 @@ function clearAllDatabases(callback) {
SpecialPowers.clearStorageForURI(document.documentURI, callback, appId, inBrowser);
}
let testHarnessGenerator = testHarnessSteps();
testHarnessGenerator.next();
function testHarnessSteps() {
function nextTestHarnessStep(val) {
testHarnessGenerator.send(val);
}
let testScriptPath;
let testScriptFilename;
let scripts = document.getElementsByTagName("script");
for (let i = 0; i < scripts.length; i++) {
let src = scripts[i].src;
let match = src.match(/indexedDB\/test\/unit\/(test_[^\/]+\.js)$/);
if (match && match.length == 2) {
testScriptPath = src;
testScriptFilename = match[1];
break;
}
}
let limitedQuota = yield undefined;
info("Running" +
(testScriptFilename ? " '" + testScriptFilename + "'" : "") +
" with " +
(limitedQuota ? "" : "un") + "limited quota");
info("Pushing preferences");
SpecialPowers.pushPrefEnv(
{
"set": [
["dom.indexedDB.testing", true],
["dom.indexedDB.experimental", true],
["dom.archivereader.enabled", true],
["dom.workers.latestJSVersion", true]
]
},
nextTestHarnessStep
);
yield undefined;
info("Pushing permissions");
SpecialPowers.pushPermissions(
[
{
type: "indexedDB",
allow: true,
context: document
}, {
type: "indexedDB-unlimited",
allow: !limitedQuota,
context: document
}
],
nextTestHarnessStep
);
yield undefined;
info("Clearing old databases");
clearAllDatabases(nextTestHarnessStep);
yield undefined;
if (testScriptFilename && !window.disableWorkerTest) {
info("Running test in a worker");
let workerScriptBlob =
new Blob([ "(" + workerScript.toString() + ")();" ],
{ type: "text/javascript;version=1.7" });
let workerScriptURL = URL.createObjectURL(workerScriptBlob);
let worker = new Worker(workerScriptURL);
worker.onerror = function(event) {
ok(false, "Worker had an error: " + event.message);
worker.terminate();
nextTestHarnessStep();
};
worker.onmessage = function(event) {
let message = event.data;
switch (message.op) {
case "ok":
ok(message.condition, message.name, message.diag);
break;
case "todo":
todo(message.condition, message.name, message.diag);
break;
case "info":
info(message.msg);
break;
case "ready":
worker.postMessage({ op: "load", files: [ testScriptPath ] });
break;
case "loaded":
worker.postMessage({ op: "start" });
break;
case "done":
ok(true, "Worker finished");
nextTestHarnessStep();
break;
default:
ok(false,
"Received a bad message from worker: " + JSON.stringify(message));
nextTestHarnessStep();
}
};
URL.revokeObjectURL(workerScriptURL);
yield undefined;
worker.terminate();
worker = null;
clearAllDatabases(nextTestHarnessStep);
yield undefined;
} else if (testScriptFilename) {
todo(false,
"Skipping test in a worker because it is explicitly disabled: " +
disableWorkerTest);
} else {
todo(false,
"Skipping test in a worker because it's not structured properly");
}
info("Running test in main thread");
// Now run the test script in the main thread.
testGenerator.next();
yield undefined;
}
if (!window.runTest) {
window.runTest = function(limitedQuota)
{
SimpleTest.waitForExplicitFinish();
allowIndexedDB();
if (limitedQuota) {
denyUnlimitedQuota();
}
else {
allowUnlimitedQuota();
}
enableTesting();
enableExperimental();
enableArchiveReader();
clearAllDatabases(function () { testGenerator.next(); });
testHarnessGenerator.send(limitedQuota);
}
}
function finishTest()
{
resetArchiveReader();
resetExperimental();
resetTesting();
resetUnlimitedQuota();
resetIndexedDB();
SpecialPowers.notifyObserversInParentProcess(null, "disk-space-watcher",
SpecialPowers.notifyObserversInParentProcess(null,
"disk-space-watcher",
"free");
SimpleTest.executeSoon(function() {
testGenerator.close();
testHarnessGenerator.close();
clearAllDatabases(function() { SimpleTest.finish(); });
});
}
@ -154,26 +282,26 @@ ExpectError.prototype = {
}
};
function compareKeys(k1, k2) {
let t = typeof k1;
if (t != typeof k2)
function compareKeys(_k1_, _k2_) {
let t = typeof _k1_;
if (t != typeof _k2_)
return false;
if (t !== "object")
return k1 === k2;
return _k1_ === _k2_;
if (k1 instanceof Date) {
return (k2 instanceof Date) &&
k1.getTime() === k2.getTime();
if (_k1_ instanceof Date) {
return (_k2_ instanceof Date) &&
_k1_.getTime() === _k2_.getTime();
}
if (k1 instanceof Array) {
if (!(k2 instanceof Array) ||
k1.length != k2.length)
if (_k1_ instanceof Array) {
if (!(_k2_ instanceof Array) ||
_k1_.length != _k2_.length)
return false;
for (let i = 0; i < k1.length; ++i) {
if (!compareKeys(k1[i], k2[i]))
for (let i = 0; i < _k1_.length; ++i) {
if (!compareKeys(_k1_[i], _k2_[i]))
return false;
}
@ -183,14 +311,6 @@ function compareKeys(k1, k2) {
return false;
}
function addPermission(type, allow, url)
{
if (!url) {
url = window.document;
}
SpecialPowers.addPermission(type, allow, url);
}
function removePermission(type, url)
{
if (!url) {
@ -199,62 +319,6 @@ function removePermission(type, url)
SpecialPowers.removePermission(type, url);
}
function allowIndexedDB(url)
{
addPermission("indexedDB", true, url);
}
function resetIndexedDB(url)
{
removePermission("indexedDB", url);
}
function allowUnlimitedQuota(url)
{
addPermission("indexedDB-unlimited", true, url);
}
function denyUnlimitedQuota(url)
{
addPermission("indexedDB-unlimited", false, url);
}
function resetUnlimitedQuota(url)
{
removePermission("indexedDB-unlimited", url);
}
function enableArchiveReader()
{
archiveReaderEnabled = SpecialPowers.getBoolPref("dom.archivereader.enabled");
SpecialPowers.setBoolPref("dom.archivereader.enabled", true);
}
function resetArchiveReader()
{
SpecialPowers.setBoolPref("dom.archivereader.enabled", archiveReaderEnabled);
}
function enableExperimental()
{
SpecialPowers.setBoolPref("dom.indexedDB.experimental", true);
}
function resetExperimental()
{
SpecialPowers.clearUserPref("dom.indexedDB.experimental");
}
function enableTesting()
{
SpecialPowers.setBoolPref("dom.indexedDB.testing", true);
}
function resetTesting()
{
SpecialPowers.clearUserPref("dom.indexedDB.testing");
}
function gc()
{
SpecialPowers.forceGC();
@ -265,3 +329,188 @@ function scheduleGC()
{
SpecialPowers.exactGC(window, continueToNextStep);
}
function workerScript() {
"use strict";
self.repr = function(_thing_) {
if (typeof(_thing_) == "undefined") {
return "undefined";
}
if (o === null) {
return "null";
}
let str;
try {
str = _thing_ + "";
} catch (e) {
return "[" + typeof(_thing_) + "]";
}
if (typeof(_thing_) == "function") {
str = str.replace(/^\s+/, "");
let idx = str.indexOf("{");
if (idx != -1) {
str = str.substr(0, idx) + "{...}";
}
}
return str;
};
self.ok = function(_condition_, _name_, _diag_) {
self.postMessage({ op: "ok",
condition: !!_condition_,
name: _name_,
diag: _diag_ });
};
self.is = function(_a_, _b_, _name_) {
let pass = (_a_ == _b_);
let diag = pass ? "" : "got " + repr(_a_) + ", expected " + repr(_b_);
ok(pass, _name_, diag);
};
self.isnot = function(_a_, _b_, _name_) {
let pass = (_a_ != _b_);
let diag = pass ? "" : "didn't expect " + repr(_a_) + ", but got it";
ok(pass, _name_, diag);
};
self.todo = function(_condition_, _name_, _diag_) {
self.postMessage({ op: "todo",
condition: !!_condition_,
name: _name_,
diag: _diag_ });
};
self.info = function(_msg_) {
self.postMessage({ op: "info", msg: _msg_ });
};
self.executeSoon = function(_fun_) {
setTimeout(_fun_, 0);
};
self.finishTest = function() {
self.postMessage({ op: "done" });
};
self.grabEventAndContinueHandler = function(_event_) {
testGenerator.send(_event_);
};
self.continueToNextStep = function() {
executeSoon(function() {
testGenerator.next();
});
};
self.continueToNextStepSync = function() {
testGenerator.next();
};
self.errorHandler = function(_event_) {
ok(false, "indexedDB error, '" + _event_.target.error.name + "'");
finishTest();
};
self.unexpectedSuccessHandler = function()
{
ok(false, "Got success, but did not expect it!");
finishTest();
};
self.expectedErrorHandler = function(_name_)
{
return function(_event_) {
is(_event_.type, "error", "Got an error event");
is(_event_.target.error.name, _name_, "Expected error was thrown.");
_event_.preventDefault();
grabEventAndContinueHandler(_event_);
};
};
self.ExpectError = function(_name_, _preventDefault_)
{
this._name = _name_;
this._preventDefault = _preventDefault_;
}
self.ExpectError.prototype = {
handleEvent: function(_event_)
{
is(_event_.type, "error", "Got an error event");
is(_event_.target.error.name, this._name, "Expected error was thrown.");
if (this._preventDefault) {
_event_.preventDefault();
_event_.stopPropagation();
}
grabEventAndContinueHandler(_event_);
}
};
self.compareKeys = function(_k1_, _k2_) {
let t = typeof _k1_;
if (t != typeof _k2_)
return false;
if (t !== "object")
return _k1_ === _k2_;
if (_k1_ instanceof Date) {
return (_k2_ instanceof Date) &&
_k1_.getTime() === _k2_.getTime();
}
if (_k1_ instanceof Array) {
if (!(_k2_ instanceof Array) ||
_k1_.length != _k2_.length)
return false;
for (let i = 0; i < _k1_.length; ++i) {
if (!compareKeys(_k1_[i], _k2_[i]))
return false;
}
return true;
}
return false;
}
self.onerror = function(_message_, _file_, _line_) {
ok(false,
"Worker: uncaught exception [" + _file_ + ":" + _line_ + "]: '" +
_message_ + "'");
self.finishTest();
self.close();
return true;
};
self.onmessage = function(_event_) {
let message = _event_.data;
switch (message.op) {
case "load":
info("Worker: loading " + JSON.stringify(message.files));
self.importScripts(message.files);
self.postMessage({ op: "loaded" });
break;
case "start":
executeSoon(function() {
info("Worker: starting tests");
testGenerator.next();
});
break;
default:
throw new Error("Received a bad message from parent: " +
JSON.stringify(message));
}
};
self.postMessage({ op: "ready" });
}

View File

@ -27,7 +27,6 @@
let iframe = document.getElementById("iframe1");
window.addEventListener("message", grabEventAndContinueHandler, false);
// Put it in a different origin to be safe
//allowUnlimitedQuota("http://example.org/");
iframe.src = //"http://example.org" +
window.location.pathname.replace(
"test_blob_worker_crash.html",

View File

@ -3,6 +3,8 @@
* http://creativecommons.org/publicdomain/zero/1.0/
*/
let disableWorkerTest = "Need to implement a gc() function for worker tests";
if (!this.window) {
this.runTest = function() {
todo(false, "Test disabled in xpcshell test suite for now");
@ -373,7 +375,7 @@ function testSteps()
yield undefined; yield undefined;
db.close();
SpecialPowers.gc();
gc();
openRequest = indexedDB.open(dbname, 2);
openRequest.onerror = errorHandler;

View File

@ -2,6 +2,9 @@
* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/
*/
let disableWorkerTest = "This test uses SpecialPowers";
let testGenerator = testSteps();
function createFileReader() {

View File

@ -3,6 +3,8 @@
* http://creativecommons.org/publicdomain/zero/1.0/
*/
let disableWorkerTest = "Need to implement a gc() function for worker tests";
let testGenerator = testSteps();
function testSteps()

View File

@ -4,6 +4,8 @@
*/
"use strict";
let disableWorkerTest = "This test uses SpecialPowers";
var self = this;
var testGenerator = testSteps();

View File

@ -3,13 +3,6 @@
* http://creativecommons.org/publicdomain/zero/1.0/
*/
if (!this.window) {
this.runTest = function() {
todo(false, "Test disabled in xpcshell test suite for now");
finishTest();
}
}
var testGenerator = testSteps();
function testSteps()

View File

@ -50,6 +50,9 @@ function testSteps()
is(objectStore.indexNames.item(0), indexName, "Correct recreacted name");
is(objectStore.index(indexName), index2, "Correct instance");
event.target.transaction.oncomplete = grabEventAndContinueHandler;
event = yield undefined;
finishTest();
yield undefined;
}

View File

@ -37,6 +37,9 @@ function testSteps()
is(db.objectStoreNames.length, 1, "Correct objectStoreNames list");
is(db.objectStoreNames.item(0), objectStoreName, "Correct name");
event.target.transaction.oncomplete = grabEventAndContinueHandler;
event = yield undefined;
db.close();
request = indexedDB.open(name, 2);
@ -81,6 +84,9 @@ function testSteps()
continueToNextStep();
yield undefined;
trans.oncomplete = grabEventAndContinueHandler;
event = yield undefined;
db.close();
request = indexedDB.open(name, 3);
@ -89,6 +95,7 @@ function testSteps()
event = yield undefined;
db = event.target.result;
trans = event.target.transaction;
objectStore = db.createObjectStore(objectStoreName, { keyPath: "foo" });
@ -100,6 +107,9 @@ function testSteps()
event = yield undefined;
trans.oncomplete = grabEventAndContinueHandler;
event = yield undefined;
finishTest();
yield undefined;
}

View File

@ -49,12 +49,8 @@ function testSteps()
request.onerror = errorHandler;
request.onsuccess = errorHandler;
request.onupgradeneeded = grabEventAndContinueHandler;
if (SpecialPowers.isMainProcess()) {
request.onblocked = errorHandler;
}
else {
todo(false, "Need to fix blocked events in child processes!");
}
request.onblocked = errorHandler;
event = yield undefined;
// Test the upgradeneeded event.
@ -86,12 +82,8 @@ function testSteps()
request = indexedDB.open(name, 2);
request.onerror = errorHandler;
request.onsuccess = grabEventAndContinueHandler;
if (SpecialPowers.isMainProcess()) {
request.onblocked = errorHandler;
}
else {
todo(false, "Need to fix blocked events in child processes!");
}
request.onblocked = errorHandler;
event = yield undefined;
db3 = event.target.result;
@ -130,12 +122,7 @@ function testSteps()
request.onerror = errorHandler;
request.onsuccess = errorHandler;
request.onupgradeneeded = grabEventAndContinueHandler;
if (SpecialPowers.isMainProcess()) {
request.onblocked = errorHandler;
}
else {
todo(false, "Need to fix blocked events in child processes!");
}
request.onblocked = errorHandler;
event = yield undefined;

View File

@ -15,8 +15,6 @@ function abortListener(evt)
function testSteps()
{
const Ci = Components.interfaces;
const name = this.window ? window.location.pathname : "Splendid Test";
let request = indexedDB.open(name, 1);

View File

@ -82,6 +82,18 @@ function testSteps() {
if ("SimpleTest" in this) {
SimpleTest.expectUncaughtException();
} else if ("DedicatedWorkerGlobalScope" in self &&
self instanceof DedicatedWorkerGlobalScope) {
let oldErrorFunction = self.onerror;
self.onerror = function(message, file, line) {
self.onerror = oldErrorFunction;
oldErrorFunction = null;
is(message,
"ConstraintError",
"Got expected ConstraintError on DedicatedWorkerGlobalScope");
return true;
};
}
request = objectStore.add(data, dataKey);

View File

@ -3,6 +3,8 @@
* http://creativecommons.org/publicdomain/zero/1.0/
*/
let disableWorkerTest = "This test uses SpecialPowers";
var testGenerator = testSteps();
function testSteps()

View File

@ -5,6 +5,10 @@
const { 'classes': Cc, 'interfaces': Ci, 'utils': Cu } = Components;
if (!("self" in this)) {
this.self = this;
}
const DOMException = Ci.nsIDOMDOMException;
function is(a, b, msg) {
@ -176,16 +180,6 @@ function disallowIndexedDB(url)
throw "disallowIndexedDB";
}
function allowUnlimitedQuota(url)
{
throw "allowUnlimitedQuota";
}
function disallowUnlimitedQuota(url)
{
throw "disallowUnlimitedQuota";
}
function enableExperimental()
{
SpecialPowers.setBoolPref("dom.indexedDB.experimental", true);

View File

@ -20,7 +20,7 @@ interface nsIURI;
typedef unsigned short CSPDirective;
[scriptable, uuid(69b7663e-117a-4a3b-81bd-d86420b7c79e)]
[scriptable, uuid(68434447-b816-4473-a731-efc4f6d59902)]
interface nsIContentSecurityPolicy : nsISerializable
{
/**
@ -47,6 +47,7 @@ interface nsIContentSecurityPolicy : nsISerializable
const unsigned short REFLECTED_XSS_DIRECTIVE = 12;
const unsigned short BASE_URI_DIRECTIVE = 13;
const unsigned short FORM_ACTION_DIRECTIVE = 14;
const unsigned short REFERRER_DIRECTIVE = 15;
/**
* Accessor method for a read-only string version of the policy at a given
@ -60,6 +61,21 @@ interface nsIContentSecurityPolicy : nsISerializable
*/
readonly attribute unsigned long policyCount;
/**
* Obtains the referrer policy (as integer) for this browsing context as
* specified in CSP. If there are multiple policies and...
* - only one sets a referrer policy: that policy is returned
* - more than one sets different referrer policies: no-referrer is returned
* - more than one set equivalent policies: that policy is returned
* For the enumeration of policies see ReferrerPolicy.h and nsIHttpChannel.
*
* @param aPolicy
* The referrer policy to use for the protected resource.
* @return
* true if a referrer policy is specified, false if it's unspecified.
*/
bool getReferrerPolicy(out unsigned long policy);
/**
* Remove a policy associated with this CSP context.
* @throws NS_ERROR_FAILURE if the index is out of bounds or invalid.

File diff suppressed because it is too large Load Diff

View File

@ -135,7 +135,7 @@ private:
BlobChild(nsIContentChild* aManager, BlobChild* aOther);
BlobChild(PBackgroundChild* aManager, BlobChild* aOther);
BlobChild(PBackgroundChild* aManager, BlobChild* aOther, FileImpl* aBlobImpl);
// These constructors are called on the receiving side.
BlobChild(nsIContentChild* aManager,
@ -160,7 +160,7 @@ private:
CommonInit(FileImpl* aBlobImpl);
void
CommonInit(BlobChild* aOther);
CommonInit(BlobChild* aOther, FileImpl* aBlobImpl);
void
CommonInit(const ChildBlobConstructorParams& aParams);
@ -185,11 +185,13 @@ private:
static BlobChild*
MaybeGetActorFromRemoteBlob(nsIRemoteBlob* aRemoteBlob,
nsIContentChild* aManager);
nsIContentChild* aManager,
FileImpl* aBlobImpl);
static BlobChild*
MaybeGetActorFromRemoteBlob(nsIRemoteBlob* aRemoteBlob,
PBackgroundChild* aManager);
PBackgroundChild* aManager,
FileImpl* aBlobImpl);
void
NoteDyingRemoteBlobImpl();

View File

@ -220,6 +220,12 @@ private:
virtual bool
RecvResolveMystery(const ResolveMysteryParams& aParams) MOZ_OVERRIDE;
virtual bool
RecvBlobStreamSync(const uint64_t& aStart,
const uint64_t& aLength,
InputStreamParams* aParams,
OptionalFileDescriptorSet* aFDs) MOZ_OVERRIDE;
virtual bool
RecvWaitForSliceCreation() MOZ_OVERRIDE;

View File

@ -6,8 +6,10 @@ include protocol PBackground;
include protocol PBlobStream;
include protocol PContent;
include protocol PContentBridge;
include protocol PFileDescriptorSet;
include DOMTypes;
include InputStreamParams;
namespace mozilla {
namespace dom {
@ -31,6 +33,9 @@ parent:
ResolveMystery(ResolveMysteryParams params);
sync BlobStreamSync(uint64_t begin, uint64_t length)
returns (InputStreamParams params, OptionalFileDescriptorSet fds);
sync WaitForSliceCreation();
// Use only for testing!

View File

@ -6,8 +6,6 @@ include protocol PBlob;
include protocol PFileDescriptorSet;
include InputStreamParams;
using mozilla::void_t from "ipc/IPCMessageUtils.h";
namespace mozilla {
namespace dom {

View File

@ -245,11 +245,11 @@ TabChildBase::InitializeRootMetrics()
ParentLayerPoint(),
ParentLayerSize(ViewAs<ParentLayerPixel>(mInnerSize, PixelCastJustification::ScreenIsParentLayerForRoot)));
mLastRootMetrics.SetZoom(mLastRootMetrics.CalculateIntrinsicScale());
mLastRootMetrics.mDevPixelsPerCSSPixel = WebWidget()->GetDefaultScale();
mLastRootMetrics.SetDevPixelsPerCSSPixel(WebWidget()->GetDefaultScale());
// We use ParentLayerToLayerScale(1) below in order to turn the
// async zoom amount into the gecko zoom amount.
mLastRootMetrics.mCumulativeResolution =
mLastRootMetrics.GetZoom() / mLastRootMetrics.mDevPixelsPerCSSPixel * ParentLayerToLayerScale(1);
mLastRootMetrics.GetZoom() / mLastRootMetrics.GetDevPixelsPerCSSPixel() * ParentLayerToLayerScale(1);
// This is the root layer, so the cumulative resolution is the same
// as the resolution.
mLastRootMetrics.mPresShellResolution = mLastRootMetrics.mCumulativeResolution.scale;
@ -384,7 +384,7 @@ TabChildBase::HandlePossibleViewportChange(const ScreenIntSize& aOldScreenSize)
ParentLayerPoint(),
ParentLayerSize(ViewAs<ParentLayerPixel>(mInnerSize, PixelCastJustification::ScreenIsParentLayerForRoot)));
metrics.SetRootCompositionSize(
ScreenSize(mInnerSize) * ScreenToLayoutDeviceScale(1.0f) / metrics.mDevPixelsPerCSSPixel);
ScreenSize(mInnerSize) * ScreenToLayoutDeviceScale(1.0f) / metrics.GetDevPixelsPerCSSPixel());
// This change to the zoom accounts for all types of changes I can conceive:
// 1. screen size changes, CSS viewport does not (pages with no meta viewport
@ -425,13 +425,13 @@ TabChildBase::HandlePossibleViewportChange(const ScreenIntSize& aOldScreenSize)
if (nsIPresShell* shell = document->GetShell()) {
if (nsPresContext* context = shell->GetPresContext()) {
metrics.mDevPixelsPerCSSPixel = CSSToLayoutDeviceScale(
(float)nsPresContext::AppUnitsPerCSSPixel() / context->AppUnitsPerDevPixel());
metrics.SetDevPixelsPerCSSPixel(CSSToLayoutDeviceScale(
(float)nsPresContext::AppUnitsPerCSSPixel() / context->AppUnitsPerDevPixel()));
}
}
metrics.mCumulativeResolution = metrics.GetZoom()
/ metrics.mDevPixelsPerCSSPixel
/ metrics.GetDevPixelsPerCSSPixel()
* ParentLayerToLayerScale(1);
// This is the root layer, so the cumulative resolution is the same
// as the resolution.
@ -468,7 +468,7 @@ TabChildBase::HandlePossibleViewportChange(const ScreenIntSize& aOldScreenSize)
if (viewportInfo.IsZoomAllowed() && scrollIdentifiersValid) {
// If the CSS viewport is narrower than the screen (i.e. width <= device-width)
// then we disable double-tap-to-zoom behaviour.
bool allowDoubleTapZoom = (viewport.width > screenW / metrics.mDevPixelsPerCSSPixel.scale);
bool allowDoubleTapZoom = (viewport.width > screenW / metrics.GetDevPixelsPerCSSPixel().scale);
if (allowDoubleTapZoom != viewportInfo.IsDoubleTapZoomAllowed()) {
viewportInfo.SetAllowDoubleTapZoom(allowDoubleTapZoom);

View File

@ -19,6 +19,7 @@
#include "mozilla/Hal.h"
#include "mozilla/ipc/DocumentRendererParent.h"
#include "mozilla/layers/CompositorParent.h"
#include "mozilla/layers/InputAPZContext.h"
#include "mozilla/layout/RenderFrameParent.h"
#include "mozilla/MouseEvents.h"
#include "mozilla/net/NeckoChild.h"
@ -2103,6 +2104,20 @@ TabParent::MaybeForwardEventToRenderFrame(WidgetInputEvent& aEvent,
ScrollableLayerGuid* aOutTargetGuid,
uint64_t* aOutInputBlockId)
{
if (aEvent.mClass == eWheelEventClass) {
// Wheel events must be sent to APZ directly from the widget. New APZ-
// aware events should follow suit and move there as well. However, we
// do need to inform the child process of the correct target and block
// id.
if (aOutTargetGuid) {
*aOutTargetGuid = InputAPZContext::GetTargetLayerGuid();
}
if (aOutInputBlockId) {
*aOutInputBlockId = InputAPZContext::GetInputBlockId();
}
return nsEventStatus_eIgnore;
}
if (RenderFrameParent* rfp = GetRenderFrame()) {
return rfp->NotifyInputEvent(aEvent, aOutTargetGuid, aOutInputBlockId);
}

View File

@ -114,6 +114,7 @@ LOCAL_INCLUDES += [
'/dom/media/webspeech/synth/ipc',
'/dom/mobilemessage/ipc',
'/dom/storage',
'/dom/workers',
'/editor/libeditor',
'/embedding/components/printingui/ipc',
'/extensions/cookie',

View File

@ -472,6 +472,7 @@ skip-if = true # bug 1021673
[test_seek_out_of_range.html]
skip-if = (toolkit == 'android' && processor == 'x86') #x86 only bug 914439
[test_seek-1.html]
skip-if = android_version == '10' # bug 1059116
[test_seek-2.html]
[test_seek-3.html]
[test_seek-4.html]

View File

@ -1299,6 +1299,32 @@ private:
PromiseWorkerProxy::RunCallbackFunc mFunc;
};
/* static */
already_AddRefed<PromiseWorkerProxy>
PromiseWorkerProxy::Create(WorkerPrivate* aWorkerPrivate,
Promise* aWorkerPromise,
const JSStructuredCloneCallbacks* aCb)
{
MOZ_ASSERT(aWorkerPrivate);
aWorkerPrivate->AssertIsOnWorkerThread();
MOZ_ASSERT(aWorkerPromise);
nsRefPtr<PromiseWorkerProxy> proxy =
new PromiseWorkerProxy(aWorkerPrivate, aWorkerPromise, aCb);
// We do this to make sure the worker thread won't shut down before the
// promise is resolved/rejected on the worker thread.
if (!aWorkerPrivate->AddFeature(aWorkerPrivate->GetJSContext(), proxy)) {
// Probably the worker is terminating. We cannot complete the operation
// and we have to release all the resources.
proxy->mCleanedUp = true;
proxy->mWorkerPromise = nullptr;
return nullptr;
}
return proxy.forget();
}
PromiseWorkerProxy::PromiseWorkerProxy(WorkerPrivate* aWorkerPrivate,
Promise* aWorkerPromise,
const JSStructuredCloneCallbacks* aCallbacks)
@ -1308,16 +1334,6 @@ PromiseWorkerProxy::PromiseWorkerProxy(WorkerPrivate* aWorkerPrivate,
, mCallbacks(aCallbacks)
, mCleanUpLock("cleanUpLock")
{
MOZ_ASSERT(mWorkerPrivate);
mWorkerPrivate->AssertIsOnWorkerThread();
MOZ_ASSERT(mWorkerPromise);
// We do this to make sure the worker thread won't shut down before the
// promise is resolved/rejected on the worker thread.
if (!mWorkerPrivate->AddFeature(mWorkerPrivate->GetJSContext(), this)) {
MOZ_ASSERT(false, "cannot add the worker feature!");
return;
}
}
PromiseWorkerProxy::~PromiseWorkerProxy()
@ -1352,6 +1368,36 @@ PromiseWorkerProxy::StoreISupports(nsISupports* aSupports)
mSupportsArray.AppendElement(supports);
}
namespace {
class PromiseWorkerProxyControlRunnable MOZ_FINAL
: public WorkerControlRunnable
{
nsRefPtr<PromiseWorkerProxy> mProxy;
public:
PromiseWorkerProxyControlRunnable(WorkerPrivate* aWorkerPrivate,
PromiseWorkerProxy* aProxy)
: WorkerControlRunnable(aWorkerPrivate, WorkerThreadUnchangedBusyCount)
, mProxy(aProxy)
{
MOZ_ASSERT(aProxy);
}
virtual bool
WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) MOZ_OVERRIDE
{
mProxy->CleanUp(aCx);
return true;
}
private:
~PromiseWorkerProxyControlRunnable()
{}
};
} // anonymous namespace
void
PromiseWorkerProxy::RunCallback(JSContext* aCx,
JS::Handle<JS::Value> aValue,
@ -1380,7 +1426,11 @@ PromiseWorkerProxy::RunCallback(JSContext* aCx,
Move(buffer),
aFunc);
runnable->Dispatch(aCx);
if (!runnable->Dispatch(aCx)) {
nsRefPtr<WorkerControlRunnable> runnable =
new PromiseWorkerProxyControlRunnable(mWorkerPrivate, this);
mWorkerPrivate->DispatchControlRunnable(runnable);
}
}
void

View File

@ -65,9 +65,10 @@ class PromiseWorkerProxy : public PromiseNativeHandler,
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(PromiseWorkerProxy)
public:
PromiseWorkerProxy(workers::WorkerPrivate* aWorkerPrivate,
Promise* aWorkerPromise,
const JSStructuredCloneCallbacks* aCallbacks = nullptr);
static already_AddRefed<PromiseWorkerProxy>
Create(workers::WorkerPrivate* aWorkerPrivate,
Promise* aWorkerPromise,
const JSStructuredCloneCallbacks* aCallbacks = nullptr);
workers::WorkerPrivate* GetWorkerPrivate() const;
@ -87,6 +88,10 @@ protected:
virtual bool Notify(JSContext* aCx, workers::Status aStatus) MOZ_OVERRIDE;
private:
PromiseWorkerProxy(workers::WorkerPrivate* aWorkerPrivate,
Promise* aWorkerPromise,
const JSStructuredCloneCallbacks* aCallbacks = nullptr);
virtual ~PromiseWorkerProxy();
// Function pointer for calling Promise::{ResolveInternal,RejectInternal}.

View File

@ -36,6 +36,7 @@
#include "nsString.h"
#include "prlog.h"
#include "mozilla/dom/CSPReportBinding.h"
#include "mozilla/net/ReferrerPolicy.h"
using namespace mozilla;
@ -305,6 +306,34 @@ nsCSPContext::GetPolicyCount(uint32_t *outPolicyCount)
return NS_OK;
}
NS_IMETHODIMP
nsCSPContext::GetReferrerPolicy(uint32_t* outPolicy, bool* outIsSet)
{
*outIsSet = false;
*outPolicy = mozilla::net::RP_Default;
nsAutoString refpol;
mozilla::net::ReferrerPolicy previousPolicy = mozilla::net::RP_Default;
for (uint32_t i = 0; i < mPolicies.Length(); i++) {
mPolicies[i]->getReferrerPolicy(refpol);
// an empty string in refpol means it wasn't set (that's the default in
// nsCSPPolicy).
if (!refpol.IsEmpty()) {
// if there are two policies that specify a referrer policy, then they
// must agree or the employed policy is no-referrer.
uint32_t currentPolicy = mozilla::net::ReferrerPolicyFromString(refpol);
if (*outIsSet && previousPolicy != currentPolicy) {
*outPolicy = mozilla::net::RP_No_Referrer;
return NS_OK;
}
*outPolicy = currentPolicy;
*outIsSet = true;
}
}
return NS_OK;
}
NS_IMETHODIMP
nsCSPContext::RemovePolicy(uint32_t aIndex)
{

View File

@ -14,6 +14,7 @@
#include "nsReadableUtils.h"
#include "nsServiceManagerUtils.h"
#include "nsUnicharUtils.h"
#include "mozilla/net/ReferrerPolicy.h"
using namespace mozilla;
@ -857,6 +858,30 @@ nsCSPParser::sourceList(nsTArray<nsCSPBaseSrc*>& outSrcs)
}
}
void
nsCSPParser::referrerDirectiveValue()
{
// directive-value = "none" / "none-when-downgrade" / "origin" / "origin-when-cross-origin" / "unsafe-url"
// directive name is token 0, we need to examine the remaining tokens (and
// there should only be one token in the value).
CSPPARSERLOG(("nsCSPParser::referrerDirectiveValue"));
if (mCurDir.Length() > 2) {
CSPPARSERLOG(("Too many tokens in referrer directive, got %d expected 1",
mCurDir.Length() - 1));
return;
}
if (!mozilla::net::IsValidReferrerPolicy(mCurDir[1])) {
CSPPARSERLOG(("invalid value for referrer directive: %s",
NS_ConvertUTF16toUTF8(mCurDir[1]).get()));
return;
}
// the referrer policy is valid, so go ahead and use it.
mPolicy->setReferrerPolicy(&mCurDir[1]);
}
void
nsCSPParser::reportURIList(nsTArray<nsCSPBaseSrc*>& outSrcs)
{
@ -900,6 +925,14 @@ nsCSPParser::directiveValue(nsTArray<nsCSPBaseSrc*>& outSrcs)
reportURIList(outSrcs);
return;
}
// special case handling of the referrer directive (since it doesn't contain
// source lists)
if (CSP_IsDirective(mCurDir[0], nsIContentSecurityPolicy::REFERRER_DIRECTIVE)) {
referrerDirectiveValue();
return;
}
// Otherwise just forward to sourceList
sourceList(outSrcs);
}

View File

@ -113,6 +113,7 @@ class nsCSPParser {
void directive();
nsCSPDirective* directiveName();
void directiveValue(nsTArray<nsCSPBaseSrc*>& outSrcs);
void referrerDirectiveValue();
void sourceList(nsTArray<nsCSPBaseSrc*>& outSrcs);
nsCSPBaseSrc* sourceExpression();
nsCSPSchemeSrc* schemeSource();

View File

@ -899,7 +899,14 @@ nsCSPPolicy::toString(nsAString& outStr) const
{
uint32_t length = mDirectives.Length();
for (uint32_t i = 0; i < length; ++i) {
mDirectives[i]->toString(outStr);
if (mDirectives[i]->equals(nsIContentSecurityPolicy::REFERRER_DIRECTIVE)) {
outStr.AppendASCII(CSP_CSPDirectiveToString(nsIContentSecurityPolicy::REFERRER_DIRECTIVE));
outStr.AppendASCII(" ");
outStr.Append(mReferrerPolicy);
} else {
mDirectives[i]->toString(outStr);
}
if (i != (length - 1)) {
outStr.AppendASCII("; ");
}

View File

@ -73,7 +73,8 @@ static const char* CSPStrDirectives[] = {
"frame-ancestors", // FRAME_ANCESTORS_DIRECTIVE
"reflected-xss", // REFLECTED_XSS_DIRECTIVE
"base-uri", // BASE_URI_DIRECTIVE
"form-action" // FORM_ACTION_DIRECTIVE
"form-action", // FORM_ACTION_DIRECTIVE
"referrer" // REFERRER_DIRECTIVE
};
inline const char* CSP_CSPDirectiveToString(CSPDirective aDir)
@ -332,6 +333,12 @@ class nsCSPPolicy {
inline bool getReportOnlyFlag() const
{ return mReportOnly; }
inline void setReferrerPolicy(const nsAString* aValue)
{ mReferrerPolicy = *aValue; }
inline void getReferrerPolicy(nsAString& outPolicy) const
{ outPolicy.Assign(mReferrerPolicy); }
void getReportURIs(nsTArray<nsString> &outReportURIs) const;
void getDirectiveStringForContentType(nsContentPolicyType aContentType,
@ -345,6 +352,7 @@ class nsCSPPolicy {
private:
nsTArray<nsCSPDirective*> mDirectives;
bool mReportOnly;
nsString mReferrerPolicy;
};
#endif /* nsCSPUtils_h___ */

View File

@ -199,7 +199,7 @@ SVGContentUtils::GetStrokeOptions(AutoStrokeOptions* aStrokeOptions,
switch (styleSVG->mStrokeLinejoin) {
case NS_STYLE_STROKE_LINEJOIN_MITER:
aStrokeOptions->mLineJoin = JoinStyle::MITER;
aStrokeOptions->mLineJoin = JoinStyle::MITER_OR_BEVEL;
break;
case NS_STYLE_STROKE_LINEJOIN_ROUND:
aStrokeOptions->mLineJoin = JoinStyle::ROUND;

View File

@ -11,7 +11,7 @@
*/
[Constructor(DOMString name, optional DOMString message = ""),
Exposed=(Window,System)]
Exposed=(Window,Worker,System)]
interface DOMError {
[Constant]
readonly attribute DOMString name;

View File

@ -10,6 +10,7 @@
* liability, trademark and document use rules apply.
*/
[Exposed=(Window,Worker)]
interface DOMStringList {
readonly attribute unsigned long length;
getter DOMString? item(unsigned long index);

View File

@ -14,6 +14,7 @@ enum IDBCursorDirection {
"prevunique"
};
[Exposed=(Window,Worker)]
interface IDBCursor {
readonly attribute (IDBObjectStore or IDBIndex) source;

View File

@ -10,6 +10,7 @@
* liability, trademark and document use rules apply.
*/
[Exposed=(Window,Worker)]
interface IDBDatabase : EventTarget {
readonly attribute DOMString name;
readonly attribute unsigned long long version;
@ -40,13 +41,13 @@ interface IDBDatabase : EventTarget {
};
partial interface IDBDatabase {
[Pref="dom.indexedDB.experimental"]
[Func="mozilla::dom::indexedDB::IndexedDatabaseManager::ExperimentalFeaturesEnabled"]
readonly attribute StorageType storage;
[Throws]
[Exposed=Window, Throws]
IDBRequest createMutableFile (DOMString name, optional DOMString type);
// this is deprecated due to renaming in the spec
[Throws]
[Exposed=Window, Throws]
IDBRequest mozCreateFileHandle (DOMString name, optional DOMString type); // now createMutableFile
};

View File

@ -7,7 +7,7 @@
* https://dvcs.w3.org/hg/IndexedDB/raw-file/tip/Overview.html
*/
[NoInterfaceObject]
[Exposed=(Window,Worker), NoInterfaceObject]
interface IDBEnvironment {
//[Throws] readonly attribute IDBFactory indexedDB;
[Throws] readonly attribute IDBFactory? indexedDB;
@ -15,5 +15,6 @@ interface IDBEnvironment {
// Mozilla-specific stuff
partial interface IDBEnvironment {
[Throws] readonly attribute IDBFactory? mozIndexedDB;
[Exposed=Window, Throws]
readonly attribute IDBFactory? mozIndexedDB;
};

View File

@ -23,6 +23,7 @@ dictionary IDBOpenDBOptions
* http://dvcs.w3.org/hg/IndexedDB/raw-file/tip/Overview.html#idl-def-IDBFactory
* for more information.
*/
[Exposed=(Window,Worker)]
interface IDBFactory {
[Throws]
IDBOpenDBRequest

View File

@ -12,6 +12,7 @@ dictionary IDBIndexParameters {
boolean multiEntry = false;
};
[Exposed=(Window,Worker)]
interface IDBIndex {
readonly attribute DOMString name;
readonly attribute IDBObjectStore objectStore;
@ -45,9 +46,11 @@ partial interface IDBIndex {
[Throws]
IDBRequest mozGetAllKeys (optional any key, optional unsigned long limit);
[Pref="dom.indexedDB.experimental", Throws]
[Throws,
Func="mozilla::dom::indexedDB::IndexedDatabaseManager::ExperimentalFeaturesEnabled"]
IDBRequest getAll (optional any key, optional unsigned long limit);
[Pref="dom.indexedDB.experimental", Throws]
[Throws,
Func="mozilla::dom::indexedDB::IndexedDatabaseManager::ExperimentalFeaturesEnabled"]
IDBRequest getAllKeys (optional any key, optional unsigned long limit);
};

View File

@ -9,6 +9,7 @@
* liability, trademark and document use rules apply.
*/
[Exposed=(Window,Worker)]
interface IDBKeyRange {
[Throws]
readonly attribute any lower;

View File

@ -12,6 +12,7 @@ dictionary IDBObjectStoreParameters {
boolean autoIncrement = false;
};
[Exposed=(Window,Worker)]
interface IDBObjectStore {
readonly attribute DOMString name;
@ -64,12 +65,15 @@ partial interface IDBObjectStore {
[Throws]
IDBRequest mozGetAll (optional any key, optional unsigned long limit);
[Pref="dom.indexedDB.experimental", Throws]
[Throws,
Func="mozilla::dom::indexedDB::IndexedDatabaseManager::ExperimentalFeaturesEnabled"]
IDBRequest getAll (optional any key, optional unsigned long limit);
[Pref="dom.indexedDB.experimental", Throws]
[Throws,
Func="mozilla::dom::indexedDB::IndexedDatabaseManager::ExperimentalFeaturesEnabled"]
IDBRequest getAllKeys (optional any key, optional unsigned long limit);
[Pref="dom.indexedDB.experimental", Throws]
[Throws,
Func="mozilla::dom::indexedDB::IndexedDatabaseManager::ExperimentalFeaturesEnabled"]
IDBRequest openKeyCursor (optional any range, optional IDBCursorDirection direction = "next");
};

View File

@ -7,6 +7,7 @@
* https://dvcs.w3.org/hg/IndexedDB/raw-file/tip/Overview.html#idl-def-IDBOpenDBRequest
*/
[Exposed=(Window,Worker)]
interface IDBOpenDBRequest : IDBRequest {
attribute EventHandler onblocked;

View File

@ -13,6 +13,7 @@ enum IDBRequestReadyState {
"done"
};
[Exposed=(Window,Worker)]
interface IDBRequest : EventTarget {
[Throws]
readonly attribute any result;

View File

@ -14,6 +14,7 @@ enum IDBTransactionMode {
"versionchange"
};
[Exposed=(Window,Worker)]
interface IDBTransaction : EventTarget {
[Throws]
readonly attribute IDBTransactionMode mode;

View File

@ -15,7 +15,8 @@ dictionary IDBVersionChangeEventInit : EventInit {
unsigned long long? newVersion = null;
};
[Constructor(DOMString type, optional IDBVersionChangeEventInit eventInitDict)]
[Constructor(DOMString type, optional IDBVersionChangeEventInit eventInitDict),
Exposed=(Window,Worker)]
interface IDBVersionChangeEvent : Event {
readonly attribute unsigned long long oldVersion;
readonly attribute unsigned long long? newVersion;

View File

@ -39,6 +39,7 @@ partial interface WorkerGlobalScope {
WorkerGlobalScope implements WindowTimers;
WorkerGlobalScope implements WindowBase64;
WorkerGlobalScope implements GlobalFetch;
WorkerGlobalScope implements IDBEnvironment;
// Not implemented yet: bug 1072107.
// WorkerGlobalScope implements FontFaceSource;

View File

@ -137,10 +137,40 @@ protected:
}
};
// A DataStoreRunnable to run DataStore::Get(...) on the main thread.
class DataStoreGetRunnable MOZ_FINAL : public DataStoreRunnable
class DataStoreProxyRunnable : public DataStoreRunnable
{
public:
DataStoreProxyRunnable(WorkerPrivate* aWorkerPrivate,
const nsMainThreadPtrHandle<DataStore>& aBackingStore,
Promise* aWorkerPromise)
: DataStoreRunnable(aWorkerPrivate, aBackingStore)
{
MOZ_ASSERT(aWorkerPrivate);
aWorkerPrivate->AssertIsOnWorkerThread();
mPromiseWorkerProxy =
PromiseWorkerProxy::Create(aWorkerPrivate, aWorkerPromise);
}
bool Dispatch(JSContext* aCx)
{
if (mPromiseWorkerProxy) {
return DataStoreRunnable::Dispatch(aCx);
}
// If the creation of mProxyWorkerProxy failed, the worker is terminating.
// In this case we don't want to dispatch the runnable and we should stop
// the promise chain here.
return true;
}
protected:
nsRefPtr<PromiseWorkerProxy> mPromiseWorkerProxy;
};
// A DataStoreRunnable to run DataStore::Get(...) on the main thread.
class DataStoreGetRunnable MOZ_FINAL : public DataStoreProxyRunnable
{
Sequence<OwningStringOrUnsignedLong> mId;
ErrorResult& mRv;
@ -150,7 +180,7 @@ public:
Promise* aWorkerPromise,
const Sequence<OwningStringOrUnsignedLong>& aId,
ErrorResult& aRv)
: DataStoreRunnable(aWorkerPrivate, aBackingStore)
: DataStoreProxyRunnable(aWorkerPrivate, aBackingStore, aWorkerPromise)
, mRv(aRv)
{
MOZ_ASSERT(aWorkerPrivate);
@ -159,9 +189,6 @@ public:
if (!mId.AppendElements(aId)) {
mRv.Throw(NS_ERROR_OUT_OF_MEMORY);
}
mPromiseWorkerProxy =
new PromiseWorkerProxy(aWorkerPrivate, aWorkerPromise);
}
protected:
@ -177,9 +204,8 @@ protected:
};
// A DataStoreRunnable to run DataStore::Put(...) on the main thread.
class DataStorePutRunnable MOZ_FINAL : public DataStoreRunnable
class DataStorePutRunnable MOZ_FINAL : public DataStoreProxyRunnable
{
nsRefPtr<PromiseWorkerProxy> mPromiseWorkerProxy;
JSAutoStructuredCloneBuffer mObjBuffer;
const StringOrUnsignedLong& mId;
const nsString mRevisionId;
@ -194,7 +220,7 @@ public:
const StringOrUnsignedLong& aId,
const nsAString& aRevisionId,
ErrorResult& aRv)
: DataStoreRunnable(aWorkerPrivate, aBackingStore)
: DataStoreProxyRunnable(aWorkerPrivate, aBackingStore, aWorkerPromise)
, mId(aId)
, mRevisionId(aRevisionId)
, mRv(aRv)
@ -207,9 +233,6 @@ public:
JS_ClearPendingException(aCx);
mRv.Throw(NS_ERROR_DOM_DATA_CLONE_ERR);
}
mPromiseWorkerProxy =
new PromiseWorkerProxy(aWorkerPrivate, aWorkerPromise);
}
protected:
@ -244,9 +267,8 @@ protected:
};
// A DataStoreRunnable to run DataStore::Add(...) on the main thread.
class DataStoreAddRunnable MOZ_FINAL : public DataStoreRunnable
class DataStoreAddRunnable MOZ_FINAL : public DataStoreProxyRunnable
{
nsRefPtr<PromiseWorkerProxy> mPromiseWorkerProxy;
JSAutoStructuredCloneBuffer mObjBuffer;
const Optional<StringOrUnsignedLong>& mId;
const nsString mRevisionId;
@ -261,7 +283,7 @@ public:
const Optional<StringOrUnsignedLong>& aId,
const nsAString& aRevisionId,
ErrorResult& aRv)
: DataStoreRunnable(aWorkerPrivate, aBackingStore)
: DataStoreProxyRunnable(aWorkerPrivate, aBackingStore, aWorkerPromise)
, mId(aId)
, mRevisionId(aRevisionId)
, mRv(aRv)
@ -274,9 +296,6 @@ public:
JS_ClearPendingException(aCx);
mRv.Throw(NS_ERROR_DOM_DATA_CLONE_ERR);
}
mPromiseWorkerProxy =
new PromiseWorkerProxy(aWorkerPrivate, aWorkerPromise);
}
protected:
@ -312,9 +331,8 @@ protected:
// A DataStoreRunnable to run DataStore::Remove(...) on the main
// thread.
class DataStoreRemoveRunnable MOZ_FINAL : public DataStoreRunnable
class DataStoreRemoveRunnable MOZ_FINAL : public DataStoreProxyRunnable
{
nsRefPtr<PromiseWorkerProxy> mPromiseWorkerProxy;
const StringOrUnsignedLong& mId;
const nsString mRevisionId;
ErrorResult& mRv;
@ -326,16 +344,13 @@ public:
const StringOrUnsignedLong& aId,
const nsAString& aRevisionId,
ErrorResult& aRv)
: DataStoreRunnable(aWorkerPrivate, aBackingStore)
: DataStoreProxyRunnable(aWorkerPrivate, aBackingStore, aWorkerPromise)
, mId(aId)
, mRevisionId(aRevisionId)
, mRv(aRv)
{
MOZ_ASSERT(aWorkerPrivate);
aWorkerPrivate->AssertIsOnWorkerThread();
mPromiseWorkerProxy =
new PromiseWorkerProxy(aWorkerPrivate, aWorkerPromise);
}
protected:
@ -351,9 +366,8 @@ protected:
};
// A DataStoreRunnable to run DataStore::Clear(...) on the main thread.
class DataStoreClearRunnable MOZ_FINAL : public DataStoreRunnable
class DataStoreClearRunnable MOZ_FINAL : public DataStoreProxyRunnable
{
nsRefPtr<PromiseWorkerProxy> mPromiseWorkerProxy;
const nsString mRevisionId;
ErrorResult& mRv;
@ -363,15 +377,12 @@ public:
Promise* aWorkerPromise,
const nsAString& aRevisionId,
ErrorResult& aRv)
: DataStoreRunnable(aWorkerPrivate, aBackingStore)
: DataStoreProxyRunnable(aWorkerPrivate, aBackingStore, aWorkerPromise)
, mRevisionId(aRevisionId)
, mRv(aRv)
{
MOZ_ASSERT(aWorkerPrivate);
aWorkerPrivate->AssertIsOnWorkerThread();
mPromiseWorkerProxy =
new PromiseWorkerProxy(aWorkerPrivate, aWorkerPromise);
}
protected:
@ -626,9 +637,8 @@ WorkerDataStore::GetRevisionId(JSContext* aCx,
}
// A DataStoreRunnable to run DataStore::GetLength(...) on the main thread.
class DataStoreGetLengthRunnable MOZ_FINAL : public DataStoreRunnable
class DataStoreGetLengthRunnable MOZ_FINAL : public DataStoreProxyRunnable
{
nsRefPtr<PromiseWorkerProxy> mPromiseWorkerProxy;
ErrorResult& mRv;
public:
@ -636,14 +646,11 @@ public:
const nsMainThreadPtrHandle<DataStore>& aBackingStore,
Promise* aWorkerPromise,
ErrorResult& aRv)
: DataStoreRunnable(aWorkerPrivate, aBackingStore)
: DataStoreProxyRunnable(aWorkerPrivate, aBackingStore, aWorkerPromise)
, mRv(aRv)
{
MOZ_ASSERT(aWorkerPrivate);
aWorkerPrivate->AssertIsOnWorkerThread();
mPromiseWorkerProxy =
new PromiseWorkerProxy(aWorkerPrivate, aWorkerPromise);
}
protected:

View File

@ -82,7 +82,19 @@ public:
aWorkerPrivate->AssertIsOnWorkerThread();
mPromiseWorkerProxy =
new PromiseWorkerProxy(aWorkerPrivate, aWorkerPromise);
PromiseWorkerProxy::Create(aWorkerPrivate, aWorkerPromise);
}
bool Dispatch(JSContext* aCx)
{
if (mPromiseWorkerProxy) {
return DataStoreCursorRunnable::Dispatch(aCx);
}
// If the creation of mProxyWorkerProxy failed, the worker is terminating.
// In this case we don't want to dispatch the runnable and we should stop
// the promise chain here.
return true;
}
protected:

View File

@ -223,12 +223,26 @@ public:
MOZ_ASSERT(aWorkerPrivate);
aWorkerPrivate->AssertIsOnWorkerThread();
// this might return null if the worker has started the close handler.
mPromiseWorkerProxy =
new PromiseWorkerProxy(aWorkerPrivate,
aWorkerPromise,
&kGetDataStoresStructuredCloneCallbacks);
PromiseWorkerProxy::Create(aWorkerPrivate,
aWorkerPromise,
&kGetDataStoresStructuredCloneCallbacks);
}
bool Dispatch(JSContext* aCx)
{
if (mPromiseWorkerProxy) {
return WorkerMainThreadRunnable::Dispatch(aCx);
}
// If the creation of mProxyWorkerProxy failed, the worker is terminating.
// In this case we don't want to dispatch the runnable and we should stop
// the promise chain here.
return true;
}
protected:
virtual bool
MainThreadRun() MOZ_OVERRIDE

View File

@ -35,6 +35,8 @@
#include "mozilla/dom/MessageEventBinding.h"
#include "mozilla/dom/WorkerBinding.h"
#include "mozilla/dom/ScriptSettings.h"
#include "mozilla/dom/indexedDB/IndexedDatabaseManager.h"
#include "mozilla/ipc/BackgroundChild.h"
#include "mozilla/DebugOnly.h"
#include "mozilla/Preferences.h"
#include "mozilla/dom/Navigator.h"
@ -71,12 +73,14 @@
using namespace mozilla;
using namespace mozilla::dom;
using namespace mozilla::ipc;
USING_WORKERS_NAMESPACE
using mozilla::MutexAutoLock;
using mozilla::MutexAutoUnlock;
using mozilla::Preferences;
using mozilla::dom::indexedDB::IndexedDatabaseManager;
// The size of the worker runtime heaps in bytes. May be changed via pref.
#define WORKER_DEFAULT_RUNTIME_HEAPSIZE 32 * 1024 * 1024
@ -1121,6 +1125,40 @@ PlatformOverrideChanged(const char* /* aPrefName */, void* /* aClosure */)
}
}
class BackgroundChildCallback MOZ_FINAL
: public nsIIPCBackgroundChildCreateCallback
{
public:
BackgroundChildCallback()
{
AssertIsOnMainThread();
}
NS_DECL_ISUPPORTS
private:
~BackgroundChildCallback()
{
AssertIsOnMainThread();
}
virtual void
ActorCreated(PBackgroundChild* aActor) MOZ_OVERRIDE
{
AssertIsOnMainThread();
MOZ_ASSERT(aActor);
}
virtual void
ActorFailed() MOZ_OVERRIDE
{
AssertIsOnMainThread();
MOZ_CRASH("Unable to connect PBackground actor for the main thread!");
}
};
NS_IMPL_ISUPPORTS(BackgroundChildCallback, nsIIPCBackgroundChildCreateCallback)
} /* anonymous namespace */
BEGIN_WORKERS_NAMESPACE
@ -1639,6 +1677,15 @@ RuntimeService::Init()
nsLayoutStatics::AddRef();
// Make sure PBackground actors are connected as soon as possible for the main
// thread in case workers clone remote blobs here.
if (!BackgroundChild::GetForCurrentThread()) {
nsRefPtr<BackgroundChildCallback> callback = new BackgroundChildCallback();
if (!BackgroundChild::GetOrCreateForCurrentThread(callback)) {
MOZ_CRASH("Unable to connect PBackground actor for the main thread!");
}
}
// Initialize JSSettings.
if (!sDefaultJSSettings.gcSettings[0].IsSet()) {
sDefaultJSSettings.runtimeOptions = JS::RuntimeOptions();
@ -1776,6 +1823,10 @@ RuntimeService::Init()
return rv;
}
if (NS_WARN_IF(!IndexedDatabaseManager::GetOrCreate())) {
return NS_ERROR_UNEXPECTED;
}
return NS_OK;
}
@ -2160,7 +2211,7 @@ RuntimeService::CreateServiceWorker(const GlobalObject& aGlobal,
nsresult
RuntimeService::CreateServiceWorkerFromLoadInfo(JSContext* aCx,
WorkerPrivate::LoadInfo aLoadInfo,
WorkerPrivate::LoadInfo* aLoadInfo,
const nsAString& aScriptURL,
const nsACString& aScope,
ServiceWorker** aServiceWorker)
@ -2205,21 +2256,21 @@ RuntimeService::CreateSharedWorkerInternal(const GlobalObject& aGlobal,
false, &loadInfo);
NS_ENSURE_SUCCESS(rv, rv);
return CreateSharedWorkerFromLoadInfo(cx, loadInfo, aScriptURL, aName, aType,
return CreateSharedWorkerFromLoadInfo(cx, &loadInfo, aScriptURL, aName, aType,
aSharedWorker);
}
nsresult
RuntimeService::CreateSharedWorkerFromLoadInfo(JSContext* aCx,
WorkerPrivate::LoadInfo aLoadInfo,
WorkerPrivate::LoadInfo* aLoadInfo,
const nsAString& aScriptURL,
const nsACString& aName,
WorkerType aType,
SharedWorker** aSharedWorker)
{
AssertIsOnMainThread();
MOZ_ASSERT(aLoadInfo.mResolvedScriptURI);
MOZ_ASSERT(aLoadInfo);
MOZ_ASSERT(aLoadInfo->mResolvedScriptURI);
nsRefPtr<WorkerPrivate> workerPrivate;
{
@ -2229,13 +2280,13 @@ RuntimeService::CreateSharedWorkerFromLoadInfo(JSContext* aCx,
SharedWorkerInfo* sharedWorkerInfo;
nsCString scriptSpec;
nsresult rv = aLoadInfo.mResolvedScriptURI->GetSpec(scriptSpec);
nsresult rv = aLoadInfo->mResolvedScriptURI->GetSpec(scriptSpec);
NS_ENSURE_SUCCESS(rv, rv);
nsAutoCString key;
GenerateSharedWorkerKey(scriptSpec, aName, key);
if (mDomainMap.Get(aLoadInfo.mDomain, &domainInfo) &&
if (mDomainMap.Get(aLoadInfo->mDomain, &domainInfo) &&
domainInfo->mSharedWorkerInfos.Get(key, &sharedWorkerInfo)) {
workerPrivate = sharedWorkerInfo->mWorkerPrivate;
}
@ -2245,14 +2296,14 @@ RuntimeService::CreateSharedWorkerFromLoadInfo(JSContext* aCx,
// a Shared/Service worker and the worker script loads and executes before
// the SharedWorker object itself is created before then WorkerScriptLoaded()
// will reset the loadInfo's window.
nsCOMPtr<nsPIDOMWindow> window = aLoadInfo.mWindow;
nsCOMPtr<nsPIDOMWindow> window = aLoadInfo->mWindow;
bool created = false;
if (!workerPrivate) {
ErrorResult rv;
workerPrivate =
WorkerPrivate::Constructor(aCx, aScriptURL, false,
aType, aName, &aLoadInfo, rv);
aType, aName, aLoadInfo, rv);
NS_ENSURE_TRUE(workerPrivate, rv.ErrorCode());
created = true;

View File

@ -155,7 +155,7 @@ public:
nsresult
CreateServiceWorkerFromLoadInfo(JSContext* aCx,
WorkerPrivate::LoadInfo aLoadInfo,
WorkerPrivate::LoadInfo* aLoadInfo,
const nsAString& aScriptURL,
const nsACString& aScope,
ServiceWorker** aServiceWorker);
@ -308,7 +308,7 @@ private:
nsresult
CreateSharedWorkerFromLoadInfo(JSContext* aCx,
WorkerPrivate::LoadInfo aLoadInfo,
WorkerPrivate::LoadInfo* aLoadInfo,
const nsAString& aScriptURL,
const nsACString& aName,
WorkerType aType,

View File

@ -2122,7 +2122,7 @@ ServiceWorkerManager::CreateServiceWorker(const nsACString& aScriptSpec,
return NS_ERROR_FAILURE;
}
rv = rs->CreateServiceWorkerFromLoadInfo(cx, info, NS_ConvertUTF8toUTF16(aScriptSpec), aScope,
rv = rs->CreateServiceWorkerFromLoadInfo(cx, &info, NS_ConvertUTF8toUTF16(aScriptSpec), aScope,
getter_AddRefs(serviceWorker));
if (NS_WARN_IF(NS_FAILED(rv))) {

View File

@ -20,8 +20,6 @@
#include "nsIScriptError.h"
#include "nsIScriptGlobalObject.h"
#include "nsIScriptSecurityManager.h"
#include "nsPerformance.h"
#include "nsPIDOMWindow.h"
#include "nsITextToSubURI.h"
#include "nsIThreadInternal.h"
#include "nsITimer.h"
@ -29,6 +27,8 @@
#include "nsIURL.h"
#include "nsIWorkerDebugger.h"
#include "nsIXPConnect.h"
#include "nsPerformance.h"
#include "nsPIDOMWindow.h"
#include <algorithm>
#include "jsfriendapi.h"
@ -54,6 +54,12 @@
#include "mozilla/dom/ScriptSettings.h"
#include "mozilla/dom/StructuredClone.h"
#include "mozilla/dom/WorkerBinding.h"
#include "mozilla/dom/indexedDB/IDBFactory.h"
#include "mozilla/dom/ipc/BlobChild.h"
#include "mozilla/dom/ipc/nsIRemoteBlob.h"
#include "mozilla/ipc/BackgroundChild.h"
#include "mozilla/ipc/BackgroundUtils.h"
#include "mozilla/ipc/PBackgroundSharedTypes.h"
#include "mozilla/Preferences.h"
#include "nsAlgorithm.h"
#include "nsContentUtils.h"
@ -90,6 +96,10 @@
#include "WorkerScope.h"
#include "WorkerThread.h"
#ifdef XP_WIN
#undef PostMessage
#endif
// JS_MaybeGC will run once every second during normal execution.
#define PERIODIC_GC_TIMER_DELAY_SEC 1
@ -106,6 +116,8 @@
using namespace mozilla;
using namespace mozilla::dom;
using namespace mozilla::ipc;
USING_WORKERS_NAMESPACE
MOZ_DEFINE_MALLOC_SIZE_OF(JsWorkerMallocSizeOf)
@ -295,6 +307,105 @@ LogErrorToConsole(const nsAString& aMessage,
fflush(stderr);
}
void
ReadBlobOrFile(JSContext* aCx,
JSStructuredCloneReader* aReader,
bool aIsMainThread,
JS::MutableHandle<JSObject*> aBlobOrFile)
{
MOZ_ASSERT(aCx);
MOZ_ASSERT(aReader);
MOZ_ASSERT(!aBlobOrFile);
nsRefPtr<FileImpl> blobImpl;
{
FileImpl* rawBlobImpl;
MOZ_ALWAYS_TRUE(JS_ReadBytes(aReader, &rawBlobImpl, sizeof(rawBlobImpl)));
MOZ_ASSERT(rawBlobImpl);
blobImpl = rawBlobImpl;
}
DebugOnly<bool> isMutable;
MOZ_ASSERT(NS_SUCCEEDED(blobImpl->GetMutable(&isMutable)));
MOZ_ASSERT(!isMutable);
if (nsCOMPtr<nsIRemoteBlob> remoteBlob = do_QueryObject(blobImpl)) {
PBackgroundChild* backgroundManager =
BackgroundChild::GetForCurrentThread();
MOZ_ASSERT(backgroundManager);
// Always make sure we have a blob from an actor we can use on this thread.
BlobChild* blobChild = BlobChild::GetOrCreate(backgroundManager, blobImpl);
MOZ_ASSERT(blobChild);
blobImpl = blobChild->GetBlobImpl();
MOZ_ASSERT(blobImpl);
}
nsCOMPtr<nsISupports> parent;
if (aIsMainThread) {
AssertIsOnMainThread();
nsCOMPtr<nsIScriptGlobalObject> scriptGlobal =
nsJSUtils::GetStaticScriptGlobal(JS::CurrentGlobalOrNull(aCx));
parent = do_QueryInterface(scriptGlobal);
} else {
MOZ_ASSERT(!NS_IsMainThread());
WorkerPrivate* workerPrivate = GetWorkerPrivateFromContext(aCx);
MOZ_ASSERT(workerPrivate);
WorkerGlobalScope* globalScope = workerPrivate->GlobalScope();
MOZ_ASSERT(globalScope);
parent = do_QueryObject(globalScope);
}
nsRefPtr<File> blob = new File(parent, blobImpl);
aBlobOrFile.set(blob->WrapObject(aCx));
}
bool
WriteBlobOrFile(JSContext* aCx,
JSStructuredCloneWriter* aWriter,
FileImpl* aBlobOrFileImpl,
nsTArray<nsCOMPtr<nsISupports>>& aClonedObjects)
{
MOZ_ASSERT(aCx);
MOZ_ASSERT(aWriter);
MOZ_ASSERT(aBlobOrFileImpl);
nsRefPtr<FileImpl> newBlobOrFileImpl;
if (nsCOMPtr<nsIRemoteBlob> remoteBlob = do_QueryObject(aBlobOrFileImpl)) {
PBackgroundChild* backgroundManager =
BackgroundChild::GetForCurrentThread();
MOZ_ASSERT(backgroundManager);
// Always make sure we have a blob from an actor we can use on this thread.
BlobChild* blobChild =
BlobChild::GetOrCreate(backgroundManager, aBlobOrFileImpl);
MOZ_ASSERT(blobChild);
newBlobOrFileImpl = blobChild->GetBlobImpl();
MOZ_ASSERT(newBlobOrFileImpl);
aBlobOrFileImpl = newBlobOrFileImpl;
}
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(aBlobOrFileImpl->SetMutable(false)));
if (NS_WARN_IF(!JS_WriteUint32Pair(aWriter, DOMWORKER_SCTAG_BLOB, 0)) ||
NS_WARN_IF(!JS_WriteBytes(aWriter,
&aBlobOrFileImpl,
sizeof(aBlobOrFileImpl)))) {
return false;
}
aClonedObjects.AppendElement(aBlobOrFileImpl);
return true;
}
struct WorkerStructuredCloneCallbacks
{
static JSObject*
@ -307,31 +418,10 @@ struct WorkerStructuredCloneCallbacks
if (aTag == DOMWORKER_SCTAG_BLOB) {
MOZ_ASSERT(!aData);
FileImpl* blobImpl;
if (JS_ReadBytes(aReader, &blobImpl, sizeof(blobImpl))) {
MOZ_ASSERT(blobImpl);
JS::Rooted<JSObject*> blobOrFile(aCx);
ReadBlobOrFile(aCx, aReader, /* aIsMainThread */ false, &blobOrFile);
#ifdef DEBUG
{
// Blob should not be mutable.
bool isMutable;
NS_ASSERTION(NS_SUCCEEDED(blobImpl->GetMutable(&isMutable)) &&
!isMutable,
"Only immutable blob should be passed to worker");
}
#endif
{
// New scope to protect |result| from a moving GC during ~nsRefPtr.
nsRefPtr<File> blob = new File(nullptr, blobImpl);
JS::Rooted<JS::Value> val(aCx);
if (GetOrCreateDOMReflector(aCx, blob, &val)) {
result = val.toObjectOrNull();
}
}
return result;
}
return blobOrFile;
}
// See if the object is an ImageData.
else if (aTag == SCTAG_DOM_IMAGEDATA) {
@ -350,18 +440,17 @@ struct WorkerStructuredCloneCallbacks
NS_ASSERTION(aClosure, "Null pointer!");
// We'll stash any nsISupports pointers that need to be AddRef'd here.
nsTArray<nsCOMPtr<nsISupports> >* clonedObjects =
static_cast<nsTArray<nsCOMPtr<nsISupports> >*>(aClosure);
auto* clonedObjects =
static_cast<nsTArray<nsCOMPtr<nsISupports>>*>(aClosure);
// See if this is a Blob/File object.
{
File* blob = nullptr;
nsRefPtr<File> blob;
if (NS_SUCCEEDED(UNWRAP_OBJECT(Blob, aObj, blob))) {
FileImpl* blobImpl = blob->Impl();
if (blobImpl && NS_SUCCEEDED(blobImpl->SetMutable(false)) &&
JS_WriteUint32Pair(aWriter, DOMWORKER_SCTAG_BLOB, 0) &&
JS_WriteBytes(aWriter, &blobImpl, sizeof(blobImpl))) {
clonedObjects->AppendElement(blobImpl);
MOZ_ASSERT(blobImpl);
if (WriteBlobOrFile(aCx, aWriter, blobImpl, *clonedObjects)) {
return true;
}
}
@ -407,35 +496,10 @@ struct MainThreadWorkerStructuredCloneCallbacks
if (aTag == DOMWORKER_SCTAG_BLOB) {
MOZ_ASSERT(!aData);
FileImpl* blobImpl;
if (JS_ReadBytes(aReader, &blobImpl, sizeof(blobImpl))) {
MOZ_ASSERT(blobImpl);
JS::Rooted<JSObject*> blobOrFile(aCx);
ReadBlobOrFile(aCx, aReader, /* aIsMainThread */ true, &blobOrFile);
#ifdef DEBUG
{
// Blob should not be mutable.
bool isMutable;
NS_ASSERTION(NS_SUCCEEDED(blobImpl->GetMutable(&isMutable)) &&
!isMutable,
"Only immutable blob should be passed to worker");
}
#endif
// nsRefPtr<File> needs to go out of scope before toObjectOrNull() is
// called because the static analysis thinks dereferencing XPCOM objects
// can GC (because in some cases it can!), and a return statement with a
// JSObject* type means that JSObject* is on the stack as a raw pointer
// while destructors are running.
JS::Rooted<JS::Value> val(aCx);
{
nsRefPtr<File> blob = new File(nullptr, blobImpl);
if (!GetOrCreateDOMReflector(aCx, blob, &val)) {
return nullptr;
}
}
return &val.toObject();
}
return blobOrFile;
}
JS_ClearPendingException(aCx);
@ -451,20 +515,19 @@ struct MainThreadWorkerStructuredCloneCallbacks
NS_ASSERTION(aClosure, "Null pointer!");
// We'll stash any nsISupports pointers that need to be AddRef'd here.
nsTArray<nsCOMPtr<nsISupports> >* clonedObjects =
static_cast<nsTArray<nsCOMPtr<nsISupports> >*>(aClosure);
auto* clonedObjects =
static_cast<nsTArray<nsCOMPtr<nsISupports>>*>(aClosure);
// See if this is a Blob/File object.
{
File* blob = nullptr;
nsRefPtr<File> blob;
if (NS_SUCCEEDED(UNWRAP_OBJECT(Blob, aObj, blob))) {
FileImpl* blobImpl = blob->Impl();
MOZ_ASSERT(blobImpl);
if (blobImpl->IsCCed()) {
NS_WARNING("Cycle collected blob objects are not supported!");
} else if (NS_SUCCEEDED(blobImpl->SetMutable(false)) &&
JS_WriteUint32Pair(aWriter, DOMWORKER_SCTAG_BLOB, 0) &&
JS_WriteBytes(aWriter, &blobImpl, sizeof(blobImpl))) {
clonedObjects->AppendElement(blobImpl);
} else if (WriteBlobOrFile(aCx, aWriter, blobImpl, *clonedObjects)) {
return true;
}
}
@ -1224,7 +1287,7 @@ private:
// check is only going to succeed when the worker is accepting events.
if (workerIsAcceptingEvents) {
aWorkerPrivate->AssertInnerWindowIsCorrect();
innerWindowId = aWorkerPrivate->GetInnerWindowId();
innerWindowId = aWorkerPrivate->WindowID();
}
}
@ -1710,6 +1773,46 @@ private:
}
};
class DummyRunnable MOZ_FINAL
: public WorkerRunnable
{
public:
explicit
DummyRunnable(WorkerPrivate* aWorkerPrivate)
: WorkerRunnable(aWorkerPrivate, WorkerThreadUnchangedBusyCount)
{
aWorkerPrivate->AssertIsOnWorkerThread();
}
private:
~DummyRunnable()
{
mWorkerPrivate->AssertIsOnWorkerThread();
}
virtual bool
PreDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate) MOZ_OVERRIDE
{
MOZ_ASSERT_UNREACHABLE("Should never call Dispatch on this!");
return true;
}
virtual void
PostDispatch(JSContext* aCx,
WorkerPrivate* aWorkerPrivate,
bool aDispatchResult) MOZ_OVERRIDE
{
MOZ_ASSERT_UNREACHABLE("Should never call Dispatch on this!");
}
virtual bool
WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) MOZ_OVERRIDE
{
// Do nothing.
return true;
}
};
PRThread*
PRThreadFromThread(nsIThread* aThread)
{
@ -1730,6 +1833,29 @@ NS_IMPL_ISUPPORTS_INHERITED0(TopLevelWorkerFinishedRunnable, nsRunnable)
NS_IMPL_ISUPPORTS(TimerThreadEventTarget, nsIEventTarget)
template <class Derived>
WorkerPrivateParent<Derived>::
LoadInfo::LoadInfo()
: mWindowID(UINT64_MAX)
, mFromWindow(false)
, mEvalAllowed(false)
, mReportCSPViolations(false)
, mXHRParamsAllowed(false)
, mPrincipalIsSystem(false)
, mIsInPrivilegedApp(false)
, mIsInCertifiedApp(false)
, mIndexedDBAllowed(false)
{
MOZ_COUNT_CTOR(WorkerPrivateParent<Derived>::LoadInfo);
}
template <class Derived>
WorkerPrivateParent<Derived>::
LoadInfo::~LoadInfo()
{
MOZ_COUNT_DTOR(WorkerPrivateParent<Derived>::LoadInfo);
}
template <class Derived>
class WorkerPrivateParent<Derived>::SynchronizeAndResumeRunnable MOZ_FINAL
: public nsRunnable
@ -2009,6 +2135,22 @@ WorkerPrivate::SyncLoopInfo::SyncLoopInfo(EventTarget* aEventTarget)
{
}
struct WorkerPrivate::PreemptingRunnableInfo MOZ_FINAL
{
nsCOMPtr<nsIRunnable> mRunnable;
uint32_t mRecursionDepth;
PreemptingRunnableInfo()
{
MOZ_COUNT_CTOR(WorkerPrivate::PreemptingRunnableInfo);
}
~PreemptingRunnableInfo()
{
MOZ_COUNT_DTOR(WorkerPrivate::PreemptingRunnableInfo);
}
};
// Can't use NS_IMPL_CYCLE_COLLECTION_CLASS(WorkerPrivateParent) because of the
// templates.
template <class Derived>
@ -2806,16 +2948,6 @@ WorkerPrivateParent<Derived>::DispatchMessageEventToMessagePort(
return true;
}
template <class Derived>
uint64_t
WorkerPrivateParent<Derived>::GetInnerWindowId()
{
AssertIsOnMainThread();
NS_ASSERTION(!mLoadInfo.mWindow || mLoadInfo.mWindow->IsInnerWindow(),
"Outer window?");
return mLoadInfo.mWindow ? mLoadInfo.mWindow->WindowID() : 0;
}
template <class Derived>
void
WorkerPrivateParent<Derived>::UpdateRuntimeOptions(
@ -3367,6 +3499,7 @@ WorkerPrivateParent<Derived>::SetPrincipal(nsIPrincipal* aPrincipal,
{
AssertIsOnMainThread();
MOZ_ASSERT(NS_LoadGroupMatchesPrincipal(aLoadGroup, aPrincipal));
MOZ_ASSERT(!mLoadInfo.mPrincipalInfo);
mLoadInfo.mPrincipal = aPrincipal;
mLoadInfo.mPrincipalIsSystem = nsContentUtils::IsSystemPrincipal(aPrincipal);
@ -3377,6 +3510,11 @@ WorkerPrivateParent<Derived>::SetPrincipal(nsIPrincipal* aPrincipal,
mLoadInfo.mIsInCertifiedApp = (appStatus == nsIPrincipal::APP_STATUS_CERTIFIED);
mLoadInfo.mLoadGroup = aLoadGroup;
mLoadInfo.mPrincipalInfo = new PrincipalInfo();
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(
PrincipalToPrincipalInfo(aPrincipal, mLoadInfo.mPrincipalInfo)));
}
template <class Derived>
@ -3908,6 +4046,7 @@ WorkerPrivate::GetLoadInfo(JSContext* aCx, nsPIDOMWindow* aWindow,
bool aIsChromeWorker, LoadInfo* aLoadInfo)
{
using namespace mozilla::dom::workers::scriptloader;
using mozilla::dom::indexedDB::IDBFactory;
MOZ_ASSERT(aCx);
MOZ_ASSERT_IF(NS_IsMainThread(), aCx == nsContentUtils::GetCurrentJSContext());
@ -3958,6 +4097,9 @@ WorkerPrivate::GetLoadInfo(JSContext* aCx, nsPIDOMWindow* aWindow,
}
loadInfo.mDomain = aParent->Domain();
loadInfo.mFromWindow = aParent->IsFromWindow();
loadInfo.mWindowID = aParent->WindowID();
loadInfo.mIndexedDBAllowed = aParent->IsIndexedDBAllowed();
} else {
AssertIsOnMainThread();
@ -4071,6 +4213,9 @@ WorkerPrivate::GetLoadInfo(JSContext* aCx, nsPIDOMWindow* aWindow,
(appStatus == nsIPrincipal::APP_STATUS_CERTIFIED ||
appStatus == nsIPrincipal::APP_STATUS_PRIVILEGED);
loadInfo.mIsInCertifiedApp = (appStatus == nsIPrincipal::APP_STATUS_CERTIFIED);
loadInfo.mFromWindow = true;
loadInfo.mWindowID = globalWindow->WindowID();
loadInfo.mIndexedDBAllowed = IDBFactory::AllowedForWindow(globalWindow);
} else {
// Not a window
MOZ_ASSERT(isChrome);
@ -4109,6 +4254,9 @@ WorkerPrivate::GetLoadInfo(JSContext* aCx, nsPIDOMWindow* aWindow,
}
}
loadInfo.mXHRParamsAllowed = true;
loadInfo.mFromWindow = false;
loadInfo.mWindowID = UINT64_MAX;
loadInfo.mIndexedDBAllowed = true;
}
MOZ_ASSERT(loadInfo.mPrincipal);
@ -4293,6 +4441,29 @@ WorkerPrivate::OnProcessNextEvent(uint32_t aRecursionDepth)
mSyncLoopStack.Length() < aRecursionDepth - 1) {
ProcessAllControlRunnables();
}
// Run any preempting runnables that match this depth.
if (!mPreemptingRunnableInfos.IsEmpty()) {
nsTArray<PreemptingRunnableInfo> pendingRunnableInfos;
for (uint32_t index = 0;
index < mPreemptingRunnableInfos.Length();
index++) {
PreemptingRunnableInfo& preemptingRunnableInfo =
mPreemptingRunnableInfos[index];
if (preemptingRunnableInfo.mRecursionDepth == aRecursionDepth) {
preemptingRunnableInfo.mRunnable->Run();
preemptingRunnableInfo.mRunnable = nullptr;
} else {
PreemptingRunnableInfo* pending = pendingRunnableInfos.AppendElement();
pending->mRunnable.swap(preemptingRunnableInfo.mRunnable);
pending->mRecursionDepth = preemptingRunnableInfo.mRecursionDepth;
}
}
mPreemptingRunnableInfos.SwapElements(pendingRunnableInfos);
}
}
void
@ -4302,6 +4473,42 @@ WorkerPrivate::AfterProcessNextEvent(uint32_t aRecursionDepth)
MOZ_ASSERT(aRecursionDepth);
}
bool
WorkerPrivate::RunBeforeNextEvent(nsIRunnable* aRunnable)
{
AssertIsOnWorkerThread();
MOZ_ASSERT(aRunnable);
MOZ_ASSERT_IF(!mPreemptingRunnableInfos.IsEmpty(),
NS_HasPendingEvents(mThread));
const uint32_t recursionDepth =
mThread->RecursionDepth(WorkerThreadFriendKey());
PreemptingRunnableInfo* preemptingRunnableInfo =
mPreemptingRunnableInfos.AppendElement();
preemptingRunnableInfo->mRunnable = aRunnable;
// Due to the weird way that the thread recursion counter is implemented we
// subtract one from the recursion level if we have one.
preemptingRunnableInfo->mRecursionDepth =
recursionDepth ? recursionDepth - 1 : 0;
// Ensure that we have a pending event so that the runnable will be guaranteed
// to run.
if (mPreemptingRunnableInfos.Length() == 1 && !NS_HasPendingEvents(mThread)) {
nsRefPtr<DummyRunnable> dummyRunnable = new DummyRunnable(this);
if (NS_FAILED(Dispatch(dummyRunnable))) {
NS_WARNING("RunBeforeNextEvent called after the thread is shutting "
"down!");
mPreemptingRunnableInfos.Clear();
return false;
}
}
return true;
}
void
WorkerPrivate::InitializeGCTimers()
{

View File

@ -17,6 +17,7 @@
#include "mozilla/DOMEventTargetHelper.h"
#include "mozilla/TimeStamp.h"
#include "mozilla/dom/BindingDeclarations.h"
#include "nsAutoPtr.h"
#include "nsCycleCollectionParticipant.h"
#include "nsDataHashtable.h"
#include "nsHashKeys.h"
@ -48,6 +49,9 @@ namespace mozilla {
namespace dom {
class Function;
}
namespace ipc {
class PrincipalInfo;
}
}
struct PRThread;
@ -131,6 +135,8 @@ protected:
class EventTarget;
friend class EventTarget;
typedef mozilla::ipc::PrincipalInfo PrincipalInfo;
public:
struct LocationInfo
{
@ -157,20 +163,22 @@ public:
nsCOMPtr<nsIChannel> mChannel;
nsCOMPtr<nsILoadGroup> mLoadGroup;
nsAutoPtr<PrincipalInfo> mPrincipalInfo;
nsCString mDomain;
uint64_t mWindowID;
bool mFromWindow;
bool mEvalAllowed;
bool mReportCSPViolations;
bool mXHRParamsAllowed;
bool mPrincipalIsSystem;
bool mIsInPrivilegedApp;
bool mIsInCertifiedApp;
bool mIndexedDBAllowed;
LoadInfo()
: mEvalAllowed(false), mReportCSPViolations(false),
mXHRParamsAllowed(false), mPrincipalIsSystem(false),
mIsInPrivilegedApp(false), mIsInCertifiedApp(false)
{ }
LoadInfo();
~LoadInfo();
void
StealFrom(LoadInfo& aOther)
@ -199,13 +207,19 @@ public:
MOZ_ASSERT(!mLoadGroup);
aOther.mLoadGroup.swap(mLoadGroup);
MOZ_ASSERT(!mPrincipalInfo);
mPrincipalInfo = aOther.mPrincipalInfo.forget();
mDomain = aOther.mDomain;
mWindowID = aOther.mWindowID;
mFromWindow = aOther.mFromWindow;
mEvalAllowed = aOther.mEvalAllowed;
mReportCSPViolations = aOther.mReportCSPViolations;
mXHRParamsAllowed = aOther.mXHRParamsAllowed;
mPrincipalIsSystem = aOther.mPrincipalIsSystem;
mIsInPrivilegedApp = aOther.mIsInPrivilegedApp;
mIsInCertifiedApp = aOther.mIsInCertifiedApp;
mIndexedDBAllowed = aOther.mIndexedDBAllowed;
}
};
@ -404,9 +418,6 @@ public:
JSAutoStructuredCloneBuffer&& aBuffer,
nsTArray<nsCOMPtr<nsISupports>>& aClonedObjects);
uint64_t
GetInnerWindowId();
void
UpdateRuntimeOptions(JSContext* aCx,
const JS::RuntimeOptions& aRuntimeOptions);
@ -511,6 +522,18 @@ public:
return mLoadInfo.mDomain;
}
bool
IsFromWindow() const
{
return mLoadInfo.mFromWindow;
}
uint64_t
WindowID() const
{
return mLoadInfo.mWindowID;
}
nsIURI*
GetBaseURI() const
{
@ -582,6 +605,12 @@ public:
return mLoadInfo.mIsInCertifiedApp;
}
const PrincipalInfo&
GetPrincipalInfo() const
{
return *mLoadInfo.mPrincipalInfo;
}
already_AddRefed<nsIChannel>
ForgetWorkerChannel()
{
@ -713,6 +742,12 @@ public:
return mMessagePortSerial++;
}
bool
IsIndexedDBAllowed() const
{
return mLoadInfo.mIndexedDBAllowed;
}
void
GetAllSharedWorkers(nsTArray<nsRefPtr<SharedWorker>>& aSharedWorkers);
@ -833,6 +868,9 @@ class WorkerPrivate : public WorkerPrivateParent<WorkerPrivate>
// modifications are done with mMutex held *only* in DEBUG builds.
nsTArray<nsAutoPtr<SyncLoopInfo>> mSyncLoopStack;
struct PreemptingRunnableInfo;
nsTArray<PreemptingRunnableInfo> mPreemptingRunnableInfos;
nsCOMPtr<nsITimer> mTimer;
nsCOMPtr<nsITimer> mGCTimer;
@ -1167,6 +1205,11 @@ public:
return mWorkerScriptExecutedSuccessfully;
}
// Just like nsIAppShell::RunBeforeNextEvent. May only be called on the worker
// thread.
bool
RunBeforeNextEvent(nsIRunnable* aRunnable);
private:
WorkerPrivate(JSContext* aCx, WorkerPrivate* aParent,
const nsAString& aScriptURL, bool aIsChromeWorker,

View File

@ -8,6 +8,7 @@
#include "jsapi.h"
#include "mozilla/EventListenerManager.h"
#include "mozilla/dom/BindingDeclarations.h"
#include "mozilla/dom/Console.h"
#include "mozilla/dom/DedicatedWorkerGlobalScopeBinding.h"
#include "mozilla/dom/Fetch.h"
@ -15,6 +16,7 @@
#include "mozilla/dom/Promise.h"
#include "mozilla/dom/ServiceWorkerGlobalScopeBinding.h"
#include "mozilla/dom/SharedWorkerGlobalScopeBinding.h"
#include "mozilla/dom/indexedDB/IDBFactory.h"
#include "mozilla/Services.h"
#include "nsServiceManagerUtils.h"
@ -43,6 +45,9 @@ using namespace mozilla;
using namespace mozilla::dom;
USING_WORKERS_NAMESPACE
using mozilla::dom::indexedDB::IDBFactory;
using mozilla::ipc::PrincipalInfo;
BEGIN_WORKERS_NAMESPACE
WorkerGlobalScope::WorkerGlobalScope(WorkerPrivate* aWorkerPrivate)
@ -65,6 +70,7 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(WorkerGlobalScope,
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPerformance)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mLocation)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mNavigator)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mIndexedDB)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(WorkerGlobalScope,
@ -74,6 +80,7 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(WorkerGlobalScope,
NS_IMPL_CYCLE_COLLECTION_UNLINK(mPerformance)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mLocation)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mNavigator)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mIndexedDB)
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(WorkerGlobalScope,
@ -312,6 +319,44 @@ WorkerGlobalScope::Fetch(const RequestOrUSVString& aInput,
return FetchRequest(this, aInput, aInit, aRv);
}
already_AddRefed<IDBFactory>
WorkerGlobalScope::GetIndexedDB(ErrorResult& aErrorResult)
{
mWorkerPrivate->AssertIsOnWorkerThread();
nsRefPtr<IDBFactory> indexedDB = mIndexedDB;
if (!indexedDB) {
if (!mWorkerPrivate->IsIndexedDBAllowed()) {
NS_WARNING("IndexedDB is not allowed in this worker!");
return nullptr;
}
JSContext* cx = mWorkerPrivate->GetJSContext();
MOZ_ASSERT(cx);
JS::Rooted<JSObject*> owningObject(cx, GetGlobalJSObject());
MOZ_ASSERT(owningObject);
const PrincipalInfo& principalInfo = mWorkerPrivate->GetPrincipalInfo();
nsresult rv =
IDBFactory::CreateForWorker(cx,
owningObject,
principalInfo,
mWorkerPrivate->WindowID(),
getter_AddRefs(indexedDB));
if (NS_WARN_IF(NS_FAILED(rv))) {
aErrorResult = rv;
return nullptr;
}
mIndexedDB = indexedDB;
}
return indexedDB.forget();
}
DedicatedWorkerGlobalScope::DedicatedWorkerGlobalScope(WorkerPrivate* aWorkerPrivate)
: WorkerGlobalScope(aWorkerPrivate)
{

View File

@ -19,6 +19,12 @@ class Function;
class Promise;
class RequestOrUSVString;
namespace indexedDB {
class IDBFactory;
} // namespace indexedDB
} // namespace dom
} // namespace mozilla
@ -33,10 +39,13 @@ class Performance;
class WorkerGlobalScope : public DOMEventTargetHelper,
public nsIGlobalObject
{
typedef mozilla::dom::indexedDB::IDBFactory IDBFactory;
nsRefPtr<Console> mConsole;
nsRefPtr<WorkerLocation> mLocation;
nsRefPtr<WorkerNavigator> mNavigator;
nsRefPtr<Performance> mPerformance;
nsRefPtr<IDBFactory> mIndexedDB;
protected:
WorkerPrivate* mWorkerPrivate;
@ -127,6 +136,9 @@ public:
already_AddRefed<Promise>
Fetch(const RequestOrUSVString& aInput, const RequestInit& aInit, ErrorResult& aRv);
already_AddRefed<IDBFactory>
GetIndexedDB(ErrorResult& aErrorResult);
};
class DedicatedWorkerGlobalScope MOZ_FINAL : public WorkerGlobalScope

View File

@ -284,6 +284,14 @@ WorkerThread::Dispatch(nsIRunnable* aRunnable, uint32_t aFlags)
return NS_OK;
}
uint32_t
WorkerThread::RecursionDepth(const WorkerThreadFriendKey& /* aKey */) const
{
MOZ_ASSERT(PR_GetCurrentThread() == mThread);
return mRunningEvent;
}
NS_IMPL_ISUPPORTS(WorkerThread::Observer, nsIThreadObserver)
NS_IMETHODIMP

View File

@ -72,6 +72,9 @@ public:
Dispatch(const WorkerThreadFriendKey& aKey,
WorkerRunnable* aWorkerRunnable);
uint32_t
RecursionDepth(const WorkerThreadFriendKey& aKey) const;
NS_DECL_ISUPPORTS_INHERITED
private:

View File

@ -93,8 +93,12 @@ var interfaceNamesInGlobalScope =
{ name: "DataStore", b2g: true },
// IMPORTANT: Do not change this list without review from a DOM peer!
{ name: "DataStoreCursor", b2g: true },
// IMPORTANT: Do not change this list without review from a DOM peer!
"DOMError",
// IMPORTANT: Do not change this list without review from a DOM peer!
"DOMException",
// IMPORTANT: Do not change this list without review from a DOM peer!
"DOMStringList",
// IMPORTANT: Do not change this list without review from a DOM peer!
"Event",
// IMPORTANT: Do not change this list without review from a DOM peer!
@ -105,6 +109,26 @@ var interfaceNamesInGlobalScope =
"FileReaderSync",
// IMPORTANT: Do not change this list without review from a DOM peer!
{ name: "Headers", pref: "dom.fetch.enabled" },
// IMPORTANT: Do not change this list without review from a DOM peer!
"IDBCursor",
// IMPORTANT: Do not change this list without review from a DOM peer!
"IDBDatabase",
// IMPORTANT: Do not change this list without review from a DOM peer!
"IDBFactory",
// IMPORTANT: Do not change this list without review from a DOM peer!
"IDBIndex",
// IMPORTANT: Do not change this list without review from a DOM peer!
"IDBKeyRange",
// IMPORTANT: Do not change this list without review from a DOM peer!
"IDBObjectStore",
// IMPORTANT: Do not change this list without review from a DOM peer!
"IDBOpenDBRequest",
// IMPORTANT: Do not change this list without review from a DOM peer!
"IDBRequest",
// IMPORTANT: Do not change this list without review from a DOM peer!
"IDBTransaction",
// IMPORTANT: Do not change this list without review from a DOM peer!
"IDBVersionChangeEvent",
// IMPORTANT: Do not change this list without review from a DOM peer!
"ImageData",
// IMPORTANT: Do not change this list without review from a DOM peer!

View File

@ -654,10 +654,9 @@ DrawTargetCairo::Snapshot()
IntSize size = GetSize();
cairo_content_t content = cairo_surface_get_content(mSurface);
mSnapshot = new SourceSurfaceCairo(mSurface,
size,
CairoContentToGfxFormat(content),
GfxFormatForCairoSurface(mSurface),
this);
return mSnapshot;
}
@ -1503,7 +1502,7 @@ DrawTargetCairo::InitAlreadyReferenced(cairo_surface_t* aSurface, const IntSize&
mContext = cairo_create(aSurface);
mSurface = aSurface;
mSize = aSize;
mFormat = aFormat ? *aFormat : CairoContentToGfxFormat(cairo_surface_get_content(aSurface));
mFormat = aFormat ? *aFormat : GfxFormatForCairoSurface(aSurface);
// Cairo image surface have a bug where they will allocate a mask surface (for clipping)
// the size of the clip extents, and don't take the surface extents into account.

View File

@ -216,6 +216,35 @@ CairoContentToGfxFormat(cairo_content_t content)
return SurfaceFormat::B8G8R8A8;
}
static inline SurfaceFormat
CairoFormatToGfxFormat(cairo_format_t format)
{
switch (format) {
case CAIRO_FORMAT_ARGB32:
return SurfaceFormat::B8G8R8A8;
case CAIRO_FORMAT_RGB24:
return SurfaceFormat::B8G8R8X8;
case CAIRO_FORMAT_A8:
return SurfaceFormat::A8;
case CAIRO_FORMAT_RGB16_565:
return SurfaceFormat::R5G6B5;
default:
gfxWarning() << "Unknown cairo format";
MOZ_ASSERT(false, "Unknown cairo format");
return SurfaceFormat::UNKNOWN;
}
}
static inline SurfaceFormat
GfxFormatForCairoSurface(cairo_surface_t* surface)
{
if (cairo_surface_get_type(surface) == CAIRO_SURFACE_TYPE_IMAGE) {
return CairoFormatToGfxFormat(cairo_image_surface_get_format(surface));
}
return CairoContentToGfxFormat(cairo_surface_get_content(surface));
}
static inline void
GfxMatrixToCairoMatrix(const Matrix& mat, cairo_matrix_t& retval)
{

Some files were not shown because too many files have changed in this diff Show More