nsresult nsXBLService::GetBinding(nsIContent* aBoundElement, nsIURI* aURI, bool aPeekOnly, nsIPrincipal* aOriginPrincipal, bool* aIsReady, nsXBLBinding** aResult, nsTArray<nsCOMPtr<nsIURI>>& aDontExtendURIs) { NS_ASSERTION(aPeekOnly || aResult, "Must have non-null out param if not just peeking to see " "whether the binding is ready"); if (aResult) *aResult = nullptr; if (!aURI) return NS_ERROR_FAILURE; nsAutoCString ref; aURI->GetRef(ref); nsCOMPtr<nsIDocument> boundDocument = aBoundElement->OwnerDoc(); RefPtr<nsXBLDocumentInfo> docInfo; nsresult rv = LoadBindingDocumentInfo(aBoundElement, boundDocument, aURI, aOriginPrincipal, false, getter_AddRefs(docInfo)); NS_ENSURE_SUCCESS(rv, rv); if (!docInfo) return NS_ERROR_FAILURE; WeakPtr<nsXBLPrototypeBinding> protoBinding = docInfo->GetPrototypeBinding(ref); if (!protoBinding) { #ifdef DEBUG nsAutoCString uriSpec; aURI->GetSpec(uriSpec); nsAutoCString doc; boundDocument->GetDocumentURI()->GetSpec(doc); nsAutoCString message("Unable to locate an XBL binding for URI "); message += uriSpec; message += " in document "; message += doc; NS_WARNING(message.get()); #endif return NS_ERROR_FAILURE; } // If the binding isn't whitelisted, refuse to apply it to content that // doesn't subsume it (modulo a few exceptions). if (!MayBindToContent(protoBinding, aBoundElement, aURI)) { #ifdef DEBUG nsAutoCString uriSpec; aURI->GetSpec(uriSpec); nsAutoCString message("Permission denied to apply binding "); message += uriSpec; message += " to unprivileged content. Set bindToUntrustedContent=true on " "the binding to override this restriction."; NS_WARNING(message.get()); #endif return NS_ERROR_FAILURE; } aDontExtendURIs.AppendElement(protoBinding->BindingURI()); nsCOMPtr<nsIURI> altBindingURI = protoBinding->AlternateBindingURI(); if (altBindingURI) { aDontExtendURIs.AppendElement(altBindingURI); } // Our prototype binding must have all its resources loaded. bool ready = protoBinding->LoadResources(); if (!ready) { // Add our bound element to the protos list of elts that should // be notified when the stylesheets and scripts finish loading. protoBinding->AddResourceListener(aBoundElement); return NS_ERROR_FAILURE; // The binding isn't ready yet. } rv = protoBinding->ResolveBaseBinding(); NS_ENSURE_SUCCESS(rv, rv); nsCOMPtr<nsIURI> baseBindingURI; WeakPtr<nsXBLPrototypeBinding> baseProto = protoBinding->GetBasePrototype(); if (baseProto) { baseBindingURI = baseProto->BindingURI(); } else { baseBindingURI = protoBinding->GetBaseBindingURI(); if (baseBindingURI) { uint32_t count = aDontExtendURIs.Length(); for (uint32_t index = 0; index < count; ++index) { bool equal; rv = aDontExtendURIs[index]->Equals(baseBindingURI, &equal); NS_ENSURE_SUCCESS(rv, rv); if (equal) { nsAutoCString spec, basespec; protoBinding->BindingURI()->GetSpec(spec); NS_ConvertUTF8toUTF16 protoSpec(spec); baseBindingURI->GetSpec(basespec); NS_ConvertUTF8toUTF16 baseSpecUTF16(basespec); const char16_t* params[] = { protoSpec.get(), baseSpecUTF16.get() }; nsContentUtils::ReportToConsole(nsIScriptError::warningFlag, NS_LITERAL_CSTRING("XBL"), nullptr, nsContentUtils::eXBL_PROPERTIES, "CircularExtendsBinding", params, ArrayLength(params), boundDocument->GetDocumentURI()); return NS_ERROR_ILLEGAL_VALUE; } } } } RefPtr<nsXBLBinding> baseBinding; if (baseBindingURI) { nsCOMPtr<nsIContent> child = protoBinding->GetBindingElement(); rv = GetBinding(aBoundElement, baseBindingURI, aPeekOnly, child->NodePrincipal(), aIsReady, getter_AddRefs(baseBinding), aDontExtendURIs); if (NS_FAILED(rv)) return rv; // We aren't ready yet. } *aIsReady = true; if (!aPeekOnly) { // Make a new binding NS_ENSURE_STATE(protoBinding); nsXBLBinding *newBinding = new nsXBLBinding(protoBinding); if (baseBinding) { if (!baseProto) { protoBinding->SetBasePrototype(baseBinding->PrototypeBinding()); } newBinding->SetBaseBinding(baseBinding); } NS_ADDREF(*aResult = newBinding); } return NS_OK; }