Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/dom/file/ipc/IPCBlobInputStreamStorage.cpp
Line
Count
Source (jump to first uncovered line)
1
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
3
/* This Source Code Form is subject to the terms of the Mozilla Public
4
 * License, v. 2.0. If a copy of the MPL was not distributed with this
5
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7
#include "IPCBlobInputStreamStorage.h"
8
9
#include "mozilla/dom/ContentParent.h"
10
#include "mozilla/StaticMutex.h"
11
#include "mozilla/StaticPtr.h"
12
#include "nsIPropertyBag2.h"
13
#include "nsStreamUtils.h"
14
15
namespace mozilla {
16
17
using namespace hal;
18
19
namespace dom {
20
21
namespace {
22
StaticMutex gMutex;
23
StaticRefPtr<IPCBlobInputStreamStorage> gStorage;
24
}
25
26
0
NS_INTERFACE_MAP_BEGIN(IPCBlobInputStreamStorage)
27
0
  NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIObserver)
28
0
  NS_INTERFACE_MAP_ENTRY(nsIObserver)
29
0
NS_INTERFACE_MAP_END
30
31
NS_IMPL_ADDREF(IPCBlobInputStreamStorage)
32
NS_IMPL_RELEASE(IPCBlobInputStreamStorage)
33
34
IPCBlobInputStreamStorage::IPCBlobInputStreamStorage()
35
3
{}
36
37
IPCBlobInputStreamStorage::~IPCBlobInputStreamStorage()
38
0
{}
39
40
/* static */ IPCBlobInputStreamStorage*
41
IPCBlobInputStreamStorage::Get()
42
0
{
43
0
  return gStorage;
44
0
}
45
46
/* static */ void
47
IPCBlobInputStreamStorage::Initialize()
48
3
{
49
3
  MOZ_ASSERT(!gStorage);
50
3
51
3
  gStorage = new IPCBlobInputStreamStorage();
52
3
53
3
  nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
54
3
  if (obs) {
55
3
    obs->AddObserver(gStorage, "xpcom-shutdown", false);
56
3
    obs->AddObserver(gStorage, "ipc:content-shutdown", false);
57
3
  }
58
3
}
59
60
NS_IMETHODIMP
61
IPCBlobInputStreamStorage::Observe(nsISupports* aSubject, const char* aTopic,
62
                                   const char16_t* aData)
63
0
{
64
0
  if (!strcmp(aTopic, "xpcom-shutdown")) {
65
0
    nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
66
0
    if (obs) {
67
0
      obs->RemoveObserver(this, "xpcom-shutdown");
68
0
      obs->RemoveObserver(this, "ipc:content-shutdown");
69
0
    }
70
0
71
0
    gStorage = nullptr;
72
0
    return NS_OK;
73
0
  }
74
0
75
0
  MOZ_ASSERT(!strcmp(aTopic, "ipc:content-shutdown"));
76
0
77
0
  nsCOMPtr<nsIPropertyBag2> props = do_QueryInterface(aSubject);
78
0
  if (NS_WARN_IF(!props)) {
79
0
    return NS_ERROR_FAILURE;
80
0
  }
81
0
82
0
  uint64_t childID = CONTENT_PROCESS_ID_UNKNOWN;
83
0
  props->GetPropertyAsUint64(NS_LITERAL_STRING("childID"), &childID);
84
0
  if (NS_WARN_IF(childID == CONTENT_PROCESS_ID_UNKNOWN)) {
85
0
    return NS_ERROR_FAILURE;
86
0
  }
87
0
88
0
  mozilla::StaticMutexAutoLock lock(gMutex);
89
0
90
0
  for (auto iter = mStorage.Iter(); !iter.Done(); iter.Next()) {
91
0
    if (iter.Data()->mChildID == childID) {
92
0
      iter.Remove();
93
0
    }
94
0
  }
95
0
96
0
  return NS_OK;
97
0
}
98
99
void
100
IPCBlobInputStreamStorage::AddStream(nsIInputStream* aInputStream,
101
                                     const nsID& aID,
102
                                     uint64_t aSize,
103
                                     uint64_t aChildID)
104
0
{
105
0
  MOZ_ASSERT(aInputStream);
106
0
107
0
  StreamData* data = new StreamData();
108
0
  data->mInputStream = aInputStream;
109
0
  data->mChildID = aChildID;
110
0
  data->mSize = aSize;
111
0
112
0
  mozilla::StaticMutexAutoLock lock(gMutex);
113
0
  mStorage.Put(aID, data);
114
0
}
115
116
void
117
IPCBlobInputStreamStorage::ForgetStream(const nsID& aID)
118
0
{
119
0
  mozilla::StaticMutexAutoLock lock(gMutex);
120
0
  mStorage.Remove(aID);
121
0
}
122
123
void
124
IPCBlobInputStreamStorage::GetStream(const nsID& aID,
125
                                     uint64_t aStart, uint64_t aLength,
126
                                     nsIInputStream** aInputStream)
127
0
{
128
0
  *aInputStream = nullptr;
129
0
130
0
  nsCOMPtr<nsIInputStream> inputStream;
131
0
  uint64_t size;
132
0
133
0
  // NS_CloneInputStream cannot be called when the mutex is locked because it
134
0
  // can, recursively call GetStream() in case the child actor lives on the
135
0
  // parent process.
136
0
  {
137
0
    mozilla::StaticMutexAutoLock lock(gMutex);
138
0
    StreamData* data = mStorage.Get(aID);
139
0
    if (!data) {
140
0
      return;
141
0
    }
142
0
143
0
    inputStream = data->mInputStream;
144
0
    size = data->mSize;
145
0
  }
146
0
147
0
  MOZ_ASSERT(inputStream);
148
0
149
0
  // We cannot return always the same inputStream because not all of them are
150
0
  // able to be reused. Better to clone them.
151
0
152
0
  nsCOMPtr<nsIInputStream> clonedStream;
153
0
  nsCOMPtr<nsIInputStream> replacementStream;
154
0
155
0
  nsresult rv =
156
0
    NS_CloneInputStream(inputStream, getter_AddRefs(clonedStream),
157
0
                        getter_AddRefs(replacementStream));
158
0
  if (NS_WARN_IF(NS_FAILED(rv))) {
159
0
    return;
160
0
  }
161
0
162
0
  if (replacementStream) {
163
0
    mozilla::StaticMutexAutoLock lock(gMutex);
164
0
    StreamData* data = mStorage.Get(aID);
165
0
    // data can be gone in the meantime.
166
0
    if (!data) {
167
0
      return;
168
0
    }
169
0
170
0
    data->mInputStream = replacementStream;
171
0
  }
172
0
173
0
  // Now it's the right time to apply a slice if needed.
174
0
  if (aStart > 0 || aLength < size) {
175
0
    clonedStream =
176
0
      new SlicedInputStream(clonedStream.forget(), aStart, aLength);
177
0
  }
178
0
179
0
  clonedStream.forget(aInputStream);
180
0
}
181
182
void
183
IPCBlobInputStreamStorage::StoreCallback(const nsID& aID,
184
                                         IPCBlobInputStreamParentCallback* aCallback)
185
0
{
186
0
  MOZ_ASSERT(aCallback);
187
0
188
0
  mozilla::StaticMutexAutoLock lock(gMutex);
189
0
  StreamData* data = mStorage.Get(aID);
190
0
  if (data) {
191
0
    MOZ_ASSERT(!data->mCallback);
192
0
    data->mCallback = aCallback;
193
0
  }
194
0
}
195
196
already_AddRefed<IPCBlobInputStreamParentCallback>
197
IPCBlobInputStreamStorage::TakeCallback(const nsID& aID)
198
0
{
199
0
  mozilla::StaticMutexAutoLock lock(gMutex);
200
0
  StreamData* data = mStorage.Get(aID);
201
0
  if (!data) {
202
0
    return nullptr;
203
0
  }
204
0
205
0
  RefPtr<IPCBlobInputStreamParentCallback> callback;
206
0
  data->mCallback.swap(callback);
207
0
  return callback.forget();
208
0
}
209
210
} // namespace dom
211
} // namespace mozilla