already_AddRefed<Promise> MediaKeys::CreateSession(const nsAString& initDataType, const Uint8Array& aInitData, SessionType aSessionType, ErrorResult& aRv) { aInitData.ComputeLengthAndData(); nsRefPtr<Promise> promise(MakePromise(aRv)); if (aRv.Failed()) { return nullptr; } nsRefPtr<MediaKeySession> session = new MediaKeySession(GetParentObject(), this, mKeySystem, aSessionType, aRv); if (aRv.Failed()) { return nullptr; } auto pid = StorePromise(promise); // Hang onto session until the CDM has finished setting it up. mPendingSessions.Put(pid, session); mProxy->CreateSession(aSessionType, pid, initDataType, aInitData); return promise.forget(); }
already_AddRefed<DetailedPromise> MediaKeys::SetServerCertificate(const ArrayBufferViewOrArrayBuffer& aCert, ErrorResult& aRv) { RefPtr<DetailedPromise> promise(MakePromise(aRv, NS_LITERAL_CSTRING("MediaKeys.setServerCertificate"))); if (aRv.Failed()) { return nullptr; } if (!mProxy) { NS_WARNING("Tried to use a MediaKeys without a CDM"); promise->MaybeReject(NS_ERROR_DOM_INVALID_STATE_ERR, NS_LITERAL_CSTRING("Null CDM in MediaKeys.setServerCertificate()")); return promise.forget(); } nsTArray<uint8_t> data; CopyArrayBufferViewOrArrayBufferData(aCert, data); if (data.IsEmpty()) { promise->MaybeReject(NS_ERROR_DOM_TYPE_ERR, NS_LITERAL_CSTRING("Empty certificate passed to MediaKeys.setServerCertificate()")); return promise.forget(); } mProxy->SetServerCertificate(StorePromise(promise), data); return promise.forget(); }
already_AddRefed<Promise> MediaKeys::LoadSession(const nsAString& aSessionId, ErrorResult& aRv) { nsRefPtr<Promise> promise(MakePromise(aRv)); if (aRv.Failed()) { return nullptr; } if (aSessionId.IsEmpty()) { promise->MaybeReject(NS_ERROR_DOM_INVALID_ACCESS_ERR); // "The sessionId parameter is empty." return promise.forget(); } // TODO: The spec doesn't specify what to do in this case... if (mKeySessions.Contains(aSessionId)) { promise->MaybeReject(NS_ERROR_DOM_INVALID_ACCESS_ERR); return promise.forget(); } // Create session. nsRefPtr<MediaKeySession> session( new MediaKeySession(GetParentObject(), this, mKeySystem, SessionType::Persistent, aRv)); if (aRv.Failed()) { return nullptr; } session->Init(aSessionId); auto pid = StorePromise(promise); mPendingSessions.Put(pid, session); mProxy->LoadSession(pid, aSessionId); return promise.forget(); }
already_AddRefed<Promise> MediaKeys::SetServerCertificate(const ArrayBufferViewOrArrayBuffer& aCert, ErrorResult& aRv) { nsRefPtr<Promise> promise(MakePromise(aRv)); if (aRv.Failed()) { return nullptr; } nsTArray<uint8_t> data; if (!CopyArrayBufferViewOrArrayBufferData(aCert, data)) { promise->MaybeReject(NS_ERROR_DOM_INVALID_ACCESS_ERR); return promise.forget(); } mProxy->SetServerCertificate(StorePromise(promise), data); return promise.forget(); }
already_AddRefed<Promise> MediaKeys::Init(ErrorResult& aRv) { nsRefPtr<Promise> promise(MakePromise(aRv)); if (aRv.Failed()) { return nullptr; } mProxy = new CDMProxy(this, mKeySystem); // Determine principal (at creation time) of the MediaKeys object. nsCOMPtr<nsIScriptObjectPrincipal> sop = do_QueryInterface(GetParentObject()); if (!sop) { promise->MaybeReject(NS_ERROR_DOM_INVALID_STATE_ERR); return promise.forget(); } mPrincipal = sop->GetPrincipal(); // Determine principal of the "top-level" window; the principal of the // page that will display in the URL bar. nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(GetParentObject()); if (!window) { promise->MaybeReject(NS_ERROR_DOM_INVALID_STATE_ERR); return promise.forget(); } nsCOMPtr<nsIDOMWindow> topWindow; window->GetTop(getter_AddRefs(topWindow)); nsCOMPtr<nsPIDOMWindow> top = do_QueryInterface(topWindow); if (!top || !top->GetExtantDoc()) { promise->MaybeReject(NS_ERROR_DOM_INVALID_STATE_ERR); return promise.forget(); } mTopLevelPrincipal = top->GetExtantDoc()->NodePrincipal(); if (!mPrincipal || !mTopLevelPrincipal) { NS_WARNING("Failed to get principals when creating MediaKeys"); promise->MaybeReject(NS_ERROR_DOM_INVALID_STATE_ERR); return promise.forget(); } nsAutoString origin; nsresult rv = nsContentUtils::GetUTFOrigin(mPrincipal, origin); if (NS_FAILED(rv)) { promise->MaybeReject(NS_ERROR_DOM_INVALID_STATE_ERR); return promise.forget(); } nsAutoString topLevelOrigin; rv = nsContentUtils::GetUTFOrigin(mTopLevelPrincipal, topLevelOrigin); if (NS_FAILED(rv)) { promise->MaybeReject(NS_ERROR_DOM_INVALID_STATE_ERR); return promise.forget(); } if (!window) { promise->MaybeReject(NS_ERROR_DOM_INVALID_STATE_ERR); return promise.forget(); } nsIDocument* doc = window->GetExtantDoc(); const bool inPrivateBrowsing = nsContentUtils::IsInPrivateBrowsing(doc); EME_LOG("MediaKeys::Create() (%s, %s), %s", NS_ConvertUTF16toUTF8(origin).get(), NS_ConvertUTF16toUTF8(topLevelOrigin).get(), (inPrivateBrowsing ? "PrivateBrowsing" : "NonPrivateBrowsing")); // The CDMProxy's initialization is asynchronous. The MediaKeys is // refcounted, and its instance is returned to JS by promise once // it's been initialized. No external refs exist to the MediaKeys while // we're waiting for the promise to be resolved, so we must hold a // reference to the new MediaKeys object until it's been created, // or its creation has failed. Store the id of the promise returned // here, and hold a self-reference until that promise is resolved or // rejected. MOZ_ASSERT(!mCreatePromiseId, "Should only be created once!"); mCreatePromiseId = StorePromise(promise); AddRef(); mProxy->Init(mCreatePromiseId, origin, topLevelOrigin, inPrivateBrowsing); return promise.forget(); }