mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Merge inbound to m-c. a=merge
CLOSED TREE
This commit is contained in:
commit
d2ebc2ac1b
@ -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;
|
||||
}
|
||||
|
@ -579,6 +579,7 @@ let ClickEventHandler = {
|
||||
event.preventDefault(); // Need to prevent the pageload.
|
||||
}
|
||||
}
|
||||
json.noReferrer = BrowserUtils.linkHasNoReferrer(node)
|
||||
}
|
||||
|
||||
sendAsyncMessage("Content:Click", json);
|
||||
|
@ -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.
|
||||
|
6
browser/config/mozconfigs/linux64/code-coverage
Normal file
6
browser/config/mozconfigs/linux64/code-coverage
Normal 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"
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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));
|
||||
}
|
||||
|
||||
|
55
dom/base/test/csp/file_csp_referrerdirective.html
Normal file
55
dom/base/test/csp/file_csp_referrerdirective.html
Normal 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>
|
@ -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]
|
||||
|
36
dom/base/test/csp/referrerdirective.sjs
Normal file
36
dom/base/test/csp/referrerdirective.sjs
Normal 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);
|
||||
}
|
||||
}
|
125
dom/base/test/csp/test_CSP_referrerdirective.html
Normal file
125
dom/base/test/csp/test_CSP_referrerdirective.html
Normal 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>
|
29
dom/datastore/tests/file_worker_close.html
Normal file
29
dom/datastore/tests/file_worker_close.html
Normal 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>
|
18
dom/datastore/tests/file_worker_close.js
Normal file
18
dom/datastore/tests/file_worker_close.js
Normal 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);
|
||||
}
|
||||
}
|
@ -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]
|
||||
|
130
dom/datastore/tests/test_worker_close.html
Normal file
130
dom/datastore/tests/test_worker_close.html
Normal 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>
|
@ -214,8 +214,8 @@ public:
|
||||
};
|
||||
|
||||
WorkerFetchResolver::WorkerFetchResolver(WorkerPrivate* aWorkerPrivate, Promise* aPromise)
|
||||
: mPromiseProxy(new PromiseWorkerProxy(aWorkerPrivate, aPromise))
|
||||
{
|
||||
mPromiseProxy = PromiseWorkerProxy::Create(aWorkerPrivate, aPromise);
|
||||
}
|
||||
|
||||
WorkerFetchResolver::~WorkerFetchResolver()
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -514,7 +514,7 @@ public:
|
||||
#endif
|
||||
|
||||
void
|
||||
SendDeleteMeInternal();
|
||||
SendDeleteMeInternal(bool aFailedConstructor);
|
||||
|
||||
private:
|
||||
// Only created by BackgroundDatabaseChild.
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
{
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -94,6 +94,7 @@ LOCAL_INCLUDES += [
|
||||
'/db/sqlite3/src',
|
||||
'/dom/base',
|
||||
'/dom/storage',
|
||||
'/dom/workers',
|
||||
'/ipc/glue',
|
||||
'/xpcom/build',
|
||||
]
|
||||
|
@ -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" });
|
||||
}
|
||||
|
@ -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",
|
||||
|
@ -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;
|
||||
|
@ -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() {
|
||||
|
@ -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()
|
||||
|
@ -4,6 +4,8 @@
|
||||
*/
|
||||
"use strict";
|
||||
|
||||
let disableWorkerTest = "This test uses SpecialPowers";
|
||||
|
||||
var self = this;
|
||||
|
||||
var testGenerator = testSteps();
|
||||
|
@ -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()
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -3,6 +3,8 @@
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/
|
||||
*/
|
||||
|
||||
let disableWorkerTest = "This test uses SpecialPowers";
|
||||
|
||||
var testGenerator = testSteps();
|
||||
|
||||
function testSteps()
|
||||
|
@ -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);
|
||||
|
@ -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.
|
||||
|
1099
dom/ipc/Blob.cpp
1099
dom/ipc/Blob.cpp
File diff suppressed because it is too large
Load Diff
@ -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();
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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!
|
||||
|
@ -6,8 +6,6 @@ include protocol PBlob;
|
||||
include protocol PFileDescriptorSet;
|
||||
include InputStreamParams;
|
||||
|
||||
using mozilla::void_t from "ipc/IPCMessageUtils.h";
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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',
|
||||
|
@ -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]
|
||||
|
@ -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
|
||||
|
@ -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}.
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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();
|
||||
|
@ -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("; ");
|
||||
}
|
||||
|
@ -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___ */
|
||||
|
@ -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;
|
||||
|
@ -11,7 +11,7 @@
|
||||
*/
|
||||
|
||||
[Constructor(DOMString name, optional DOMString message = ""),
|
||||
Exposed=(Window,System)]
|
||||
Exposed=(Window,Worker,System)]
|
||||
interface DOMError {
|
||||
[Constant]
|
||||
readonly attribute DOMString name;
|
||||
|
@ -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);
|
||||
|
@ -14,6 +14,7 @@ enum IDBCursorDirection {
|
||||
"prevunique"
|
||||
};
|
||||
|
||||
[Exposed=(Window,Worker)]
|
||||
interface IDBCursor {
|
||||
readonly attribute (IDBObjectStore or IDBIndex) source;
|
||||
|
||||
|
@ -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
|
||||
};
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
};
|
||||
|
@ -9,6 +9,7 @@
|
||||
* liability, trademark and document use rules apply.
|
||||
*/
|
||||
|
||||
[Exposed=(Window,Worker)]
|
||||
interface IDBKeyRange {
|
||||
[Throws]
|
||||
readonly attribute any lower;
|
||||
|
@ -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");
|
||||
};
|
||||
|
@ -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;
|
||||
|
||||
|
@ -13,6 +13,7 @@ enum IDBRequestReadyState {
|
||||
"done"
|
||||
};
|
||||
|
||||
[Exposed=(Window,Worker)]
|
||||
interface IDBRequest : EventTarget {
|
||||
[Throws]
|
||||
readonly attribute any result;
|
||||
|
@ -14,6 +14,7 @@ enum IDBTransactionMode {
|
||||
"versionchange"
|
||||
};
|
||||
|
||||
[Exposed=(Window,Worker)]
|
||||
interface IDBTransaction : EventTarget {
|
||||
[Throws]
|
||||
readonly attribute IDBTransactionMode mode;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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:
|
||||
|
@ -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:
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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,
|
||||
|
@ -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))) {
|
||||
|
@ -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()
|
||||
{
|
||||
|
@ -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,
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -72,6 +72,9 @@ public:
|
||||
Dispatch(const WorkerThreadFriendKey& aKey,
|
||||
WorkerRunnable* aWorkerRunnable);
|
||||
|
||||
uint32_t
|
||||
RecursionDepth(const WorkerThreadFriendKey& aKey) const;
|
||||
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
|
||||
private:
|
||||
|
@ -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!
|
||||
|
@ -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.
|
||||
|
@ -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
Loading…
Reference in New Issue
Block a user