Bug 1626076 - Make it possible to use DataStorage on socket process r=keeler,dragana,necko-reviewers

Differential Revision: https://phabricator.services.mozilla.com/D68877
This commit is contained in:
Kershaw Chang 2020-04-20 09:41:58 +00:00
Родитель 2550d855b2
Коммит 85532d60f8
11 изменённых файлов: 253 добавлений и 53 удалений

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

@ -65,6 +65,7 @@ include ClientIPCTypes;
include HangTypes;
include PrefsTypes;
include NeckoChannelParams;
include PSMIPCTypes;
#if defined(MOZ_SANDBOX) && defined(MOZ_DEBUG) && defined(ENABLE_TESTS)
include protocol PSandboxTesting;
@ -89,7 +90,6 @@ using mozilla::LayoutDeviceIntPoint from "Units.h";
using struct LookAndFeelInt from "mozilla/widget/WidgetMessageUtils.h";
using class mozilla::dom::MessagePort from "mozilla/dom/MessagePort.h";
using class mozilla::dom::ipc::StructuredCloneData from "mozilla/dom/ipc/StructuredCloneData.h";
using mozilla::DataStorageType from "ipc/DataStorageIPCUtils.h";
using mozilla::OriginAttributes from "mozilla/ipc/BackgroundUtils.h";
using struct mozilla::layers::TextureFactoryIdentifier from "mozilla/layers/CompositorTypes.h";
using mozilla::layers::CompositorOptions from "mozilla/layers/CompositorOptions.h";
@ -169,17 +169,6 @@ struct SystemFontListEntry {
};
#endif
struct DataStorageItem {
nsCString key;
nsCString value;
DataStorageType type;
};
struct DataStorageEntry {
DataStorageItem[] items;
nsString filename;
};
struct ClipboardCapabilities {
bool supportsSelectionClipboard;
bool supportsFindClipboard;

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

@ -35,3 +35,5 @@ with Files('**'):
BUG_COMPONENT = ('Core', 'Networking')
include('/tools/fuzzing/libfuzzer-config.mozbuild')
include('/ipc/chromium/chromium-config.mozbuild')

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

@ -703,6 +703,29 @@ nsFileOutputStream::Init(nsIFile* file, int32_t ioFlags, int32_t perm,
mBehaviorFlags & nsIFileOutputStream::DEFER_OPEN);
}
nsresult nsFileOutputStream::InitWithFileDescriptor(
const mozilla::ipc::FileDescriptor& aFd) {
NS_ENSURE_TRUE(mFD == nullptr, NS_ERROR_ALREADY_INITIALIZED);
NS_ENSURE_TRUE(mState == eUnitialized || mState == eClosed,
NS_ERROR_ALREADY_INITIALIZED);
if (aFd.IsValid()) {
auto rawFD = aFd.ClonePlatformHandle();
PRFileDesc* fileDesc = PR_ImportFile(PROsfd(rawFD.release()));
if (!fileDesc) {
NS_WARNING("Failed to import file handle!");
return NS_ERROR_FAILURE;
}
mFD = fileDesc;
mState = eOpened;
} else {
mState = eError;
mErrorValue = NS_ERROR_FILE_NOT_FOUND;
}
return NS_OK;
}
NS_IMETHODIMP
nsFileOutputStream::Preallocate(int64_t aLength) {
if (!mFD) {

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

@ -20,6 +20,12 @@
#include "nsReadLine.h"
#include <algorithm>
namespace mozilla {
namespace ipc {
class FileDescriptor;
} // namespace ipc
} // namespace mozilla
////////////////////////////////////////////////////////////////////////////////
class nsFileStreamBase : public nsISeekableStream, public nsIFileMetadata {
@ -195,6 +201,7 @@ class nsFileOutputStream : public nsFileStreamBase, public nsIFileOutputStream {
NS_FORWARD_NSIOUTPUTSTREAM(nsFileStreamBase::)
static nsresult Create(nsISupports* aOuter, REFNSIID aIID, void** aResult);
nsresult InitWithFileDescriptor(const mozilla::ipc::FileDescriptor& aFd);
protected:
virtual ~nsFileOutputStream() = default;

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

@ -151,6 +151,22 @@ nsresult NS_NewLocalFileOutputStream(nsIOutputStream** result, nsIFile* file,
return rv;
}
nsresult NS_NewLocalFileOutputStream(nsIOutputStream** result,
const mozilla::ipc::FileDescriptor& fd) {
nsCOMPtr<nsIFileOutputStream> out;
nsFileOutputStream::Create(nullptr, NS_GET_IID(nsIFileOutputStream),
getter_AddRefs(out));
nsresult rv =
static_cast<nsFileOutputStream*>(out.get())->InitWithFileDescriptor(fd);
if (NS_FAILED(rv)) {
return rv;
}
out.forget(result);
return NS_OK;
}
nsresult net_EnsureIOService(nsIIOService** ios, nsCOMPtr<nsIIOService>& grip) {
nsresult rv = NS_OK;
if (!*ios) {

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

@ -61,6 +61,11 @@ class ClientInfo;
class PerformanceStorage;
class ServiceWorkerDescriptor;
} // namespace dom
namespace ipc {
class FileDescriptor;
} // namespace ipc
} // namespace mozilla
template <class>
@ -462,6 +467,9 @@ nsresult NS_NewLocalFileOutputStream(nsIOutputStream** result, nsIFile* file,
int32_t ioFlags = -1, int32_t perm = -1,
int32_t behaviorFlags = 0);
nsresult NS_NewLocalFileOutputStream(nsIOutputStream** result,
const mozilla::ipc::FileDescriptor& fd);
// returns a file output stream which can be QI'ed to nsISafeOutputStream.
nsresult NS_NewAtomicFileOutputStream(nsIOutputStream** result, nsIFile* file,
int32_t ioFlags = -1, int32_t perm = -1,

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

@ -1220,7 +1220,7 @@ void AltSvcCache::ClearAltServiceMappings() {
nsresult AltSvcCache::GetAltSvcCacheKeys(nsTArray<nsCString>& value) {
MOZ_ASSERT(NS_IsMainThread());
if (gHttpHandler->AllowAltSvc() && mStorage) {
nsTArray<mozilla::dom::DataStorageItem> items;
nsTArray<mozilla::psm::DataStorageItem> items;
mStorage->GetAll(&items);
for (const auto& item : items) {

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

@ -10,6 +10,7 @@
#include "mozilla/ClearOnShutdown.h"
#include "mozilla/dom/PContent.h"
#include "mozilla/dom/ContentParent.h"
#include "mozilla/FileUtils.h"
#include "mozilla/Preferences.h"
#include "mozilla/Services.h"
#include "mozilla/StaticMutex.h"
@ -29,6 +30,11 @@
#include "nsPrintfCString.h"
#include "nsStreamUtils.h"
#include "nsThreadUtils.h"
#include "private/pprio.h"
#if defined(XP_WIN)
# include "nsILocalFileWin.h"
#endif
// NB: Read DataStorage.h first.
@ -77,7 +83,7 @@ static mozilla::StaticAutoPtr<DataStorageSharedThread> gDataStorageSharedThread;
static bool gDataStorageSharedThreadShutDown = false;
nsresult DataStorageSharedThread::Initialize() {
MOZ_ASSERT(XRE_IsParentProcess());
MOZ_ASSERT(XRE_IsParentProcess() || XRE_IsSocketProcess());
mozilla::StaticMutexAutoLock lock(sDataStorageSharedThreadMutex);
// If this happens, we initialized a DataStorage after shutdown notifications
@ -100,7 +106,7 @@ nsresult DataStorageSharedThread::Initialize() {
}
nsresult DataStorageSharedThread::Shutdown() {
MOZ_ASSERT(XRE_IsParentProcess());
MOZ_ASSERT(XRE_IsParentProcess() || XRE_IsSocketProcess());
mozilla::StaticMutexAutoLock lock(sDataStorageSharedThreadMutex);
if (!gDataStorageSharedThread || gDataStorageSharedThreadShutDown) {
@ -132,7 +138,7 @@ nsresult DataStorageSharedThread::Shutdown() {
}
nsresult DataStorageSharedThread::Dispatch(nsIRunnable* event) {
MOZ_ASSERT(XRE_IsParentProcess());
MOZ_ASSERT(XRE_IsParentProcess() || XRE_IsSocketProcess());
mozilla::StaticMutexAutoLock lock(sDataStorageSharedThreadMutex);
if (gDataStorageSharedThreadShutDown || !gDataStorageSharedThread ||
!gDataStorageSharedThread->mThread) {
@ -233,11 +239,11 @@ void DataStorage::GetAllFileNames(nsTArray<nsString>& aItems) {
// static
void DataStorage::GetAllChildProcessData(
nsTArray<mozilla::dom::DataStorageEntry>& aEntries) {
nsTArray<mozilla::psm::DataStorageEntry>& aEntries) {
nsTArray<nsString> storageFiles;
GetAllFileNames(storageFiles);
for (auto& file : storageFiles) {
dom::DataStorageEntry entry;
psm::DataStorageEntry entry;
entry.filename() = file;
RefPtr<DataStorage> storage = DataStorage::GetFromRawFileName(file);
if (!storage->mInitCalled) {
@ -255,7 +261,7 @@ void DataStorage::GetAllChildProcessData(
// static
void DataStorage::SetCachedStorageEntries(
const nsTArray<mozilla::dom::DataStorageEntry>& aEntries) {
const nsTArray<mozilla::psm::DataStorageEntry>& aEntries) {
MOZ_ASSERT(XRE_IsContentProcess());
// Make sure to initialize all DataStorage classes.
@ -266,10 +272,10 @@ void DataStorage::SetCachedStorageEntries(
// (currently 3). There is a comment in the DataStorageList.h header
// about updating the algorithm here to something more fancy if the list
// of DataStorage items grows some day.
nsTArray<dom::DataStorageEntry> entries;
nsTArray<psm::DataStorageEntry> entries;
#define DATA_STORAGE(_) \
{ \
dom::DataStorageEntry entry; \
psm::DataStorageEntry entry; \
entry.filename() = NS_LITERAL_STRING(#_ ".txt"); \
for (auto& e : aEntries) { \
if (entry.filename().Equals(e.filename())) { \
@ -299,8 +305,8 @@ size_t DataStorage::SizeOfIncludingThis(
return aMallocSizeOf(this) + sizeOfExcludingThis;
}
nsresult DataStorage::Init(
const nsTArray<mozilla::dom::DataStorageItem>* aItems) {
nsresult DataStorage::Init(const nsTArray<DataStorageItem>* aItems,
mozilla::ipc::FileDescriptor aWriteFd) {
// Don't access the observer service or preferences off the main thread.
if (!NS_IsMainThread()) {
MOZ_ASSERT_UNREACHABLE("DataStorage::Init called off main thread");
@ -339,11 +345,20 @@ nsresult DataStorage::Init(
return rv;
}
} else {
// In the child process, we use the data passed to us by the parent process
// to initialize.
MOZ_ASSERT(XRE_IsContentProcess());
// In the child process and socket process, we use the data passed to us by
// the parent process to initialize.
MOZ_ASSERT(XRE_IsContentProcess() || XRE_IsSocketProcess());
MOZ_ASSERT(aItems);
if (XRE_IsSocketProcess() && aWriteFd.IsValid()) {
rv = DataStorageSharedThread::Initialize();
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
mWriteFd = aWriteFd;
}
for (auto& item : *aItems) {
Entry entry;
entry.mValue = item.value();
@ -384,6 +399,87 @@ nsresult DataStorage::Init(
return NS_OK;
}
class DataStorage::Opener : public Runnable {
public:
explicit Opener(
nsIFile* aFile,
std::function<void(mozilla::ipc::FileDescriptor&&)>&& aResolver)
: Runnable("DataStorage::Opener"),
mFile(aFile),
mResolver(std::move(aResolver)) {
MOZ_ASSERT(mFile);
}
~Opener() = default;
private:
NS_DECL_NSIRUNNABLE
void ResolveFD();
nsCOMPtr<nsIFile> mFile;
std::function<void(mozilla::ipc::FileDescriptor&&)> mResolver;
mozilla::ipc::FileDescriptor mFd;
};
void DataStorage::Opener::ResolveFD() {
MOZ_ASSERT(NS_IsMainThread());
mResolver(std::move(mFd));
}
NS_IMETHODIMP
DataStorage::Opener::Run() {
AutoFDClose prFileDesc;
nsresult rv;
#if defined(XP_WIN)
nsCOMPtr<nsILocalFileWin> winFile = do_QueryInterface(mFile, &rv);
MOZ_ASSERT(winFile);
if (NS_SUCCEEDED(rv)) {
rv = winFile->OpenNSPRFileDescShareDelete(
PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE, 0664, &prFileDesc.rwget());
}
#else
rv = mFile->OpenNSPRFileDesc(PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE, 0664,
&prFileDesc.rwget());
#endif /* XP_WIN */
if (NS_SUCCEEDED(rv)) {
mFd = mozilla::ipc::FileDescriptor(
mozilla::ipc::FileDescriptor::PlatformHandleType(
PR_FileDesc2NativeHandle(prFileDesc)));
}
RefPtr<Opener> self = this;
rv = NS_DispatchToMainThread(
NS_NewRunnableFunction("DataStorage::Opener::ResolveFD",
[self]() { self->ResolveFD(); }),
NS_DISPATCH_NORMAL);
MOZ_ASSERT(NS_SUCCEEDED(rv));
return NS_OK;
}
nsresult DataStorage::AsyncTakeFileDesc(
std::function<void(mozilla::ipc::FileDescriptor&&)>&& aResolver) {
MOZ_ASSERT(XRE_IsParentProcess());
WaitForReady();
MutexAutoLock lock(mMutex);
if (!mBackingFile) {
return NS_ERROR_NOT_AVAILABLE;
}
RefPtr<Opener> job(new Opener(mBackingFile, std::move(aResolver)));
nsresult rv = DataStorageSharedThread::Dispatch(job);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
mBackingFile = nullptr;
return NS_OK;
}
class DataStorage::Reader : public Runnable {
public:
explicit Reader(DataStorage* aDataStorage)
@ -676,7 +772,7 @@ DataStorage::DataStorageTable& DataStorage::GetTableForType(
}
void DataStorage::ReadAllFromTable(DataStorageType aType,
nsTArray<dom::DataStorageItem>* aItems,
nsTArray<DataStorageItem>* aItems,
const MutexAutoLock& aProofOfLock) {
for (auto iter = GetTableForType(aType, aProofOfLock).Iter(); !iter.Done();
iter.Next()) {
@ -687,7 +783,7 @@ void DataStorage::ReadAllFromTable(DataStorageType aType,
}
}
void DataStorage::GetAll(nsTArray<dom::DataStorageItem>* aItems) {
void DataStorage::GetAll(nsTArray<DataStorageItem>* aItems) {
WaitForReady();
MutexAutoLock lock(mMutex);
@ -820,23 +916,40 @@ void DataStorage::Remove(const nsCString& aKey, DataStorageType aType) {
});
}
class DataStorage::Writer : public Runnable {
class DataStorage::Writer final : public Runnable {
public:
Writer(nsCString& aData, DataStorage* aDataStorage)
: Runnable("DataStorage::Writer"),
mData(aData),
mDataStorage(aDataStorage) {}
private:
protected:
NS_DECL_NSIRUNNABLE
nsresult CreateOutputStream(nsIOutputStream** aResult);
nsCString mData;
RefPtr<DataStorage> mDataStorage;
};
NS_IMETHODIMP
DataStorage::Writer::Run() {
nsresult DataStorage::Writer::CreateOutputStream(nsIOutputStream** aResult) {
nsresult rv;
if (XRE_IsSocketProcess()) {
mozilla::ipc::FileDescriptor fd;
{
MutexAutoLock lock(mDataStorage->mMutex);
fd = mDataStorage->mWriteFd;
}
if (!fd.IsValid()) {
return NS_ERROR_NOT_AVAILABLE;
}
return NS_NewLocalFileOutputStream(aResult, fd);
}
MOZ_ASSERT(XRE_IsParentProcess());
// Concurrent operations on nsIFile objects are not guaranteed to be safe,
// so we clone the file while holding the lock and then release the lock.
// At that point, we can safely operate on the clone.
@ -853,13 +966,23 @@ DataStorage::Writer::Run() {
}
}
return NS_NewLocalFileOutputStream(aResult, file,
PR_CREATE_FILE | PR_TRUNCATE | PR_WRONLY);
}
NS_IMETHODIMP
DataStorage::Writer::Run() {
nsCOMPtr<nsIOutputStream> outputStream;
rv = NS_NewLocalFileOutputStream(getter_AddRefs(outputStream), file,
PR_CREATE_FILE | PR_TRUNCATE | PR_WRONLY);
nsresult rv = CreateOutputStream(getter_AddRefs(outputStream));
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
// When the output stream is null, it means we don't have a profile.
if (!outputStream) {
return NS_OK;
}
const char* ptr = mData.get();
int32_t remaining = mData.Length();
uint32_t written = 0;
@ -885,9 +1008,9 @@ DataStorage::Writer::Run() {
}
nsresult DataStorage::AsyncWriteData(const MutexAutoLock& /*aProofOfLock*/) {
MOZ_ASSERT(XRE_IsParentProcess());
MOZ_ASSERT(XRE_IsParentProcess() || XRE_IsSocketProcess());
if (mShuttingDown || !mBackingFile) {
if (mShuttingDown || (!mBackingFile && !mWriteFd.IsValid())) {
return NS_OK;
}
@ -921,7 +1044,7 @@ nsresult DataStorage::Clear() {
mTemporaryDataTable.Clear();
mPrivateDataTable.Clear();
if (XRE_IsParentProcess()) {
if (XRE_IsParentProcess() || XRE_IsSocketProcess()) {
// Asynchronously clear the file. This is similar to the permission manager
// in that it doesn't wait to synchronously remove the data from its backing
// storage either.
@ -941,7 +1064,7 @@ nsresult DataStorage::Clear() {
/* static */
void DataStorage::TimerCallback(nsITimer* aTimer, void* aClosure) {
MOZ_ASSERT(XRE_IsParentProcess());
MOZ_ASSERT(XRE_IsParentProcess() || XRE_IsSocketProcess());
RefPtr<DataStorage> aDataStorage = (DataStorage*)aClosure;
MutexAutoLock lock(aDataStorage->mMutex);
@ -951,7 +1074,7 @@ void DataStorage::TimerCallback(nsITimer* aTimer, void* aClosure) {
// We only initialize the timer on the worker thread because it's not safe
// to mix what threads are operating on the timer.
nsresult DataStorage::AsyncSetTimer(const MutexAutoLock& /*aProofOfLock*/) {
if (mShuttingDown || !XRE_IsParentProcess()) {
if (mShuttingDown || (!XRE_IsParentProcess() && !XRE_IsSocketProcess())) {
return NS_OK;
}
@ -967,7 +1090,7 @@ nsresult DataStorage::AsyncSetTimer(const MutexAutoLock& /*aProofOfLock*/) {
void DataStorage::SetTimer() {
MOZ_ASSERT(!NS_IsMainThread());
MOZ_ASSERT(XRE_IsParentProcess());
MOZ_ASSERT(XRE_IsParentProcess() || XRE_IsSocketProcess());
MutexAutoLock lock(mMutex);
@ -1001,7 +1124,7 @@ void DataStorage::NotifyObservers(const char* aTopic) {
nsresult DataStorage::DispatchShutdownTimer(
const MutexAutoLock& /*aProofOfLock*/) {
MOZ_ASSERT(XRE_IsParentProcess());
MOZ_ASSERT(XRE_IsParentProcess() || XRE_IsSocketProcess());
nsCOMPtr<nsIRunnable> job = NewRunnableMethod(
"DataStorage::ShutdownTimer", this, &DataStorage::ShutdownTimer);
@ -1013,7 +1136,7 @@ nsresult DataStorage::DispatchShutdownTimer(
}
void DataStorage::ShutdownTimer() {
MOZ_ASSERT(XRE_IsParentProcess());
MOZ_ASSERT(XRE_IsParentProcess() || XRE_IsSocketProcess());
MOZ_ASSERT(!NS_IsMainThread());
MutexAutoLock lock(mMutex);
nsresult rv = mTimer->Cancel();
@ -1039,7 +1162,7 @@ DataStorage::Observe(nsISupports* /*aSubject*/, const char* aTopic,
mPrivateDataTable.Clear();
}
if (!XRE_IsParentProcess()) {
if (!XRE_IsParentProcess() && !XRE_IsSocketProcess()) {
if (strcmp(aTopic, "xpcom-shutdown-threads") == 0) {
sDataStorages->Clear();
}

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

@ -8,6 +8,7 @@
#define mozilla_DataStorage_h
#include "mozilla/Atomics.h"
#include "mozilla/ipc/FileDescriptor.h"
#include "mozilla/MemoryReporting.h"
#include "mozilla/Monitor.h"
#include "mozilla/Mutex.h"
@ -26,9 +27,12 @@ class DataStorageMemoryReporter;
namespace dom {
class ContentChild;
} // namespace dom
namespace psm {
class DataStorageEntry;
class DataStorageItem;
} // namespace dom
} // namespace psm
/**
* DataStorage is a threadsafe, generic, narrow string-based hash map that
@ -101,7 +105,7 @@ enum class DataStorageClass {
};
class DataStorage : public nsIObserver {
typedef dom::DataStorageItem DataStorageItem;
typedef psm::DataStorageItem DataStorageItem;
public:
NS_DECL_THREADSAFE_ISUPPORTS
@ -112,10 +116,22 @@ class DataStorage : public nsIObserver {
static already_AddRefed<DataStorage> Get(DataStorageClass aFilename);
// Initializes the DataStorage. Must be called before using.
// aItems is used in the content process to initialize a cache of the items
// received from the parent process over IPC. nullptr must be passed for the
// parent process.
nsresult Init(const nsTArray<mozilla::dom::DataStorageItem>* aItems);
// aItems is used in the content process and the socket process to initialize
// a cache of the items received from the parent process over IPC. nullptr
// must be passed for the parent process.
// aWriteFd is only used in the socket process for now. The FileDesc is opened
// in parent process and send to socket process. The data storage instance in
// socket process will use this FD to write data to the backing file.
nsresult Init(
const nsTArray<mozilla::psm::DataStorageItem>* aItems,
mozilla::ipc::FileDescriptor aWriteFd = mozilla::ipc::FileDescriptor());
// This function is used to create the file descriptor asynchronously. The FD
// will be sent via the callback. Note that after this call, mBackingFile will
// be nulled to prevent parent process to access the file.
nsresult AsyncTakeFileDesc(
std::function<void(mozilla::ipc::FileDescriptor&&)>&& aResolver);
// Given a key and a type of data, returns a value. Returns an empty string if
// the key is not present for that type of data. If Get is called before the
// "data-storage-ready" event is observed, it will block. NB: It is not
@ -136,14 +152,14 @@ class DataStorage : public nsIObserver {
// Read all child process data that we know about.
static void GetAllChildProcessData(
nsTArray<mozilla::dom::DataStorageEntry>& aEntries);
nsTArray<mozilla::psm::DataStorageEntry>& aEntries);
// Read all of the data items.
void GetAll(nsTArray<DataStorageItem>* aItems);
// Set the cached copy of our DataStorage entries in the content process.
static void SetCachedStorageEntries(
const nsTArray<mozilla::dom::DataStorageEntry>& aEntries);
const nsTArray<mozilla::psm::DataStorageEntry>& aEntries);
size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
@ -160,6 +176,7 @@ class DataStorage : public nsIObserver {
class Writer;
class Reader;
class Opener;
class Entry {
public:
@ -230,6 +247,8 @@ class DataStorage : public nsIObserver {
const nsString mFilename;
mozilla::ipc::FileDescriptor mWriteFd;
static StaticAutoPtr<DataStorages> sDataStorages;
};

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

@ -5,6 +5,8 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
using mozilla::DataStorageType from "ipc/DataStorageIPCUtils.h";
namespace mozilla {
namespace psm {
@ -17,5 +19,16 @@ struct DelegatedCredentialInfoArg {
uint32_t authKeyBits;
};
struct DataStorageItem {
nsCString key;
nsCString value;
DataStorageType type;
};
struct DataStorageEntry {
DataStorageItem[] items;
nsString filename;
};
} // namespace psm
} // namespace mozilla

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

@ -1791,11 +1791,11 @@ nsSiteSecurityService::Enumerate(uint32_t aType,
return NS_ERROR_INVALID_ARG;
}
nsTArray<mozilla::dom::DataStorageItem> items;
nsTArray<mozilla::psm::DataStorageItem> items;
mSiteStateStorage->GetAll(&items);
nsCOMArray<nsISiteSecurityState> states;
for (const mozilla::dom::DataStorageItem& item : items) {
for (const mozilla::psm::DataStorageItem& item : items) {
if (!StringEndsWith(item.key(), keySuffix)) {
// The key does not end with correct suffix, so is not the type we want.
continue;