зеркало из https://github.com/mozilla/gecko-dev.git
296 строки
8.0 KiB
C++
296 строки
8.0 KiB
C++
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
#include "FileBlobImpl.h"
|
|
#include "mozilla/SlicedInputStream.h"
|
|
#include "mozilla/dom/WorkerPrivate.h"
|
|
#include "mozilla/dom/WorkerRunnable.h"
|
|
#include "nsCExternalHandlerService.h"
|
|
#include "nsIFile.h"
|
|
#include "nsIFileStreams.h"
|
|
#include "nsIMIMEService.h"
|
|
#include "nsNetUtil.h"
|
|
#include "nsStreamUtils.h"
|
|
|
|
namespace mozilla {
|
|
namespace dom {
|
|
|
|
FileBlobImpl::FileBlobImpl(nsIFile* aFile)
|
|
: mMutex("FileBlobImpl::mMutex"),
|
|
mFile(aFile),
|
|
mSerialNumber(BaseBlobImpl::NextSerialNumber()),
|
|
mStart(0),
|
|
mFileId(-1),
|
|
mIsFile(true),
|
|
mWholeFile(true) {
|
|
MOZ_ASSERT(mFile, "must have file");
|
|
MOZ_ASSERT(XRE_IsParentProcess());
|
|
// Lazily get the content type and size
|
|
mContentType.SetIsVoid(true);
|
|
mMozFullPath.SetIsVoid(true);
|
|
mFile->GetLeafName(mName);
|
|
}
|
|
|
|
FileBlobImpl::FileBlobImpl(const nsAString& aName,
|
|
const nsAString& aContentType, uint64_t aLength,
|
|
nsIFile* aFile)
|
|
: mMutex("FileBlobImpl::mMutex"),
|
|
mFile(aFile),
|
|
mContentType(aContentType),
|
|
mName(aName),
|
|
mSerialNumber(BaseBlobImpl::NextSerialNumber()),
|
|
mStart(0),
|
|
mFileId(-1),
|
|
mLength(Some(aLength)),
|
|
mIsFile(true),
|
|
mWholeFile(true) {
|
|
MOZ_ASSERT(mFile, "must have file");
|
|
MOZ_ASSERT(XRE_IsParentProcess());
|
|
mMozFullPath.SetIsVoid(true);
|
|
}
|
|
|
|
FileBlobImpl::FileBlobImpl(const nsAString& aName,
|
|
const nsAString& aContentType, uint64_t aLength,
|
|
nsIFile* aFile, int64_t aLastModificationDate)
|
|
: mMutex("FileBlobImpl::mMutex"),
|
|
mFile(aFile),
|
|
mContentType(aContentType),
|
|
mName(aName),
|
|
mSerialNumber(BaseBlobImpl::NextSerialNumber()),
|
|
mStart(0),
|
|
mFileId(-1),
|
|
mLength(Some(aLength)),
|
|
mLastModified(Some(aLastModificationDate)),
|
|
mIsFile(true),
|
|
mWholeFile(true) {
|
|
MOZ_ASSERT(mFile, "must have file");
|
|
MOZ_ASSERT(XRE_IsParentProcess());
|
|
mMozFullPath.SetIsVoid(true);
|
|
}
|
|
|
|
FileBlobImpl::FileBlobImpl(nsIFile* aFile, const nsAString& aName,
|
|
const nsAString& aContentType)
|
|
: mMutex("FileBlobImpl::mMutex"),
|
|
mFile(aFile),
|
|
mContentType(aContentType),
|
|
mName(aName),
|
|
mSerialNumber(BaseBlobImpl::NextSerialNumber()),
|
|
mStart(0),
|
|
mFileId(-1),
|
|
mIsFile(true),
|
|
mWholeFile(true) {
|
|
MOZ_ASSERT(mFile, "must have file");
|
|
MOZ_ASSERT(XRE_IsParentProcess());
|
|
if (aContentType.IsEmpty()) {
|
|
// Lazily get the content type and size
|
|
mContentType.SetIsVoid(true);
|
|
}
|
|
|
|
mMozFullPath.SetIsVoid(true);
|
|
}
|
|
|
|
FileBlobImpl::FileBlobImpl(const FileBlobImpl* aOther, uint64_t aStart,
|
|
uint64_t aLength, const nsAString& aContentType)
|
|
: mMutex("FileBlobImpl::mMutex"),
|
|
mFile(aOther->mFile),
|
|
mContentType(aContentType),
|
|
mSerialNumber(BaseBlobImpl::NextSerialNumber()),
|
|
mStart(aOther->mStart + aStart),
|
|
mFileId(-1),
|
|
mLength(Some(aLength)),
|
|
mIsFile(false),
|
|
mWholeFile(false) {
|
|
MOZ_ASSERT(mFile, "must have file");
|
|
MOZ_ASSERT(XRE_IsParentProcess());
|
|
mMozFullPath = aOther->mMozFullPath;
|
|
}
|
|
|
|
already_AddRefed<BlobImpl> FileBlobImpl::CreateSlice(
|
|
uint64_t aStart, uint64_t aLength, const nsAString& aContentType,
|
|
ErrorResult& aRv) {
|
|
RefPtr<FileBlobImpl> impl =
|
|
new FileBlobImpl(this, aStart, aLength, aContentType);
|
|
return impl.forget();
|
|
}
|
|
|
|
void FileBlobImpl::GetMozFullPathInternal(nsAString& aFilename,
|
|
ErrorResult& aRv) {
|
|
MOZ_ASSERT(mIsFile, "Should only be called on files");
|
|
|
|
MutexAutoLock lock(mMutex);
|
|
|
|
if (!mMozFullPath.IsVoid()) {
|
|
aFilename = mMozFullPath;
|
|
return;
|
|
}
|
|
|
|
aRv = mFile->GetPath(aFilename);
|
|
if (NS_WARN_IF(aRv.Failed())) {
|
|
return;
|
|
}
|
|
|
|
mMozFullPath = aFilename;
|
|
}
|
|
|
|
uint64_t FileBlobImpl::GetSize(ErrorResult& aRv) {
|
|
MutexAutoLock lock(mMutex);
|
|
|
|
if (mLength.isNothing()) {
|
|
MOZ_ASSERT(mWholeFile,
|
|
"Should only use lazy size when using the whole file");
|
|
int64_t fileSize;
|
|
aRv = mFile->GetFileSize(&fileSize);
|
|
if (NS_WARN_IF(aRv.Failed())) {
|
|
return 0;
|
|
}
|
|
|
|
if (fileSize < 0) {
|
|
aRv.Throw(NS_ERROR_FAILURE);
|
|
return 0;
|
|
}
|
|
|
|
mLength.emplace(fileSize);
|
|
}
|
|
|
|
return mLength.value();
|
|
}
|
|
|
|
class FileBlobImpl::GetTypeRunnable final : public WorkerMainThreadRunnable {
|
|
public:
|
|
GetTypeRunnable(WorkerPrivate* aWorkerPrivate, FileBlobImpl* aBlobImpl,
|
|
const MutexAutoLock& aProofOfLock)
|
|
: WorkerMainThreadRunnable(aWorkerPrivate, "FileBlobImpl :: GetType"_ns),
|
|
mBlobImpl(aBlobImpl),
|
|
mProofOfLock(aProofOfLock) {
|
|
MOZ_ASSERT(aBlobImpl);
|
|
aWorkerPrivate->AssertIsOnWorkerThread();
|
|
}
|
|
|
|
bool MainThreadRun() override {
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
|
|
nsAutoString type;
|
|
mBlobImpl->GetTypeInternal(type, mProofOfLock);
|
|
return true;
|
|
}
|
|
|
|
private:
|
|
~GetTypeRunnable() = default;
|
|
|
|
RefPtr<FileBlobImpl> mBlobImpl;
|
|
const MutexAutoLock& mProofOfLock;
|
|
};
|
|
|
|
void FileBlobImpl::GetType(nsAString& aType) {
|
|
MutexAutoLock lock(mMutex);
|
|
GetTypeInternal(aType, lock);
|
|
}
|
|
|
|
void FileBlobImpl::GetTypeInternal(nsAString& aType,
|
|
const MutexAutoLock& aProofOfLock) {
|
|
aType.Truncate();
|
|
|
|
if (mContentType.IsVoid()) {
|
|
MOZ_ASSERT(mWholeFile,
|
|
"Should only use lazy ContentType when using the whole file");
|
|
|
|
if (!NS_IsMainThread()) {
|
|
WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate();
|
|
if (!workerPrivate) {
|
|
// I have no idea in which thread this method is called. We cannot
|
|
// return any valid value.
|
|
return;
|
|
}
|
|
|
|
RefPtr<GetTypeRunnable> runnable =
|
|
new GetTypeRunnable(workerPrivate, this, aProofOfLock);
|
|
|
|
ErrorResult rv;
|
|
runnable->Dispatch(Canceling, rv);
|
|
if (NS_WARN_IF(rv.Failed())) {
|
|
rv.SuppressException();
|
|
return;
|
|
}
|
|
} else {
|
|
nsresult rv;
|
|
nsCOMPtr<nsIMIMEService> mimeService =
|
|
do_GetService(NS_MIMESERVICE_CONTRACTID, &rv);
|
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
|
return;
|
|
}
|
|
|
|
nsAutoCString mimeType;
|
|
rv = mimeService->GetTypeFromFile(mFile, mimeType);
|
|
if (NS_FAILED(rv)) {
|
|
mimeType.Truncate();
|
|
}
|
|
|
|
AppendUTF8toUTF16(mimeType, mContentType);
|
|
mContentType.SetIsVoid(false);
|
|
}
|
|
}
|
|
|
|
aType = mContentType;
|
|
}
|
|
|
|
void FileBlobImpl::GetBlobImplType(nsAString& aBlobImplType) const {
|
|
aBlobImplType = u"FileBlobImpl"_ns;
|
|
}
|
|
|
|
int64_t FileBlobImpl::GetLastModified(ErrorResult& aRv) {
|
|
MOZ_ASSERT(mIsFile, "Should only be called on files");
|
|
|
|
MutexAutoLock lock(mMutex);
|
|
|
|
if (mLastModified.isNothing()) {
|
|
PRTime msecs;
|
|
aRv = mFile->GetLastModifiedTime(&msecs);
|
|
if (NS_WARN_IF(aRv.Failed())) {
|
|
return 0;
|
|
}
|
|
|
|
mLastModified.emplace(int64_t(msecs));
|
|
}
|
|
|
|
return mLastModified.value();
|
|
}
|
|
|
|
const uint32_t sFileStreamFlags =
|
|
nsIFileInputStream::CLOSE_ON_EOF | nsIFileInputStream::REOPEN_ON_REWIND |
|
|
nsIFileInputStream::DEFER_OPEN | nsIFileInputStream::SHARE_DELETE;
|
|
|
|
void FileBlobImpl::CreateInputStream(nsIInputStream** aStream,
|
|
ErrorResult& aRv) {
|
|
nsCOMPtr<nsIInputStream> stream;
|
|
aRv = NS_NewLocalFileInputStream(getter_AddRefs(stream), mFile, -1, -1,
|
|
sFileStreamFlags);
|
|
if (NS_WARN_IF(aRv.Failed())) {
|
|
return;
|
|
}
|
|
|
|
if (mWholeFile) {
|
|
stream.forget(aStream);
|
|
return;
|
|
}
|
|
|
|
MOZ_ASSERT(mLength.isSome());
|
|
|
|
RefPtr<SlicedInputStream> slicedInputStream =
|
|
new SlicedInputStream(stream.forget(), mStart, mLength.value());
|
|
slicedInputStream.forget(aStream);
|
|
}
|
|
|
|
bool FileBlobImpl::IsDirectory() const {
|
|
bool isDirectory = false;
|
|
if (mFile) {
|
|
mFile->IsDirectory(&isDirectory);
|
|
}
|
|
return isDirectory;
|
|
}
|
|
|
|
} // namespace dom
|
|
} // namespace mozilla
|