/* -*- 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/. */ #include "FileCreatorHelper.h" #include "mozilla/dom/BindingDeclarations.h" #include "mozilla/dom/ContentChild.h" #include "mozilla/dom/ContentParent.h" #include "mozilla/dom/FileBinding.h" #include "mozilla/dom/File.h" #include "mozilla/dom/Promise.h" #include "nsContentUtils.h" #include "nsPIDOMWindow.h" #include "nsIFile.h" // Undefine the macro of CreateFile to avoid FileCreatorHelper#CreateFile being // replaced by FileCreatorHelper#CreateFileW. #ifdef CreateFile #undef CreateFile #endif namespace mozilla { namespace dom { /* static */ already_AddRefed FileCreatorHelper::CreateFile(nsIGlobalObject* aGlobalObject, nsIFile* aFile, const ChromeFilePropertyBag& aBag, bool aIsFromNsIFile, ErrorResult& aRv) { MOZ_DIAGNOSTIC_ASSERT(NS_IsMainThread()); RefPtr promise = Promise::Create(aGlobalObject, aRv); if (NS_WARN_IF(aRv.Failed())) { return nullptr; } nsCOMPtr window = do_QueryInterface(aGlobalObject); // Parent process if (XRE_IsParentProcess()) { RefPtr file = CreateFileInternal(window, aFile, aBag, aIsFromNsIFile, aRv); if (aRv.Failed()) { return nullptr; } promise->MaybeResolve(file); return promise.forget(); } // Content process. ContentChild* cc = ContentChild::GetSingleton(); if (!cc) { promise->MaybeReject(NS_ERROR_DOM_INVALID_STATE_ERR); return promise.forget(); } if (!cc->GetRemoteType().EqualsLiteral(FILE_REMOTE_TYPE) && !Preferences::GetBool("dom.file.createInChild", false)) { // If this pref is not set and the request is received by the parent // process, this child is killed for security reason. promise->MaybeReject(NS_ERROR_DOM_INVALID_STATE_ERR); return promise.forget(); } RefPtr helper = new FileCreatorHelper(promise, window); // The request is sent to the parent process and it's kept alive by // ContentChild. helper->SendRequest(aFile, aBag, aIsFromNsIFile, aRv); if (NS_WARN_IF(aRv.Failed())) { return nullptr; } return promise.forget(); } /* static */ already_AddRefed FileCreatorHelper::CreateFileInternal(nsPIDOMWindowInner* aWindow, nsIFile* aFile, const ChromeFilePropertyBag& aBag, bool aIsFromNsIFile, ErrorResult& aRv) { bool lastModifiedPassed = false; int64_t lastModified = 0; if (aBag.mLastModified.WasPassed()) { lastModifiedPassed = true; lastModified = aBag.mLastModified.Value(); } RefPtr blobImpl; aRv = CreateBlobImpl(aFile, aBag.mType, aBag.mName, lastModifiedPassed, lastModified, aBag.mExistenceCheck, aIsFromNsIFile, getter_AddRefs(blobImpl)); if (aRv.Failed()) { return nullptr; } RefPtr file = File::Create(aWindow, blobImpl); return file.forget(); } FileCreatorHelper::FileCreatorHelper(Promise* aPromise, nsPIDOMWindowInner* aWindow) : mPromise(aPromise) , mWindow(aWindow) { MOZ_ASSERT(aPromise); } FileCreatorHelper::~FileCreatorHelper() { } void FileCreatorHelper::SendRequest(nsIFile* aFile, const ChromeFilePropertyBag& aBag, bool aIsFromNsIFile, ErrorResult& aRv) { MOZ_ASSERT(aFile); ContentChild* cc = ContentChild::GetSingleton(); if (NS_WARN_IF(!cc)) { aRv.Throw(NS_ERROR_FAILURE); return; } nsID uuid; aRv = nsContentUtils::GenerateUUIDInPlace(uuid); if (NS_WARN_IF(aRv.Failed())) { return; } nsAutoString path; aRv = aFile->GetPath(path); if (NS_WARN_IF(aRv.Failed())) { return; } cc->FileCreationRequest(uuid, this, path, aBag.mType, aBag.mName, aBag.mLastModified, aBag.mExistenceCheck, aIsFromNsIFile); } void FileCreatorHelper::ResponseReceived(BlobImpl* aBlobImpl, nsresult aRv) { if (NS_FAILED(aRv)) { mPromise->MaybeReject(aRv); return; } RefPtr file = File::Create(mWindow, aBlobImpl); mPromise->MaybeResolve(file); } /* static */ nsresult FileCreatorHelper::CreateBlobImplForIPC(const nsAString& aPath, const nsAString& aType, const nsAString& aName, bool aLastModifiedPassed, int64_t aLastModified, bool aExistenceCheck, bool aIsFromNsIFile, BlobImpl** aBlobImpl) { nsCOMPtr file; nsresult rv = NS_NewLocalFile(aPath, true, getter_AddRefs(file)); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } return CreateBlobImpl(file, aType, aName, aLastModifiedPassed, aLastModified, aExistenceCheck, aIsFromNsIFile, aBlobImpl); } /* static */ nsresult FileCreatorHelper::CreateBlobImpl(nsIFile* aFile, const nsAString& aType, const nsAString& aName, bool aLastModifiedPassed, int64_t aLastModified, bool aExistenceCheck, bool aIsFromNsIFile, BlobImpl** aBlobImpl) { if (!aExistenceCheck) { RefPtr impl = new FileBlobImpl(aFile); if (!aName.IsEmpty()) { impl->SetName(aName); } if (!aType.IsEmpty()) { impl->SetType(aType); } if (aLastModifiedPassed) { impl->SetLastModified(aLastModified); } impl.forget(aBlobImpl); return NS_OK; } RefPtr impl = new MultipartBlobImpl(EmptyString()); nsresult rv = impl->InitializeChromeFile(aFile, aType, aName, aLastModifiedPassed, aLastModified, aIsFromNsIFile); if (NS_FAILED(rv)) { return rv; } MOZ_ASSERT(impl->IsFile()); impl.forget(aBlobImpl); return NS_OK; } } // dom namespace } // mozilla namespace