Bug 1111787 - Part 1: Delete the directory for the origin pair when "forget this site" is invoked. r=cpearce

This commit is contained in:
JW Wang 2015-01-05 19:00:00 -05:00
Родитель 70996c375b
Коммит ea65e9fd34
4 изменённых файлов: 137 добавлений и 36 удалений

Просмотреть файл

@ -32,6 +32,7 @@
#include "nsDirectoryServiceDefs.h"
#include "nsHashKeys.h"
#include "nsIFile.h"
#include "nsISimpleEnumerator.h"
namespace mozilla {
@ -63,6 +64,7 @@ GetGMPLog()
namespace gmp {
static const uint32_t NodeIdSaltLength = 32;
static StaticRefPtr<GeckoMediaPluginService> sSingletonService;
class GMPServiceCreateHelper MOZ_FINAL : public nsRunnable
@ -323,16 +325,23 @@ GeckoMediaPluginService::Observe(nsISupports* aSubject,
// open a PB mode origin-pair, we'll re-generate new salt.
mTempNodeIds.Clear();
} else if (!strcmp("gmp-clear-storage", aTopic)) {
nsresult rv = GMPDispatch(
NS_NewRunnableMethod(this, &GeckoMediaPluginService::ClearStorage));
NS_ENSURE_SUCCESS(rv, rv);
}
return NS_OK;
}
nsresult
GeckoMediaPluginService::GMPDispatch(nsIRunnable* event, uint32_t flags)
{
nsCOMPtr<nsIRunnable> r(event);
nsCOMPtr<nsIThread> thread;
nsresult rv = GetThread(getter_AddRefs(thread));
if (NS_FAILED(rv)) {
return rv;
}
thread->Dispatch(
NS_NewRunnableMethod(this, &GeckoMediaPluginService::ClearStorage),
NS_DISPATCH_NORMAL);
}
return NS_OK;
return thread->Dispatch(r, flags);
}
// always call with getter_AddRefs, because it does
@ -631,28 +640,14 @@ NS_IMETHODIMP
GeckoMediaPluginService::AddPluginDirectory(const nsAString& aDirectory)
{
MOZ_ASSERT(NS_IsMainThread());
nsCOMPtr<nsIThread> thread;
nsresult rv = GetThread(getter_AddRefs(thread));
if (NS_FAILED(rv)) {
return rv;
}
nsCOMPtr<nsIRunnable> r = new PathRunnable(this, aDirectory, true);
thread->Dispatch(r, NS_DISPATCH_NORMAL);
return NS_OK;
return GMPDispatch(new PathRunnable(this, aDirectory, true));
}
NS_IMETHODIMP
GeckoMediaPluginService::RemovePluginDirectory(const nsAString& aDirectory)
{
MOZ_ASSERT(NS_IsMainThread());
nsCOMPtr<nsIThread> thread;
nsresult rv = GetThread(getter_AddRefs(thread));
if (NS_FAILED(rv)) {
return rv;
}
nsCOMPtr<nsIRunnable> r = new PathRunnable(this, aDirectory, false);
thread->Dispatch(r, NS_DISPATCH_NORMAL);
return NS_OK;
return GMPDispatch(new PathRunnable(this, aDirectory, false));
}
class DummyRunnable : public nsRunnable {
@ -676,12 +671,8 @@ GeckoMediaPluginService::HasPluginForAPI(const nsACString& aAPI,
// cause an event to be dispatched to which scans for plugins. We
// dispatch a sync event to the GMP thread here in order to wait until
// after the GMP thread has scanned any paths in MOZ_GMP_PATH.
nsCOMPtr<nsIThread> thread;
nsresult rv = GetThread(getter_AddRefs(thread));
if (NS_FAILED(rv)) {
return rv;
}
thread->Dispatch(new DummyRunnable(), NS_DISPATCH_SYNC);
nsresult rv = GMPDispatch(new DummyRunnable(), NS_DISPATCH_SYNC);
NS_ENSURE_SUCCESS(rv, rv);
MOZ_ASSERT(mScannedPluginOnDisk, "Should have scanned MOZ_GMP_PATH by now");
}
@ -979,6 +970,14 @@ ReadFromFile(nsIFile* aPath,
return NS_OK;
}
static nsresult
ReadSalt(nsIFile* aPath, nsCString& aOutData)
{
return ReadFromFile(aPath, NS_LITERAL_CSTRING("salt"),
aOutData, NodeIdSaltLength);
}
NS_IMETHODIMP
GeckoMediaPluginService::IsPersistentStorageAllowed(const nsACString& aNodeId,
bool* aOutAllowed)
@ -1007,7 +1006,6 @@ GeckoMediaPluginService::GetNodeId(const nsAString& aOrigin,
#endif
nsresult rv;
const uint32_t NodeIdSaltLength = 32;
if (aOrigin.EqualsLiteral("null") ||
aOrigin.IsEmpty() ||
@ -1131,10 +1129,7 @@ GeckoMediaPluginService::GetNodeId(const nsAString& aOrigin,
}
} else {
rv = ReadFromFile(path,
NS_LITERAL_CSTRING("salt"),
salt,
NodeIdSaltLength);
rv = ReadSalt(path, salt);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
@ -1146,6 +1141,97 @@ GeckoMediaPluginService::GetNodeId(const nsAString& aOrigin,
return NS_OK;
}
static bool
MatchOrigin(nsIFile* aPath, const nsACString& aMatch)
{
// http://en.wikipedia.org/wiki/Domain_Name_System#Domain_name_syntax
static const uint32_t MaxDomainLength = 253;
nsresult rv;
nsCString str;
rv = ReadFromFile(aPath, NS_LITERAL_CSTRING("origin"), str, MaxDomainLength);
if (NS_SUCCEEDED(rv) && aMatch.Equals(str)) {
return true;
}
rv = ReadFromFile(aPath, NS_LITERAL_CSTRING("topLevelOrigin"), str, MaxDomainLength);
if (NS_SUCCEEDED(rv) && aMatch.Equals(str)) {
return true;
}
return false;
}
void
GeckoMediaPluginService::ForgetThisSiteOnGMPThread(const nsACString& aOrigin)
{
#define ERR_RET(x) NS_ENSURE_SUCCESS_VOID(x)
#define ERR_CONT(x) if (NS_FAILED(x)) { continue; }
MOZ_ASSERT(NS_GetCurrentThread() == mGMPThread);
LOGD(("%s::%s: origin=%s", __CLASS__, __FUNCTION__, aOrigin.Data()));
nsresult rv;
nsCOMPtr<nsIFile> path;
// $profileDir/gmp/
ERR_RET(GetStorageDir(getter_AddRefs(path)));
// $profileDir/gmp/id/
ERR_RET(path->AppendNative(NS_LITERAL_CSTRING("id")));
// Iterate all sub-folders of $profileDir/gmp/id/
nsCOMPtr<nsISimpleEnumerator> iter;
ERR_RET(path->GetDirectoryEntries(getter_AddRefs(iter)));
bool hasMore = false;
nsTArray<nsCString> nodeIDsToClear;
while (NS_SUCCEEDED(iter->HasMoreElements(&hasMore)) && hasMore) {
nsCOMPtr<nsISupports> supports;
ERR_CONT(iter->GetNext(getter_AddRefs(supports)));
// $profileDir/gmp/id/$hash
nsCOMPtr<nsIFile> dirEntry(do_QueryInterface(supports, &rv));
ERR_CONT(rv);
// Skip non-directory files.
bool isDirectory = false;
ERR_CONT(dirEntry->IsDirectory(&isDirectory));
if (!isDirectory) {
continue;
}
// Check if origin or topLevelOrigin match the origin being forgotten.
if (!MatchOrigin(dirEntry, aOrigin)) {
continue;
}
// Keep node IDs to clear data/plugins associated with them later.
nsAutoCString salt;
if (NS_SUCCEEDED(ReadSalt(dirEntry, salt))) {
nodeIDsToClear.AppendElement(salt);
}
// Now we can remove the directory for the origin pair.
if (NS_FAILED(dirEntry->Remove(true))) {
NS_WARNING("Failed to delete the directory for the origin pair");
}
}
// TODO: Clear plugins/data associated with the node IDs in nodeIDsToClear
// in next patch.
nodeIDsToClear.Clear();
#undef ERR_RET
#undef ERR_CONT
}
NS_IMETHODIMP
GeckoMediaPluginService::ForgetThisSite(const nsAString& aOrigin)
{
MOZ_ASSERT(NS_IsMainThread());
return GMPDispatch(NS_NewRunnableMethodWithArg<nsCString>(
this, &GeckoMediaPluginService::ForgetThisSiteOnGMPThread,
NS_ConvertUTF16toUTF8(aOrigin)));
}
class StorageClearedTask : public nsRunnable {
public:
NS_IMETHOD Run() {

Просмотреть файл

@ -52,6 +52,8 @@ public:
private:
~GeckoMediaPluginService();
nsresult GMPDispatch(nsIRunnable* event, uint32_t flags = NS_DISPATCH_NORMAL);
void ClearStorage();
GMPParent* SelectPluginForAPI(const nsACString& aNodeId,
@ -74,6 +76,8 @@ private:
nsresult SetAsyncShutdownTimeout();
void ForgetThisSiteOnGMPThread(const nsACString& aOrigin);
protected:
friend class GMPParent;
void ReAddOnGMPThread(nsRefPtr<GMPParent>& aOld);

Просмотреть файл

@ -26,7 +26,7 @@ class GMPVideoHost;
[ptr] native GMPDecryptorProxy(GMPDecryptorProxy);
[ptr] native GMPAudioDecoderProxy(GMPAudioDecoderProxy);
[scriptable, uuid(657443a4-6b5d-4181-98b0-56997b35bd57)]
[scriptable, uuid(4aaf58d3-181f-4325-9a2f-41172d995a70)]
interface mozIGeckoMediaPluginService : nsISupports
{
@ -96,6 +96,11 @@ interface mozIGeckoMediaPluginService : nsISupports
in AString topLevelOrigin,
in bool inPrivateBrowsingMode);
/**
* Clears storage data associated with the origin.
*/
void forgetThisSite(in AString origin);
/**
* Returns true if the given node id is allowed to store things
* persistently on disk. Private Browsing and local content are not

Просмотреть файл

@ -80,6 +80,12 @@ this.ForgetAboutSite = {
cm.remove(cookie.host, cookie.name, cookie.path, false);
}
// EME
let (mps = Cc["@mozilla.org/gecko-media-plugin-service;1"].
getService(Ci.mozIGeckoMediaPluginService)) {
mps.forgetThisSite(aDomain);
}
// Plugin data
const phInterface = Ci.nsIPluginHost;
const FLAG_CLEAR_ALL = phInterface.FLAG_CLEAR_ALL;