diff --git a/caps/BasePrincipal.cpp b/caps/BasePrincipal.cpp index 1f8907c932..c27c62eee4 100644 --- a/caps/BasePrincipal.cpp +++ b/caps/BasePrincipal.cpp @@ -303,13 +303,25 @@ BasePrincipal::GetCsp(nsIContentSecurityPolicy** aCsp) } NS_IMETHODIMP -BasePrincipal::SetCsp(nsIContentSecurityPolicy* aCsp) +BasePrincipal::EnsureCSP(nsIDOMDocument* aDocument, + nsIContentSecurityPolicy** aCSP) { if (mCSP) { - return NS_ERROR_ALREADY_INITIALIZED; + // if there is a CSP already associated with this principal + // then just return that - do not overwrite it!!! + NS_IF_ADDREF(*aCSP = mCSP); + return NS_OK; } - mCSP = aCsp; + nsresult rv = NS_OK; + mCSP = do_CreateInstance("@mozilla.org/cspcontext;1", &rv); + NS_ENSURE_SUCCESS(rv, rv); + + // Store the request context for violation reports + rv = aDocument ? mCSP->SetRequestContext(aDocument, nullptr) + : mCSP->SetRequestContext(nullptr, this); + NS_ENSURE_SUCCESS(rv, rv); + NS_IF_ADDREF(*aCSP = mCSP); return NS_OK; } @@ -321,12 +333,25 @@ BasePrincipal::GetPreloadCsp(nsIContentSecurityPolicy** aPreloadCSP) } NS_IMETHODIMP -BasePrincipal::SetPreloadCsp(nsIContentSecurityPolicy* aPreloadCSP) +BasePrincipal::EnsurePreloadCSP(nsIDOMDocument* aDocument, + nsIContentSecurityPolicy** aPreloadCSP) { if (mPreloadCSP) { - return NS_ERROR_ALREADY_INITIALIZED; + // if there is a speculative CSP already associated with this principal + // then just return that - do not overwrite it!!! + NS_IF_ADDREF(*aPreloadCSP = mPreloadCSP); + return NS_OK; } - mPreloadCSP = aPreloadCSP; + + nsresult rv = NS_OK; + mPreloadCSP = do_CreateInstance("@mozilla.org/cspcontext;1", &rv); + NS_ENSURE_SUCCESS(rv, rv); + + // Store the request context for violation reports + rv = aDocument ? mPreloadCSP->SetRequestContext(aDocument, nullptr) + : mPreloadCSP->SetRequestContext(nullptr, this); + NS_ENSURE_SUCCESS(rv, rv); + NS_IF_ADDREF(*aPreloadCSP = mPreloadCSP); return NS_OK; } diff --git a/caps/BasePrincipal.h b/caps/BasePrincipal.h index e3918582a3..d8faed7f82 100644 --- a/caps/BasePrincipal.h +++ b/caps/BasePrincipal.h @@ -144,9 +144,9 @@ public: NS_IMETHOD SubsumesConsideringDomain(nsIPrincipal* other, bool* _retval) final; NS_IMETHOD CheckMayLoad(nsIURI* uri, bool report, bool allowIfInheritsPrincipal) final; NS_IMETHOD GetCsp(nsIContentSecurityPolicy** aCsp) override; - NS_IMETHOD SetCsp(nsIContentSecurityPolicy* aCsp) override; + NS_IMETHOD EnsureCSP(nsIDOMDocument* aDocument, nsIContentSecurityPolicy** aCSP) override; NS_IMETHOD GetPreloadCsp(nsIContentSecurityPolicy** aPreloadCSP) override; - NS_IMETHOD SetPreloadCsp(nsIContentSecurityPolicy* aPreloadCSP) override; + NS_IMETHOD EnsurePreloadCSP(nsIDOMDocument* aDocument, nsIContentSecurityPolicy** aCSP) override; NS_IMETHOD GetCspJSON(nsAString& outCSPinJSON) override; NS_IMETHOD GetIsNullPrincipal(bool* aResult) override; NS_IMETHOD GetIsCodebasePrincipal(bool* aResult) override; diff --git a/caps/nsIPrincipal.idl b/caps/nsIPrincipal.idl index 0b692d6d47..277561a838 100644 --- a/caps/nsIPrincipal.idl +++ b/caps/nsIPrincipal.idl @@ -15,12 +15,13 @@ struct JSPrincipals; interface nsIURI; interface nsIContentSecurityPolicy; +interface nsIDOMDocument; [ptr] native JSContext(JSContext); [ptr] native JSPrincipals(JSPrincipals); [ptr] native PrincipalArray(nsTArray >); -[scriptable, builtinclass, uuid(188fc4a2-3157-4956-a7a2-d674991770da)] +[scriptable, builtinclass, uuid(d0391e86-1ad7-4ab0-bb7c-14d6d9967369)] interface nsIPrincipal : nsISerializable { /** @@ -142,12 +143,19 @@ interface nsIPrincipal : nsISerializable /** * A Content Security Policy associated with this principal. * - * Please note that if a csp was already set on the - * principal, then it should not be destroyed! Instead, the - * current csp should be quried and extended by - * calling AppendPolicy() on it. + * Use this function to query the associated CSP with this principal. */ - [noscript] attribute nsIContentSecurityPolicy csp; + [noscript] readonly attribute nsIContentSecurityPolicy csp; + + /* + * Use this function to query a CSP associated with this principal. + * If no CSP is associated with this principal then one is created + * internally and setRequestContext is called on the CSP using aDocument. + * + * Please note if aDocument is null, then setRequestContext on the + * CSP object is called using the current principal. + */ + [noscript] nsIContentSecurityPolicy ensureCSP(in nsIDOMDocument aDocument); /** * A speculative Content Security Policy associated with this @@ -156,13 +164,19 @@ interface nsIPrincipal : nsISerializable * * If you want to query the CSP associated with that principal, * then this is *not* what you want. Instead query 'csp'. - * - * Please note that if a preloadCSP was already set on the - * principal, then it should not be destroyed! Instead, the - * current preloadCSP should be quried and extended by - * calling AppendPolicy() on it. */ - [noscript] attribute nsIContentSecurityPolicy preloadCsp; + [noscript] readonly attribute nsIContentSecurityPolicy preloadCsp; + + /* + * Use this function to query a speculative CSP associated with this + * principal. If no speculative CSP is associated with this principal + * then one is created internally and setRequestContext is called on + * the CSP using aDocument. + * + * Please note if aDocument is null, then setRequestContext on the + * speculative CSP object is called using the current principal. + */ + [noscript] nsIContentSecurityPolicy ensurePreloadCSP(in nsIDOMDocument aDocument); /** * The CSP of the principal in JSON notation. diff --git a/caps/nsPrincipal.cpp b/caps/nsPrincipal.cpp index 80e2c1ad57..c0744528b9 100644 --- a/caps/nsPrincipal.cpp +++ b/caps/nsPrincipal.cpp @@ -398,19 +398,14 @@ nsPrincipal::Read(nsIObjectInputStream* aStream) rv = NS_ReadOptionalObject(aStream, true, getter_AddRefs(supports)); NS_ENSURE_SUCCESS(rv, rv); - // This may be null. - nsCOMPtr csp = do_QueryInterface(supports, &rv); - rv = Init(codebase, attrs); NS_ENSURE_SUCCESS(rv, rv); - rv = SetCsp(csp); - NS_ENSURE_SUCCESS(rv, rv); - - // need to link in the CSP context here (link in the URI of the protected - // resource). - if (csp) { - csp->SetRequestContext(nullptr, this); + mCSP = do_QueryInterface(supports, &rv); + // make sure setRequestContext is called after Init(), + // to make sure the principals URI been initalized. + if (mCSP) { + mCSP->SetRequestContext(nullptr, this); } SetDomain(domain); diff --git a/caps/nsSystemPrincipal.cpp b/caps/nsSystemPrincipal.cpp index e8f52f1869..1711f367f6 100644 --- a/caps/nsSystemPrincipal.cpp +++ b/caps/nsSystemPrincipal.cpp @@ -70,7 +70,8 @@ nsSystemPrincipal::GetCsp(nsIContentSecurityPolicy** aCsp) } NS_IMETHODIMP -nsSystemPrincipal::SetCsp(nsIContentSecurityPolicy* aCsp) +nsSystemPrincipal::EnsureCSP(nsIDOMDocument* aDocument, + nsIContentSecurityPolicy** aCSP) { // CSP on a system principal makes no sense return NS_OK; @@ -84,7 +85,8 @@ nsSystemPrincipal::GetPreloadCsp(nsIContentSecurityPolicy** aPreloadCSP) } NS_IMETHODIMP -nsSystemPrincipal::SetPreloadCsp(nsIContentSecurityPolicy* aPreloadCSP) +nsSystemPrincipal::EnsurePreloadCSP(nsIDOMDocument* aDocument, + nsIContentSecurityPolicy** aPreloadCSP) { // CSP on a system principal makes no sense return NS_OK; diff --git a/caps/nsSystemPrincipal.h b/caps/nsSystemPrincipal.h index 03e9175f1a..8c57196c76 100644 --- a/caps/nsSystemPrincipal.h +++ b/caps/nsSystemPrincipal.h @@ -30,9 +30,9 @@ public: NS_IMETHOD GetDomain(nsIURI** aDomain) override; NS_IMETHOD SetDomain(nsIURI* aDomain) override; NS_IMETHOD GetCsp(nsIContentSecurityPolicy** aCsp) override; - NS_IMETHOD SetCsp(nsIContentSecurityPolicy* aCsp) override; + NS_IMETHOD EnsureCSP(nsIDOMDocument* aDocument, nsIContentSecurityPolicy** aCSP) override; NS_IMETHOD GetPreloadCsp(nsIContentSecurityPolicy** aPreloadCSP) override; - NS_IMETHOD SetPreloadCsp(nsIContentSecurityPolicy* aPreloadCSP) override; + NS_IMETHOD EnsurePreloadCSP(nsIDOMDocument* aDocument, nsIContentSecurityPolicy** aCSP) override; NS_IMETHOD GetBaseDomain(nsACString& aBaseDomain) override; nsresult GetOriginInternal(nsACString& aOrigin) override; diff --git a/dom/base/Attr.cpp b/dom/base/Attr.cpp index 4c9a8950bd..bc74558669 100644 --- a/dom/base/Attr.cpp +++ b/dom/base/Attr.cpp @@ -28,9 +28,8 @@ #include "nsWrapperCacheInlines.h" nsIAttribute::nsIAttribute(nsDOMAttributeMap* aAttrMap, - already_AddRefed& aNodeInfo, - bool aNsAware) -: nsINode(aNodeInfo), mAttrMap(aAttrMap), mNsAware(aNsAware) + already_AddRefed& aNodeInfo) +: nsINode(aNodeInfo), mAttrMap(aAttrMap) { } @@ -46,8 +45,8 @@ bool Attr::sInitialized; Attr::Attr(nsDOMAttributeMap *aAttrMap, already_AddRefed&& aNodeInfo, - const nsAString &aValue, bool aNsAware) - : nsIAttribute(aAttrMap, aNodeInfo, aNsAware), mValue(aValue) + const nsAString &aValue) + : nsIAttribute(aAttrMap, aNodeInfo), mValue(aValue) { MOZ_ASSERT(mNodeInfo, "We must get a nodeinfo here!"); MOZ_ASSERT(mNodeInfo->NodeType() == nsIDOMNode::ATTRIBUTE_NODE, @@ -262,7 +261,7 @@ Attr::Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const const_cast(this)->GetValue(value); RefPtr ni = aNodeInfo; - *aResult = new Attr(nullptr, ni.forget(), value, mNsAware); + *aResult = new Attr(nullptr, ni.forget(), value); if (!*aResult) { return NS_ERROR_OUT_OF_MEMORY; } diff --git a/dom/base/Attr.h b/dom/base/Attr.h index f772ba3222..3f80030d22 100644 --- a/dom/base/Attr.h +++ b/dom/base/Attr.h @@ -37,8 +37,7 @@ class Attr final : public nsIAttribute, public: Attr(nsDOMAttributeMap* aAttrMap, already_AddRefed&& aNodeInfo, - const nsAString& aValue, - bool aNsAware); + const nsAString& aValue); NS_DECL_CYCLE_COLLECTING_ISUPPORTS diff --git a/dom/base/WebSocket.cpp b/dom/base/WebSocket.cpp index 45268ff7bc..7c23a188b9 100644 --- a/dom/base/WebSocket.cpp +++ b/dom/base/WebSocket.cpp @@ -1563,7 +1563,7 @@ WebSocketImpl::Init(JSContext* aCx, // to reflect that upgrade. Please note that we can not upgrade from ws: // to wss: before performing content policy checks because CSP needs to // send reports in case the scheme is about to be upgraded. - if (!mSecure && originDoc && originDoc->GetUpgradeInsecureRequests()) { + if (!mSecure && originDoc && originDoc->GetUpgradeInsecureRequests(false)) { // let's use the old specification before the upgrade for logging NS_ConvertUTF8toUTF16 reportSpec(mURI); diff --git a/dom/base/nsContentPolicy.cpp b/dom/base/nsContentPolicy.cpp index 9a2ee81812..33faadbdd5 100644 --- a/dom/base/nsContentPolicy.cpp +++ b/dom/base/nsContentPolicy.cpp @@ -116,12 +116,6 @@ nsContentPolicy::CheckPolicy(CPMethod policyMethod, nsContentPolicyType externalType = nsContentUtils::InternalContentPolicyTypeToExternal(contentType); - nsContentPolicyType externalTypeOrMCBInternal = - nsContentUtils::InternalContentPolicyTypeToExternalOrMCBInternal(contentType); - - nsContentPolicyType externalTypeOrCSPInternal = - nsContentUtils::InternalContentPolicyTypeToExternalOrCSPInternal(contentType); - nsCOMPtr mixedContentBlocker = do_GetService(NS_MIXEDCONTENTBLOCKER_CONTRACTID); @@ -138,27 +132,10 @@ nsContentPolicy::CheckPolicy(CPMethod policyMethod, int32_t count = entries.Count(); for (int32_t i = 0; i < count; i++) { /* check the appropriate policy */ - // Send the internal content policy type to the mixed content blocker - // which needs to know about TYPE_INTERNAL_WORKER, - // TYPE_INTERNAL_SHARED_WORKER and TYPE_INTERNAL_SERVICE_WORKER - // and also preloads: TYPE_INTERNAL_SCRIPT_PRELOAD, - // TYPE_INTERNAL_IMAGE_PRELOAD, TYPE_INTERNAL_STYLESHEET_PRELOAD - bool isMixedContentBlocker = mixedContentBlocker == entries[i]; + // Send internal content policy type to CSP and mixed content blocker nsContentPolicyType type = externalType; - if (isMixedContentBlocker) { - type = externalTypeOrMCBInternal; - } - // Send the internal content policy type for CSP which needs to - // know about preloads and workers, in particular: - // * TYPE_INTERNAL_SCRIPT_PRELOAD - // * TYPE_INTERNAL_IMAGE_PRELOAD - // * TYPE_INTERNAL_STYLESHEET_PRELOAD - // * TYPE_INTERNAL_WORKER - // * TYPE_INTERNAL_SHARED_WORKER - // * TYPE_INTERNAL_SERVICE_WORKER - bool isCSP = cspService == entries[i]; - if (isCSP) { - type = externalTypeOrCSPInternal; + if (mixedContentBlocker == entries[i] || cspService == entries[i]) { + type = contentType; } rv = (entries[i]->*policyMethod)(type, contentLocation, requestingLocation, requestingContext, diff --git a/dom/base/nsContentTypeParser.h b/dom/base/nsContentTypeParser.h index 1b05a6b52d..e6bf64d855 100644 --- a/dom/base/nsContentTypeParser.h +++ b/dom/base/nsContentTypeParser.h @@ -17,10 +17,7 @@ public: ~nsContentTypeParser(); nsresult GetParameter(const char* aParameterName, nsAString& aResult); - nsresult GetType(nsAString& aResult) - { - return GetParameter(nullptr, aResult); - } + nsresult GetType(nsAString& aResult); private: NS_ConvertUTF16toUTF8 mString; diff --git a/dom/base/nsContentUtils.cpp b/dom/base/nsContentUtils.cpp index e9b1154144..742d66a006 100644 --- a/dom/base/nsContentUtils.cpp +++ b/dom/base/nsContentUtils.cpp @@ -11,7 +11,6 @@ #include #include -#include "prprf.h" #include "DecoderTraits.h" #include "harfbuzz/hb.h" #include "imgICache.h" @@ -560,7 +559,7 @@ nsContentUtils::Init() "dom.performance.enable_user_timing_logging", false); Preferences::AddBoolVarCache(&sIsFrameTimingPrefEnabled, - "dom.enable_frame_timing", true); + "dom.enable_frame_timing", false); Preferences::AddBoolVarCache(&sIsExperimentalAutocompleteEnabled, "dom.forms.autocomplete.experimental", false); @@ -2789,11 +2788,14 @@ nsContentUtils::IsCustomElementName(nsIAtom* aName) { // The custom element name identifies a custom element and is a sequence of // alphanumeric ASCII characters that must match the NCName production and - // contain a U+002D HYPHEN-MINUS character. + // contain a U+002D HYPHEN-MINUS character. We check for the HYPHEN-MINUS + // first, since that will typically not be present, which will allow us to + // return before doing the more expensive (and generally passing) CheckQName + // check. nsDependentAtomString str(aName); const char16_t* colon; - if (NS_FAILED(nsContentUtils::CheckQName(str, false, &colon)) || colon || - str.FindChar('-') == -1) { + if (str.FindChar('-') == -1 || + NS_FAILED(nsContentUtils::CheckQName(str, false, &colon)) || colon) { return false; } @@ -3538,7 +3540,7 @@ nsContentUtils::ReportToConsoleNonLocalized(const nsAString& aErrorText, } void -nsContentUtils::LogMessageToConsole(const char* aMsg, ...) +nsContentUtils::LogMessageToConsole(const char* aMsg) { if (!sConsoleService) { // only need to bother null-checking here CallGetService(NS_CONSOLESERVICE_CONTRACTID, &sConsoleService); @@ -3546,17 +3548,7 @@ nsContentUtils::LogMessageToConsole(const char* aMsg, ...) return; } } - - va_list args; - va_start(args, aMsg); - char* formatted = PR_vsmprintf(aMsg, args); - va_end(args); - if (!formatted) { - return; - } - - sConsoleService->LogStringMessage(NS_ConvertUTF8toUTF16(formatted).get()); - PR_smprintf_free(formatted); + sConsoleService->LogStringMessage(NS_ConvertUTF8toUTF16(aMsg).get()); } bool @@ -6095,12 +6087,21 @@ nsContentTypeParser::GetParameter(const char* aParameterName, nsAString& aResult aResult); } +nsresult +nsContentTypeParser::GetType(nsAString& aResult) +{ + nsresult rv = GetParameter(nullptr, aResult); + NS_ENSURE_SUCCESS(rv, rv); + nsContentUtils::ASCIIToLower(aResult); + return NS_OK; +} + /* static */ bool nsContentUtils::CanAccessNativeAnon() { - return IsCallerChrome() || IsCallerContentXBL(); + return LegacyIsCallerChromeOrNativeCode() || IsCallerContentXBL(); } /* static */ nsresult @@ -6631,6 +6632,48 @@ nsContentUtils::FindInternalContentViewer(const nsACString& aType, return nullptr; } +static void +ReportPatternCompileFailure(nsAString& aPattern, nsIDocument* aDocument, + JSContext* cx) +{ + MOZ_ASSERT(JS_IsExceptionPending(cx)); + + JS::RootedValue exn(cx); + if (!JS_GetPendingException(cx, &exn)) { + return; + } + if (!exn.isObject()) { + // If pending exception is not an object, it should be OOM. + return; + } + + JS::AutoSaveExceptionState savedExc(cx); + JS::RootedObject exnObj(cx, &exn.toObject()); + JS::RootedValue messageVal(cx); + if (!JS_GetProperty(cx, exnObj, "message", &messageVal)) { + return; + } + MOZ_ASSERT(messageVal.isString()); + + JS::RootedString messageStr(cx, messageVal.toString()); + MOZ_ASSERT(messageStr); + + nsAutoString wideMessage; + if (!AssignJSString(cx, wideMessage, messageStr)) { + return; + } + + const nsString& pattern = PromiseFlatString(aPattern); + const char16_t *strings[] = { pattern.get(), wideMessage.get() }; + nsContentUtils::ReportToConsole(nsIScriptError::errorFlag, + NS_LITERAL_CSTRING("DOM"), + aDocument, + nsContentUtils::eDOM_PROPERTIES, + "PatternAttributeCompileFailure", + strings, ArrayLength(strings)); + savedExc.drop(); +} + // static bool nsContentUtils::IsPatternMatching(nsAString& aValue, nsAString& aPattern, @@ -6657,8 +6700,12 @@ nsContentUtils::IsPatternMatching(nsAString& aValue, nsAString& aPattern, JS::Rooted re(cx, JS_NewUCRegExpObjectNoStatics(cx, static_cast(aPattern.BeginWriting()), - aPattern.Length(), 0)); + aPattern.Length(), JSREG_UNICODE)); if (!re) { + // Remove extra patterns added above to report with the original pattern. + aPattern.Cut(0, 4); + aPattern.Cut(aPattern.Length() - 2, 2); + ReportPatternCompileFailure(aPattern, aDocument, cx); return true; } @@ -6782,66 +6829,6 @@ nsContentUtils::HaveEqualPrincipals(nsIDocument* aDoc1, nsIDocument* aDoc2) return principalsEqual; } -static void -CheckForWindowedPlugins(nsISupports* aSupports, void* aResult) -{ - nsCOMPtr content(do_QueryInterface(aSupports)); - if (!content || !content->IsInDoc()) { - return; - } - nsCOMPtr olc(do_QueryInterface(content)); - if (!olc) { - return; - } - RefPtr plugin; - olc->GetPluginInstance(getter_AddRefs(plugin)); - if (!plugin) { - return; - } - bool isWindowless = false; - nsresult res = plugin->IsWindowless(&isWindowless); - if (NS_SUCCEEDED(res) && !isWindowless) { - *static_cast(aResult) = true; - } -} - -static bool -DocTreeContainsWindowedPlugins(nsIDocument* aDoc, void* aResult) -{ - if (!nsContentUtils::IsChromeDoc(aDoc)) { - aDoc->EnumerateActivityObservers(CheckForWindowedPlugins, aResult); - } - if (*static_cast(aResult)) { - // Return false to stop iteration, we found a windowed plugin. - return false; - } - aDoc->EnumerateSubDocuments(DocTreeContainsWindowedPlugins, aResult); - // Return false to stop iteration if we found a windowed plugin in - // the sub documents. - return !*static_cast(aResult); -} - -/* static */ -bool -nsContentUtils::HasPluginWithUncontrolledEventDispatch(nsIDocument* aDoc) -{ -#ifdef XP_MACOSX - // We control dispatch to all mac plugins. - return false; -#endif - bool result = false; - - // Find the top of the document's branch, the child of the chrome document. - nsIDocument* doc = aDoc; - nsIDocument* parent = nullptr; - while (doc && (parent = doc->GetParentDocument()) && !IsChromeDoc(parent)) { - doc = parent; - } - - DocTreeContainsWindowedPlugins(doc, &result); - return result; -} - /* static */ bool nsContentUtils::HasPluginWithUncontrolledEventDispatch(nsIContent* aContent) @@ -6849,10 +6836,30 @@ nsContentUtils::HasPluginWithUncontrolledEventDispatch(nsIContent* aContent) #ifdef XP_MACOSX // We control dispatch to all mac plugins. return false; +#else + if (!aContent || !aContent->IsInDoc()) { + return false; + } + + nsCOMPtr olc = do_QueryInterface(aContent); + if (!olc) { + return false; + } + + RefPtr plugin; + olc->GetPluginInstance(getter_AddRefs(plugin)); + if (!plugin) { + return false; + } + + bool isWindowless = false; + nsresult res = plugin->IsWindowless(&isWindowless); + if (NS_FAILED(res)) { + return false; + } + + return !isWindowless; #endif - bool result = false; - CheckForWindowedPlugins(aContent, &result); - return result; } /* static */ @@ -7298,13 +7305,13 @@ nsContentUtils::GetInnerWindowID(nsIRequest* aRequest) return inner ? inner->WindowID() : 0; } -void +nsresult nsContentUtils::GetHostOrIPv6WithBrackets(nsIURI* aURI, nsCString& aHost) { aHost.Truncate(); nsresult rv = aURI->GetHost(aHost); if (NS_FAILED(rv)) { // Some URIs do not have a host - return; + return rv; } if (aHost.FindChar(':') != -1) { // Escape IPv6 address @@ -7313,14 +7320,20 @@ nsContentUtils::GetHostOrIPv6WithBrackets(nsIURI* aURI, nsCString& aHost) aHost.Insert('[', 0); aHost.Append(']'); } + + return NS_OK; } -void +nsresult nsContentUtils::GetHostOrIPv6WithBrackets(nsIURI* aURI, nsAString& aHost) { nsAutoCString hostname; - GetHostOrIPv6WithBrackets(aURI, hostname); + nsresult rv = GetHostOrIPv6WithBrackets(aURI, hostname); + if (NS_FAILED(rv)) { + return rv; + } CopyUTF8toUTF16(hostname, aHost); + return NS_OK; } void @@ -7556,7 +7569,9 @@ nsContentUtils::TransferableToIPCTransferable(nsITransferable* aTransferable, if (IsFileImage(file, type)) { IPCDataTransferItem* item = aIPCDataTransfer->items().AppendElement(); item->flavor() = type; - SlurpFileToString(file, item->data()); + nsAutoCString data; + SlurpFileToString(file, data); + item->data() = data; } continue; @@ -7868,23 +7883,26 @@ nsContentUtils::SendMouseEvent(nsCOMPtr aPresShell, EventMessage msg; bool contextMenuKey = false; - if (aType.EqualsLiteral("mousedown")) + if (aType.EqualsLiteral("mousedown")) { msg = eMouseDown; - else if (aType.EqualsLiteral("mouseup")) + } else if (aType.EqualsLiteral("mouseup")) { msg = eMouseUp; - else if (aType.EqualsLiteral("mousemove")) + } else if (aType.EqualsLiteral("mousemove")) { msg = eMouseMove; - else if (aType.EqualsLiteral("mouseover")) + } else if (aType.EqualsLiteral("mouseover")) { msg = eMouseEnterIntoWidget; - else if (aType.EqualsLiteral("mouseout")) + } else if (aType.EqualsLiteral("mouseout")) { msg = eMouseExitFromWidget; - else if (aType.EqualsLiteral("contextmenu")) { + } else if (aType.EqualsLiteral("mouselongtap")) { + msg = eMouseLongTap; + } else if (aType.EqualsLiteral("contextmenu")) { msg = eContextMenu; contextMenuKey = (aButton == 0); - } else if (aType.EqualsLiteral("MozMouseHittest")) + } else if (aType.EqualsLiteral("MozMouseHittest")) { msg = eMouseHitTest; - else + } else { return NS_ERROR_FAILURE; + } if (aInputSourceArg == nsIDOMMouseEvent::MOZ_SOURCE_UNKNOWN) { aInputSourceArg = nsIDOMMouseEvent::MOZ_SOURCE_MOUSE; @@ -8041,35 +8059,6 @@ nsContentUtils::InternalContentPolicyTypeToExternal(nsContentPolicyType aType) } } -/* static */ -nsContentPolicyType -nsContentUtils::InternalContentPolicyTypeToExternalOrMCBInternal(nsContentPolicyType aType) -{ - switch (aType) { - case nsIContentPolicy::TYPE_INTERNAL_SCRIPT: - case nsIContentPolicy::TYPE_INTERNAL_WORKER: - case nsIContentPolicy::TYPE_INTERNAL_SHARED_WORKER: - case nsIContentPolicy::TYPE_INTERNAL_SERVICE_WORKER: - return aType; - - default: - return InternalContentPolicyTypeToExternalOrPreload(aType); - } -} - -/* static */ -nsContentPolicyType -nsContentUtils::InternalContentPolicyTypeToExternalOrPreload(nsContentPolicyType aType) -{ - if (aType == nsIContentPolicy::TYPE_INTERNAL_SCRIPT_PRELOAD || - aType == nsIContentPolicy::TYPE_INTERNAL_IMAGE_PRELOAD || - aType == nsIContentPolicy::TYPE_INTERNAL_STYLESHEET_PRELOAD) { - return aType; - } - return InternalContentPolicyTypeToExternal(aType); -} - - /* static */ nsContentPolicyType nsContentUtils::InternalContentPolicyTypeToExternalOrWorker(nsContentPolicyType aType) @@ -8097,17 +8086,6 @@ nsContentUtils::IsPreloadType(nsContentPolicyType aType) return false; } -/* static */ -nsContentPolicyType -nsContentUtils::InternalContentPolicyTypeToExternalOrCSPInternal(nsContentPolicyType aType) -{ - if (aType == InternalContentPolicyTypeToExternalOrWorker(aType) || - aType == InternalContentPolicyTypeToExternalOrPreload(aType)) { - return aType; - } - return InternalContentPolicyTypeToExternal(aType); -} - nsresult nsContentUtils::SetFetchReferrerURIWithPolicy(nsIPrincipal* aPrincipal, nsIDocument* aDoc, @@ -8249,6 +8227,24 @@ nsContentUtils::InternalStorageAllowedForPrincipal(nsIPrincipal* aPrincipal, } } + nsCOMPtr permissionManager = + services::GetPermissionManager(); + if (!permissionManager) { + return StorageAccess::eDeny; + } + + // check the permission manager for any allow or deny permissions + // for cookies for the window. + uint32_t perm; + permissionManager->TestPermissionFromPrincipal(aPrincipal, "cookie", &perm); + if (perm == nsIPermissionManager::DENY_ACTION) { + return StorageAccess::eDeny; + } else if (perm == nsICookiePermission::ACCESS_SESSION) { + return std::min(access, StorageAccess::eSessionScoped); + } else if (perm == nsIPermissionManager::ALLOW_ACTION) { + return access; + } + // Check if we should only allow storage for the session, and record that fact if (sCookiesLifetimePolicy == nsICookieService::ACCEPT_SESSION) { // Storage could be StorageAccess::ePrivateBrowsing or StorageAccess::eAllow @@ -8270,24 +8266,6 @@ nsContentUtils::InternalStorageAllowedForPrincipal(nsIPrincipal* aPrincipal, } } - nsCOMPtr permissionManager = - services::GetPermissionManager(); - if (!permissionManager) { - return StorageAccess::eDeny; - } - - // check the permission manager for any allow or deny permissions - // for cookies for the window. - uint32_t perm; - permissionManager->TestPermissionFromPrincipal(aPrincipal, "cookie", &perm); - if (perm == nsIPermissionManager::DENY_ACTION) { - return StorageAccess::eDeny; - } else if (perm == nsICookiePermission::ACCESS_SESSION) { - return std::min(access, StorageAccess::eSessionScoped); - } else if (perm == nsIPermissionManager::ALLOW_ACTION) { - return access; - } - // We don't want to prompt for every attempt to access permissions. if (sCookiesBehavior == nsICookieService::BEHAVIOR_REJECT) { return StorageAccess::eDeny; diff --git a/dom/base/nsContentUtils.h b/dom/base/nsContentUtils.h index 36618d264f..8067dbd4ca 100644 --- a/dom/base/nsContentUtils.h +++ b/dom/base/nsContentUtils.h @@ -876,8 +876,8 @@ public: uint32_t aLineNumber = 0, uint32_t aColumnNumber = 0); - static void LogMessageToConsole(const char* aMsg, ...); - + static void LogMessageToConsole(const char* aMsg); + /** * Get the localized string named |aKey| in properties file |aFile|. */ @@ -967,20 +967,6 @@ public: */ static nsContentPolicyType InternalContentPolicyTypeToExternal(nsContentPolicyType aType); - /** - * Map internal content policy types to external ones or script types or preload types: - * * TYPE_INTERNAL_SCRIPT - * * TYPE_INTERNAL_WORKER - * * TYPE_INTERNAL_SHARED_WORKER - * * TYPE_INTERNAL_SERVICE_WORKER - * * TYPE_INTERNAL_SCRIPT_PRELOAD - * * TYPE_INTERNAL_IMAGE_PRELOAD - * * TYPE_INTERNAL_STYLESHEET_PRELOAD - * - * Note: DO NOT call this function unless you know what you're doing! - */ - static nsContentPolicyType InternalContentPolicyTypeToExternalOrMCBInternal(nsContentPolicyType aType); - /** * Map internal content policy types to external ones or preload types: * * TYPE_INTERNAL_SCRIPT_PRELOAD @@ -991,19 +977,6 @@ public: */ static nsContentPolicyType InternalContentPolicyTypeToExternalOrPreload(nsContentPolicyType aType); - /** - * Map internal content policy types to external ones, worker, or preload types: - * * TYPE_INTERNAL_WORKER - * * TYPE_INTERNAL_SHARED_WORKER - * * TYPE_INTERNAL_SERVICE_WORKER - * * TYPE_INTERNAL_SCRIPT_PRELOAD - * * TYPE_INTERNAL_IMAGE_PRELOAD - * * TYPE_INTERNAL_STYLESHEET_PRELOAD - * - * Note: DO NOT call this function unless you know what you're doing! - */ - static nsContentPolicyType InternalContentPolicyTypeToExternalOrCSPInternal(nsContentPolicyType aType); - /** * Map internal content policy types to external ones, worker, or preload types: * * TYPE_INTERNAL_WORKER @@ -2070,14 +2043,6 @@ public: return sPrivacyResistFingerprinting; } - /** - * Returns true if the doc tree branch which contains aDoc contains any - * plugins which we don't control event dispatch for, i.e. do any plugins - * in the same tab as this document receive key events outside of our - * control? This always returns false on MacOSX. - */ - static bool HasPluginWithUncontrolledEventDispatch(nsIDocument* aDoc); - /** * Return true if this doc is controlled by a ServiceWorker. */ @@ -2443,8 +2408,8 @@ public: * If the hostname for aURI is an IPv6 it encloses it in brackets, * otherwise it just outputs the hostname in aHost. */ - static void GetHostOrIPv6WithBrackets(nsIURI* aURI, nsAString& aHost); - static void GetHostOrIPv6WithBrackets(nsIURI* aURI, nsCString& aHost); + static nsresult GetHostOrIPv6WithBrackets(nsIURI* aURI, nsAString& aHost); + static nsresult GetHostOrIPv6WithBrackets(nsIURI* aURI, nsCString& aHost); /* * Call the given callback on all remote children of the given top-level diff --git a/dom/base/nsDOMAttributeMap.cpp b/dom/base/nsDOMAttributeMap.cpp index b953496824..948603c7ff 100644 --- a/dom/base/nsDOMAttributeMap.cpp +++ b/dom/base/nsDOMAttributeMap.cpp @@ -129,35 +129,8 @@ nsDOMAttributeMap::DropAttribute(int32_t aNamespaceID, nsIAtom* aLocalName) } } -already_AddRefed -nsDOMAttributeMap::RemoveAttribute(mozilla::dom::NodeInfo* aNodeInfo) -{ - NS_ASSERTION(aNodeInfo, "RemoveAttribute() called with aNodeInfo == nullptr!"); - - nsAttrKey attr(aNodeInfo->NamespaceID(), aNodeInfo->NameAtom()); - - RefPtr node; - if (!mAttributeCache.Get(attr, getter_AddRefs(node))) { - nsAutoString value; - // As we are removing the attribute we need to set the current value in - // the attribute node. - mContent->GetAttr(aNodeInfo->NamespaceID(), aNodeInfo->NameAtom(), value); - RefPtr ni = aNodeInfo; - node = new Attr(nullptr, ni.forget(), value, true); - } - else { - // Break link to map - node->SetMap(nullptr); - - // Remove from cache - mAttributeCache.Remove(attr); - } - - return node.forget(); -} - Attr* -nsDOMAttributeMap::GetAttribute(mozilla::dom::NodeInfo* aNodeInfo, bool aNsAware) +nsDOMAttributeMap::GetAttribute(mozilla::dom::NodeInfo* aNodeInfo) { NS_ASSERTION(aNodeInfo, "GetAttribute() called with aNodeInfo == nullptr!"); @@ -167,7 +140,7 @@ nsDOMAttributeMap::GetAttribute(mozilla::dom::NodeInfo* aNodeInfo, bool aNsAware if (!node) { RefPtr ni = aNodeInfo; RefPtr newAttr = - new Attr(this, ni.forget(), EmptyString(), aNsAware); + new Attr(this, ni.forget(), EmptyString()); mAttributeCache.Put(attr, newAttr); node = newAttr; } @@ -187,13 +160,51 @@ nsDOMAttributeMap::NamedGetter(const nsAString& aAttrName, bool& aFound) } aFound = true; - return GetAttribute(ni, false); + return GetAttribute(ni); } bool nsDOMAttributeMap::NameIsEnumerable(const nsAString& aName) { - return true; + return false; +} + +void +nsDOMAttributeMap::GetSupportedNames(unsigned aFlags, + nsTArray& aNames) +{ + if (!(aFlags & JSITER_HIDDEN)) { + return; + } + + // For HTML elements in HTML documents, only include names that are still the + // same after ASCII-lowercasing, since our named getter will end up + // ASCII-lowercasing the given string. + bool lowercaseNamesOnly = + mContent->IsHTMLElement() && mContent->IsInHTMLDocument(); + + const uint32_t count = mContent->GetAttrCount(); + bool seenNonAtomName = false; + for (uint32_t i = 0; i < count; i++) { + const nsAttrName* name = mContent->GetAttrNameAt(i); + seenNonAtomName = seenNonAtomName || !name->IsAtom(); + nsString qualifiedName; + name->GetQualifiedName(qualifiedName); + + if (lowercaseNamesOnly && + nsContentUtils::StringContainsASCIIUpper(qualifiedName)) { + continue; + } + + // Omit duplicates. We only need to do this check if we've seen a non-atom + // name, because that's the only way we can have two identical qualified + // names. + if (seenNonAtomName && aNames.Contains(qualifiedName)) { + continue; + } + + aNames.AppendElement(qualifiedName); + } } Attr* @@ -287,38 +298,22 @@ nsDOMAttributeMap::SetNamedItemNS(Attr& aAttr, ErrorResult& aError) } } - RefPtr attr; + RefPtr oldAttr; if (oldNi) { - RefPtr oldAttr = GetAttribute(oldNi, true); + oldAttr = GetAttribute(oldNi); if (oldAttr == &aAttr) { return oldAttr.forget(); } if (oldAttr) { - attr = RemoveNamedItem(oldNi, aError); - NS_ASSERTION(attr->NodeInfo()->NameAndNamespaceEquals(oldNi), - "RemoveNamedItem() called, attr->NodeInfo() should be equal to oldNi!"); - - // That might have run mutation event listeners, so re-verify - // our assumptions. - nsDOMAttributeMap* newOwner = aAttr.GetMap(); - if (newOwner) { - if (newOwner == this) { - // OK, we're just done here. - return attr.forget(); - } - - // The attr we're trying to set got stuck on some other - // element. Just throw, for lack of anything better to do. - aError.Throw(NS_ERROR_DOM_INUSE_ATTRIBUTE_ERR); - return nullptr; - } else if (mContent->OwnerDoc() != aAttr.OwnerDoc()) { - // Got moved into a different document, boo. - aError.Throw(NS_ERROR_DOM_HIERARCHY_REQUEST_ERR); - return nullptr; - } + // Just remove it from our hashtable. This has no side-effects, so we + // don't have to recheck anything after we do it. Then we'll add our new + // Attr to the hashtable and do the actual attr set on the element. This + // will make the whole thing look like a single attribute mutation (with + // the new attr node in place) as opposed to a removal and addition. + DropAttribute(oldNi->NamespaceID(), oldNi->NameAtom()); } } @@ -340,13 +335,13 @@ nsDOMAttributeMap::SetNamedItemNS(Attr& aAttr, ErrorResult& aError) DropAttribute(ni->NamespaceID(), ni->NameAtom()); } - return attr.forget(); + return oldAttr.forget(); } already_AddRefed nsDOMAttributeMap::RemoveNamedItem(NodeInfo* aNodeInfo, ErrorResult& aError) { - RefPtr attribute = GetAttribute(aNodeInfo, true); + RefPtr attribute = GetAttribute(aNodeInfo); // This removes the attribute node from the attribute map. aError = mContent->UnsetAttr(aNodeInfo->NamespaceID(), aNodeInfo->NameAtom(), true); return attribute.forget(); @@ -396,7 +391,7 @@ nsDOMAttributeMap::IndexedGetter(uint32_t aIndex, bool& aFound) RefPtr ni = mContent->NodeInfo()->NodeInfoManager()-> GetNodeInfo(name->LocalName(), name->GetPrefix(), name->NamespaceID(), nsIDOMNode::ATTRIBUTE_NODE); - return GetAttribute(ni, true); + return GetAttribute(ni); } Attr* @@ -447,7 +442,7 @@ nsDOMAttributeMap::GetNamedItemNS(const nsAString& aNamespaceURI, return nullptr; } - return GetAttribute(ni, true); + return GetAttribute(ni); } already_AddRefed diff --git a/dom/base/nsDOMAttributeMap.h b/dom/base/nsDOMAttributeMap.h index 3abacf8aee..d403f209fe 100644 --- a/dom/base/nsDOMAttributeMap.h +++ b/dom/base/nsDOMAttributeMap.h @@ -158,10 +158,8 @@ public: RemoveNamedItemNS(const nsAString& aNamespaceURI, const nsAString& aLocalName, ErrorResult& aError); - void GetSupportedNames(unsigned, nsTArray& aNames) - { - // No supported names we want to show up in iteration. - } + void + GetSupportedNames(unsigned aFlags, nsTArray& aNames); size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const; @@ -180,12 +178,7 @@ private: GetAttrNodeInfo(const nsAString& aNamespaceURI, const nsAString& aLocalName); - Attr* GetAttribute(mozilla::dom::NodeInfo* aNodeInfo, bool aNsAware); - - /** - * Remove an attribute, returns the removed node. - */ - already_AddRefed RemoveAttribute(mozilla::dom::NodeInfo* aNodeInfo); + Attr* GetAttribute(mozilla::dom::NodeInfo* aNodeInfo); }; // XXX khuey yes this is crazy. The bindings code needs to see this include, diff --git a/dom/base/nsDOMWindowUtils.cpp b/dom/base/nsDOMWindowUtils.cpp index 8f9a070b4c..b447ad2ca3 100644 --- a/dom/base/nsDOMWindowUtils.cpp +++ b/dom/base/nsDOMWindowUtils.cpp @@ -3959,9 +3959,11 @@ nsDOMWindowUtils::SetNextPaintSyncId(int32_t aSyncId) if (lm && lm->GetBackendType() == LayersBackend::LAYERS_CLIENT) { ClientLayerManager* clm = static_cast(lm.get()); clm->SetNextPaintSyncId(aSyncId); + return NS_OK; } } + NS_WARNING("Paint sync id could not be set on the ClientLayerManager"); return NS_OK; } diff --git a/dom/base/nsDocument.cpp b/dom/base/nsDocument.cpp index 0fe5204fe2..937de31b1a 100644 --- a/dom/base/nsDocument.cpp +++ b/dom/base/nsDocument.cpp @@ -2289,7 +2289,7 @@ nsDocument::ResetToURI(nsIURI *aURI, nsILoadGroup *aLoadGroup, // Refresh the principal on the compartment. nsPIDOMWindow* win = GetInnerWindow(); if (win) { - win->RefreshCompartmentPrincipal(); + nsGlobalWindow::Cast(win)->RefreshCompartmentPrincipal(); } } @@ -2580,12 +2580,12 @@ nsDocument::StartDocumentLoad(const char* aCommand, nsIChannel* aChannel, treeItem->GetSameTypeParent(getter_AddRefs(sameTypeParent)); if (sameTypeParent) { mUpgradeInsecureRequests = - sameTypeParent->GetDocument()->GetUpgradeInsecureRequests(); + sameTypeParent->GetDocument()->GetUpgradeInsecureRequests(false); // if the parent document makes use of upgrade-insecure-requests // then subdocument preloads should always be upgraded. mUpgradeInsecurePreloads = mUpgradeInsecureRequests || - sameTypeParent->GetDocument()->GetUpgradeInsecurePreloads(); + sameTypeParent->GetDocument()->GetUpgradeInsecureRequests(true); } } @@ -2691,6 +2691,9 @@ nsDocument::ApplySettingsFromCSP(bool aSpeculative) rv = csp->GetUpgradeInsecureRequests(&mUpgradeInsecureRequests); NS_ENSURE_SUCCESS_VOID(rv); } + if (!mUpgradeInsecurePreloads) { + mUpgradeInsecurePreloads = mUpgradeInsecureRequests; + } } return; } @@ -2815,19 +2818,8 @@ nsDocument::InitCSP(nsIChannel* aChannel) } } - csp = do_CreateInstance("@mozilla.org/cspcontext;1", &rv); - - if (NS_FAILED(rv)) { - MOZ_LOG(gCspPRLog, LogLevel::Debug, ("Failed to create CSP object: %x", rv)); - return rv; - } - - // used as a "self" identifier for the CSP. - nsCOMPtr selfURI; - aChannel->GetURI(getter_AddRefs(selfURI)); - - // Store the request context for violation reports - csp->SetRequestContext(this, nullptr); + rv = principal->EnsureCSP(this, getter_AddRefs(csp)); + NS_ENSURE_SUCCESS(rv, rv); // ----- if the doc is an app and we want a default CSP, apply it. if (applyAppDefaultCSP) { @@ -2877,14 +2869,7 @@ nsDocument::InitCSP(nsIChannel* aChannel) aChannel->Cancel(NS_ERROR_CSP_FRAME_ANCESTOR_VIOLATION); } } - - rv = principal->SetCsp(csp); - NS_ENSURE_SUCCESS(rv, rv); - MOZ_LOG(gCspPRLog, LogLevel::Debug, - ("Inserted CSP into principal %p", principal)); - ApplySettingsFromCSP(false); - return NS_OK; } @@ -3836,8 +3821,8 @@ nsIDocument::ShouldThrottleFrameRequests() return false; } - if (!mIsShowing) { - // We're not showing (probably in a background tab or the bf cache). + if (Hidden()) { + // We're not visible (probably in a background tab or the bf cache). return true; } @@ -5751,7 +5736,7 @@ nsIDocument::CreateAttribute(const nsAString& aName, ErrorResult& rv) } RefPtr attribute = new Attr(nullptr, nodeInfo.forget(), - EmptyString(), false); + EmptyString()); return attribute.forget(); } @@ -5784,7 +5769,7 @@ nsIDocument::CreateAttributeNS(const nsAString& aNamespaceURI, } RefPtr attribute = new Attr(nullptr, nodeInfo.forget(), - EmptyString(), true); + EmptyString()); return attribute.forget(); } @@ -7855,7 +7840,7 @@ nsDocument::GetViewportInfo(const ScreenIntSize& aDisplaySize) nsPresContext* context = mPresShell->GetPresContext(); float fullZoom = context ? context->GetFullZoom() : 1.0; fullZoom = (fullZoom == 0.0) ? 1.0 : fullZoom; - CSSToLayoutDeviceScale layoutDeviceScale = context->CSSToDevPixelScale(); + CSSToLayoutDeviceScale layoutDeviceScale = context ? context->CSSToDevPixelScale() : CSSToLayoutDeviceScale(1); CSSToScreenScale defaultScale = layoutDeviceScale * LayoutDeviceToScreenScale(1.0); @@ -8068,7 +8053,7 @@ nsDocument::GetViewportInfo(const ScreenIntSize& aDisplaySize) // We need to perform a conversion, but only if the initial or maximum // scale were set explicitly by the user. - if (mValidScaleFloat) { + if (mValidScaleFloat && scaleFloat >= scaleMinFloat && scaleFloat <= scaleMaxFloat) { CSSSize displaySize = ScreenSize(aDisplaySize) / scaleFloat; size.width = std::max(size.width, displaySize.width); size.height = std::max(size.height, displaySize.height); @@ -10847,6 +10832,24 @@ nsIDocument::ObsoleteSheet(const nsAString& aSheetURI, ErrorResult& rv) } } +already_AddRefed +nsIDocument::GetMozDocumentURIIfNotForErrorPages() +{ + if (mFailedChannel) { + nsCOMPtr failedURI; + if (NS_SUCCEEDED(mFailedChannel->GetURI(getter_AddRefs(failedURI)))) { + return failedURI.forget(); + } + } + + nsCOMPtr uri = GetDocumentURIObject(); + if (!uri) { + return nullptr; + } + + return uri.forget(); +} + nsIHTMLCollection* nsIDocument::Children() { diff --git a/dom/base/nsGlobalWindow.h b/dom/base/nsGlobalWindow.h index 1a6ea304a1..5d15f41d05 100644 --- a/dom/base/nsGlobalWindow.h +++ b/dom/base/nsGlobalWindow.h @@ -461,7 +461,7 @@ public: bool DispatchResizeEvent(const mozilla::CSSIntSize& aSize); // Inner windows only. - virtual void RefreshCompartmentPrincipal() override; + void RefreshCompartmentPrincipal(); // Outer windows only. virtual nsresult SetFullScreenInternal(bool aIsFullscreen, bool aFullscreenMode, diff --git a/dom/base/nsIAttribute.h b/dom/base/nsIAttribute.h index ddbd897da3..ee18d54f54 100644 --- a/dom/base/nsIAttribute.h +++ b/dom/base/nsIAttribute.h @@ -41,13 +41,11 @@ public: protected: #ifdef MOZILLA_INTERNAL_API nsIAttribute(nsDOMAttributeMap *aAttrMap, - already_AddRefed& aNodeInfo, - bool aNsAware); + already_AddRefed& aNodeInfo); #endif //MOZILLA_INTERNAL_API virtual ~nsIAttribute(); RefPtr mAttrMap; - bool mNsAware; }; NS_DEFINE_STATIC_IID_ACCESSOR(nsIAttribute, NS_IATTRIBUTE_IID) diff --git a/dom/base/nsIDocument.h b/dom/base/nsIDocument.h index de6ef5b5fc..d2c5078b8d 100644 --- a/dom/base/nsIDocument.h +++ b/dom/base/nsIDocument.h @@ -331,19 +331,14 @@ public: * of the document's ancestors up to the toplevel document makes use * of the CSP directive 'upgrade-insecure-requests'. */ - bool GetUpgradeInsecureRequests() const + bool GetUpgradeInsecureRequests(bool aPreload) const { + if (aPreload) { + return mUpgradeInsecurePreloads; + } return mUpgradeInsecureRequests; } - /** - * Same as GetUpgradeInsecureRequests() but *only* for preloads. - */ - bool GetUpgradeInsecurePreloads() const - { - return mUpgradeInsecurePreloads; - } - /** * Set the principal responsible for this document. */ @@ -2628,6 +2623,8 @@ public: void ObsoleteSheet(const nsAString& aSheetURI, mozilla::ErrorResult& rv); + already_AddRefed GetMozDocumentURIIfNotForErrorPages(); + // ParentNode nsIHTMLCollection* Children(); uint32_t ChildElementCount(); diff --git a/dom/base/nsPIDOMWindow.h b/dom/base/nsPIDOMWindow.h index 383ea4e2f6..75a068fe18 100644 --- a/dom/base/nsPIDOMWindow.h +++ b/dom/base/nsPIDOMWindow.h @@ -704,14 +704,6 @@ public: */ virtual bool DispatchCustomEvent(const nsAString& aEventName) = 0; - /** - * Call when the document principal may have changed and the compartment - * principal needs to be updated. - * - * Inner windows only. - */ - virtual void RefreshCompartmentPrincipal() = 0; - /** * Like nsIDOMWindow::Open, except that we don't navigate to the given URL. * diff --git a/dom/html/HTMLFormElement.cpp b/dom/html/HTMLFormElement.cpp index 3c68c79fae..aa0ba35bad 100644 --- a/dom/html/HTMLFormElement.cpp +++ b/dom/html/HTMLFormElement.cpp @@ -1744,7 +1744,7 @@ HTMLFormElement::GetActionURL(nsIURI** aActionURL, bool isHttpScheme = false; rv = actionURL->SchemeIs("http", &isHttpScheme); NS_ENSURE_SUCCESS(rv, rv); - if (isHttpScheme && document->GetUpgradeInsecureRequests()) { + if (isHttpScheme && document->GetUpgradeInsecureRequests(false)) { // let's use the old specification before the upgrade for logging nsAutoCString spec; rv = actionURL->GetSpec(spec); diff --git a/dom/html/HTMLMetaElement.cpp b/dom/html/HTMLMetaElement.cpp index a362f14172..274eadaa28 100644 --- a/dom/html/HTMLMetaElement.cpp +++ b/dom/html/HTMLMetaElement.cpp @@ -129,26 +129,13 @@ HTMLMetaElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent, nsIPrincipal* principal = aDocument->NodePrincipal(); nsCOMPtr csp; - rv = principal->GetCsp(getter_AddRefs(csp)); + nsCOMPtr domDoc = do_QueryInterface(aDocument); + rv = principal->EnsureCSP(domDoc, getter_AddRefs(csp)); NS_ENSURE_SUCCESS(rv, rv); // Multiple CSPs (delivered through either header of meta tag) need to be // joined together, see: // https://w3c.github.io/webappsec/specs/content-security-policy/#delivery-html-meta-element - if (!csp) { - csp = do_CreateInstance("@mozilla.org/cspcontext;1", &rv); - NS_ENSURE_SUCCESS(rv, rv); - - // Store the request context so CSP can resolve 'self' - nsCOMPtr domDoc = do_QueryInterface(aDocument); - rv = csp->SetRequestContext(domDoc, nullptr); - NS_ENSURE_SUCCESS(rv, rv); - - // set the new CSP - rv = principal->SetCsp(csp); - NS_ENSURE_SUCCESS(rv, rv); - } - rv = csp->AppendPolicy(content, false, // csp via meta tag can not be report only true); // delivered through the meta tag diff --git a/dom/html/nsHTMLDocument.cpp b/dom/html/nsHTMLDocument.cpp index adb998b55e..7b8756001d 100644 --- a/dom/html/nsHTMLDocument.cpp +++ b/dom/html/nsHTMLDocument.cpp @@ -891,8 +891,8 @@ nsHTMLDocument::GetDomain(nsAString& aDomain) } nsAutoCString hostName; - - if (NS_SUCCEEDED(uri->GetHost(hostName))) { + nsresult rv = nsContentUtils::GetHostOrIPv6WithBrackets(uri, hostName); + if (NS_SUCCEEDED(rv)) { CopyUTF8toUTF16(hostName, aDomain); } else { // If we can't get the host from the URI (e.g. about:, javascript:, @@ -3250,6 +3250,12 @@ nsHTMLDocument::ExecCommand(const nsAString& commandID, } if (!nsContentUtils::IsCutCopyAllowed()) { + // We have rejected the event due to it not being performed in an + // input-driven context therefore, we report the error to the console. + nsContentUtils::ReportToConsole(nsIScriptError::warningFlag, + NS_LITERAL_CSTRING("DOM"), this, + nsContentUtils::eDOM_PROPERTIES, + "ExecCommandCutCopyDeniedNotInputDriven"); return false; } diff --git a/dom/html/test/forms/test_pattern_attribute.html b/dom/html/test/forms/test_pattern_attribute.html index 9253176420..31916b73c3 100644 --- a/dom/html/test/forms/test_pattern_attribute.html +++ b/dom/html/test/forms/test_pattern_attribute.html @@ -121,6 +121,12 @@ function checkInvalidPattern(element, completeCheck) } } +function checkSyntaxError(element) +{ + ok(!element.validity.patternMismatch, + "On SyntaxError, element should not suffer"); +} + function checkPatternValidity(element) { element.pattern = "foo"; @@ -165,17 +171,6 @@ function checkPatternValidity(element) element.value = "foo"; checkInvalidPattern(element); - // We need '\\\\' because '\\' will produce '\\' and we want to escape the '\' - // for the regexp. - element.pattern = "foo\\\\bar"; - element.value = "foo\\bar"; - checkValidPattern(element); - - // The same way, we want to escape the ' in the pattern. - element.pattern = "foo\\'bar"; - element.value = "foo'bar"; - checkValidPattern(element); - // Check for 'i' flag disabled. Should be case sensitive. element.value = "Foo"; checkInvalidPattern(element); @@ -183,6 +178,20 @@ function checkPatternValidity(element) // We can't check for the 'g' flag because we only test, we don't execute. // We can't check for the 'm' flag because .value shouldn't contain line breaks. + // We need '\\\\' because '\\' will produce '\\' and we want to escape the '\' + // for the regexp. + element.pattern = "foo\\\\bar"; + element.value = "foo\\bar"; + checkValidPattern(element); + + // We may want to escape the ' in the pattern, but this is a SyntaxError + // when unicode flag is set. + element.pattern = "foo\\'bar"; + element.value = "foo'bar"; + checkSyntaxError(element); + element.value = "baz"; + checkSyntaxError(element); + // We should check the pattern attribute do not pollute |RegExp.lastParen|. is(RegExp.lastParen, "", "RegExp.lastParen should be the empty string"); @@ -254,6 +263,33 @@ function checkPatternValidity(element) element.removeAttribute('pattern'); checkValidPattern(element, true); + + // Unicode pattern + for (var pattern of ["\\u{1F438}{2}", "\u{1F438}{2}", + "\\uD83D\\uDC38{2}", "\uD83D\uDC38{2}", + "\u{D83D}\u{DC38}{2}"]) { + element.pattern = pattern; + + element.value = "\u{1F438}\u{1F438}"; + checkValidPattern(element); + + element.value = "\uD83D\uDC38\uD83D\uDC38"; + checkValidPattern(element); + + element.value = "\uD83D\uDC38\uDC38"; + checkInvalidPattern(element); + } + + element.pattern = "\\u{D83D}\\u{DC38}{2}"; + + element.value = "\u{1F438}\u{1F438}"; + checkInvalidPattern(element); + + element.value = "\uD83D\uDC38\uD83D\uDC38"; + checkInvalidPattern(element); + + element.value = "\uD83D\uDC38\uDC38"; + checkInvalidPattern(element); } var input = document.getElementById('i'); diff --git a/dom/locales/en-US/chrome/dom/dom.properties b/dom/locales/en-US/chrome/dom/dom.properties index 9ea23b848e..4deda97a67 100644 --- a/dom/locales/en-US/chrome/dom/dom.properties +++ b/dom/locales/en-US/chrome/dom/dom.properties @@ -190,6 +190,8 @@ InterceptionCanceledWithURL=Failed to load '%S'. A ServiceWorker canceled the lo InterceptionRejectedResponseWithURL=Failed to load '%1$S'. A ServiceWorker passed a promise to FetchEvent.respondWith() that rejected with '%2$S'. # LOCALIZATION NOTE: Do not translate "ServiceWorker", "promise", "FetchEvent.respondWith()", or "Response". %1$S is a URL. %2$S is an error string. InterceptedNonResponseWithURL=Failed to load '%1$S'. A ServiceWorker passed a promise to FetchEvent.respondWith() that resolved with non-Response value '%2$S'. +ExecCommandCutCopyDeniedNotInputDriven=document.execCommand('cut'/'copy') was denied because it was not called from inside a short running user-generated event handler. +PatternAttributeCompileFailure=Unable to check because the pattern is not a valid regexp: %S # LOCALIZATION NOTE: Do not translate 'youtube'. %S values are origins, like https://domain.com:port RewriteYoutubeEmbed=Rewriting old-style Youtube Flash embed (%S) to iframe embed (%S). Please update page to use iframe instead of embed/object, if possible. # LOCALIZATION NOTE: Do not translate 'youtube'. %S values are origins, like https://domain.com:port diff --git a/dom/network/tests/unit_stats/test_networkstats_service_proxy.js b/dom/network/tests/unit_stats/test_networkstats_service_proxy.js index c4a18557cc..b78c53f173 100644 --- a/dom/network/tests/unit_stats/test_networkstats_service_proxy.js +++ b/dom/network/tests/unit_stats/test_networkstats_service_proxy.js @@ -61,16 +61,14 @@ add_test(function test_saveAppStats() { do_check_eq(cachedStats[key1].serviceType.length, 0); do_check_eq(cachedStats[key1].networkId, wifi.id); do_check_eq(cachedStats[key1].networkType, wifi.type); - do_check_eq(new Date(cachedStats[key1].date).getTime() / 1000, - Math.floor(timestamp / 1000)); + do_check_eq(cachedStats[key1].date.getTime(), timestamp); do_check_eq(cachedStats[key1].rxBytes, 10); do_check_eq(cachedStats[key1].txBytes, 20); do_check_eq(cachedStats[key2].appId, 1); do_check_eq(cachedStats[key1].serviceType.length, 0); do_check_eq(cachedStats[key2].networkId, mobile.id); do_check_eq(cachedStats[key2].networkType, mobile.type); - do_check_eq(new Date(cachedStats[key2].date).getTime() / 1000, - Math.floor(timestamp / 1000)); + do_check_eq(cachedStats[key2].date.getTime(), timestamp); do_check_eq(cachedStats[key2].rxBytes, 10); do_check_eq(cachedStats[key2].txBytes, 20); @@ -113,16 +111,14 @@ add_test(function test_saveServiceStats() { do_check_eq(cachedStats[key1].serviceType, serviceType); do_check_eq(cachedStats[key1].networkId, wifi.id); do_check_eq(cachedStats[key1].networkType, wifi.type); - do_check_eq(new Date(cachedStats[key1].date).getTime() / 1000, - Math.floor(timestamp / 1000)); + do_check_eq(cachedStats[key1].date.getTime(), timestamp); do_check_eq(cachedStats[key1].rxBytes, 10); do_check_eq(cachedStats[key1].txBytes, 20); do_check_eq(cachedStats[key2].appId, 0); do_check_eq(cachedStats[key1].serviceType, serviceType); do_check_eq(cachedStats[key2].networkId, mobile.id); do_check_eq(cachedStats[key2].networkType, mobile.type); - do_check_eq(new Date(cachedStats[key2].date).getTime() / 1000, - Math.floor(timestamp / 1000)); + do_check_eq(cachedStats[key2].date.getTime(), timestamp); do_check_eq(cachedStats[key2].rxBytes, 10); do_check_eq(cachedStats[key2].txBytes, 20); @@ -157,8 +153,7 @@ add_test(function test_saveStatsWithDifferentDates() { do_check_eq(cachedStats[key].isInBrowser, false); do_check_eq(cachedStats[key].networkId, mobile.id); do_check_eq(cachedStats[key].networkType, mobile.type); - do_check_eq(new Date(cachedStats[key].date).getTime() / 1000, - Math.floor(tomorrow.getTime() / 1000)); + do_check_eq(cachedStats[key].date.getTime(), tomorrow.getTime()); do_check_eq(cachedStats[key].rxBytes, 30); do_check_eq(cachedStats[key].txBytes, 40); diff --git a/dom/security/nsCSPContext.cpp b/dom/security/nsCSPContext.cpp index 57ce983c11..a38b782875 100644 --- a/dom/security/nsCSPContext.cpp +++ b/dom/security/nsCSPContext.cpp @@ -424,7 +424,9 @@ nsCSPContext::reportInlineViolation(nsContentPolicyType aContentType, // use selfURI as the sourceFile nsAutoCString sourceFile; - mSelfURI->GetSpec(sourceFile); + if (mSelfURI) { + mSelfURI->GetSpec(sourceFile); + } nsAutoString codeSample(aContent); // cap the length of the script sample at 40 chars diff --git a/dom/security/nsCSPService.cpp b/dom/security/nsCSPService.cpp index 7a2864758d..d92109f853 100644 --- a/dom/security/nsCSPService.cpp +++ b/dom/security/nsCSPService.cpp @@ -102,10 +102,6 @@ CSPService::ShouldLoad(uint32_t aContentType, nsIPrincipal *aRequestPrincipal, int16_t *aDecision) { - MOZ_ASSERT(aContentType == - nsContentUtils::InternalContentPolicyTypeToExternalOrCSPInternal(aContentType), - "We should only see external content policy types or CSP special types (preloads or workers) here."); - if (!aContentLocation) { return NS_ERROR_FAILURE; } @@ -250,10 +246,6 @@ CSPService::ShouldProcess(uint32_t aContentType, nsIPrincipal *aRequestPrincipal, int16_t *aDecision) { - MOZ_ASSERT(aContentType == - nsContentUtils::InternalContentPolicyTypeToExternalOrCSPInternal(aContentType), - "We should only see external content policy types or preloads here."); - if (!aContentLocation) return NS_ERROR_FAILURE; diff --git a/dom/security/nsMixedContentBlocker.cpp b/dom/security/nsMixedContentBlocker.cpp index 3a5571b24e..2dda70a7cc 100644 --- a/dom/security/nsMixedContentBlocker.cpp +++ b/dom/security/nsMixedContentBlocker.cpp @@ -310,7 +310,7 @@ nsMixedContentBlocker::AsyncOnChannelRedirect(nsIChannel* aOldChannel, } int16_t decision = REJECT_REQUEST; - rv = ShouldLoad(nsContentUtils::InternalContentPolicyTypeToExternalOrMCBInternal(contentPolicyType), + rv = ShouldLoad(contentPolicyType, newUri, requestingLocation, loadInfo->LoadingNode(), @@ -323,7 +323,6 @@ nsMixedContentBlocker::AsyncOnChannelRedirect(nsIChannel* aOldChannel, // If the channel is about to load mixed content, abort the channel if (!NS_CP_ACCEPTED(decision)) { autoCallback.DontCallback(); - aOldChannel->Cancel(NS_ERROR_DOM_BAD_URI); return NS_BINDING_FAILED; } @@ -379,9 +378,6 @@ nsMixedContentBlocker::ShouldLoad(bool aHadInsecureImageRedirect, // to them. MOZ_ASSERT(NS_IsMainThread()); - MOZ_ASSERT(aContentType == nsContentUtils::InternalContentPolicyTypeToExternalOrMCBInternal(aContentType), - "We should only see external content policy types here."); - bool isPreload = nsContentUtils::IsPreloadType(aContentType); // The content policy type that we receive may be an internal type for @@ -671,7 +667,7 @@ nsMixedContentBlocker::ShouldLoad(bool aHadInsecureImageRedirect, bool isHttpScheme = false; rv = aContentLocation->SchemeIs("http", &isHttpScheme); NS_ENSURE_SUCCESS(rv, rv); - if (isHttpScheme && docShell->GetDocument()->GetUpgradeInsecureRequests()) { + if (isHttpScheme && docShell->GetDocument()->GetUpgradeInsecureRequests(isPreload)) { *aDecision = ACCEPT; return NS_OK; } @@ -898,8 +894,7 @@ nsMixedContentBlocker::ShouldProcess(uint32_t aContentType, nsIPrincipal* aRequestPrincipal, int16_t* aDecision) { - MOZ_ASSERT(aContentType == nsContentUtils::InternalContentPolicyTypeToExternal(aContentType), - "We should only see external content policy types here."); + aContentType = nsContentUtils::InternalContentPolicyTypeToExternal(aContentType); if (!aContentLocation) { // aContentLocation may be null when a plugin is loading without an associated URI resource diff --git a/dom/tests/mochitest/localstorage/frameLocalStorageSessionOnly.html b/dom/tests/mochitest/localstorage/frameLocalStorageSessionOnly.html new file mode 100644 index 0000000000..f6c7f0291f --- /dev/null +++ b/dom/tests/mochitest/localstorage/frameLocalStorageSessionOnly.html @@ -0,0 +1,8 @@ + + + + + + diff --git a/dom/tests/mochitest/localstorage/mochitest.ini b/dom/tests/mochitest/localstorage/mochitest.ini index 14b678e292..a44be4be01 100644 --- a/dom/tests/mochitest/localstorage/mochitest.ini +++ b/dom/tests/mochitest/localstorage/mochitest.ini @@ -16,6 +16,7 @@ support-files = interOriginTest.js interOriginTest2.js localStorageCommon.js + frameLocalStorageSessionOnly.html [test_appIsolation.html] skip-if = buildapp == 'b2g' || toolkit == 'android' || e10s #bug 793211 # b2g(needs https to work) b2g-debug(needs https to work) b2g-desktop(needs https to work) @@ -56,3 +57,4 @@ skip-if = buildapp == 'b2g' || toolkit == 'android' #TIMED_OUT # b2g(needs https skip-if = (buildapp == 'b2g' && (toolkit != 'gonk' || debug)) || toolkit == 'android' [test_lowDeviceStorage.html] [test_storageConstructor.html] +[test_localStorageSessionPrefOverride.html] diff --git a/dom/tests/mochitest/localstorage/test_localStorageSessionPrefOverride.html b/dom/tests/mochitest/localstorage/test_localStorageSessionPrefOverride.html new file mode 100644 index 0000000000..9fe6a48ec6 --- /dev/null +++ b/dom/tests/mochitest/localstorage/test_localStorageSessionPrefOverride.html @@ -0,0 +1,54 @@ + + + Local Storage Session Pref Override + + + + + + + + diff --git a/dom/webidl/Document.webidl b/dom/webidl/Document.webidl index 43a4f7fc26..444dd93994 100644 --- a/dom/webidl/Document.webidl +++ b/dom/webidl/Document.webidl @@ -254,17 +254,12 @@ partial interface Document { Element createElementNS(DOMString? namespace, DOMString qualifiedName, DOMString typeExtension); }; -// https://w3c.github.io/page-visibility/#extensions-to-the-document-interface +// http://dvcs.w3.org/hg/webperf/raw-file/tip/specs/PageVisibility/Overview.html#sec-document-interface partial interface Document { - [Pref="dom.visibilityAPI.enabled"] readonly attribute boolean hidden; - [Pref="dom.visibilityAPI.enabled"] readonly attribute boolean mozHidden; - [Pref="dom.visibilityAPI.enabled"] readonly attribute VisibilityState visibilityState; - [Pref="dom.visibilityAPI.enabled"] readonly attribute VisibilityState mozVisibilityState; - [Pref="dom.visibilityAPI.enabled"] attribute EventHandler onvisibilitychange; }; @@ -372,6 +367,10 @@ partial interface Document { [ChromeOnly] readonly attribute DOMString contentLanguage; [ChromeOnly] readonly attribute nsILoadGroup? documentLoadGroup; + + // like documentURI, except that for error pages, it returns the URI we were + // trying to load when we hit an error, rather than the error page's own URI. + [ChromeOnly] readonly attribute URI? mozDocumentURIIfNotForErrorPages; }; // Extension to give chrome JS the ability to determine when a document was diff --git a/dom/webidl/Storage.webidl b/dom/webidl/Storage.webidl index 406c8b83bb..949c5e607f 100644 --- a/dom/webidl/Storage.webidl +++ b/dom/webidl/Storage.webidl @@ -29,4 +29,7 @@ interface Storage { [Throws] void clear(); + + [ChromeOnly] + readonly attribute boolean isSessionOnly; }; diff --git a/gfx/layers/LayerTreeInvalidation.cpp b/gfx/layers/LayerTreeInvalidation.cpp index f5c0693904..4017a2ff9f 100644 --- a/gfx/layers/LayerTreeInvalidation.cpp +++ b/gfx/layers/LayerTreeInvalidation.cpp @@ -231,13 +231,13 @@ struct LayerPropertiesBase : public LayerProperties return result; } - IntRect NewTransformedBounds() + virtual IntRect NewTransformedBounds() { return TransformRect(mLayer->GetVisibleRegion().ToUnknownRegion().GetBounds(), GetTransformForInvalidation(mLayer)); } - IntRect OldTransformedBounds() + virtual IntRect OldTransformedBounds() { return TransformRect(mVisibleRegion.ToUnknownRegion().GetBounds(), mTransform); } @@ -273,8 +273,8 @@ struct ContainerLayerProperties : public LayerPropertiesBase } } - virtual nsIntRegion ComputeChangeInternal(NotifySubDocInvalidationFunc aCallback, - bool& aGeometryChanged) + nsIntRegion ComputeChangeInternal(NotifySubDocInvalidationFunc aCallback, + bool& aGeometryChanged) override { ContainerLayer* container = mLayer->AsContainerLayer(); nsIntRegion invalidOfLayer; // Invalid regions of this layer. @@ -382,6 +382,31 @@ struct ContainerLayerProperties : public LayerPropertiesBase return result; } + IntRect NewTransformedBounds() override + { + if (mLayer->Extend3DContext()) { + IntRect result; + for (UniquePtr& child : mChildren) { + result = result.Union(child->NewTransformedBounds()); + } + return result; + } + + return LayerPropertiesBase::NewTransformedBounds(); + } + + IntRect OldTransformedBounds() override + { + if (mLayer->Extend3DContext()) { + IntRect result; + for (UniquePtr& child : mChildren) { + result = result.Union(child->OldTransformedBounds()); + } + return result; + } + return LayerPropertiesBase::OldTransformedBounds(); + } + // The old list of children: AutoTArray,1> mChildren; float mPreXScale; diff --git a/ipc/glue/BackgroundUtils.cpp b/ipc/glue/BackgroundUtils.cpp index 054935792a..07149753a4 100644 --- a/ipc/glue/BackgroundUtils.cpp +++ b/ipc/glue/BackgroundUtils.cpp @@ -244,7 +244,6 @@ LoadInfoToLoadInfoArgs(nsILoadInfo *aLoadInfo, aLoadInfo->InternalContentPolicyType(), static_cast(aLoadInfo->GetTainting()), aLoadInfo->GetUpgradeInsecureRequests(), - aLoadInfo->GetUpgradeInsecurePreloads(), aLoadInfo->GetInnerWindowID(), aLoadInfo->GetOuterWindowID(), aLoadInfo->GetParentOuterWindowID(), @@ -304,7 +303,6 @@ LoadInfoArgsToLoadInfo(const OptionalLoadInfoArgs& aOptionalLoadInfoArgs, loadInfoArgs.contentPolicyType(), static_cast(loadInfoArgs.tainting()), loadInfoArgs.upgradeInsecureRequests(), - loadInfoArgs.upgradeInsecurePreloads(), loadInfoArgs.innerWindowID(), loadInfoArgs.outerWindowID(), loadInfoArgs.parentOuterWindowID(), diff --git a/js/src/frontend/ParseNode.cpp b/js/src/frontend/ParseNode.cpp index 6bab0be2eb..30b35bd7eb 100644 --- a/js/src/frontend/ParseNode.cpp +++ b/js/src/frontend/ParseNode.cpp @@ -1162,6 +1162,12 @@ ObjectBox::asFunctionBox() return static_cast(this); } +bool +ObjectBox::isModuleBox() +{ + return object->is(); +} + ModuleBox* ObjectBox::asModuleBox() { diff --git a/js/src/frontend/ParseNode.h b/js/src/frontend/ParseNode.h index c744e965ee..9abeb039da 100644 --- a/js/src/frontend/ParseNode.h +++ b/js/src/frontend/ParseNode.h @@ -1719,7 +1719,7 @@ class ObjectBox ObjectBox(JSObject* object, ObjectBox* traceLink); bool isFunctionBox() { return object->is(); } FunctionBox* asFunctionBox(); - bool isModuleBox() { return object->is(); } + bool isModuleBox(); ModuleBox* asModuleBox(); virtual void trace(JSTracer* trc); diff --git a/js/src/gc/Statistics.cpp b/js/src/gc/Statistics.cpp index 776683ea4d..414c542293 100644 --- a/js/src/gc/Statistics.cpp +++ b/js/src/gc/Statistics.cpp @@ -31,9 +31,6 @@ using mozilla::MakeRange; using mozilla::PodArrayZero; using mozilla::PodZero; -/* Except for the first and last, slices of less than 10ms are not reported. */ -static const int64_t SLICE_MIN_REPORT_TIME = 10 * PRMJ_USEC_PER_MSEC; - const char* js::gcstats::ExplainInvocationKind(JSGCInvocationKind gckind) { diff --git a/js/src/jsdate.cpp b/js/src/jsdate.cpp index 97e698e5f6..50374a7c85 100644 --- a/js/src/jsdate.cpp +++ b/js/src/jsdate.cpp @@ -700,6 +700,26 @@ ParseDigitsN(size_t n, size_t* result, const CharT* s, size_t* i, size_t limit) return false; } +/* + * Read and convert n or less decimal digits from s[*i] + * to s[min(*i+n,limit)] into *result. + * + * Succeed only if greater than zero but less than or equal to n digits are + * converted. Advance *i only on success. + */ +template +static bool +ParseDigitsNOrLess(size_t n, size_t* result, const CharT* s, size_t* i, size_t limit) +{ + size_t init = *i; + + if (ParseDigits(result, s, i, Min(limit, init + n))) + return ((*i - init) > 0) && ((*i - init) <= n); + + *i = init; + return false; +} + static int DaysInMonth(int year, int month) { @@ -713,11 +733,6 @@ DaysInMonth(int year, int month) * "NOTE-datetime" specification. These formats make up a restricted * profile of the ISO 8601 format. Quoted here: * - * The formats are as follows. Exactly the components shown here - * must be present, with exactly this punctuation. Note that the "T" - * appears literally in the string, to indicate the beginning of the - * time element, as specified in ISO 8601. - * * Any combination of the date formats with the time formats is * allowed, and also either the date or the time can be missing. * @@ -730,6 +745,12 @@ DaysInMonth(int year, int month) * 00:00 UTC. If the time is present but the time zone field is * missing then we use local time. * + * For the sake of cross compatibility with other implementations we + * make a few exceptions to the standard: months, days, hours, minutes + * and seconds may be either one or two digits long, and the 'T' from + * the time part may be replaced with a space. Given that, a date time + * like "1999-1-1 1:1:1" will parse successfully. + * * Date part: * * Year: @@ -755,17 +776,17 @@ DaysInMonth(int year, int month) * where: * * YYYY = four-digit year or six digit year as +YYYYYY or -YYYYYY - * MM = two-digit month (01=January, etc.) - * DD = two-digit day of month (01 through 31) - * hh = two digits of hour (00 through 23) (am/pm NOT allowed) - * mm = two digits of minute (00 through 59) - * ss = two digits of second (00 through 59) + * MM = one or two-digit month (01=January, etc.) + * DD = one or two-digit day of month (01 through 31) + * hh = one or two digits of hour (00 through 23) (am/pm NOT allowed) + * mm = one or two digits of minute (00 through 59) + * ss = one or two digits of second (00 through 59) * s = one or more digits representing a decimal fraction of a second * TZD = time zone designator (Z or +hh:mm or -hh:mm or missing for local) */ template static bool -ParseISODate(const CharT* s, size_t length, ClippedTime* result) +ParseISOStyleDate(const CharT* s, size_t length, ClippedTime* result) { size_t i = 0; int tzMul = 1; @@ -795,6 +816,9 @@ ParseISODate(const CharT* s, size_t length, ClippedTime* result) #define NEED_NDIGITS(n, field) \ if (!ParseDigitsN(n, &field, s, &i, length)) { return false; } +#define NEED_NDIGITS_OR_LESS(n, field) \ + if (!ParseDigitsNOrLess(n, &field, s, &i, length)) { return false; } + if (PEEK('+') || PEEK('-')) { if (PEEK('-')) dateMul = -1; @@ -804,19 +828,23 @@ ParseISODate(const CharT* s, size_t length, ClippedTime* result) NEED_NDIGITS(4, year); } DONE_DATE_UNLESS('-'); - NEED_NDIGITS(2, month); + NEED_NDIGITS_OR_LESS(2, month); DONE_DATE_UNLESS('-'); - NEED_NDIGITS(2, day); + NEED_NDIGITS_OR_LESS(2, day); done_date: - DONE_UNLESS('T'); - NEED_NDIGITS(2, hour); + if (PEEK('T') || PEEK(' ')) + i++; + else + goto done; + + NEED_NDIGITS_OR_LESS(2, hour); NEED(':'); - NEED_NDIGITS(2, min); + NEED_NDIGITS_OR_LESS(2, min); if (PEEK(':')) { ++i; - NEED_NDIGITS(2, sec); + NEED_NDIGITS_OR_LESS(2, sec); if (PEEK('.')) { ++i; if (!ParseFractional(&frac, s, &i, length)) @@ -882,7 +910,7 @@ template static bool ParseDate(const CharT* s, size_t length, ClippedTime* result) { - if (ParseISODate(s, length, result)) + if (ParseISOStyleDate(s, length, result)) return true; if (length == 0) @@ -1338,14 +1366,7 @@ DateObject::fillLocalTimeSlots() int weekday = WeekDay(localTime); setReservedSlot(LOCAL_DAY_SLOT, Int32Value(weekday)); - int seconds = yearSeconds % 60; - setReservedSlot(LOCAL_SECONDS_SLOT, Int32Value(seconds)); - - int minutes = (yearSeconds / 60) % 60; - setReservedSlot(LOCAL_MINUTES_SLOT, Int32Value(minutes)); - - int hours = (yearSeconds / (60 * 60)) % 24; - setReservedSlot(LOCAL_HOURS_SLOT, Int32Value(hours)); + setReservedSlot(LOCAL_SECONDS_INTO_YEAR_SLOT, Int32Value(yearSeconds)); } inline double @@ -1546,7 +1567,15 @@ DateObject::getHours_impl(JSContext* cx, const CallArgs& args) DateObject* dateObj = &args.thisv().toObject().as(); dateObj->fillLocalTimeSlots(); - args.rval().set(dateObj->getReservedSlot(LOCAL_HOURS_SLOT)); + // Note: LOCAL_SECONDS_INTO_YEAR_SLOT is guaranteed to contain an + // int32 or NaN after the call to fillLocalTimeSlots. + Value yearSeconds = dateObj->getReservedSlot(LOCAL_SECONDS_INTO_YEAR_SLOT); + if (yearSeconds.isDouble()) { + MOZ_ASSERT(IsNaN(yearSeconds.toDouble())); + args.rval().set(yearSeconds); + } else { + args.rval().setInt32((yearSeconds.toInt32() / int(SecondsPerHour)) % int(HoursPerDay)); + } return true; } @@ -1581,7 +1610,15 @@ DateObject::getMinutes_impl(JSContext* cx, const CallArgs& args) DateObject* dateObj = &args.thisv().toObject().as(); dateObj->fillLocalTimeSlots(); - args.rval().set(dateObj->getReservedSlot(LOCAL_MINUTES_SLOT)); + // Note: LOCAL_SECONDS_INTO_YEAR_SLOT is guaranteed to contain an + // int32 or NaN after the call to fillLocalTimeSlots. + Value yearSeconds = dateObj->getReservedSlot(LOCAL_SECONDS_INTO_YEAR_SLOT); + if (yearSeconds.isDouble()) { + MOZ_ASSERT(IsNaN(yearSeconds.toDouble())); + args.rval().set(yearSeconds); + } else { + args.rval().setInt32((yearSeconds.toInt32() / int(SecondsPerMinute)) % int(MinutesPerHour)); + } return true; } @@ -1610,7 +1647,17 @@ date_getUTCMinutes(JSContext* cx, unsigned argc, Value* vp) return CallNonGenericMethod(cx, args); } -/* Date.getSeconds is mapped to getUTCSeconds */ +/* + * Date.getSeconds is mapped to getUTCSeconds. As long as no supported time + * zone has a fractional-minute component, the differences in their + * specifications aren't observable. + * + * We'll have to split the implementations if a new time zone with a + * fractional-minute component is introduced or once we implement ES6's + * 20.3.1.7 Local Time Zone Adjustment: time zones with adjustments like that + * did historically exist, e.g. + * https://en.wikipedia.org/wiki/UTC%E2%88%9200:25:21 + */ /* static */ MOZ_ALWAYS_INLINE bool DateObject::getUTCSeconds_impl(JSContext* cx, const CallArgs& args) @@ -1618,7 +1665,15 @@ DateObject::getUTCSeconds_impl(JSContext* cx, const CallArgs& args) DateObject* dateObj = &args.thisv().toObject().as(); dateObj->fillLocalTimeSlots(); - args.rval().set(dateObj->getReservedSlot(LOCAL_SECONDS_SLOT)); + // Note: LOCAL_SECONDS_INTO_YEAR_SLOT is guaranteed to contain an + // int32 or NaN after the call to fillLocalTimeSlots. + Value yearSeconds = dateObj->getReservedSlot(LOCAL_SECONDS_INTO_YEAR_SLOT); + if (yearSeconds.isDouble()) { + MOZ_ASSERT(IsNaN(yearSeconds.toDouble())); + args.rval().set(yearSeconds); + } else { + args.rval().setInt32(yearSeconds.toInt32() % int(SecondsPerMinute)); + } return true; } @@ -1628,8 +1683,13 @@ date_getUTCSeconds(JSContext* cx, unsigned argc, Value* vp) CallArgs args = CallArgsFromVp(argc, vp); return CallNonGenericMethod(cx, args); } - -/* Date.getMilliseconds is mapped to getUTCMilliseconds */ +/* + * Date.getMilliseconds is mapped to getUTCMilliseconds for the same reasons + * that getSeconds is mapped to getUTCSeconds (see above). No known LocalTZA + * has *ever* included a fractional-second component, however, so we can keep + * this simplification even if we stop implementing ES5 local-time computation + * semantics. + */ /* static */ MOZ_ALWAYS_INLINE bool DateObject::getUTCMilliseconds_impl(JSContext* cx, const CallArgs& args) @@ -2863,34 +2923,49 @@ date_toSource(JSContext* cx, unsigned argc, Value* vp) } #endif -// ES6 final draft 20.3.4.41. -static bool -date_toString(JSContext* cx, unsigned argc, Value* vp) +MOZ_ALWAYS_INLINE bool +IsObject(HandleValue v) { - CallArgs args = CallArgsFromVp(argc, vp); - // Step 2.a. (reordered) - double tv = GenericNaN(); - if (args.thisv().isObject()) { - // Step 1. - RootedObject obj(cx, &args.thisv().toObject()); + return v.isObject(); +} +// ES6 20.3.4.41. +MOZ_ALWAYS_INLINE bool +date_toString_impl(JSContext* cx, const CallArgs& args) +{ + // Step 1. + RootedObject obj(cx, &args.thisv().toObject()); + + // Step 2. + ESClassValue cls; + if (!GetBuiltinClass(cx, obj, &cls)) + return false; + + double tv; + if (cls != ESClass_Date) { // Step 2. - ESClassValue cls; - if (!GetBuiltinClass(cx, obj, &cls)) + tv = GenericNaN(); + } else { + // Step 3. + RootedValue unboxed(cx); + if (!Unbox(cx, obj, &unboxed)) return false; - if (cls == ESClass_Date) { - // Step 3.a. - RootedValue unboxed(cx); - if (!Unbox(cx, obj, &unboxed)) - return false; - tv = unboxed.toNumber(); - } + tv = unboxed.toNumber(); } + // Step 4. return date_format(cx, tv, FORMATSPEC_FULL, args.rval()); } +bool +date_toString(JSContext* cx, unsigned argc, Value* vp) +{ + // Step 1. + CallArgs args = CallArgsFromVp(argc, vp); + return CallNonGenericMethod(cx, args); +} + MOZ_ALWAYS_INLINE bool date_valueOf_impl(JSContext* cx, const CallArgs& args) { @@ -3040,11 +3115,26 @@ DateOneArgument(JSContext* cx, const CallArgs& args) MOZ_ASSERT(args.length() == 1); if (args.isConstructing()) { - ClippedTime t; + if (args[0].isObject()) { + RootedObject obj(cx, &args[0].toObject()); + + ESClassValue cls; + if (!GetBuiltinClass(cx, obj, &cls)) + return false; + + if (cls == ESClass_Date) { + RootedValue unboxed(cx); + if (!Unbox(cx, obj, &unboxed)) + return false; + + return NewDateObject(cx, args, TimeClip(unboxed.toNumber())); + } + } if (!ToPrimitive(cx, args[0])) return false; + ClippedTime t; if (args[0].isString()) { JSLinearString* linearStr = args[0].toString()->ensureLinear(cx); if (!linearStr) diff --git a/js/src/proxy/ScriptedDirectProxyHandler.cpp b/js/src/proxy/ScriptedDirectProxyHandler.cpp index 2022fbb4c5..d3fb6824e4 100644 --- a/js/src/proxy/ScriptedDirectProxyHandler.cpp +++ b/js/src/proxy/ScriptedDirectProxyHandler.cpp @@ -18,18 +18,6 @@ using namespace js; using JS::IsArrayAnswer; using mozilla::ArrayLength; -static inline bool -IsDataDescriptor(const PropertyDescriptor& desc) -{ - return desc.obj && !(desc.attrs & (JSPROP_GETTER | JSPROP_SETTER)); -} - -static inline bool -IsAccessorDescriptor(const PropertyDescriptor& desc) -{ - return desc.obj && desc.attrs & (JSPROP_GETTER | JSPROP_SETTER); -} - // ES6 (5 April 2014) ValidateAndApplyPropertyDescriptor(O, P, Extensible, Desc, Current) // Since we are actually performing 9.1.6.2 IsCompatiblePropertyDescriptor(Extensible, Desc, // Current), some parameters are omitted. diff --git a/js/src/tests/ecma_6/Date/constructor-one-Date-argument.js b/js/src/tests/ecma_6/Date/constructor-one-Date-argument.js new file mode 100644 index 0000000000..718c413731 --- /dev/null +++ b/js/src/tests/ecma_6/Date/constructor-one-Date-argument.js @@ -0,0 +1,40 @@ +/* + * Any copyright is dedicated to the Public Domain. + * http://creativecommonn.org/licenses/publicdomain/ + */ + +var BUGNUMBER = 1187233; +var summary = + "Passing a Date object to |new Date()| should copy it, not convert it to " + + "a primitive and create it from that."; + +print(BUGNUMBER + ": " + summary); + +/************** + * BEGIN TEST * + **************/ + +Date.prototype.toString = Date.prototype.valueOf = null; +var d = new Date(new Date(8675309)); +assertEq(d.getTime(), 8675309); + +Date.prototype.valueOf = () => 42; +d = new Date(new Date(8675309)); +assertEq(d.getTime(), 8675309); + +var D = newGlobal().Date; + +D.prototype.toString = D.prototype.valueOf = null; +var d = new Date(new D(3141592654)); +assertEq(d.getTime(), 3141592654); + +D.prototype.valueOf = () => 525600; +d = new Date(new D(3141592654)); +assertEq(d.getTime(), 3141592654); + +/******************************************************************************/ + +if (typeof reportCompare === "function") + reportCompare(true, true); + +print("Tests complete"); diff --git a/js/src/tests/ecma_6/Date/non-iso.js b/js/src/tests/ecma_6/Date/non-iso.js new file mode 100644 index 0000000000..9c352ee740 --- /dev/null +++ b/js/src/tests/ecma_6/Date/non-iso.js @@ -0,0 +1,63 @@ +/* + * Any copyright is dedicated to the Public Domain. + * http://creativecommonn.org/licenses/publicdomain/ + */ + +/* + * For the sake of cross compatibility with other implementations we + * follow the W3C "NOTE-datetime" specification when parsing dates of + * the form YYYY-MM-DDTHH:MM:SS save for a few exceptions: months, days, hours + * minutes, and seconds may be either one _or_ two digits long, and the 'T' + * preceding the time part may be replaced with a space. So, a string like + * "1997-3-8 1:1:1" will parse successfully. See bug: 1203298 + */ + +/************** + * BEGIN TEST * + **************/ + +assertEq(new Date("1997-03-08 1:1:1.01").getTime(), + new Date("1997-03-08T01:01:01.01").getTime()); +assertEq(new Date("1997-03-08 11:19:20").getTime(), + new Date("1997-03-08T11:19:20").getTime()); +assertEq(new Date("1997-3-08 11:19:20").getTime(), + new Date("1997-03-08T11:19:20").getTime()); +assertEq(new Date("1997-3-8 11:19:20").getTime(), + new Date("1997-03-08T11:19:20").getTime()); +assertEq(new Date("1997-3-8T11:19:20").getTime(), + new Date("1997-03-08T11:19:20").getTime()); +assertEq(new Date("1997-03-8T11:19:20").getTime(), + new Date("1997-03-08T11:19:20").getTime()); +assertEq(new Date("1997-03-08 11:19").getTime(), + new Date("1997-03-08T11:19").getTime()); +assertEq(new Date("1997-03-08 1:19").getTime(), + new Date("1997-03-08T1:19").getTime()); +assertEq(new Date("1997-03-08 1:1").getTime(), + new Date("1997-03-08T1:1").getTime()); +assertEq(new Date("1997-03-08 1:1:01").getTime(), + new Date("1997-03-08T1:1:01").getTime()); +assertEq(new Date("1997-03-08 1:1:1").getTime(), + new Date("1997-03-08T1:1:1").getTime()); +assertEq(new Date("1997-03-08 11").getTime(), + new Date("1997-03-08T11").getTime()); +assertEq(new Date("1997-03-08").getTime(), + new Date("1997-03-08").getTime()); +assertEq(new Date("1997-03-8").getTime(), + new Date("1997-03-08").getTime()); +assertEq(new Date("1997-3-8").getTime(), + new Date("1997-03-08").getTime()); +assertEq(new Date("1997-3-8 ").getTime(), + new Date("1997-03-08T").getTime()); // Date(NaN) +assertEq(new Date("1997-3-8 :00:01").getTime(), + new Date(NaN).getTime()); +assertEq(new Date("1997-3-8 :00:01").getTime(), + new Date(NaN).getTime()); +assertEq(new Date("1997-3-8 01::01").getTime(), + new Date(NaN).getTime()); + +/******************************************************************************/ + +if (typeof reportCompare === "function") + reportCompare(true, true); + +print("Tests complete"); diff --git a/js/src/tests/ecma_6/Date/toString-generic.js b/js/src/tests/ecma_6/Date/toString-generic.js index bd50e84953..caee47d7b1 100644 --- a/js/src/tests/ecma_6/Date/toString-generic.js +++ b/js/src/tests/ecma_6/Date/toString-generic.js @@ -3,11 +3,11 @@ var summary = 'Date.prototype.toString is a generic function'; print(BUGNUMBER + ": " + summary); -for (var thisValue of [null, undefined, 0, 1.2, true, false, "foo", Symbol.iterator, - {}, [], /foo/, Date.prototype, new Proxy(new Date(), {})]) -{ +for (var thisValue of [{}, [], /foo/, Date.prototype, new Proxy(new Date(), {})]) assertEq(Date.prototype.toString.call(thisValue), "Invalid Date"); -} + +for (var prim of [null, undefined, 0, 1.2, true, false, "foo", Symbol.iterator]) + assertThrowsInstanceOf(() => Date.prototype.toString.call(prim), TypeError); if (typeof reportCompare === "function") reportCompare(true, true); diff --git a/js/src/vm/DateObject.h b/js/src/vm/DateObject.h index b0f43d46e3..682823765a 100644 --- a/js/src/vm/DateObject.h +++ b/js/src/vm/DateObject.h @@ -31,11 +31,19 @@ class DateObject : public NativeObject static const uint32_t LOCAL_MONTH_SLOT = COMPONENTS_START_SLOT + 2; static const uint32_t LOCAL_DATE_SLOT = COMPONENTS_START_SLOT + 3; static const uint32_t LOCAL_DAY_SLOT = COMPONENTS_START_SLOT + 4; - static const uint32_t LOCAL_HOURS_SLOT = COMPONENTS_START_SLOT + 5; - static const uint32_t LOCAL_MINUTES_SLOT = COMPONENTS_START_SLOT + 6; - static const uint32_t LOCAL_SECONDS_SLOT = COMPONENTS_START_SLOT + 7; - static const uint32_t RESERVED_SLOTS = LOCAL_SECONDS_SLOT + 1; + /* + * Unlike the above slots that hold LocalTZA-adjusted component values, + * LOCAL_SECONDS_INTO_YEAR_SLOT holds a composite value that can be used + * to compute LocalTZA-adjusted hours, minutes, and seconds values. + * Specifically, LOCAL_SECONDS_INTO_YEAR_SLOT holds the number of + * LocalTZA-adjusted seconds into the year. Unix timestamps ignore leap + * seconds, so recovering hours/minutes/seconds requires only trivial + * division/modulus operations. + */ + static const uint32_t LOCAL_SECONDS_INTO_YEAR_SLOT = COMPONENTS_START_SLOT + 5; + + static const uint32_t RESERVED_SLOTS = LOCAL_SECONDS_INTO_YEAR_SLOT + 1; public: static const Class class_; diff --git a/layout/base/FrameLayerBuilder.cpp b/layout/base/FrameLayerBuilder.cpp index 9e9ba2b42a..0422156345 100644 --- a/layout/base/FrameLayerBuilder.cpp +++ b/layout/base/FrameLayerBuilder.cpp @@ -3507,7 +3507,7 @@ ContainerState::NewPaintedLayerData(nsDisplayItem* aItem, data.mAnimatedGeometryRootOffset = aTopLeft; data.mReferenceFrame = aItem->ReferenceFrame(); data.mSingleItemFixedToViewport = aShouldFixToViewport; - data.mBackfaceHidden = aItem->Frame()->BackfaceIsHidden(); + data.mBackfaceHidden = aItem->Frame()->In3DContextAndBackfaceIsHidden(); data.mIsCaret = aItem->GetType() == nsDisplayItem::TYPE_CARET; data.mNewChildLayersIndex = mNewChildLayers.Length(); @@ -4126,7 +4126,7 @@ ContainerState::ProcessDisplayItems(nsDisplayList* aList) PaintedLayerData* paintedLayerData = mPaintedLayerDataTree.FindPaintedLayerFor(animatedGeometryRoot, agrScrollClip, itemVisibleRect, false, - item->Frame()->BackfaceIsHidden(), + item->Frame()->In3DContextAndBackfaceIsHidden(), avoidCreatingLayer, [&]() { layerCount++; diff --git a/layout/generic/nsFrame.cpp b/layout/generic/nsFrame.cpp index edb178acad..4ded186cd3 100644 --- a/layout/generic/nsFrame.cpp +++ b/layout/generic/nsFrame.cpp @@ -1170,6 +1170,12 @@ nsIFrame::Combines3DTransformWithAncestors() const return StyleDisplay()->HasTransform(this) || StyleDisplay()->BackfaceIsHidden(); } +bool +nsIFrame::In3DContextAndBackfaceIsHidden() const +{ + return Combines3DTransformWithAncestors() && StyleDisplay()->BackfaceIsHidden(); +} + bool nsIFrame::HasPerspective() const { diff --git a/layout/generic/nsIFrame.h b/layout/generic/nsIFrame.h index 6605812fc6..26948731c2 100644 --- a/layout/generic/nsIFrame.h +++ b/layout/generic/nsIFrame.h @@ -1281,6 +1281,13 @@ public: */ bool Combines3DTransformWithAncestors() const; + /** + * Returns whether this frame has a hidden backface and has a parent that + * Extend3DContext(). This is useful because in some cases the hidden + * backface can safely be ignored if it could not be visible anyway. + */ + bool In3DContextAndBackfaceIsHidden() const; + bool IsPreserve3DLeaf() const { return Combines3DTransformWithAncestors() && !Extend3DContext(); } diff --git a/modules/libpref/init/all.js b/modules/libpref/init/all.js index cd7ff80e2c..ad88f6013b 100644 --- a/modules/libpref/init/all.js +++ b/modules/libpref/init/all.js @@ -133,9 +133,6 @@ pref("dom.select_events.enabled", true); // Whether or not selection events on text controls are enabled pref("dom.select_events.textcontrols.enabled", true); -// Whether or not the document visbility API is enabled -pref("dom.visibilityAPI.enabled", true); - // Whether or not File Handle is enabled. pref("dom.fileHandle.enabled", true); diff --git a/netwerk/base/LoadInfo.cpp b/netwerk/base/LoadInfo.cpp index 56e134188d..a23086cfb3 100644 --- a/netwerk/base/LoadInfo.cpp +++ b/netwerk/base/LoadInfo.cpp @@ -38,7 +38,6 @@ LoadInfo::LoadInfo(nsIPrincipal* aLoadingPrincipal, , mInternalContentPolicyType(aContentPolicyType) , mTainting(LoadTainting::Basic) , mUpgradeInsecureRequests(false) - , mUpgradeInsecurePreloads(false) , mInnerWindowID(0) , mOuterWindowID(0) , mParentOuterWindowID(0) @@ -90,8 +89,13 @@ LoadInfo::LoadInfo(nsIPrincipal* aLoadingPrincipal, ComputeIsThirdPartyContext(outerWindow); } - mUpgradeInsecureRequests = aLoadingContext->OwnerDoc()->GetUpgradeInsecureRequests(); - mUpgradeInsecurePreloads = aLoadingContext->OwnerDoc()->GetUpgradeInsecurePreloads(); + // if the document forces all requests to be upgraded from http to https, then + // we should do that for all requests. If it only forces preloads to be upgraded + // then we should enforce upgrade insecure requests only for preloads. + mUpgradeInsecureRequests = + aLoadingContext->OwnerDoc()->GetUpgradeInsecureRequests(false) || + (nsContentUtils::IsPreloadType(mInternalContentPolicyType) && + aLoadingContext->OwnerDoc()->GetUpgradeInsecureRequests(true)); } mOriginAttributes = BasePrincipal::Cast(mLoadingPrincipal)->OriginAttributesRef(); @@ -105,7 +109,6 @@ LoadInfo::LoadInfo(const LoadInfo& rhs) , mInternalContentPolicyType(rhs.mInternalContentPolicyType) , mTainting(rhs.mTainting) , mUpgradeInsecureRequests(rhs.mUpgradeInsecureRequests) - , mUpgradeInsecurePreloads(rhs.mUpgradeInsecurePreloads) , mInnerWindowID(rhs.mInnerWindowID) , mOuterWindowID(rhs.mOuterWindowID) , mParentOuterWindowID(rhs.mParentOuterWindowID) @@ -129,7 +132,6 @@ LoadInfo::LoadInfo(nsIPrincipal* aLoadingPrincipal, nsContentPolicyType aContentPolicyType, LoadTainting aTainting, bool aUpgradeInsecureRequests, - bool aUpgradeInsecurePreloads, uint64_t aInnerWindowID, uint64_t aOuterWindowID, uint64_t aParentOuterWindowID, @@ -148,7 +150,6 @@ LoadInfo::LoadInfo(nsIPrincipal* aLoadingPrincipal, , mInternalContentPolicyType(aContentPolicyType) , mTainting(aTainting) , mUpgradeInsecureRequests(aUpgradeInsecureRequests) - , mUpgradeInsecurePreloads(aUpgradeInsecurePreloads) , mInnerWindowID(aInnerWindowID) , mOuterWindowID(aOuterWindowID) , mParentOuterWindowID(aParentOuterWindowID) @@ -390,13 +391,6 @@ LoadInfo::GetUpgradeInsecureRequests(bool* aResult) return NS_OK; } -NS_IMETHODIMP -LoadInfo::GetUpgradeInsecurePreloads(bool* aResult) -{ - *aResult = mUpgradeInsecurePreloads; - return NS_OK; -} - NS_IMETHODIMP LoadInfo::GetInnerWindowID(uint64_t* aResult) { diff --git a/netwerk/base/LoadInfo.h b/netwerk/base/LoadInfo.h index 55e8f75a11..4ad26eabff 100644 --- a/netwerk/base/LoadInfo.h +++ b/netwerk/base/LoadInfo.h @@ -81,7 +81,6 @@ private: nsContentPolicyType aContentPolicyType, LoadTainting aTainting, bool aUpgradeInsecureRequests, - bool aUpgradeInsecurePreloads, uint64_t aInnerWindowID, uint64_t aOuterWindowID, uint64_t aParentOuterWindowID, @@ -119,7 +118,6 @@ private: nsContentPolicyType mInternalContentPolicyType; LoadTainting mTainting; bool mUpgradeInsecureRequests; - bool mUpgradeInsecurePreloads; uint64_t mInnerWindowID; uint64_t mOuterWindowID; uint64_t mParentOuterWindowID; diff --git a/netwerk/base/nsILoadInfo.idl b/netwerk/base/nsILoadInfo.idl index e283433044..8912e7bbb0 100644 --- a/netwerk/base/nsILoadInfo.idl +++ b/netwerk/base/nsILoadInfo.idl @@ -29,7 +29,7 @@ typedef unsigned long nsSecurityFlags; /** * An nsILoadOwner represents per-load information about who started the load. */ -[scriptable, builtinclass, uuid(41e311d0-5894-4aaa-80b5-5b7099dfc404)] +[scriptable, builtinclass, uuid(ddc65bf9-2f60-41ab-b22a-4f1ae9efcd36)] interface nsILoadInfo : nsISupports { /** @@ -336,11 +336,6 @@ interface nsILoadInfo : nsISupports */ [infallible] readonly attribute boolean upgradeInsecureRequests; - /** - * Same as upgradeInsecureRequests but for preloads. - */ - [infallible] readonly attribute boolean upgradeInsecurePreloads; - /** * Typically these are the window IDs of the window in which the element being * loaded lives. However, if the element being loaded is InternalContentPolicyType()); - bool upgradeRequests = - ((isPreload && aLoadInfo->GetUpgradeInsecurePreloads()) || - (aLoadInfo->GetUpgradeInsecureRequests())); - // Please note that cross origin top level navigations are not subject // to upgrade-insecure-requests, see: // http://www.w3.org/TR/upgrade-insecure-requests/#examples @@ -2268,7 +2263,7 @@ NS_ShouldSecureUpgrade(nsIURI* aURI, (aLoadInfo->GetExternalContentPolicyType() == nsIContentPolicy::TYPE_DOCUMENT) && (!aChannelResultPrincipal->Equals(aLoadInfo->LoadingPrincipal())); - if (upgradeRequests && !crossOriginNavigation) { + if (aLoadInfo->GetUpgradeInsecureRequests() && !crossOriginNavigation) { // let's log a message to the console that we are upgrading a request nsAutoCString spec, scheme; aURI->GetSpec(spec); diff --git a/netwerk/ipc/NeckoChannelParams.ipdlh b/netwerk/ipc/NeckoChannelParams.ipdlh index ae6ede538e..9d3cc5b49d 100644 --- a/netwerk/ipc/NeckoChannelParams.ipdlh +++ b/netwerk/ipc/NeckoChannelParams.ipdlh @@ -32,7 +32,6 @@ struct LoadInfoArgs uint32_t contentPolicyType; uint32_t tainting; bool upgradeInsecureRequests; - bool upgradeInsecurePreloads; uint64_t innerWindowID; uint64_t outerWindowID; uint64_t parentOuterWindowID; diff --git a/parser/html/nsHtml5TreeOpExecutor.cpp b/parser/html/nsHtml5TreeOpExecutor.cpp index c9659f1b8d..72c710edba 100644 --- a/parser/html/nsHtml5TreeOpExecutor.cpp +++ b/parser/html/nsHtml5TreeOpExecutor.cpp @@ -1028,21 +1028,9 @@ nsHtml5TreeOpExecutor::AddSpeculationCSP(const nsAString& aCSP) nsIPrincipal* principal = mDocument->NodePrincipal(); nsCOMPtr preloadCsp; - nsresult rv = principal->GetPreloadCsp(getter_AddRefs(preloadCsp)); + nsCOMPtr domDoc = do_QueryInterface(mDocument); + nsresult rv = principal->EnsurePreloadCSP(domDoc, getter_AddRefs(preloadCsp)); NS_ENSURE_SUCCESS_VOID(rv); - if (!preloadCsp) { - preloadCsp = do_CreateInstance("@mozilla.org/cspcontext;1", &rv); - NS_ENSURE_SUCCESS_VOID(rv); - - // Store the request context for violation reports - nsCOMPtr domDoc = do_QueryInterface(mDocument); - rv = preloadCsp->SetRequestContext(domDoc, nullptr); - NS_ENSURE_SUCCESS_VOID(rv); - - // set the new csp - rv = principal->SetPreloadCsp(preloadCsp); - NS_ENSURE_SUCCESS_VOID(rv); - } // please note that meta CSPs and CSPs delivered through a header need // to be joined together. diff --git a/security/manager/locales/en-US/chrome/pipnss/pipnss.properties b/security/manager/locales/en-US/chrome/pipnss/pipnss.properties index 7f9eb05e82..902fa984ab 100755 --- a/security/manager/locales/en-US/chrome/pipnss/pipnss.properties +++ b/security/manager/locales/en-US/chrome/pipnss/pipnss.properties @@ -292,7 +292,8 @@ certErrorExpiredNow=The certificate expired on %1$S. The current time is %2$S. # LOCALIZATION NOTE (certErrorNotYetValidNow): Do not translate %1$S (date+time certificate will become valid) or %2$S (current date+time) certErrorNotYetValidNow=The certificate will not be valid until %1$S. The current time is %2$S. -certErrorCodePrefix=(Error code: %S) +# LOCALIZATION NOTE (certErrorCodePrefix2): Do not translate %1$S +certErrorCodePrefix2=Error code: %1$S CertInfoIssuedFor=Issued to: CertInfoIssuedBy=Issued by: diff --git a/security/manager/ssl/TransportSecurityInfo.cpp b/security/manager/ssl/TransportSecurityInfo.cpp index 88a6625832..41e8682c1e 100644 --- a/security/manager/ssl/TransportSecurityInfo.cpp +++ b/security/manager/ssl/TransportSecurityInfo.cpp @@ -885,7 +885,6 @@ AppendErrorTextCode(PRErrorCode errorCodeToReport, if (codeName) { nsCString error_id(codeName); - ToLowerCase(error_id); NS_ConvertASCIItoUTF16 idU(error_id); const char16_t *params[1]; @@ -893,7 +892,7 @@ AppendErrorTextCode(PRErrorCode errorCodeToReport, nsString formattedString; nsresult rv; - rv = component->PIPBundleFormatStringFromName("certErrorCodePrefix", + rv = component->PIPBundleFormatStringFromName("certErrorCodePrefix2", params, 1, formattedString); if (NS_SUCCEEDED(rv)) { diff --git a/security/manager/ssl/nsNSSErrors.cpp b/security/manager/ssl/nsNSSErrors.cpp index 28272e32b2..fc8bd3e318 100644 --- a/security/manager/ssl/nsNSSErrors.cpp +++ b/security/manager/ssl/nsNSSErrors.cpp @@ -78,14 +78,13 @@ nsNSSErrors::getErrorMessageFromCode(PRErrorCode err, { nsresult rv; nsCString error_id(nss_error_id_str); - ToLowerCase(error_id); NS_ConvertASCIItoUTF16 idU(error_id); const char16_t *params[1]; params[0] = idU.get(); nsString formattedString; - rv = component->PIPBundleFormatStringFromName("certErrorCodePrefix", + rv = component->PIPBundleFormatStringFromName("certErrorCodePrefix2", params, 1, formattedString); if (NS_SUCCEEDED(rv)) { diff --git a/security/manager/ssl/tests/unit/test_toolkit_securityreporter.js b/security/manager/ssl/tests/unit/test_toolkit_securityreporter.js new file mode 100644 index 0000000000..1c7286a6ac --- /dev/null +++ b/security/manager/ssl/tests/unit/test_toolkit_securityreporter.js @@ -0,0 +1,132 @@ +/* -*- 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/. */ + +/* This test is for the TLS error reporting functionality exposed by + * SecurityReporter.js in /toolkit/components/securityreporter. The test is + * here because we make use of the tlsserver functionality that lives with the + * PSM ssl tests. + * + * The testing here will be augmented by the existing mochitests for the + * error reporting functionality in aboutNetError.xhtml and + * aboutCertError.xhtml once these make use of this component. + */ + +"use strict"; +const CC = Components.Constructor; +const Cm = Components.manager; + +Cu.import("resource://testing-common/AppInfo.jsm"); +updateAppInfo(); + +// We must get the profile before performing operations on the cert db. +do_get_profile(); + +const certdb = Cc["@mozilla.org/security/x509certdb;1"] + .getService(Ci.nsIX509CertDB); +const reporter = Cc["@mozilla.org/securityreporter;1"] + .getService(Ci.nsISecurityReporter); + + +const BinaryInputStream = CC("@mozilla.org/binaryinputstream;1", + "nsIBinaryInputStream", "setInputStream"); + +var server; + +// this allows us to create a callback which checks that a report is as +// expected. +function getReportCheck(expectReport, expectedError) { + return function sendReportWithInfo(transportSecurityInfo) { + // register a path handler on the server + server.registerPathHandler("/submit/sslreports", + function(request, response) { + if (expectReport) { + let report = JSON.parse(readDataFromRequest(request)); + do_check_eq(report.errorCode, expectedError); + response.setStatusLine(null, 201, "Created"); + response.write("Created"); + } else { + do_throw("No report should have been received"); + } + }); + + reporter.reportTLSError(transportSecurityInfo, "example.com", -1); + } +} + +// read the request body from a request +function readDataFromRequest(aRequest) { + if (aRequest.method == "POST" || aRequest.method == "PUT") { + if (aRequest.bodyInputStream) { + let inputStream = new BinaryInputStream(aRequest.bodyInputStream); + let bytes = []; + let available; + + while ((available = inputStream.available()) > 0) { + Array.prototype.push.apply(bytes, inputStream.readByteArray(available)); + } + + return String.fromCharCode.apply(null, bytes); + } + } + return null; +} + +function run_test() { + // start a report server + server = new HttpServer(); + server.start(-1); + + let port = server.identity.primaryPort; + + // Set the reporting URL to ensure any reports are sent to the test server + Services.prefs.setCharPref("security.ssl.errorReporting.url", + `http://localhost:${port}/submit/sslreports`); + // set strict-mode pinning enforcement so we can cause connection failures. + Services.prefs.setIntPref("security.cert_pinning.enforcement_level", 2); + + // start a TLS server + add_tls_server_setup("BadCertServer", "bad_certs"); + + // Add a user-specified trust anchor. + addCertFromFile(certdb, "bad_certs/other-test-ca.pem", "CTu,u,u"); + + + // Cause a reportable condition with error reporting disabled. No report + // should be sent. + Services.prefs.setBoolPref("security.ssl.errorReporting.enabled", false); + add_connection_test("expired.example.com", + SEC_ERROR_EXPIRED_CERTIFICATE, null, + getReportCheck(false)); + + // Now enable reporting + add_test(function () { + Services.prefs.setBoolPref("security.ssl.errorReporting.enabled", true); + run_next_test(); + }); + + // test calling the component with no transportSecurityInfo. No report should + // be sent even though reporting is enabled. + add_test(function() { + server.registerPathHandler("/submit/sslreports", + function(request, response) { + do_throw("No report should be sent"); + }); + reporter.reportTLSError(null, "example.com", -1); + run_next_test(); + }); + + // Test sending a report with no error. This allows us to check the case + // where there is no failed cert chain + add_connection_test("good.include-subdomains.pinning.example.com", + PRErrorCodeSuccess, null, + getReportCheck(true, PRErrorCodeSuccess)); + + // Test sending a report where there is an error and a failed cert chain. + add_connection_test("expired.example.com", + SEC_ERROR_EXPIRED_CERTIFICATE, null, + getReportCheck(true, SEC_ERROR_EXPIRED_CERTIFICATE)); + + run_next_test(); +} diff --git a/security/manager/ssl/tests/unit/xpcshell.ini b/security/manager/ssl/tests/unit/xpcshell.ini index 66e953226f..2befbb41f3 100644 --- a/security/manager/ssl/tests/unit/xpcshell.ini +++ b/security/manager/ssl/tests/unit/xpcshell.ini @@ -155,3 +155,6 @@ skip-if = toolkit == 'android' || buildapp == 'b2g' [test_weak_crypto.js] firefox-appdir = browser + +# The TLS error reporting functionality lives in /toolkit but needs tlsserver +[test_toolkit_securityreporter.js] diff --git a/testing/profiles/prefs_general.js b/testing/profiles/prefs_general.js index 69ad052e05..c3caaa1215 100644 --- a/testing/profiles/prefs_general.js +++ b/testing/profiles/prefs_general.js @@ -241,7 +241,7 @@ user_pref("identity.fxaccounts.remote.signin.uri", "https://%(server)s/fxa-signi user_pref("identity.fxaccounts.settings.uri", "https://%(server)s/fxa-settings"); // Make sure SSL Error reports don't hit the network -user_pref("security.ssl.errorReporting.url", "https://example.com/browser/browser/base/content/test/general/pinning_reports.sjs?succeed"); +user_pref("security.ssl.errorReporting.url", "https://example.com/browser/browser/base/content/test/general/ssl_error_reports.sjs?succeed"); // Make sure Translation won't hit the network. user_pref("browser.translation.bing.authURL", "http://%(server)s/browser/browser/components/translation/test/bing.sjs"); diff --git a/testing/web-platform/tests/cssom-view/scrollingElement.html b/testing/web-platform/tests/cssom-view/scrollingElement.html new file mode 100644 index 0000000000..57ca450220 --- /dev/null +++ b/testing/web-platform/tests/cssom-view/scrollingElement.html @@ -0,0 +1,97 @@ + + +cssom-view - scrollingElement + + + + +
+ diff --git a/testing/web-platform/tests/dom/nodes/attributes.html b/testing/web-platform/tests/dom/nodes/attributes.html index 58a3c89d03..52af437349 100644 --- a/testing/web-platform/tests/dom/nodes/attributes.html +++ b/testing/web-platform/tests/dom/nodes/attributes.html @@ -395,6 +395,125 @@ test(function() { assert_equals(attr.ownerElement, null) }, "Attribute loses its owner when removed") +test(function() { + var el = document.createElement("div") + el.setAttribute("foo", "bar") + var attr = el.attributes[0] + var attrNode = el.getAttributeNode("foo"); + var attrNodeNS = el.getAttributeNodeNS("", "foo"); + assert_equals(attr, attrNode); + assert_equals(attr, attrNodeNS); + el.setAttributeNS("x", "foo2", "bar2"); + var attr2 = el.attributes[1]; + var attrNodeNS2 = el.getAttributeNodeNS("x", "foo2"); + assert_equals(attr2, attrNodeNS2); +}, "Basic functionality of getAttributeNode/getAttributeNodeNS") + +test(function() { + var el = document.createElement("div") + el.setAttribute("foo", "bar") + var attrNode = el.getAttributeNode("foo"); + var attrNodeNS = el.getAttributeNodeNS("", "foo"); + assert_equals(attrNode, attrNodeNS); + el.removeAttribute("foo"); + var el2 = document.createElement("div"); + el2.setAttributeNode(attrNode); + assert_equals(attrNode, el2.getAttributeNode("foo")); + assert_equals(attrNode, el2.attributes[0]); + assert_equals(attrNode.ownerElement, el2); + assert_equals(attrNode.value, "bar"); + + var el3 = document.createElement("div"); + el2.removeAttribute("foo"); + el3.setAttribute("foo", "baz"); + el3.setAttributeNode(attrNode); + assert_equals(el3.getAttribute("foo"), "bar"); +}, "Basic functionality of setAttributeNode") + +test(function() { + var el = document.createElement("div") + el.setAttributeNS("x", "foo", "bar") + var attrNode = el.getAttributeNodeNS("x", "foo"); + el.removeAttribute("foo"); + var el2 = document.createElement("div"); + el2.setAttributeNS("x", "foo", "baz"); + el2.setAttributeNodeNS(attrNode); + assert_equals(el2.getAttributeNS("x", "foo"), "bar"); +}, "Basic functionality of setAttributeNodeNS") + +test(function() { + var el = document.createElement("div") + el.setAttribute("foo", "bar") + var attrNode = el.getAttributeNode("foo"); + el.removeAttributeNode(attrNode); + var el2 = document.createElement("div"); + el2.setAttributeNode(attrNode); + assert_equals(el2.attributes[0], attrNode); + assert_equals(el.attributes.length, 0); +}, "Basic functionality of removeAttributeNode") + +test(function() { + var el = document.createElement("div") + el.setAttribute("foo", "bar") + var attrNode = el.getAttributeNode("foo"); + var el2 = document.createElement("div"); + assert_throws("INUSE_ATTRIBUTE_ERR", function(){el2.setAttributeNode(attrNode)}); +}, "setAttributeNode on bound attribute should throw InUseAttributeError") + +// Have to use an async_test to see what a DOMAttrModified listener sees, +// because otherwise the event dispatch code will swallow our exceptions. And +// we want to make sure this test always happens, even when no mutation events +// run. +var setAttributeNode_mutation_test = async_test("setAttributeNode, if it fires mutation events, should fire one with the new node when resetting an existing attribute"); + +test(function(){ + var el = document.createElement("div") + var attrNode1 = document.createAttribute("foo"); + attrNode1.value = "bar"; + el.setAttributeNode(attrNode1); + var attrNode2 = document.createAttribute("foo"); + attrNode2.value = "baz"; + + el.addEventListener("DOMAttrModified", function(e) { + // If this never gets called, that's OK, I guess. But if it gets called, it + // better represent a single modification with attrNode2 as the relatedNode. + // We have to do an inner test() call here, because otherwise the exceptions + // our asserts trigger will get swallowed by the event dispatch code. + setAttributeNode_mutation_test.step(function() { + assert_equals(e.attrName, "foo"); + assert_equals(e.attrChange, MutationEvent.MODIFICATION); + assert_equals(e.prevValue, "bar"); + assert_equals(e.newValue, "baz"); + assert_equals(e.relatedNode, attrNode2); + }); + }); + + var oldNode = el.setAttributeNode(attrNode2); + assert_equals(oldNode, attrNode1, + "Must return the old attr node from a setAttributeNode call"); +}, "setAttributeNode, if it fires mutation events, should fire one with the new node when resetting an existing attribute (outer shell)"); +setAttributeNode_mutation_test.done(); + +test(function(){ + var el = document.createElement("div") + el.setAttribute("a", "b"); + el.setAttribute("c", "d"); + + assert_array_equals(Array.prototype.map.call(el.attributes, function(a) { return a.name }), + ["a", "c"]); + assert_array_equals(Array.prototype.map.call(el.attributes, function(a) { return a.value }), + ["b", "d"]); + + var attrNode = document.createAttribute("a"); + attrNode.value = "e"; + el.setAttributeNode(attrNode); + + assert_array_equals(Array.prototype.map.call(el.attributes, function(a) { return a.name }), + ["a", "c"]); + assert_array_equals(Array.prototype.map.call(el.attributes, function(a) { return a.value }), + ["e", "d"]); +}, "setAttributeNode called with an Attr that has the same name as an existing one should not change attribute order"); + test(function() { var el = document.createElement("div"); el.setAttribute("foo", "bar"); @@ -428,4 +547,132 @@ test(function() { assert_equals(el.getAttributeNames()[1], el.attributes[1].name); assert_equals(el.getAttributeNames()[2], el.attributes[2].name); }, "getAttributeNames tests"); + +function getEnumerableOwnProps1(obj) { + var arr = []; + for (var prop in obj) { + if (obj.hasOwnProperty(prop)) { + arr.push(prop); + } + } + return arr; +} + +function getEnumerableOwnProps2(obj) { + return Object.getOwnPropertyNames(obj).filter( + (name) => Object.getOwnPropertyDescriptor(obj, name).enumerable) +} + +test(function() { + var el = document.createElement("div"); + el.setAttribute("a", ""); + el.setAttribute("b", ""); + assert_array_equals(getEnumerableOwnProps1(el.attributes), + ["0", "1"]) + assert_array_equals(getEnumerableOwnProps2(el.attributes), + ["0", "1"]) + assert_array_equals(Object.getOwnPropertyNames(el.attributes), + ["0", "1", "a", "b"]) +}, "Own property correctness with basic attributes"); + +test(function() { + var el = document.createElement("div"); + el.setAttributeNS("", "a", ""); + el.setAttribute("b", ""); + el.setAttributeNS("foo", "a", ""); + assert_array_equals(getEnumerableOwnProps1(el.attributes), + ["0", "1", "2"]) + assert_array_equals(getEnumerableOwnProps2(el.attributes), + ["0", "1", "2"]) + assert_array_equals(Object.getOwnPropertyNames(el.attributes), + ["0", "1", "2", "a", "b"]) + for (var propName of Object.getOwnPropertyNames(el.attributes)) { + assert_true(el.attributes[propName] instanceof Attr, + "el.attributes has an Attr for property name " + propName); + } +}, "Own property correctness with non-namespaced attribute before same-name namespaced one"); + +test(function() { + var el = document.createElement("div"); + el.setAttributeNS("foo", "a", ""); + el.setAttribute("b", ""); + el.setAttributeNS("", "a", ""); + assert_array_equals(getEnumerableOwnProps1(el.attributes), + ["0", "1", "2"]) + assert_array_equals(getEnumerableOwnProps2(el.attributes), + ["0", "1", "2"]) + assert_array_equals(Object.getOwnPropertyNames(el.attributes), + ["0", "1", "2", "a", "b"]) + for (var propName of Object.getOwnPropertyNames(el.attributes)) { + assert_true(el.attributes[propName] instanceof Attr, + "el.attributes has an Attr for property name " + propName); + } +}, "Own property correctness with namespaced attribute before same-name non-namespaced one"); + +test(function() { + var el = document.createElement("div"); + el.setAttributeNS("foo", "a:b", ""); + el.setAttributeNS("foo", "c:d", ""); + el.setAttributeNS("bar", "a:b", ""); + assert_array_equals(getEnumerableOwnProps1(el.attributes), + ["0", "1", "2"]) + assert_array_equals(getEnumerableOwnProps2(el.attributes), + ["0", "1", "2"]) + assert_array_equals(Object.getOwnPropertyNames(el.attributes), + ["0", "1", "2", "a:b", "c:d"]) + for (var propName of Object.getOwnPropertyNames(el.attributes)) { + assert_true(el.attributes[propName] instanceof Attr, + "el.attributes has an Attr for property name " + propName); + } +}, "Own property correctness with two namespaced attributes with the same name-with-prefix"); + +test(function() { + var el = document.createElement("div"); + el.setAttributeNS("foo", "A:B", ""); + el.setAttributeNS("bar", "c:D", ""); + el.setAttributeNS("baz", "e:F", ""); + el.setAttributeNS("qux", "g:h", ""); + el.setAttributeNS("", "I", ""); + el.setAttributeNS("", "j", ""); + assert_array_equals(Object.getOwnPropertyNames(el.attributes), + ["0", "1", "2", "3", "4", "5", "g:h", "j"]) + for (var propName of Object.getOwnPropertyNames(el.attributes)) { + assert_true(el.attributes[propName] instanceof Attr, + "el.attributes has an Attr for property name " + propName); + } +}, "Own property names should only include all-lowercase qualified names for an HTML element in an HTML document"); + +test(function() { + var el = document.createElementNS("", "div"); + el.setAttributeNS("foo", "A:B", ""); + el.setAttributeNS("bar", "c:D", ""); + el.setAttributeNS("baz", "e:F", ""); + el.setAttributeNS("qux", "g:h", ""); + el.setAttributeNS("", "I", ""); + el.setAttributeNS("", "j", ""); + assert_array_equals(Object.getOwnPropertyNames(el.attributes), + ["0", "1", "2", "3", "4", "5", "A:B", "c:D", "e:F", "g:h", "I", "j"]) + for (var propName of Object.getOwnPropertyNames(el.attributes)) { + assert_true(el.attributes[propName] instanceof Attr, + "el.attributes has an Attr for property name " + propName); + } +}, "Own property names should include all qualified names for a non-HTML element in an HTML document"); + +test(function() { + var doc = document.implementation.createDocument(null, ""); + assert_equals(doc.contentType, "application/xml"); + var el = doc.createElementNS("http://www.w3.org/1999/xhtml", "div"); + el.setAttributeNS("foo", "A:B", ""); + el.setAttributeNS("bar", "c:D", ""); + el.setAttributeNS("baz", "e:F", ""); + el.setAttributeNS("qux", "g:h", ""); + el.setAttributeNS("", "I", ""); + el.setAttributeNS("", "j", ""); + assert_array_equals(Object.getOwnPropertyNames(el.attributes), + ["0", "1", "2", "3", "4", "5", "A:B", "c:D", "e:F", "g:h", "I", "j"]) + for (var propName of Object.getOwnPropertyNames(el.attributes)) { + assert_true(el.attributes[propName] instanceof Attr, + "el.attributes has an Attr for property name " + propName); + } +}, "Own property names should include all qualified names for an HTML element in a non-HTML document"); diff --git a/toolkit/themes/shared/in-content/common.inc.css b/toolkit/themes/shared/in-content/common.inc.css index 00178cc8f7..753e09965d 100644 --- a/toolkit/themes/shared/in-content/common.inc.css +++ b/toolkit/themes/shared/in-content/common.inc.css @@ -175,7 +175,6 @@ html|button:disabled, xul|button[disabled="true"], xul|colorpicker[type="button"][disabled="true"], xul|menulist[disabled="true"] { - cursor: not-allowed; opacity: 0.5; }