2017-04-24 13:09:40 +03:00
|
|
|
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
|
|
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
|
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
|
|
* 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/. */
|
|
|
|
|
|
|
|
#include "IPCBlobInputStreamStorage.h"
|
|
|
|
|
2017-05-31 08:41:11 +03:00
|
|
|
#include "mozilla/dom/ContentParent.h"
|
2017-04-24 13:09:40 +03:00
|
|
|
#include "mozilla/StaticMutex.h"
|
|
|
|
#include "mozilla/StaticPtr.h"
|
2017-05-31 08:41:11 +03:00
|
|
|
#include "nsIPropertyBag2.h"
|
2017-04-24 13:09:40 +03:00
|
|
|
#include "nsStreamUtils.h"
|
2017-04-24 13:09:40 +03:00
|
|
|
|
|
|
|
namespace mozilla {
|
2017-05-31 08:41:11 +03:00
|
|
|
|
|
|
|
using namespace hal;
|
|
|
|
|
2017-04-24 13:09:40 +03:00
|
|
|
namespace dom {
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
StaticMutex gMutex;
|
|
|
|
StaticRefPtr<IPCBlobInputStreamStorage> gStorage;
|
|
|
|
}
|
|
|
|
|
2017-05-31 08:41:11 +03:00
|
|
|
NS_INTERFACE_MAP_BEGIN(IPCBlobInputStreamStorage)
|
|
|
|
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIObserver)
|
|
|
|
NS_INTERFACE_MAP_ENTRY(nsIObserver)
|
|
|
|
NS_INTERFACE_MAP_END
|
|
|
|
|
|
|
|
NS_IMPL_ADDREF(IPCBlobInputStreamStorage)
|
|
|
|
NS_IMPL_RELEASE(IPCBlobInputStreamStorage)
|
|
|
|
|
2017-05-31 08:41:10 +03:00
|
|
|
IPCBlobInputStreamStorage::IPCBlobInputStreamStorage()
|
|
|
|
{}
|
|
|
|
|
2017-04-24 13:09:40 +03:00
|
|
|
IPCBlobInputStreamStorage::~IPCBlobInputStreamStorage()
|
|
|
|
{}
|
|
|
|
|
|
|
|
/* static */ IPCBlobInputStreamStorage*
|
|
|
|
IPCBlobInputStreamStorage::Get()
|
|
|
|
{
|
|
|
|
return gStorage;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* static */ void
|
|
|
|
IPCBlobInputStreamStorage::Initialize()
|
|
|
|
{
|
|
|
|
MOZ_ASSERT(!gStorage);
|
|
|
|
|
|
|
|
gStorage = new IPCBlobInputStreamStorage();
|
2017-05-31 08:41:11 +03:00
|
|
|
|
|
|
|
nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
|
|
|
|
if (obs) {
|
|
|
|
obs->AddObserver(gStorage, "xpcom-shutdown", false);
|
|
|
|
obs->AddObserver(gStorage, "ipc:content-shutdown", false);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
IPCBlobInputStreamStorage::Observe(nsISupports* aSubject, const char* aTopic,
|
|
|
|
const char16_t* aData)
|
|
|
|
{
|
|
|
|
if (!strcmp(aTopic, "xpcom-shutdown")) {
|
|
|
|
nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
|
|
|
|
if (obs) {
|
|
|
|
obs->RemoveObserver(this, "xpcom-shutdown");
|
|
|
|
obs->RemoveObserver(this, "ipc:content-shutdown");
|
|
|
|
}
|
|
|
|
|
|
|
|
gStorage = nullptr;
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
MOZ_ASSERT(!strcmp(aTopic, "ipc:content-shutdown"));
|
|
|
|
|
|
|
|
nsCOMPtr<nsIPropertyBag2> props = do_QueryInterface(aSubject);
|
|
|
|
if (NS_WARN_IF(!props)) {
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint64_t childID = CONTENT_PROCESS_ID_UNKNOWN;
|
|
|
|
props->GetPropertyAsUint64(NS_LITERAL_STRING("childID"), &childID);
|
|
|
|
if (NS_WARN_IF(childID == CONTENT_PROCESS_ID_UNKNOWN)) {
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
}
|
|
|
|
|
|
|
|
mozilla::StaticMutexAutoLock lock(gMutex);
|
|
|
|
|
|
|
|
for (auto iter = mStorage.Iter(); !iter.Done(); iter.Next()) {
|
|
|
|
if (iter.Data()->mChildID == childID) {
|
|
|
|
iter.Remove();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return NS_OK;
|
2017-04-24 13:09:40 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
IPCBlobInputStreamStorage::AddStream(nsIInputStream* aInputStream,
|
2017-05-31 08:41:11 +03:00
|
|
|
const nsID& aID,
|
2017-09-11 18:29:44 +03:00
|
|
|
uint64_t aSize,
|
2017-05-31 08:41:11 +03:00
|
|
|
uint64_t aChildID)
|
2017-04-24 13:09:40 +03:00
|
|
|
{
|
|
|
|
MOZ_ASSERT(aInputStream);
|
|
|
|
|
2017-05-31 08:41:10 +03:00
|
|
|
StreamData* data = new StreamData();
|
|
|
|
data->mInputStream = aInputStream;
|
2017-05-31 08:41:11 +03:00
|
|
|
data->mChildID = aChildID;
|
2017-09-11 18:29:44 +03:00
|
|
|
data->mSize = aSize;
|
2017-05-31 08:41:10 +03:00
|
|
|
|
2017-04-24 13:09:40 +03:00
|
|
|
mozilla::StaticMutexAutoLock lock(gMutex);
|
2017-05-31 08:41:10 +03:00
|
|
|
mStorage.Put(aID, data);
|
2017-04-24 13:09:40 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
IPCBlobInputStreamStorage::ForgetStream(const nsID& aID)
|
|
|
|
{
|
|
|
|
mozilla::StaticMutexAutoLock lock(gMutex);
|
|
|
|
mStorage.Remove(aID);
|
|
|
|
}
|
|
|
|
|
2017-04-24 13:09:40 +03:00
|
|
|
void
|
|
|
|
IPCBlobInputStreamStorage::GetStream(const nsID& aID,
|
2017-09-11 18:29:44 +03:00
|
|
|
uint64_t aStart, uint64_t aLength,
|
2017-04-24 13:09:40 +03:00
|
|
|
nsIInputStream** aInputStream)
|
|
|
|
{
|
2017-06-02 12:05:27 +03:00
|
|
|
*aInputStream = nullptr;
|
|
|
|
|
|
|
|
nsCOMPtr<nsIInputStream> inputStream;
|
2017-09-11 18:29:44 +03:00
|
|
|
uint64_t size;
|
2017-06-02 12:05:27 +03:00
|
|
|
|
|
|
|
// NS_CloneInputStream cannot be called when the mutex is locked because it
|
|
|
|
// can, recursively call GetStream() in case the child actor lives on the
|
|
|
|
// parent process.
|
|
|
|
{
|
|
|
|
mozilla::StaticMutexAutoLock lock(gMutex);
|
|
|
|
StreamData* data = mStorage.Get(aID);
|
|
|
|
if (!data) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
inputStream = data->mInputStream;
|
2017-09-11 18:29:44 +03:00
|
|
|
size = data->mSize;
|
2017-04-24 13:09:40 +03:00
|
|
|
}
|
|
|
|
|
2017-06-02 12:05:27 +03:00
|
|
|
MOZ_ASSERT(inputStream);
|
|
|
|
|
2017-04-24 13:09:40 +03:00
|
|
|
// We cannot return always the same inputStream because not all of them are
|
|
|
|
// able to be reused. Better to clone them.
|
|
|
|
|
|
|
|
nsCOMPtr<nsIInputStream> clonedStream;
|
|
|
|
nsCOMPtr<nsIInputStream> replacementStream;
|
|
|
|
|
|
|
|
nsresult rv =
|
2017-06-02 12:05:27 +03:00
|
|
|
NS_CloneInputStream(inputStream, getter_AddRefs(clonedStream),
|
2017-04-24 13:09:40 +03:00
|
|
|
getter_AddRefs(replacementStream));
|
|
|
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (replacementStream) {
|
2017-06-02 12:05:27 +03:00
|
|
|
mozilla::StaticMutexAutoLock lock(gMutex);
|
|
|
|
StreamData* data = mStorage.Get(aID);
|
|
|
|
// data can be gone in the meantime.
|
|
|
|
if (!data) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2017-05-31 08:41:10 +03:00
|
|
|
data->mInputStream = replacementStream;
|
2017-04-24 13:09:40 +03:00
|
|
|
}
|
|
|
|
|
2017-09-11 18:29:44 +03:00
|
|
|
// Now it's the right time to apply a slice if needed.
|
|
|
|
if (aStart > 0 || aLength < size) {
|
2017-10-05 08:38:48 +03:00
|
|
|
clonedStream =
|
|
|
|
new SlicedInputStream(clonedStream.forget(), aStart, aLength);
|
2017-09-11 18:29:44 +03:00
|
|
|
}
|
|
|
|
|
2017-04-24 13:09:40 +03:00
|
|
|
clonedStream.forget(aInputStream);
|
|
|
|
}
|
|
|
|
|
2017-05-31 08:41:10 +03:00
|
|
|
void
|
|
|
|
IPCBlobInputStreamStorage::StoreCallback(const nsID& aID,
|
|
|
|
IPCBlobInputStreamParentCallback* aCallback)
|
|
|
|
{
|
|
|
|
MOZ_ASSERT(aCallback);
|
|
|
|
|
|
|
|
mozilla::StaticMutexAutoLock lock(gMutex);
|
|
|
|
StreamData* data = mStorage.Get(aID);
|
|
|
|
if (data) {
|
|
|
|
MOZ_ASSERT(!data->mCallback);
|
|
|
|
data->mCallback = aCallback;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
already_AddRefed<IPCBlobInputStreamParentCallback>
|
|
|
|
IPCBlobInputStreamStorage::TakeCallback(const nsID& aID)
|
|
|
|
{
|
|
|
|
mozilla::StaticMutexAutoLock lock(gMutex);
|
|
|
|
StreamData* data = mStorage.Get(aID);
|
|
|
|
if (!data) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
RefPtr<IPCBlobInputStreamParentCallback> callback;
|
|
|
|
data->mCallback.swap(callback);
|
|
|
|
return callback.forget();
|
|
|
|
}
|
|
|
|
|
2017-04-24 13:09:40 +03:00
|
|
|
} // namespace dom
|
|
|
|
} // namespace mozilla
|