Blame dom/file/FileCreatorHelper.cpp

Packit f0b94e
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
Packit f0b94e
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
Packit f0b94e
/* This Source Code Form is subject to the terms of the Mozilla Public
Packit f0b94e
 * License, v. 2.0. If a copy of the MPL was not distributed with this
Packit f0b94e
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
Packit f0b94e
Packit f0b94e
#include "FileCreatorHelper.h"
Packit f0b94e
Packit f0b94e
#include "mozilla/dom/BindingDeclarations.h"
Packit f0b94e
#include "mozilla/dom/ContentChild.h"
Packit f0b94e
#include "mozilla/dom/ContentParent.h"
Packit f0b94e
#include "mozilla/dom/FileBinding.h"
Packit f0b94e
#include "mozilla/dom/File.h"
Packit f0b94e
#include "mozilla/dom/Promise.h"
Packit f0b94e
#include "nsContentUtils.h"
Packit f0b94e
#include "nsPIDOMWindow.h"
Packit f0b94e
#include "nsIFile.h"
Packit f0b94e
Packit f0b94e
// Undefine the macro of CreateFile to avoid FileCreatorHelper#CreateFile being
Packit f0b94e
// replaced by FileCreatorHelper#CreateFileW.
Packit f0b94e
#ifdef CreateFile
Packit f0b94e
#undef CreateFile
Packit f0b94e
#endif
Packit f0b94e
Packit f0b94e
namespace mozilla {
Packit f0b94e
namespace dom {
Packit f0b94e
Packit f0b94e
/* static */ already_AddRefed<Promise> FileCreatorHelper::CreateFile(
Packit f0b94e
    nsIGlobalObject* aGlobalObject, nsIFile* aFile,
Packit f0b94e
    const ChromeFilePropertyBag& aBag, bool aIsFromNsIFile, ErrorResult& aRv) {
Packit f0b94e
  MOZ_DIAGNOSTIC_ASSERT(NS_IsMainThread());
Packit f0b94e
Packit f0b94e
  RefPtr<Promise> promise = Promise::Create(aGlobalObject, aRv);
Packit f0b94e
  if (NS_WARN_IF(aRv.Failed())) {
Packit f0b94e
    return nullptr;
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  nsCOMPtr<nsPIDOMWindowInner> window = do_QueryInterface(aGlobalObject);
Packit f0b94e
Packit f0b94e
  // Parent process
Packit f0b94e
Packit f0b94e
  if (XRE_IsParentProcess()) {
Packit f0b94e
    RefPtr<File> file =
Packit f0b94e
        CreateFileInternal(window, aFile, aBag, aIsFromNsIFile, aRv);
Packit f0b94e
    if (aRv.Failed()) {
Packit f0b94e
      return nullptr;
Packit f0b94e
    }
Packit f0b94e
    promise->MaybeResolve(file);
Packit f0b94e
    return promise.forget();
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  // Content process.
Packit f0b94e
Packit f0b94e
  ContentChild* cc = ContentChild::GetSingleton();
Packit f0b94e
  if (!cc) {
Packit f0b94e
    promise->MaybeReject(NS_ERROR_DOM_INVALID_STATE_ERR);
Packit f0b94e
    return promise.forget();
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  if (!cc->GetRemoteType().EqualsLiteral(FILE_REMOTE_TYPE) &&
Packit f0b94e
      !Preferences::GetBool("dom.file.createInChild", false)) {
Packit f0b94e
    // If this pref is not set and the request is received by the parent
Packit f0b94e
    // process, this child is killed for security reason.
Packit f0b94e
    promise->MaybeReject(NS_ERROR_DOM_INVALID_STATE_ERR);
Packit f0b94e
    return promise.forget();
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  RefPtr<FileCreatorHelper> helper = new FileCreatorHelper(promise, window);
Packit f0b94e
Packit f0b94e
  // The request is sent to the parent process and it's kept alive by
Packit f0b94e
  // ContentChild.
Packit f0b94e
  helper->SendRequest(aFile, aBag, aIsFromNsIFile, aRv);
Packit f0b94e
  if (NS_WARN_IF(aRv.Failed())) {
Packit f0b94e
    return nullptr;
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  return promise.forget();
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
/* static */ already_AddRefed<File> FileCreatorHelper::CreateFileInternal(
Packit f0b94e
    nsPIDOMWindowInner* aWindow, nsIFile* aFile,
Packit f0b94e
    const ChromeFilePropertyBag& aBag, bool aIsFromNsIFile, ErrorResult& aRv) {
Packit f0b94e
  bool lastModifiedPassed = false;
Packit f0b94e
  int64_t lastModified = 0;
Packit f0b94e
  if (aBag.mLastModified.WasPassed()) {
Packit f0b94e
    lastModifiedPassed = true;
Packit f0b94e
    lastModified = aBag.mLastModified.Value();
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  RefPtr<BlobImpl> blobImpl;
Packit f0b94e
  aRv = CreateBlobImpl(aFile, aBag.mType, aBag.mName, lastModifiedPassed,
Packit f0b94e
                       lastModified, aBag.mExistenceCheck, aIsFromNsIFile,
Packit f0b94e
                       getter_AddRefs(blobImpl));
Packit f0b94e
  if (aRv.Failed()) {
Packit f0b94e
    return nullptr;
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  RefPtr<File> file = File::Create(aWindow, blobImpl);
Packit f0b94e
  return file.forget();
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
FileCreatorHelper::FileCreatorHelper(Promise* aPromise,
Packit f0b94e
                                     nsPIDOMWindowInner* aWindow)
Packit f0b94e
    : mPromise(aPromise), mWindow(aWindow) {
Packit f0b94e
  MOZ_ASSERT(aPromise);
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
FileCreatorHelper::~FileCreatorHelper() {}
Packit f0b94e
Packit f0b94e
void FileCreatorHelper::SendRequest(nsIFile* aFile,
Packit f0b94e
                                    const ChromeFilePropertyBag& aBag,
Packit f0b94e
                                    bool aIsFromNsIFile, ErrorResult& aRv) {
Packit f0b94e
  MOZ_ASSERT(aFile);
Packit f0b94e
Packit f0b94e
  ContentChild* cc = ContentChild::GetSingleton();
Packit f0b94e
  if (NS_WARN_IF(!cc)) {
Packit f0b94e
    aRv.Throw(NS_ERROR_FAILURE);
Packit f0b94e
    return;
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  nsID uuid;
Packit f0b94e
  aRv = nsContentUtils::GenerateUUIDInPlace(uuid);
Packit f0b94e
  if (NS_WARN_IF(aRv.Failed())) {
Packit f0b94e
    return;
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  nsAutoString path;
Packit f0b94e
  aRv = aFile->GetPath(path);
Packit f0b94e
  if (NS_WARN_IF(aRv.Failed())) {
Packit f0b94e
    return;
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  cc->FileCreationRequest(uuid, this, path, aBag.mType, aBag.mName,
Packit f0b94e
                          aBag.mLastModified, aBag.mExistenceCheck,
Packit f0b94e
                          aIsFromNsIFile);
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
void FileCreatorHelper::ResponseReceived(BlobImpl* aBlobImpl, nsresult aRv) {
Packit f0b94e
  if (NS_FAILED(aRv)) {
Packit f0b94e
    mPromise->MaybeReject(aRv);
Packit f0b94e
    return;
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  RefPtr<File> file = File::Create(mWindow, aBlobImpl);
Packit f0b94e
  mPromise->MaybeResolve(file);
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
/* static */ nsresult FileCreatorHelper::CreateBlobImplForIPC(
Packit f0b94e
    const nsAString& aPath, const nsAString& aType, const nsAString& aName,
Packit f0b94e
    bool aLastModifiedPassed, int64_t aLastModified, bool aExistenceCheck,
Packit f0b94e
    bool aIsFromNsIFile, BlobImpl** aBlobImpl) {
Packit f0b94e
  nsCOMPtr<nsIFile> file;
Packit f0b94e
  nsresult rv = NS_NewLocalFile(aPath, true, getter_AddRefs(file));
Packit f0b94e
  if (NS_WARN_IF(NS_FAILED(rv))) {
Packit f0b94e
    return rv;
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  return CreateBlobImpl(file, aType, aName, aLastModifiedPassed, aLastModified,
Packit f0b94e
                        aExistenceCheck, aIsFromNsIFile, aBlobImpl);
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
/* static */ nsresult FileCreatorHelper::CreateBlobImpl(
Packit f0b94e
    nsIFile* aFile, const nsAString& aType, const nsAString& aName,
Packit f0b94e
    bool aLastModifiedPassed, int64_t aLastModified, bool aExistenceCheck,
Packit f0b94e
    bool aIsFromNsIFile, BlobImpl** aBlobImpl) {
Packit f0b94e
  if (!aExistenceCheck) {
Packit f0b94e
    RefPtr<FileBlobImpl> impl = new FileBlobImpl(aFile);
Packit f0b94e
Packit f0b94e
    if (!aName.IsEmpty()) {
Packit f0b94e
      impl->SetName(aName);
Packit f0b94e
    }
Packit f0b94e
Packit f0b94e
    if (!aType.IsEmpty()) {
Packit f0b94e
      impl->SetType(aType);
Packit f0b94e
    }
Packit f0b94e
Packit f0b94e
    if (aLastModifiedPassed) {
Packit f0b94e
      impl->SetLastModified(aLastModified);
Packit f0b94e
    }
Packit f0b94e
Packit f0b94e
    impl.forget(aBlobImpl);
Packit f0b94e
    return NS_OK;
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  RefPtr<MultipartBlobImpl> impl = new MultipartBlobImpl(EmptyString());
Packit f0b94e
  nsresult rv = impl->InitializeChromeFile(
Packit f0b94e
      aFile, aType, aName, aLastModifiedPassed, aLastModified, aIsFromNsIFile);
Packit f0b94e
  if (NS_FAILED(rv)) {
Packit f0b94e
    return rv;
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  MOZ_ASSERT(impl->IsFile());
Packit f0b94e
Packit f0b94e
  impl.forget(aBlobImpl);
Packit f0b94e
  return NS_OK;
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
}  // namespace dom
Packit f0b94e
}  // namespace mozilla