summaryrefslogtreecommitdiff
path: root/Source/WebCore/testing/MockCDMFactory.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Source/WebCore/testing/MockCDMFactory.cpp')
-rw-r--r--Source/WebCore/testing/MockCDMFactory.cpp382
1 files changed, 382 insertions, 0 deletions
diff --git a/Source/WebCore/testing/MockCDMFactory.cpp b/Source/WebCore/testing/MockCDMFactory.cpp
new file mode 100644
index 000000000..f3b4a47e6
--- /dev/null
+++ b/Source/WebCore/testing/MockCDMFactory.cpp
@@ -0,0 +1,382 @@
+/*
+ * Copyright (C) 2016 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "MockCDMFactory.h"
+
+#if ENABLE(ENCRYPTED_MEDIA)
+
+#include "InitDataRegistry.h"
+#include "UUID.h"
+#include <runtime/ArrayBuffer.h>
+#include <wtf/text/StringHash.h>
+#include <wtf/text/StringView.h>
+
+namespace WebCore {
+
+MockCDMFactory::MockCDMFactory()
+ : m_supportedSessionTypes({ MediaKeySessionType::Temporary, MediaKeySessionType::PersistentUsageRecord, MediaKeySessionType::PersistentLicense })
+ , m_weakPtrFactory(this)
+{
+ CDM::registerCDMFactory(*this);
+}
+
+MockCDMFactory::~MockCDMFactory()
+{
+ unregister();
+}
+
+void MockCDMFactory::unregister()
+{
+ if (m_registered) {
+ CDM::unregisterCDMFactory(*this);
+ m_registered = false;
+ }
+}
+
+bool MockCDMFactory::supportsKeySystem(const String& keySystem)
+{
+ return equalIgnoringASCIICase(keySystem, "org.webkit.mock");
+}
+
+void MockCDMFactory::addKeysToSessionWithID(const String& id, Vector<Ref<SharedBuffer>>&& keys)
+{
+ auto addResult = m_sessions.add(id, WTFMove(keys));
+ if (addResult.isNewEntry)
+ return;
+
+ auto& value = addResult.iterator->value;
+ for (auto& key : keys)
+ value.append(WTFMove(key));
+}
+
+Vector<Ref<SharedBuffer>> MockCDMFactory::removeKeysFromSessionWithID(const String& id)
+{
+ auto it = m_sessions.find(id);
+ if (it == m_sessions.end())
+ return { };
+
+ return WTFMove(it->value);
+}
+
+std::optional<const Vector<Ref<SharedBuffer>>&> MockCDMFactory::keysForSessionWithID(const String& id) const
+{
+ auto it = m_sessions.find(id);
+ if (it == m_sessions.end())
+ return std::nullopt;
+ return it->value;
+}
+
+void MockCDMFactory::setSupportedDataTypes(Vector<String>&& types)
+{
+ m_supportedDataTypes.clear();
+ for (auto& type : types)
+ m_supportedDataTypes.append(type);
+}
+
+std::unique_ptr<CDMPrivate> MockCDMFactory::createCDM(CDM&)
+{
+ return std::make_unique<MockCDM>(m_weakPtrFactory.createWeakPtr());
+}
+
+MockCDM::MockCDM(WeakPtr<MockCDMFactory> factory)
+ : m_factory(WTFMove(factory))
+ , m_weakPtrFactory(this)
+{
+}
+
+bool MockCDM::supportsInitDataType(const AtomicString& initDataType) const
+{
+ if (m_factory)
+ return m_factory->supportedDataTypes().contains(initDataType);
+ return false;
+}
+
+bool MockCDM::supportsConfiguration(const MediaKeySystemConfiguration&) const
+{
+ // NOTE: Implement;
+ return true;
+
+}
+
+bool MockCDM::supportsConfigurationWithRestrictions(const MediaKeySystemConfiguration&, const MediaKeysRestrictions&) const
+{
+ // NOTE: Implement;
+ return true;
+}
+
+bool MockCDM::supportsSessionTypeWithConfiguration(MediaKeySessionType& sessionType, const MediaKeySystemConfiguration&) const
+{
+ if (!m_factory || !m_factory->supportedSessionTypes().contains(sessionType))
+ return false;
+
+ // NOTE: Implement configuration checking;
+ return true;
+}
+
+bool MockCDM::supportsRobustness(const String& robustness) const
+{
+ if (m_factory)
+ return m_factory->supportedRobustness().contains(robustness);
+ return false;
+}
+
+MediaKeysRequirement MockCDM::distinctiveIdentifiersRequirement(const MediaKeySystemConfiguration&, const MediaKeysRestrictions&) const
+{
+ if (m_factory)
+ return m_factory->distinctiveIdentifiersRequirement();
+ return MediaKeysRequirement::Optional;
+}
+
+MediaKeysRequirement MockCDM::persistentStateRequirement(const MediaKeySystemConfiguration&, const MediaKeysRestrictions&) const
+{
+ if (m_factory)
+ return m_factory->persistentStateRequirement();
+ return MediaKeysRequirement::Optional;
+}
+
+bool MockCDM::distinctiveIdentifiersAreUniquePerOriginAndClearable(const MediaKeySystemConfiguration&) const
+{
+ // NOTE: Implement;
+ return true;
+}
+
+RefPtr<CDMInstance> MockCDM::createInstance()
+{
+ if (m_factory && !m_factory->canCreateInstances())
+ return nullptr;
+ return adoptRef(new MockCDMInstance(m_weakPtrFactory.createWeakPtr()));
+}
+
+void MockCDM::loadAndInitialize()
+{
+ // No-op.
+}
+
+bool MockCDM::supportsServerCertificates() const
+{
+ return m_factory && m_factory->supportsServerCertificates();
+}
+
+bool MockCDM::supportsSessions() const
+{
+ return m_factory && m_factory->supportsSessions();
+}
+
+bool MockCDM::supportsInitData(const AtomicString& initDataType, const SharedBuffer& initData) const
+{
+ if (!supportsInitDataType(initDataType))
+ return false;
+
+ UNUSED_PARAM(initData);
+ return true;
+}
+
+RefPtr<SharedBuffer> MockCDM::sanitizeResponse(const SharedBuffer& response) const
+{
+ if (!charactersAreAllASCII(reinterpret_cast<const LChar*>(response.data()), response.size()))
+ return nullptr;
+
+ Vector<String> responseArray;
+ String(response.data(), response.size()).split(ASCIILiteral(" "), responseArray);
+
+ if (!responseArray.contains(String(ASCIILiteral("valid-response"))))
+ return nullptr;
+
+ return response.copy();
+}
+
+std::optional<String> MockCDM::sanitizeSessionId(const String& sessionId) const
+{
+ if (equalLettersIgnoringASCIICase(sessionId, "valid-loaded-session"))
+ return sessionId;
+ return std::nullopt;
+}
+
+MockCDMInstance::MockCDMInstance(WeakPtr<MockCDM> cdm)
+ : m_cdm(cdm)
+{
+}
+
+CDMInstance::SuccessValue MockCDMInstance::initializeWithConfiguration(const MediaKeySystemConfiguration& configuration)
+{
+ if (!m_cdm || !m_cdm->supportsConfiguration(configuration))
+ return Failed;
+
+ return Succeeded;
+}
+
+CDMInstance::SuccessValue MockCDMInstance::setDistinctiveIdentifiersAllowed(bool distinctiveIdentifiersAllowed)
+{
+ if (m_distinctiveIdentifiersAllowed == distinctiveIdentifiersAllowed)
+ return Succeeded;
+
+ auto* factory = m_cdm ? m_cdm->factory() : nullptr;
+
+ if (!factory || (!distinctiveIdentifiersAllowed && factory->distinctiveIdentifiersRequirement() == MediaKeysRequirement::Required))
+ return Failed;
+
+ m_distinctiveIdentifiersAllowed = distinctiveIdentifiersAllowed;
+ return Succeeded;
+}
+
+CDMInstance::SuccessValue MockCDMInstance::setPersistentStateAllowed(bool persistentStateAllowed)
+{
+ if (m_persistentStateAllowed == persistentStateAllowed)
+ return Succeeded;
+
+ MockCDMFactory* factory = m_cdm ? m_cdm->factory() : nullptr;
+
+ if (!factory || (!persistentStateAllowed && factory->persistentStateRequirement() == MediaKeysRequirement::Required))
+ return Failed;
+
+ m_persistentStateAllowed = persistentStateAllowed;
+ return Succeeded;
+}
+
+CDMInstance::SuccessValue MockCDMInstance::setServerCertificate(Ref<SharedBuffer>&& certificate)
+{
+ StringView certificateStringView(reinterpret_cast<const LChar*>(certificate->data()), certificate->size());
+
+ if (equalIgnoringASCIICase(certificateStringView, "valid"))
+ return Succeeded;
+ return Failed;
+}
+
+void MockCDMInstance::requestLicense(LicenseType licenseType, const AtomicString& initDataType, Ref<SharedBuffer>&& initData, LicenseCallback callback)
+{
+ MockCDMFactory* factory = m_cdm ? m_cdm->factory() : nullptr;
+ if (!factory) {
+ callback(SharedBuffer::create(), emptyAtom, false, SuccessValue::Failed);
+ return;
+ }
+
+ if (!factory->supportedSessionTypes().contains(licenseType) || !factory->supportedDataTypes().contains(initDataType)) {
+ callback(SharedBuffer::create(), emptyString(), false, SuccessValue::Failed);
+ return;
+ }
+
+ auto keyIDs = InitDataRegistry::shared().extractKeyIDs(initDataType, initData);
+ if (keyIDs.isEmpty()) {
+ callback(SharedBuffer::create(), emptyString(), false, SuccessValue::Failed);
+ return;
+ }
+
+ String sessionID = createCanonicalUUIDString();
+ factory->addKeysToSessionWithID(sessionID, WTFMove(keyIDs));
+
+ CString license { "license" };
+ callback(SharedBuffer::create(license.data(), license.length()), sessionID, false, SuccessValue::Succeeded);
+}
+
+void MockCDMInstance::updateLicense(const String& sessionID, LicenseType, const SharedBuffer& response, LicenseUpdateCallback callback)
+{
+ MockCDMFactory* factory = m_cdm ? m_cdm->factory() : nullptr;
+ if (!factory) {
+ callback(false, std::nullopt, std::nullopt, std::nullopt, SuccessValue::Failed);
+ return;
+ }
+
+ Vector<String> responseVector;
+ String(response.data(), response.size()).split(ASCIILiteral(" "), responseVector);
+
+ if (responseVector.contains(String(ASCIILiteral("invalid-format")))) {
+ callback(false, std::nullopt, std::nullopt, std::nullopt, SuccessValue::Failed);
+ return;
+ }
+
+ std::optional<KeyStatusVector> changedKeys;
+ if (responseVector.contains(String(ASCIILiteral("keys-changed")))) {
+ std::optional<const Vector<Ref<SharedBuffer>>&> keys = factory->keysForSessionWithID(sessionID);
+ if (keys) {
+ KeyStatusVector keyStatusVector;
+ keyStatusVector.reserveInitialCapacity(keys->size());
+ for (auto& key : *keys)
+ keyStatusVector.uncheckedAppend({ key.copyRef(), KeyStatus::Usable });
+
+ changedKeys = WTFMove(keyStatusVector);
+ }
+ }
+
+ // FIXME: Session closure, expiration and message handling should be implemented
+ // once the relevant algorithms are supported.
+
+ callback(false, WTFMove(changedKeys), std::nullopt, std::nullopt, SuccessValue::Succeeded);
+}
+
+void MockCDMInstance::loadSession(LicenseType, const String&, const String&, LoadSessionCallback callback)
+{
+ MockCDMFactory* factory = m_cdm ? m_cdm->factory() : nullptr;
+ if (!factory) {
+ callback(std::nullopt, std::nullopt, std::nullopt, SuccessValue::Failed, SessionLoadFailure::Other);
+ return;
+ }
+
+ // FIXME: Key status and expiration handling should be implemented once the relevant algorithms are supported.
+
+ CString messageData { "session loaded" };
+ Message message { MessageType::LicenseRenewal, SharedBuffer::create(messageData.data(), messageData.length()) };
+
+ callback(std::nullopt, std::nullopt, WTFMove(message), SuccessValue::Succeeded, SessionLoadFailure::None);
+}
+
+void MockCDMInstance::closeSession(const String& sessionID, CloseSessionCallback callback)
+{
+ MockCDMFactory* factory = m_cdm ? m_cdm->factory() : nullptr;
+ if (!factory) {
+ callback();
+ return;
+ }
+
+ factory->removeSessionWithID(sessionID);
+ callback();
+}
+
+void MockCDMInstance::removeSessionData(const String& id, LicenseType, RemoveSessionDataCallback callback)
+{
+ MockCDMFactory* factory = m_cdm ? m_cdm->factory() : nullptr;
+ if (!factory) {
+ callback({ }, std::nullopt, SuccessValue::Failed);
+ return;
+ }
+
+ auto keys = factory->removeKeysFromSessionWithID(id);
+ KeyStatusVector keyStatusVector;
+ keyStatusVector.reserveInitialCapacity(keys.size());
+ for (auto& key : keys)
+ keyStatusVector.uncheckedAppend({ WTFMove(key), KeyStatus::Released });
+
+ CString message { "remove-message" };
+ callback(WTFMove(keyStatusVector), SharedBuffer::create(message.data(), message.length()), SuccessValue::Succeeded);
+}
+
+void MockCDMInstance::storeRecordOfKeyUsage(const String&)
+{
+ // FIXME: This should be implemented along with the support for persistent-usage-record sessions.
+}
+
+}
+
+#endif