From 968d2b4e7143172a901845b95a5cb350155d07c6 Mon Sep 17 00:00:00 2001 From: roytam1 Date: Tue, 14 Dec 2021 09:20:33 +0800 Subject: [PATCH] import changes from `dev' branch of rmottola/Arctic-Fox: - Bug 1153314 - Assign load group to IdP load channel, r=jib (2c78dcc17) - Bug 1048048 - add preload content policy types for scripts (r=baku) (8dc3c1db1) - Bug 1210941 P1 Create the LOAD_BYPASS_SERVICE_WORKER flag. r=jduell (59fcdd603) - Bug 1173378 - crash in mozilla::net::HttpBaseChannel::OverrideSecurityInfo(nsISupports*), r=ehsan (de9772c35) - Bug 1179399 - Add a flag to HttpBaseChannel indicating whether interception is occurring. r=mayhemer (58a874dc5) - Bug 1168084 - Persist view source tab options. r=mconley (c48d492b2) - Bug 1187399 - Add a js::DefaultHasher specialization for mozilla::UniquePtr that proxies the UniquePtr's raw pointer to PointerHasher. r=terrence (bfeed9936) - Bug 1193459: Fix JS_DEPENDENT_TEMPLATE_HINT for clang-cl. r=jimb (9565eceaf) - pointer style (329deb0ec) - space and pointer style (844d8998a) - Bug 1172503 - Delete unwarranted optimization to fix "Assertion failure: !!desc.object() == objHasOwn, at js/src/vm/NativeObject.cpp:1990". r=evilpie. (a97fe0bd4) - pointer style (4c5f6eb6d) --- dom/base/nsScriptLoader.cpp | 24 ++++++++--- dom/base/nsScriptLoader.h | 6 ++- dom/fetch/ChannelInfo.cpp | 5 ++- dom/media/IdpSandbox.jsm | 17 +++++--- dom/media/PeerConnectionIdp.jsm | 2 +- dom/workers/ServiceWorkerScriptCache.cpp | 4 +- dom/xul/XULDocument.cpp | 3 +- js/public/HashTable.h | 20 +++++++++ js/public/TraceKind.h | 4 +- js/src/builtin/Intl.cpp | 2 +- js/src/builtin/ReflectParse.cpp | 12 +++--- js/src/builtin/TypedObject.cpp | 8 ++-- js/src/jit-test/tests/basic/bug1172503-2.js | 10 +++++ js/src/jit-test/tests/basic/bug1172503.js | 9 ++++ js/src/vm/NativeObject.cpp | 30 +++---------- js/src/vm/NativeObject.h | 2 +- js/src/vm/UnboxedObject-inl.h | 4 +- js/src/vm/UnboxedObject.cpp | 4 +- netwerk/base/nsIChannel.idl | 11 ++++- netwerk/protocol/http/HttpBaseChannel.cpp | 43 +++++++++++++++---- netwerk/protocol/http/HttpBaseChannel.h | 5 ++- netwerk/protocol/http/HttpChannelChild.cpp | 2 + netwerk/protocol/http/nsHttpChannel.cpp | 1 + .../viewsource/ViewSourceBrowser.jsm | 27 ++++++++++++ .../viewsource/content/viewSource-content.js | 11 +++-- .../viewsource/content/viewSource.js | 20 ++++----- .../test/browser/browser_viewsourceprefs.js | 8 ++++ .../viewsource/test/browser/head.js | 13 ++++++ 28 files changed, 218 insertions(+), 89 deletions(-) create mode 100644 js/src/jit-test/tests/basic/bug1172503-2.js create mode 100644 js/src/jit-test/tests/basic/bug1172503.js diff --git a/dom/base/nsScriptLoader.cpp b/dom/base/nsScriptLoader.cpp index 8b33877e54..f873bf12f1 100644 --- a/dom/base/nsScriptLoader.cpp +++ b/dom/base/nsScriptLoader.cpp @@ -223,10 +223,15 @@ nsresult nsScriptLoader::CheckContentPolicy(nsIDocument* aDocument, nsISupports *aContext, nsIURI *aURI, - const nsAString &aType) + const nsAString &aType, + bool aIsPreLoad) { + nsContentPolicyType contentPolicyType = aIsPreLoad + ? nsIContentPolicy::TYPE_INTERNAL_SCRIPT_PRELOAD + : nsIContentPolicy::TYPE_INTERNAL_SCRIPT; + int16_t shouldLoad = nsIContentPolicy::ACCEPT; - nsresult rv = NS_CheckContentLoadPolicy(nsIContentPolicy::TYPE_INTERNAL_SCRIPT, + nsresult rv = NS_CheckContentLoadPolicy(contentPolicyType, aURI, aDocument->NodePrincipal(), aContext, @@ -249,7 +254,8 @@ nsresult nsScriptLoader::ShouldLoadScript(nsIDocument* aDocument, nsISupports* aContext, nsIURI* aURI, - const nsAString &aType) + const nsAString &aType, + bool aIsPreLoad) { // Check that the containing page is allowed to load this URI. nsresult rv = nsContentUtils::GetSecurityManager()-> @@ -259,7 +265,7 @@ nsScriptLoader::ShouldLoadScript(nsIDocument* aDocument, NS_ENSURE_SUCCESS(rv, rv); // After the security manager, the content-policy stuff gets a veto - rv = CheckContentPolicy(aDocument, aContext, aURI, aType); + rv = CheckContentPolicy(aDocument, aContext, aURI, aType, aIsPreLoad); if (NS_FAILED(rv)) { return rv; } @@ -274,7 +280,7 @@ nsScriptLoader::StartLoad(nsScriptLoadRequest *aRequest, const nsAString &aType, nsISupports *context = aRequest->mElement.get() ? static_cast(aRequest->mElement.get()) : static_cast(mDocument); - nsresult rv = ShouldLoadScript(mDocument, context, aRequest->mURI, aType); + nsresult rv = ShouldLoadScript(mDocument, context, aRequest->mURI, aType, aRequest->IsPreload()); if (NS_FAILED(rv)) { return rv; } @@ -296,12 +302,16 @@ nsScriptLoader::StartLoad(nsScriptLoadRequest *aRequest, const nsAString &aType, return NS_OK; } + nsContentPolicyType contentPolicyType = aRequest->IsPreload() + ? nsIContentPolicy::TYPE_INTERNAL_SCRIPT_PRELOAD + : nsIContentPolicy::TYPE_INTERNAL_SCRIPT; + nsCOMPtr channel; rv = NS_NewChannel(getter_AddRefs(channel), aRequest->mURI, mDocument, nsILoadInfo::SEC_NORMAL, - nsIContentPolicy::TYPE_INTERNAL_SCRIPT, + contentPolicyType, loadGroup, prompter, nsIRequest::LOAD_NORMAL | @@ -628,7 +638,7 @@ nsScriptLoader::ProcessScriptElement(nsIScriptElement *aElement) if (elementCharset.Equals(preloadCharset) && ourCORSMode == request->mCORSMode && ourRefPolicy == request->mReferrerPolicy) { - rv = CheckContentPolicy(mDocument, aElement, request->mURI, type); + rv = CheckContentPolicy(mDocument, aElement, request->mURI, type, false); NS_ENSURE_SUCCESS(rv, false); } else { // Drop the preload diff --git a/dom/base/nsScriptLoader.h b/dom/base/nsScriptLoader.h index 06d323b113..a430e00605 100644 --- a/dom/base/nsScriptLoader.h +++ b/dom/base/nsScriptLoader.h @@ -337,7 +337,8 @@ public: static nsresult ShouldLoadScript(nsIDocument* aDocument, nsISupports* aContext, nsIURI* aURI, - const nsAString &aType); + const nsAString &aType, + bool aIsPreLoad); /** * Starts deferring deferred scripts and puts them in the mDeferredRequests @@ -418,7 +419,8 @@ private: static nsresult CheckContentPolicy(nsIDocument* aDocument, nsISupports *aContext, nsIURI *aURI, - const nsAString &aType); + const nsAString &aType, + bool aIsPreLoad); /** * Start a load for aRequest's URI. diff --git a/dom/fetch/ChannelInfo.cpp b/dom/fetch/ChannelInfo.cpp index 5ee01864a0..bf49e530ce 100644 --- a/dom/fetch/ChannelInfo.cpp +++ b/dom/fetch/ChannelInfo.cpp @@ -121,7 +121,10 @@ ChannelInfo::ResurrectInfoOnChannel(nsIChannel* aChannel) if (httpChannel) { net::HttpBaseChannel* httpBaseChannel = static_cast(httpChannel.get()); - httpBaseChannel->OverrideURI(redirectedURI); + rv = httpBaseChannel->OverrideURI(redirectedURI); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } } else { if (NS_WARN_IF(!jarChannel)) { return NS_ERROR_FAILURE; diff --git a/dom/media/IdpSandbox.jsm b/dom/media/IdpSandbox.jsm index 7c638b1003..4a644d71fa 100644 --- a/dom/media/IdpSandbox.jsm +++ b/dom/media/IdpSandbox.jsm @@ -40,16 +40,19 @@ function ResourceLoader(res, rej) { this.data = ''; } -/** Loads the identified https:// URL. */ -ResourceLoader.load = function(uri) { +/** Loads the identified https:// URL. */ +ResourceLoader.load = function(uri, doc) { return new Promise((resolve, reject) => { let listener = new ResourceLoader(resolve, reject); let ioService = Cc['@mozilla.org/network/io-service;1'] .getService(Ci.nsIIOService); let systemPrincipal = Services.scriptSecurityManager.getSystemPrincipal(); // the '2' identifies this as a script load - let ioChannel = ioService.newChannelFromURI2(uri, null, systemPrincipal, - systemPrincipal, 0, 2); + let ioChannel = ioService.newChannelFromURI2(uri, doc, doc.nodePrincipal, + systemPrincipal, 0, + Ci.nsIContentPolicy.TYPE_INTERNAL_SCRIPT); + + ioChannel.loadGroup = doc.documentLoadGroup.QueryInterface(Ci.nsILoadGroup); ioChannel.notificationCallbacks = new RedirectHttpsOnly(); ioChannel.asyncOpen(listener, null); }); @@ -110,12 +113,14 @@ function createLocationFromURI(uri) { * * @param domain (string) the domain of the IdP * @param protocol (string?) the protocol of the IdP [default: 'default'] + * @param doc (obj) the current document * @throws if the domain or protocol aren't valid */ -function IdpSandbox(domain, protocol) { +function IdpSandbox(domain, protocol, doc) { this.source = IdpSandbox.createIdpUri(domain, protocol || "default"); this.active = null; this.sandbox = null; + this.document = doc; } IdpSandbox.checkDomain = function(domain) { @@ -176,7 +181,7 @@ IdpSandbox.prototype = { start: function() { if (!this.active) { - this.active = ResourceLoader.load(this.source) + this.active = ResourceLoader.load(this.source, this.document) .then(result => this._createSandbox(result)); } return this.active; diff --git a/dom/media/PeerConnectionIdp.jsm b/dom/media/PeerConnectionIdp.jsm index daac5b392e..0248346e21 100644 --- a/dom/media/PeerConnectionIdp.jsm +++ b/dom/media/PeerConnectionIdp.jsm @@ -56,7 +56,7 @@ PeerConnectionIdp.prototype = { } this._idp.stop(); } - this._idp = new IdpSandbox(provider, protocol); + this._idp = new IdpSandbox(provider, protocol, this._win.document); }, // start the IdP and do some error fixup diff --git a/dom/workers/ServiceWorkerScriptCache.cpp b/dom/workers/ServiceWorkerScriptCache.cpp index 48b695585e..0b699cef0c 100644 --- a/dom/workers/ServiceWorkerScriptCache.cpp +++ b/dom/workers/ServiceWorkerScriptCache.cpp @@ -115,12 +115,12 @@ public: } // Note that because there is no "serviceworker" RequestContext type, we can - // use the external TYPE_SCRIPT content policy types when loading a service + // use the TYPE_INTERNAL_SCRIPT content policy types when loading a service // worker. rv = NS_NewChannel(getter_AddRefs(mChannel), uri, aPrincipal, nsILoadInfo::SEC_NORMAL, - nsIContentPolicy::TYPE_SCRIPT, + nsIContentPolicy::TYPE_INTERNAL_SCRIPT, loadGroup); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; diff --git a/dom/xul/XULDocument.cpp b/dom/xul/XULDocument.cpp index 4a8b46c349..76ae995148 100644 --- a/dom/xul/XULDocument.cpp +++ b/dom/xul/XULDocument.cpp @@ -3269,7 +3269,8 @@ XULDocument::LoadScript(nsXULPrototypeScript* aScriptProto, bool* aBlock) this, static_cast(this), aScriptProto->mSrcURI, - NS_LITERAL_STRING("application/x-javascript")); + NS_LITERAL_STRING("application/x-javascript"), + false); if (NS_FAILED(rv)) { *aBlock = false; return rv; diff --git a/js/public/HashTable.h b/js/public/HashTable.h index db4841c099..e8b212d25d 100644 --- a/js/public/HashTable.h +++ b/js/public/HashTable.h @@ -18,6 +18,7 @@ #include "mozilla/ReentrancyGuard.h" #include "mozilla/TemplateLib.h" #include "mozilla/TypeTraits.h" +#include "mozilla/UniquePtr.h" #include "js/Utility.h" @@ -593,6 +594,25 @@ template struct DefaultHasher : PointerHasher::value> {}; +// Specialize hashing policy for mozilla::UniquePtr to proxy the UniquePtr's +// raw pointer to PointerHasher. +template +struct DefaultHasher> +{ + using Lookup = mozilla::UniquePtr; + using PtrHasher = PointerHasher::value>; + + static HashNumber hash(const Lookup& l) { + return PtrHasher::hash(l.get()); + } + static bool match(const mozilla::UniquePtr& k, const Lookup& l) { + return PtrHasher::match(k.get(), l.get()); + } + static void rekey(mozilla::UniquePtr& k, mozilla::UniquePtr&& newKey) { + k = mozilla::Move(newKey); + } +}; + // For doubles, we can xor the two uint32s. template <> struct DefaultHasher diff --git a/js/public/TraceKind.h b/js/public/TraceKind.h index be5bef3b79..f4db1e20d8 100644 --- a/js/public/TraceKind.h +++ b/js/public/TraceKind.h @@ -98,7 +98,9 @@ JS_FOR_EACH_TRACEKIND(JS_EXPAND_DEF); // GCC and Clang require an explicit template declaration in front of the // specialization of operator() because it is a dependent template. MSVC, on // the other hand, gets very confused if we have a |template| token there. -#ifdef _MSC_VER +// The clang-cl front end defines _MSC_VER, but still requires the explicit +// template declaration, so we must test for __clang__ here as well. +#if defined(_MSC_VER) && !defined(__clang__) # define JS_DEPENDENT_TEMPLATE_HINT #else # define JS_DEPENDENT_TEMPLATE_HINT template diff --git a/js/src/builtin/Intl.cpp b/js/src/builtin/Intl.cpp index 5f92c86e4d..d91fa7c90c 100644 --- a/js/src/builtin/Intl.cpp +++ b/js/src/builtin/Intl.cpp @@ -2059,7 +2059,7 @@ static const JSFunctionSpec intl_static_methods[] = { * Spec: ECMAScript Internationalization API Specification, 8.0, 8.1 */ JSObject* -js::InitIntlClass(JSContext *cx, HandleObject obj) +js::InitIntlClass(JSContext* cx, HandleObject obj) { MOZ_ASSERT(obj->is()); Rooted global(cx, &obj->as()); diff --git a/js/src/builtin/ReflectParse.cpp b/js/src/builtin/ReflectParse.cpp index c97b4f3133..258b5c64cb 100644 --- a/js/src/builtin/ReflectParse.cpp +++ b/js/src/builtin/ReflectParse.cpp @@ -691,10 +691,10 @@ class NodeBuilder bool exportBatchSpecifier(TokenPos* pos, MutableHandleValue dst); - bool classDefinition(bool expr, HandleValue name, HandleValue heritage, HandleValue block, TokenPos *pos, + bool classDefinition(bool expr, HandleValue name, HandleValue heritage, HandleValue block, TokenPos* pos, MutableHandleValue dst); - bool classMethods(NodeVector &methods, MutableHandleValue dst); - bool classMethod(HandleValue name, HandleValue body, PropKind kind, bool isStatic, TokenPos *pos, MutableHandleValue dst); + bool classMethods(NodeVector& methods, MutableHandleValue dst); + bool classMethod(HandleValue name, HandleValue body, PropKind kind, bool isStatic, TokenPos* pos, MutableHandleValue dst); /* * expressions @@ -2813,8 +2813,8 @@ ASTSerializer::rightAssociate(ParseNode* pn, MutableHandleValue dst) ParseNode* next; while (current != nullptr) { - next = current->pn_next; - current->pn_next = prev; + next = current->pn_next; + current->pn_next = prev; prev = current; current = next; } @@ -3068,7 +3068,7 @@ ASTSerializer::expression(ParseNode* pn, MutableHandleValue dst) return leftAssociate(pn, dst); case PNK_POW: - return rightAssociate(pn, dst); + return rightAssociate(pn, dst); case PNK_DELETENAME: case PNK_DELETEPROP: diff --git a/js/src/builtin/TypedObject.cpp b/js/src/builtin/TypedObject.cpp index 7ee2156f9b..4e46764e7a 100644 --- a/js/src/builtin/TypedObject.cpp +++ b/js/src/builtin/TypedObject.cpp @@ -1922,7 +1922,7 @@ TypedObject::obj_setProperty(JSContext* cx, HandleObject obj, HandleId id, Handl uint32_t index; if (IdIsIndex(id, &index)) { if (!receiver.isObject() || obj != &receiver.toObject()) - return SetPropertyByDefining(cx, obj, id, v, receiver, false, result); + return SetPropertyByDefining(cx, obj, id, v, receiver, result); if (index >= uint32_t(typedObj->length())) { JS_ReportErrorNumber(cx, GetErrorMessage, @@ -1948,7 +1948,7 @@ TypedObject::obj_setProperty(JSContext* cx, HandleObject obj, HandleId id, Handl break; if (!receiver.isObject() || obj != &receiver.toObject()) - return SetPropertyByDefining(cx, obj, id, v, receiver, false, result); + return SetPropertyByDefining(cx, obj, id, v, receiver, result); size_t offset = descr->fieldOffset(fieldIndex); Rooted fieldType(cx, &descr->fieldDescr(fieldIndex)); @@ -2193,7 +2193,7 @@ InlineTransparentTypedObject::getOrCreateBuffer(JSContext* cx) return nullptr; } - JSObject *obj = table->lookup(this); + JSObject* obj = table->lookup(this); if (obj) return &obj->as(); @@ -2205,7 +2205,7 @@ InlineTransparentTypedObject::getOrCreateBuffer(JSContext* cx) // and its contents. gc::AutoSuppressGC suppress(cx); - ArrayBufferObject *buffer = + ArrayBufferObject* buffer = ArrayBufferObject::create(cx, nbytes, contents, ArrayBufferObject::DoesntOwnData); if (!buffer) return nullptr; diff --git a/js/src/jit-test/tests/basic/bug1172503-2.js b/js/src/jit-test/tests/basic/bug1172503-2.js new file mode 100644 index 0000000000..7f1ded8dc3 --- /dev/null +++ b/js/src/jit-test/tests/basic/bug1172503-2.js @@ -0,0 +1,10 @@ +var n = 0; +this.__proto__ = new Proxy({}, { + has: function () { + if (++n === 2) + return false; + a = 0; + } +}); +a = 0; +assertEq(a, 0); diff --git a/js/src/jit-test/tests/basic/bug1172503.js b/js/src/jit-test/tests/basic/bug1172503.js new file mode 100644 index 0000000000..5fda66ffe3 --- /dev/null +++ b/js/src/jit-test/tests/basic/bug1172503.js @@ -0,0 +1,9 @@ +// |jit-test| error: m is not defined +this.__proto__ = Proxy.create({ + has:function(){ + try { + aa0 = Function(undefined); + } catch (aa) {} + } +}); +m(); diff --git a/js/src/vm/NativeObject.cpp b/js/src/vm/NativeObject.cpp index a2b841e7e6..ad38ef4030 100644 --- a/js/src/vm/NativeObject.cpp +++ b/js/src/vm/NativeObject.cpp @@ -2073,7 +2073,7 @@ NativeSetExistingDataProperty(JSContext* cx, HandleNativeObject obj, HandleShape */ bool js::SetPropertyByDefining(JSContext* cx, HandleObject obj, HandleId id, HandleValue v, - HandleValue receiverValue, bool objHasOwn, ObjectOpResult& result) + HandleValue receiverValue, ObjectOpResult& result) { // Step 5.b. if (!receiverValue.isObject()) @@ -2081,25 +2081,7 @@ js::SetPropertyByDefining(JSContext* cx, HandleObject obj, HandleId id, HandleVa RootedObject receiver(cx, &receiverValue.toObject()); bool existing; - if (receiver == obj) { - // Steps 5.c-e.ii. - // The common case. The caller has necessarily done a property lookup - // on obj and passed us the answer as objHasOwn. - // We also know that the property is a data property and writable - // if it exists. -#ifdef DEBUG - // Check that objHasOwn is correct. This could fail if receiver or a - // native object on its prototype chain has a nondeterministic resolve - // hook. We shouldn't have any that are quite that badly behaved. - Rooted desc(cx); - if (!GetOwnPropertyDescriptor(cx, receiver, id, &desc)) - return false; - MOZ_ASSERT(!!desc.object() == objHasOwn); - MOZ_ASSERT_IF(desc.object(), desc.isDataDescriptor()); - MOZ_ASSERT_IF(desc.object(), desc.writable()); -#endif - existing = objHasOwn; - } else { + { // Steps 5.c-d. Rooted desc(cx); if (!GetOwnPropertyDescriptor(cx, receiver, id, &desc)) @@ -2174,7 +2156,7 @@ js::SetPropertyOnProto(JSContext* cx, HandleObject obj, HandleId id, HandleValue RootedObject proto(cx, obj->getProto()); if (proto) return SetProperty(cx, proto, id, v, receiver, result); - return SetPropertyByDefining(cx, obj, id, v, receiver, false, result); + return SetPropertyByDefining(cx, obj, id, v, receiver, result); } /* @@ -2196,7 +2178,7 @@ SetNonexistentProperty(JSContext* cx, HandleNativeObject obj, HandleId id, Handl return false; } - return SetPropertyByDefining(cx, obj, id, v, receiver, false, result); + return SetPropertyByDefining(cx, obj, id, v, receiver, result); } /* @@ -2257,7 +2239,7 @@ SetExistingProperty(JSContext* cx, HandleNativeObject obj, HandleId id, HandleVa return SetDenseOrTypedArrayElement(cx, pobj, JSID_TO_INT(id), v, result); // Steps 5.b-f. - return SetPropertyByDefining(cx, obj, id, v, receiver, obj == pobj, result); + return SetPropertyByDefining(cx, obj, id, v, receiver, result); } // Step 5 for all other properties. @@ -2295,7 +2277,7 @@ SetExistingProperty(JSContext* cx, HandleNativeObject obj, HandleId id, HandleVa // Shadow pobj[id] by defining a new data property receiver[id]. // Delegate everything to SetPropertyByDefining. - return SetPropertyByDefining(cx, obj, id, v, receiver, obj == pobj, result); + return SetPropertyByDefining(cx, obj, id, v, receiver, result); } // Steps 6-11. diff --git a/js/src/vm/NativeObject.h b/js/src/vm/NativeObject.h index 1a6c9ac2b8..b3521a1115 100644 --- a/js/src/vm/NativeObject.h +++ b/js/src/vm/NativeObject.h @@ -1315,7 +1315,7 @@ NativeGetElement(JSContext* cx, HandleNativeObject obj, uint32_t index, MutableH bool SetPropertyByDefining(JSContext* cx, HandleObject obj, HandleId id, HandleValue v, - HandleValue receiver, bool objHasOwn, ObjectOpResult& result); + HandleValue receiver, ObjectOpResult& result); bool SetPropertyOnProto(JSContext* cx, HandleObject obj, HandleId id, HandleValue v, diff --git a/js/src/vm/UnboxedObject-inl.h b/js/src/vm/UnboxedObject-inl.h index 3300607c86..66885126eb 100644 --- a/js/src/vm/UnboxedObject-inl.h +++ b/js/src/vm/UnboxedObject-inl.h @@ -620,8 +620,8 @@ CopyBoxedOrUnboxedDenseElements(JSContext* cx, JSObject* dst, JSObject* src, // Dispatch to specialized methods based on the type of an object. ///////////////////////////////////////////////////////////////////// -// Goop to fix MSVC. See CallTyped in jsgc.h. -#ifdef _MSC_VER +// Goop to fix MSVC. See DispatchTraceKindTyped in TraceKind.h. +#if defined(_MSC_VER) && !defined(__clang__) # define DEPENDENT_TEMPLATE_HINT #else # define DEPENDENT_TEMPLATE_HINT template diff --git a/js/src/vm/UnboxedObject.cpp b/js/src/vm/UnboxedObject.cpp index 31cd149200..5f38bb2159 100644 --- a/js/src/vm/UnboxedObject.cpp +++ b/js/src/vm/UnboxedObject.cpp @@ -822,7 +822,7 @@ UnboxedPlainObject::obj_setProperty(JSContext* cx, HandleObject obj, HandleId id return SetProperty(cx, obj, id, v, receiver, result); } - return SetPropertyByDefining(cx, obj, id, v, receiver, false, result); + return SetPropertyByDefining(cx, obj, id, v, receiver, result); } if (UnboxedExpandoObject* expando = obj->as().maybeExpando()) { @@ -1528,7 +1528,7 @@ UnboxedArrayObject::obj_setProperty(JSContext* cx, HandleObject obj, HandleId id return SetProperty(cx, obj, id, v, receiver, result); } - return SetPropertyByDefining(cx, obj, id, v, receiver, false, result); + return SetPropertyByDefining(cx, obj, id, v, receiver, result); } return SetPropertyOnProto(cx, obj, id, v, receiver, result); diff --git a/netwerk/base/nsIChannel.idl b/netwerk/base/nsIChannel.idl index cc9486f777..efd32c3525 100644 --- a/netwerk/base/nsIChannel.idl +++ b/netwerk/base/nsIChannel.idl @@ -29,7 +29,7 @@ interface nsIStreamListener; * * This interface must be used only from the XPCOM main thread. */ -[scriptable, uuid(cc3bff29-324e-4704-9eeb-1b8a62c4a9dc)] +[scriptable, uuid(2c389865-23db-4aa7-9fe5-60cc7b00697e)] interface nsIChannel : nsIRequest { /** @@ -192,7 +192,7 @@ interface nsIChannel : nsIRequest /************************************************************************** * Channel specific load flags: * - * Bits 23-31 are reserved for future use by this interface or one of its + * Bits 26-31 are reserved for future use by this interface or one of its * derivatives (e.g., see nsICachingChannel). */ @@ -272,6 +272,13 @@ interface nsIChannel : nsIRequest */ const unsigned long LOAD_EXPLICIT_CREDENTIALS = 1 << 24; + /** + * Set to force bypass of any service worker interception of the channel. + */ + const unsigned long LOAD_BYPASS_SERVICE_WORKER = 1 << 25; + + // nsICachingChannel load flags begin at bit 26. + /** * Access to the type implied or stated by the Content-Disposition header * if available and if applicable. This allows determining inline versus diff --git a/netwerk/protocol/http/HttpBaseChannel.cpp b/netwerk/protocol/http/HttpBaseChannel.cpp index 4cfd301701..34dd579ab0 100644 --- a/netwerk/protocol/http/HttpBaseChannel.cpp +++ b/netwerk/protocol/http/HttpBaseChannel.cpp @@ -76,6 +76,7 @@ HttpBaseChannel::HttpBaseChannel() , mResponseTimeoutEnabled(true) , mAllRedirectsSameOrigin(true) , mAllRedirectsPassTimingAllowCheck(true) + , mResponseCouldBeSynthesized(false) , mForceNoIntercept(false) , mAllowStaleCacheContent(false) , mSuspendCount(0) @@ -1498,24 +1499,47 @@ HttpBaseChannel::SetRedirectionLimit(uint32_t value) nsresult HttpBaseChannel::OverrideSecurityInfo(nsISupports* aSecurityInfo) { - MOZ_RELEASE_ASSERT(!mSecurityInfo, - "This can only be called when we don't have a security info object already"); + MOZ_ASSERT(!mSecurityInfo, + "This can only be called when we don't have a security info object already"); MOZ_RELEASE_ASSERT(aSecurityInfo, "This can only be called with a valid security info object"); - MOZ_RELEASE_ASSERT(ShouldIntercept(), - "This can only be called on channels that can be intercepted"); + MOZ_ASSERT(mResponseCouldBeSynthesized, + "This can only be called on channels that can be intercepted"); + if (mSecurityInfo) { + LOG(("HttpBaseChannel::OverrideSecurityInfo mSecurityInfo is null! " + "[this=%p]\n", this)); + return NS_ERROR_UNEXPECTED; + } + if (!mResponseCouldBeSynthesized) { + LOG(("HttpBaseChannel::OverrideSecurityInfo channel cannot be intercepted! " + "[this=%p]\n", this)); + return NS_ERROR_UNEXPECTED; + } + mSecurityInfo = aSecurityInfo; return NS_OK; } -void +nsresult HttpBaseChannel::OverrideURI(nsIURI* aRedirectedURI) { - MOZ_RELEASE_ASSERT(mLoadFlags & LOAD_REPLACE, - "This can only happen if the LOAD_REPLACE flag is set"); - MOZ_RELEASE_ASSERT(ShouldIntercept(), - "This can only be called on channels that can be intercepted"); + MOZ_ASSERT(mLoadFlags & LOAD_REPLACE, + "This can only happen if the LOAD_REPLACE flag is set"); + MOZ_ASSERT(ShouldIntercept(), + "This can only be called on channels that can be intercepted"); + if (!(mLoadFlags & LOAD_REPLACE)) { + LOG(("HttpBaseChannel::OverrideURI LOAD_REPLACE flag not set! [this=%p]\n", + this)); + return NS_ERROR_UNEXPECTED; + } + if (!mResponseCouldBeSynthesized) { + LOG(("HttpBaseChannel::OverrideURI channel cannot be intercepted! " + "[this=%p]\n", this)); + return NS_ERROR_UNEXPECTED; + } + mURI = aRedirectedURI; + return NS_OK; } NS_IMETHODIMP @@ -2013,6 +2037,7 @@ NS_IMETHODIMP HttpBaseChannel::ForceNoIntercept() { mForceNoIntercept = true; + mResponseCouldBeSynthesized = false; return NS_OK; } diff --git a/netwerk/protocol/http/HttpBaseChannel.h b/netwerk/protocol/http/HttpBaseChannel.h index 0b12d496b7..4cd146536f 100644 --- a/netwerk/protocol/http/HttpBaseChannel.h +++ b/netwerk/protocol/http/HttpBaseChannel.h @@ -247,7 +247,7 @@ public: const NetAddr& GetPeerAddr() { return mPeerAddr; } nsresult OverrideSecurityInfo(nsISupports* aSecurityInfo); - void OverrideURI(nsIURI* aRedirectedURI); + nsresult OverrideURI(nsIURI* aRedirectedURI); public: /* Necko internal use only... */ bool IsNavigation(); @@ -386,6 +386,9 @@ protected: // Used to enforce that flag's behavior but not expose it externally. uint32_t mAllowStaleCacheContent : 1; + // True if this channel was intercepted and could receive a synthesized response. + uint32_t mResponseCouldBeSynthesized : 1; + // Current suspension depth for this channel object uint32_t mSuspendCount; diff --git a/netwerk/protocol/http/HttpChannelChild.cpp b/netwerk/protocol/http/HttpChannelChild.cpp index bfd34410d0..de9a66838b 100644 --- a/netwerk/protocol/http/HttpChannelChild.cpp +++ b/netwerk/protocol/http/HttpChannelChild.cpp @@ -1548,6 +1548,8 @@ HttpChannelChild::AsyncOpen(nsIStreamListener *listener, nsISupports *aContext) } if (ShouldIntercept()) { + mResponseCouldBeSynthesized = true; + nsCOMPtr controller; GetCallback(controller); diff --git a/netwerk/protocol/http/nsHttpChannel.cpp b/netwerk/protocol/http/nsHttpChannel.cpp index c9b22f924b..aa28f68749 100644 --- a/netwerk/protocol/http/nsHttpChannel.cpp +++ b/netwerk/protocol/http/nsHttpChannel.cpp @@ -4900,6 +4900,7 @@ nsHttpChannel::AsyncOpen(nsIStreamListener *listener, nsISupports *context) if (ShouldIntercept()) { mInterceptCache = MAYBE_INTERCEPT; + mResponseCouldBeSynthesized = true; } // Remember the cookie header that was set, if any diff --git a/toolkit/components/viewsource/ViewSourceBrowser.jsm b/toolkit/components/viewsource/ViewSourceBrowser.jsm index 20685f78de..cb844fcd54 100644 --- a/toolkit/components/viewsource/ViewSourceBrowser.jsm +++ b/toolkit/components/viewsource/ViewSourceBrowser.jsm @@ -76,6 +76,8 @@ ViewSourceBrowser.prototype = { "ViewSource:PromptAndGoToLine", "ViewSource:GoToLine:Success", "ViewSource:GoToLine:Failed", + "ViewSource:StoreWrapping", + "ViewSource:StoreSyntaxHighlighting", ], /** @@ -133,6 +135,12 @@ ViewSourceBrowser.prototype = { case "ViewSource:GoToLine:Failed": this.onGoToLineFailed(); break; + case "ViewSource:StoreWrapping": + this.storeWrapping(data.state); + break; + case "ViewSource:StoreSyntaxHighlighting": + this.storeSyntaxHighlighting(data.state); + break; } }, @@ -647,6 +655,25 @@ ViewSourceBrowser.prototype = { this.bundle.GetStringFromName("outOfRangeText")); this.promptAndGoToLine(); }, + + /** + * Update the wrapping pref based on the child's current state. + * @param state + * Whether wrapping is currently enabled in the child. + */ + storeWrapping(state) { + Services.prefs.setBoolPref("view_source.wrap_long_lines", state); + }, + + /** + * Update the syntax highlighting pref based on the child's current state. + * @param state + * Whether syntax highlighting is currently enabled in the child. + */ + storeSyntaxHighlighting(state) { + Services.prefs.setBoolPref("view_source.syntax_highlight", state); + }, + }; /** diff --git a/toolkit/components/viewsource/content/viewSource-content.js b/toolkit/components/viewsource/content/viewSource-content.js index 969b0767e0..cb84977be2 100644 --- a/toolkit/components/viewsource/content/viewSource-content.js +++ b/toolkit/components/viewsource/content/viewSource-content.js @@ -672,20 +672,23 @@ let ViewSourceContent = { /** * Toggles the "wrap" class on the document body, which sets whether - * or not long lines are wrapped. + * or not long lines are wrapped. Notifies parent to update the pref. */ toggleWrapping() { let body = content.document.body; - body.classList.toggle("wrap"); + let state = body.classList.toggle("wrap"); + sendAsyncMessage("ViewSource:StoreWrapping", { state }); }, /** * Toggles the "highlight" class on the document body, which sets whether - * or not syntax highlighting is displayed. + * or not syntax highlighting is displayed. Notifies parent to update the + * pref. */ toggleSyntaxHighlighting() { let body = content.document.body; - body.classList.toggle("highlight"); + let state = body.classList.toggle("highlight"); + sendAsyncMessage("ViewSource:StoreSyntaxHighlighting", { state }); }, /** diff --git a/toolkit/components/viewsource/content/viewSource.js b/toolkit/components/viewsource/content/viewSource.js index b7f5657480..df8ae17587 100644 --- a/toolkit/components/viewsource/content/viewSource.js +++ b/toolkit/components/viewsource/content/viewSource.js @@ -131,6 +131,12 @@ ViewSourceChrome.prototype = { case "ViewSource:GoToLine:Failed": this.onGoToLineFailed(); break; + case "ViewSource:StoreWrapping": + this.storeWrapping(data.state); + break; + case "ViewSource:StoreSyntaxHighlighting": + this.storeSyntaxHighlighting(data.state); + break; // End messages from super class case "ViewSource:SourceLoaded": this.onSourceLoaded(); @@ -629,28 +635,18 @@ ViewSourceChrome.prototype = { }, /** - * Called when the user clicks on the "Wrap Long Lines" menu item, and - * flips the user preference for wrapping long lines in the view source - * browser. + * Called when the user clicks on the "Wrap Long Lines" menu item. */ toggleWrapping() { this.shouldWrap = !this.shouldWrap; - Services.prefs.setBoolPref("view_source.wrap_long_lines", - this.shouldWrap); this.sendAsyncMessage("ViewSource:ToggleWrapping"); }, /** - * Called when the user clicks on the "Syntax Highlighting" menu item, and - * flips the user preference for wrapping long lines in the view source - * browser. + * Called when the user clicks on the "Syntax Highlighting" menu item. */ toggleSyntaxHighlighting() { this.shouldHighlight = !this.shouldHighlight; - // We can't flip this value in the child, since prefs are read-only there. - // We flip it here, and then toggle a class in the child. - Services.prefs.setBoolPref("view_source.syntax_highlight", - this.shouldHighlight); this.sendAsyncMessage("ViewSource:ToggleSyntaxHighlighting"); }, diff --git a/toolkit/components/viewsource/test/browser/browser_viewsourceprefs.js b/toolkit/components/viewsource/test/browser/browser_viewsourceprefs.js index b76173173f..0227ee1241 100644 --- a/toolkit/components/viewsource/test/browser/browser_viewsourceprefs.js +++ b/toolkit/components/viewsource/test/browser/browser_viewsourceprefs.js @@ -41,25 +41,33 @@ let exercisePrefs = Task.async(function* (source, highlightable) { yield checkStyle(win, "white-space", "pre"); // Next, test that the Wrap Long Lines menu item works. + let prefReady = waitForPrefChange("view_source.wrap_long_lines"); simulateClick(wrapMenuItem); is(wrapMenuItem.hasAttribute("checked"), true, "Wrap menu item checked"); + yield prefReady; is(SpecialPowers.getBoolPref("view_source.wrap_long_lines"), true, "Wrap pref set"); yield checkStyle(win, "white-space", "pre-wrap"); + prefReady = waitForPrefChange("view_source.wrap_long_lines"); simulateClick(wrapMenuItem); is(wrapMenuItem.hasAttribute("checked"), false, "Wrap menu item unchecked"); + yield prefReady; is(SpecialPowers.getBoolPref("view_source.wrap_long_lines"), false, "Wrap pref set"); yield checkStyle(win, "white-space", "pre"); // Check that the Syntax Highlighting menu item works. + prefReady = waitForPrefChange("view_source.syntax_highlight"); simulateClick(syntaxMenuItem); is(syntaxMenuItem.hasAttribute("checked"), false, "Syntax menu item unchecked"); + yield prefReady; is(SpecialPowers.getBoolPref("view_source.syntax_highlight"), false, "Syntax highlighting pref set"); yield checkHighlight(win, false); + prefReady = waitForPrefChange("view_source.syntax_highlight"); simulateClick(syntaxMenuItem); is(syntaxMenuItem.hasAttribute("checked"), true, "Syntax menu item checked"); + yield prefReady; is(SpecialPowers.getBoolPref("view_source.syntax_highlight"), true, "Syntax highlighting pref set"); yield checkHighlight(win, highlightable); yield BrowserTestUtils.closeWindow(win); diff --git a/toolkit/components/viewsource/test/browser/head.js b/toolkit/components/viewsource/test/browser/head.js index 80fd482b70..26224b4fb1 100644 --- a/toolkit/components/viewsource/test/browser/head.js +++ b/toolkit/components/viewsource/test/browser/head.js @@ -2,6 +2,9 @@ * http://creativecommons.org/publicdomain/zero/1.0/ */ +Cu.import("resource://gre/modules/PromiseUtils.jsm"); +Cu.import("resource://gre/modules/Preferences.jsm"); + function openViewSourceWindow(aURI, aCallback) { let viewSourceWindow = openDialog("chrome://global/content/viewSource.xul", null, null, aURI); viewSourceWindow.addEventListener("pageshow", function pageShowHandler(event) { @@ -78,3 +81,13 @@ function openDocumentSelect(aURI, aCSSSelector, aCallback) { openViewPartialSourceWindow(selection, aCallback); }); } + +function waitForPrefChange(pref) { + let deferred = PromiseUtils.defer(); + let observer = () => { + Preferences.ignore(pref, observer); + deferred.resolve(); + }; + Preferences.observe(pref, observer); + return deferred.promise; +}