dom/ipc/Blob.cpp

Sat, 03 Jan 2015 20:18:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Sat, 03 Jan 2015 20:18:00 +0100
branch
TOR_BUG_3246
changeset 7
129ffea94266
permissions
-rw-r--r--

Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.

michael@0 1 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 2 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 4
michael@0 5 #include "Blob.h"
michael@0 6
michael@0 7 #include "ContentChild.h"
michael@0 8 #include "ContentParent.h"
michael@0 9 #include "FileDescriptorSetChild.h"
michael@0 10 #include "jsapi.h"
michael@0 11 #include "mozilla/Assertions.h"
michael@0 12 #include "mozilla/DebugOnly.h"
michael@0 13 #include "mozilla/Monitor.h"
michael@0 14 #include "mozilla/unused.h"
michael@0 15 #include "mozilla/dom/PBlobStreamChild.h"
michael@0 16 #include "mozilla/dom/PBlobStreamParent.h"
michael@0 17 #include "mozilla/dom/PFileDescriptorSetParent.h"
michael@0 18 #include "mozilla/ipc/InputStreamUtils.h"
michael@0 19 #include "nsCOMPtr.h"
michael@0 20 #include "nsDOMFile.h"
michael@0 21 #include "nsIDOMFile.h"
michael@0 22 #include "nsIInputStream.h"
michael@0 23 #include "nsIIPCSerializableInputStream.h"
michael@0 24 #include "nsIMultiplexInputStream.h"
michael@0 25 #include "nsIRemoteBlob.h"
michael@0 26 #include "nsISeekableStream.h"
michael@0 27 #include "nsNetCID.h"
michael@0 28 #include "nsProxyRelease.h"
michael@0 29 #include "nsThreadUtils.h"
michael@0 30
michael@0 31 #define PRIVATE_REMOTE_INPUT_STREAM_IID \
michael@0 32 {0x30c7699f, 0x51d2, 0x48c8, {0xad, 0x56, 0xc0, 0x16, 0xd7, 0x6f, 0x71, 0x27}}
michael@0 33
michael@0 34 using namespace mozilla;
michael@0 35 using namespace mozilla::dom;
michael@0 36 using namespace mozilla::ipc;
michael@0 37
michael@0 38 namespace {
michael@0 39
michael@0 40 enum ActorType
michael@0 41 {
michael@0 42 ChildActor,
michael@0 43 ParentActor
michael@0 44 };
michael@0 45
michael@0 46 // Ensure that a nsCOMPtr/nsRefPtr is released on the main thread.
michael@0 47 template <template <class> class SmartPtr, class T>
michael@0 48 void
michael@0 49 ProxyReleaseToMainThread(SmartPtr<T>& aDoomed)
michael@0 50 {
michael@0 51 MOZ_ASSERT(!NS_IsMainThread());
michael@0 52
michael@0 53 nsCOMPtr<nsIThread> mainThread = do_GetMainThread();
michael@0 54 NS_ENSURE_TRUE_VOID(mainThread);
michael@0 55
michael@0 56 if (NS_FAILED(NS_ProxyRelease(mainThread, aDoomed, true))) {
michael@0 57 NS_WARNING("Failed to proxy release to main thread!");
michael@0 58 }
michael@0 59 }
michael@0 60
michael@0 61 class NS_NO_VTABLE IPrivateRemoteInputStream : public nsISupports
michael@0 62 {
michael@0 63 public:
michael@0 64 NS_DECLARE_STATIC_IID_ACCESSOR(PRIVATE_REMOTE_INPUT_STREAM_IID)
michael@0 65
michael@0 66 // This will return the underlying stream.
michael@0 67 virtual nsIInputStream*
michael@0 68 BlockAndGetInternalStream() = 0;
michael@0 69 };
michael@0 70
michael@0 71 NS_DEFINE_STATIC_IID_ACCESSOR(IPrivateRemoteInputStream,
michael@0 72 PRIVATE_REMOTE_INPUT_STREAM_IID)
michael@0 73
michael@0 74 // This class exists to keep a blob alive at least as long as its internal
michael@0 75 // stream.
michael@0 76 class BlobInputStreamTether : public nsIMultiplexInputStream,
michael@0 77 public nsISeekableStream,
michael@0 78 public nsIIPCSerializableInputStream
michael@0 79 {
michael@0 80 nsCOMPtr<nsIInputStream> mStream;
michael@0 81 nsCOMPtr<nsIDOMBlob> mSourceBlob;
michael@0 82
michael@0 83 nsIMultiplexInputStream* mWeakMultiplexStream;
michael@0 84 nsISeekableStream* mWeakSeekableStream;
michael@0 85 nsIIPCSerializableInputStream* mWeakSerializableStream;
michael@0 86
michael@0 87 public:
michael@0 88 NS_DECL_THREADSAFE_ISUPPORTS
michael@0 89 NS_FORWARD_NSIINPUTSTREAM(mStream->)
michael@0 90 NS_FORWARD_SAFE_NSIMULTIPLEXINPUTSTREAM(mWeakMultiplexStream)
michael@0 91 NS_FORWARD_SAFE_NSISEEKABLESTREAM(mWeakSeekableStream)
michael@0 92 NS_FORWARD_SAFE_NSIIPCSERIALIZABLEINPUTSTREAM(mWeakSerializableStream)
michael@0 93
michael@0 94 BlobInputStreamTether(nsIInputStream* aStream, nsIDOMBlob* aSourceBlob)
michael@0 95 : mStream(aStream), mSourceBlob(aSourceBlob), mWeakMultiplexStream(nullptr),
michael@0 96 mWeakSeekableStream(nullptr), mWeakSerializableStream(nullptr)
michael@0 97 {
michael@0 98 MOZ_ASSERT(aStream);
michael@0 99 MOZ_ASSERT(aSourceBlob);
michael@0 100
michael@0 101 nsCOMPtr<nsIMultiplexInputStream> multiplexStream =
michael@0 102 do_QueryInterface(aStream);
michael@0 103 if (multiplexStream) {
michael@0 104 MOZ_ASSERT(SameCOMIdentity(aStream, multiplexStream));
michael@0 105 mWeakMultiplexStream = multiplexStream;
michael@0 106 }
michael@0 107
michael@0 108 nsCOMPtr<nsISeekableStream> seekableStream = do_QueryInterface(aStream);
michael@0 109 if (seekableStream) {
michael@0 110 MOZ_ASSERT(SameCOMIdentity(aStream, seekableStream));
michael@0 111 mWeakSeekableStream = seekableStream;
michael@0 112 }
michael@0 113
michael@0 114 nsCOMPtr<nsIIPCSerializableInputStream> serializableStream =
michael@0 115 do_QueryInterface(aStream);
michael@0 116 if (serializableStream) {
michael@0 117 MOZ_ASSERT(SameCOMIdentity(aStream, serializableStream));
michael@0 118 mWeakSerializableStream = serializableStream;
michael@0 119 }
michael@0 120 }
michael@0 121
michael@0 122 protected:
michael@0 123 virtual ~BlobInputStreamTether()
michael@0 124 {
michael@0 125 MOZ_ASSERT(mStream);
michael@0 126 MOZ_ASSERT(mSourceBlob);
michael@0 127
michael@0 128 if (!NS_IsMainThread()) {
michael@0 129 mStream = nullptr;
michael@0 130 ProxyReleaseToMainThread(mSourceBlob);
michael@0 131 }
michael@0 132 }
michael@0 133 };
michael@0 134
michael@0 135 NS_IMPL_ADDREF(BlobInputStreamTether)
michael@0 136 NS_IMPL_RELEASE(BlobInputStreamTether)
michael@0 137
michael@0 138 NS_INTERFACE_MAP_BEGIN(BlobInputStreamTether)
michael@0 139 NS_INTERFACE_MAP_ENTRY(nsIInputStream)
michael@0 140 NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIMultiplexInputStream,
michael@0 141 mWeakMultiplexStream)
michael@0 142 NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsISeekableStream, mWeakSeekableStream)
michael@0 143 NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIIPCSerializableInputStream,
michael@0 144 mWeakSerializableStream)
michael@0 145 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIInputStream)
michael@0 146 NS_INTERFACE_MAP_END
michael@0 147
michael@0 148 class RemoteInputStream : public nsIInputStream,
michael@0 149 public nsISeekableStream,
michael@0 150 public nsIIPCSerializableInputStream,
michael@0 151 public IPrivateRemoteInputStream
michael@0 152 {
michael@0 153 mozilla::Monitor mMonitor;
michael@0 154 nsCOMPtr<nsIInputStream> mStream;
michael@0 155 nsCOMPtr<nsIDOMBlob> mSourceBlob;
michael@0 156 nsISeekableStream* mWeakSeekableStream;
michael@0 157 ActorType mOrigin;
michael@0 158
michael@0 159 public:
michael@0 160 NS_DECL_THREADSAFE_ISUPPORTS
michael@0 161
michael@0 162 RemoteInputStream(nsIDOMBlob* aSourceBlob, ActorType aOrigin)
michael@0 163 : mMonitor("RemoteInputStream.mMonitor"), mSourceBlob(aSourceBlob),
michael@0 164 mWeakSeekableStream(nullptr), mOrigin(aOrigin)
michael@0 165 {
michael@0 166 MOZ_ASSERT(NS_IsMainThread());
michael@0 167 MOZ_ASSERT(aSourceBlob);
michael@0 168 }
michael@0 169
michael@0 170 void
michael@0 171 Serialize(InputStreamParams& aParams,
michael@0 172 FileDescriptorArray& /* aFileDescriptors */)
michael@0 173 {
michael@0 174 nsCOMPtr<nsIRemoteBlob> remote = do_QueryInterface(mSourceBlob);
michael@0 175 MOZ_ASSERT(remote);
michael@0 176
michael@0 177 if (mOrigin == ParentActor) {
michael@0 178 aParams = RemoteInputStreamParams(
michael@0 179 static_cast<PBlobParent*>(remote->GetPBlob()), nullptr);
michael@0 180 } else {
michael@0 181 MOZ_ASSERT(mOrigin == ChildActor);
michael@0 182 aParams = RemoteInputStreamParams(
michael@0 183 nullptr, static_cast<PBlobChild*>(remote->GetPBlob()));
michael@0 184 }
michael@0 185 }
michael@0 186
michael@0 187 bool
michael@0 188 Deserialize(const InputStreamParams& aParams,
michael@0 189 const FileDescriptorArray& /* aFileDescriptors */)
michael@0 190 {
michael@0 191 // See InputStreamUtils.cpp to see how deserialization of a
michael@0 192 // RemoteInputStream is special-cased.
michael@0 193 MOZ_CRASH("RemoteInputStream should never be deserialized");
michael@0 194 }
michael@0 195
michael@0 196 void
michael@0 197 SetStream(nsIInputStream* aStream)
michael@0 198 {
michael@0 199 MOZ_ASSERT(NS_IsMainThread());
michael@0 200 MOZ_ASSERT(aStream);
michael@0 201
michael@0 202 nsCOMPtr<nsIInputStream> stream = aStream;
michael@0 203 nsCOMPtr<nsISeekableStream> seekableStream = do_QueryInterface(aStream);
michael@0 204
michael@0 205 MOZ_ASSERT_IF(seekableStream, SameCOMIdentity(aStream, seekableStream));
michael@0 206
michael@0 207 {
michael@0 208 mozilla::MonitorAutoLock lock(mMonitor);
michael@0 209
michael@0 210 MOZ_ASSERT(!mStream);
michael@0 211 MOZ_ASSERT(!mWeakSeekableStream);
michael@0 212
michael@0 213 mStream.swap(stream);
michael@0 214 mWeakSeekableStream = seekableStream;
michael@0 215
michael@0 216 mMonitor.Notify();
michael@0 217 }
michael@0 218 }
michael@0 219
michael@0 220 NS_IMETHOD
michael@0 221 Close() MOZ_OVERRIDE
michael@0 222 {
michael@0 223 nsresult rv = BlockAndWaitForStream();
michael@0 224 NS_ENSURE_SUCCESS(rv, rv);
michael@0 225
michael@0 226 nsCOMPtr<nsIDOMBlob> sourceBlob;
michael@0 227 mSourceBlob.swap(sourceBlob);
michael@0 228
michael@0 229 rv = mStream->Close();
michael@0 230 NS_ENSURE_SUCCESS(rv, rv);
michael@0 231
michael@0 232 return NS_OK;
michael@0 233 }
michael@0 234
michael@0 235 NS_IMETHOD
michael@0 236 Available(uint64_t* aAvailable) MOZ_OVERRIDE
michael@0 237 {
michael@0 238 // See large comment in FileInputStreamWrapper::Available.
michael@0 239 if (NS_IsMainThread()) {
michael@0 240 return NS_BASE_STREAM_CLOSED;
michael@0 241 }
michael@0 242
michael@0 243 nsresult rv = BlockAndWaitForStream();
michael@0 244 NS_ENSURE_SUCCESS(rv, rv);
michael@0 245
michael@0 246 rv = mStream->Available(aAvailable);
michael@0 247 NS_ENSURE_SUCCESS(rv, rv);
michael@0 248
michael@0 249 return NS_OK;
michael@0 250 }
michael@0 251
michael@0 252 NS_IMETHOD
michael@0 253 Read(char* aBuffer, uint32_t aCount, uint32_t* aResult) MOZ_OVERRIDE
michael@0 254 {
michael@0 255 nsresult rv = BlockAndWaitForStream();
michael@0 256 NS_ENSURE_SUCCESS(rv, rv);
michael@0 257
michael@0 258 rv = mStream->Read(aBuffer, aCount, aResult);
michael@0 259 NS_ENSURE_SUCCESS(rv, rv);
michael@0 260
michael@0 261 return NS_OK;
michael@0 262 }
michael@0 263
michael@0 264 NS_IMETHOD
michael@0 265 ReadSegments(nsWriteSegmentFun aWriter, void* aClosure, uint32_t aCount,
michael@0 266 uint32_t* aResult) MOZ_OVERRIDE
michael@0 267 {
michael@0 268 nsresult rv = BlockAndWaitForStream();
michael@0 269 NS_ENSURE_SUCCESS(rv, rv);
michael@0 270
michael@0 271 rv = mStream->ReadSegments(aWriter, aClosure, aCount, aResult);
michael@0 272 NS_ENSURE_SUCCESS(rv, rv);
michael@0 273
michael@0 274 return NS_OK;
michael@0 275 }
michael@0 276
michael@0 277 NS_IMETHOD
michael@0 278 IsNonBlocking(bool* aNonBlocking) MOZ_OVERRIDE
michael@0 279 {
michael@0 280 NS_ENSURE_ARG_POINTER(aNonBlocking);
michael@0 281
michael@0 282 *aNonBlocking = false;
michael@0 283 return NS_OK;
michael@0 284 }
michael@0 285
michael@0 286 NS_IMETHOD
michael@0 287 Seek(int32_t aWhence, int64_t aOffset) MOZ_OVERRIDE
michael@0 288 {
michael@0 289 nsresult rv = BlockAndWaitForStream();
michael@0 290 NS_ENSURE_SUCCESS(rv, rv);
michael@0 291
michael@0 292 if (!mWeakSeekableStream) {
michael@0 293 NS_WARNING("Underlying blob stream is not seekable!");
michael@0 294 return NS_ERROR_NO_INTERFACE;
michael@0 295 }
michael@0 296
michael@0 297 rv = mWeakSeekableStream->Seek(aWhence, aOffset);
michael@0 298 NS_ENSURE_SUCCESS(rv, rv);
michael@0 299
michael@0 300 return NS_OK;
michael@0 301 }
michael@0 302
michael@0 303 NS_IMETHOD
michael@0 304 Tell(int64_t* aResult)
michael@0 305 {
michael@0 306 // We can cheat here and assume that we're going to start at 0 if we don't
michael@0 307 // yet have our stream. Though, really, this should abort since most input
michael@0 308 // streams could block here.
michael@0 309 if (NS_IsMainThread() && !mStream) {
michael@0 310 *aResult = 0;
michael@0 311 return NS_OK;
michael@0 312 }
michael@0 313
michael@0 314 nsresult rv = BlockAndWaitForStream();
michael@0 315 NS_ENSURE_SUCCESS(rv, rv);
michael@0 316
michael@0 317 if (!mWeakSeekableStream) {
michael@0 318 NS_WARNING("Underlying blob stream is not seekable!");
michael@0 319 return NS_ERROR_NO_INTERFACE;
michael@0 320 }
michael@0 321
michael@0 322 rv = mWeakSeekableStream->Tell(aResult);
michael@0 323 NS_ENSURE_SUCCESS(rv, rv);
michael@0 324
michael@0 325 return NS_OK;
michael@0 326 }
michael@0 327
michael@0 328 NS_IMETHOD
michael@0 329 SetEOF()
michael@0 330 {
michael@0 331 nsresult rv = BlockAndWaitForStream();
michael@0 332 NS_ENSURE_SUCCESS(rv, rv);
michael@0 333
michael@0 334 if (!mWeakSeekableStream) {
michael@0 335 NS_WARNING("Underlying blob stream is not seekable!");
michael@0 336 return NS_ERROR_NO_INTERFACE;
michael@0 337 }
michael@0 338
michael@0 339 rv = mWeakSeekableStream->SetEOF();
michael@0 340 NS_ENSURE_SUCCESS(rv, rv);
michael@0 341
michael@0 342 return NS_OK;
michael@0 343 }
michael@0 344
michael@0 345 virtual nsIInputStream*
michael@0 346 BlockAndGetInternalStream()
michael@0 347 {
michael@0 348 MOZ_ASSERT(!NS_IsMainThread());
michael@0 349
michael@0 350 nsresult rv = BlockAndWaitForStream();
michael@0 351 NS_ENSURE_SUCCESS(rv, nullptr);
michael@0 352
michael@0 353 return mStream;
michael@0 354 }
michael@0 355
michael@0 356 private:
michael@0 357 virtual ~RemoteInputStream()
michael@0 358 {
michael@0 359 if (!NS_IsMainThread()) {
michael@0 360 mStream = nullptr;
michael@0 361 mWeakSeekableStream = nullptr;
michael@0 362 ProxyReleaseToMainThread(mSourceBlob);
michael@0 363 }
michael@0 364 }
michael@0 365
michael@0 366 void
michael@0 367 ReallyBlockAndWaitForStream()
michael@0 368 {
michael@0 369 mozilla::DebugOnly<bool> waited;
michael@0 370
michael@0 371 {
michael@0 372 mozilla::MonitorAutoLock lock(mMonitor);
michael@0 373
michael@0 374 waited = !mStream;
michael@0 375
michael@0 376 while (!mStream) {
michael@0 377 mMonitor.Wait();
michael@0 378 }
michael@0 379 }
michael@0 380
michael@0 381 MOZ_ASSERT(mStream);
michael@0 382
michael@0 383 #ifdef DEBUG
michael@0 384 if (waited && mWeakSeekableStream) {
michael@0 385 int64_t position;
michael@0 386 MOZ_ASSERT(NS_SUCCEEDED(mWeakSeekableStream->Tell(&position)),
michael@0 387 "Failed to determine initial stream position!");
michael@0 388 MOZ_ASSERT(!position, "Stream not starting at 0!");
michael@0 389 }
michael@0 390 #endif
michael@0 391 }
michael@0 392
michael@0 393 nsresult
michael@0 394 BlockAndWaitForStream()
michael@0 395 {
michael@0 396 if (NS_IsMainThread()) {
michael@0 397 NS_WARNING("Blocking the main thread is not supported!");
michael@0 398 return NS_ERROR_FAILURE;
michael@0 399 }
michael@0 400
michael@0 401 ReallyBlockAndWaitForStream();
michael@0 402
michael@0 403 return NS_OK;
michael@0 404 }
michael@0 405
michael@0 406 bool
michael@0 407 IsSeekableStream()
michael@0 408 {
michael@0 409 if (NS_IsMainThread()) {
michael@0 410 if (!mStream) {
michael@0 411 NS_WARNING("Don't know if this stream is seekable yet!");
michael@0 412 return true;
michael@0 413 }
michael@0 414 }
michael@0 415 else {
michael@0 416 ReallyBlockAndWaitForStream();
michael@0 417 }
michael@0 418
michael@0 419 return !!mWeakSeekableStream;
michael@0 420 }
michael@0 421 };
michael@0 422
michael@0 423 NS_IMPL_ADDREF(RemoteInputStream)
michael@0 424 NS_IMPL_RELEASE(RemoteInputStream)
michael@0 425
michael@0 426 NS_INTERFACE_MAP_BEGIN(RemoteInputStream)
michael@0 427 NS_INTERFACE_MAP_ENTRY(nsIInputStream)
michael@0 428 NS_INTERFACE_MAP_ENTRY(nsIIPCSerializableInputStream)
michael@0 429 NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsISeekableStream, IsSeekableStream())
michael@0 430 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIInputStream)
michael@0 431 NS_INTERFACE_MAP_ENTRY(IPrivateRemoteInputStream)
michael@0 432 NS_INTERFACE_MAP_END
michael@0 433
michael@0 434 class InputStreamChild MOZ_FINAL
michael@0 435 : public PBlobStreamChild
michael@0 436 {
michael@0 437 nsRefPtr<RemoteInputStream> mRemoteStream;
michael@0 438
michael@0 439 public:
michael@0 440 InputStreamChild(RemoteInputStream* aRemoteStream)
michael@0 441 : mRemoteStream(aRemoteStream)
michael@0 442 {
michael@0 443 MOZ_ASSERT(NS_IsMainThread());
michael@0 444 MOZ_ASSERT(aRemoteStream);
michael@0 445 }
michael@0 446
michael@0 447 InputStreamChild()
michael@0 448 {
michael@0 449 MOZ_ASSERT(NS_IsMainThread());
michael@0 450 }
michael@0 451
michael@0 452 private:
michael@0 453 // This method is only called by the IPDL message machinery.
michael@0 454 virtual bool
michael@0 455 Recv__delete__(const InputStreamParams& aParams,
michael@0 456 const OptionalFileDescriptorSet& aFDs) MOZ_OVERRIDE;
michael@0 457 };
michael@0 458
michael@0 459 class InputStreamParent MOZ_FINAL
michael@0 460 : public PBlobStreamParent
michael@0 461 {
michael@0 462 nsRefPtr<RemoteInputStream> mRemoteStream;
michael@0 463
michael@0 464 public:
michael@0 465 InputStreamParent(RemoteInputStream* aRemoteStream)
michael@0 466 : mRemoteStream(aRemoteStream)
michael@0 467 {
michael@0 468 MOZ_ASSERT(NS_IsMainThread());
michael@0 469 MOZ_ASSERT(aRemoteStream);
michael@0 470 }
michael@0 471
michael@0 472 InputStreamParent()
michael@0 473 {
michael@0 474 MOZ_ASSERT(NS_IsMainThread());
michael@0 475 }
michael@0 476
michael@0 477 private:
michael@0 478 // This method is only called by the IPDL message machinery.
michael@0 479 virtual bool
michael@0 480 Recv__delete__(const InputStreamParams& aParams,
michael@0 481 const OptionalFileDescriptorSet& aFDs) MOZ_OVERRIDE;
michael@0 482 };
michael@0 483
michael@0 484 nsDOMFileBase*
michael@0 485 ToConcreteBlob(nsIDOMBlob* aBlob)
michael@0 486 {
michael@0 487 // XXX This is only safe so long as all blob implementations in our tree
michael@0 488 // inherit nsDOMFileBase. If that ever changes then this will need to grow
michael@0 489 // a real interface or something.
michael@0 490 return static_cast<nsDOMFileBase*>(aBlob);
michael@0 491 }
michael@0 492
michael@0 493 } // anonymous namespace
michael@0 494
michael@0 495 // Each instance of this class will be dispatched to the network stream thread
michael@0 496 // pool to run the first time where it will open the file input stream. It will
michael@0 497 // then dispatch itself back to the main thread to send the child process its
michael@0 498 // response (assuming that the child has not crashed). The runnable will then
michael@0 499 // dispatch itself to the thread pool again in order to close the file input
michael@0 500 // stream.
michael@0 501 class BlobParent::OpenStreamRunnable MOZ_FINAL
michael@0 502 : public nsRunnable
michael@0 503 {
michael@0 504 friend class nsRevocableEventPtr<OpenStreamRunnable>;
michael@0 505
michael@0 506 // Only safe to access these pointers if mRevoked is false!
michael@0 507 BlobParent* mBlobActor;
michael@0 508 PBlobStreamParent* mStreamActor;
michael@0 509
michael@0 510 nsCOMPtr<nsIInputStream> mStream;
michael@0 511 nsCOMPtr<nsIIPCSerializableInputStream> mSerializable;
michael@0 512 nsCOMPtr<nsIEventTarget> mTarget;
michael@0 513
michael@0 514 bool mRevoked;
michael@0 515 bool mClosing;
michael@0 516
michael@0 517 public:
michael@0 518 OpenStreamRunnable(BlobParent* aBlobActor,
michael@0 519 PBlobStreamParent* aStreamActor,
michael@0 520 nsIInputStream* aStream,
michael@0 521 nsIIPCSerializableInputStream* aSerializable,
michael@0 522 nsIEventTarget* aTarget)
michael@0 523 : mBlobActor(aBlobActor), mStreamActor(aStreamActor), mStream(aStream),
michael@0 524 mSerializable(aSerializable), mTarget(aTarget), mRevoked(false),
michael@0 525 mClosing(false)
michael@0 526 {
michael@0 527 MOZ_ASSERT(NS_IsMainThread());
michael@0 528 MOZ_ASSERT(aBlobActor);
michael@0 529 MOZ_ASSERT(aStreamActor);
michael@0 530 MOZ_ASSERT(aStream);
michael@0 531 // aSerializable may be null.
michael@0 532 MOZ_ASSERT(aTarget);
michael@0 533 }
michael@0 534
michael@0 535 NS_IMETHOD
michael@0 536 Run()
michael@0 537 {
michael@0 538 if (NS_IsMainThread()) {
michael@0 539 return SendResponse();
michael@0 540 }
michael@0 541
michael@0 542 if (!mClosing) {
michael@0 543 return OpenStream();
michael@0 544 }
michael@0 545
michael@0 546 return CloseStream();
michael@0 547 }
michael@0 548
michael@0 549 nsresult
michael@0 550 Dispatch()
michael@0 551 {
michael@0 552 MOZ_ASSERT(NS_IsMainThread());
michael@0 553 MOZ_ASSERT(mTarget);
michael@0 554
michael@0 555 nsresult rv = mTarget->Dispatch(this, NS_DISPATCH_NORMAL);
michael@0 556 NS_ENSURE_SUCCESS(rv, rv);
michael@0 557
michael@0 558 return NS_OK;
michael@0 559 }
michael@0 560
michael@0 561 private:
michael@0 562 void
michael@0 563 Revoke()
michael@0 564 {
michael@0 565 MOZ_ASSERT(NS_IsMainThread());
michael@0 566 #ifdef DEBUG
michael@0 567 mBlobActor = nullptr;
michael@0 568 mStreamActor = nullptr;
michael@0 569 #endif
michael@0 570 mRevoked = true;
michael@0 571 }
michael@0 572
michael@0 573 nsresult
michael@0 574 OpenStream()
michael@0 575 {
michael@0 576 MOZ_ASSERT(!NS_IsMainThread());
michael@0 577 MOZ_ASSERT(mStream);
michael@0 578
michael@0 579 if (!mSerializable) {
michael@0 580 nsCOMPtr<IPrivateRemoteInputStream> remoteStream =
michael@0 581 do_QueryInterface(mStream);
michael@0 582 MOZ_ASSERT(remoteStream, "Must QI to IPrivateRemoteInputStream here!");
michael@0 583
michael@0 584 nsCOMPtr<nsIInputStream> realStream =
michael@0 585 remoteStream->BlockAndGetInternalStream();
michael@0 586 NS_ENSURE_TRUE(realStream, NS_ERROR_FAILURE);
michael@0 587
michael@0 588 mSerializable = do_QueryInterface(realStream);
michael@0 589 if (!mSerializable) {
michael@0 590 MOZ_ASSERT(false, "Must be serializable!");
michael@0 591 return NS_ERROR_FAILURE;
michael@0 592 }
michael@0 593
michael@0 594 mStream.swap(realStream);
michael@0 595 }
michael@0 596
michael@0 597 // To force the stream open we call Available(). We don't actually care
michael@0 598 // how much data is available.
michael@0 599 uint64_t available;
michael@0 600 if (NS_FAILED(mStream->Available(&available))) {
michael@0 601 NS_WARNING("Available failed on this stream!");
michael@0 602 }
michael@0 603
michael@0 604 nsresult rv = NS_DispatchToMainThread(this, NS_DISPATCH_NORMAL);
michael@0 605 NS_ENSURE_SUCCESS(rv, rv);
michael@0 606
michael@0 607 return NS_OK;
michael@0 608 }
michael@0 609
michael@0 610 nsresult
michael@0 611 CloseStream()
michael@0 612 {
michael@0 613 MOZ_ASSERT(!NS_IsMainThread());
michael@0 614 MOZ_ASSERT(mStream);
michael@0 615
michael@0 616 // Going to always release here.
michael@0 617 nsCOMPtr<nsIInputStream> stream;
michael@0 618 mStream.swap(stream);
michael@0 619
michael@0 620 nsresult rv = stream->Close();
michael@0 621 NS_ENSURE_SUCCESS(rv, rv);
michael@0 622
michael@0 623 return NS_OK;
michael@0 624 }
michael@0 625
michael@0 626 nsresult
michael@0 627 SendResponse()
michael@0 628 {
michael@0 629 MOZ_ASSERT(NS_IsMainThread());
michael@0 630
michael@0 631 MOZ_ASSERT(mStream);
michael@0 632 MOZ_ASSERT(mSerializable);
michael@0 633 MOZ_ASSERT(mTarget);
michael@0 634 MOZ_ASSERT(!mClosing);
michael@0 635
michael@0 636 nsCOMPtr<nsIIPCSerializableInputStream> serializable;
michael@0 637 mSerializable.swap(serializable);
michael@0 638
michael@0 639 if (mRevoked) {
michael@0 640 MOZ_ASSERT(!mBlobActor);
michael@0 641 MOZ_ASSERT(!mStreamActor);
michael@0 642 }
michael@0 643 else {
michael@0 644 MOZ_ASSERT(mBlobActor);
michael@0 645 MOZ_ASSERT(mStreamActor);
michael@0 646
michael@0 647 InputStreamParams params;
michael@0 648 nsAutoTArray<FileDescriptor, 10> fds;
michael@0 649 serializable->Serialize(params, fds);
michael@0 650
michael@0 651 MOZ_ASSERT(params.type() != InputStreamParams::T__None);
michael@0 652
michael@0 653 PFileDescriptorSetParent* fdSet = nullptr;
michael@0 654
michael@0 655 if (!fds.IsEmpty()) {
michael@0 656 auto* manager = static_cast<ContentParent*>(mBlobActor->Manager());
michael@0 657 MOZ_ASSERT(manager);
michael@0 658
michael@0 659 fdSet = manager->SendPFileDescriptorSetConstructor(fds[0]);
michael@0 660 if (fdSet) {
michael@0 661 for (uint32_t index = 1; index < fds.Length(); index++) {
michael@0 662 unused << fdSet->SendAddFileDescriptor(fds[index]);
michael@0 663 }
michael@0 664 }
michael@0 665 }
michael@0 666
michael@0 667 OptionalFileDescriptorSet optionalFDs;
michael@0 668 if (fdSet) {
michael@0 669 optionalFDs = fdSet;
michael@0 670 } else {
michael@0 671 optionalFDs = mozilla::void_t();
michael@0 672 }
michael@0 673
michael@0 674 unused <<
michael@0 675 PBlobStreamParent::Send__delete__(mStreamActor, params, optionalFDs);
michael@0 676
michael@0 677 mBlobActor->NoteRunnableCompleted(this);
michael@0 678
michael@0 679 #ifdef DEBUG
michael@0 680 mBlobActor = nullptr;
michael@0 681 mStreamActor = nullptr;
michael@0 682 #endif
michael@0 683 }
michael@0 684
michael@0 685 mClosing = true;
michael@0 686
michael@0 687 nsCOMPtr<nsIEventTarget> target;
michael@0 688 mTarget.swap(target);
michael@0 689
michael@0 690 nsresult rv = target->Dispatch(this, NS_DISPATCH_NORMAL);
michael@0 691 NS_ENSURE_SUCCESS(rv, rv);
michael@0 692
michael@0 693 return NS_OK;
michael@0 694 }
michael@0 695 };
michael@0 696
michael@0 697 /*******************************************************************************
michael@0 698 * BlobChild::RemoteBlob Declaration
michael@0 699 ******************************************************************************/
michael@0 700
michael@0 701 class BlobChild::RemoteBlob MOZ_FINAL
michael@0 702 : public nsDOMFile
michael@0 703 , public nsIRemoteBlob
michael@0 704 {
michael@0 705 class StreamHelper;
michael@0 706 class SliceHelper;
michael@0 707
michael@0 708 BlobChild* mActor;
michael@0 709
michael@0 710 public:
michael@0 711 RemoteBlob(const nsAString& aName,
michael@0 712 const nsAString& aContentType,
michael@0 713 uint64_t aLength,
michael@0 714 uint64_t aModDate)
michael@0 715 : nsDOMFile(aName, aContentType, aLength, aModDate)
michael@0 716 , mActor(nullptr)
michael@0 717 {
michael@0 718 mImmutable = true;
michael@0 719 }
michael@0 720
michael@0 721 RemoteBlob(const nsAString& aContentType, uint64_t aLength)
michael@0 722 : nsDOMFile(aContentType, aLength)
michael@0 723 , mActor(nullptr)
michael@0 724 {
michael@0 725 mImmutable = true;
michael@0 726 }
michael@0 727
michael@0 728 RemoteBlob()
michael@0 729 : nsDOMFile(EmptyString(), EmptyString(), UINT64_MAX, UINT64_MAX)
michael@0 730 , mActor(nullptr)
michael@0 731 {
michael@0 732 mImmutable = true;
michael@0 733 }
michael@0 734
michael@0 735 void
michael@0 736 SetActor(BlobChild* aActor)
michael@0 737 {
michael@0 738 MOZ_ASSERT(!aActor || !mActor);
michael@0 739 mActor = aActor;
michael@0 740 }
michael@0 741
michael@0 742 NS_DECL_ISUPPORTS_INHERITED
michael@0 743
michael@0 744 virtual already_AddRefed<nsIDOMBlob>
michael@0 745 CreateSlice(uint64_t aStart, uint64_t aLength, const nsAString& aContentType)
michael@0 746 MOZ_OVERRIDE;
michael@0 747
michael@0 748 NS_IMETHOD
michael@0 749 GetInternalStream(nsIInputStream** aStream) MOZ_OVERRIDE;
michael@0 750
michael@0 751 NS_IMETHOD
michael@0 752 GetLastModifiedDate(JSContext* cx,
michael@0 753 JS::MutableHandle<JS::Value> aLastModifiedDate)
michael@0 754 MOZ_OVERRIDE;
michael@0 755
michael@0 756 virtual void*
michael@0 757 GetPBlob() MOZ_OVERRIDE;
michael@0 758
michael@0 759 private:
michael@0 760 ~RemoteBlob()
michael@0 761 {
michael@0 762 if (mActor) {
michael@0 763 mActor->NoteDyingRemoteBlob();
michael@0 764 }
michael@0 765 }
michael@0 766 };
michael@0 767
michael@0 768 class BlobChild::RemoteBlob::StreamHelper MOZ_FINAL
michael@0 769 : public nsRunnable
michael@0 770 {
michael@0 771 mozilla::Monitor mMonitor;
michael@0 772 BlobChild* mActor;
michael@0 773 nsCOMPtr<nsIDOMBlob> mSourceBlob;
michael@0 774 nsRefPtr<RemoteInputStream> mInputStream;
michael@0 775 bool mDone;
michael@0 776
michael@0 777 public:
michael@0 778 StreamHelper(BlobChild* aActor, nsIDOMBlob* aSourceBlob)
michael@0 779 : mMonitor("BlobChild::RemoteBlob::StreamHelper::mMonitor")
michael@0 780 , mActor(aActor)
michael@0 781 , mSourceBlob(aSourceBlob)
michael@0 782 , mDone(false)
michael@0 783 {
michael@0 784 // This may be created on any thread.
michael@0 785 MOZ_ASSERT(aActor);
michael@0 786 MOZ_ASSERT(aSourceBlob);
michael@0 787 }
michael@0 788
michael@0 789 nsresult
michael@0 790 GetStream(nsIInputStream** aInputStream)
michael@0 791 {
michael@0 792 // This may be called on any thread.
michael@0 793 MOZ_ASSERT(aInputStream);
michael@0 794 MOZ_ASSERT(mActor);
michael@0 795 MOZ_ASSERT(!mInputStream);
michael@0 796 MOZ_ASSERT(!mDone);
michael@0 797
michael@0 798 if (NS_IsMainThread()) {
michael@0 799 RunInternal(false);
michael@0 800 }
michael@0 801 else {
michael@0 802 nsCOMPtr<nsIThread> mainThread = do_GetMainThread();
michael@0 803 NS_ENSURE_TRUE(mainThread, NS_ERROR_FAILURE);
michael@0 804
michael@0 805 nsresult rv = mainThread->Dispatch(this, NS_DISPATCH_NORMAL);
michael@0 806 NS_ENSURE_SUCCESS(rv, rv);
michael@0 807
michael@0 808 {
michael@0 809 MonitorAutoLock lock(mMonitor);
michael@0 810 while (!mDone) {
michael@0 811 lock.Wait();
michael@0 812 }
michael@0 813 }
michael@0 814 }
michael@0 815
michael@0 816 MOZ_ASSERT(!mActor);
michael@0 817 MOZ_ASSERT(mDone);
michael@0 818
michael@0 819 if (!mInputStream) {
michael@0 820 return NS_ERROR_UNEXPECTED;
michael@0 821 }
michael@0 822
michael@0 823 mInputStream.forget(aInputStream);
michael@0 824 return NS_OK;
michael@0 825 }
michael@0 826
michael@0 827 NS_IMETHOD
michael@0 828 Run()
michael@0 829 {
michael@0 830 MOZ_ASSERT(NS_IsMainThread());
michael@0 831 RunInternal(true);
michael@0 832 return NS_OK;
michael@0 833 }
michael@0 834
michael@0 835 private:
michael@0 836 void
michael@0 837 RunInternal(bool aNotify)
michael@0 838 {
michael@0 839 MOZ_ASSERT(NS_IsMainThread());
michael@0 840 MOZ_ASSERT(mActor);
michael@0 841 MOZ_ASSERT(!mInputStream);
michael@0 842 MOZ_ASSERT(!mDone);
michael@0 843
michael@0 844 nsRefPtr<RemoteInputStream> stream =
michael@0 845 new RemoteInputStream(mSourceBlob, ChildActor);
michael@0 846
michael@0 847 InputStreamChild* streamActor = new InputStreamChild(stream);
michael@0 848 if (mActor->SendPBlobStreamConstructor(streamActor)) {
michael@0 849 stream.swap(mInputStream);
michael@0 850 }
michael@0 851
michael@0 852 mActor = nullptr;
michael@0 853
michael@0 854 if (aNotify) {
michael@0 855 MonitorAutoLock lock(mMonitor);
michael@0 856 mDone = true;
michael@0 857 lock.Notify();
michael@0 858 }
michael@0 859 else {
michael@0 860 mDone = true;
michael@0 861 }
michael@0 862 }
michael@0 863 };
michael@0 864
michael@0 865 class BlobChild::RemoteBlob::SliceHelper MOZ_FINAL
michael@0 866 : public nsRunnable
michael@0 867 {
michael@0 868 mozilla::Monitor mMonitor;
michael@0 869 BlobChild* mActor;
michael@0 870 nsCOMPtr<nsIDOMBlob> mSlice;
michael@0 871 uint64_t mStart;
michael@0 872 uint64_t mLength;
michael@0 873 nsString mContentType;
michael@0 874 bool mDone;
michael@0 875
michael@0 876 public:
michael@0 877 SliceHelper(BlobChild* aActor)
michael@0 878 : mMonitor("BlobChild::RemoteBlob::SliceHelper::mMonitor")
michael@0 879 , mActor(aActor)
michael@0 880 , mStart(0)
michael@0 881 , mLength(0)
michael@0 882 , mDone(false)
michael@0 883 {
michael@0 884 // This may be created on any thread.
michael@0 885 MOZ_ASSERT(aActor);
michael@0 886 }
michael@0 887
michael@0 888 nsresult
michael@0 889 GetSlice(uint64_t aStart,
michael@0 890 uint64_t aLength,
michael@0 891 const nsAString& aContentType,
michael@0 892 nsIDOMBlob** aSlice)
michael@0 893 {
michael@0 894 // This may be called on any thread.
michael@0 895 MOZ_ASSERT(aSlice);
michael@0 896 MOZ_ASSERT(mActor);
michael@0 897 MOZ_ASSERT(!mSlice);
michael@0 898 MOZ_ASSERT(!mDone);
michael@0 899
michael@0 900 mStart = aStart;
michael@0 901 mLength = aLength;
michael@0 902 mContentType = aContentType;
michael@0 903
michael@0 904 if (NS_IsMainThread()) {
michael@0 905 RunInternal(false);
michael@0 906 }
michael@0 907 else {
michael@0 908 nsCOMPtr<nsIThread> mainThread = do_GetMainThread();
michael@0 909 NS_ENSURE_TRUE(mainThread, NS_ERROR_FAILURE);
michael@0 910
michael@0 911 nsresult rv = mainThread->Dispatch(this, NS_DISPATCH_NORMAL);
michael@0 912 NS_ENSURE_SUCCESS(rv, rv);
michael@0 913
michael@0 914 {
michael@0 915 MonitorAutoLock lock(mMonitor);
michael@0 916 while (!mDone) {
michael@0 917 lock.Wait();
michael@0 918 }
michael@0 919 }
michael@0 920 }
michael@0 921
michael@0 922 MOZ_ASSERT(!mActor);
michael@0 923 MOZ_ASSERT(mDone);
michael@0 924
michael@0 925 if (!mSlice) {
michael@0 926 return NS_ERROR_UNEXPECTED;
michael@0 927 }
michael@0 928
michael@0 929 mSlice.forget(aSlice);
michael@0 930 return NS_OK;
michael@0 931 }
michael@0 932
michael@0 933 NS_IMETHOD
michael@0 934 Run()
michael@0 935 {
michael@0 936 MOZ_ASSERT(NS_IsMainThread());
michael@0 937 RunInternal(true);
michael@0 938 return NS_OK;
michael@0 939 }
michael@0 940
michael@0 941 private:
michael@0 942 void
michael@0 943 RunInternal(bool aNotify)
michael@0 944 {
michael@0 945 MOZ_ASSERT(NS_IsMainThread());
michael@0 946 MOZ_ASSERT(mActor);
michael@0 947 MOZ_ASSERT(!mSlice);
michael@0 948 MOZ_ASSERT(!mDone);
michael@0 949
michael@0 950 NS_ENSURE_TRUE_VOID(mActor->Manager());
michael@0 951
michael@0 952 NormalBlobConstructorParams normalParams;
michael@0 953 normalParams.contentType() = mContentType;
michael@0 954 normalParams.length() = mLength;
michael@0 955
michael@0 956 auto* manager = static_cast<ContentChild*>(mActor->Manager());
michael@0 957 MOZ_ASSERT(manager);
michael@0 958
michael@0 959 BlobChild* newActor = BlobChild::Create(manager, normalParams);
michael@0 960 MOZ_ASSERT(newActor);
michael@0 961
michael@0 962 SlicedBlobConstructorParams slicedParams;
michael@0 963 slicedParams.contentType() = mContentType;
michael@0 964 slicedParams.begin() = mStart;
michael@0 965 slicedParams.end() = mStart + mLength;
michael@0 966 slicedParams.sourceChild() = mActor;
michael@0 967
michael@0 968 ParentBlobConstructorParams otherSideParams;
michael@0 969 otherSideParams.blobParams() = slicedParams;
michael@0 970 otherSideParams.optionalInputStreamParams() = mozilla::void_t();
michael@0 971
michael@0 972 if (mActor->Manager()->SendPBlobConstructor(newActor, otherSideParams)) {
michael@0 973 mSlice = newActor->GetBlob();
michael@0 974 }
michael@0 975
michael@0 976 mActor = nullptr;
michael@0 977
michael@0 978 if (aNotify) {
michael@0 979 MonitorAutoLock lock(mMonitor);
michael@0 980 mDone = true;
michael@0 981 lock.Notify();
michael@0 982 }
michael@0 983 else {
michael@0 984 mDone = true;
michael@0 985 }
michael@0 986 }
michael@0 987 };
michael@0 988
michael@0 989 /*******************************************************************************
michael@0 990 * BlobChild::RemoteBlob Implementation
michael@0 991 ******************************************************************************/
michael@0 992
michael@0 993 NS_IMPL_ISUPPORTS_INHERITED(BlobChild::RemoteBlob, nsDOMFile, nsIRemoteBlob)
michael@0 994
michael@0 995 already_AddRefed<nsIDOMBlob>
michael@0 996 BlobChild::
michael@0 997 RemoteBlob::CreateSlice(uint64_t aStart,
michael@0 998 uint64_t aLength,
michael@0 999 const nsAString& aContentType)
michael@0 1000 {
michael@0 1001 if (!mActor) {
michael@0 1002 return nullptr;
michael@0 1003 }
michael@0 1004
michael@0 1005 nsRefPtr<SliceHelper> helper = new SliceHelper(mActor);
michael@0 1006
michael@0 1007 nsCOMPtr<nsIDOMBlob> slice;
michael@0 1008 nsresult rv =
michael@0 1009 helper->GetSlice(aStart, aLength, aContentType, getter_AddRefs(slice));
michael@0 1010 NS_ENSURE_SUCCESS(rv, nullptr);
michael@0 1011
michael@0 1012 return slice.forget();
michael@0 1013 }
michael@0 1014
michael@0 1015 NS_IMETHODIMP
michael@0 1016 BlobChild::
michael@0 1017 RemoteBlob::GetInternalStream(nsIInputStream** aStream)
michael@0 1018 {
michael@0 1019 if (!mActor) {
michael@0 1020 return NS_ERROR_UNEXPECTED;
michael@0 1021 }
michael@0 1022
michael@0 1023 nsRefPtr<StreamHelper> helper = new StreamHelper(mActor, this);
michael@0 1024 return helper->GetStream(aStream);
michael@0 1025 }
michael@0 1026
michael@0 1027 NS_IMETHODIMP
michael@0 1028 BlobChild::
michael@0 1029 RemoteBlob::GetLastModifiedDate(JSContext* cx,
michael@0 1030 JS::MutableHandle<JS::Value> aLastModifiedDate)
michael@0 1031 {
michael@0 1032 if (IsDateUnknown()) {
michael@0 1033 aLastModifiedDate.setNull();
michael@0 1034 } else {
michael@0 1035 JSObject* date = JS_NewDateObjectMsec(cx, mLastModificationDate);
michael@0 1036 if (!date) {
michael@0 1037 return NS_ERROR_OUT_OF_MEMORY;
michael@0 1038 }
michael@0 1039 aLastModifiedDate.setObject(*date);
michael@0 1040 }
michael@0 1041 return NS_OK;
michael@0 1042 }
michael@0 1043
michael@0 1044 void*
michael@0 1045 BlobChild::
michael@0 1046 RemoteBlob::GetPBlob()
michael@0 1047 {
michael@0 1048 return static_cast<PBlobChild*>(mActor);
michael@0 1049 }
michael@0 1050
michael@0 1051 /*******************************************************************************
michael@0 1052 * BlobChild
michael@0 1053 ******************************************************************************/
michael@0 1054
michael@0 1055 BlobChild::BlobChild(ContentChild* aManager, nsIDOMBlob* aBlob)
michael@0 1056 : mBlob(aBlob)
michael@0 1057 , mRemoteBlob(nullptr)
michael@0 1058 , mStrongManager(aManager)
michael@0 1059 , mOwnsBlob(true)
michael@0 1060 , mBlobIsFile(false)
michael@0 1061 {
michael@0 1062 MOZ_ASSERT(NS_IsMainThread());
michael@0 1063 MOZ_ASSERT(aManager);
michael@0 1064 MOZ_ASSERT(aBlob);
michael@0 1065
michael@0 1066 aBlob->AddRef();
michael@0 1067
michael@0 1068 nsCOMPtr<nsIDOMFile> file = do_QueryInterface(aBlob);
michael@0 1069 mBlobIsFile = !!file;
michael@0 1070 }
michael@0 1071
michael@0 1072 BlobChild::BlobChild(ContentChild* aManager,
michael@0 1073 const ChildBlobConstructorParams& aParams)
michael@0 1074 : mBlob(nullptr)
michael@0 1075 , mRemoteBlob(nullptr)
michael@0 1076 , mStrongManager(aManager)
michael@0 1077 , mOwnsBlob(false)
michael@0 1078 , mBlobIsFile(false)
michael@0 1079 {
michael@0 1080 MOZ_ASSERT(NS_IsMainThread());
michael@0 1081 MOZ_ASSERT(aManager);
michael@0 1082
michael@0 1083 ChildBlobConstructorParams::Type paramsType = aParams.type();
michael@0 1084
michael@0 1085 mBlobIsFile =
michael@0 1086 paramsType == ChildBlobConstructorParams::TFileBlobConstructorParams ||
michael@0 1087 paramsType == ChildBlobConstructorParams::TMysteryBlobConstructorParams;
michael@0 1088
michael@0 1089 nsRefPtr<RemoteBlob> remoteBlob = CreateRemoteBlob(aParams);
michael@0 1090 MOZ_ASSERT(remoteBlob);
michael@0 1091
michael@0 1092 remoteBlob->SetActor(this);
michael@0 1093 remoteBlob.forget(&mRemoteBlob);
michael@0 1094
michael@0 1095 mBlob = mRemoteBlob;
michael@0 1096 mOwnsBlob = true;
michael@0 1097 }
michael@0 1098
michael@0 1099 BlobChild::~BlobChild()
michael@0 1100 {
michael@0 1101 }
michael@0 1102
michael@0 1103 BlobChild*
michael@0 1104 BlobChild::Create(ContentChild* aManager,
michael@0 1105 const ChildBlobConstructorParams& aParams)
michael@0 1106 {
michael@0 1107 MOZ_ASSERT(NS_IsMainThread());
michael@0 1108 MOZ_ASSERT(aManager);
michael@0 1109
michael@0 1110 switch (aParams.type()) {
michael@0 1111 case ChildBlobConstructorParams::TNormalBlobConstructorParams:
michael@0 1112 case ChildBlobConstructorParams::TFileBlobConstructorParams:
michael@0 1113 case ChildBlobConstructorParams::TMysteryBlobConstructorParams:
michael@0 1114 return new BlobChild(aManager, aParams);
michael@0 1115
michael@0 1116 case ChildBlobConstructorParams::TSlicedBlobConstructorParams: {
michael@0 1117 const SlicedBlobConstructorParams& params =
michael@0 1118 aParams.get_SlicedBlobConstructorParams();
michael@0 1119
michael@0 1120 auto* actor =
michael@0 1121 const_cast<BlobChild*>(
michael@0 1122 static_cast<const BlobChild*>(params.sourceChild()));
michael@0 1123 MOZ_ASSERT(actor);
michael@0 1124
michael@0 1125 nsCOMPtr<nsIDOMBlob> source = actor->GetBlob();
michael@0 1126 MOZ_ASSERT(source);
michael@0 1127
michael@0 1128 nsCOMPtr<nsIDOMBlob> slice;
michael@0 1129 nsresult rv =
michael@0 1130 source->Slice(params.begin(), params.end(), params.contentType(), 3,
michael@0 1131 getter_AddRefs(slice));
michael@0 1132 NS_ENSURE_SUCCESS(rv, nullptr);
michael@0 1133
michael@0 1134 return new BlobChild(aManager, slice);
michael@0 1135 }
michael@0 1136
michael@0 1137 default:
michael@0 1138 MOZ_CRASH("Unknown params!");
michael@0 1139 }
michael@0 1140
michael@0 1141 return nullptr;
michael@0 1142 }
michael@0 1143
michael@0 1144 already_AddRefed<nsIDOMBlob>
michael@0 1145 BlobChild::GetBlob()
michael@0 1146 {
michael@0 1147 MOZ_ASSERT(NS_IsMainThread());
michael@0 1148 MOZ_ASSERT(mBlob);
michael@0 1149
michael@0 1150 nsCOMPtr<nsIDOMBlob> blob;
michael@0 1151
michael@0 1152 // Remote blobs are held alive until the first call to GetBlob. Thereafter we
michael@0 1153 // only hold a weak reference. Normal blobs are held alive until the actor is
michael@0 1154 // destroyed.
michael@0 1155 if (mRemoteBlob && mOwnsBlob) {
michael@0 1156 blob = dont_AddRef(mBlob);
michael@0 1157 mOwnsBlob = false;
michael@0 1158 }
michael@0 1159 else {
michael@0 1160 blob = mBlob;
michael@0 1161 }
michael@0 1162
michael@0 1163 MOZ_ASSERT(blob);
michael@0 1164
michael@0 1165 return blob.forget();
michael@0 1166 }
michael@0 1167
michael@0 1168 bool
michael@0 1169 BlobChild::SetMysteryBlobInfo(const nsString& aName,
michael@0 1170 const nsString& aContentType,
michael@0 1171 uint64_t aLength,
michael@0 1172 uint64_t aLastModifiedDate)
michael@0 1173 {
michael@0 1174 MOZ_ASSERT(NS_IsMainThread());
michael@0 1175 MOZ_ASSERT(mBlob);
michael@0 1176 MOZ_ASSERT(mRemoteBlob);
michael@0 1177 MOZ_ASSERT(aLastModifiedDate != UINT64_MAX);
michael@0 1178
michael@0 1179 ToConcreteBlob(mBlob)->SetLazyData(aName, aContentType, aLength,
michael@0 1180 aLastModifiedDate);
michael@0 1181
michael@0 1182 FileBlobConstructorParams params(aName, aContentType, aLength,
michael@0 1183 aLastModifiedDate);
michael@0 1184 return SendResolveMystery(params);
michael@0 1185 }
michael@0 1186
michael@0 1187 bool
michael@0 1188 BlobChild::SetMysteryBlobInfo(const nsString& aContentType, uint64_t aLength)
michael@0 1189 {
michael@0 1190 MOZ_ASSERT(NS_IsMainThread());
michael@0 1191 MOZ_ASSERT(mBlob);
michael@0 1192 MOZ_ASSERT(mRemoteBlob);
michael@0 1193
michael@0 1194 nsString voidString;
michael@0 1195 voidString.SetIsVoid(true);
michael@0 1196
michael@0 1197 ToConcreteBlob(mBlob)->SetLazyData(voidString, aContentType, aLength,
michael@0 1198 UINT64_MAX);
michael@0 1199
michael@0 1200 NormalBlobConstructorParams params(aContentType, aLength);
michael@0 1201 return SendResolveMystery(params);
michael@0 1202 }
michael@0 1203
michael@0 1204 already_AddRefed<BlobChild::RemoteBlob>
michael@0 1205 BlobChild::CreateRemoteBlob(const ChildBlobConstructorParams& aParams)
michael@0 1206 {
michael@0 1207 MOZ_ASSERT(NS_IsMainThread());
michael@0 1208
michael@0 1209 nsRefPtr<RemoteBlob> remoteBlob;
michael@0 1210
michael@0 1211 switch (aParams.type()) {
michael@0 1212 case ChildBlobConstructorParams::TNormalBlobConstructorParams: {
michael@0 1213 const NormalBlobConstructorParams& params =
michael@0 1214 aParams.get_NormalBlobConstructorParams();
michael@0 1215 remoteBlob = new RemoteBlob(params.contentType(), params.length());
michael@0 1216 break;
michael@0 1217 }
michael@0 1218
michael@0 1219 case ChildBlobConstructorParams::TFileBlobConstructorParams: {
michael@0 1220 const FileBlobConstructorParams& params =
michael@0 1221 aParams.get_FileBlobConstructorParams();
michael@0 1222 remoteBlob =
michael@0 1223 new RemoteBlob(params.name(), params.contentType(), params.length(),
michael@0 1224 params.modDate());
michael@0 1225 break;
michael@0 1226 }
michael@0 1227
michael@0 1228 case ChildBlobConstructorParams::TMysteryBlobConstructorParams: {
michael@0 1229 remoteBlob = new RemoteBlob();
michael@0 1230 break;
michael@0 1231 }
michael@0 1232
michael@0 1233 default:
michael@0 1234 MOZ_CRASH("Unknown params!");
michael@0 1235 }
michael@0 1236
michael@0 1237 MOZ_ASSERT(remoteBlob);
michael@0 1238
michael@0 1239 if (NS_FAILED(remoteBlob->SetMutable(false))) {
michael@0 1240 MOZ_CRASH("Failed to make remote blob immutable!");
michael@0 1241 }
michael@0 1242
michael@0 1243 return remoteBlob.forget();
michael@0 1244 }
michael@0 1245
michael@0 1246 void
michael@0 1247 BlobChild::NoteDyingRemoteBlob()
michael@0 1248 {
michael@0 1249 MOZ_ASSERT(mBlob);
michael@0 1250 MOZ_ASSERT(mRemoteBlob);
michael@0 1251 MOZ_ASSERT(!mOwnsBlob);
michael@0 1252
michael@0 1253 // This may be called on any thread due to the fact that RemoteBlob is
michael@0 1254 // designed to be passed between threads. We must start the shutdown process
michael@0 1255 // on the main thread, so we proxy here if necessary.
michael@0 1256 if (!NS_IsMainThread()) {
michael@0 1257 nsCOMPtr<nsIRunnable> runnable =
michael@0 1258 NS_NewNonOwningRunnableMethod(this, &BlobChild::NoteDyingRemoteBlob);
michael@0 1259 if (NS_FAILED(NS_DispatchToMainThread(runnable))) {
michael@0 1260 MOZ_ASSERT(false, "Should never fail!");
michael@0 1261 }
michael@0 1262
michael@0 1263 return;
michael@0 1264 }
michael@0 1265
michael@0 1266 // Must do this before calling Send__delete__ or we'll crash there trying to
michael@0 1267 // access a dangling pointer.
michael@0 1268 mBlob = nullptr;
michael@0 1269 mRemoteBlob = nullptr;
michael@0 1270
michael@0 1271 PBlobChild::Send__delete__(this);
michael@0 1272 }
michael@0 1273
michael@0 1274 void
michael@0 1275 BlobChild::ActorDestroy(ActorDestroyReason aWhy)
michael@0 1276 {
michael@0 1277 MOZ_ASSERT(NS_IsMainThread());
michael@0 1278
michael@0 1279 if (mRemoteBlob) {
michael@0 1280 mRemoteBlob->SetActor(nullptr);
michael@0 1281 }
michael@0 1282
michael@0 1283 if (mBlob && mOwnsBlob) {
michael@0 1284 mBlob->Release();
michael@0 1285 }
michael@0 1286
michael@0 1287 mStrongManager = nullptr;
michael@0 1288 }
michael@0 1289
michael@0 1290 PBlobStreamChild*
michael@0 1291 BlobChild::AllocPBlobStreamChild()
michael@0 1292 {
michael@0 1293 MOZ_ASSERT(NS_IsMainThread());
michael@0 1294
michael@0 1295 return new InputStreamChild();
michael@0 1296 }
michael@0 1297
michael@0 1298 bool
michael@0 1299 BlobChild::RecvPBlobStreamConstructor(PBlobStreamChild* aActor)
michael@0 1300 {
michael@0 1301 MOZ_ASSERT(NS_IsMainThread());
michael@0 1302 MOZ_ASSERT(aActor);
michael@0 1303 MOZ_ASSERT(mBlob);
michael@0 1304 MOZ_ASSERT(!mRemoteBlob);
michael@0 1305
michael@0 1306 nsCOMPtr<nsIInputStream> stream;
michael@0 1307 nsresult rv = mBlob->GetInternalStream(getter_AddRefs(stream));
michael@0 1308 NS_ENSURE_SUCCESS(rv, false);
michael@0 1309
michael@0 1310 nsCOMPtr<nsIIPCSerializableInputStream> serializable =
michael@0 1311 do_QueryInterface(stream);
michael@0 1312 if (!serializable) {
michael@0 1313 MOZ_ASSERT(false, "Must be serializable!");
michael@0 1314 return false;
michael@0 1315 }
michael@0 1316
michael@0 1317 InputStreamParams params;
michael@0 1318 nsTArray<FileDescriptor> fds;
michael@0 1319 serializable->Serialize(params, fds);
michael@0 1320
michael@0 1321 MOZ_ASSERT(params.type() != InputStreamParams::T__None);
michael@0 1322 MOZ_ASSERT(fds.IsEmpty());
michael@0 1323
michael@0 1324 return aActor->Send__delete__(aActor, params, mozilla::void_t());
michael@0 1325 }
michael@0 1326
michael@0 1327 bool
michael@0 1328 BlobChild::DeallocPBlobStreamChild(PBlobStreamChild* aActor)
michael@0 1329 {
michael@0 1330 MOZ_ASSERT(NS_IsMainThread());
michael@0 1331
michael@0 1332 delete static_cast<InputStreamChild*>(aActor);
michael@0 1333 return true;
michael@0 1334 }
michael@0 1335
michael@0 1336 bool
michael@0 1337 BlobChild::RecvResolveMystery(const ResolveMysteryParams& aParams)
michael@0 1338 {
michael@0 1339 MOZ_ASSERT(NS_IsMainThread());
michael@0 1340 MOZ_ASSERT(mBlob);
michael@0 1341 MOZ_ASSERT(!mRemoteBlob);
michael@0 1342 MOZ_ASSERT(mOwnsBlob);
michael@0 1343
michael@0 1344 if (!mBlobIsFile) {
michael@0 1345 MOZ_ASSERT(false, "Must always be a file!");
michael@0 1346 return false;
michael@0 1347 }
michael@0 1348
michael@0 1349 nsDOMFileBase* blob = ToConcreteBlob(mBlob);
michael@0 1350
michael@0 1351 switch (aParams.type()) {
michael@0 1352 case ResolveMysteryParams::TNormalBlobConstructorParams: {
michael@0 1353 const NormalBlobConstructorParams& params =
michael@0 1354 aParams.get_NormalBlobConstructorParams();
michael@0 1355 nsString voidString;
michael@0 1356 voidString.SetIsVoid(true);
michael@0 1357 blob->SetLazyData(voidString, params.contentType(), params.length(),
michael@0 1358 UINT64_MAX);
michael@0 1359 break;
michael@0 1360 }
michael@0 1361
michael@0 1362 case ResolveMysteryParams::TFileBlobConstructorParams: {
michael@0 1363 const FileBlobConstructorParams& params =
michael@0 1364 aParams.get_FileBlobConstructorParams();
michael@0 1365 blob->SetLazyData(params.name(), params.contentType(), params.length(),
michael@0 1366 params.modDate());
michael@0 1367 break;
michael@0 1368 }
michael@0 1369
michael@0 1370 default:
michael@0 1371 MOZ_CRASH("Unknown params!");
michael@0 1372 }
michael@0 1373
michael@0 1374 return true;
michael@0 1375 }
michael@0 1376
michael@0 1377 /*******************************************************************************
michael@0 1378 * BlobParent::RemoteBlob Declaration
michael@0 1379 ******************************************************************************/
michael@0 1380
michael@0 1381 class BlobParent::RemoteBlob MOZ_FINAL
michael@0 1382 : public nsDOMFile
michael@0 1383 , public nsIRemoteBlob
michael@0 1384 {
michael@0 1385 class StreamHelper;
michael@0 1386 class SliceHelper;
michael@0 1387
michael@0 1388 BlobParent* mActor;
michael@0 1389 InputStreamParams mInputStreamParams;
michael@0 1390
michael@0 1391 public:
michael@0 1392 RemoteBlob(const nsAString& aName,
michael@0 1393 const nsAString& aContentType,
michael@0 1394 uint64_t aLength,
michael@0 1395 uint64_t aModDate)
michael@0 1396 : nsDOMFile(aName, aContentType, aLength, aModDate)
michael@0 1397 , mActor(nullptr)
michael@0 1398 {
michael@0 1399 mImmutable = true;
michael@0 1400 }
michael@0 1401
michael@0 1402 RemoteBlob(const nsAString& aContentType, uint64_t aLength)
michael@0 1403 : nsDOMFile(aContentType, aLength)
michael@0 1404 , mActor(nullptr)
michael@0 1405 {
michael@0 1406 mImmutable = true;
michael@0 1407 }
michael@0 1408
michael@0 1409 RemoteBlob()
michael@0 1410 : nsDOMFile(EmptyString(), EmptyString(), UINT64_MAX, UINT64_MAX)
michael@0 1411 , mActor(nullptr)
michael@0 1412 {
michael@0 1413 mImmutable = true;
michael@0 1414 }
michael@0 1415
michael@0 1416 void
michael@0 1417 SetActor(BlobParent* aActor)
michael@0 1418 {
michael@0 1419 MOZ_ASSERT(!aActor || !mActor);
michael@0 1420 mActor = aActor;
michael@0 1421 }
michael@0 1422
michael@0 1423 void
michael@0 1424 MaybeSetInputStream(const ParentBlobConstructorParams& aParams)
michael@0 1425 {
michael@0 1426 if (aParams.optionalInputStreamParams().type() ==
michael@0 1427 OptionalInputStreamParams::TInputStreamParams) {
michael@0 1428 mInputStreamParams =
michael@0 1429 aParams.optionalInputStreamParams().get_InputStreamParams();
michael@0 1430 }
michael@0 1431 }
michael@0 1432
michael@0 1433 NS_DECL_ISUPPORTS_INHERITED
michael@0 1434
michael@0 1435 virtual already_AddRefed<nsIDOMBlob>
michael@0 1436 CreateSlice(uint64_t aStart, uint64_t aLength, const nsAString& aContentType)
michael@0 1437 MOZ_OVERRIDE;
michael@0 1438
michael@0 1439 NS_IMETHOD
michael@0 1440 GetInternalStream(nsIInputStream** aStream) MOZ_OVERRIDE;
michael@0 1441
michael@0 1442 NS_IMETHOD
michael@0 1443 GetLastModifiedDate(JSContext* cx,
michael@0 1444 JS::MutableHandle<JS::Value> aLastModifiedDate)
michael@0 1445 MOZ_OVERRIDE;
michael@0 1446
michael@0 1447 virtual void*
michael@0 1448 GetPBlob() MOZ_OVERRIDE;
michael@0 1449
michael@0 1450 private:
michael@0 1451 ~RemoteBlob()
michael@0 1452 {
michael@0 1453 if (mActor) {
michael@0 1454 mActor->NoteDyingRemoteBlob();
michael@0 1455 }
michael@0 1456 }
michael@0 1457 };
michael@0 1458
michael@0 1459 class BlobParent::RemoteBlob::StreamHelper MOZ_FINAL
michael@0 1460 : public nsRunnable
michael@0 1461 {
michael@0 1462 mozilla::Monitor mMonitor;
michael@0 1463 BlobParent* mActor;
michael@0 1464 nsCOMPtr<nsIDOMBlob> mSourceBlob;
michael@0 1465 nsRefPtr<RemoteInputStream> mInputStream;
michael@0 1466 bool mDone;
michael@0 1467
michael@0 1468 public:
michael@0 1469 StreamHelper(BlobParent* aActor, nsIDOMBlob* aSourceBlob)
michael@0 1470 : mMonitor("BlobParent::RemoteBlob::StreamHelper::mMonitor")
michael@0 1471 , mActor(aActor)
michael@0 1472 , mSourceBlob(aSourceBlob)
michael@0 1473 , mDone(false)
michael@0 1474 {
michael@0 1475 // This may be created on any thread.
michael@0 1476 MOZ_ASSERT(aActor);
michael@0 1477 MOZ_ASSERT(aSourceBlob);
michael@0 1478 }
michael@0 1479
michael@0 1480 nsresult
michael@0 1481 GetStream(nsIInputStream** aInputStream)
michael@0 1482 {
michael@0 1483 // This may be called on any thread.
michael@0 1484 MOZ_ASSERT(aInputStream);
michael@0 1485 MOZ_ASSERT(mActor);
michael@0 1486 MOZ_ASSERT(!mInputStream);
michael@0 1487 MOZ_ASSERT(!mDone);
michael@0 1488
michael@0 1489 if (NS_IsMainThread()) {
michael@0 1490 RunInternal(false);
michael@0 1491 }
michael@0 1492 else {
michael@0 1493 nsCOMPtr<nsIThread> mainThread = do_GetMainThread();
michael@0 1494 NS_ENSURE_TRUE(mainThread, NS_ERROR_FAILURE);
michael@0 1495
michael@0 1496 nsresult rv = mainThread->Dispatch(this, NS_DISPATCH_NORMAL);
michael@0 1497 NS_ENSURE_SUCCESS(rv, rv);
michael@0 1498
michael@0 1499 {
michael@0 1500 MonitorAutoLock lock(mMonitor);
michael@0 1501 while (!mDone) {
michael@0 1502 lock.Wait();
michael@0 1503 }
michael@0 1504 }
michael@0 1505 }
michael@0 1506
michael@0 1507 MOZ_ASSERT(!mActor);
michael@0 1508 MOZ_ASSERT(mDone);
michael@0 1509
michael@0 1510 if (!mInputStream) {
michael@0 1511 return NS_ERROR_UNEXPECTED;
michael@0 1512 }
michael@0 1513
michael@0 1514 mInputStream.forget(aInputStream);
michael@0 1515 return NS_OK;
michael@0 1516 }
michael@0 1517
michael@0 1518 NS_IMETHOD
michael@0 1519 Run()
michael@0 1520 {
michael@0 1521 MOZ_ASSERT(NS_IsMainThread());
michael@0 1522 RunInternal(true);
michael@0 1523 return NS_OK;
michael@0 1524 }
michael@0 1525
michael@0 1526 private:
michael@0 1527 void
michael@0 1528 RunInternal(bool aNotify)
michael@0 1529 {
michael@0 1530 MOZ_ASSERT(NS_IsMainThread());
michael@0 1531 MOZ_ASSERT(mActor);
michael@0 1532 MOZ_ASSERT(!mInputStream);
michael@0 1533 MOZ_ASSERT(!mDone);
michael@0 1534
michael@0 1535 nsRefPtr<RemoteInputStream> stream =
michael@0 1536 new RemoteInputStream(mSourceBlob, ParentActor);
michael@0 1537
michael@0 1538 InputStreamParent* streamActor = new InputStreamParent(stream);
michael@0 1539 if (mActor->SendPBlobStreamConstructor(streamActor)) {
michael@0 1540 stream.swap(mInputStream);
michael@0 1541 }
michael@0 1542
michael@0 1543 mActor = nullptr;
michael@0 1544
michael@0 1545 if (aNotify) {
michael@0 1546 MonitorAutoLock lock(mMonitor);
michael@0 1547 mDone = true;
michael@0 1548 lock.Notify();
michael@0 1549 }
michael@0 1550 else {
michael@0 1551 mDone = true;
michael@0 1552 }
michael@0 1553 }
michael@0 1554 };
michael@0 1555
michael@0 1556 class BlobParent::RemoteBlob::SliceHelper MOZ_FINAL
michael@0 1557 : public nsRunnable
michael@0 1558 {
michael@0 1559 mozilla::Monitor mMonitor;
michael@0 1560 BlobParent* mActor;
michael@0 1561 nsCOMPtr<nsIDOMBlob> mSlice;
michael@0 1562 uint64_t mStart;
michael@0 1563 uint64_t mLength;
michael@0 1564 nsString mContentType;
michael@0 1565 bool mDone;
michael@0 1566
michael@0 1567 public:
michael@0 1568 SliceHelper(BlobParent* aActor)
michael@0 1569 : mMonitor("BlobParent::RemoteBlob::SliceHelper::mMonitor")
michael@0 1570 , mActor(aActor)
michael@0 1571 , mStart(0)
michael@0 1572 , mLength(0)
michael@0 1573 , mDone(false)
michael@0 1574 {
michael@0 1575 // This may be created on any thread.
michael@0 1576 MOZ_ASSERT(aActor);
michael@0 1577 }
michael@0 1578
michael@0 1579 nsresult
michael@0 1580 GetSlice(uint64_t aStart,
michael@0 1581 uint64_t aLength,
michael@0 1582 const nsAString& aContentType,
michael@0 1583 nsIDOMBlob** aSlice)
michael@0 1584 {
michael@0 1585 // This may be called on any thread.
michael@0 1586 MOZ_ASSERT(aSlice);
michael@0 1587 MOZ_ASSERT(mActor);
michael@0 1588 MOZ_ASSERT(!mSlice);
michael@0 1589 MOZ_ASSERT(!mDone);
michael@0 1590
michael@0 1591 mStart = aStart;
michael@0 1592 mLength = aLength;
michael@0 1593 mContentType = aContentType;
michael@0 1594
michael@0 1595 if (NS_IsMainThread()) {
michael@0 1596 RunInternal(false);
michael@0 1597 }
michael@0 1598 else {
michael@0 1599 nsCOMPtr<nsIThread> mainThread = do_GetMainThread();
michael@0 1600 NS_ENSURE_TRUE(mainThread, NS_ERROR_FAILURE);
michael@0 1601
michael@0 1602 nsresult rv = mainThread->Dispatch(this, NS_DISPATCH_NORMAL);
michael@0 1603 NS_ENSURE_SUCCESS(rv, rv);
michael@0 1604
michael@0 1605 {
michael@0 1606 MonitorAutoLock lock(mMonitor);
michael@0 1607 while (!mDone) {
michael@0 1608 lock.Wait();
michael@0 1609 }
michael@0 1610 }
michael@0 1611 }
michael@0 1612
michael@0 1613 MOZ_ASSERT(!mActor);
michael@0 1614 MOZ_ASSERT(mDone);
michael@0 1615
michael@0 1616 if (!mSlice) {
michael@0 1617 return NS_ERROR_UNEXPECTED;
michael@0 1618 }
michael@0 1619
michael@0 1620 mSlice.forget(aSlice);
michael@0 1621 return NS_OK;
michael@0 1622 }
michael@0 1623
michael@0 1624 NS_IMETHOD
michael@0 1625 Run()
michael@0 1626 {
michael@0 1627 MOZ_ASSERT(NS_IsMainThread());
michael@0 1628 RunInternal(true);
michael@0 1629 return NS_OK;
michael@0 1630 }
michael@0 1631
michael@0 1632 private:
michael@0 1633 void
michael@0 1634 RunInternal(bool aNotify)
michael@0 1635 {
michael@0 1636 MOZ_ASSERT(NS_IsMainThread());
michael@0 1637 MOZ_ASSERT(mActor);
michael@0 1638 MOZ_ASSERT(!mSlice);
michael@0 1639 MOZ_ASSERT(!mDone);
michael@0 1640
michael@0 1641 NS_ENSURE_TRUE_VOID(mActor->Manager());
michael@0 1642
michael@0 1643 NormalBlobConstructorParams normalParams;
michael@0 1644 normalParams.contentType() = mContentType;
michael@0 1645 normalParams.length() = mLength;
michael@0 1646
michael@0 1647 ParentBlobConstructorParams params;
michael@0 1648 params.blobParams() = normalParams;
michael@0 1649 params.optionalInputStreamParams() = void_t();
michael@0 1650
michael@0 1651 auto* manager = static_cast<ContentParent*>(mActor->Manager());
michael@0 1652 MOZ_ASSERT(manager);
michael@0 1653
michael@0 1654 BlobParent* newActor = BlobParent::Create(manager, params);
michael@0 1655 MOZ_ASSERT(newActor);
michael@0 1656
michael@0 1657 SlicedBlobConstructorParams slicedParams;
michael@0 1658 slicedParams.contentType() = mContentType;
michael@0 1659 slicedParams.begin() = mStart;
michael@0 1660 slicedParams.end() = mStart + mLength;
michael@0 1661 slicedParams.sourceParent() = mActor;
michael@0 1662
michael@0 1663 ChildBlobConstructorParams otherSideParams = slicedParams;
michael@0 1664
michael@0 1665 if (mActor->Manager()->SendPBlobConstructor(newActor, otherSideParams)) {
michael@0 1666 mSlice = newActor->GetBlob();
michael@0 1667 }
michael@0 1668
michael@0 1669 mActor = nullptr;
michael@0 1670
michael@0 1671 if (aNotify) {
michael@0 1672 MonitorAutoLock lock(mMonitor);
michael@0 1673 mDone = true;
michael@0 1674 lock.Notify();
michael@0 1675 }
michael@0 1676 else {
michael@0 1677 mDone = true;
michael@0 1678 }
michael@0 1679 }
michael@0 1680 };
michael@0 1681
michael@0 1682 /*******************************************************************************
michael@0 1683 * BlobChild::RemoteBlob Implementation
michael@0 1684 ******************************************************************************/
michael@0 1685
michael@0 1686 NS_IMPL_ISUPPORTS_INHERITED(BlobParent::RemoteBlob, nsDOMFile, nsIRemoteBlob)
michael@0 1687
michael@0 1688 already_AddRefed<nsIDOMBlob>
michael@0 1689 BlobParent::
michael@0 1690 RemoteBlob::CreateSlice(uint64_t aStart,
michael@0 1691 uint64_t aLength,
michael@0 1692 const nsAString& aContentType)
michael@0 1693 {
michael@0 1694 if (!mActor) {
michael@0 1695 return nullptr;
michael@0 1696 }
michael@0 1697
michael@0 1698 nsRefPtr<SliceHelper> helper = new SliceHelper(mActor);
michael@0 1699
michael@0 1700 nsCOMPtr<nsIDOMBlob> slice;
michael@0 1701 nsresult rv =
michael@0 1702 helper->GetSlice(aStart, aLength, aContentType, getter_AddRefs(slice));
michael@0 1703 NS_ENSURE_SUCCESS(rv, nullptr);
michael@0 1704
michael@0 1705 return slice.forget();
michael@0 1706 }
michael@0 1707
michael@0 1708 NS_IMETHODIMP
michael@0 1709 BlobParent::
michael@0 1710 RemoteBlob::GetInternalStream(nsIInputStream** aStream)
michael@0 1711 {
michael@0 1712 if (mInputStreamParams.type() != InputStreamParams::T__None) {
michael@0 1713 nsTArray<FileDescriptor> fds;
michael@0 1714 nsCOMPtr<nsIInputStream> realStream =
michael@0 1715 DeserializeInputStream(mInputStreamParams, fds);
michael@0 1716 if (!realStream) {
michael@0 1717 NS_WARNING("Failed to deserialize stream!");
michael@0 1718 return NS_ERROR_UNEXPECTED;
michael@0 1719 }
michael@0 1720
michael@0 1721 nsCOMPtr<nsIInputStream> stream =
michael@0 1722 new BlobInputStreamTether(realStream, this);
michael@0 1723 stream.forget(aStream);
michael@0 1724 return NS_OK;
michael@0 1725 }
michael@0 1726
michael@0 1727 if (!mActor) {
michael@0 1728 return NS_ERROR_UNEXPECTED;
michael@0 1729 }
michael@0 1730
michael@0 1731 nsRefPtr<StreamHelper> helper = new StreamHelper(mActor, this);
michael@0 1732 return helper->GetStream(aStream);
michael@0 1733 }
michael@0 1734
michael@0 1735 NS_IMETHODIMP
michael@0 1736 BlobParent::
michael@0 1737 RemoteBlob::GetLastModifiedDate(JSContext* cx,
michael@0 1738 JS::MutableHandle<JS::Value> aLastModifiedDate)
michael@0 1739 {
michael@0 1740 if (IsDateUnknown()) {
michael@0 1741 aLastModifiedDate.setNull();
michael@0 1742 } else {
michael@0 1743 JSObject* date = JS_NewDateObjectMsec(cx, mLastModificationDate);
michael@0 1744 if (!date) {
michael@0 1745 return NS_ERROR_OUT_OF_MEMORY;
michael@0 1746 }
michael@0 1747 aLastModifiedDate.setObject(*date);
michael@0 1748 }
michael@0 1749 return NS_OK;
michael@0 1750 }
michael@0 1751
michael@0 1752 void*
michael@0 1753 BlobParent::
michael@0 1754 RemoteBlob::GetPBlob()
michael@0 1755 {
michael@0 1756 return static_cast<PBlobParent*>(mActor);
michael@0 1757 }
michael@0 1758
michael@0 1759 /*******************************************************************************
michael@0 1760 * BlobParent
michael@0 1761 ******************************************************************************/
michael@0 1762
michael@0 1763 BlobParent::BlobParent(ContentParent* aManager, nsIDOMBlob* aBlob)
michael@0 1764 : mBlob(aBlob)
michael@0 1765 , mRemoteBlob(nullptr)
michael@0 1766 , mStrongManager(aManager)
michael@0 1767 , mOwnsBlob(true)
michael@0 1768 , mBlobIsFile(false)
michael@0 1769 {
michael@0 1770 MOZ_ASSERT(NS_IsMainThread());
michael@0 1771 MOZ_ASSERT(aManager);
michael@0 1772 MOZ_ASSERT(aBlob);
michael@0 1773
michael@0 1774 aBlob->AddRef();
michael@0 1775
michael@0 1776 nsCOMPtr<nsIDOMFile> file = do_QueryInterface(aBlob);
michael@0 1777 mBlobIsFile = !!file;
michael@0 1778 }
michael@0 1779
michael@0 1780 BlobParent::BlobParent(ContentParent* aManager,
michael@0 1781 const ParentBlobConstructorParams& aParams)
michael@0 1782 : mBlob(nullptr)
michael@0 1783 , mRemoteBlob(nullptr)
michael@0 1784 , mStrongManager(aManager)
michael@0 1785 , mOwnsBlob(false)
michael@0 1786 , mBlobIsFile(false)
michael@0 1787 {
michael@0 1788 MOZ_ASSERT(NS_IsMainThread());
michael@0 1789 MOZ_ASSERT(aManager);
michael@0 1790
michael@0 1791 ChildBlobConstructorParams::Type paramsType = aParams.blobParams().type();
michael@0 1792
michael@0 1793 mBlobIsFile =
michael@0 1794 paramsType == ChildBlobConstructorParams::TFileBlobConstructorParams ||
michael@0 1795 paramsType == ChildBlobConstructorParams::TMysteryBlobConstructorParams;
michael@0 1796
michael@0 1797 nsRefPtr<RemoteBlob> remoteBlob = CreateRemoteBlob(aParams);
michael@0 1798 MOZ_ASSERT(remoteBlob);
michael@0 1799
michael@0 1800 remoteBlob->SetActor(this);
michael@0 1801 remoteBlob->MaybeSetInputStream(aParams);
michael@0 1802 remoteBlob.forget(&mRemoteBlob);
michael@0 1803
michael@0 1804 mBlob = mRemoteBlob;
michael@0 1805 mOwnsBlob = true;
michael@0 1806 }
michael@0 1807
michael@0 1808 BlobParent::~BlobParent()
michael@0 1809 {
michael@0 1810 }
michael@0 1811
michael@0 1812 BlobParent*
michael@0 1813 BlobParent::Create(ContentParent* aManager,
michael@0 1814 const ParentBlobConstructorParams& aParams)
michael@0 1815 {
michael@0 1816 MOZ_ASSERT(NS_IsMainThread());
michael@0 1817 MOZ_ASSERT(aManager);
michael@0 1818
michael@0 1819 const ChildBlobConstructorParams& blobParams = aParams.blobParams();
michael@0 1820
michael@0 1821 switch (blobParams.type()) {
michael@0 1822 case ChildBlobConstructorParams::TNormalBlobConstructorParams:
michael@0 1823 case ChildBlobConstructorParams::TFileBlobConstructorParams:
michael@0 1824 case ChildBlobConstructorParams::TMysteryBlobConstructorParams:
michael@0 1825 return new BlobParent(aManager, aParams);
michael@0 1826
michael@0 1827 case ChildBlobConstructorParams::TSlicedBlobConstructorParams: {
michael@0 1828 const SlicedBlobConstructorParams& params =
michael@0 1829 blobParams.get_SlicedBlobConstructorParams();
michael@0 1830
michael@0 1831 auto* actor =
michael@0 1832 const_cast<BlobParent*>(
michael@0 1833 static_cast<const BlobParent*>(params.sourceParent()));
michael@0 1834 MOZ_ASSERT(actor);
michael@0 1835
michael@0 1836 nsCOMPtr<nsIDOMBlob> source = actor->GetBlob();
michael@0 1837 MOZ_ASSERT(source);
michael@0 1838
michael@0 1839 nsCOMPtr<nsIDOMBlob> slice;
michael@0 1840 nsresult rv =
michael@0 1841 source->Slice(params.begin(), params.end(), params.contentType(), 3,
michael@0 1842 getter_AddRefs(slice));
michael@0 1843 NS_ENSURE_SUCCESS(rv, nullptr);
michael@0 1844
michael@0 1845 return new BlobParent(aManager, slice);
michael@0 1846 }
michael@0 1847
michael@0 1848 default:
michael@0 1849 MOZ_CRASH("Unknown params!");
michael@0 1850 }
michael@0 1851
michael@0 1852 return nullptr;
michael@0 1853 }
michael@0 1854
michael@0 1855 already_AddRefed<nsIDOMBlob>
michael@0 1856 BlobParent::GetBlob()
michael@0 1857 {
michael@0 1858 MOZ_ASSERT(NS_IsMainThread());
michael@0 1859 MOZ_ASSERT(mBlob);
michael@0 1860
michael@0 1861 nsCOMPtr<nsIDOMBlob> blob;
michael@0 1862
michael@0 1863 // Remote blobs are held alive until the first call to GetBlob. Thereafter we
michael@0 1864 // only hold a weak reference. Normal blobs are held alive until the actor is
michael@0 1865 // destroyed.
michael@0 1866 if (mRemoteBlob && mOwnsBlob) {
michael@0 1867 blob = dont_AddRef(mBlob);
michael@0 1868 mOwnsBlob = false;
michael@0 1869 }
michael@0 1870 else {
michael@0 1871 blob = mBlob;
michael@0 1872 }
michael@0 1873
michael@0 1874 MOZ_ASSERT(blob);
michael@0 1875
michael@0 1876 return blob.forget();
michael@0 1877 }
michael@0 1878
michael@0 1879 bool
michael@0 1880 BlobParent::SetMysteryBlobInfo(const nsString& aName,
michael@0 1881 const nsString& aContentType,
michael@0 1882 uint64_t aLength,
michael@0 1883 uint64_t aLastModifiedDate)
michael@0 1884 {
michael@0 1885 MOZ_ASSERT(NS_IsMainThread());
michael@0 1886 MOZ_ASSERT(mBlob);
michael@0 1887 MOZ_ASSERT(mRemoteBlob);
michael@0 1888 MOZ_ASSERT(aLastModifiedDate != UINT64_MAX);
michael@0 1889
michael@0 1890 ToConcreteBlob(mBlob)->SetLazyData(aName, aContentType, aLength,
michael@0 1891 aLastModifiedDate);
michael@0 1892
michael@0 1893 FileBlobConstructorParams params(aName, aContentType, aLength,
michael@0 1894 aLastModifiedDate);
michael@0 1895 return SendResolveMystery(params);
michael@0 1896 }
michael@0 1897
michael@0 1898 bool
michael@0 1899 BlobParent::SetMysteryBlobInfo(const nsString& aContentType, uint64_t aLength)
michael@0 1900 {
michael@0 1901 MOZ_ASSERT(NS_IsMainThread());
michael@0 1902 MOZ_ASSERT(mBlob);
michael@0 1903 MOZ_ASSERT(mRemoteBlob);
michael@0 1904
michael@0 1905 nsString voidString;
michael@0 1906 voidString.SetIsVoid(true);
michael@0 1907
michael@0 1908 ToConcreteBlob(mBlob)->SetLazyData(voidString, aContentType, aLength,
michael@0 1909 UINT64_MAX);
michael@0 1910
michael@0 1911 NormalBlobConstructorParams params(aContentType, aLength);
michael@0 1912 return SendResolveMystery(params);
michael@0 1913 }
michael@0 1914
michael@0 1915 already_AddRefed<BlobParent::RemoteBlob>
michael@0 1916 BlobParent::CreateRemoteBlob(const ParentBlobConstructorParams& aParams)
michael@0 1917 {
michael@0 1918 MOZ_ASSERT(NS_IsMainThread());
michael@0 1919
michael@0 1920 const ChildBlobConstructorParams& blobParams = aParams.blobParams();
michael@0 1921
michael@0 1922 nsRefPtr<RemoteBlob> remoteBlob;
michael@0 1923
michael@0 1924 switch (blobParams.type()) {
michael@0 1925 case ChildBlobConstructorParams::TNormalBlobConstructorParams: {
michael@0 1926 const NormalBlobConstructorParams& params =
michael@0 1927 blobParams.get_NormalBlobConstructorParams();
michael@0 1928 remoteBlob = new RemoteBlob(params.contentType(), params.length());
michael@0 1929 break;
michael@0 1930 }
michael@0 1931
michael@0 1932 case ChildBlobConstructorParams::TFileBlobConstructorParams: {
michael@0 1933 const FileBlobConstructorParams& params =
michael@0 1934 blobParams.get_FileBlobConstructorParams();
michael@0 1935 remoteBlob =
michael@0 1936 new RemoteBlob(params.name(), params.contentType(), params.length(),
michael@0 1937 params.modDate());
michael@0 1938 break;
michael@0 1939 }
michael@0 1940
michael@0 1941 case ChildBlobConstructorParams::TMysteryBlobConstructorParams: {
michael@0 1942 remoteBlob = new RemoteBlob();
michael@0 1943 break;
michael@0 1944 }
michael@0 1945
michael@0 1946 default:
michael@0 1947 MOZ_CRASH("Unknown params!");
michael@0 1948 }
michael@0 1949
michael@0 1950 MOZ_ASSERT(remoteBlob);
michael@0 1951
michael@0 1952 if (NS_FAILED(remoteBlob->SetMutable(false))) {
michael@0 1953 MOZ_CRASH("Failed to make remote blob immutable!");
michael@0 1954 }
michael@0 1955
michael@0 1956 return remoteBlob.forget();
michael@0 1957 }
michael@0 1958
michael@0 1959 void
michael@0 1960 BlobParent::NoteDyingRemoteBlob()
michael@0 1961 {
michael@0 1962 MOZ_ASSERT(mBlob);
michael@0 1963 MOZ_ASSERT(mRemoteBlob);
michael@0 1964 MOZ_ASSERT(!mOwnsBlob);
michael@0 1965
michael@0 1966 // This may be called on any thread due to the fact that RemoteBlob is
michael@0 1967 // designed to be passed between threads. We must start the shutdown process
michael@0 1968 // on the main thread, so we proxy here if necessary.
michael@0 1969 if (!NS_IsMainThread()) {
michael@0 1970 nsCOMPtr<nsIRunnable> runnable =
michael@0 1971 NS_NewNonOwningRunnableMethod(this, &BlobParent::NoteDyingRemoteBlob);
michael@0 1972 if (NS_FAILED(NS_DispatchToMainThread(runnable))) {
michael@0 1973 MOZ_ASSERT(false, "Should never fail!");
michael@0 1974 }
michael@0 1975
michael@0 1976 return;
michael@0 1977 }
michael@0 1978
michael@0 1979 // Must do this before calling Send__delete__ or we'll crash there trying to
michael@0 1980 // access a dangling pointer.
michael@0 1981 mBlob = nullptr;
michael@0 1982 mRemoteBlob = nullptr;
michael@0 1983
michael@0 1984 mozilla::unused << PBlobParent::Send__delete__(this);
michael@0 1985 }
michael@0 1986
michael@0 1987 void
michael@0 1988 BlobParent::NoteRunnableCompleted(OpenStreamRunnable* aRunnable)
michael@0 1989 {
michael@0 1990 MOZ_ASSERT(NS_IsMainThread());
michael@0 1991
michael@0 1992 for (uint32_t index = 0; index < mOpenStreamRunnables.Length(); index++) {
michael@0 1993 nsRevocableEventPtr<OpenStreamRunnable>& runnable =
michael@0 1994 mOpenStreamRunnables[index];
michael@0 1995
michael@0 1996 if (runnable.get() == aRunnable) {
michael@0 1997 runnable.Forget();
michael@0 1998 mOpenStreamRunnables.RemoveElementAt(index);
michael@0 1999 return;
michael@0 2000 }
michael@0 2001 }
michael@0 2002
michael@0 2003 MOZ_CRASH("Runnable not in our array!");
michael@0 2004 }
michael@0 2005
michael@0 2006 void
michael@0 2007 BlobParent::ActorDestroy(ActorDestroyReason aWhy)
michael@0 2008 {
michael@0 2009 MOZ_ASSERT(NS_IsMainThread());
michael@0 2010
michael@0 2011 if (mRemoteBlob) {
michael@0 2012 mRemoteBlob->SetActor(nullptr);
michael@0 2013 }
michael@0 2014
michael@0 2015 if (mBlob && mOwnsBlob) {
michael@0 2016 mBlob->Release();
michael@0 2017 }
michael@0 2018
michael@0 2019 mStrongManager = nullptr;
michael@0 2020 }
michael@0 2021
michael@0 2022 PBlobStreamParent*
michael@0 2023 BlobParent::AllocPBlobStreamParent()
michael@0 2024 {
michael@0 2025 MOZ_ASSERT(NS_IsMainThread());
michael@0 2026
michael@0 2027 return new InputStreamParent();
michael@0 2028 }
michael@0 2029
michael@0 2030 bool
michael@0 2031 BlobParent::RecvPBlobStreamConstructor(PBlobStreamParent* aActor)
michael@0 2032 {
michael@0 2033 MOZ_ASSERT(NS_IsMainThread());
michael@0 2034 MOZ_ASSERT(aActor);
michael@0 2035 MOZ_ASSERT(mBlob);
michael@0 2036 MOZ_ASSERT(!mRemoteBlob);
michael@0 2037
michael@0 2038 nsCOMPtr<nsIInputStream> stream;
michael@0 2039 nsresult rv = mBlob->GetInternalStream(getter_AddRefs(stream));
michael@0 2040 NS_ENSURE_SUCCESS(rv, false);
michael@0 2041
michael@0 2042 nsCOMPtr<nsIRemoteBlob> remoteBlob = do_QueryInterface(mBlob);
michael@0 2043
michael@0 2044 nsCOMPtr<IPrivateRemoteInputStream> remoteStream;
michael@0 2045 if (remoteBlob) {
michael@0 2046 remoteStream = do_QueryInterface(stream);
michael@0 2047 }
michael@0 2048
michael@0 2049 // There are three cases in which we can use the stream obtained from the blob
michael@0 2050 // directly as our serialized stream:
michael@0 2051 //
michael@0 2052 // 1. The blob is not a remote blob.
michael@0 2053 // 2. The blob is a remote blob that represents this actor.
michael@0 2054 // 3. The blob is a remote blob representing a different actor but we
michael@0 2055 // already have a non-remote, i.e. serialized, serialized stream.
michael@0 2056 //
michael@0 2057 // In all other cases we need to be on a background thread before we can get
michael@0 2058 // to the real stream.
michael@0 2059 nsCOMPtr<nsIIPCSerializableInputStream> serializableStream;
michael@0 2060 if (!remoteBlob ||
michael@0 2061 static_cast<PBlobParent*>(remoteBlob->GetPBlob()) == this ||
michael@0 2062 !remoteStream) {
michael@0 2063 serializableStream = do_QueryInterface(stream);
michael@0 2064 if (!serializableStream) {
michael@0 2065 MOZ_ASSERT(false, "Must be serializable!");
michael@0 2066 return false;
michael@0 2067 }
michael@0 2068 }
michael@0 2069
michael@0 2070 nsCOMPtr<nsIEventTarget> target =
michael@0 2071 do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID);
michael@0 2072 NS_ENSURE_TRUE(target, false);
michael@0 2073
michael@0 2074 nsRefPtr<OpenStreamRunnable> runnable =
michael@0 2075 new OpenStreamRunnable(this, aActor, stream, serializableStream, target);
michael@0 2076
michael@0 2077 rv = runnable->Dispatch();
michael@0 2078 NS_ENSURE_SUCCESS(rv, false);
michael@0 2079
michael@0 2080 // nsRevocableEventPtr lacks some of the operators needed for anything nicer.
michael@0 2081 *mOpenStreamRunnables.AppendElement() = runnable;
michael@0 2082 return true;
michael@0 2083 }
michael@0 2084
michael@0 2085 bool
michael@0 2086 BlobParent::DeallocPBlobStreamParent(PBlobStreamParent* aActor)
michael@0 2087 {
michael@0 2088 MOZ_ASSERT(NS_IsMainThread());
michael@0 2089
michael@0 2090 delete static_cast<InputStreamParent*>(aActor);
michael@0 2091 return true;
michael@0 2092 }
michael@0 2093
michael@0 2094 bool
michael@0 2095 BlobParent::RecvResolveMystery(const ResolveMysteryParams& aParams)
michael@0 2096 {
michael@0 2097 MOZ_ASSERT(NS_IsMainThread());
michael@0 2098 MOZ_ASSERT(mBlob);
michael@0 2099 MOZ_ASSERT(!mRemoteBlob);
michael@0 2100 MOZ_ASSERT(mOwnsBlob);
michael@0 2101
michael@0 2102 if (!mBlobIsFile) {
michael@0 2103 MOZ_ASSERT(false, "Must always be a file!");
michael@0 2104 return false;
michael@0 2105 }
michael@0 2106
michael@0 2107 nsDOMFileBase* blob = ToConcreteBlob(mBlob);
michael@0 2108
michael@0 2109 switch (aParams.type()) {
michael@0 2110 case ResolveMysteryParams::TNormalBlobConstructorParams: {
michael@0 2111 const NormalBlobConstructorParams& params =
michael@0 2112 aParams.get_NormalBlobConstructorParams();
michael@0 2113 nsString voidString;
michael@0 2114 voidString.SetIsVoid(true);
michael@0 2115 blob->SetLazyData(voidString, params.contentType(),
michael@0 2116 params.length(), UINT64_MAX);
michael@0 2117 break;
michael@0 2118 }
michael@0 2119
michael@0 2120 case ResolveMysteryParams::TFileBlobConstructorParams: {
michael@0 2121 const FileBlobConstructorParams& params =
michael@0 2122 aParams.get_FileBlobConstructorParams();
michael@0 2123 blob->SetLazyData(params.name(), params.contentType(),
michael@0 2124 params.length(), params.modDate());
michael@0 2125 break;
michael@0 2126 }
michael@0 2127
michael@0 2128 default:
michael@0 2129 MOZ_CRASH("Unknown params!");
michael@0 2130 }
michael@0 2131
michael@0 2132 return true;
michael@0 2133 }
michael@0 2134
michael@0 2135 bool
michael@0 2136 InputStreamChild::Recv__delete__(const InputStreamParams& aParams,
michael@0 2137 const OptionalFileDescriptorSet& aFDs)
michael@0 2138 {
michael@0 2139 MOZ_ASSERT(NS_IsMainThread());
michael@0 2140 MOZ_ASSERT(mRemoteStream);
michael@0 2141
michael@0 2142 nsTArray<FileDescriptor> fds;
michael@0 2143 if (aFDs.type() == OptionalFileDescriptorSet::TPFileDescriptorSetChild) {
michael@0 2144 FileDescriptorSetChild* fdSetActor =
michael@0 2145 static_cast<FileDescriptorSetChild*>(aFDs.get_PFileDescriptorSetChild());
michael@0 2146 MOZ_ASSERT(fdSetActor);
michael@0 2147
michael@0 2148 fdSetActor->ForgetFileDescriptors(fds);
michael@0 2149 MOZ_ASSERT(!fds.IsEmpty());
michael@0 2150
michael@0 2151 fdSetActor->Send__delete__(fdSetActor);
michael@0 2152 }
michael@0 2153
michael@0 2154 nsCOMPtr<nsIInputStream> stream = DeserializeInputStream(aParams, fds);
michael@0 2155 if (!stream) {
michael@0 2156 return false;
michael@0 2157 }
michael@0 2158
michael@0 2159 mRemoteStream->SetStream(stream);
michael@0 2160 return true;
michael@0 2161 }
michael@0 2162
michael@0 2163 bool
michael@0 2164 InputStreamParent::Recv__delete__(const InputStreamParams& aParams,
michael@0 2165 const OptionalFileDescriptorSet& aFDs)
michael@0 2166 {
michael@0 2167 MOZ_ASSERT(NS_IsMainThread());
michael@0 2168 MOZ_ASSERT(mRemoteStream);
michael@0 2169
michael@0 2170 if (aFDs.type() != OptionalFileDescriptorSet::Tvoid_t) {
michael@0 2171 NS_WARNING("Child cannot send FileDescriptors to the parent!");
michael@0 2172 return false;
michael@0 2173 }
michael@0 2174
michael@0 2175 nsTArray<FileDescriptor> fds;
michael@0 2176 nsCOMPtr<nsIInputStream> stream = DeserializeInputStream(aParams, fds);
michael@0 2177 if (!stream) {
michael@0 2178 return false;
michael@0 2179 }
michael@0 2180
michael@0 2181 MOZ_ASSERT(fds.IsEmpty());
michael@0 2182
michael@0 2183 mRemoteStream->SetStream(stream);
michael@0 2184 return true;
michael@0 2185 }

mercurial