summaryrefslogtreecommitdiffstats
path: root/dom/filesystem/FileSystemRequestParent.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'dom/filesystem/FileSystemRequestParent.cpp')
-rw-r--r--dom/filesystem/FileSystemRequestParent.cpp188
1 files changed, 188 insertions, 0 deletions
diff --git a/dom/filesystem/FileSystemRequestParent.cpp b/dom/filesystem/FileSystemRequestParent.cpp
new file mode 100644
index 0000000000..25211dbd23
--- /dev/null
+++ b/dom/filesystem/FileSystemRequestParent.cpp
@@ -0,0 +1,188 @@
+/* -*- 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 "mozilla/dom/FileSystemRequestParent.h"
+#include "mozilla/dom/PFileSystemParams.h"
+
+#include "GetDirectoryListingTask.h"
+#include "GetFileOrDirectoryTask.h"
+#include "GetFilesTask.h"
+
+#include "mozilla/dom/BlobImpl.h"
+#include "mozilla/dom/ContentParent.h"
+#include "mozilla/dom/FileSystemBase.h"
+#include "mozilla/dom/FileSystemSecurity.h"
+#include "mozilla/ipc/BackgroundParent.h"
+#include "mozilla/dom/OSFileSystem.h"
+#include "mozilla/Preferences.h"
+#include "mozilla/ScopeExit.h"
+#include "mozilla/Unused.h"
+#include "nsProxyRelease.h"
+
+using namespace mozilla::ipc;
+
+namespace mozilla::dom {
+
+FileSystemRequestParent::FileSystemRequestParent() : mDestroyed(false) {
+ AssertIsOnBackgroundThread();
+}
+
+FileSystemRequestParent::~FileSystemRequestParent() {
+ AssertIsOnBackgroundThread();
+}
+
+#define FILESYSTEM_REQUEST_PARENT_DISPATCH_ENTRY(name) \
+ case FileSystemParams::TFileSystem##name##Params: { \
+ const FileSystem##name##Params& p = aParams; \
+ mFileSystem = new OSFileSystemParent(p.filesystem()); \
+ MOZ_ASSERT(mFileSystem); \
+ mTask = name##TaskParent::Create(mFileSystem, p, this, rv); \
+ if (NS_WARN_IF(rv.Failed())) { \
+ rv.SuppressException(); \
+ return false; \
+ } \
+ break; \
+ }
+
+bool FileSystemRequestParent::Initialize(const FileSystemParams& aParams) {
+ AssertIsOnBackgroundThread();
+
+ ErrorResult rv;
+
+ switch (aParams.type()) {
+ FILESYSTEM_REQUEST_PARENT_DISPATCH_ENTRY(GetDirectoryListing)
+ FILESYSTEM_REQUEST_PARENT_DISPATCH_ENTRY(GetFileOrDirectory)
+ FILESYSTEM_REQUEST_PARENT_DISPATCH_ENTRY(GetFiles)
+
+ default: {
+ MOZ_CRASH("not reached");
+ break;
+ }
+ }
+
+ if (NS_WARN_IF(!mTask || !mFileSystem)) {
+ // Should never reach here.
+ return false;
+ }
+
+ return true;
+}
+
+namespace {
+
+class CheckPermissionRunnable final : public Runnable {
+ public:
+ CheckPermissionRunnable(
+ already_AddRefed<ThreadsafeContentParentHandle> aParent,
+ FileSystemRequestParent* aActor, FileSystemTaskParentBase* aTask,
+ const nsAString& aPath)
+ : Runnable("dom::CheckPermissionRunnable"),
+ mContentHandle(aParent),
+ mActor(aActor),
+ mTask(aTask),
+ mPath(aPath),
+ mBackgroundEventTarget(GetCurrentSerialEventTarget()) {
+ AssertIsInMainProcess();
+ AssertIsOnBackgroundThread();
+
+ MOZ_ASSERT(mContentHandle);
+ MOZ_ASSERT(mActor);
+ MOZ_ASSERT(mTask);
+ MOZ_ASSERT(mBackgroundEventTarget);
+ }
+
+ NS_IMETHOD
+ Run() override {
+ if (NS_IsMainThread()) {
+ if (!mozilla::Preferences::GetBool("dom.filesystem.pathcheck.disabled",
+ false)) {
+ RefPtr<FileSystemSecurity> fss = FileSystemSecurity::Get();
+ if (NS_WARN_IF(!fss || !fss->ContentProcessHasAccessTo(
+ mContentHandle->ChildID(), mPath))) {
+ AssertIsOnMainThread();
+ if (RefPtr<ContentParent> contentParent =
+ mContentHandle->GetContentParent()) {
+ contentParent->KillHard("This path is not allowed.");
+ }
+ return NS_OK;
+ }
+ }
+
+ return mBackgroundEventTarget->Dispatch(this, NS_DISPATCH_NORMAL);
+ }
+
+ AssertIsOnBackgroundThread();
+
+ // It can happen that this actor has been destroyed in the meantime we were
+ // on the main-thread.
+ if (!mActor->Destroyed()) {
+ mTask->Start();
+ }
+
+ return NS_OK;
+ }
+
+ private:
+ ~CheckPermissionRunnable() {
+ NS_ProxyRelease("CheckPermissionRunnable::mActor", mBackgroundEventTarget,
+ mActor.forget());
+ }
+
+ RefPtr<ThreadsafeContentParentHandle> mContentHandle;
+ RefPtr<FileSystemRequestParent> mActor;
+ RefPtr<FileSystemTaskParentBase> mTask;
+ const nsString mPath;
+
+ nsCOMPtr<nsIEventTarget> mBackgroundEventTarget;
+};
+
+} // namespace
+
+void FileSystemRequestParent::Start() {
+ AssertIsInMainProcess();
+ AssertIsOnBackgroundThread();
+
+ MOZ_ASSERT(!mDestroyed);
+ MOZ_ASSERT(mFileSystem);
+ MOZ_ASSERT(mTask);
+
+ nsAutoString path;
+ if (NS_WARN_IF(NS_FAILED(mTask->GetTargetPath(path)))) {
+ (void)Send__delete__(this,
+ FileSystemErrorResponse(NS_ERROR_DOM_SECURITY_ERR));
+ return;
+ }
+
+ RefPtr<ThreadsafeContentParentHandle> parent =
+ BackgroundParent::GetContentParentHandle(Manager());
+
+ // If the ThreadsafeContentParentHandle is null we are dealing with a
+ // same-process actor.
+ if (!parent) {
+ mTask->Start();
+ return;
+ }
+
+ RefPtr<Runnable> runnable =
+ new CheckPermissionRunnable(parent.forget(), this, mTask, path);
+ NS_DispatchToMainThread(runnable);
+}
+
+void FileSystemRequestParent::ActorDestroy(ActorDestroyReason aWhy) {
+ AssertIsOnBackgroundThread();
+ MOZ_ASSERT(!mDestroyed);
+
+ if (!mFileSystem) {
+ return;
+ }
+
+ mFileSystem->Shutdown();
+ mFileSystem = nullptr;
+ mTask = nullptr;
+ mDestroyed = true;
+}
+
+} // namespace mozilla::dom