Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/dom/file/ipc/IPCBlobUtils.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 "IPCBlobUtils.h"
8
#include "IPCBlobInputStream.h"
9
#include "IPCBlobInputStreamChild.h"
10
#include "IPCBlobInputStreamParent.h"
11
#include "IPCBlobInputStreamStorage.h"
12
#include "mozilla/dom/IPCBlob.h"
13
#include "mozilla/ipc/BackgroundParent.h"
14
#include "mozilla/ipc/PBackgroundParent.h"
15
#include "mozilla/ipc/PBackgroundChild.h"
16
#include "mozilla/dom/ContentParent.h"
17
#include "mozilla/dom/ContentChild.h"
18
#include "mozilla/ipc/IPCStreamUtils.h"
19
#include "mozilla/ipc/ProtocolUtils.h"
20
#include "StreamBlobImpl.h"
21
#include "prtime.h"
22
23
namespace mozilla {
24
25
using namespace ipc;
26
27
namespace dom {
28
namespace IPCBlobUtils {
29
30
already_AddRefed<BlobImpl>
31
Deserialize(const IPCBlob& aIPCBlob)
32
0
{
33
0
  nsCOMPtr<nsIInputStream> inputStream;
34
0
35
0
  const IPCBlobStream& stream = aIPCBlob.inputStream();
36
0
  switch (stream.type()) {
37
0
38
0
  // Parent to child: when an nsIInputStream is sent from parent to child, the
39
0
  // child receives a IPCBlobInputStream actor.
40
0
  case IPCBlobStream::TPIPCBlobInputStreamChild: {
41
0
    IPCBlobInputStreamChild* actor =
42
0
      static_cast<IPCBlobInputStreamChild*>(stream.get_PIPCBlobInputStreamChild());
43
0
    inputStream = actor->CreateStream();
44
0
    break;
45
0
  }
46
0
47
0
  // Child to Parent: when a blob is created on the content process send it's
48
0
  // sent to the parent, we have an IPCStream object.
49
0
  case IPCBlobStream::TIPCStream:
50
0
    MOZ_ASSERT(XRE_IsParentProcess());
51
0
    inputStream = DeserializeIPCStream(stream.get_IPCStream());
52
0
    break;
53
0
54
0
  default:
55
0
    MOZ_CRASH("Unknown type.");
56
0
    break;
57
0
  }
58
0
59
0
  MOZ_ASSERT(inputStream);
60
0
61
0
  RefPtr<StreamBlobImpl> blobImpl;
62
0
63
0
  if (aIPCBlob.file().type() == IPCFileUnion::Tvoid_t) {
64
0
    blobImpl = StreamBlobImpl::Create(inputStream.forget(),
65
0
                                      aIPCBlob.type(),
66
0
                                      aIPCBlob.size());
67
0
  } else {
68
0
    const IPCFile& file = aIPCBlob.file().get_IPCFile();
69
0
    blobImpl = StreamBlobImpl::Create(inputStream.forget(),
70
0
                                      file.name(),
71
0
                                      aIPCBlob.type(),
72
0
                                      file.lastModified(),
73
0
                                      aIPCBlob.size());
74
0
    blobImpl->SetDOMPath(file.DOMPath());
75
0
    blobImpl->SetFullPath(file.fullPath());
76
0
    blobImpl->SetIsDirectory(file.isDirectory());
77
0
  }
78
0
79
0
  blobImpl->SetFileId(aIPCBlob.fileId());
80
0
81
0
  return blobImpl.forget();
82
0
}
83
84
template<typename M>
85
nsresult
86
SerializeInputStreamParent(nsIInputStream* aInputStream, uint64_t aSize,
87
                           uint64_t aChildID, IPCBlob& aIPCBlob, M* aManager)
88
0
{
89
0
  // Parent to Child we always send a IPCBlobInputStream.
90
0
  MOZ_ASSERT(XRE_IsParentProcess());
91
0
92
0
  nsCOMPtr<nsIInputStream> stream = aInputStream;
93
0
94
0
  // In case this is a IPCBlobInputStream, we don't want to create a loop:
95
0
  // IPCBlobInputStreamParent -> IPCBlobInputStream ->
96
0
  // IPCBlobInputStreamParent. Let's use the underlying inputStream instead.
97
0
  nsCOMPtr<nsIIPCBlobInputStream> ipcBlobInputStream =
98
0
    do_QueryInterface(aInputStream);
99
0
  if (ipcBlobInputStream) {
100
0
    stream = ipcBlobInputStream->GetInternalStream();
101
0
    // If we don't have an underlying stream, it's better to terminate here
102
0
    // instead of sending an 'empty' IPCBlobInputStream actor on the other side,
103
0
    // unable to be used.
104
0
    if (NS_WARN_IF(!stream)) {
105
0
      return NS_ERROR_FAILURE;
106
0
    }
107
0
  }
108
0
109
0
  nsresult rv;
110
0
  RefPtr<IPCBlobInputStreamParent> parentActor =
111
0
    IPCBlobInputStreamParent::Create(stream, aSize, aChildID, &rv, aManager);
112
0
  if (!parentActor) {
113
0
    return rv;
114
0
  }
115
0
116
0
  // We need manually to increase the reference for this actor because the
117
0
  // IPC allocator method is not triggered. The Release() is called by IPDL
118
0
  // when the actor is deleted.
119
0
  parentActor.get()->AddRef();
120
0
121
0
  if (!aManager->SendPIPCBlobInputStreamConstructor(parentActor,
122
0
                                                    parentActor->ID(),
123
0
                                                    parentActor->Size())) {
124
0
    return NS_ERROR_FAILURE;
125
0
  }
126
0
127
0
  aIPCBlob.inputStream() = parentActor;
128
0
  return NS_OK;
129
0
}
Unexecuted instantiation: nsresult mozilla::dom::IPCBlobUtils::SerializeInputStreamParent<mozilla::dom::nsIContentParent>(nsIInputStream*, unsigned long, unsigned long, mozilla::dom::IPCBlob&, mozilla::dom::nsIContentParent*)
Unexecuted instantiation: nsresult mozilla::dom::IPCBlobUtils::SerializeInputStreamParent<mozilla::ipc::PBackgroundParent>(nsIInputStream*, unsigned long, unsigned long, mozilla::dom::IPCBlob&, mozilla::ipc::PBackgroundParent*)
130
131
template<typename M>
132
nsresult
133
SerializeInputStreamChild(nsIInputStream* aInputStream, IPCBlob& aIPCBlob,
134
                          M* aManager)
135
0
{
136
0
  AutoIPCStream ipcStream(true /* delayed start */);
137
0
  if (!ipcStream.Serialize(aInputStream, aManager)) {
138
0
    return NS_ERROR_FAILURE;
139
0
  }
140
0
141
0
  aIPCBlob.inputStream() = ipcStream.TakeValue();
142
0
  return NS_OK;
143
0
}
Unexecuted instantiation: nsresult mozilla::dom::IPCBlobUtils::SerializeInputStreamChild<mozilla::dom::nsIContentChild>(nsIInputStream*, mozilla::dom::IPCBlob&, mozilla::dom::nsIContentChild*)
Unexecuted instantiation: nsresult mozilla::dom::IPCBlobUtils::SerializeInputStreamChild<mozilla::ipc::PBackgroundChild>(nsIInputStream*, mozilla::dom::IPCBlob&, mozilla::ipc::PBackgroundChild*)
144
145
nsresult
146
SerializeInputStream(nsIInputStream* aInputStream, uint64_t aSize,
147
                     uint64_t aChildID, IPCBlob& aIPCBlob,
148
                     nsIContentParent* aManager)
149
0
{
150
0
  return SerializeInputStreamParent(aInputStream, aSize, aChildID, aIPCBlob,
151
0
                                    aManager);
152
0
}
153
154
nsresult
155
SerializeInputStream(nsIInputStream* aInputStream, uint64_t aSize,
156
                     uint64_t aChildID, IPCBlob& aIPCBlob,
157
                     PBackgroundParent* aManager)
158
0
{
159
0
  return SerializeInputStreamParent(aInputStream, aSize, aChildID, aIPCBlob,
160
0
                                    aManager);
161
0
}
162
163
nsresult
164
SerializeInputStream(nsIInputStream* aInputStream, uint64_t aSize,
165
                     uint64_t aChildID, IPCBlob& aIPCBlob,
166
                     nsIContentChild* aManager)
167
0
{
168
0
  return SerializeInputStreamChild(aInputStream, aIPCBlob, aManager);
169
0
}
170
171
nsresult
172
SerializeInputStream(nsIInputStream* aInputStream, uint64_t aSize,
173
                     uint64_t aChildID, IPCBlob& aIPCBlob,
174
                     PBackgroundChild* aManager)
175
0
{
176
0
  return SerializeInputStreamChild(aInputStream, aIPCBlob, aManager);
177
0
}
178
179
uint64_t
180
ChildIDFromManager(nsIContentParent* aManager)
181
0
{
182
0
  return aManager->ChildID();
183
0
}
184
185
uint64_t
186
ChildIDFromManager(PBackgroundParent* aManager)
187
0
{
188
0
  return BackgroundParent::GetChildID(aManager);
189
0
}
190
191
uint64_t
192
ChildIDFromManager(nsIContentChild* aManager)
193
0
{
194
0
  return 0;
195
0
}
196
197
uint64_t
198
ChildIDFromManager(PBackgroundChild* aManager)
199
0
{
200
0
  return 0;
201
0
}
202
203
template<typename M>
204
nsresult
205
SerializeInternal(BlobImpl* aBlobImpl, M* aManager, IPCBlob& aIPCBlob)
206
0
{
207
0
  MOZ_ASSERT(aBlobImpl);
208
0
209
0
  nsAutoString value;
210
0
  aBlobImpl->GetType(value);
211
0
  aIPCBlob.type() = value;
212
0
213
0
  ErrorResult rv;
214
0
  aIPCBlob.size() = aBlobImpl->GetSize(rv);
215
0
  if (NS_WARN_IF(rv.Failed())) {
216
0
    return rv.StealNSResult();
217
0
  }
218
0
219
0
  if (!aBlobImpl->IsFile()) {
220
0
    aIPCBlob.file() = void_t();
221
0
  } else {
222
0
    IPCFile file;
223
0
224
0
    aBlobImpl->GetName(value);
225
0
    file.name() = value;
226
0
227
0
    file.lastModified() = aBlobImpl->GetLastModified(rv) * PR_USEC_PER_MSEC;
228
0
    if (NS_WARN_IF(rv.Failed())) {
229
0
      return rv.StealNSResult();
230
0
    }
231
0
232
0
    aBlobImpl->GetDOMPath(value);
233
0
    file.DOMPath() = value;
234
0
235
0
    aBlobImpl->GetMozFullPathInternal(value, rv);
236
0
    if (NS_WARN_IF(rv.Failed())) {
237
0
      return rv.StealNSResult();
238
0
    }
239
0
    file.fullPath() = value;
240
0
241
0
    file.isDirectory() = aBlobImpl->IsDirectory();
242
0
243
0
    aIPCBlob.file() = file;
244
0
  }
245
0
246
0
  aIPCBlob.fileId() = aBlobImpl->GetFileId();
247
0
248
0
  nsCOMPtr<nsIInputStream> inputStream;
249
0
  aBlobImpl->CreateInputStream(getter_AddRefs(inputStream), rv);
250
0
  if (NS_WARN_IF(rv.Failed())) {
251
0
    return rv.StealNSResult();
252
0
  }
253
0
254
0
  rv = SerializeInputStream(inputStream, aIPCBlob.size(),
255
0
                            ChildIDFromManager(aManager), aIPCBlob, aManager);
256
0
  if (NS_WARN_IF(rv.Failed())) {
257
0
    return rv.StealNSResult();
258
0
  }
259
0
260
0
  return NS_OK;
261
0
}
Unexecuted instantiation: nsresult mozilla::dom::IPCBlobUtils::SerializeInternal<mozilla::dom::nsIContentChild>(mozilla::dom::BlobImpl*, mozilla::dom::nsIContentChild*, mozilla::dom::IPCBlob&)
Unexecuted instantiation: nsresult mozilla::dom::IPCBlobUtils::SerializeInternal<mozilla::ipc::PBackgroundChild>(mozilla::dom::BlobImpl*, mozilla::ipc::PBackgroundChild*, mozilla::dom::IPCBlob&)
Unexecuted instantiation: nsresult mozilla::dom::IPCBlobUtils::SerializeInternal<mozilla::dom::nsIContentParent>(mozilla::dom::BlobImpl*, mozilla::dom::nsIContentParent*, mozilla::dom::IPCBlob&)
Unexecuted instantiation: nsresult mozilla::dom::IPCBlobUtils::SerializeInternal<mozilla::ipc::PBackgroundParent>(mozilla::dom::BlobImpl*, mozilla::ipc::PBackgroundParent*, mozilla::dom::IPCBlob&)
Unexecuted instantiation: nsresult mozilla::dom::IPCBlobUtils::SerializeInternal<mozilla::dom::ContentParent>(mozilla::dom::BlobImpl*, mozilla::dom::ContentParent*, mozilla::dom::IPCBlob&)
Unexecuted instantiation: nsresult mozilla::dom::IPCBlobUtils::SerializeInternal<mozilla::dom::ContentChild>(mozilla::dom::BlobImpl*, mozilla::dom::ContentChild*, mozilla::dom::IPCBlob&)
262
263
nsresult
264
Serialize(BlobImpl* aBlobImpl, nsIContentChild* aManager, IPCBlob& aIPCBlob)
265
0
{
266
0
  return SerializeInternal(aBlobImpl, aManager, aIPCBlob);
267
0
}
268
269
nsresult
270
Serialize(BlobImpl* aBlobImpl, PBackgroundChild* aManager, IPCBlob& aIPCBlob)
271
0
{
272
0
  return SerializeInternal(aBlobImpl, aManager, aIPCBlob);
273
0
}
274
275
nsresult
276
Serialize(BlobImpl* aBlobImpl, nsIContentParent* aManager, IPCBlob& aIPCBlob)
277
0
{
278
0
  return SerializeInternal(aBlobImpl, aManager, aIPCBlob);
279
0
}
280
281
nsresult
282
Serialize(BlobImpl* aBlobImpl, PBackgroundParent* aManager, IPCBlob& aIPCBlob)
283
0
{
284
0
  return SerializeInternal(aBlobImpl, aManager, aIPCBlob);
285
0
}
286
287
nsresult
288
SerializeUntyped(BlobImpl* aBlobImpl, IProtocol* aActor, IPCBlob& aIPCBlob)
289
0
{
290
0
  // We always want to act on the toplevel protocol.
291
0
  IProtocol* manager = aActor;
292
0
  while (manager->Manager()) {
293
0
    manager = manager->Manager();
294
0
  }
295
0
296
0
  // We always need the toplevel protocol
297
0
  switch(manager->GetProtocolTypeId()) {
298
0
  case PBackgroundMsgStart:
299
0
    if (manager->GetSide() == mozilla::ipc::ParentSide) {
300
0
      return SerializeInternal(aBlobImpl,
301
0
                               static_cast<PBackgroundParent*>(manager),
302
0
                               aIPCBlob);
303
0
    } else {
304
0
      return SerializeInternal(aBlobImpl,
305
0
                               static_cast<PBackgroundChild*>(manager),
306
0
                               aIPCBlob);
307
0
    }
308
0
  case PContentMsgStart:
309
0
    if (manager->GetSide() == mozilla::ipc::ParentSide) {
310
0
      return SerializeInternal(aBlobImpl,
311
0
                               static_cast<ContentParent*>(manager),
312
0
                               aIPCBlob);
313
0
    } else {
314
0
      return SerializeInternal(aBlobImpl,
315
0
                               static_cast<ContentChild*>(manager),
316
0
                               aIPCBlob);
317
0
    }
318
0
  default:
319
0
    MOZ_CRASH("Unsupported protocol passed to BlobImpl serialize");
320
0
  }
321
0
}
322
323
} // IPCBlobUtils namespace
324
} // dom namespace
325
326
namespace ipc {
327
void
328
IPDLParamTraits<mozilla::dom::BlobImpl>::Write(
329
  IPC::Message* aMsg, IProtocol* aActor,
330
  mozilla::dom::BlobImpl* aParam)
331
0
{
332
0
  nsresult rv;
333
0
  mozilla::dom::IPCBlob ipcblob;
334
0
  if (aParam) {
335
0
    rv = mozilla::dom::IPCBlobUtils::SerializeUntyped(aParam, aActor, ipcblob);
336
0
  }
337
0
  if (!aParam || NS_WARN_IF(NS_FAILED(rv))) {
338
0
    WriteIPDLParam(aMsg, aActor, false);
339
0
  } else {
340
0
    WriteIPDLParam(aMsg, aActor, true);
341
0
    WriteIPDLParam(aMsg, aActor, ipcblob);
342
0
  }
343
0
}
344
345
bool
346
IPDLParamTraits<mozilla::dom::BlobImpl>::Read(
347
  const IPC::Message* aMsg, PickleIterator* aIter,
348
  IProtocol* aActor, RefPtr<mozilla::dom::BlobImpl>* aResult)
349
0
{
350
0
  *aResult = nullptr;
351
0
352
0
  bool notnull = false;
353
0
  if (!ReadIPDLParam(aMsg, aIter, aActor, &notnull)) {
354
0
    return false;
355
0
  }
356
0
  if (notnull) {
357
0
    mozilla::dom::IPCBlob ipcblob;
358
0
    if (!ReadIPDLParam(aMsg, aIter, aActor, &ipcblob)) {
359
0
      return false;
360
0
    }
361
0
    *aResult = mozilla::dom::IPCBlobUtils::Deserialize(ipcblob);
362
0
  }
363
0
  return true;
364
0
}
365
} // ipc namespace
366
} // mozilla namespace