already_AddRefed<Promise> MediaKeySession::GenerateRequest(const nsAString& aInitDataType, const ArrayBufferViewOrArrayBuffer& aInitData, ErrorResult& aRv) { RefPtr<DetailedPromise> promise(MakePromise(aRv, NS_LITERAL_CSTRING("MediaKeySession.generateRequest"))); if (aRv.Failed()) { return nullptr; } if (!mUninitialized) { EME_LOG("MediaKeySession[%p,'%s'] GenerateRequest() failed, uninitialized", this, NS_ConvertUTF16toUTF8(mSessionId).get()); promise->MaybeReject(NS_ERROR_DOM_INVALID_ACCESS_ERR, NS_LITERAL_CSTRING("Session is already initialized in MediaKeySession.generateRequest()")); return promise.forget(); } mUninitialized = false; if (aInitDataType.IsEmpty()) { promise->MaybeReject(NS_ERROR_DOM_TYPE_ERR, NS_LITERAL_CSTRING("Empty initDataType passed to MediaKeySession.generateRequest()")); EME_LOG("MediaKeySession[%p,'%s'] GenerateRequest() failed, empty initDataType", this, NS_ConvertUTF16toUTF8(mSessionId).get()); return promise.forget(); } nsTArray<uint8_t> data; CopyArrayBufferViewOrArrayBufferData(aInitData, data); if (data.IsEmpty()) { promise->MaybeReject(NS_ERROR_DOM_TYPE_ERR, NS_LITERAL_CSTRING("Empty initData passed to MediaKeySession.generateRequest()")); EME_LOG("MediaKeySession[%p,'%s'] GenerateRequest() failed, empty initData", this, NS_ConvertUTF16toUTF8(mSessionId).get()); return promise.forget(); } // Convert initData to base64 for easier logging. // Note: CreateSession() Move()s the data out of the array, so we have // to copy it here. nsAutoCString base64InitData(ToBase64(data)); PromiseId pid = mKeys->StorePromise(promise); mKeys->GetCDMProxy()->CreateSession(Token(), mSessionType, pid, aInitDataType, data); EME_LOG("MediaKeySession[%p,'%s'] GenerateRequest() sent, " "promiseId=%d initData(base64)='%s' initDataType='%s'", this, NS_ConvertUTF16toUTF8(mSessionId).get(), pid, base64InitData.get(), NS_ConvertUTF16toUTF8(aInitDataType).get()); return promise.forget(); }
// Generates a license request based on the initData. A message of type // "license-request" or "individualization-request" will always be queued // if the algorithm succeeds and the promise is resolved. already_AddRefed<Promise> MediaKeySession::GenerateRequest(const nsAString& aInitDataType, const ArrayBufferViewOrArrayBuffer& aInitData, ErrorResult& aRv) { RefPtr<DetailedPromise> promise(MakePromise(aRv, NS_LITERAL_CSTRING("MediaKeySession.generateRequest"))); if (aRv.Failed()) { return nullptr; } // If this object is closed, return a promise rejected with an InvalidStateError. if (IsClosed()) { EME_LOG("MediaKeySession[%p,'%s'] GenerateRequest() failed, closed", this, NS_ConvertUTF16toUTF8(mSessionId).get()); promise->MaybeReject(NS_ERROR_DOM_INVALID_STATE_ERR, NS_LITERAL_CSTRING("Session is closed in MediaKeySession.generateRequest()")); return promise.forget(); } // If this object's uninitialized value is false, return a promise rejected // with an InvalidStateError. if (!mUninitialized) { EME_LOG("MediaKeySession[%p,'%s'] GenerateRequest() failed, uninitialized", this, NS_ConvertUTF16toUTF8(mSessionId).get()); promise->MaybeReject(NS_ERROR_DOM_INVALID_STATE_ERR, NS_LITERAL_CSTRING("Session is already initialized in MediaKeySession.generateRequest()")); return promise.forget(); } // Let this object's uninitialized value be false. mUninitialized = false; // If initDataType is the empty string, return a promise rejected // with a newly created TypeError. if (aInitDataType.IsEmpty()) { promise->MaybeReject(NS_ERROR_DOM_TYPE_ERR, NS_LITERAL_CSTRING("Empty initDataType passed to MediaKeySession.generateRequest()")); EME_LOG("MediaKeySession[%p,'%s'] GenerateRequest() failed, empty initDataType", this, NS_ConvertUTF16toUTF8(mSessionId).get()); return promise.forget(); } // If initData is an empty array, return a promise rejected with // a newly created TypeError. nsTArray<uint8_t> data; CopyArrayBufferViewOrArrayBufferData(aInitData, data); if (data.IsEmpty()) { promise->MaybeReject(NS_ERROR_DOM_TYPE_ERR, NS_LITERAL_CSTRING("Empty initData passed to MediaKeySession.generateRequest()")); EME_LOG("MediaKeySession[%p,'%s'] GenerateRequest() failed, empty initData", this, NS_ConvertUTF16toUTF8(mSessionId).get()); return promise.forget(); } // If the Key System implementation represented by this object's // cdm implementation value does not support initDataType as an // Initialization Data Type, return a promise rejected with a // NotSupportedError. String comparison is case-sensitive. if (!MediaKeySystemAccess::KeySystemSupportsInitDataType(mKeySystem, aInitDataType)) { promise->MaybeReject(NS_ERROR_DOM_NOT_SUPPORTED_ERR, NS_LITERAL_CSTRING("Unsupported initDataType passed to MediaKeySession.generateRequest()")); EME_LOG("MediaKeySession[%p,'%s'] GenerateRequest() failed, unsupported initDataType", this, NS_ConvertUTF16toUTF8(mSessionId).get()); return promise.forget(); } // Let init data be a copy of the contents of the initData parameter. // Note: Handled by the CopyArrayBufferViewOrArrayBufferData call above. // Let session type be this object's session type. // Let promise be a new promise. // Run the following steps in parallel: // If the init data is not valid for initDataType, reject promise with // a newly created TypeError. if (!ValidateInitData(data, aInitDataType)) { // If the preceding step failed, reject promise with a newly created TypeError. promise->MaybeReject(NS_ERROR_DOM_TYPE_ERR, NS_LITERAL_CSTRING("initData sanitization failed in MediaKeySession.generateRequest()")); EME_LOG("MediaKeySession[%p,'%s'] GenerateRequest() initData sanitization failed", this, NS_ConvertUTF16toUTF8(mSessionId).get()); return promise.forget(); } // Let sanitized init data be a validated and sanitized version of init data. // If sanitized init data is empty, reject promise with a NotSupportedError. // Note: Remaining steps of generateRequest method continue in CDM. Telemetry::Accumulate(Telemetry::VIDEO_CDM_GENERATE_REQUEST_CALLED, ToCDMTypeTelemetryEnum(mKeySystem)); // Convert initData to base64 for easier logging. // Note: CreateSession() Move()s the data out of the array, so we have // to copy it here. nsAutoCString base64InitData(ToBase64(data)); PromiseId pid = mKeys->StorePromise(promise); mKeys->ConnectPendingPromiseIdWithToken(pid, Token()); mKeys->GetCDMProxy()->CreateSession(Token(), mSessionType, pid, aInitDataType, data); EME_LOG("MediaKeySession[%p,'%s'] GenerateRequest() sent, " "promiseId=%d initData(base64)='%s' initDataType='%s'", this, NS_ConvertUTF16toUTF8(mSessionId).get(), pid, base64InitData.get(), NS_ConvertUTF16toUTF8(aInitDataType).get()); return promise.forget(); }