Line data Source code
1 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 : /* This Source Code Form is subject to the terms of the Mozilla Public
4 : * License, v. 2.0. If a copy of the MPL was not distributed with this
5 : * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 :
7 : #include "FileCreatorHelper.h"
8 :
9 : #include "mozilla/dom/BindingDeclarations.h"
10 : #include "mozilla/dom/ContentChild.h"
11 : #include "mozilla/dom/ContentParent.h"
12 : #include "mozilla/dom/FileBinding.h"
13 : #include "mozilla/dom/File.h"
14 : #include "mozilla/dom/Promise.h"
15 : #include "nsContentUtils.h"
16 : #include "nsPIDOMWindow.h"
17 : #include "nsIFile.h"
18 :
19 : // Undefine the macro of CreateFile to avoid FileCreatorHelper#CreateFile being
20 : // replaced by FileCreatorHelper#CreateFileW.
21 : #ifdef CreateFile
22 : #undef CreateFile
23 : #endif
24 :
25 : namespace mozilla {
26 : namespace dom {
27 :
28 : /* static */ already_AddRefed<Promise>
29 0 : FileCreatorHelper::CreateFile(nsIGlobalObject* aGlobalObject,
30 : nsIFile* aFile,
31 : const ChromeFilePropertyBag& aBag,
32 : bool aIsFromNsIFile,
33 : ErrorResult& aRv)
34 : {
35 0 : MOZ_DIAGNOSTIC_ASSERT(NS_IsMainThread());
36 :
37 0 : RefPtr<Promise> promise = Promise::Create(aGlobalObject, aRv);
38 0 : if (NS_WARN_IF(aRv.Failed())) {
39 0 : return nullptr;
40 : }
41 :
42 0 : nsCOMPtr<nsPIDOMWindowInner> window = do_QueryInterface(aGlobalObject);
43 :
44 : // Parent process
45 :
46 0 : if (XRE_IsParentProcess()) {
47 : RefPtr<File> file =
48 0 : CreateFileInternal(window, aFile, aBag, aIsFromNsIFile, aRv);
49 0 : if (aRv.Failed()) {
50 0 : return nullptr;
51 : }
52 0 : promise->MaybeResolve(file);
53 0 : return promise.forget();
54 : }
55 :
56 : // Content process.
57 :
58 0 : ContentChild* cc = ContentChild::GetSingleton();
59 0 : if (!cc) {
60 0 : promise->MaybeReject(NS_ERROR_DOM_INVALID_STATE_ERR);
61 0 : return promise.forget();
62 : }
63 :
64 0 : if (!cc->GetRemoteType().EqualsLiteral(FILE_REMOTE_TYPE) &&
65 0 : !Preferences::GetBool("dom.file.createInChild", false)) {
66 : // If this pref is not set and the request is received by the parent
67 : // process, this child is killed for security reason.
68 0 : promise->MaybeReject(NS_ERROR_DOM_INVALID_STATE_ERR);
69 0 : return promise.forget();
70 : }
71 :
72 0 : RefPtr<FileCreatorHelper> helper = new FileCreatorHelper(promise, window);
73 :
74 : // The request is sent to the parent process and it's kept alive by
75 : // ContentChild.
76 0 : helper->SendRequest(aFile, aBag, aIsFromNsIFile, aRv);
77 0 : if (NS_WARN_IF(aRv.Failed())) {
78 0 : return nullptr;
79 : }
80 :
81 0 : return promise.forget();
82 : }
83 :
84 : /* static */ already_AddRefed<File>
85 0 : FileCreatorHelper::CreateFileInternal(nsPIDOMWindowInner* aWindow,
86 : nsIFile* aFile,
87 : const ChromeFilePropertyBag& aBag,
88 : bool aIsFromNsIFile,
89 : ErrorResult& aRv)
90 : {
91 0 : bool lastModifiedPassed = false;
92 0 : int64_t lastModified = 0;
93 0 : if (aBag.mLastModified.WasPassed()) {
94 0 : lastModifiedPassed = true;
95 0 : lastModified = aBag.mLastModified.Value();
96 : }
97 :
98 0 : RefPtr<BlobImpl> blobImpl;
99 0 : aRv = CreateBlobImpl(aFile, aBag.mType, aBag.mName, lastModifiedPassed,
100 0 : lastModified, aBag.mExistenceCheck, aIsFromNsIFile,
101 0 : getter_AddRefs(blobImpl));
102 0 : if (aRv.Failed()) {
103 0 : return nullptr;
104 : }
105 :
106 0 : RefPtr<File> file = File::Create(aWindow, blobImpl);
107 0 : return file.forget();
108 : }
109 :
110 0 : FileCreatorHelper::FileCreatorHelper(Promise* aPromise,
111 0 : nsPIDOMWindowInner* aWindow)
112 : : mPromise(aPromise)
113 0 : , mWindow(aWindow)
114 : {
115 0 : MOZ_ASSERT(aPromise);
116 0 : }
117 :
118 0 : FileCreatorHelper::~FileCreatorHelper()
119 : {
120 0 : }
121 :
122 : void
123 0 : FileCreatorHelper::SendRequest(nsIFile* aFile,
124 : const ChromeFilePropertyBag& aBag,
125 : bool aIsFromNsIFile,
126 : ErrorResult& aRv)
127 : {
128 0 : MOZ_ASSERT(aFile);
129 :
130 0 : ContentChild* cc = ContentChild::GetSingleton();
131 0 : if (NS_WARN_IF(!cc)) {
132 0 : aRv.Throw(NS_ERROR_FAILURE);
133 0 : return;
134 : }
135 :
136 : nsID uuid;
137 0 : aRv = nsContentUtils::GenerateUUIDInPlace(uuid);
138 0 : if (NS_WARN_IF(aRv.Failed())) {
139 0 : return;
140 : }
141 :
142 0 : nsAutoString path;
143 0 : aRv = aFile->GetPath(path);
144 0 : if (NS_WARN_IF(aRv.Failed())) {
145 0 : return;
146 : }
147 :
148 0 : cc->FileCreationRequest(uuid, this, path, aBag.mType, aBag.mName,
149 0 : aBag.mLastModified, aBag.mExistenceCheck,
150 0 : aIsFromNsIFile);
151 : }
152 :
153 : void
154 0 : FileCreatorHelper::ResponseReceived(BlobImpl* aBlobImpl, nsresult aRv)
155 : {
156 0 : if (NS_FAILED(aRv)) {
157 0 : mPromise->MaybeReject(aRv);
158 0 : return;
159 : }
160 :
161 0 : RefPtr<File> file = File::Create(mWindow, aBlobImpl);
162 0 : mPromise->MaybeResolve(file);
163 : }
164 :
165 : /* static */ nsresult
166 0 : FileCreatorHelper::CreateBlobImplForIPC(const nsAString& aPath,
167 : const nsAString& aType,
168 : const nsAString& aName,
169 : bool aLastModifiedPassed,
170 : int64_t aLastModified,
171 : bool aExistenceCheck,
172 : bool aIsFromNsIFile,
173 : BlobImpl** aBlobImpl)
174 : {
175 0 : nsCOMPtr<nsIFile> file;
176 0 : nsresult rv = NS_NewLocalFile(aPath, true, getter_AddRefs(file));
177 0 : if (NS_WARN_IF(NS_FAILED(rv))) {
178 0 : return rv;
179 : }
180 :
181 0 : return CreateBlobImpl(file, aType, aName, aLastModifiedPassed, aLastModified,
182 0 : aExistenceCheck, aIsFromNsIFile, aBlobImpl);
183 : }
184 :
185 : /* static */ nsresult
186 0 : FileCreatorHelper::CreateBlobImpl(nsIFile* aFile,
187 : const nsAString& aType,
188 : const nsAString& aName,
189 : bool aLastModifiedPassed,
190 : int64_t aLastModified,
191 : bool aExistenceCheck,
192 : bool aIsFromNsIFile,
193 : BlobImpl** aBlobImpl)
194 : {
195 0 : if (!aExistenceCheck) {
196 0 : RefPtr<FileBlobImpl> impl = new FileBlobImpl(aFile);
197 :
198 0 : if (!aName.IsEmpty()) {
199 0 : impl->SetName(aName);
200 : }
201 :
202 0 : if (!aType.IsEmpty()) {
203 0 : impl->SetType(aType);
204 : }
205 :
206 0 : if (aLastModifiedPassed) {
207 0 : impl->SetLastModified(aLastModified);
208 : }
209 :
210 0 : impl.forget(aBlobImpl);
211 0 : return NS_OK;
212 : }
213 :
214 0 : RefPtr<MultipartBlobImpl> impl = new MultipartBlobImpl(EmptyString());
215 : nsresult rv =
216 0 : impl->InitializeChromeFile(aFile, aType, aName, aLastModifiedPassed,
217 0 : aLastModified, aIsFromNsIFile);
218 0 : if (NS_FAILED(rv)) {
219 0 : return rv;
220 : }
221 :
222 0 : MOZ_ASSERT(impl->IsFile());
223 :
224 0 : impl.forget(aBlobImpl);
225 0 : return NS_OK;
226 : }
227 :
228 : } // dom namespace
229 : } // mozilla namespace
|