1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/dom/ipc/Blob.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,2185 @@ 1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.6 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.7 + 1.8 +#include "Blob.h" 1.9 + 1.10 +#include "ContentChild.h" 1.11 +#include "ContentParent.h" 1.12 +#include "FileDescriptorSetChild.h" 1.13 +#include "jsapi.h" 1.14 +#include "mozilla/Assertions.h" 1.15 +#include "mozilla/DebugOnly.h" 1.16 +#include "mozilla/Monitor.h" 1.17 +#include "mozilla/unused.h" 1.18 +#include "mozilla/dom/PBlobStreamChild.h" 1.19 +#include "mozilla/dom/PBlobStreamParent.h" 1.20 +#include "mozilla/dom/PFileDescriptorSetParent.h" 1.21 +#include "mozilla/ipc/InputStreamUtils.h" 1.22 +#include "nsCOMPtr.h" 1.23 +#include "nsDOMFile.h" 1.24 +#include "nsIDOMFile.h" 1.25 +#include "nsIInputStream.h" 1.26 +#include "nsIIPCSerializableInputStream.h" 1.27 +#include "nsIMultiplexInputStream.h" 1.28 +#include "nsIRemoteBlob.h" 1.29 +#include "nsISeekableStream.h" 1.30 +#include "nsNetCID.h" 1.31 +#include "nsProxyRelease.h" 1.32 +#include "nsThreadUtils.h" 1.33 + 1.34 +#define PRIVATE_REMOTE_INPUT_STREAM_IID \ 1.35 + {0x30c7699f, 0x51d2, 0x48c8, {0xad, 0x56, 0xc0, 0x16, 0xd7, 0x6f, 0x71, 0x27}} 1.36 + 1.37 +using namespace mozilla; 1.38 +using namespace mozilla::dom; 1.39 +using namespace mozilla::ipc; 1.40 + 1.41 +namespace { 1.42 + 1.43 +enum ActorType 1.44 +{ 1.45 + ChildActor, 1.46 + ParentActor 1.47 +}; 1.48 + 1.49 +// Ensure that a nsCOMPtr/nsRefPtr is released on the main thread. 1.50 +template <template <class> class SmartPtr, class T> 1.51 +void 1.52 +ProxyReleaseToMainThread(SmartPtr<T>& aDoomed) 1.53 +{ 1.54 + MOZ_ASSERT(!NS_IsMainThread()); 1.55 + 1.56 + nsCOMPtr<nsIThread> mainThread = do_GetMainThread(); 1.57 + NS_ENSURE_TRUE_VOID(mainThread); 1.58 + 1.59 + if (NS_FAILED(NS_ProxyRelease(mainThread, aDoomed, true))) { 1.60 + NS_WARNING("Failed to proxy release to main thread!"); 1.61 + } 1.62 +} 1.63 + 1.64 +class NS_NO_VTABLE IPrivateRemoteInputStream : public nsISupports 1.65 +{ 1.66 +public: 1.67 + NS_DECLARE_STATIC_IID_ACCESSOR(PRIVATE_REMOTE_INPUT_STREAM_IID) 1.68 + 1.69 + // This will return the underlying stream. 1.70 + virtual nsIInputStream* 1.71 + BlockAndGetInternalStream() = 0; 1.72 +}; 1.73 + 1.74 +NS_DEFINE_STATIC_IID_ACCESSOR(IPrivateRemoteInputStream, 1.75 + PRIVATE_REMOTE_INPUT_STREAM_IID) 1.76 + 1.77 +// This class exists to keep a blob alive at least as long as its internal 1.78 +// stream. 1.79 +class BlobInputStreamTether : public nsIMultiplexInputStream, 1.80 + public nsISeekableStream, 1.81 + public nsIIPCSerializableInputStream 1.82 +{ 1.83 + nsCOMPtr<nsIInputStream> mStream; 1.84 + nsCOMPtr<nsIDOMBlob> mSourceBlob; 1.85 + 1.86 + nsIMultiplexInputStream* mWeakMultiplexStream; 1.87 + nsISeekableStream* mWeakSeekableStream; 1.88 + nsIIPCSerializableInputStream* mWeakSerializableStream; 1.89 + 1.90 +public: 1.91 + NS_DECL_THREADSAFE_ISUPPORTS 1.92 + NS_FORWARD_NSIINPUTSTREAM(mStream->) 1.93 + NS_FORWARD_SAFE_NSIMULTIPLEXINPUTSTREAM(mWeakMultiplexStream) 1.94 + NS_FORWARD_SAFE_NSISEEKABLESTREAM(mWeakSeekableStream) 1.95 + NS_FORWARD_SAFE_NSIIPCSERIALIZABLEINPUTSTREAM(mWeakSerializableStream) 1.96 + 1.97 + BlobInputStreamTether(nsIInputStream* aStream, nsIDOMBlob* aSourceBlob) 1.98 + : mStream(aStream), mSourceBlob(aSourceBlob), mWeakMultiplexStream(nullptr), 1.99 + mWeakSeekableStream(nullptr), mWeakSerializableStream(nullptr) 1.100 + { 1.101 + MOZ_ASSERT(aStream); 1.102 + MOZ_ASSERT(aSourceBlob); 1.103 + 1.104 + nsCOMPtr<nsIMultiplexInputStream> multiplexStream = 1.105 + do_QueryInterface(aStream); 1.106 + if (multiplexStream) { 1.107 + MOZ_ASSERT(SameCOMIdentity(aStream, multiplexStream)); 1.108 + mWeakMultiplexStream = multiplexStream; 1.109 + } 1.110 + 1.111 + nsCOMPtr<nsISeekableStream> seekableStream = do_QueryInterface(aStream); 1.112 + if (seekableStream) { 1.113 + MOZ_ASSERT(SameCOMIdentity(aStream, seekableStream)); 1.114 + mWeakSeekableStream = seekableStream; 1.115 + } 1.116 + 1.117 + nsCOMPtr<nsIIPCSerializableInputStream> serializableStream = 1.118 + do_QueryInterface(aStream); 1.119 + if (serializableStream) { 1.120 + MOZ_ASSERT(SameCOMIdentity(aStream, serializableStream)); 1.121 + mWeakSerializableStream = serializableStream; 1.122 + } 1.123 + } 1.124 + 1.125 +protected: 1.126 + virtual ~BlobInputStreamTether() 1.127 + { 1.128 + MOZ_ASSERT(mStream); 1.129 + MOZ_ASSERT(mSourceBlob); 1.130 + 1.131 + if (!NS_IsMainThread()) { 1.132 + mStream = nullptr; 1.133 + ProxyReleaseToMainThread(mSourceBlob); 1.134 + } 1.135 + } 1.136 +}; 1.137 + 1.138 +NS_IMPL_ADDREF(BlobInputStreamTether) 1.139 +NS_IMPL_RELEASE(BlobInputStreamTether) 1.140 + 1.141 +NS_INTERFACE_MAP_BEGIN(BlobInputStreamTether) 1.142 + NS_INTERFACE_MAP_ENTRY(nsIInputStream) 1.143 + NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIMultiplexInputStream, 1.144 + mWeakMultiplexStream) 1.145 + NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsISeekableStream, mWeakSeekableStream) 1.146 + NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIIPCSerializableInputStream, 1.147 + mWeakSerializableStream) 1.148 + NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIInputStream) 1.149 +NS_INTERFACE_MAP_END 1.150 + 1.151 +class RemoteInputStream : public nsIInputStream, 1.152 + public nsISeekableStream, 1.153 + public nsIIPCSerializableInputStream, 1.154 + public IPrivateRemoteInputStream 1.155 +{ 1.156 + mozilla::Monitor mMonitor; 1.157 + nsCOMPtr<nsIInputStream> mStream; 1.158 + nsCOMPtr<nsIDOMBlob> mSourceBlob; 1.159 + nsISeekableStream* mWeakSeekableStream; 1.160 + ActorType mOrigin; 1.161 + 1.162 +public: 1.163 + NS_DECL_THREADSAFE_ISUPPORTS 1.164 + 1.165 + RemoteInputStream(nsIDOMBlob* aSourceBlob, ActorType aOrigin) 1.166 + : mMonitor("RemoteInputStream.mMonitor"), mSourceBlob(aSourceBlob), 1.167 + mWeakSeekableStream(nullptr), mOrigin(aOrigin) 1.168 + { 1.169 + MOZ_ASSERT(NS_IsMainThread()); 1.170 + MOZ_ASSERT(aSourceBlob); 1.171 + } 1.172 + 1.173 + void 1.174 + Serialize(InputStreamParams& aParams, 1.175 + FileDescriptorArray& /* aFileDescriptors */) 1.176 + { 1.177 + nsCOMPtr<nsIRemoteBlob> remote = do_QueryInterface(mSourceBlob); 1.178 + MOZ_ASSERT(remote); 1.179 + 1.180 + if (mOrigin == ParentActor) { 1.181 + aParams = RemoteInputStreamParams( 1.182 + static_cast<PBlobParent*>(remote->GetPBlob()), nullptr); 1.183 + } else { 1.184 + MOZ_ASSERT(mOrigin == ChildActor); 1.185 + aParams = RemoteInputStreamParams( 1.186 + nullptr, static_cast<PBlobChild*>(remote->GetPBlob())); 1.187 + } 1.188 + } 1.189 + 1.190 + bool 1.191 + Deserialize(const InputStreamParams& aParams, 1.192 + const FileDescriptorArray& /* aFileDescriptors */) 1.193 + { 1.194 + // See InputStreamUtils.cpp to see how deserialization of a 1.195 + // RemoteInputStream is special-cased. 1.196 + MOZ_CRASH("RemoteInputStream should never be deserialized"); 1.197 + } 1.198 + 1.199 + void 1.200 + SetStream(nsIInputStream* aStream) 1.201 + { 1.202 + MOZ_ASSERT(NS_IsMainThread()); 1.203 + MOZ_ASSERT(aStream); 1.204 + 1.205 + nsCOMPtr<nsIInputStream> stream = aStream; 1.206 + nsCOMPtr<nsISeekableStream> seekableStream = do_QueryInterface(aStream); 1.207 + 1.208 + MOZ_ASSERT_IF(seekableStream, SameCOMIdentity(aStream, seekableStream)); 1.209 + 1.210 + { 1.211 + mozilla::MonitorAutoLock lock(mMonitor); 1.212 + 1.213 + MOZ_ASSERT(!mStream); 1.214 + MOZ_ASSERT(!mWeakSeekableStream); 1.215 + 1.216 + mStream.swap(stream); 1.217 + mWeakSeekableStream = seekableStream; 1.218 + 1.219 + mMonitor.Notify(); 1.220 + } 1.221 + } 1.222 + 1.223 + NS_IMETHOD 1.224 + Close() MOZ_OVERRIDE 1.225 + { 1.226 + nsresult rv = BlockAndWaitForStream(); 1.227 + NS_ENSURE_SUCCESS(rv, rv); 1.228 + 1.229 + nsCOMPtr<nsIDOMBlob> sourceBlob; 1.230 + mSourceBlob.swap(sourceBlob); 1.231 + 1.232 + rv = mStream->Close(); 1.233 + NS_ENSURE_SUCCESS(rv, rv); 1.234 + 1.235 + return NS_OK; 1.236 + } 1.237 + 1.238 + NS_IMETHOD 1.239 + Available(uint64_t* aAvailable) MOZ_OVERRIDE 1.240 + { 1.241 + // See large comment in FileInputStreamWrapper::Available. 1.242 + if (NS_IsMainThread()) { 1.243 + return NS_BASE_STREAM_CLOSED; 1.244 + } 1.245 + 1.246 + nsresult rv = BlockAndWaitForStream(); 1.247 + NS_ENSURE_SUCCESS(rv, rv); 1.248 + 1.249 + rv = mStream->Available(aAvailable); 1.250 + NS_ENSURE_SUCCESS(rv, rv); 1.251 + 1.252 + return NS_OK; 1.253 + } 1.254 + 1.255 + NS_IMETHOD 1.256 + Read(char* aBuffer, uint32_t aCount, uint32_t* aResult) MOZ_OVERRIDE 1.257 + { 1.258 + nsresult rv = BlockAndWaitForStream(); 1.259 + NS_ENSURE_SUCCESS(rv, rv); 1.260 + 1.261 + rv = mStream->Read(aBuffer, aCount, aResult); 1.262 + NS_ENSURE_SUCCESS(rv, rv); 1.263 + 1.264 + return NS_OK; 1.265 + } 1.266 + 1.267 + NS_IMETHOD 1.268 + ReadSegments(nsWriteSegmentFun aWriter, void* aClosure, uint32_t aCount, 1.269 + uint32_t* aResult) MOZ_OVERRIDE 1.270 + { 1.271 + nsresult rv = BlockAndWaitForStream(); 1.272 + NS_ENSURE_SUCCESS(rv, rv); 1.273 + 1.274 + rv = mStream->ReadSegments(aWriter, aClosure, aCount, aResult); 1.275 + NS_ENSURE_SUCCESS(rv, rv); 1.276 + 1.277 + return NS_OK; 1.278 + } 1.279 + 1.280 + NS_IMETHOD 1.281 + IsNonBlocking(bool* aNonBlocking) MOZ_OVERRIDE 1.282 + { 1.283 + NS_ENSURE_ARG_POINTER(aNonBlocking); 1.284 + 1.285 + *aNonBlocking = false; 1.286 + return NS_OK; 1.287 + } 1.288 + 1.289 + NS_IMETHOD 1.290 + Seek(int32_t aWhence, int64_t aOffset) MOZ_OVERRIDE 1.291 + { 1.292 + nsresult rv = BlockAndWaitForStream(); 1.293 + NS_ENSURE_SUCCESS(rv, rv); 1.294 + 1.295 + if (!mWeakSeekableStream) { 1.296 + NS_WARNING("Underlying blob stream is not seekable!"); 1.297 + return NS_ERROR_NO_INTERFACE; 1.298 + } 1.299 + 1.300 + rv = mWeakSeekableStream->Seek(aWhence, aOffset); 1.301 + NS_ENSURE_SUCCESS(rv, rv); 1.302 + 1.303 + return NS_OK; 1.304 + } 1.305 + 1.306 + NS_IMETHOD 1.307 + Tell(int64_t* aResult) 1.308 + { 1.309 + // We can cheat here and assume that we're going to start at 0 if we don't 1.310 + // yet have our stream. Though, really, this should abort since most input 1.311 + // streams could block here. 1.312 + if (NS_IsMainThread() && !mStream) { 1.313 + *aResult = 0; 1.314 + return NS_OK; 1.315 + } 1.316 + 1.317 + nsresult rv = BlockAndWaitForStream(); 1.318 + NS_ENSURE_SUCCESS(rv, rv); 1.319 + 1.320 + if (!mWeakSeekableStream) { 1.321 + NS_WARNING("Underlying blob stream is not seekable!"); 1.322 + return NS_ERROR_NO_INTERFACE; 1.323 + } 1.324 + 1.325 + rv = mWeakSeekableStream->Tell(aResult); 1.326 + NS_ENSURE_SUCCESS(rv, rv); 1.327 + 1.328 + return NS_OK; 1.329 + } 1.330 + 1.331 + NS_IMETHOD 1.332 + SetEOF() 1.333 + { 1.334 + nsresult rv = BlockAndWaitForStream(); 1.335 + NS_ENSURE_SUCCESS(rv, rv); 1.336 + 1.337 + if (!mWeakSeekableStream) { 1.338 + NS_WARNING("Underlying blob stream is not seekable!"); 1.339 + return NS_ERROR_NO_INTERFACE; 1.340 + } 1.341 + 1.342 + rv = mWeakSeekableStream->SetEOF(); 1.343 + NS_ENSURE_SUCCESS(rv, rv); 1.344 + 1.345 + return NS_OK; 1.346 + } 1.347 + 1.348 + virtual nsIInputStream* 1.349 + BlockAndGetInternalStream() 1.350 + { 1.351 + MOZ_ASSERT(!NS_IsMainThread()); 1.352 + 1.353 + nsresult rv = BlockAndWaitForStream(); 1.354 + NS_ENSURE_SUCCESS(rv, nullptr); 1.355 + 1.356 + return mStream; 1.357 + } 1.358 + 1.359 +private: 1.360 + virtual ~RemoteInputStream() 1.361 + { 1.362 + if (!NS_IsMainThread()) { 1.363 + mStream = nullptr; 1.364 + mWeakSeekableStream = nullptr; 1.365 + ProxyReleaseToMainThread(mSourceBlob); 1.366 + } 1.367 + } 1.368 + 1.369 + void 1.370 + ReallyBlockAndWaitForStream() 1.371 + { 1.372 + mozilla::DebugOnly<bool> waited; 1.373 + 1.374 + { 1.375 + mozilla::MonitorAutoLock lock(mMonitor); 1.376 + 1.377 + waited = !mStream; 1.378 + 1.379 + while (!mStream) { 1.380 + mMonitor.Wait(); 1.381 + } 1.382 + } 1.383 + 1.384 + MOZ_ASSERT(mStream); 1.385 + 1.386 +#ifdef DEBUG 1.387 + if (waited && mWeakSeekableStream) { 1.388 + int64_t position; 1.389 + MOZ_ASSERT(NS_SUCCEEDED(mWeakSeekableStream->Tell(&position)), 1.390 + "Failed to determine initial stream position!"); 1.391 + MOZ_ASSERT(!position, "Stream not starting at 0!"); 1.392 + } 1.393 +#endif 1.394 + } 1.395 + 1.396 + nsresult 1.397 + BlockAndWaitForStream() 1.398 + { 1.399 + if (NS_IsMainThread()) { 1.400 + NS_WARNING("Blocking the main thread is not supported!"); 1.401 + return NS_ERROR_FAILURE; 1.402 + } 1.403 + 1.404 + ReallyBlockAndWaitForStream(); 1.405 + 1.406 + return NS_OK; 1.407 + } 1.408 + 1.409 + bool 1.410 + IsSeekableStream() 1.411 + { 1.412 + if (NS_IsMainThread()) { 1.413 + if (!mStream) { 1.414 + NS_WARNING("Don't know if this stream is seekable yet!"); 1.415 + return true; 1.416 + } 1.417 + } 1.418 + else { 1.419 + ReallyBlockAndWaitForStream(); 1.420 + } 1.421 + 1.422 + return !!mWeakSeekableStream; 1.423 + } 1.424 +}; 1.425 + 1.426 +NS_IMPL_ADDREF(RemoteInputStream) 1.427 +NS_IMPL_RELEASE(RemoteInputStream) 1.428 + 1.429 +NS_INTERFACE_MAP_BEGIN(RemoteInputStream) 1.430 + NS_INTERFACE_MAP_ENTRY(nsIInputStream) 1.431 + NS_INTERFACE_MAP_ENTRY(nsIIPCSerializableInputStream) 1.432 + NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsISeekableStream, IsSeekableStream()) 1.433 + NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIInputStream) 1.434 + NS_INTERFACE_MAP_ENTRY(IPrivateRemoteInputStream) 1.435 +NS_INTERFACE_MAP_END 1.436 + 1.437 +class InputStreamChild MOZ_FINAL 1.438 + : public PBlobStreamChild 1.439 +{ 1.440 + nsRefPtr<RemoteInputStream> mRemoteStream; 1.441 + 1.442 +public: 1.443 + InputStreamChild(RemoteInputStream* aRemoteStream) 1.444 + : mRemoteStream(aRemoteStream) 1.445 + { 1.446 + MOZ_ASSERT(NS_IsMainThread()); 1.447 + MOZ_ASSERT(aRemoteStream); 1.448 + } 1.449 + 1.450 + InputStreamChild() 1.451 + { 1.452 + MOZ_ASSERT(NS_IsMainThread()); 1.453 + } 1.454 + 1.455 +private: 1.456 + // This method is only called by the IPDL message machinery. 1.457 + virtual bool 1.458 + Recv__delete__(const InputStreamParams& aParams, 1.459 + const OptionalFileDescriptorSet& aFDs) MOZ_OVERRIDE; 1.460 +}; 1.461 + 1.462 +class InputStreamParent MOZ_FINAL 1.463 + : public PBlobStreamParent 1.464 +{ 1.465 + nsRefPtr<RemoteInputStream> mRemoteStream; 1.466 + 1.467 +public: 1.468 + InputStreamParent(RemoteInputStream* aRemoteStream) 1.469 + : mRemoteStream(aRemoteStream) 1.470 + { 1.471 + MOZ_ASSERT(NS_IsMainThread()); 1.472 + MOZ_ASSERT(aRemoteStream); 1.473 + } 1.474 + 1.475 + InputStreamParent() 1.476 + { 1.477 + MOZ_ASSERT(NS_IsMainThread()); 1.478 + } 1.479 + 1.480 +private: 1.481 + // This method is only called by the IPDL message machinery. 1.482 + virtual bool 1.483 + Recv__delete__(const InputStreamParams& aParams, 1.484 + const OptionalFileDescriptorSet& aFDs) MOZ_OVERRIDE; 1.485 +}; 1.486 + 1.487 +nsDOMFileBase* 1.488 +ToConcreteBlob(nsIDOMBlob* aBlob) 1.489 +{ 1.490 + // XXX This is only safe so long as all blob implementations in our tree 1.491 + // inherit nsDOMFileBase. If that ever changes then this will need to grow 1.492 + // a real interface or something. 1.493 + return static_cast<nsDOMFileBase*>(aBlob); 1.494 +} 1.495 + 1.496 +} // anonymous namespace 1.497 + 1.498 +// Each instance of this class will be dispatched to the network stream thread 1.499 +// pool to run the first time where it will open the file input stream. It will 1.500 +// then dispatch itself back to the main thread to send the child process its 1.501 +// response (assuming that the child has not crashed). The runnable will then 1.502 +// dispatch itself to the thread pool again in order to close the file input 1.503 +// stream. 1.504 +class BlobParent::OpenStreamRunnable MOZ_FINAL 1.505 + : public nsRunnable 1.506 +{ 1.507 + friend class nsRevocableEventPtr<OpenStreamRunnable>; 1.508 + 1.509 + // Only safe to access these pointers if mRevoked is false! 1.510 + BlobParent* mBlobActor; 1.511 + PBlobStreamParent* mStreamActor; 1.512 + 1.513 + nsCOMPtr<nsIInputStream> mStream; 1.514 + nsCOMPtr<nsIIPCSerializableInputStream> mSerializable; 1.515 + nsCOMPtr<nsIEventTarget> mTarget; 1.516 + 1.517 + bool mRevoked; 1.518 + bool mClosing; 1.519 + 1.520 +public: 1.521 + OpenStreamRunnable(BlobParent* aBlobActor, 1.522 + PBlobStreamParent* aStreamActor, 1.523 + nsIInputStream* aStream, 1.524 + nsIIPCSerializableInputStream* aSerializable, 1.525 + nsIEventTarget* aTarget) 1.526 + : mBlobActor(aBlobActor), mStreamActor(aStreamActor), mStream(aStream), 1.527 + mSerializable(aSerializable), mTarget(aTarget), mRevoked(false), 1.528 + mClosing(false) 1.529 + { 1.530 + MOZ_ASSERT(NS_IsMainThread()); 1.531 + MOZ_ASSERT(aBlobActor); 1.532 + MOZ_ASSERT(aStreamActor); 1.533 + MOZ_ASSERT(aStream); 1.534 + // aSerializable may be null. 1.535 + MOZ_ASSERT(aTarget); 1.536 + } 1.537 + 1.538 + NS_IMETHOD 1.539 + Run() 1.540 + { 1.541 + if (NS_IsMainThread()) { 1.542 + return SendResponse(); 1.543 + } 1.544 + 1.545 + if (!mClosing) { 1.546 + return OpenStream(); 1.547 + } 1.548 + 1.549 + return CloseStream(); 1.550 + } 1.551 + 1.552 + nsresult 1.553 + Dispatch() 1.554 + { 1.555 + MOZ_ASSERT(NS_IsMainThread()); 1.556 + MOZ_ASSERT(mTarget); 1.557 + 1.558 + nsresult rv = mTarget->Dispatch(this, NS_DISPATCH_NORMAL); 1.559 + NS_ENSURE_SUCCESS(rv, rv); 1.560 + 1.561 + return NS_OK; 1.562 + } 1.563 + 1.564 +private: 1.565 + void 1.566 + Revoke() 1.567 + { 1.568 + MOZ_ASSERT(NS_IsMainThread()); 1.569 +#ifdef DEBUG 1.570 + mBlobActor = nullptr; 1.571 + mStreamActor = nullptr; 1.572 +#endif 1.573 + mRevoked = true; 1.574 + } 1.575 + 1.576 + nsresult 1.577 + OpenStream() 1.578 + { 1.579 + MOZ_ASSERT(!NS_IsMainThread()); 1.580 + MOZ_ASSERT(mStream); 1.581 + 1.582 + if (!mSerializable) { 1.583 + nsCOMPtr<IPrivateRemoteInputStream> remoteStream = 1.584 + do_QueryInterface(mStream); 1.585 + MOZ_ASSERT(remoteStream, "Must QI to IPrivateRemoteInputStream here!"); 1.586 + 1.587 + nsCOMPtr<nsIInputStream> realStream = 1.588 + remoteStream->BlockAndGetInternalStream(); 1.589 + NS_ENSURE_TRUE(realStream, NS_ERROR_FAILURE); 1.590 + 1.591 + mSerializable = do_QueryInterface(realStream); 1.592 + if (!mSerializable) { 1.593 + MOZ_ASSERT(false, "Must be serializable!"); 1.594 + return NS_ERROR_FAILURE; 1.595 + } 1.596 + 1.597 + mStream.swap(realStream); 1.598 + } 1.599 + 1.600 + // To force the stream open we call Available(). We don't actually care 1.601 + // how much data is available. 1.602 + uint64_t available; 1.603 + if (NS_FAILED(mStream->Available(&available))) { 1.604 + NS_WARNING("Available failed on this stream!"); 1.605 + } 1.606 + 1.607 + nsresult rv = NS_DispatchToMainThread(this, NS_DISPATCH_NORMAL); 1.608 + NS_ENSURE_SUCCESS(rv, rv); 1.609 + 1.610 + return NS_OK; 1.611 + } 1.612 + 1.613 + nsresult 1.614 + CloseStream() 1.615 + { 1.616 + MOZ_ASSERT(!NS_IsMainThread()); 1.617 + MOZ_ASSERT(mStream); 1.618 + 1.619 + // Going to always release here. 1.620 + nsCOMPtr<nsIInputStream> stream; 1.621 + mStream.swap(stream); 1.622 + 1.623 + nsresult rv = stream->Close(); 1.624 + NS_ENSURE_SUCCESS(rv, rv); 1.625 + 1.626 + return NS_OK; 1.627 + } 1.628 + 1.629 + nsresult 1.630 + SendResponse() 1.631 + { 1.632 + MOZ_ASSERT(NS_IsMainThread()); 1.633 + 1.634 + MOZ_ASSERT(mStream); 1.635 + MOZ_ASSERT(mSerializable); 1.636 + MOZ_ASSERT(mTarget); 1.637 + MOZ_ASSERT(!mClosing); 1.638 + 1.639 + nsCOMPtr<nsIIPCSerializableInputStream> serializable; 1.640 + mSerializable.swap(serializable); 1.641 + 1.642 + if (mRevoked) { 1.643 + MOZ_ASSERT(!mBlobActor); 1.644 + MOZ_ASSERT(!mStreamActor); 1.645 + } 1.646 + else { 1.647 + MOZ_ASSERT(mBlobActor); 1.648 + MOZ_ASSERT(mStreamActor); 1.649 + 1.650 + InputStreamParams params; 1.651 + nsAutoTArray<FileDescriptor, 10> fds; 1.652 + serializable->Serialize(params, fds); 1.653 + 1.654 + MOZ_ASSERT(params.type() != InputStreamParams::T__None); 1.655 + 1.656 + PFileDescriptorSetParent* fdSet = nullptr; 1.657 + 1.658 + if (!fds.IsEmpty()) { 1.659 + auto* manager = static_cast<ContentParent*>(mBlobActor->Manager()); 1.660 + MOZ_ASSERT(manager); 1.661 + 1.662 + fdSet = manager->SendPFileDescriptorSetConstructor(fds[0]); 1.663 + if (fdSet) { 1.664 + for (uint32_t index = 1; index < fds.Length(); index++) { 1.665 + unused << fdSet->SendAddFileDescriptor(fds[index]); 1.666 + } 1.667 + } 1.668 + } 1.669 + 1.670 + OptionalFileDescriptorSet optionalFDs; 1.671 + if (fdSet) { 1.672 + optionalFDs = fdSet; 1.673 + } else { 1.674 + optionalFDs = mozilla::void_t(); 1.675 + } 1.676 + 1.677 + unused << 1.678 + PBlobStreamParent::Send__delete__(mStreamActor, params, optionalFDs); 1.679 + 1.680 + mBlobActor->NoteRunnableCompleted(this); 1.681 + 1.682 +#ifdef DEBUG 1.683 + mBlobActor = nullptr; 1.684 + mStreamActor = nullptr; 1.685 +#endif 1.686 + } 1.687 + 1.688 + mClosing = true; 1.689 + 1.690 + nsCOMPtr<nsIEventTarget> target; 1.691 + mTarget.swap(target); 1.692 + 1.693 + nsresult rv = target->Dispatch(this, NS_DISPATCH_NORMAL); 1.694 + NS_ENSURE_SUCCESS(rv, rv); 1.695 + 1.696 + return NS_OK; 1.697 + } 1.698 +}; 1.699 + 1.700 +/******************************************************************************* 1.701 + * BlobChild::RemoteBlob Declaration 1.702 + ******************************************************************************/ 1.703 + 1.704 +class BlobChild::RemoteBlob MOZ_FINAL 1.705 + : public nsDOMFile 1.706 + , public nsIRemoteBlob 1.707 +{ 1.708 + class StreamHelper; 1.709 + class SliceHelper; 1.710 + 1.711 + BlobChild* mActor; 1.712 + 1.713 +public: 1.714 + RemoteBlob(const nsAString& aName, 1.715 + const nsAString& aContentType, 1.716 + uint64_t aLength, 1.717 + uint64_t aModDate) 1.718 + : nsDOMFile(aName, aContentType, aLength, aModDate) 1.719 + , mActor(nullptr) 1.720 + { 1.721 + mImmutable = true; 1.722 + } 1.723 + 1.724 + RemoteBlob(const nsAString& aContentType, uint64_t aLength) 1.725 + : nsDOMFile(aContentType, aLength) 1.726 + , mActor(nullptr) 1.727 + { 1.728 + mImmutable = true; 1.729 + } 1.730 + 1.731 + RemoteBlob() 1.732 + : nsDOMFile(EmptyString(), EmptyString(), UINT64_MAX, UINT64_MAX) 1.733 + , mActor(nullptr) 1.734 + { 1.735 + mImmutable = true; 1.736 + } 1.737 + 1.738 + void 1.739 + SetActor(BlobChild* aActor) 1.740 + { 1.741 + MOZ_ASSERT(!aActor || !mActor); 1.742 + mActor = aActor; 1.743 + } 1.744 + 1.745 + NS_DECL_ISUPPORTS_INHERITED 1.746 + 1.747 + virtual already_AddRefed<nsIDOMBlob> 1.748 + CreateSlice(uint64_t aStart, uint64_t aLength, const nsAString& aContentType) 1.749 + MOZ_OVERRIDE; 1.750 + 1.751 + NS_IMETHOD 1.752 + GetInternalStream(nsIInputStream** aStream) MOZ_OVERRIDE; 1.753 + 1.754 + NS_IMETHOD 1.755 + GetLastModifiedDate(JSContext* cx, 1.756 + JS::MutableHandle<JS::Value> aLastModifiedDate) 1.757 + MOZ_OVERRIDE; 1.758 + 1.759 + virtual void* 1.760 + GetPBlob() MOZ_OVERRIDE; 1.761 + 1.762 +private: 1.763 + ~RemoteBlob() 1.764 + { 1.765 + if (mActor) { 1.766 + mActor->NoteDyingRemoteBlob(); 1.767 + } 1.768 + } 1.769 +}; 1.770 + 1.771 +class BlobChild::RemoteBlob::StreamHelper MOZ_FINAL 1.772 + : public nsRunnable 1.773 +{ 1.774 + mozilla::Monitor mMonitor; 1.775 + BlobChild* mActor; 1.776 + nsCOMPtr<nsIDOMBlob> mSourceBlob; 1.777 + nsRefPtr<RemoteInputStream> mInputStream; 1.778 + bool mDone; 1.779 + 1.780 +public: 1.781 + StreamHelper(BlobChild* aActor, nsIDOMBlob* aSourceBlob) 1.782 + : mMonitor("BlobChild::RemoteBlob::StreamHelper::mMonitor") 1.783 + , mActor(aActor) 1.784 + , mSourceBlob(aSourceBlob) 1.785 + , mDone(false) 1.786 + { 1.787 + // This may be created on any thread. 1.788 + MOZ_ASSERT(aActor); 1.789 + MOZ_ASSERT(aSourceBlob); 1.790 + } 1.791 + 1.792 + nsresult 1.793 + GetStream(nsIInputStream** aInputStream) 1.794 + { 1.795 + // This may be called on any thread. 1.796 + MOZ_ASSERT(aInputStream); 1.797 + MOZ_ASSERT(mActor); 1.798 + MOZ_ASSERT(!mInputStream); 1.799 + MOZ_ASSERT(!mDone); 1.800 + 1.801 + if (NS_IsMainThread()) { 1.802 + RunInternal(false); 1.803 + } 1.804 + else { 1.805 + nsCOMPtr<nsIThread> mainThread = do_GetMainThread(); 1.806 + NS_ENSURE_TRUE(mainThread, NS_ERROR_FAILURE); 1.807 + 1.808 + nsresult rv = mainThread->Dispatch(this, NS_DISPATCH_NORMAL); 1.809 + NS_ENSURE_SUCCESS(rv, rv); 1.810 + 1.811 + { 1.812 + MonitorAutoLock lock(mMonitor); 1.813 + while (!mDone) { 1.814 + lock.Wait(); 1.815 + } 1.816 + } 1.817 + } 1.818 + 1.819 + MOZ_ASSERT(!mActor); 1.820 + MOZ_ASSERT(mDone); 1.821 + 1.822 + if (!mInputStream) { 1.823 + return NS_ERROR_UNEXPECTED; 1.824 + } 1.825 + 1.826 + mInputStream.forget(aInputStream); 1.827 + return NS_OK; 1.828 + } 1.829 + 1.830 + NS_IMETHOD 1.831 + Run() 1.832 + { 1.833 + MOZ_ASSERT(NS_IsMainThread()); 1.834 + RunInternal(true); 1.835 + return NS_OK; 1.836 + } 1.837 + 1.838 +private: 1.839 + void 1.840 + RunInternal(bool aNotify) 1.841 + { 1.842 + MOZ_ASSERT(NS_IsMainThread()); 1.843 + MOZ_ASSERT(mActor); 1.844 + MOZ_ASSERT(!mInputStream); 1.845 + MOZ_ASSERT(!mDone); 1.846 + 1.847 + nsRefPtr<RemoteInputStream> stream = 1.848 + new RemoteInputStream(mSourceBlob, ChildActor); 1.849 + 1.850 + InputStreamChild* streamActor = new InputStreamChild(stream); 1.851 + if (mActor->SendPBlobStreamConstructor(streamActor)) { 1.852 + stream.swap(mInputStream); 1.853 + } 1.854 + 1.855 + mActor = nullptr; 1.856 + 1.857 + if (aNotify) { 1.858 + MonitorAutoLock lock(mMonitor); 1.859 + mDone = true; 1.860 + lock.Notify(); 1.861 + } 1.862 + else { 1.863 + mDone = true; 1.864 + } 1.865 + } 1.866 +}; 1.867 + 1.868 +class BlobChild::RemoteBlob::SliceHelper MOZ_FINAL 1.869 + : public nsRunnable 1.870 +{ 1.871 + mozilla::Monitor mMonitor; 1.872 + BlobChild* mActor; 1.873 + nsCOMPtr<nsIDOMBlob> mSlice; 1.874 + uint64_t mStart; 1.875 + uint64_t mLength; 1.876 + nsString mContentType; 1.877 + bool mDone; 1.878 + 1.879 +public: 1.880 + SliceHelper(BlobChild* aActor) 1.881 + : mMonitor("BlobChild::RemoteBlob::SliceHelper::mMonitor") 1.882 + , mActor(aActor) 1.883 + , mStart(0) 1.884 + , mLength(0) 1.885 + , mDone(false) 1.886 + { 1.887 + // This may be created on any thread. 1.888 + MOZ_ASSERT(aActor); 1.889 + } 1.890 + 1.891 + nsresult 1.892 + GetSlice(uint64_t aStart, 1.893 + uint64_t aLength, 1.894 + const nsAString& aContentType, 1.895 + nsIDOMBlob** aSlice) 1.896 + { 1.897 + // This may be called on any thread. 1.898 + MOZ_ASSERT(aSlice); 1.899 + MOZ_ASSERT(mActor); 1.900 + MOZ_ASSERT(!mSlice); 1.901 + MOZ_ASSERT(!mDone); 1.902 + 1.903 + mStart = aStart; 1.904 + mLength = aLength; 1.905 + mContentType = aContentType; 1.906 + 1.907 + if (NS_IsMainThread()) { 1.908 + RunInternal(false); 1.909 + } 1.910 + else { 1.911 + nsCOMPtr<nsIThread> mainThread = do_GetMainThread(); 1.912 + NS_ENSURE_TRUE(mainThread, NS_ERROR_FAILURE); 1.913 + 1.914 + nsresult rv = mainThread->Dispatch(this, NS_DISPATCH_NORMAL); 1.915 + NS_ENSURE_SUCCESS(rv, rv); 1.916 + 1.917 + { 1.918 + MonitorAutoLock lock(mMonitor); 1.919 + while (!mDone) { 1.920 + lock.Wait(); 1.921 + } 1.922 + } 1.923 + } 1.924 + 1.925 + MOZ_ASSERT(!mActor); 1.926 + MOZ_ASSERT(mDone); 1.927 + 1.928 + if (!mSlice) { 1.929 + return NS_ERROR_UNEXPECTED; 1.930 + } 1.931 + 1.932 + mSlice.forget(aSlice); 1.933 + return NS_OK; 1.934 + } 1.935 + 1.936 + NS_IMETHOD 1.937 + Run() 1.938 + { 1.939 + MOZ_ASSERT(NS_IsMainThread()); 1.940 + RunInternal(true); 1.941 + return NS_OK; 1.942 + } 1.943 + 1.944 +private: 1.945 + void 1.946 + RunInternal(bool aNotify) 1.947 + { 1.948 + MOZ_ASSERT(NS_IsMainThread()); 1.949 + MOZ_ASSERT(mActor); 1.950 + MOZ_ASSERT(!mSlice); 1.951 + MOZ_ASSERT(!mDone); 1.952 + 1.953 + NS_ENSURE_TRUE_VOID(mActor->Manager()); 1.954 + 1.955 + NormalBlobConstructorParams normalParams; 1.956 + normalParams.contentType() = mContentType; 1.957 + normalParams.length() = mLength; 1.958 + 1.959 + auto* manager = static_cast<ContentChild*>(mActor->Manager()); 1.960 + MOZ_ASSERT(manager); 1.961 + 1.962 + BlobChild* newActor = BlobChild::Create(manager, normalParams); 1.963 + MOZ_ASSERT(newActor); 1.964 + 1.965 + SlicedBlobConstructorParams slicedParams; 1.966 + slicedParams.contentType() = mContentType; 1.967 + slicedParams.begin() = mStart; 1.968 + slicedParams.end() = mStart + mLength; 1.969 + slicedParams.sourceChild() = mActor; 1.970 + 1.971 + ParentBlobConstructorParams otherSideParams; 1.972 + otherSideParams.blobParams() = slicedParams; 1.973 + otherSideParams.optionalInputStreamParams() = mozilla::void_t(); 1.974 + 1.975 + if (mActor->Manager()->SendPBlobConstructor(newActor, otherSideParams)) { 1.976 + mSlice = newActor->GetBlob(); 1.977 + } 1.978 + 1.979 + mActor = nullptr; 1.980 + 1.981 + if (aNotify) { 1.982 + MonitorAutoLock lock(mMonitor); 1.983 + mDone = true; 1.984 + lock.Notify(); 1.985 + } 1.986 + else { 1.987 + mDone = true; 1.988 + } 1.989 + } 1.990 +}; 1.991 + 1.992 +/******************************************************************************* 1.993 + * BlobChild::RemoteBlob Implementation 1.994 + ******************************************************************************/ 1.995 + 1.996 +NS_IMPL_ISUPPORTS_INHERITED(BlobChild::RemoteBlob, nsDOMFile, nsIRemoteBlob) 1.997 + 1.998 +already_AddRefed<nsIDOMBlob> 1.999 +BlobChild:: 1.1000 +RemoteBlob::CreateSlice(uint64_t aStart, 1.1001 + uint64_t aLength, 1.1002 + const nsAString& aContentType) 1.1003 +{ 1.1004 + if (!mActor) { 1.1005 + return nullptr; 1.1006 + } 1.1007 + 1.1008 + nsRefPtr<SliceHelper> helper = new SliceHelper(mActor); 1.1009 + 1.1010 + nsCOMPtr<nsIDOMBlob> slice; 1.1011 + nsresult rv = 1.1012 + helper->GetSlice(aStart, aLength, aContentType, getter_AddRefs(slice)); 1.1013 + NS_ENSURE_SUCCESS(rv, nullptr); 1.1014 + 1.1015 + return slice.forget(); 1.1016 +} 1.1017 + 1.1018 +NS_IMETHODIMP 1.1019 +BlobChild:: 1.1020 +RemoteBlob::GetInternalStream(nsIInputStream** aStream) 1.1021 +{ 1.1022 + if (!mActor) { 1.1023 + return NS_ERROR_UNEXPECTED; 1.1024 + } 1.1025 + 1.1026 + nsRefPtr<StreamHelper> helper = new StreamHelper(mActor, this); 1.1027 + return helper->GetStream(aStream); 1.1028 +} 1.1029 + 1.1030 +NS_IMETHODIMP 1.1031 +BlobChild:: 1.1032 +RemoteBlob::GetLastModifiedDate(JSContext* cx, 1.1033 + JS::MutableHandle<JS::Value> aLastModifiedDate) 1.1034 +{ 1.1035 + if (IsDateUnknown()) { 1.1036 + aLastModifiedDate.setNull(); 1.1037 + } else { 1.1038 + JSObject* date = JS_NewDateObjectMsec(cx, mLastModificationDate); 1.1039 + if (!date) { 1.1040 + return NS_ERROR_OUT_OF_MEMORY; 1.1041 + } 1.1042 + aLastModifiedDate.setObject(*date); 1.1043 + } 1.1044 + return NS_OK; 1.1045 +} 1.1046 + 1.1047 +void* 1.1048 +BlobChild:: 1.1049 +RemoteBlob::GetPBlob() 1.1050 +{ 1.1051 + return static_cast<PBlobChild*>(mActor); 1.1052 +} 1.1053 + 1.1054 +/******************************************************************************* 1.1055 + * BlobChild 1.1056 + ******************************************************************************/ 1.1057 + 1.1058 +BlobChild::BlobChild(ContentChild* aManager, nsIDOMBlob* aBlob) 1.1059 + : mBlob(aBlob) 1.1060 + , mRemoteBlob(nullptr) 1.1061 + , mStrongManager(aManager) 1.1062 + , mOwnsBlob(true) 1.1063 + , mBlobIsFile(false) 1.1064 +{ 1.1065 + MOZ_ASSERT(NS_IsMainThread()); 1.1066 + MOZ_ASSERT(aManager); 1.1067 + MOZ_ASSERT(aBlob); 1.1068 + 1.1069 + aBlob->AddRef(); 1.1070 + 1.1071 + nsCOMPtr<nsIDOMFile> file = do_QueryInterface(aBlob); 1.1072 + mBlobIsFile = !!file; 1.1073 +} 1.1074 + 1.1075 +BlobChild::BlobChild(ContentChild* aManager, 1.1076 + const ChildBlobConstructorParams& aParams) 1.1077 + : mBlob(nullptr) 1.1078 + , mRemoteBlob(nullptr) 1.1079 + , mStrongManager(aManager) 1.1080 + , mOwnsBlob(false) 1.1081 + , mBlobIsFile(false) 1.1082 +{ 1.1083 + MOZ_ASSERT(NS_IsMainThread()); 1.1084 + MOZ_ASSERT(aManager); 1.1085 + 1.1086 + ChildBlobConstructorParams::Type paramsType = aParams.type(); 1.1087 + 1.1088 + mBlobIsFile = 1.1089 + paramsType == ChildBlobConstructorParams::TFileBlobConstructorParams || 1.1090 + paramsType == ChildBlobConstructorParams::TMysteryBlobConstructorParams; 1.1091 + 1.1092 + nsRefPtr<RemoteBlob> remoteBlob = CreateRemoteBlob(aParams); 1.1093 + MOZ_ASSERT(remoteBlob); 1.1094 + 1.1095 + remoteBlob->SetActor(this); 1.1096 + remoteBlob.forget(&mRemoteBlob); 1.1097 + 1.1098 + mBlob = mRemoteBlob; 1.1099 + mOwnsBlob = true; 1.1100 +} 1.1101 + 1.1102 +BlobChild::~BlobChild() 1.1103 +{ 1.1104 +} 1.1105 + 1.1106 +BlobChild* 1.1107 +BlobChild::Create(ContentChild* aManager, 1.1108 + const ChildBlobConstructorParams& aParams) 1.1109 +{ 1.1110 + MOZ_ASSERT(NS_IsMainThread()); 1.1111 + MOZ_ASSERT(aManager); 1.1112 + 1.1113 + switch (aParams.type()) { 1.1114 + case ChildBlobConstructorParams::TNormalBlobConstructorParams: 1.1115 + case ChildBlobConstructorParams::TFileBlobConstructorParams: 1.1116 + case ChildBlobConstructorParams::TMysteryBlobConstructorParams: 1.1117 + return new BlobChild(aManager, aParams); 1.1118 + 1.1119 + case ChildBlobConstructorParams::TSlicedBlobConstructorParams: { 1.1120 + const SlicedBlobConstructorParams& params = 1.1121 + aParams.get_SlicedBlobConstructorParams(); 1.1122 + 1.1123 + auto* actor = 1.1124 + const_cast<BlobChild*>( 1.1125 + static_cast<const BlobChild*>(params.sourceChild())); 1.1126 + MOZ_ASSERT(actor); 1.1127 + 1.1128 + nsCOMPtr<nsIDOMBlob> source = actor->GetBlob(); 1.1129 + MOZ_ASSERT(source); 1.1130 + 1.1131 + nsCOMPtr<nsIDOMBlob> slice; 1.1132 + nsresult rv = 1.1133 + source->Slice(params.begin(), params.end(), params.contentType(), 3, 1.1134 + getter_AddRefs(slice)); 1.1135 + NS_ENSURE_SUCCESS(rv, nullptr); 1.1136 + 1.1137 + return new BlobChild(aManager, slice); 1.1138 + } 1.1139 + 1.1140 + default: 1.1141 + MOZ_CRASH("Unknown params!"); 1.1142 + } 1.1143 + 1.1144 + return nullptr; 1.1145 +} 1.1146 + 1.1147 +already_AddRefed<nsIDOMBlob> 1.1148 +BlobChild::GetBlob() 1.1149 +{ 1.1150 + MOZ_ASSERT(NS_IsMainThread()); 1.1151 + MOZ_ASSERT(mBlob); 1.1152 + 1.1153 + nsCOMPtr<nsIDOMBlob> blob; 1.1154 + 1.1155 + // Remote blobs are held alive until the first call to GetBlob. Thereafter we 1.1156 + // only hold a weak reference. Normal blobs are held alive until the actor is 1.1157 + // destroyed. 1.1158 + if (mRemoteBlob && mOwnsBlob) { 1.1159 + blob = dont_AddRef(mBlob); 1.1160 + mOwnsBlob = false; 1.1161 + } 1.1162 + else { 1.1163 + blob = mBlob; 1.1164 + } 1.1165 + 1.1166 + MOZ_ASSERT(blob); 1.1167 + 1.1168 + return blob.forget(); 1.1169 +} 1.1170 + 1.1171 +bool 1.1172 +BlobChild::SetMysteryBlobInfo(const nsString& aName, 1.1173 + const nsString& aContentType, 1.1174 + uint64_t aLength, 1.1175 + uint64_t aLastModifiedDate) 1.1176 +{ 1.1177 + MOZ_ASSERT(NS_IsMainThread()); 1.1178 + MOZ_ASSERT(mBlob); 1.1179 + MOZ_ASSERT(mRemoteBlob); 1.1180 + MOZ_ASSERT(aLastModifiedDate != UINT64_MAX); 1.1181 + 1.1182 + ToConcreteBlob(mBlob)->SetLazyData(aName, aContentType, aLength, 1.1183 + aLastModifiedDate); 1.1184 + 1.1185 + FileBlobConstructorParams params(aName, aContentType, aLength, 1.1186 + aLastModifiedDate); 1.1187 + return SendResolveMystery(params); 1.1188 +} 1.1189 + 1.1190 +bool 1.1191 +BlobChild::SetMysteryBlobInfo(const nsString& aContentType, uint64_t aLength) 1.1192 +{ 1.1193 + MOZ_ASSERT(NS_IsMainThread()); 1.1194 + MOZ_ASSERT(mBlob); 1.1195 + MOZ_ASSERT(mRemoteBlob); 1.1196 + 1.1197 + nsString voidString; 1.1198 + voidString.SetIsVoid(true); 1.1199 + 1.1200 + ToConcreteBlob(mBlob)->SetLazyData(voidString, aContentType, aLength, 1.1201 + UINT64_MAX); 1.1202 + 1.1203 + NormalBlobConstructorParams params(aContentType, aLength); 1.1204 + return SendResolveMystery(params); 1.1205 +} 1.1206 + 1.1207 +already_AddRefed<BlobChild::RemoteBlob> 1.1208 +BlobChild::CreateRemoteBlob(const ChildBlobConstructorParams& aParams) 1.1209 +{ 1.1210 + MOZ_ASSERT(NS_IsMainThread()); 1.1211 + 1.1212 + nsRefPtr<RemoteBlob> remoteBlob; 1.1213 + 1.1214 + switch (aParams.type()) { 1.1215 + case ChildBlobConstructorParams::TNormalBlobConstructorParams: { 1.1216 + const NormalBlobConstructorParams& params = 1.1217 + aParams.get_NormalBlobConstructorParams(); 1.1218 + remoteBlob = new RemoteBlob(params.contentType(), params.length()); 1.1219 + break; 1.1220 + } 1.1221 + 1.1222 + case ChildBlobConstructorParams::TFileBlobConstructorParams: { 1.1223 + const FileBlobConstructorParams& params = 1.1224 + aParams.get_FileBlobConstructorParams(); 1.1225 + remoteBlob = 1.1226 + new RemoteBlob(params.name(), params.contentType(), params.length(), 1.1227 + params.modDate()); 1.1228 + break; 1.1229 + } 1.1230 + 1.1231 + case ChildBlobConstructorParams::TMysteryBlobConstructorParams: { 1.1232 + remoteBlob = new RemoteBlob(); 1.1233 + break; 1.1234 + } 1.1235 + 1.1236 + default: 1.1237 + MOZ_CRASH("Unknown params!"); 1.1238 + } 1.1239 + 1.1240 + MOZ_ASSERT(remoteBlob); 1.1241 + 1.1242 + if (NS_FAILED(remoteBlob->SetMutable(false))) { 1.1243 + MOZ_CRASH("Failed to make remote blob immutable!"); 1.1244 + } 1.1245 + 1.1246 + return remoteBlob.forget(); 1.1247 +} 1.1248 + 1.1249 +void 1.1250 +BlobChild::NoteDyingRemoteBlob() 1.1251 +{ 1.1252 + MOZ_ASSERT(mBlob); 1.1253 + MOZ_ASSERT(mRemoteBlob); 1.1254 + MOZ_ASSERT(!mOwnsBlob); 1.1255 + 1.1256 + // This may be called on any thread due to the fact that RemoteBlob is 1.1257 + // designed to be passed between threads. We must start the shutdown process 1.1258 + // on the main thread, so we proxy here if necessary. 1.1259 + if (!NS_IsMainThread()) { 1.1260 + nsCOMPtr<nsIRunnable> runnable = 1.1261 + NS_NewNonOwningRunnableMethod(this, &BlobChild::NoteDyingRemoteBlob); 1.1262 + if (NS_FAILED(NS_DispatchToMainThread(runnable))) { 1.1263 + MOZ_ASSERT(false, "Should never fail!"); 1.1264 + } 1.1265 + 1.1266 + return; 1.1267 + } 1.1268 + 1.1269 + // Must do this before calling Send__delete__ or we'll crash there trying to 1.1270 + // access a dangling pointer. 1.1271 + mBlob = nullptr; 1.1272 + mRemoteBlob = nullptr; 1.1273 + 1.1274 + PBlobChild::Send__delete__(this); 1.1275 +} 1.1276 + 1.1277 +void 1.1278 +BlobChild::ActorDestroy(ActorDestroyReason aWhy) 1.1279 +{ 1.1280 + MOZ_ASSERT(NS_IsMainThread()); 1.1281 + 1.1282 + if (mRemoteBlob) { 1.1283 + mRemoteBlob->SetActor(nullptr); 1.1284 + } 1.1285 + 1.1286 + if (mBlob && mOwnsBlob) { 1.1287 + mBlob->Release(); 1.1288 + } 1.1289 + 1.1290 + mStrongManager = nullptr; 1.1291 +} 1.1292 + 1.1293 +PBlobStreamChild* 1.1294 +BlobChild::AllocPBlobStreamChild() 1.1295 +{ 1.1296 + MOZ_ASSERT(NS_IsMainThread()); 1.1297 + 1.1298 + return new InputStreamChild(); 1.1299 +} 1.1300 + 1.1301 +bool 1.1302 +BlobChild::RecvPBlobStreamConstructor(PBlobStreamChild* aActor) 1.1303 +{ 1.1304 + MOZ_ASSERT(NS_IsMainThread()); 1.1305 + MOZ_ASSERT(aActor); 1.1306 + MOZ_ASSERT(mBlob); 1.1307 + MOZ_ASSERT(!mRemoteBlob); 1.1308 + 1.1309 + nsCOMPtr<nsIInputStream> stream; 1.1310 + nsresult rv = mBlob->GetInternalStream(getter_AddRefs(stream)); 1.1311 + NS_ENSURE_SUCCESS(rv, false); 1.1312 + 1.1313 + nsCOMPtr<nsIIPCSerializableInputStream> serializable = 1.1314 + do_QueryInterface(stream); 1.1315 + if (!serializable) { 1.1316 + MOZ_ASSERT(false, "Must be serializable!"); 1.1317 + return false; 1.1318 + } 1.1319 + 1.1320 + InputStreamParams params; 1.1321 + nsTArray<FileDescriptor> fds; 1.1322 + serializable->Serialize(params, fds); 1.1323 + 1.1324 + MOZ_ASSERT(params.type() != InputStreamParams::T__None); 1.1325 + MOZ_ASSERT(fds.IsEmpty()); 1.1326 + 1.1327 + return aActor->Send__delete__(aActor, params, mozilla::void_t()); 1.1328 +} 1.1329 + 1.1330 +bool 1.1331 +BlobChild::DeallocPBlobStreamChild(PBlobStreamChild* aActor) 1.1332 +{ 1.1333 + MOZ_ASSERT(NS_IsMainThread()); 1.1334 + 1.1335 + delete static_cast<InputStreamChild*>(aActor); 1.1336 + return true; 1.1337 +} 1.1338 + 1.1339 +bool 1.1340 +BlobChild::RecvResolveMystery(const ResolveMysteryParams& aParams) 1.1341 +{ 1.1342 + MOZ_ASSERT(NS_IsMainThread()); 1.1343 + MOZ_ASSERT(mBlob); 1.1344 + MOZ_ASSERT(!mRemoteBlob); 1.1345 + MOZ_ASSERT(mOwnsBlob); 1.1346 + 1.1347 + if (!mBlobIsFile) { 1.1348 + MOZ_ASSERT(false, "Must always be a file!"); 1.1349 + return false; 1.1350 + } 1.1351 + 1.1352 + nsDOMFileBase* blob = ToConcreteBlob(mBlob); 1.1353 + 1.1354 + switch (aParams.type()) { 1.1355 + case ResolveMysteryParams::TNormalBlobConstructorParams: { 1.1356 + const NormalBlobConstructorParams& params = 1.1357 + aParams.get_NormalBlobConstructorParams(); 1.1358 + nsString voidString; 1.1359 + voidString.SetIsVoid(true); 1.1360 + blob->SetLazyData(voidString, params.contentType(), params.length(), 1.1361 + UINT64_MAX); 1.1362 + break; 1.1363 + } 1.1364 + 1.1365 + case ResolveMysteryParams::TFileBlobConstructorParams: { 1.1366 + const FileBlobConstructorParams& params = 1.1367 + aParams.get_FileBlobConstructorParams(); 1.1368 + blob->SetLazyData(params.name(), params.contentType(), params.length(), 1.1369 + params.modDate()); 1.1370 + break; 1.1371 + } 1.1372 + 1.1373 + default: 1.1374 + MOZ_CRASH("Unknown params!"); 1.1375 + } 1.1376 + 1.1377 + return true; 1.1378 +} 1.1379 + 1.1380 +/******************************************************************************* 1.1381 + * BlobParent::RemoteBlob Declaration 1.1382 + ******************************************************************************/ 1.1383 + 1.1384 +class BlobParent::RemoteBlob MOZ_FINAL 1.1385 + : public nsDOMFile 1.1386 + , public nsIRemoteBlob 1.1387 +{ 1.1388 + class StreamHelper; 1.1389 + class SliceHelper; 1.1390 + 1.1391 + BlobParent* mActor; 1.1392 + InputStreamParams mInputStreamParams; 1.1393 + 1.1394 +public: 1.1395 + RemoteBlob(const nsAString& aName, 1.1396 + const nsAString& aContentType, 1.1397 + uint64_t aLength, 1.1398 + uint64_t aModDate) 1.1399 + : nsDOMFile(aName, aContentType, aLength, aModDate) 1.1400 + , mActor(nullptr) 1.1401 + { 1.1402 + mImmutable = true; 1.1403 + } 1.1404 + 1.1405 + RemoteBlob(const nsAString& aContentType, uint64_t aLength) 1.1406 + : nsDOMFile(aContentType, aLength) 1.1407 + , mActor(nullptr) 1.1408 + { 1.1409 + mImmutable = true; 1.1410 + } 1.1411 + 1.1412 + RemoteBlob() 1.1413 + : nsDOMFile(EmptyString(), EmptyString(), UINT64_MAX, UINT64_MAX) 1.1414 + , mActor(nullptr) 1.1415 + { 1.1416 + mImmutable = true; 1.1417 + } 1.1418 + 1.1419 + void 1.1420 + SetActor(BlobParent* aActor) 1.1421 + { 1.1422 + MOZ_ASSERT(!aActor || !mActor); 1.1423 + mActor = aActor; 1.1424 + } 1.1425 + 1.1426 + void 1.1427 + MaybeSetInputStream(const ParentBlobConstructorParams& aParams) 1.1428 + { 1.1429 + if (aParams.optionalInputStreamParams().type() == 1.1430 + OptionalInputStreamParams::TInputStreamParams) { 1.1431 + mInputStreamParams = 1.1432 + aParams.optionalInputStreamParams().get_InputStreamParams(); 1.1433 + } 1.1434 + } 1.1435 + 1.1436 + NS_DECL_ISUPPORTS_INHERITED 1.1437 + 1.1438 + virtual already_AddRefed<nsIDOMBlob> 1.1439 + CreateSlice(uint64_t aStart, uint64_t aLength, const nsAString& aContentType) 1.1440 + MOZ_OVERRIDE; 1.1441 + 1.1442 + NS_IMETHOD 1.1443 + GetInternalStream(nsIInputStream** aStream) MOZ_OVERRIDE; 1.1444 + 1.1445 + NS_IMETHOD 1.1446 + GetLastModifiedDate(JSContext* cx, 1.1447 + JS::MutableHandle<JS::Value> aLastModifiedDate) 1.1448 + MOZ_OVERRIDE; 1.1449 + 1.1450 + virtual void* 1.1451 + GetPBlob() MOZ_OVERRIDE; 1.1452 + 1.1453 +private: 1.1454 + ~RemoteBlob() 1.1455 + { 1.1456 + if (mActor) { 1.1457 + mActor->NoteDyingRemoteBlob(); 1.1458 + } 1.1459 + } 1.1460 +}; 1.1461 + 1.1462 +class BlobParent::RemoteBlob::StreamHelper MOZ_FINAL 1.1463 + : public nsRunnable 1.1464 +{ 1.1465 + mozilla::Monitor mMonitor; 1.1466 + BlobParent* mActor; 1.1467 + nsCOMPtr<nsIDOMBlob> mSourceBlob; 1.1468 + nsRefPtr<RemoteInputStream> mInputStream; 1.1469 + bool mDone; 1.1470 + 1.1471 +public: 1.1472 + StreamHelper(BlobParent* aActor, nsIDOMBlob* aSourceBlob) 1.1473 + : mMonitor("BlobParent::RemoteBlob::StreamHelper::mMonitor") 1.1474 + , mActor(aActor) 1.1475 + , mSourceBlob(aSourceBlob) 1.1476 + , mDone(false) 1.1477 + { 1.1478 + // This may be created on any thread. 1.1479 + MOZ_ASSERT(aActor); 1.1480 + MOZ_ASSERT(aSourceBlob); 1.1481 + } 1.1482 + 1.1483 + nsresult 1.1484 + GetStream(nsIInputStream** aInputStream) 1.1485 + { 1.1486 + // This may be called on any thread. 1.1487 + MOZ_ASSERT(aInputStream); 1.1488 + MOZ_ASSERT(mActor); 1.1489 + MOZ_ASSERT(!mInputStream); 1.1490 + MOZ_ASSERT(!mDone); 1.1491 + 1.1492 + if (NS_IsMainThread()) { 1.1493 + RunInternal(false); 1.1494 + } 1.1495 + else { 1.1496 + nsCOMPtr<nsIThread> mainThread = do_GetMainThread(); 1.1497 + NS_ENSURE_TRUE(mainThread, NS_ERROR_FAILURE); 1.1498 + 1.1499 + nsresult rv = mainThread->Dispatch(this, NS_DISPATCH_NORMAL); 1.1500 + NS_ENSURE_SUCCESS(rv, rv); 1.1501 + 1.1502 + { 1.1503 + MonitorAutoLock lock(mMonitor); 1.1504 + while (!mDone) { 1.1505 + lock.Wait(); 1.1506 + } 1.1507 + } 1.1508 + } 1.1509 + 1.1510 + MOZ_ASSERT(!mActor); 1.1511 + MOZ_ASSERT(mDone); 1.1512 + 1.1513 + if (!mInputStream) { 1.1514 + return NS_ERROR_UNEXPECTED; 1.1515 + } 1.1516 + 1.1517 + mInputStream.forget(aInputStream); 1.1518 + return NS_OK; 1.1519 + } 1.1520 + 1.1521 + NS_IMETHOD 1.1522 + Run() 1.1523 + { 1.1524 + MOZ_ASSERT(NS_IsMainThread()); 1.1525 + RunInternal(true); 1.1526 + return NS_OK; 1.1527 + } 1.1528 + 1.1529 +private: 1.1530 + void 1.1531 + RunInternal(bool aNotify) 1.1532 + { 1.1533 + MOZ_ASSERT(NS_IsMainThread()); 1.1534 + MOZ_ASSERT(mActor); 1.1535 + MOZ_ASSERT(!mInputStream); 1.1536 + MOZ_ASSERT(!mDone); 1.1537 + 1.1538 + nsRefPtr<RemoteInputStream> stream = 1.1539 + new RemoteInputStream(mSourceBlob, ParentActor); 1.1540 + 1.1541 + InputStreamParent* streamActor = new InputStreamParent(stream); 1.1542 + if (mActor->SendPBlobStreamConstructor(streamActor)) { 1.1543 + stream.swap(mInputStream); 1.1544 + } 1.1545 + 1.1546 + mActor = nullptr; 1.1547 + 1.1548 + if (aNotify) { 1.1549 + MonitorAutoLock lock(mMonitor); 1.1550 + mDone = true; 1.1551 + lock.Notify(); 1.1552 + } 1.1553 + else { 1.1554 + mDone = true; 1.1555 + } 1.1556 + } 1.1557 +}; 1.1558 + 1.1559 +class BlobParent::RemoteBlob::SliceHelper MOZ_FINAL 1.1560 + : public nsRunnable 1.1561 +{ 1.1562 + mozilla::Monitor mMonitor; 1.1563 + BlobParent* mActor; 1.1564 + nsCOMPtr<nsIDOMBlob> mSlice; 1.1565 + uint64_t mStart; 1.1566 + uint64_t mLength; 1.1567 + nsString mContentType; 1.1568 + bool mDone; 1.1569 + 1.1570 +public: 1.1571 + SliceHelper(BlobParent* aActor) 1.1572 + : mMonitor("BlobParent::RemoteBlob::SliceHelper::mMonitor") 1.1573 + , mActor(aActor) 1.1574 + , mStart(0) 1.1575 + , mLength(0) 1.1576 + , mDone(false) 1.1577 + { 1.1578 + // This may be created on any thread. 1.1579 + MOZ_ASSERT(aActor); 1.1580 + } 1.1581 + 1.1582 + nsresult 1.1583 + GetSlice(uint64_t aStart, 1.1584 + uint64_t aLength, 1.1585 + const nsAString& aContentType, 1.1586 + nsIDOMBlob** aSlice) 1.1587 + { 1.1588 + // This may be called on any thread. 1.1589 + MOZ_ASSERT(aSlice); 1.1590 + MOZ_ASSERT(mActor); 1.1591 + MOZ_ASSERT(!mSlice); 1.1592 + MOZ_ASSERT(!mDone); 1.1593 + 1.1594 + mStart = aStart; 1.1595 + mLength = aLength; 1.1596 + mContentType = aContentType; 1.1597 + 1.1598 + if (NS_IsMainThread()) { 1.1599 + RunInternal(false); 1.1600 + } 1.1601 + else { 1.1602 + nsCOMPtr<nsIThread> mainThread = do_GetMainThread(); 1.1603 + NS_ENSURE_TRUE(mainThread, NS_ERROR_FAILURE); 1.1604 + 1.1605 + nsresult rv = mainThread->Dispatch(this, NS_DISPATCH_NORMAL); 1.1606 + NS_ENSURE_SUCCESS(rv, rv); 1.1607 + 1.1608 + { 1.1609 + MonitorAutoLock lock(mMonitor); 1.1610 + while (!mDone) { 1.1611 + lock.Wait(); 1.1612 + } 1.1613 + } 1.1614 + } 1.1615 + 1.1616 + MOZ_ASSERT(!mActor); 1.1617 + MOZ_ASSERT(mDone); 1.1618 + 1.1619 + if (!mSlice) { 1.1620 + return NS_ERROR_UNEXPECTED; 1.1621 + } 1.1622 + 1.1623 + mSlice.forget(aSlice); 1.1624 + return NS_OK; 1.1625 + } 1.1626 + 1.1627 + NS_IMETHOD 1.1628 + Run() 1.1629 + { 1.1630 + MOZ_ASSERT(NS_IsMainThread()); 1.1631 + RunInternal(true); 1.1632 + return NS_OK; 1.1633 + } 1.1634 + 1.1635 +private: 1.1636 + void 1.1637 + RunInternal(bool aNotify) 1.1638 + { 1.1639 + MOZ_ASSERT(NS_IsMainThread()); 1.1640 + MOZ_ASSERT(mActor); 1.1641 + MOZ_ASSERT(!mSlice); 1.1642 + MOZ_ASSERT(!mDone); 1.1643 + 1.1644 + NS_ENSURE_TRUE_VOID(mActor->Manager()); 1.1645 + 1.1646 + NormalBlobConstructorParams normalParams; 1.1647 + normalParams.contentType() = mContentType; 1.1648 + normalParams.length() = mLength; 1.1649 + 1.1650 + ParentBlobConstructorParams params; 1.1651 + params.blobParams() = normalParams; 1.1652 + params.optionalInputStreamParams() = void_t(); 1.1653 + 1.1654 + auto* manager = static_cast<ContentParent*>(mActor->Manager()); 1.1655 + MOZ_ASSERT(manager); 1.1656 + 1.1657 + BlobParent* newActor = BlobParent::Create(manager, params); 1.1658 + MOZ_ASSERT(newActor); 1.1659 + 1.1660 + SlicedBlobConstructorParams slicedParams; 1.1661 + slicedParams.contentType() = mContentType; 1.1662 + slicedParams.begin() = mStart; 1.1663 + slicedParams.end() = mStart + mLength; 1.1664 + slicedParams.sourceParent() = mActor; 1.1665 + 1.1666 + ChildBlobConstructorParams otherSideParams = slicedParams; 1.1667 + 1.1668 + if (mActor->Manager()->SendPBlobConstructor(newActor, otherSideParams)) { 1.1669 + mSlice = newActor->GetBlob(); 1.1670 + } 1.1671 + 1.1672 + mActor = nullptr; 1.1673 + 1.1674 + if (aNotify) { 1.1675 + MonitorAutoLock lock(mMonitor); 1.1676 + mDone = true; 1.1677 + lock.Notify(); 1.1678 + } 1.1679 + else { 1.1680 + mDone = true; 1.1681 + } 1.1682 + } 1.1683 +}; 1.1684 + 1.1685 +/******************************************************************************* 1.1686 + * BlobChild::RemoteBlob Implementation 1.1687 + ******************************************************************************/ 1.1688 + 1.1689 +NS_IMPL_ISUPPORTS_INHERITED(BlobParent::RemoteBlob, nsDOMFile, nsIRemoteBlob) 1.1690 + 1.1691 +already_AddRefed<nsIDOMBlob> 1.1692 +BlobParent:: 1.1693 +RemoteBlob::CreateSlice(uint64_t aStart, 1.1694 + uint64_t aLength, 1.1695 + const nsAString& aContentType) 1.1696 +{ 1.1697 + if (!mActor) { 1.1698 + return nullptr; 1.1699 + } 1.1700 + 1.1701 + nsRefPtr<SliceHelper> helper = new SliceHelper(mActor); 1.1702 + 1.1703 + nsCOMPtr<nsIDOMBlob> slice; 1.1704 + nsresult rv = 1.1705 + helper->GetSlice(aStart, aLength, aContentType, getter_AddRefs(slice)); 1.1706 + NS_ENSURE_SUCCESS(rv, nullptr); 1.1707 + 1.1708 + return slice.forget(); 1.1709 +} 1.1710 + 1.1711 +NS_IMETHODIMP 1.1712 +BlobParent:: 1.1713 +RemoteBlob::GetInternalStream(nsIInputStream** aStream) 1.1714 +{ 1.1715 + if (mInputStreamParams.type() != InputStreamParams::T__None) { 1.1716 + nsTArray<FileDescriptor> fds; 1.1717 + nsCOMPtr<nsIInputStream> realStream = 1.1718 + DeserializeInputStream(mInputStreamParams, fds); 1.1719 + if (!realStream) { 1.1720 + NS_WARNING("Failed to deserialize stream!"); 1.1721 + return NS_ERROR_UNEXPECTED; 1.1722 + } 1.1723 + 1.1724 + nsCOMPtr<nsIInputStream> stream = 1.1725 + new BlobInputStreamTether(realStream, this); 1.1726 + stream.forget(aStream); 1.1727 + return NS_OK; 1.1728 + } 1.1729 + 1.1730 + if (!mActor) { 1.1731 + return NS_ERROR_UNEXPECTED; 1.1732 + } 1.1733 + 1.1734 + nsRefPtr<StreamHelper> helper = new StreamHelper(mActor, this); 1.1735 + return helper->GetStream(aStream); 1.1736 +} 1.1737 + 1.1738 +NS_IMETHODIMP 1.1739 +BlobParent:: 1.1740 +RemoteBlob::GetLastModifiedDate(JSContext* cx, 1.1741 + JS::MutableHandle<JS::Value> aLastModifiedDate) 1.1742 +{ 1.1743 + if (IsDateUnknown()) { 1.1744 + aLastModifiedDate.setNull(); 1.1745 + } else { 1.1746 + JSObject* date = JS_NewDateObjectMsec(cx, mLastModificationDate); 1.1747 + if (!date) { 1.1748 + return NS_ERROR_OUT_OF_MEMORY; 1.1749 + } 1.1750 + aLastModifiedDate.setObject(*date); 1.1751 + } 1.1752 + return NS_OK; 1.1753 +} 1.1754 + 1.1755 +void* 1.1756 +BlobParent:: 1.1757 +RemoteBlob::GetPBlob() 1.1758 +{ 1.1759 + return static_cast<PBlobParent*>(mActor); 1.1760 +} 1.1761 + 1.1762 +/******************************************************************************* 1.1763 + * BlobParent 1.1764 + ******************************************************************************/ 1.1765 + 1.1766 +BlobParent::BlobParent(ContentParent* aManager, nsIDOMBlob* aBlob) 1.1767 + : mBlob(aBlob) 1.1768 + , mRemoteBlob(nullptr) 1.1769 + , mStrongManager(aManager) 1.1770 + , mOwnsBlob(true) 1.1771 + , mBlobIsFile(false) 1.1772 +{ 1.1773 + MOZ_ASSERT(NS_IsMainThread()); 1.1774 + MOZ_ASSERT(aManager); 1.1775 + MOZ_ASSERT(aBlob); 1.1776 + 1.1777 + aBlob->AddRef(); 1.1778 + 1.1779 + nsCOMPtr<nsIDOMFile> file = do_QueryInterface(aBlob); 1.1780 + mBlobIsFile = !!file; 1.1781 +} 1.1782 + 1.1783 +BlobParent::BlobParent(ContentParent* aManager, 1.1784 + const ParentBlobConstructorParams& aParams) 1.1785 + : mBlob(nullptr) 1.1786 + , mRemoteBlob(nullptr) 1.1787 + , mStrongManager(aManager) 1.1788 + , mOwnsBlob(false) 1.1789 + , mBlobIsFile(false) 1.1790 +{ 1.1791 + MOZ_ASSERT(NS_IsMainThread()); 1.1792 + MOZ_ASSERT(aManager); 1.1793 + 1.1794 + ChildBlobConstructorParams::Type paramsType = aParams.blobParams().type(); 1.1795 + 1.1796 + mBlobIsFile = 1.1797 + paramsType == ChildBlobConstructorParams::TFileBlobConstructorParams || 1.1798 + paramsType == ChildBlobConstructorParams::TMysteryBlobConstructorParams; 1.1799 + 1.1800 + nsRefPtr<RemoteBlob> remoteBlob = CreateRemoteBlob(aParams); 1.1801 + MOZ_ASSERT(remoteBlob); 1.1802 + 1.1803 + remoteBlob->SetActor(this); 1.1804 + remoteBlob->MaybeSetInputStream(aParams); 1.1805 + remoteBlob.forget(&mRemoteBlob); 1.1806 + 1.1807 + mBlob = mRemoteBlob; 1.1808 + mOwnsBlob = true; 1.1809 +} 1.1810 + 1.1811 +BlobParent::~BlobParent() 1.1812 +{ 1.1813 +} 1.1814 + 1.1815 +BlobParent* 1.1816 +BlobParent::Create(ContentParent* aManager, 1.1817 + const ParentBlobConstructorParams& aParams) 1.1818 +{ 1.1819 + MOZ_ASSERT(NS_IsMainThread()); 1.1820 + MOZ_ASSERT(aManager); 1.1821 + 1.1822 + const ChildBlobConstructorParams& blobParams = aParams.blobParams(); 1.1823 + 1.1824 + switch (blobParams.type()) { 1.1825 + case ChildBlobConstructorParams::TNormalBlobConstructorParams: 1.1826 + case ChildBlobConstructorParams::TFileBlobConstructorParams: 1.1827 + case ChildBlobConstructorParams::TMysteryBlobConstructorParams: 1.1828 + return new BlobParent(aManager, aParams); 1.1829 + 1.1830 + case ChildBlobConstructorParams::TSlicedBlobConstructorParams: { 1.1831 + const SlicedBlobConstructorParams& params = 1.1832 + blobParams.get_SlicedBlobConstructorParams(); 1.1833 + 1.1834 + auto* actor = 1.1835 + const_cast<BlobParent*>( 1.1836 + static_cast<const BlobParent*>(params.sourceParent())); 1.1837 + MOZ_ASSERT(actor); 1.1838 + 1.1839 + nsCOMPtr<nsIDOMBlob> source = actor->GetBlob(); 1.1840 + MOZ_ASSERT(source); 1.1841 + 1.1842 + nsCOMPtr<nsIDOMBlob> slice; 1.1843 + nsresult rv = 1.1844 + source->Slice(params.begin(), params.end(), params.contentType(), 3, 1.1845 + getter_AddRefs(slice)); 1.1846 + NS_ENSURE_SUCCESS(rv, nullptr); 1.1847 + 1.1848 + return new BlobParent(aManager, slice); 1.1849 + } 1.1850 + 1.1851 + default: 1.1852 + MOZ_CRASH("Unknown params!"); 1.1853 + } 1.1854 + 1.1855 + return nullptr; 1.1856 +} 1.1857 + 1.1858 +already_AddRefed<nsIDOMBlob> 1.1859 +BlobParent::GetBlob() 1.1860 +{ 1.1861 + MOZ_ASSERT(NS_IsMainThread()); 1.1862 + MOZ_ASSERT(mBlob); 1.1863 + 1.1864 + nsCOMPtr<nsIDOMBlob> blob; 1.1865 + 1.1866 + // Remote blobs are held alive until the first call to GetBlob. Thereafter we 1.1867 + // only hold a weak reference. Normal blobs are held alive until the actor is 1.1868 + // destroyed. 1.1869 + if (mRemoteBlob && mOwnsBlob) { 1.1870 + blob = dont_AddRef(mBlob); 1.1871 + mOwnsBlob = false; 1.1872 + } 1.1873 + else { 1.1874 + blob = mBlob; 1.1875 + } 1.1876 + 1.1877 + MOZ_ASSERT(blob); 1.1878 + 1.1879 + return blob.forget(); 1.1880 +} 1.1881 + 1.1882 +bool 1.1883 +BlobParent::SetMysteryBlobInfo(const nsString& aName, 1.1884 + const nsString& aContentType, 1.1885 + uint64_t aLength, 1.1886 + uint64_t aLastModifiedDate) 1.1887 +{ 1.1888 + MOZ_ASSERT(NS_IsMainThread()); 1.1889 + MOZ_ASSERT(mBlob); 1.1890 + MOZ_ASSERT(mRemoteBlob); 1.1891 + MOZ_ASSERT(aLastModifiedDate != UINT64_MAX); 1.1892 + 1.1893 + ToConcreteBlob(mBlob)->SetLazyData(aName, aContentType, aLength, 1.1894 + aLastModifiedDate); 1.1895 + 1.1896 + FileBlobConstructorParams params(aName, aContentType, aLength, 1.1897 + aLastModifiedDate); 1.1898 + return SendResolveMystery(params); 1.1899 +} 1.1900 + 1.1901 +bool 1.1902 +BlobParent::SetMysteryBlobInfo(const nsString& aContentType, uint64_t aLength) 1.1903 +{ 1.1904 + MOZ_ASSERT(NS_IsMainThread()); 1.1905 + MOZ_ASSERT(mBlob); 1.1906 + MOZ_ASSERT(mRemoteBlob); 1.1907 + 1.1908 + nsString voidString; 1.1909 + voidString.SetIsVoid(true); 1.1910 + 1.1911 + ToConcreteBlob(mBlob)->SetLazyData(voidString, aContentType, aLength, 1.1912 + UINT64_MAX); 1.1913 + 1.1914 + NormalBlobConstructorParams params(aContentType, aLength); 1.1915 + return SendResolveMystery(params); 1.1916 +} 1.1917 + 1.1918 +already_AddRefed<BlobParent::RemoteBlob> 1.1919 +BlobParent::CreateRemoteBlob(const ParentBlobConstructorParams& aParams) 1.1920 +{ 1.1921 + MOZ_ASSERT(NS_IsMainThread()); 1.1922 + 1.1923 + const ChildBlobConstructorParams& blobParams = aParams.blobParams(); 1.1924 + 1.1925 + nsRefPtr<RemoteBlob> remoteBlob; 1.1926 + 1.1927 + switch (blobParams.type()) { 1.1928 + case ChildBlobConstructorParams::TNormalBlobConstructorParams: { 1.1929 + const NormalBlobConstructorParams& params = 1.1930 + blobParams.get_NormalBlobConstructorParams(); 1.1931 + remoteBlob = new RemoteBlob(params.contentType(), params.length()); 1.1932 + break; 1.1933 + } 1.1934 + 1.1935 + case ChildBlobConstructorParams::TFileBlobConstructorParams: { 1.1936 + const FileBlobConstructorParams& params = 1.1937 + blobParams.get_FileBlobConstructorParams(); 1.1938 + remoteBlob = 1.1939 + new RemoteBlob(params.name(), params.contentType(), params.length(), 1.1940 + params.modDate()); 1.1941 + break; 1.1942 + } 1.1943 + 1.1944 + case ChildBlobConstructorParams::TMysteryBlobConstructorParams: { 1.1945 + remoteBlob = new RemoteBlob(); 1.1946 + break; 1.1947 + } 1.1948 + 1.1949 + default: 1.1950 + MOZ_CRASH("Unknown params!"); 1.1951 + } 1.1952 + 1.1953 + MOZ_ASSERT(remoteBlob); 1.1954 + 1.1955 + if (NS_FAILED(remoteBlob->SetMutable(false))) { 1.1956 + MOZ_CRASH("Failed to make remote blob immutable!"); 1.1957 + } 1.1958 + 1.1959 + return remoteBlob.forget(); 1.1960 +} 1.1961 + 1.1962 +void 1.1963 +BlobParent::NoteDyingRemoteBlob() 1.1964 +{ 1.1965 + MOZ_ASSERT(mBlob); 1.1966 + MOZ_ASSERT(mRemoteBlob); 1.1967 + MOZ_ASSERT(!mOwnsBlob); 1.1968 + 1.1969 + // This may be called on any thread due to the fact that RemoteBlob is 1.1970 + // designed to be passed between threads. We must start the shutdown process 1.1971 + // on the main thread, so we proxy here if necessary. 1.1972 + if (!NS_IsMainThread()) { 1.1973 + nsCOMPtr<nsIRunnable> runnable = 1.1974 + NS_NewNonOwningRunnableMethod(this, &BlobParent::NoteDyingRemoteBlob); 1.1975 + if (NS_FAILED(NS_DispatchToMainThread(runnable))) { 1.1976 + MOZ_ASSERT(false, "Should never fail!"); 1.1977 + } 1.1978 + 1.1979 + return; 1.1980 + } 1.1981 + 1.1982 + // Must do this before calling Send__delete__ or we'll crash there trying to 1.1983 + // access a dangling pointer. 1.1984 + mBlob = nullptr; 1.1985 + mRemoteBlob = nullptr; 1.1986 + 1.1987 + mozilla::unused << PBlobParent::Send__delete__(this); 1.1988 +} 1.1989 + 1.1990 +void 1.1991 +BlobParent::NoteRunnableCompleted(OpenStreamRunnable* aRunnable) 1.1992 +{ 1.1993 + MOZ_ASSERT(NS_IsMainThread()); 1.1994 + 1.1995 + for (uint32_t index = 0; index < mOpenStreamRunnables.Length(); index++) { 1.1996 + nsRevocableEventPtr<OpenStreamRunnable>& runnable = 1.1997 + mOpenStreamRunnables[index]; 1.1998 + 1.1999 + if (runnable.get() == aRunnable) { 1.2000 + runnable.Forget(); 1.2001 + mOpenStreamRunnables.RemoveElementAt(index); 1.2002 + return; 1.2003 + } 1.2004 + } 1.2005 + 1.2006 + MOZ_CRASH("Runnable not in our array!"); 1.2007 +} 1.2008 + 1.2009 +void 1.2010 +BlobParent::ActorDestroy(ActorDestroyReason aWhy) 1.2011 +{ 1.2012 + MOZ_ASSERT(NS_IsMainThread()); 1.2013 + 1.2014 + if (mRemoteBlob) { 1.2015 + mRemoteBlob->SetActor(nullptr); 1.2016 + } 1.2017 + 1.2018 + if (mBlob && mOwnsBlob) { 1.2019 + mBlob->Release(); 1.2020 + } 1.2021 + 1.2022 + mStrongManager = nullptr; 1.2023 +} 1.2024 + 1.2025 +PBlobStreamParent* 1.2026 +BlobParent::AllocPBlobStreamParent() 1.2027 +{ 1.2028 + MOZ_ASSERT(NS_IsMainThread()); 1.2029 + 1.2030 + return new InputStreamParent(); 1.2031 +} 1.2032 + 1.2033 +bool 1.2034 +BlobParent::RecvPBlobStreamConstructor(PBlobStreamParent* aActor) 1.2035 +{ 1.2036 + MOZ_ASSERT(NS_IsMainThread()); 1.2037 + MOZ_ASSERT(aActor); 1.2038 + MOZ_ASSERT(mBlob); 1.2039 + MOZ_ASSERT(!mRemoteBlob); 1.2040 + 1.2041 + nsCOMPtr<nsIInputStream> stream; 1.2042 + nsresult rv = mBlob->GetInternalStream(getter_AddRefs(stream)); 1.2043 + NS_ENSURE_SUCCESS(rv, false); 1.2044 + 1.2045 + nsCOMPtr<nsIRemoteBlob> remoteBlob = do_QueryInterface(mBlob); 1.2046 + 1.2047 + nsCOMPtr<IPrivateRemoteInputStream> remoteStream; 1.2048 + if (remoteBlob) { 1.2049 + remoteStream = do_QueryInterface(stream); 1.2050 + } 1.2051 + 1.2052 + // There are three cases in which we can use the stream obtained from the blob 1.2053 + // directly as our serialized stream: 1.2054 + // 1.2055 + // 1. The blob is not a remote blob. 1.2056 + // 2. The blob is a remote blob that represents this actor. 1.2057 + // 3. The blob is a remote blob representing a different actor but we 1.2058 + // already have a non-remote, i.e. serialized, serialized stream. 1.2059 + // 1.2060 + // In all other cases we need to be on a background thread before we can get 1.2061 + // to the real stream. 1.2062 + nsCOMPtr<nsIIPCSerializableInputStream> serializableStream; 1.2063 + if (!remoteBlob || 1.2064 + static_cast<PBlobParent*>(remoteBlob->GetPBlob()) == this || 1.2065 + !remoteStream) { 1.2066 + serializableStream = do_QueryInterface(stream); 1.2067 + if (!serializableStream) { 1.2068 + MOZ_ASSERT(false, "Must be serializable!"); 1.2069 + return false; 1.2070 + } 1.2071 + } 1.2072 + 1.2073 + nsCOMPtr<nsIEventTarget> target = 1.2074 + do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID); 1.2075 + NS_ENSURE_TRUE(target, false); 1.2076 + 1.2077 + nsRefPtr<OpenStreamRunnable> runnable = 1.2078 + new OpenStreamRunnable(this, aActor, stream, serializableStream, target); 1.2079 + 1.2080 + rv = runnable->Dispatch(); 1.2081 + NS_ENSURE_SUCCESS(rv, false); 1.2082 + 1.2083 + // nsRevocableEventPtr lacks some of the operators needed for anything nicer. 1.2084 + *mOpenStreamRunnables.AppendElement() = runnable; 1.2085 + return true; 1.2086 +} 1.2087 + 1.2088 +bool 1.2089 +BlobParent::DeallocPBlobStreamParent(PBlobStreamParent* aActor) 1.2090 +{ 1.2091 + MOZ_ASSERT(NS_IsMainThread()); 1.2092 + 1.2093 + delete static_cast<InputStreamParent*>(aActor); 1.2094 + return true; 1.2095 +} 1.2096 + 1.2097 +bool 1.2098 +BlobParent::RecvResolveMystery(const ResolveMysteryParams& aParams) 1.2099 +{ 1.2100 + MOZ_ASSERT(NS_IsMainThread()); 1.2101 + MOZ_ASSERT(mBlob); 1.2102 + MOZ_ASSERT(!mRemoteBlob); 1.2103 + MOZ_ASSERT(mOwnsBlob); 1.2104 + 1.2105 + if (!mBlobIsFile) { 1.2106 + MOZ_ASSERT(false, "Must always be a file!"); 1.2107 + return false; 1.2108 + } 1.2109 + 1.2110 + nsDOMFileBase* blob = ToConcreteBlob(mBlob); 1.2111 + 1.2112 + switch (aParams.type()) { 1.2113 + case ResolveMysteryParams::TNormalBlobConstructorParams: { 1.2114 + const NormalBlobConstructorParams& params = 1.2115 + aParams.get_NormalBlobConstructorParams(); 1.2116 + nsString voidString; 1.2117 + voidString.SetIsVoid(true); 1.2118 + blob->SetLazyData(voidString, params.contentType(), 1.2119 + params.length(), UINT64_MAX); 1.2120 + break; 1.2121 + } 1.2122 + 1.2123 + case ResolveMysteryParams::TFileBlobConstructorParams: { 1.2124 + const FileBlobConstructorParams& params = 1.2125 + aParams.get_FileBlobConstructorParams(); 1.2126 + blob->SetLazyData(params.name(), params.contentType(), 1.2127 + params.length(), params.modDate()); 1.2128 + break; 1.2129 + } 1.2130 + 1.2131 + default: 1.2132 + MOZ_CRASH("Unknown params!"); 1.2133 + } 1.2134 + 1.2135 + return true; 1.2136 +} 1.2137 + 1.2138 +bool 1.2139 +InputStreamChild::Recv__delete__(const InputStreamParams& aParams, 1.2140 + const OptionalFileDescriptorSet& aFDs) 1.2141 +{ 1.2142 + MOZ_ASSERT(NS_IsMainThread()); 1.2143 + MOZ_ASSERT(mRemoteStream); 1.2144 + 1.2145 + nsTArray<FileDescriptor> fds; 1.2146 + if (aFDs.type() == OptionalFileDescriptorSet::TPFileDescriptorSetChild) { 1.2147 + FileDescriptorSetChild* fdSetActor = 1.2148 + static_cast<FileDescriptorSetChild*>(aFDs.get_PFileDescriptorSetChild()); 1.2149 + MOZ_ASSERT(fdSetActor); 1.2150 + 1.2151 + fdSetActor->ForgetFileDescriptors(fds); 1.2152 + MOZ_ASSERT(!fds.IsEmpty()); 1.2153 + 1.2154 + fdSetActor->Send__delete__(fdSetActor); 1.2155 + } 1.2156 + 1.2157 + nsCOMPtr<nsIInputStream> stream = DeserializeInputStream(aParams, fds); 1.2158 + if (!stream) { 1.2159 + return false; 1.2160 + } 1.2161 + 1.2162 + mRemoteStream->SetStream(stream); 1.2163 + return true; 1.2164 +} 1.2165 + 1.2166 +bool 1.2167 +InputStreamParent::Recv__delete__(const InputStreamParams& aParams, 1.2168 + const OptionalFileDescriptorSet& aFDs) 1.2169 +{ 1.2170 + MOZ_ASSERT(NS_IsMainThread()); 1.2171 + MOZ_ASSERT(mRemoteStream); 1.2172 + 1.2173 + if (aFDs.type() != OptionalFileDescriptorSet::Tvoid_t) { 1.2174 + NS_WARNING("Child cannot send FileDescriptors to the parent!"); 1.2175 + return false; 1.2176 + } 1.2177 + 1.2178 + nsTArray<FileDescriptor> fds; 1.2179 + nsCOMPtr<nsIInputStream> stream = DeserializeInputStream(aParams, fds); 1.2180 + if (!stream) { 1.2181 + return false; 1.2182 + } 1.2183 + 1.2184 + MOZ_ASSERT(fds.IsEmpty()); 1.2185 + 1.2186 + mRemoteStream->SetStream(stream); 1.2187 + return true; 1.2188 +}