Coverage Report

Created: 2018-09-25 14:53

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