/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim: set ts=8 sts=2 et sw=2 tw=80: */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
// Undefine the macro of CreateFile to avoid FileCreatorHelper#CreateFile being // replaced by FileCreatorHelper#CreateFileW. #ifdef CreateFile # undef CreateFile #endif
namespace mozilla::dom {
namespace {
class BeginConsumeBodyRunnable final : public Runnable { public:
BeginConsumeBodyRunnable(BodyConsumer* aConsumer,
ThreadSafeWorkerRef* aWorkerRef)
: Runnable("BeginConsumeBodyRunnable"),
mBodyConsumer(aConsumer),
mWorkerRef(aWorkerRef) {}
/* * Called on successfully reading the complete stream.
*/ class ContinueConsumeBodyRunnable final : public MainThreadWorkerRunnable {
RefPtr<BodyConsumer> mBodyConsumer;
nsresult mStatus;
uint32_t mLength;
uint8_t* mResult;
// ControlRunnable used to complete the releasing of resources on the worker // thread when already shutting down. class AbortConsumeBodyControlRunnable final
: public MainThreadWorkerControlRunnable {
RefPtr<BodyConsumer> mBodyConsumer;
/* * In case of failure to create a stream pump or dispatch stream completion to * worker, ensure we cleanup properly. Thread agnostic.
*/ class MOZ_STACK_CLASS AutoFailConsumeBody final { public:
AutoFailConsumeBody(BodyConsumer* aBodyConsumer,
ThreadSafeWorkerRef* aWorkerRef)
: mBodyConsumer(aBodyConsumer), mWorkerRef(aWorkerRef) {}
~AutoFailConsumeBody() {
AssertIsOnMainThread();
if (!mBodyConsumer) { return;
}
// Web Worker if (mWorkerRef) {
RefPtr<AbortConsumeBodyControlRunnable> r = new AbortConsumeBodyControlRunnable(mBodyConsumer,
mWorkerRef->Private()); if (!r->Dispatch(mWorkerRef->Private())) {
MOZ_CRASH("We are going to leak");
} return;
}
/* * Called on successfully reading the complete stream for Blob.
*/ class ContinueConsumeBlobBodyRunnable final : public MainThreadWorkerRunnable {
RefPtr<BodyConsumer> mBodyConsumer;
RefPtr<BlobImpl> mBlobImpl;
// ControlRunnable used to complete the releasing of resources on the worker // thread when already shutting down. class AbortConsumeBlobBodyControlRunnable final
: public MainThreadWorkerControlRunnable {
RefPtr<BodyConsumer> mBodyConsumer;
// Main-thread. if (!mWorkerRef) {
mBodyConsumer->ContinueConsumeBody(aStatus, aResultLength,
nonconstResult); // The caller is responsible for data. return NS_SUCCESS_ADOPTED_DATA;
}
// Web Worker.
{
RefPtr<ContinueConsumeBodyRunnable> r = new ContinueConsumeBodyRunnable(
mBodyConsumer, mWorkerRef->Private(), aStatus, aResultLength,
nonconstResult); if (r->Dispatch(mWorkerRef->Private())) { // The caller is responsible for data. return NS_SUCCESS_ADOPTED_DATA;
}
}
// The worker is shutting down. Let's use a control runnable to complete the // shutting down procedure.
RefPtr<AbortConsumeBodyControlRunnable> r = new AbortConsumeBodyControlRunnable(mBodyConsumer,
mWorkerRef->Private()); if (NS_WARN_IF(!r->Dispatch(mWorkerRef->Private()))) { return NS_ERROR_FAILURE;
}
// We haven't taken ownership of the data. return NS_OK;
}
workerRef = new ThreadSafeWorkerRef(strongWorkerRef);
} else {
consumer->GlobalTeardownObserver::BindToOwner(aGlobal);
consumer->GlobalFreezeObserver::BindToOwner(aGlobal);
}
nsCOMPtr<nsIRunnable> r = new BeginConsumeBodyRunnable(consumer, workerRef);
aRv = aMainThreadEventTarget->Dispatch(r.forget(), NS_DISPATCH_NORMAL); if (NS_WARN_IF(aRv.Failed())) { return nullptr;
}
if (aSignalImpl) {
consumer->Follow(aSignalImpl);
}
bool exists;
MOZ_TRY(file->Exists(&exists)); if (!exists) { return NS_ERROR_FILE_NOT_FOUND;
}
bool isDir;
MOZ_TRY(file->IsDirectory(&isDir)); if (isDir) { return NS_ERROR_FILE_IS_DIRECTORY;
}
file.forget(aFile); return NS_OK;
}
/* * BeginConsumeBodyMainThread() will automatically reject the consume promise * and clean up on any failures, so there is no need for callers to do so, * reflected in a lack of error return code.
*/ void BodyConsumer::BeginConsumeBodyMainThread(ThreadSafeWorkerRef* aWorkerRef) {
AssertIsOnMainThread();
AutoFailConsumeBody autoReject(this, aWorkerRef);
if (mShuttingDown) { // We haven't started yet, but we have been terminated. AutoFailConsumeBody // will dispatch a runnable to release resources. return;
}
if (mConsumeType == ConsumeType::Blob) {
nsresult rv;
// If we're trying to consume a blob, and the request was for a blob URI, // then just consume that URI's blob instance. if (!mBodyBlobURISpec.IsEmpty()) {
RefPtr<BlobImpl> blobImpl;
rv = NS_GetBlobForBlobURISpec(mBodyBlobURISpec, getter_AddRefs(blobImpl)); if (NS_WARN_IF(NS_FAILED(rv)) || !blobImpl) { return;
}
autoReject.DontFail();
DispatchContinueConsumeBlobBody(blobImpl, aWorkerRef); return;
}
// If we're trying to consume a blob, and the request was for a local // file, then generate and return a File blob.
nsCOMPtr<nsIFile> file;
rv = GetBodyLocalFile(getter_AddRefs(file)); if (!NS_WARN_IF(NS_FAILED(rv)) && file && !aWorkerRef) {
ChromeFilePropertyBag bag;
CopyUTF8toUTF16(mBodyMimeType, bag.mType);
RefPtr<ConsumeBodyDoneObserver> p = new ConsumeBodyDoneObserver(this, aWorkerRef);
nsCOMPtr<nsIStreamListener> listener; if (mConsumeType == ConsumeType::Blob) {
listener = new MutableBlobStreamListener(mBlobStorageType, mBodyMimeType, p,
mMainThreadEventTarget);
} else {
nsCOMPtr<nsIStreamLoader> loader;
rv = NS_NewStreamLoader(getter_AddRefs(loader), p); if (NS_WARN_IF(NS_FAILED(rv))) { return;
}
listener = loader;
}
rv = pump->AsyncRead(listener); if (NS_WARN_IF(NS_FAILED(rv))) { return;
}
// Now that everything succeeded, we can assign the pump to a pointer that // stays alive for the lifetime of the BodyConsumer.
mConsumeBodyPump = pump;
// It is ok for retargeting to fail and reads to happen on the main thread.
autoReject.DontFail();
// Try to retarget, otherwise fall back to main thread.
nsCOMPtr<nsIThreadRetargetableRequest> rr = do_QueryInterface(pump); if (rr) {
nsCOMPtr<nsIEventTarget> sts =
do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID);
RefPtr<TaskQueue> queue =
TaskQueue::Create(sts.forget(), "BodyConsumer STS Delivery Queue");
rv = rr->RetargetDeliveryTo(queue); if (NS_FAILED(rv)) {
NS_WARNING("Retargeting failed");
}
}
}
/* * OnBlobResult() is called when a blob body is ready to be consumed (when its * network transfer completes in BeginConsumeBodyRunnable or its local File has * been wrapped by FileCreationHandler). The blob is sent to the target thread * and ContinueConsumeBody is called.
*/ void BodyConsumer::OnBlobResult(BlobImpl* aBlobImpl,
ThreadSafeWorkerRef* aWorkerRef) {
AssertIsOnMainThread();
// Main-thread. if (!aWorkerRef) { if (aBlobImpl) {
ContinueConsumeBlobBody(aBlobImpl);
} else {
ContinueConsumeBody(NS_ERROR_DOM_ABORT_ERR, 0, nullptr);
} return;
}
// Web Worker. if (aBlobImpl) {
RefPtr<ContinueConsumeBlobBodyRunnable> r = new ContinueConsumeBlobBodyRunnable(this, aWorkerRef->Private(),
aBlobImpl);
if (r->Dispatch(aWorkerRef->Private())) { return;
}
} else {
RefPtr<ContinueConsumeBodyRunnable> r = new ContinueConsumeBodyRunnable( this, aWorkerRef->Private(), NS_ERROR_DOM_ABORT_ERR, 0, nullptr);
if (r->Dispatch(aWorkerRef->Private())) { return;
}
}
// The worker is shutting down. Let's use a control runnable to complete the // shutting down procedure.
RefPtr<AbortConsumeBlobBodyControlRunnable> r = new AbortConsumeBlobBodyControlRunnable(this, aWorkerRef->Private());
/* * ContinueConsumeBody() is to be called on the target thread whenever the * final result of the fetch is known. The fetch promise is resolved or * rejected based on whether the fetch succeeded, and the body can be * converted into the expected type of JS object.
*/ void BodyConsumer::ContinueConsumeBody(nsresult aStatus, uint32_t aResultLength,
uint8_t* aResult, bool aShuttingDown) {
AssertIsOnTargetThread();
// This makes sure that we free the data correctly.
UniquePtr<uint8_t[], JS::FreePolicy> resultPtr{aResult};
if (mBodyConsumed) { return;
}
mBodyConsumed = true;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.