Bug 1852740: add tests for the `fetchpriority` attribute in Link headers. r=necko...
[gecko.git] / dom / file / FileBlobImpl.cpp
blobaf80476e1a33e9d7240e5ab4a2dd8b14c1e8bcdb
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/. */
7 #include "FileBlobImpl.h"
8 #include "BaseBlobImpl.h"
9 #include "mozilla/SlicedInputStream.h"
10 #include "mozilla/dom/WorkerPrivate.h"
11 #include "mozilla/dom/WorkerRunnable.h"
12 #include "nsCExternalHandlerService.h"
13 #include "nsIFile.h"
14 #include "nsIFileStreams.h"
15 #include "nsIMIMEService.h"
16 #include "nsNetUtil.h"
17 #include "nsStreamUtils.h"
19 namespace mozilla::dom {
21 FileBlobImpl::FileBlobImpl(nsIFile* aFile)
22 : mMutex("FileBlobImpl::mMutex"),
23 mFile(aFile),
24 mSerialNumber(BaseBlobImpl::NextSerialNumber()),
25 mStart(0),
26 mFileId(-1),
27 mIsFile(true),
28 mWholeFile(true) {
29 MOZ_ASSERT(mFile, "must have file");
30 MOZ_ASSERT(XRE_IsParentProcess());
31 // Lazily get the content type and size
32 mContentType.SetIsVoid(true);
33 mMozFullPath.SetIsVoid(true);
34 mFile->GetLeafName(mName);
37 FileBlobImpl::FileBlobImpl(const nsAString& aName,
38 const nsAString& aContentType, uint64_t aLength,
39 nsIFile* aFile)
40 : mMutex("FileBlobImpl::mMutex"),
41 mFile(aFile),
42 mContentType(aContentType),
43 mName(aName),
44 mSerialNumber(BaseBlobImpl::NextSerialNumber()),
45 mStart(0),
46 mFileId(-1),
47 mLength(Some(aLength)),
48 mIsFile(true),
49 mWholeFile(true) {
50 MOZ_ASSERT(mFile, "must have file");
51 MOZ_ASSERT(XRE_IsParentProcess());
52 mMozFullPath.SetIsVoid(true);
55 FileBlobImpl::FileBlobImpl(const nsAString& aName,
56 const nsAString& aContentType, uint64_t aLength,
57 nsIFile* aFile, int64_t aLastModificationDate)
58 : mMutex("FileBlobImpl::mMutex"),
59 mFile(aFile),
60 mContentType(aContentType),
61 mName(aName),
62 mSerialNumber(BaseBlobImpl::NextSerialNumber()),
63 mStart(0),
64 mFileId(-1),
65 mLength(Some(aLength)),
66 mLastModified(Some(aLastModificationDate)),
67 mIsFile(true),
68 mWholeFile(true) {
69 MOZ_ASSERT(mFile, "must have file");
70 MOZ_ASSERT(XRE_IsParentProcess());
71 mMozFullPath.SetIsVoid(true);
74 FileBlobImpl::FileBlobImpl(nsIFile* aFile, const nsAString& aName,
75 const nsAString& aContentType)
76 : mMutex("FileBlobImpl::mMutex"),
77 mFile(aFile),
78 mContentType(aContentType),
79 mName(aName),
80 mSerialNumber(BaseBlobImpl::NextSerialNumber()),
81 mStart(0),
82 mFileId(-1),
83 mIsFile(true),
84 mWholeFile(true) {
85 MOZ_ASSERT(mFile, "must have file");
86 MOZ_ASSERT(XRE_IsParentProcess());
87 if (aContentType.IsEmpty()) {
88 // Lazily get the content type and size
89 mContentType.SetIsVoid(true);
92 mMozFullPath.SetIsVoid(true);
95 FileBlobImpl::FileBlobImpl(const FileBlobImpl* aOther, uint64_t aStart,
96 uint64_t aLength, const nsAString& aContentType)
97 : mMutex("FileBlobImpl::mMutex"),
98 mFile(aOther->mFile),
99 mContentType(aContentType),
100 mSerialNumber(BaseBlobImpl::NextSerialNumber()),
101 mStart(aOther->mStart + aStart),
102 mFileId(-1),
103 mLength(Some(aLength)),
104 mIsFile(false),
105 mWholeFile(false) {
106 MOZ_ASSERT(mFile, "must have file");
107 MOZ_ASSERT(XRE_IsParentProcess());
108 mMozFullPath = aOther->mMozFullPath;
111 already_AddRefed<BlobImpl> FileBlobImpl::CreateSlice(
112 uint64_t aStart, uint64_t aLength, const nsAString& aContentType,
113 ErrorResult& aRv) const {
114 RefPtr<FileBlobImpl> impl =
115 new FileBlobImpl(this, aStart, aLength, aContentType);
116 return impl.forget();
119 void FileBlobImpl::GetMozFullPathInternal(nsAString& aFilename,
120 ErrorResult& aRv) {
121 MOZ_ASSERT(mIsFile, "Should only be called on files");
123 MutexAutoLock lock(mMutex);
125 if (!mMozFullPath.IsVoid()) {
126 aFilename = mMozFullPath;
127 return;
130 aRv = mFile->GetPath(aFilename);
131 if (NS_WARN_IF(aRv.Failed())) {
132 return;
135 mMozFullPath = aFilename;
138 uint64_t FileBlobImpl::GetSize(ErrorResult& aRv) {
139 MutexAutoLock lock(mMutex);
141 if (mLength.isNothing()) {
142 MOZ_ASSERT(mWholeFile,
143 "Should only use lazy size when using the whole file");
144 int64_t fileSize;
145 aRv = mFile->GetFileSize(&fileSize);
146 if (NS_WARN_IF(aRv.Failed())) {
147 return 0;
150 if (fileSize < 0) {
151 aRv.Throw(NS_ERROR_FAILURE);
152 return 0;
155 mLength.emplace(fileSize);
158 return mLength.value();
161 class FileBlobImpl::GetTypeRunnable final : public WorkerMainThreadRunnable {
162 public:
163 GetTypeRunnable(WorkerPrivate* aWorkerPrivate, FileBlobImpl* aBlobImpl,
164 const MutexAutoLock& aProofOfLock)
165 : WorkerMainThreadRunnable(aWorkerPrivate, "FileBlobImpl :: GetType"_ns),
166 mBlobImpl(aBlobImpl),
167 mProofOfLock(aProofOfLock) {
168 MOZ_ASSERT(aBlobImpl);
169 aWorkerPrivate->AssertIsOnWorkerThread();
172 bool MainThreadRun() override {
173 MOZ_ASSERT(NS_IsMainThread());
175 nsAutoString type;
176 mBlobImpl->GetTypeInternal(type, mProofOfLock);
177 return true;
180 private:
181 ~GetTypeRunnable() override = default;
183 RefPtr<FileBlobImpl> mBlobImpl;
184 const MutexAutoLock& mProofOfLock;
187 void FileBlobImpl::GetType(nsAString& aType) {
188 MutexAutoLock lock(mMutex);
189 GetTypeInternal(aType, lock);
192 void FileBlobImpl::GetTypeInternal(nsAString& aType,
193 const MutexAutoLock& aProofOfLock) {
194 aType.Truncate();
196 if (mContentType.IsVoid()) {
197 MOZ_ASSERT(mWholeFile,
198 "Should only use lazy ContentType when using the whole file");
200 if (!NS_IsMainThread()) {
201 WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate();
202 if (!workerPrivate) {
203 // I have no idea in which thread this method is called. We cannot
204 // return any valid value.
205 return;
208 RefPtr<GetTypeRunnable> runnable =
209 new GetTypeRunnable(workerPrivate, this, aProofOfLock);
211 ErrorResult rv;
212 runnable->Dispatch(Canceling, rv);
213 if (NS_WARN_IF(rv.Failed())) {
214 rv.SuppressException();
215 return;
217 } else {
218 nsresult rv;
219 nsCOMPtr<nsIMIMEService> mimeService =
220 do_GetService(NS_MIMESERVICE_CONTRACTID, &rv);
221 if (NS_WARN_IF(NS_FAILED(rv))) {
222 return;
225 nsAutoCString mimeType;
226 rv = mimeService->GetTypeFromFile(mFile, mimeType);
227 if (NS_FAILED(rv)) {
228 mimeType.Truncate();
231 AppendUTF8toUTF16(mimeType, mContentType);
232 mContentType.SetIsVoid(false);
236 aType = mContentType;
239 void FileBlobImpl::GetBlobImplType(nsAString& aBlobImplType) const {
240 aBlobImplType = u"FileBlobImpl"_ns;
243 int64_t FileBlobImpl::GetLastModified(ErrorResult& aRv) {
244 MOZ_ASSERT(mIsFile, "Should only be called on files");
246 MutexAutoLock lock(mMutex);
248 if (mLastModified.isNothing()) {
249 PRTime msecs;
250 aRv = mFile->GetLastModifiedTime(&msecs);
251 if (NS_WARN_IF(aRv.Failed())) {
252 return 0;
255 mLastModified.emplace(int64_t(msecs));
258 return mLastModified.value();
261 const uint32_t sFileStreamFlags =
262 nsIFileInputStream::CLOSE_ON_EOF | nsIFileInputStream::REOPEN_ON_REWIND |
263 nsIFileInputStream::DEFER_OPEN | nsIFileInputStream::SHARE_DELETE;
265 void FileBlobImpl::CreateInputStream(nsIInputStream** aStream,
266 ErrorResult& aRv) const {
267 nsCOMPtr<nsIInputStream> stream;
268 aRv = NS_NewLocalFileInputStream(getter_AddRefs(stream), mFile, -1, -1,
269 sFileStreamFlags);
270 if (NS_WARN_IF(aRv.Failed())) {
271 return;
274 if (mWholeFile) {
275 stream.forget(aStream);
276 return;
279 MOZ_ASSERT(mLength.isSome());
281 RefPtr<SlicedInputStream> slicedInputStream =
282 new SlicedInputStream(stream.forget(), mStart, mLength.value());
283 slicedInputStream.forget(aStream);
286 bool FileBlobImpl::IsDirectory() const {
287 bool isDirectory = false;
288 if (mFile) {
289 mFile->IsDirectory(&isDirectory);
291 return isDirectory;
294 } // namespace mozilla::dom