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 "FileBlobImpl.h"
8 : #include "mozilla/dom/WorkerPrivate.h"
9 : #include "mozilla/dom/WorkerRunnable.h"
10 : #include "nsCExternalHandlerService.h"
11 : #include "nsIFile.h"
12 : #include "nsIFileStreams.h"
13 : #include "nsIMIMEService.h"
14 : #include "nsNetUtil.h"
15 : #include "nsStreamUtils.h"
16 : #include "SlicedInputStream.h"
17 :
18 : namespace mozilla {
19 : namespace dom {
20 :
21 : using namespace workers;
22 :
23 0 : NS_IMPL_ISUPPORTS_INHERITED0(FileBlobImpl, BlobImpl)
24 :
25 0 : FileBlobImpl::FileBlobImpl(nsIFile* aFile)
26 0 : : BaseBlobImpl(EmptyString(), EmptyString(), UINT64_MAX, INT64_MAX)
27 : , mFile(aFile)
28 : , mWholeFile(true)
29 0 : , mFileId(-1)
30 : {
31 0 : MOZ_ASSERT(mFile, "must have file");
32 0 : MOZ_ASSERT(XRE_IsParentProcess());
33 : // Lazily get the content type and size
34 0 : mContentType.SetIsVoid(true);
35 0 : mFile->GetLeafName(mName);
36 0 : }
37 :
38 0 : FileBlobImpl::FileBlobImpl(const nsAString& aName,
39 : const nsAString& aContentType,
40 0 : uint64_t aLength, nsIFile* aFile)
41 : : BaseBlobImpl(aName, aContentType, aLength, UINT64_MAX)
42 : , mFile(aFile)
43 : , mWholeFile(true)
44 0 : , mFileId(-1)
45 : {
46 0 : MOZ_ASSERT(mFile, "must have file");
47 0 : MOZ_ASSERT(XRE_IsParentProcess());
48 0 : }
49 :
50 0 : FileBlobImpl::FileBlobImpl(const nsAString& aName,
51 : const nsAString& aContentType,
52 : uint64_t aLength, nsIFile* aFile,
53 0 : int64_t aLastModificationDate)
54 : : BaseBlobImpl(aName, aContentType, aLength, aLastModificationDate)
55 : , mFile(aFile)
56 : , mWholeFile(true)
57 0 : , mFileId(-1)
58 : {
59 0 : MOZ_ASSERT(mFile, "must have file");
60 0 : MOZ_ASSERT(XRE_IsParentProcess());
61 0 : }
62 :
63 0 : FileBlobImpl::FileBlobImpl(nsIFile* aFile, const nsAString& aName,
64 0 : const nsAString& aContentType)
65 : : BaseBlobImpl(aName, aContentType, UINT64_MAX, INT64_MAX)
66 : , mFile(aFile)
67 : , mWholeFile(true)
68 0 : , mFileId(-1)
69 : {
70 0 : MOZ_ASSERT(mFile, "must have file");
71 0 : MOZ_ASSERT(XRE_IsParentProcess());
72 0 : if (aContentType.IsEmpty()) {
73 : // Lazily get the content type and size
74 0 : mContentType.SetIsVoid(true);
75 : }
76 0 : }
77 :
78 0 : FileBlobImpl::FileBlobImpl(const FileBlobImpl* aOther, uint64_t aStart,
79 0 : uint64_t aLength, const nsAString& aContentType)
80 0 : : BaseBlobImpl(aContentType, aOther->mStart + aStart, aLength)
81 : , mFile(aOther->mFile)
82 : , mWholeFile(false)
83 0 : , mFileId(-1)
84 : {
85 0 : MOZ_ASSERT(mFile, "must have file");
86 0 : MOZ_ASSERT(XRE_IsParentProcess());
87 0 : mImmutable = aOther->mImmutable;
88 0 : }
89 :
90 : already_AddRefed<BlobImpl>
91 0 : FileBlobImpl::CreateSlice(uint64_t aStart, uint64_t aLength,
92 : const nsAString& aContentType,
93 : ErrorResult& aRv)
94 : {
95 : RefPtr<BlobImpl> impl =
96 0 : new FileBlobImpl(this, aStart, aLength, aContentType);
97 0 : return impl.forget();
98 : }
99 :
100 : void
101 0 : FileBlobImpl::GetMozFullPathInternal(nsAString& aFilename,
102 : ErrorResult& aRv) const
103 : {
104 0 : MOZ_ASSERT(mIsFile, "Should only be called on files");
105 0 : aRv = mFile->GetPath(aFilename);
106 0 : }
107 :
108 : uint64_t
109 0 : FileBlobImpl::GetSize(ErrorResult& aRv)
110 : {
111 0 : if (BaseBlobImpl::IsSizeUnknown()) {
112 0 : MOZ_ASSERT(mWholeFile,
113 : "Should only use lazy size when using the whole file");
114 : int64_t fileSize;
115 0 : aRv = mFile->GetFileSize(&fileSize);
116 0 : if (NS_WARN_IF(aRv.Failed())) {
117 0 : return 0;
118 : }
119 :
120 0 : if (fileSize < 0) {
121 0 : aRv.Throw(NS_ERROR_FAILURE);
122 0 : return 0;
123 : }
124 :
125 0 : mLength = fileSize;
126 : }
127 :
128 0 : return mLength;
129 : }
130 :
131 : namespace {
132 :
133 : class GetTypeRunnable final : public WorkerMainThreadRunnable
134 : {
135 : public:
136 0 : GetTypeRunnable(WorkerPrivate* aWorkerPrivate,
137 : BlobImpl* aBlobImpl)
138 0 : : WorkerMainThreadRunnable(aWorkerPrivate,
139 0 : NS_LITERAL_CSTRING("FileBlobImpl :: GetType"))
140 0 : , mBlobImpl(aBlobImpl)
141 : {
142 0 : MOZ_ASSERT(aBlobImpl);
143 0 : aWorkerPrivate->AssertIsOnWorkerThread();
144 0 : }
145 :
146 : bool
147 0 : MainThreadRun() override
148 : {
149 0 : MOZ_ASSERT(NS_IsMainThread());
150 :
151 0 : nsAutoString type;
152 0 : mBlobImpl->GetType(type);
153 0 : return true;
154 : }
155 :
156 : private:
157 0 : ~GetTypeRunnable() = default;
158 :
159 : RefPtr<BlobImpl> mBlobImpl;
160 : };
161 :
162 : } // anonymous namespace
163 :
164 : void
165 0 : FileBlobImpl::GetType(nsAString& aType)
166 : {
167 0 : aType.Truncate();
168 :
169 0 : if (mContentType.IsVoid()) {
170 0 : MOZ_ASSERT(mWholeFile,
171 : "Should only use lazy ContentType when using the whole file");
172 :
173 0 : if (!NS_IsMainThread()) {
174 0 : WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate();
175 0 : if (!workerPrivate) {
176 : // I have no idea in which thread this method is called. We cannot
177 : // return any valid value.
178 0 : return;
179 : }
180 :
181 : RefPtr<GetTypeRunnable> runnable =
182 0 : new GetTypeRunnable(workerPrivate, this);
183 :
184 0 : ErrorResult rv;
185 0 : runnable->Dispatch(Terminating, rv);
186 0 : if (NS_WARN_IF(rv.Failed())) {
187 0 : rv.SuppressException();
188 : }
189 0 : return;
190 : }
191 :
192 : nsresult rv;
193 : nsCOMPtr<nsIMIMEService> mimeService =
194 0 : do_GetService(NS_MIMESERVICE_CONTRACTID, &rv);
195 0 : if (NS_WARN_IF(NS_FAILED(rv))) {
196 0 : return;
197 : }
198 :
199 0 : nsAutoCString mimeType;
200 0 : rv = mimeService->GetTypeFromFile(mFile, mimeType);
201 0 : if (NS_FAILED(rv)) {
202 0 : mimeType.Truncate();
203 : }
204 :
205 0 : AppendUTF8toUTF16(mimeType, mContentType);
206 0 : mContentType.SetIsVoid(false);
207 : }
208 :
209 0 : aType = mContentType;
210 : }
211 :
212 : int64_t
213 0 : FileBlobImpl::GetLastModified(ErrorResult& aRv)
214 : {
215 0 : MOZ_ASSERT(mIsFile, "Should only be called on files");
216 0 : if (BaseBlobImpl::IsDateUnknown()) {
217 : PRTime msecs;
218 0 : aRv = mFile->GetLastModifiedTime(&msecs);
219 0 : if (NS_WARN_IF(aRv.Failed())) {
220 0 : return 0;
221 : }
222 :
223 0 : mLastModificationDate = msecs;
224 : }
225 :
226 0 : return mLastModificationDate;
227 : }
228 :
229 : void
230 0 : FileBlobImpl::SetLastModified(int64_t aLastModified)
231 : {
232 0 : MOZ_CRASH("SetLastModified of a real file is not allowed!");
233 : }
234 :
235 : const uint32_t sFileStreamFlags =
236 : nsIFileInputStream::CLOSE_ON_EOF |
237 : nsIFileInputStream::REOPEN_ON_REWIND |
238 : nsIFileInputStream::DEFER_OPEN |
239 : nsIFileInputStream::SHARE_DELETE;
240 :
241 : void
242 0 : FileBlobImpl::GetInternalStream(nsIInputStream** aStream, ErrorResult& aRv)
243 : {
244 0 : nsCOMPtr<nsIInputStream> stream;
245 0 : aRv = NS_NewLocalFileInputStream(getter_AddRefs(stream), mFile, -1, -1,
246 0 : sFileStreamFlags);
247 0 : if (NS_WARN_IF(aRv.Failed())) {
248 0 : return;
249 : }
250 :
251 0 : if (mWholeFile) {
252 0 : stream.forget(aStream);
253 0 : return;
254 : }
255 :
256 : RefPtr<SlicedInputStream> slicedInputStream =
257 0 : new SlicedInputStream(stream, mStart, mLength);
258 0 : slicedInputStream.forget(aStream);
259 : }
260 :
261 : bool
262 0 : FileBlobImpl::IsDirectory() const
263 : {
264 0 : bool isDirectory = false;
265 0 : if (mFile) {
266 0 : mFile->IsDirectory(&isDirectory);
267 : }
268 0 : return isDirectory;
269 : }
270 :
271 : } // namespace dom
272 : } // namespace mozilla
|