1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
4 * You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #include "DeviceStorageRequestParent.h"
8 #include "nsIMIMEService.h"
9 #include "nsCExternalHandlerService.h"
10 #include "mozilla/unused.h"
11 #include "mozilla/dom/ipc/Blob.h"
12 #include "ContentParent.h"
13 #include "nsProxyRelease.h"
14 #include "AppProcessChecker.h"
15 #include "mozilla/Preferences.h"
19 namespace devicestorage
{
21 DeviceStorageRequestParent::DeviceStorageRequestParent(const DeviceStorageParams
& aParams
)
23 , mMutex("DeviceStorageRequestParent::mMutex")
24 , mActorDestoryed(false)
26 MOZ_COUNT_CTOR(DeviceStorageRequestParent
);
28 DebugOnly
<DeviceStorageUsedSpaceCache
*> usedSpaceCache
= DeviceStorageUsedSpaceCache::CreateOrGet();
29 NS_ASSERTION(usedSpaceCache
, "DeviceStorageUsedSpaceCache is null");
33 DeviceStorageRequestParent::Dispatch()
35 switch (mParams
.type()) {
36 case DeviceStorageParams::TDeviceStorageAddParams
:
38 DeviceStorageAddParams p
= mParams
;
40 nsRefPtr
<DeviceStorageFile
> dsf
=
41 new DeviceStorageFile(p
.type(), p
.storageName(), p
.relpath());
43 BlobParent
* bp
= static_cast<BlobParent
*>(p
.blobParent());
44 nsCOMPtr
<nsIDOMBlob
> blob
= bp
->GetBlob();
46 nsCOMPtr
<nsIInputStream
> stream
;
47 blob
->GetInternalStream(getter_AddRefs(stream
));
49 nsRefPtr
<CancelableRunnable
> r
= new WriteFileEvent(this, dsf
, stream
);
51 nsCOMPtr
<nsIEventTarget
> target
= do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID
);
52 NS_ASSERTION(target
, "Must have stream transport service");
53 target
->Dispatch(r
, NS_DISPATCH_NORMAL
);
57 case DeviceStorageParams::TDeviceStorageGetParams
:
59 DeviceStorageGetParams p
= mParams
;
60 nsRefPtr
<DeviceStorageFile
> dsf
=
61 new DeviceStorageFile(p
.type(), p
.storageName(), p
.rootDir(), p
.relpath());
62 nsRefPtr
<CancelableRunnable
> r
= new ReadFileEvent(this, dsf
);
64 nsCOMPtr
<nsIEventTarget
> target
= do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID
);
65 NS_ASSERTION(target
, "Must have stream transport service");
66 target
->Dispatch(r
, NS_DISPATCH_NORMAL
);
70 case DeviceStorageParams::TDeviceStorageDeleteParams
:
72 DeviceStorageDeleteParams p
= mParams
;
74 nsRefPtr
<DeviceStorageFile
> dsf
=
75 new DeviceStorageFile(p
.type(), p
.storageName(), p
.relpath());
76 nsRefPtr
<CancelableRunnable
> r
= new DeleteFileEvent(this, dsf
);
78 nsCOMPtr
<nsIEventTarget
> target
= do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID
);
79 NS_ASSERTION(target
, "Must have stream transport service");
80 target
->Dispatch(r
, NS_DISPATCH_NORMAL
);
84 case DeviceStorageParams::TDeviceStorageFreeSpaceParams
:
86 DeviceStorageFreeSpaceParams p
= mParams
;
88 nsRefPtr
<DeviceStorageFile
> dsf
=
89 new DeviceStorageFile(p
.type(), p
.storageName());
90 nsRefPtr
<FreeSpaceFileEvent
> r
= new FreeSpaceFileEvent(this, dsf
);
92 nsCOMPtr
<nsIEventTarget
> target
= do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID
);
93 NS_ASSERTION(target
, "Must have stream transport service");
94 target
->Dispatch(r
, NS_DISPATCH_NORMAL
);
98 case DeviceStorageParams::TDeviceStorageUsedSpaceParams
:
100 DeviceStorageUsedSpaceCache
* usedSpaceCache
= DeviceStorageUsedSpaceCache::CreateOrGet();
101 NS_ASSERTION(usedSpaceCache
, "DeviceStorageUsedSpaceCache is null");
103 DeviceStorageUsedSpaceParams p
= mParams
;
105 nsRefPtr
<DeviceStorageFile
> dsf
=
106 new DeviceStorageFile(p
.type(), p
.storageName());
107 nsRefPtr
<UsedSpaceFileEvent
> r
= new UsedSpaceFileEvent(this, dsf
);
109 usedSpaceCache
->Dispatch(r
);
113 case DeviceStorageParams::TDeviceStorageAvailableParams
:
115 DeviceStorageAvailableParams p
= mParams
;
117 nsRefPtr
<DeviceStorageFile
> dsf
=
118 new DeviceStorageFile(p
.type(), p
.storageName());
119 nsRefPtr
<PostAvailableResultEvent
> r
= new PostAvailableResultEvent(this, dsf
);
120 NS_DispatchToMainThread(r
);
124 case DeviceStorageParams::TDeviceStorageEnumerationParams
:
126 DeviceStorageEnumerationParams p
= mParams
;
127 nsRefPtr
<DeviceStorageFile
> dsf
128 = new DeviceStorageFile(p
.type(), p
.storageName(), p
.rootdir(), NS_LITERAL_STRING(""));
129 nsRefPtr
<CancelableRunnable
> r
= new EnumerateFileEvent(this, dsf
, p
.since());
131 nsCOMPtr
<nsIEventTarget
> target
= do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID
);
132 NS_ASSERTION(target
, "Must have stream transport service");
133 target
->Dispatch(r
, NS_DISPATCH_NORMAL
);
138 NS_RUNTIMEABORT("not reached");
145 DeviceStorageRequestParent::EnsureRequiredPermissions(mozilla::dom::ContentParent
* aParent
)
147 if (mozilla::Preferences::GetBool("device.storage.testing", false)) {
152 DeviceStorageRequestType requestType
;
154 switch (mParams
.type())
156 case DeviceStorageParams::TDeviceStorageAddParams
:
158 DeviceStorageAddParams p
= mParams
;
160 requestType
= DEVICE_STORAGE_REQUEST_CREATE
;
164 case DeviceStorageParams::TDeviceStorageGetParams
:
166 DeviceStorageGetParams p
= mParams
;
168 requestType
= DEVICE_STORAGE_REQUEST_READ
;
172 case DeviceStorageParams::TDeviceStorageDeleteParams
:
174 DeviceStorageDeleteParams p
= mParams
;
176 requestType
= DEVICE_STORAGE_REQUEST_DELETE
;
180 case DeviceStorageParams::TDeviceStorageFreeSpaceParams
:
182 DeviceStorageFreeSpaceParams p
= mParams
;
184 requestType
= DEVICE_STORAGE_REQUEST_FREE_SPACE
;
188 case DeviceStorageParams::TDeviceStorageUsedSpaceParams
:
190 DeviceStorageUsedSpaceParams p
= mParams
;
192 requestType
= DEVICE_STORAGE_REQUEST_FREE_SPACE
;
196 case DeviceStorageParams::TDeviceStorageAvailableParams
:
198 DeviceStorageAvailableParams p
= mParams
;
200 requestType
= DEVICE_STORAGE_REQUEST_AVAILABLE
;
204 case DeviceStorageParams::TDeviceStorageEnumerationParams
:
206 DeviceStorageEnumerationParams p
= mParams
;
208 requestType
= DEVICE_STORAGE_REQUEST_READ
;
218 // The 'apps' type is special. We only want this exposed
219 // if the caller has the "webapps-manage" permission.
220 if (type
.EqualsLiteral("apps")) {
221 if (!AssertAppProcessPermission(aParent
, "webapps-manage")) {
226 nsAutoCString permissionName
;
227 nsresult rv
= DeviceStorageTypeChecker::GetPermissionForType(type
, permissionName
);
233 rv
= DeviceStorageTypeChecker::GetAccessForRequest(requestType
, access
);
238 permissionName
.AppendLiteral("-");
239 permissionName
.Append(access
);
241 if (!AssertAppProcessPermission(aParent
, permissionName
.get())) {
248 DeviceStorageRequestParent::~DeviceStorageRequestParent()
250 MOZ_COUNT_DTOR(DeviceStorageRequestParent
);
253 NS_IMPL_THREADSAFE_ADDREF(DeviceStorageRequestParent
)
254 NS_IMPL_THREADSAFE_RELEASE(DeviceStorageRequestParent
)
257 DeviceStorageRequestParent::ActorDestroy(ActorDestroyReason
)
259 MutexAutoLock
lock(mMutex
);
260 mActorDestoryed
= true;
261 int32_t count
= mRunnables
.Length();
262 for (int32_t index
= 0; index
< count
; index
++) {
263 mRunnables
[index
]->Cancel();
267 DeviceStorageRequestParent::PostFreeSpaceResultEvent::PostFreeSpaceResultEvent(DeviceStorageRequestParent
* aParent
,
269 : CancelableRunnable(aParent
)
270 , mFreeSpace(aFreeSpace
)
274 DeviceStorageRequestParent::PostFreeSpaceResultEvent::~PostFreeSpaceResultEvent() {}
277 DeviceStorageRequestParent::PostFreeSpaceResultEvent::CancelableRun() {
278 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
280 FreeSpaceStorageResponse
response(mFreeSpace
);
281 unused
<< mParent
->Send__delete__(mParent
, response
);
285 DeviceStorageRequestParent::PostUsedSpaceResultEvent::PostUsedSpaceResultEvent(DeviceStorageRequestParent
* aParent
,
286 const nsAString
& aType
,
288 : CancelableRunnable(aParent
)
290 , mUsedSpace(aUsedSpace
)
294 DeviceStorageRequestParent::PostUsedSpaceResultEvent::~PostUsedSpaceResultEvent() {}
297 DeviceStorageRequestParent::PostUsedSpaceResultEvent::CancelableRun() {
298 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
300 UsedSpaceStorageResponse
response(mUsedSpace
);
301 unused
<< mParent
->Send__delete__(mParent
, response
);
305 DeviceStorageRequestParent::PostErrorEvent::PostErrorEvent(DeviceStorageRequestParent
* aParent
,
307 : CancelableRunnable(aParent
)
309 CopyASCIItoUTF16(aError
, mError
);
312 DeviceStorageRequestParent::PostErrorEvent::~PostErrorEvent() {}
315 DeviceStorageRequestParent::PostErrorEvent::CancelableRun() {
316 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
318 ErrorResponse
response(mError
);
319 unused
<< mParent
->Send__delete__(mParent
, response
);
323 DeviceStorageRequestParent::PostSuccessEvent::PostSuccessEvent(DeviceStorageRequestParent
* aParent
)
324 : CancelableRunnable(aParent
)
328 DeviceStorageRequestParent::PostSuccessEvent::~PostSuccessEvent() {}
331 DeviceStorageRequestParent::PostSuccessEvent::CancelableRun() {
332 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
334 SuccessResponse response
;
335 unused
<< mParent
->Send__delete__(mParent
, response
);
339 DeviceStorageRequestParent::PostBlobSuccessEvent::PostBlobSuccessEvent(DeviceStorageRequestParent
* aParent
,
340 DeviceStorageFile
* aFile
,
342 nsACString
& aMimeType
,
343 uint64_t aLastModifiedDate
)
344 : CancelableRunnable(aParent
)
346 , mLastModificationDate(aLastModifiedDate
)
348 , mMimeType(aMimeType
)
352 DeviceStorageRequestParent::PostBlobSuccessEvent::~PostBlobSuccessEvent() {}
355 DeviceStorageRequestParent::PostBlobSuccessEvent::CancelableRun() {
356 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
359 CopyASCIItoUTF16(mMimeType
, mime
);
361 nsString compositePath
;
362 mFile
->GetCompositePath(compositePath
);
363 nsCOMPtr
<nsIDOMBlob
> blob
= new nsDOMFileFile(compositePath
, mime
, mLength
, mFile
->mFile
, mLastModificationDate
);
365 ContentParent
* cp
= static_cast<ContentParent
*>(mParent
->Manager());
366 BlobParent
* actor
= cp
->GetOrCreateActorForBlob(blob
);
368 ErrorResponse
response(NS_LITERAL_STRING(POST_ERROR_EVENT_UNKNOWN
));
369 unused
<< mParent
->Send__delete__(mParent
, response
);
373 BlobResponse response
;
374 response
.blobParent() = actor
;
376 unused
<< mParent
->Send__delete__(mParent
, response
);
380 DeviceStorageRequestParent::PostEnumerationSuccessEvent::PostEnumerationSuccessEvent(DeviceStorageRequestParent
* aParent
,
381 const nsAString
& aStorageType
,
382 const nsAString
& aRelPath
,
383 InfallibleTArray
<DeviceStorageFileValue
>& aPaths
)
384 : CancelableRunnable(aParent
)
385 , mStorageType(aStorageType
)
391 DeviceStorageRequestParent::PostEnumerationSuccessEvent::~PostEnumerationSuccessEvent() {}
394 DeviceStorageRequestParent::PostEnumerationSuccessEvent::CancelableRun() {
395 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
397 EnumerationResponse
response(mStorageType
, mRelPath
, mPaths
);
398 unused
<< mParent
->Send__delete__(mParent
, response
);
402 DeviceStorageRequestParent::WriteFileEvent::WriteFileEvent(DeviceStorageRequestParent
* aParent
,
403 DeviceStorageFile
* aFile
,
404 nsIInputStream
* aInputStream
)
405 : CancelableRunnable(aParent
)
407 , mInputStream(aInputStream
)
411 DeviceStorageRequestParent::WriteFileEvent::~WriteFileEvent()
416 DeviceStorageRequestParent::WriteFileEvent::CancelableRun()
418 NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
420 nsRefPtr
<nsRunnable
> r
;
423 r
= new PostErrorEvent(mParent
, POST_ERROR_EVENT_UNKNOWN
);
424 NS_DispatchToMainThread(r
);
429 mFile
->mFile
->Exists(&check
);
431 nsCOMPtr
<PostErrorEvent
> event
= new PostErrorEvent(mParent
, POST_ERROR_EVENT_FILE_EXISTS
);
432 NS_DispatchToMainThread(event
);
436 nsresult rv
= mFile
->Write(mInputStream
);
439 r
= new PostErrorEvent(mParent
, POST_ERROR_EVENT_UNKNOWN
);
442 r
= new PostPathResultEvent(mParent
, mFile
->mPath
);
445 NS_DispatchToMainThread(r
);
450 DeviceStorageRequestParent::DeleteFileEvent::DeleteFileEvent(DeviceStorageRequestParent
* aParent
,
451 DeviceStorageFile
* aFile
)
452 : CancelableRunnable(aParent
)
457 DeviceStorageRequestParent::DeleteFileEvent::~DeleteFileEvent()
462 DeviceStorageRequestParent::DeleteFileEvent::CancelableRun()
464 NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
468 nsRefPtr
<nsRunnable
> r
;
471 mFile
->mFile
->Exists(&check
);
473 r
= new PostErrorEvent(mParent
, POST_ERROR_EVENT_UNKNOWN
);
476 r
= new PostPathResultEvent(mParent
, mFile
->mPath
);
479 NS_DispatchToMainThread(r
);
483 DeviceStorageRequestParent::FreeSpaceFileEvent::FreeSpaceFileEvent(DeviceStorageRequestParent
* aParent
,
484 DeviceStorageFile
* aFile
)
485 : CancelableRunnable(aParent
)
490 DeviceStorageRequestParent::FreeSpaceFileEvent::~FreeSpaceFileEvent()
495 DeviceStorageRequestParent::FreeSpaceFileEvent::CancelableRun()
497 NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
499 int64_t freeSpace
= 0;
501 mFile
->GetDiskFreeSpace(&freeSpace
);
504 nsCOMPtr
<nsIRunnable
> r
;
505 r
= new PostFreeSpaceResultEvent(mParent
, static_cast<uint64_t>(freeSpace
));
506 NS_DispatchToMainThread(r
);
510 DeviceStorageRequestParent::UsedSpaceFileEvent::UsedSpaceFileEvent(DeviceStorageRequestParent
* aParent
,
511 DeviceStorageFile
* aFile
)
512 : CancelableRunnable(aParent
)
517 DeviceStorageRequestParent::UsedSpaceFileEvent::~UsedSpaceFileEvent()
522 DeviceStorageRequestParent::UsedSpaceFileEvent::CancelableRun()
524 NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
526 uint64_t picturesUsage
= 0, videosUsage
= 0, musicUsage
= 0, totalUsage
= 0;
527 mFile
->AccumDiskUsage(&picturesUsage
, &videosUsage
,
528 &musicUsage
, &totalUsage
);
529 nsCOMPtr
<nsIRunnable
> r
;
530 if (mFile
->mStorageType
.EqualsLiteral(DEVICESTORAGE_PICTURES
)) {
531 r
= new PostUsedSpaceResultEvent(mParent
, mFile
->mStorageType
, picturesUsage
);
533 else if (mFile
->mStorageType
.EqualsLiteral(DEVICESTORAGE_VIDEOS
)) {
534 r
= new PostUsedSpaceResultEvent(mParent
, mFile
->mStorageType
, videosUsage
);
536 else if (mFile
->mStorageType
.EqualsLiteral(DEVICESTORAGE_MUSIC
)) {
537 r
= new PostUsedSpaceResultEvent(mParent
, mFile
->mStorageType
, musicUsage
);
539 r
= new PostUsedSpaceResultEvent(mParent
, mFile
->mStorageType
, totalUsage
);
541 NS_DispatchToMainThread(r
);
545 DeviceStorageRequestParent::ReadFileEvent::ReadFileEvent(DeviceStorageRequestParent
* aParent
,
546 DeviceStorageFile
* aFile
)
547 : CancelableRunnable(aParent
)
550 nsCOMPtr
<nsIMIMEService
> mimeService
= do_GetService(NS_MIMESERVICE_CONTRACTID
);
552 nsresult rv
= mimeService
->GetTypeFromFile(mFile
->mFile
, mMimeType
);
554 mMimeType
.Truncate();
559 DeviceStorageRequestParent::ReadFileEvent::~ReadFileEvent()
564 DeviceStorageRequestParent::ReadFileEvent::CancelableRun()
566 NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
568 nsCOMPtr
<nsIRunnable
> r
;
570 mFile
->mFile
->Exists(&check
);
573 r
= new PostErrorEvent(mParent
, POST_ERROR_EVENT_FILE_DOES_NOT_EXIST
);
574 NS_DispatchToMainThread(r
);
579 nsresult rv
= mFile
->mFile
->GetFileSize(&fileSize
);
581 r
= new PostErrorEvent(mParent
, POST_ERROR_EVENT_UNKNOWN
);
582 NS_DispatchToMainThread(r
);
587 rv
= mFile
->mFile
->GetLastModifiedTime(&modDate
);
589 r
= new PostErrorEvent(mParent
, POST_ERROR_EVENT_UNKNOWN
);
590 NS_DispatchToMainThread(r
);
594 r
= new PostBlobSuccessEvent(mParent
, mFile
, static_cast<uint64_t>(fileSize
), mMimeType
, modDate
);
595 NS_DispatchToMainThread(r
);
599 DeviceStorageRequestParent::EnumerateFileEvent::EnumerateFileEvent(DeviceStorageRequestParent
* aParent
,
600 DeviceStorageFile
* aFile
,
602 : CancelableRunnable(aParent
)
608 DeviceStorageRequestParent::EnumerateFileEvent::~EnumerateFileEvent()
613 DeviceStorageRequestParent::EnumerateFileEvent::CancelableRun()
615 NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
617 nsCOMPtr
<nsIRunnable
> r
;
620 mFile
->mFile
->Exists(&check
);
622 r
= new PostErrorEvent(mParent
, POST_ERROR_EVENT_FILE_DOES_NOT_EXIST
);
623 NS_DispatchToMainThread(r
);
628 nsTArray
<nsRefPtr
<DeviceStorageFile
> > files
;
629 mFile
->CollectFiles(files
, mSince
);
631 InfallibleTArray
<DeviceStorageFileValue
> values
;
633 uint32_t count
= files
.Length();
634 for (uint32_t i
= 0; i
< count
; i
++) {
635 DeviceStorageFileValue
dsvf(files
[i
]->mStorageName
, files
[i
]->mPath
);
636 values
.AppendElement(dsvf
);
639 r
= new PostEnumerationSuccessEvent(mParent
, mFile
->mStorageType
, mFile
->mRootDir
, values
);
640 NS_DispatchToMainThread(r
);
645 DeviceStorageRequestParent::PostPathResultEvent::PostPathResultEvent(DeviceStorageRequestParent
* aParent
,
646 const nsAString
& aPath
)
647 : CancelableRunnable(aParent
)
652 DeviceStorageRequestParent::PostPathResultEvent::~PostPathResultEvent()
657 DeviceStorageRequestParent::PostPathResultEvent::CancelableRun()
659 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
661 SuccessResponse response
;
662 unused
<< mParent
->Send__delete__(mParent
, response
);
666 DeviceStorageRequestParent::PostAvailableResultEvent::PostAvailableResultEvent(DeviceStorageRequestParent
* aParent
,
667 DeviceStorageFile
* aFile
)
668 : CancelableRunnable(aParent
)
673 DeviceStorageRequestParent::PostAvailableResultEvent::~PostAvailableResultEvent()
678 DeviceStorageRequestParent::PostAvailableResultEvent::CancelableRun()
680 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
682 nsString state
= NS_LITERAL_STRING("unavailable");
684 mFile
->GetStatus(state
);
687 AvailableStorageResponse
response(state
);
688 unused
<< mParent
->Send__delete__(mParent
, response
);
692 } // namespace devicestorage
694 } // namespace mozilla