// static bool IndexedDatabaseManager::DefineIndexedDB(JSContext* aCx, JS::Handle<JSObject*> aGlobal) { MOZ_ASSERT(NS_IsMainThread()); MOZ_ASSERT(js::GetObjectClass(aGlobal)->flags & JSCLASS_DOM_GLOBAL, "Passed object is not a global object!"); RefPtr<IDBFactory> factory; if (NS_FAILED(IDBFactory::CreateForMainThreadJS(aCx, aGlobal, getter_AddRefs(factory)))) { return false; } MOZ_ASSERT(factory, "This should never fail for chrome!"); JS::Rooted<JS::Value> indexedDB(aCx); js::AssertSameCompartment(aCx, aGlobal); if (!GetOrCreateDOMReflector(aCx, factory, &indexedDB)) { return false; } return JS_DefineProperty(aCx, aGlobal, IDB_STR, indexedDB, JSPROP_ENUMERATE); }
// static bool IndexedDatabaseManager::DefineIndexedDB(JSContext* aCx, JS::Handle<JSObject*> aGlobal) { MOZ_ASSERT(NS_IsMainThread()); MOZ_ASSERT(js::GetObjectClass(aGlobal)->flags & JSCLASS_DOM_GLOBAL, "Passed object is not a global object!"); // We need to ensure that the manager has been created already here so that we // load preferences that may control which properties are exposed. if (NS_WARN_IF(!GetOrCreate())) { return false; } if (!IDBCursorBinding::GetConstructorObject(aCx, aGlobal) || !IDBCursorWithValueBinding::GetConstructorObject(aCx, aGlobal) || !IDBDatabaseBinding::GetConstructorObject(aCx, aGlobal) || !IDBFactoryBinding::GetConstructorObject(aCx, aGlobal) || !IDBIndexBinding::GetConstructorObject(aCx, aGlobal) || !IDBKeyRangeBinding::GetConstructorObject(aCx, aGlobal) || !IDBLocaleAwareKeyRangeBinding::GetConstructorObject(aCx, aGlobal) || !IDBMutableFileBinding::GetConstructorObject(aCx, aGlobal) || !IDBObjectStoreBinding::GetConstructorObject(aCx, aGlobal) || !IDBOpenDBRequestBinding::GetConstructorObject(aCx, aGlobal) || !IDBRequestBinding::GetConstructorObject(aCx, aGlobal) || !IDBTransactionBinding::GetConstructorObject(aCx, aGlobal) || !IDBVersionChangeEventBinding::GetConstructorObject(aCx, aGlobal)) { return false; } RefPtr<IDBFactory> factory; if (NS_FAILED(IDBFactory::CreateForMainThreadJS(aCx, aGlobal, getter_AddRefs(factory)))) { return false; } MOZ_ASSERT(factory, "This should never fail for chrome!"); JS::Rooted<JS::Value> indexedDB(aCx); js::AssertSameCompartment(aCx, aGlobal); if (!GetOrCreateDOMReflector(aCx, factory, &indexedDB)) { return false; } return JS_DefineProperty(aCx, aGlobal, IDB_STR, indexedDB, JSPROP_ENUMERATE); }
void ThrowExceptionObject(JSContext* aCx, Exception* aException) { JS::Rooted<JS::Value> thrown(aCx); // If we stored the original thrown JS value in the exception // (see XPCConvert::ConstructException) and we are in a web context // (i.e., not chrome), rethrow the original value. This only applies to JS // implemented components so we only need to check for this on the main // thread. if (NS_IsMainThread() && !nsContentUtils::IsCallerChrome() && aException->StealJSVal(thrown.address())) { // Now check for the case when thrown is a number which matches // aException->GetResult(). This would indicate that what actually got // thrown was an nsresult value. In that situation, we should go back // through dom::Throw with that nsresult value, because it will make sure to // create the right sort of Exception or DOMException, with the right // global. if (thrown.isNumber()) { nsresult exceptionResult; if (NS_SUCCEEDED(aException->GetResult(&exceptionResult)) && double(exceptionResult) == thrown.toNumber()) { Throw(aCx, exceptionResult); return; } } if (!JS_WrapValue(aCx, &thrown)) { return; } ThrowExceptionValueIfSafe(aCx, thrown, aException); return; } if (!GetOrCreateDOMReflector(aCx, aException, &thrown)) { return; } ThrowExceptionValueIfSafe(aCx, thrown, aException); }
bool StructuredCloneHelper::ReadTransferCallback(JSContext* aCx, JSStructuredCloneReader* aReader, uint32_t aTag, void* aContent, uint64_t aExtraData, JS::MutableHandleObject aReturnObject) { MOZ_ASSERT(mSupportsTransferring); if (aTag == SCTAG_DOM_MAP_MESSAGEPORT) { // This can be null. nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(mParent); MOZ_ASSERT(aExtraData < mPortIdentifiers.Length()); const MessagePortIdentifier& portIdentifier = mPortIdentifiers[aExtraData]; // aExtraData is the index of this port identifier. ErrorResult rv; nsRefPtr<MessagePort> port = MessagePort::Create(window, portIdentifier, rv); if (NS_WARN_IF(rv.Failed())) { return false; } mTransferredPorts.AppendElement(port); JS::Rooted<JS::Value> value(aCx); if (!GetOrCreateDOMReflector(aCx, port, &value)) { JS_ClearPendingException(aCx); return false; } aReturnObject.set(&value.toObject()); return true; } return false; }
bool ReadTransfer(JSContext* aCx, JSStructuredCloneReader* aReader, uint32_t aTag, void* aContent, uint64_t aExtraData, void* aClosure, JS::MutableHandle<JSObject*> aReturnObject) { MOZ_ASSERT(NS_IsMainThread()); MOZ_ASSERT(aClosure); auto* closure = static_cast<StructuredCloneClosureInternalReadOnly*>(aClosure); if (aTag != SCTAG_DOM_MAP_MESSAGEPORT) { return false; } MOZ_ASSERT(aContent == 0); MOZ_ASSERT(aExtraData < closure->mClosure.mMessagePortIdentifiers.Length()); ErrorResult rv; nsRefPtr<MessagePort> port = MessagePort::Create(closure->mWindow, closure->mClosure.mMessagePortIdentifiers[aExtraData], rv); if (NS_WARN_IF(rv.Failed())) { return false; } closure->mMessagePorts.AppendElement(port); JS::Rooted<JS::Value> value(aCx); if (!GetOrCreateDOMReflector(aCx, port, &value)) { JS_ClearPendingException(aCx); return false; } aReturnObject.set(&value.toObject()); return true; }
nsresult EventListenerManager::CompileEventHandlerInternal(Listener* aListener, const nsAString* aBody, Element* aElement) { MOZ_ASSERT(aListener->GetJSEventHandler()); MOZ_ASSERT(aListener->mHandlerIsString, "Why are we compiling a non-string JS listener?"); JSEventHandler* jsEventHandler = aListener->GetJSEventHandler(); MOZ_ASSERT(!jsEventHandler->GetTypedEventHandler().HasEventHandler(), "What is there to compile?"); nsresult result = NS_OK; nsCOMPtr<nsIDocument> doc; nsCOMPtr<nsIScriptGlobalObject> global = GetScriptGlobalAndDocument(getter_AddRefs(doc)); NS_ENSURE_STATE(global); // Activate JSAPI, and make sure that exceptions are reported on the right // Window. AutoJSAPI jsapi; if (NS_WARN_IF(!jsapi.Init(global))) { return NS_ERROR_UNEXPECTED; } jsapi.TakeOwnershipOfErrorReporting(); JSContext* cx = jsapi.cx(); nsCOMPtr<nsIAtom> typeAtom = aListener->mTypeAtom; nsIAtom* attrName = typeAtom; // Flag us as not a string so we don't keep trying to compile strings which // can't be compiled. aListener->mHandlerIsString = false; // mTarget may not be an Element if it's a window and we're // getting an inline event listener forwarded from <html:body> or // <html:frameset> or <xul:window> or the like. // XXX I don't like that we have to reference content from // here. The alternative is to store the event handler string on // the JSEventHandler itself, and that still doesn't address // the arg names issue. nsCOMPtr<Element> element = do_QueryInterface(mTarget); MOZ_ASSERT(element || aBody, "Where will we get our body?"); nsAutoString handlerBody; const nsAString* body = aBody; if (!aBody) { if (aListener->mTypeAtom == nsGkAtoms::onSVGLoad) { attrName = nsGkAtoms::onload; } else if (aListener->mTypeAtom == nsGkAtoms::onSVGUnload) { attrName = nsGkAtoms::onunload; } else if (aListener->mTypeAtom == nsGkAtoms::onSVGResize) { attrName = nsGkAtoms::onresize; } else if (aListener->mTypeAtom == nsGkAtoms::onSVGScroll) { attrName = nsGkAtoms::onscroll; } else if (aListener->mTypeAtom == nsGkAtoms::onSVGZoom) { attrName = nsGkAtoms::onzoom; } else if (aListener->mTypeAtom == nsGkAtoms::onbeginEvent) { attrName = nsGkAtoms::onbegin; } else if (aListener->mTypeAtom == nsGkAtoms::onrepeatEvent) { attrName = nsGkAtoms::onrepeat; } else if (aListener->mTypeAtom == nsGkAtoms::onendEvent) { attrName = nsGkAtoms::onend; } element->GetAttr(kNameSpaceID_None, attrName, handlerBody); body = &handlerBody; aElement = element; } aListener = nullptr; uint32_t lineNo = 0; nsAutoCString url (NS_LITERAL_CSTRING("-moz-evil:lying-event-listener")); MOZ_ASSERT(body); MOZ_ASSERT(aElement); nsIURI *uri = aElement->OwnerDoc()->GetDocumentURI(); if (uri) { uri->GetSpec(url); lineNo = 1; } nsCOMPtr<nsPIDOMWindow> win = do_QueryInterface(mTarget); uint32_t argCount; const char **argNames; nsContentUtils::GetEventArgNames(aElement->GetNameSpaceID(), typeAtom, win, &argCount, &argNames); JSAddonId *addonId = MapURIToAddonID(uri); // Wrap the event target, so that we can use it as the scope for the event // handler. Note that mTarget is different from aElement in the <body> case, // where mTarget is a Window. // // The wrapScope doesn't really matter here, because the target will create // its reflector in the proper scope, and then we'll enter that compartment. JS::Rooted<JSObject*> wrapScope(cx, global->GetGlobalJSObject()); JS::Rooted<JS::Value> v(cx); { JSAutoCompartment ac(cx, wrapScope); nsresult rv = nsContentUtils::WrapNative(cx, mTarget, &v, /* aAllowWrapping = */ false); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } } if (addonId) { JS::Rooted<JSObject*> vObj(cx, &v.toObject()); JS::Rooted<JSObject*> addonScope(cx, xpc::GetAddonScope(cx, vObj, addonId)); if (!addonScope) { return NS_ERROR_FAILURE; } JSAutoCompartment ac(cx, addonScope); // Wrap our event target into the addon scope, since that's where we want to // do all our work. if (!JS_WrapValue(cx, &v)) { return NS_ERROR_FAILURE; } } JS::Rooted<JSObject*> target(cx, &v.toObject()); JSAutoCompartment ac(cx, target); // Now that we've entered the compartment we actually care about, create our // scope chain. Note that we start with |element|, not aElement, because // mTarget is different from aElement in the <body> case, where mTarget is a // Window, and in that case we do not want the scope chain to include the body // or the document. JS::AutoObjectVector scopeChain(cx); if (!nsJSUtils::GetScopeChainForElement(cx, element, scopeChain)) { return NS_ERROR_OUT_OF_MEMORY; } nsDependentAtomString str(attrName); // Most of our names are short enough that we don't even have to malloc // the JS string stuff, so don't worry about playing games with // refcounting XPCOM stringbuffers. JS::Rooted<JSString*> jsStr(cx, JS_NewUCStringCopyN(cx, str.BeginReading(), str.Length())); NS_ENSURE_TRUE(jsStr, NS_ERROR_OUT_OF_MEMORY); // Get the reflector for |aElement|, so that we can pass to setElement. if (NS_WARN_IF(!GetOrCreateDOMReflector(cx, target, aElement, &v))) { return NS_ERROR_FAILURE; } JS::CompileOptions options(cx); options.setIntroductionType("eventHandler") .setFileAndLine(url.get(), lineNo) .setVersion(JSVERSION_DEFAULT) .setElement(&v.toObject()) .setElementAttributeName(jsStr); JS::Rooted<JSObject*> handler(cx); result = nsJSUtils::CompileFunction(jsapi, scopeChain, options, nsAtomCString(typeAtom), argCount, argNames, *body, handler.address()); NS_ENSURE_SUCCESS(result, result); NS_ENSURE_TRUE(handler, NS_ERROR_FAILURE); if (jsEventHandler->EventName() == nsGkAtoms::onerror && win) { nsRefPtr<OnErrorEventHandlerNonNull> handlerCallback = new OnErrorEventHandlerNonNull(handler, /* aIncumbentGlobal = */ nullptr); jsEventHandler->SetHandler(handlerCallback); } else if (jsEventHandler->EventName() == nsGkAtoms::onbeforeunload && win) { nsRefPtr<OnBeforeUnloadEventHandlerNonNull> handlerCallback = new OnBeforeUnloadEventHandlerNonNull(handler, /* aIncumbentGlobal = */ nullptr); jsEventHandler->SetHandler(handlerCallback); } else { nsRefPtr<EventHandlerNonNull> handlerCallback = new EventHandlerNonNull(handler, /* aIncumbentGlobal = */ nullptr); jsEventHandler->SetHandler(handlerCallback); } return result; }