diff options
author | Lorry Tar Creator <lorry-tar-importer@lorry> | 2017-06-27 06:07:23 +0000 |
---|---|---|
committer | Lorry Tar Creator <lorry-tar-importer@lorry> | 2017-06-27 06:07:23 +0000 |
commit | 1bf1084f2b10c3b47fd1a588d85d21ed0eb41d0c (patch) | |
tree | 46dcd36c86e7fbc6e5df36deb463b33e9967a6f7 /Source/WebCore/fileapi | |
parent | 32761a6cee1d0dee366b885b7b9c777e67885688 (diff) | |
download | WebKitGtk-tarball-master.tar.gz |
webkitgtk-2.16.5HEADwebkitgtk-2.16.5master
Diffstat (limited to 'Source/WebCore/fileapi')
37 files changed, 880 insertions, 1489 deletions
diff --git a/Source/WebCore/fileapi/AsyncFileStream.cpp b/Source/WebCore/fileapi/AsyncFileStream.cpp index 374fac0e3..168e4e277 100644 --- a/Source/WebCore/fileapi/AsyncFileStream.cpp +++ b/Source/WebCore/fileapi/AsyncFileStream.cpp @@ -1,6 +1,6 @@ /* * Copyright (C) 2010 Google Inc. All rights reserved. - * Copyright (C) 2012 Apple Inc. All rights reserved. + * Copyright (C) 2012, 2014 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are @@ -30,211 +30,148 @@ */ #include "config.h" - -#if ENABLE(BLOB) - #include "AsyncFileStream.h" -#include "Blob.h" #include "FileStream.h" #include "FileStreamClient.h" -#include "FileThread.h" -#include "FileThreadTask.h" -#include "MainThreadTask.h" +#include "URL.h" +#include <mutex> +#include <wtf/AutodrainedPool.h> +#include <wtf/Function.h> #include <wtf/MainThread.h> -#include <wtf/text/WTFString.h> - -#if PLATFORM(IOS) -#include "WebCoreThread.h" -#endif +#include <wtf/MessageQueue.h> +#include <wtf/NeverDestroyed.h> namespace WebCore { -static PassRefPtr<FileThread> createFileThread() -{ - RefPtr<FileThread> thread = FileThread::create(); - if (!thread->start()) - return 0; - return thread.release(); -} +struct AsyncFileStream::Internals { + explicit Internals(FileStreamClient&); + + FileStream stream; + FileStreamClient& client; +#if !COMPILER(MSVC) + std::atomic_bool destroyed { false }; +#else + std::atomic_bool destroyed; +#endif +}; -static FileThread* fileThread() +inline AsyncFileStream::Internals::Internals(FileStreamClient& client) + : client(client) { - ASSERT(isMainThread()); - static FileThread* thread = createFileThread().leakRef(); - return thread; +#if COMPILER(MSVC) + // Work around a bug that prevents the default value above from compiling. + atomic_init(&destroyed, false); +#endif } -inline AsyncFileStream::AsyncFileStream(FileStreamClient* client) - : m_stream(FileStream::create()) - , m_client(client) +static void callOnFileThread(Function<void ()>&& function) { ASSERT(isMainThread()); -} + ASSERT(function); -PassRefPtr<AsyncFileStream> AsyncFileStream::create(FileStreamClient* client) -{ - RefPtr<AsyncFileStream> proxy = adoptRef(new AsyncFileStream(client)); + static NeverDestroyed<MessageQueue<Function<void ()>>> queue; - // Hold a reference so that the instance will not get deleted while there are tasks on the file thread. - // This is balanced by the deref in derefProxyOnContext below. - proxy->ref(); + static std::once_flag createFileThreadOnce; + std::call_once(createFileThreadOnce, [] { + createThread("WebCore: AsyncFileStream", [] { + for (;;) { + AutodrainedPool pool; - fileThread()->postTask(createFileThreadTask(proxy.get(), &AsyncFileStream::startOnFileThread)); + auto function = queue.get().waitForMessage(); - return proxy.release(); -} + // This can never be null because we never kill the MessageQueue. + ASSERT(function); -AsyncFileStream::~AsyncFileStream() -{ -} + // This can bever be null because we never queue a function that is null. + ASSERT(*function); -static void didStart(AsyncFileStream* proxy) -{ - if (proxy->client()) - proxy->client()->didStart(); -} + (*function)(); + } + }); + }); -void AsyncFileStream::startOnFileThread() -{ - // FIXME: It is not correct to check m_client from a secondary thread - stop() could be racing with this check. - if (!m_client) - return; - m_stream->start(); - callOnMainThread(didStart, AllowCrossThreadAccess(this)); + queue.get().append(std::make_unique<Function<void ()>>(WTFMove(function))); } -void AsyncFileStream::stop() +AsyncFileStream::AsyncFileStream(FileStreamClient& client) + : m_internals(std::make_unique<Internals>(client)) { - // Clear the client so that we won't be invoking callbacks on the client. - setClient(0); - - fileThread()->unscheduleTasks(m_stream.get()); - fileThread()->postTask(createFileThreadTask(this, &AsyncFileStream::stopOnFileThread)); + ASSERT(isMainThread()); } -static void derefProxyOnMainThread(AsyncFileStream* proxy) +AsyncFileStream::~AsyncFileStream() { - ASSERT(proxy->hasOneRef()); - proxy->deref(); -} + ASSERT(isMainThread()); -void AsyncFileStream::stopOnFileThread() -{ - m_stream->stop(); - callOnMainThread(derefProxyOnMainThread, AllowCrossThreadAccess(this)); -} + // Set flag to prevent client callbacks and also prevent queued operations from starting. + m_internals->destroyed = true; -static void didGetSize(AsyncFileStream* proxy, long long size) -{ - if (proxy->client()) - proxy->client()->didGetSize(size); + // Call through file thread and back to main thread to make sure deletion happens + // after all file thread functions and all main thread functions called from them. + callOnFileThread([internals = WTFMove(m_internals)]() mutable { + callOnMainThread([internals = WTFMove(internals)] { + }); + }); } -void AsyncFileStream::getSize(const String& path, double expectedModificationTime) -{ - fileThread()->postTask(createFileThreadTask(this, &AsyncFileStream::getSizeOnFileThread, path, expectedModificationTime)); -} - -void AsyncFileStream::getSizeOnFileThread(const String& path, double expectedModificationTime) +void AsyncFileStream::perform(Function<std::function<void(FileStreamClient&)>(FileStream&)>&& operation) { - long long size = m_stream->getSize(path, expectedModificationTime); - callOnMainThread(didGetSize, AllowCrossThreadAccess(this), size); + auto& internals = *m_internals; + callOnFileThread([&internals, operation = WTFMove(operation)] { + // Don't do the operation if stop was already called on the main thread. Note that there is + // a race here, but since skipping the operation is an optimization it's OK that we can't + // guarantee exactly which operations are skipped. Note that this is also the only reason + // we use an atomic_bool rather than just a bool for destroyed. + if (internals.destroyed) + return; + callOnMainThread([&internals, mainThreadWork = operation(internals.stream)] { + if (internals.destroyed) + return; + mainThreadWork(internals.client); + }); + }); } -static void didOpen(AsyncFileStream* proxy, bool success) +void AsyncFileStream::getSize(const String& path, double expectedModificationTime) { - if (proxy->client()) - proxy->client()->didOpen(success); + // FIXME: Explicit return type here and in all the other cases like this below is a workaround for a deficiency + // in the Windows compiler at the time of this writing. Could remove it if that is resolved. + perform([path = path.isolatedCopy(), expectedModificationTime](FileStream& stream) -> std::function<void(FileStreamClient&)> { + long long size = stream.getSize(path, expectedModificationTime); + return [size](FileStreamClient& client) { + client.didGetSize(size); + }; + }); } void AsyncFileStream::openForRead(const String& path, long long offset, long long length) { - fileThread()->postTask(createFileThreadTask(this, &AsyncFileStream::openForReadOnFileThread, path, offset, length)); -} - -void AsyncFileStream::openForReadOnFileThread(const String& path, long long offset, long long length) -{ - bool success = m_stream->openForRead(path, offset, length); - callOnMainThread(didOpen, AllowCrossThreadAccess(this), success); -} - -void AsyncFileStream::openForWrite(const String& path) -{ - fileThread()->postTask( - createFileThreadTask(this, - &AsyncFileStream::openForWriteOnFileThread, path)); -} - -void AsyncFileStream::openForWriteOnFileThread(const String& path) -{ - bool success = m_stream->openForWrite(path); - callOnMainThread(didOpen, AllowCrossThreadAccess(this), success); + // FIXME: Explicit return type here is a workaround for a deficiency in the Windows compiler at the time of this writing. + perform([path = path.isolatedCopy(), offset, length](FileStream& stream) -> std::function<void(FileStreamClient&)> { + bool success = stream.openForRead(path, offset, length); + return [success](FileStreamClient& client) { + client.didOpen(success); + }; + }); } void AsyncFileStream::close() { - fileThread()->postTask(createFileThreadTask(this, &AsyncFileStream::closeOnFileThread)); -} - -void AsyncFileStream::closeOnFileThread() -{ - m_stream->close(); -} - -static void didRead(AsyncFileStream* proxy, int bytesRead) -{ - if (proxy->client()) - proxy->client()->didRead(bytesRead); + auto& internals = *m_internals; + callOnFileThread([&internals] { + internals.stream.close(); + }); } void AsyncFileStream::read(char* buffer, int length) { - fileThread()->postTask( - createFileThreadTask(this, &AsyncFileStream::readOnFileThread, - AllowCrossThreadAccess(buffer), length)); -} - -void AsyncFileStream::readOnFileThread(char* buffer, int length) -{ - int bytesRead = m_stream->read(buffer, length); - callOnMainThread(didRead, AllowCrossThreadAccess(this), bytesRead); -} - -static void didWrite(AsyncFileStream* proxy, int bytesWritten) -{ - if (proxy->client()) - proxy->client()->didWrite(bytesWritten); -} - -void AsyncFileStream::write(const URL& blobURL, long long position, int length) -{ - fileThread()->postTask(createFileThreadTask(this, &AsyncFileStream::writeOnFileThread, blobURL, position, length)); -} - -void AsyncFileStream::writeOnFileThread(const URL& blobURL, long long position, int length) -{ - int bytesWritten = m_stream->write(blobURL, position, length); - callOnMainThread(didWrite, AllowCrossThreadAccess(this), bytesWritten); -} - -static void didTruncate(AsyncFileStream* proxy, bool success) -{ - if (proxy->client()) - proxy->client()->didTruncate(success); -} - -void AsyncFileStream::truncate(long long position) -{ - fileThread()->postTask(createFileThreadTask(this, &AsyncFileStream::truncateOnFileThread, position)); -} - -void AsyncFileStream::truncateOnFileThread(long long position) -{ - bool success = m_stream->truncate(position); - callOnMainThread(didTruncate, AllowCrossThreadAccess(this), success); + perform([buffer, length](FileStream& stream) -> std::function<void(FileStreamClient&)> { + int bytesRead = stream.read(buffer, length); + return [bytesRead](FileStreamClient& client) { + client.didRead(bytesRead); + }; + }); } } // namespace WebCore - -#endif // ENABLE(BLOB) diff --git a/Source/WebCore/fileapi/AsyncFileStream.h b/Source/WebCore/fileapi/AsyncFileStream.h index 849ea2bc9..2098ee3f4 100644 --- a/Source/WebCore/fileapi/AsyncFileStream.h +++ b/Source/WebCore/fileapi/AsyncFileStream.h @@ -1,6 +1,6 @@ /* - * Copyright (C) 2010 Google Inc. All rights reserved. - * Copyright (C) 2010, 2012 Apple Inc. All rights reserved. + * Copyright (C) 2010 Google Inc. All rights reserved. + * Copyright (C) 2010, 2012, 2014 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are @@ -29,14 +29,11 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef AsyncFileStream_h -#define AsyncFileStream_h - -#if ENABLE(BLOB) +#pragma once +#include <functional> #include <wtf/Forward.h> -#include <wtf/RefCounted.h> -#include <wtf/RefPtr.h> +#include <wtf/Function.h> namespace WebCore { @@ -44,47 +41,22 @@ class FileStreamClient; class FileStream; class URL; -class AsyncFileStream : public RefCounted<AsyncFileStream> { +class WEBCORE_EXPORT AsyncFileStream { public: - static PassRefPtr<AsyncFileStream> create(FileStreamClient*); + explicit AsyncFileStream(FileStreamClient&); ~AsyncFileStream(); void getSize(const String& path, double expectedModificationTime); void openForRead(const String& path, long long offset, long long length); - void openForWrite(const String& path); void close(); void read(char* buffer, int length); - void write(const URL& blobURL, long long position, int length); - void truncate(long long position); - - // Stops the proxy and schedules it to be destructed. All the pending tasks will be aborted and the file stream will be closed. - // Note: the caller should deref the instance immediately after calling stop(). - void stop(); - - FileStreamClient* client() const { return m_client; } - void setClient(FileStreamClient* client) { m_client = client; } private: - AsyncFileStream(FileStreamClient*); - - // Called on File thread. - void startOnFileThread(); - void stopOnFileThread(); - void getSizeOnFileThread(const String& path, double expectedModificationTime); - void openForReadOnFileThread(const String& path, long long offset, long long length); - void openForWriteOnFileThread(const String& path); - void closeOnFileThread(); - void readOnFileThread(char* buffer, int length); - void writeOnFileThread(const URL& blobURL, long long position, int length); - void truncateOnFileThread(long long position); + void start(); + void perform(Function<std::function<void(FileStreamClient&)>(FileStream&)>&&); - RefPtr<FileStream> m_stream; - - FileStreamClient* m_client; + struct Internals; + std::unique_ptr<Internals> m_internals; }; } // namespace WebCore - -#endif // ENABLE(BLOB) - -#endif // AsyncFileStream_h diff --git a/Source/WebCore/fileapi/Blob.cpp b/Source/WebCore/fileapi/Blob.cpp index 6726bf470..f595b1d25 100644 --- a/Source/WebCore/fileapi/Blob.cpp +++ b/Source/WebCore/fileapi/Blob.cpp @@ -31,40 +31,30 @@ #include "config.h" #include "Blob.h" +#include "BlobBuilder.h" +#include "BlobPart.h" #include "BlobURL.h" #include "File.h" -#include "HistogramSupport.h" -#include "ScriptCallStack.h" #include "ScriptExecutionContext.h" #include "ThreadableBlobRegistry.h" +#include <wtf/NeverDestroyed.h> #include <wtf/text/CString.h> namespace WebCore { -namespace { - -// Used in histograms to see when we can actually deprecate the prefixed slice. -enum SliceHistogramEnum { - SliceWithoutPrefix, - SliceWithPrefix, - SliceHistogramEnumMax, -}; - -} // namespace - class BlobURLRegistry final : public URLRegistry { public: - virtual void registerURL(SecurityOrigin*, const URL&, URLRegistrable*) override; - virtual void unregisterURL(const URL&) override; + void registerURL(SecurityOrigin*, const URL&, URLRegistrable&) override; + void unregisterURL(const URL&) override; static URLRegistry& registry(); }; -void BlobURLRegistry::registerURL(SecurityOrigin* origin, const URL& publicURL, URLRegistrable* blob) +void BlobURLRegistry::registerURL(SecurityOrigin* origin, const URL& publicURL, URLRegistrable& blob) { - ASSERT(&blob->registry() == this); - ThreadableBlobRegistry::registerBlobURL(origin, publicURL, static_cast<Blob*>(blob)->url()); + ASSERT(&blob.registry() == this); + ThreadableBlobRegistry::registerBlobURL(origin, publicURL, static_cast<Blob&>(blob).url()); } void BlobURLRegistry::unregisterURL(const URL& url) @@ -74,39 +64,65 @@ void BlobURLRegistry::unregisterURL(const URL& url) URLRegistry& BlobURLRegistry::registry() { - DEFINE_STATIC_LOCAL(BlobURLRegistry, instance, ()); + static NeverDestroyed<BlobURLRegistry> instance; return instance; } +Blob::Blob(UninitializedContructor) +{ +} Blob::Blob() : m_size(0) { - auto blobData = std::make_unique<BlobData>(); - - // Create a new internal URL and register it with the provided blob data. m_internalURL = BlobURL::createInternalURL(); - ThreadableBlobRegistry::registerBlobURL(m_internalURL, std::move(blobData)); + ThreadableBlobRegistry::registerBlobURL(m_internalURL, { }, { }); } -Blob::Blob(std::unique_ptr<BlobData> blobData, long long size) - : m_type(blobData->contentType()) - , m_size(size) +Blob::Blob(Vector<BlobPartVariant>&& blobPartVariants, const BlobPropertyBag& propertyBag) + : m_internalURL(BlobURL::createInternalURL()) + , m_type(normalizedContentType(propertyBag.type)) + , m_size(-1) { - ASSERT(blobData); + BlobBuilder builder(propertyBag.endings); + for (auto& blobPartVariant : blobPartVariants) { + WTF::switchOn(blobPartVariant, + [&] (auto& part) { + builder.append(WTFMove(part)); + } + ); + } - // Create a new internal URL and register it with the provided blob data. + ThreadableBlobRegistry::registerBlobURL(m_internalURL, builder.finalize(), m_type); +} + +Blob::Blob(Vector<uint8_t>&& data, const String& contentType) + : m_type(contentType) + , m_size(data.size()) +{ + Vector<BlobPart> blobParts; + blobParts.append(BlobPart(WTFMove(data))); m_internalURL = BlobURL::createInternalURL(); - ThreadableBlobRegistry::registerBlobURL(m_internalURL, std::move(blobData)); + ThreadableBlobRegistry::registerBlobURL(m_internalURL, WTFMove(blobParts), contentType); } -Blob::Blob(const URL& srcURL, const String& type, long long size) - : m_type(Blob::normalizedContentType(type)) +Blob::Blob(DeserializationContructor, const URL& srcURL, const String& type, long long size, const String& fileBackedPath) + : m_type(normalizedContentType(type)) , m_size(size) { - // Create a new internal URL and register it with the same blob data as the source URL. m_internalURL = BlobURL::createInternalURL(); - ThreadableBlobRegistry::registerBlobURL(0, m_internalURL, srcURL); + if (fileBackedPath.isEmpty()) + ThreadableBlobRegistry::registerBlobURL(nullptr, m_internalURL, srcURL); + else + ThreadableBlobRegistry::registerBlobURLOptionallyFileBacked(m_internalURL, srcURL, fileBackedPath, m_type); +} + +Blob::Blob(const URL& srcURL, long long start, long long end, const String& type) + : m_type(normalizedContentType(type)) + , m_size(-1) // size is not necessarily equal to end - start. +{ + m_internalURL = BlobURL::createInternalURL(); + ThreadableBlobRegistry::registerBlobURLForSlice(m_internalURL, srcURL, start, end); } Blob::~Blob() @@ -114,118 +130,63 @@ Blob::~Blob() ThreadableBlobRegistry::unregisterBlobURL(m_internalURL); } -bool Blob::isValidContentType(const String& contentType) +unsigned long long Blob::size() const { - if (contentType.isNull()) - return true; + if (m_size < 0) { + // FIXME: JavaScript cannot represent sizes as large as unsigned long long, we need to + // come up with an exception to throw if file size is not representable. + unsigned long long actualSize = ThreadableBlobRegistry::blobSize(m_internalURL); + m_size = WTF::isInBounds<long long>(actualSize) ? static_cast<long long>(actualSize) : 0; + } - size_t length = contentType.length(); - if (contentType.is8Bit()) { - const LChar* characters = contentType.characters8(); - for (size_t i = 0; i < length; ++i) { - if (characters[i] < 0x20 || characters[i] > 0x7e) - return false; - } - } else { - const UChar* characters = contentType.characters16(); - for (size_t i = 0; i < length; ++i) { - if (characters[i] < 0x20 || characters[i] > 0x7e) - return false; - } + return static_cast<unsigned long long>(m_size); +} + +bool Blob::isValidContentType(const String& contentType) +{ + // FIXME: Do we really want to treat the empty string and null string as valid content types? + unsigned length = contentType.length(); + for (unsigned i = 0; i < length; ++i) { + if (contentType[i] < 0x20 || contentType[i] > 0x7e) + return false; } return true; } String Blob::normalizedContentType(const String& contentType) { - if (Blob::isValidContentType(contentType)) - return contentType.lower(); - return emptyString(); + if (!isValidContentType(contentType)) + return emptyString(); + return contentType.convertToASCIILowercase(); } +#if !ASSERT_DISABLED bool Blob::isNormalizedContentType(const String& contentType) { - if (contentType.isNull()) - return true; - - size_t length = contentType.length(); - if (contentType.is8Bit()) { - const LChar* characters = contentType.characters8(); - for (size_t i = 0; i < length; ++i) { - if (characters[i] < 0x20 || characters[i] > 0x7e) - return false; - if (characters[i] >= 'A' && characters[i] <= 'Z') - return false; - } - } else { - const UChar* characters = contentType.characters16(); - for (size_t i = 0; i < length; ++i) { - if (characters[i] < 0x20 || characters[i] > 0x7e) - return false; - if (characters[i] >= 'A' && characters[i] <= 'Z') - return false; - } + // FIXME: Do we really want to treat the empty string and null string as valid content types? + unsigned length = contentType.length(); + for (size_t i = 0; i < length; ++i) { + if (contentType[i] < 0x20 || contentType[i] > 0x7e) + return false; + if (isASCIIUpper(contentType[i])) + return false; } return true; } bool Blob::isNormalizedContentType(const CString& contentType) { + // FIXME: Do we really want to treat the empty string and null string as valid content types? size_t length = contentType.length(); const char* characters = contentType.data(); for (size_t i = 0; i < length; ++i) { if (characters[i] < 0x20 || characters[i] > 0x7e) return false; - if (characters[i] >= 'A' && characters[i] <= 'Z') + if (isASCIIUpper(characters[i])) return false; } return true; } - -#if ENABLE(BLOB) -PassRefPtr<Blob> Blob::slice(long long start, long long end, const String& contentType) const -{ - // When we slice a file for the first time, we obtain a snapshot of the file by capturing its current size and modification time. - // The modification time will be used to verify if the file has been changed or not, when the underlying data are accessed. - long long size; - double modificationTime; - if (isFile()) { - // FIXME: This involves synchronous file operation. We need to figure out how to make it asynchronous. - toFile(this)->captureSnapshot(size, modificationTime); - } else { - ASSERT(m_size != -1); - size = m_size; - } - - // Convert the negative value that is used to select from the end. - if (start < 0) - start = start + size; - if (end < 0) - end = end + size; - - // Clamp the range if it exceeds the size limit. - if (start < 0) - start = 0; - if (end < 0) - end = 0; - if (start >= size) { - start = 0; - end = 0; - } else if (end < start) - end = start; - else if (end > size) - end = size; - - long long length = end - start; - auto blobData = std::make_unique<BlobData>(); - blobData->setContentType(Blob::normalizedContentType(contentType)); - if (isFile()) - blobData->appendFile(toFile(this)->path(), start, length, modificationTime); - else - blobData->appendBlob(m_internalURL, start, length); - - return Blob::create(std::move(blobData), length); -} #endif URLRegistry& Blob::registry() const diff --git a/Source/WebCore/fileapi/Blob.h b/Source/WebCore/fileapi/Blob.h index 3e1e2ad9f..e7b6f8e8f 100644 --- a/Source/WebCore/fileapi/Blob.h +++ b/Source/WebCore/fileapi/Blob.h @@ -28,38 +28,47 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef Blob_h -#define Blob_h +#pragma once -#include "BlobData.h" -#include "URL.h" +#include "BlobPropertyBag.h" #include "ScriptWrappable.h" +#include "URL.h" #include "URLRegistry.h" -#include <wtf/PassRefPtr.h> -#include <wtf/RefCounted.h> -#include <wtf/text/WTFString.h> +#include <wtf/Variant.h> + +namespace JSC { +class ArrayBufferView; +class ArrayBuffer; +} namespace WebCore { +class Blob; class ScriptExecutionContext; +using BlobPartVariant = Variant<RefPtr<JSC::ArrayBufferView>, RefPtr<JSC::ArrayBuffer>, RefPtr<Blob>, String>; + class Blob : public ScriptWrappable, public URLRegistrable, public RefCounted<Blob> { public: - static PassRefPtr<Blob> create() + static Ref<Blob> create() { - return adoptRef(new Blob); + return adoptRef(*new Blob); } - static PassRefPtr<Blob> create(std::unique_ptr<BlobData> blobData, long long size) + static Ref<Blob> create(Vector<BlobPartVariant>&& blobPartVariants, const BlobPropertyBag& propertyBag) { - return adoptRef(new Blob(std::move(blobData), size)); + return adoptRef(*new Blob(WTFMove(blobPartVariants), propertyBag)); } - // For deserialization. - static PassRefPtr<Blob> create(const URL& srcURL, const String& type, long long size) + static Ref<Blob> create(Vector<uint8_t>&& data, const String& contentType) + { + return adoptRef(*new Blob(WTFMove(data), contentType)); + } + + static Ref<Blob> deserialize(const URL& srcURL, const String& type, long long size, const String& fileBackedPath) { ASSERT(Blob::isNormalizedContentType(type)); - return adoptRef(new Blob(srcURL, type, size)); + return adoptRef(*new Blob(deserializationContructor, srcURL, type, size, fileBackedPath)); } virtual ~Blob(); @@ -67,30 +76,39 @@ public: const URL& url() const { return m_internalURL; } const String& type() const { return m_type; } - virtual unsigned long long size() const { return static_cast<unsigned long long>(m_size); } + WEBCORE_EXPORT unsigned long long size() const; virtual bool isFile() const { return false; } // The checks described in the File API spec. static bool isValidContentType(const String&); // The normalization procedure described in the File API spec. static String normalizedContentType(const String&); - // Intended for use in ASSERT statements. +#if !ASSERT_DISABLED static bool isNormalizedContentType(const String&); static bool isNormalizedContentType(const CString&); +#endif // URLRegistrable - virtual URLRegistry& registry() const override; + URLRegistry& registry() const override; -#if ENABLE(BLOB) - PassRefPtr<Blob> slice(long long start = 0, long long end = std::numeric_limits<long long>::max(), const String& contentType = String()) const; -#endif + Ref<Blob> slice(long long start = 0, long long end = std::numeric_limits<long long>::max(), const String& contentType = String()) const + { + return adoptRef(*new Blob(m_internalURL, start, end, contentType)); + } protected: Blob(); - Blob(std::unique_ptr<BlobData>, long long size); + Blob(Vector<BlobPartVariant>&&, const BlobPropertyBag&); + Blob(Vector<uint8_t>&&, const String& contentType); + + enum UninitializedContructor { uninitializedContructor }; + Blob(UninitializedContructor); - // For deserialization. - Blob(const URL& srcURL, const String& type, long long size); + enum DeserializationContructor { deserializationContructor }; + Blob(DeserializationContructor, const URL& srcURL, const String& type, long long size, const String& fileBackedPath); + + // For slicing. + Blob(const URL& srcURL, long long start, long long end, const String& contentType); // This is an internal URL referring to the blob data associated with this object. It serves // as an identifier for this blob. The internal URL is never used to source the blob's content @@ -98,10 +116,7 @@ protected: URL m_internalURL; String m_type; - long long m_size; + mutable long long m_size; }; } // namespace WebCore - -#endif // Blob_h - diff --git a/Source/WebCore/fileapi/Blob.idl b/Source/WebCore/fileapi/Blob.idl index ca2dd343b..1ff0e308f 100644 --- a/Source/WebCore/fileapi/Blob.idl +++ b/Source/WebCore/fileapi/Blob.idl @@ -28,21 +28,23 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +typedef (ArrayBufferView or ArrayBuffer) BufferSource; +typedef (BufferSource or Blob or USVString) BlobPart; + [ - GlobalContext=DOMWindow&WorkerGlobalScope, + Exposed=(Window,Worker), GenerateIsReachable=Impl, CustomToJSObject, - JSNoStaticTables, - CustomConstructor, - CustomConstructor(sequence<any> blobParts, optional BlobPropertyBag options), + Constructor(optional sequence<BlobPart> blobParts, optional BlobPropertyBag options), ] interface Blob { readonly attribute unsigned long long size; readonly attribute DOMString type; -#if !defined(LANGUAGE_OBJECTIVE_C) -#if defined(ENABLE_BLOB) && ENABLE_BLOB - Blob slice(optional long long start, optional long long end, [TreatNullAs=NullString, TreatUndefinedAs=NullString] optional DOMString contentType); -#endif -#endif -}; + // slice Blob into byte-ranged chunks + Blob slice(optional long long start = 0, optional long long end = 0x7FFFFFFFFFFFFFFF, optional DOMString? contentType = null); + // FIXME: Implement: + // readonly attribute boolean isClosed; + // void close(); + +}; diff --git a/Source/WebCore/fileapi/FileThread.h b/Source/WebCore/fileapi/BlobBuilder.cpp index 4b9739e4f..d66dc9ff0 100644 --- a/Source/WebCore/fileapi/FileThread.h +++ b/Source/WebCore/fileapi/BlobBuilder.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010 Google Inc. All rights reserved. + * Copyright (C) 2010 Google Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are @@ -28,61 +28,63 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef FileThread_h -#define FileThread_h +#include "config.h" +#include "BlobBuilder.h" -#if ENABLE(BLOB) - -#include <wtf/MessageQueue.h> -#include <wtf/PassRefPtr.h> -#include <wtf/Threading.h> +#include "Blob.h" +#include "LineEnding.h" +#include "TextEncoding.h" +#include <runtime/ArrayBuffer.h> +#include <runtime/ArrayBufferView.h> +#include <wtf/text/CString.h> namespace WebCore { -class FileStream; - -class FileThread : public ThreadSafeRefCounted<FileThread> { -public: - static PassRefPtr<FileThread> create() - { - return adoptRef(new FileThread()); +BlobBuilder::BlobBuilder(BlobLineEndings endings) + : m_endings(endings) +{ +} + +void BlobBuilder::append(RefPtr<ArrayBuffer>&& arrayBuffer) +{ + if (!arrayBuffer) + return; + m_appendableData.append(static_cast<const char*>(arrayBuffer->data()), arrayBuffer->byteLength()); +} + +void BlobBuilder::append(RefPtr<ArrayBufferView>&& arrayBufferView) +{ + if (!arrayBufferView) + return; + m_appendableData.append(static_cast<const char*>(arrayBufferView->baseAddress()), arrayBufferView->byteLength()); +} + +void BlobBuilder::append(RefPtr<Blob>&& blob) +{ + if (!blob) + return; + if (!m_appendableData.isEmpty()) + m_items.append(BlobPart(WTFMove(m_appendableData))); + m_items.append(BlobPart(blob->url())); +} + +void BlobBuilder::append(const String& text) +{ + CString utf8Text = UTF8Encoding().encode(text, EntitiesForUnencodables); + + if (m_endings == BlobLineEndings::Native) + normalizeLineEndingsToNative(utf8Text, m_appendableData); + else { + ASSERT(m_endings == BlobLineEndings::Transparent); + m_appendableData.append(utf8Text.data(), utf8Text.length()); } +} - ~FileThread(); - - bool start(); - void stop(); - - class Task { - WTF_MAKE_NONCOPYABLE(Task); - public: - virtual ~Task() { } - virtual void performTask() = 0; - void* instance() const { return m_instance; } - protected: - Task(void* instance) : m_instance(instance) { } - void* m_instance; - }; - - void postTask(std::unique_ptr<Task>); - - void unscheduleTasks(const void* instance); - -private: - FileThread(); - - static void fileThreadStart(void*); - void runLoop(); - - ThreadIdentifier m_threadID; - RefPtr<FileThread> m_selfRef; - MessageQueue<Task> m_queue; - - Mutex m_threadCreationMutex; -}; +Vector<BlobPart> BlobBuilder::finalize() +{ + if (!m_appendableData.isEmpty()) + m_items.append(BlobPart(WTFMove(m_appendableData))); + return WTFMove(m_items); +} } // namespace WebCore - -#endif // ENABLE(BLOB) - -#endif // FileThread_h diff --git a/Source/WebCore/fileapi/WebKitBlobBuilder.h b/Source/WebCore/fileapi/BlobBuilder.h index bd2bbdfd9..976de344c 100644 --- a/Source/WebCore/fileapi/WebKitBlobBuilder.h +++ b/Source/WebCore/fileapi/BlobBuilder.h @@ -28,11 +28,10 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef WebKitBlobBuilder_h -#define WebKitBlobBuilder_h +#pragma once -#include "BlobData.h" -#include <wtf/Forward.h> +#include "BlobPart.h" +#include "BlobPropertyBag.h" namespace JSC { class ArrayBuffer; @@ -41,35 +40,23 @@ class ArrayBufferView; namespace WebCore { -// FIXME: Move this file to BlobBuilder.h - class Blob; -class TextEncoding; - -typedef int ExceptionCode; class BlobBuilder { public: - BlobBuilder(); + BlobBuilder(BlobLineEndings); - void append(Blob*); - void append(const String& text, const String& ending); -#if ENABLE(BLOB) - void append(JSC::ArrayBuffer*); - void append(PassRefPtr<JSC::ArrayBufferView>); -#endif + void append(RefPtr<JSC::ArrayBuffer>&&); + void append(RefPtr<JSC::ArrayBufferView>&&); + void append(RefPtr<Blob>&&); + void append(const String& text); - PassRefPtr<Blob> getBlob(const String& contentType); + Vector<BlobPart> finalize(); private: - void appendBytesData(const void*, size_t); - - Vector<char>& getBuffer(); - - long long m_size; - BlobDataItemList m_items; + BlobLineEndings m_endings; + Vector<BlobPart> m_items; + Vector<uint8_t> m_appendableData; }; } // namespace WebCore - -#endif // WebKitBlobBuilder_h diff --git a/Source/WebCore/fileapi/BlobLineEndings.h b/Source/WebCore/fileapi/BlobLineEndings.h new file mode 100644 index 000000000..92a62c369 --- /dev/null +++ b/Source/WebCore/fileapi/BlobLineEndings.h @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2016 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +namespace WebCore { + +enum class BlobLineEndings { + Transparent, + Native +}; + +} diff --git a/Source/WebCore/fileapi/BlobLineEndings.idl b/Source/WebCore/fileapi/BlobLineEndings.idl new file mode 100644 index 000000000..36831693b --- /dev/null +++ b/Source/WebCore/fileapi/BlobLineEndings.idl @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2016 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +// FIXME: This is no longer in the FileAPI spec. +enum BlobLineEndings { "transparent", "native" }; diff --git a/Source/WebCore/fileapi/BlobPropertyBag.h b/Source/WebCore/fileapi/BlobPropertyBag.h new file mode 100644 index 000000000..ac99ce9b0 --- /dev/null +++ b/Source/WebCore/fileapi/BlobPropertyBag.h @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2016 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#include "BlobLineEndings.h" +#include <wtf/text/WTFString.h> + +namespace WebCore { + +struct BlobPropertyBag { + String type; + BlobLineEndings endings = BlobLineEndings::Transparent; +}; + +} diff --git a/Source/WebCore/fileapi/BlobPropertyBag.idl b/Source/WebCore/fileapi/BlobPropertyBag.idl new file mode 100644 index 000000000..73d3d4338 --- /dev/null +++ b/Source/WebCore/fileapi/BlobPropertyBag.idl @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2016 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +dictionary BlobPropertyBag { + DOMString type = ""; + + // FIXME: This is no longer in the FileAPI spec. + BlobLineEndings endings = "transparent"; +}; diff --git a/Source/WebCore/fileapi/BlobURL.cpp b/Source/WebCore/fileapi/BlobURL.cpp index 3debf3831..847ea493b 100644 --- a/Source/WebCore/fileapi/BlobURL.cpp +++ b/Source/WebCore/fileapi/BlobURL.cpp @@ -39,7 +39,7 @@ namespace WebCore { -const char BlobURL::kBlobProtocol[] = "blob"; +const char* kBlobProtocol = "blob"; URL BlobURL::createPublicURL(SecurityOrigin* securityOrigin) { diff --git a/Source/WebCore/fileapi/BlobURL.h b/Source/WebCore/fileapi/BlobURL.h index c7fa4fe74..359eaaf7f 100644 --- a/Source/WebCore/fileapi/BlobURL.h +++ b/Source/WebCore/fileapi/BlobURL.h @@ -28,8 +28,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef BlobURL_h -#define BlobURL_h +#pragma once #include "URL.h" @@ -52,14 +51,10 @@ public: static URL createInternalURL(); static String getOrigin(const URL&); static String getIdentifier(const URL&); - static const char* blobProtocol() { return kBlobProtocol; } private: static URL createBlobURL(const String& originString); - static const char kBlobProtocol[]; BlobURL() { } }; -} - -#endif // BlobURL_h +} // namespace WebCore diff --git a/Source/WebCore/fileapi/File.cpp b/Source/WebCore/fileapi/File.cpp index 6f6dd0e61..1298e02a8 100644 --- a/Source/WebCore/fileapi/File.cpp +++ b/Source/WebCore/fileapi/File.cpp @@ -26,114 +26,98 @@ #include "config.h" #include "File.h" +#include "BlobURL.h" #include "FileMetadata.h" #include "FileSystem.h" #include "MIMETypeRegistry.h" +#include "ThreadableBlobRegistry.h" #include <wtf/CurrentTime.h> #include <wtf/DateMath.h> #include <wtf/text/WTFString.h> namespace WebCore { -static String getContentTypeFromFileName(const String& name, File::ContentTypeLookupPolicy policy) -{ - String type; - int index = name.reverseFind('.'); - if (index != -1) { - if (policy == File::WellKnownContentTypes) - type = MIMETypeRegistry::getWellKnownMIMETypeForExtension(name.substring(index + 1)); - else { - ASSERT(policy == File::AllContentTypes); - type = MIMETypeRegistry::getMIMETypeForExtension(name.substring(index + 1)); - } - } - return type; -} - -static std::unique_ptr<BlobData> createBlobDataForFileWithType(const String& path, const String& contentType) +File::File(const String& path) + : Blob(uninitializedContructor) + , m_path(path) { - auto blobData = std::make_unique<BlobData>(); - ASSERT(Blob::isNormalizedContentType(contentType)); - blobData->setContentType(contentType); - blobData->appendFile(path); - return blobData; + m_internalURL = BlobURL::createInternalURL(); + m_size = -1; + computeNameAndContentType(m_path, String(), m_name, m_type); + ThreadableBlobRegistry::registerFileBlobURL(m_internalURL, path, m_type); } -static std::unique_ptr<BlobData> createBlobDataForFile(const String& path, File::ContentTypeLookupPolicy policy) +File::File(const String& path, const String& nameOverride) + : Blob(uninitializedContructor) + , m_path(path) { - return createBlobDataForFileWithType(path, getContentTypeFromFileName(path, policy)); + m_internalURL = BlobURL::createInternalURL(); + m_size = -1; + computeNameAndContentType(m_path, nameOverride, m_name, m_type); + ThreadableBlobRegistry::registerFileBlobURL(m_internalURL, path, m_type); } -static std::unique_ptr<BlobData> createBlobDataForFileWithName(const String& path, const String& fileSystemName, File::ContentTypeLookupPolicy policy) +File::File(DeserializationContructor, const String& path, const URL& url, const String& type, const String& name) + : Blob(deserializationContructor, url, type, -1, path) + , m_path(path) + , m_name(name) { - return createBlobDataForFileWithType(path, getContentTypeFromFileName(fileSystemName, policy)); } -#if ENABLE(DIRECTORY_UPLOAD) -PassRefPtr<File> File::createWithRelativePath(const String& path, const String& relativePath) +static BlobPropertyBag convertPropertyBag(const File::PropertyBag& initialBag) { - RefPtr<File> file = adoptRef(new File(path, AllContentTypes)); - file->m_relativePath = relativePath; - return file.release(); + BlobPropertyBag bag; + bag.type = initialBag.type; + return bag; } -#endif -File::File(const String& path, ContentTypeLookupPolicy policy) - : Blob(createBlobDataForFile(path, policy), -1) - , m_path(path) - , m_name(pathGetFileName(path)) +File::File(Vector<BlobPartVariant>&& blobPartVariants, const String& filename, const PropertyBag& propertyBag) + : Blob(WTFMove(blobPartVariants), convertPropertyBag(propertyBag)) + , m_name(filename) + , m_overrideLastModifiedDate(propertyBag.lastModified.value_or(currentTimeMS())) { } -File::File(const String& path, const URL& url, const String& type) - : Blob(url, type, -1) - , m_path(path) +double File::lastModified() const { - m_name = pathGetFileName(path); - // FIXME: File object serialization/deserialization does not include - // newer file object data members: m_name and m_relativePath. - // See SerializedScriptValue.cpp -} + if (m_overrideLastModifiedDate) + return m_overrideLastModifiedDate.value(); -File::File(const String& path, const String& name, ContentTypeLookupPolicy policy) - : Blob(createBlobDataForFileWithName(path, name, policy), -1) - , m_path(path) - , m_name(name) -{ -} + double result; -double File::lastModifiedDate() const -{ + // FIXME: This does sync-i/o on the main thread and also recalculates every time the method is called. + // The i/o should be performed on a background thread, + // and the result should be cached along with an asynchronous monitor for changes to the file. time_t modificationTime; if (getFileModificationTime(m_path, modificationTime) && isValidFileTime(modificationTime)) - return modificationTime * msPerSecond; + result = modificationTime * msPerSecond; + else + result = currentTime() * msPerSecond; - return currentTime() * msPerSecond; + return WTF::timeClip(result); } -unsigned long long File::size() const +void File::computeNameAndContentType(const String& path, const String& nameOverride, String& effectiveName, String& effectiveContentType) { - // FIXME: JavaScript cannot represent sizes as large as unsigned long long, we need to - // come up with an exception to throw if file size is not representable. - long long size; - if (!getFileSize(m_path, size)) - return 0; - return static_cast<unsigned long long>(size); +#if ENABLE(FILE_REPLACEMENT) + if (shouldReplaceFile(path)) { + computeNameAndContentTypeForReplacedFile(path, nameOverride, effectiveName, effectiveContentType); + return; + } +#endif + effectiveName = nameOverride.isNull() ? pathGetFileName(path) : nameOverride; + size_t index = effectiveName.reverseFind('.'); + if (index != notFound) + effectiveContentType = MIMETypeRegistry::getMIMETypeForExtension(effectiveName.substring(index + 1)); } -void File::captureSnapshot(long long& snapshotSize, double& snapshotModificationTime) const +String File::contentTypeForFile(const String& path) { - // Obtains a snapshot of the file by capturing its current size and modification time. This is used when we slice a file for the first time. - // If we fail to retrieve the size or modification time, probably due to that the file has been deleted, 0 size is returned. - FileMetadata metadata; - if (!getFileMetadata(m_path, metadata)) { - snapshotSize = 0; - snapshotModificationTime = invalidFileTime(); - return; - } + String name; + String type; + computeNameAndContentType(path, String(), name, type); - snapshotSize = metadata.length; - snapshotModificationTime = metadata.modificationTime; + return type; } } // namespace WebCore diff --git a/Source/WebCore/fileapi/File.h b/Source/WebCore/fileapi/File.h index edf485582..fbe357254 100644 --- a/Source/WebCore/fileapi/File.h +++ b/Source/WebCore/fileapi/File.h @@ -23,94 +23,80 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef File_h -#define File_h +#pragma once #include "Blob.h" -#include <wtf/PassRefPtr.h> +#include <wtf/Optional.h> +#include <wtf/Ref.h> +#include <wtf/TypeCasts.h> #include <wtf/text/WTFString.h> namespace WebCore { -struct FileMetadata; class URL; -class File : public Blob { +class File final : public Blob { public: - // AllContentTypes should only be used when the full path/name are trusted; otherwise, it could - // allow arbitrary pages to determine what applications an user has installed. - enum ContentTypeLookupPolicy { - WellKnownContentTypes, - AllContentTypes, + struct PropertyBag : BlobPropertyBag { + std::optional<long long> lastModified; }; - static PassRefPtr<File> create(const String& path, ContentTypeLookupPolicy policy = WellKnownContentTypes) + static Ref<File> create(const String& path) { - return adoptRef(new File(path, policy)); + return adoptRef(*new File(path)); } - // For deserialization. - static PassRefPtr<File> create(const String& path, const URL& srcURL, const String& type) + // Create a File using the 'new File' constructor. + static Ref<File> create(Vector<BlobPartVariant>&& blobPartVariants, const String& filename, const PropertyBag& propertyBag) { - return adoptRef(new File(path, srcURL, type)); + return adoptRef(*new File(WTFMove(blobPartVariants), filename, propertyBag)); } -#if ENABLE(DIRECTORY_UPLOAD) - static PassRefPtr<File> createWithRelativePath(const String& path, const String& relativePath); -#endif + static Ref<File> deserialize(const String& path, const URL& srcURL, const String& type, const String& name) + { + return adoptRef(*new File(deserializationContructor, path, srcURL, type, name)); + } // Create a file with a name exposed to the author (via File.name and associated DOM properties) that differs from the one provided in the path. - static PassRefPtr<File> createWithName(const String& path, const String& name, ContentTypeLookupPolicy policy = WellKnownContentTypes) + static Ref<File> createWithName(const String& path, const String& nameOverride) { - if (name.isEmpty()) - return adoptRef(new File(path, policy)); - return adoptRef(new File(path, name, policy)); + if (nameOverride.isEmpty()) + return adoptRef(*new File(path)); + return adoptRef(*new File(path, nameOverride)); } - virtual unsigned long long size() const override; - virtual bool isFile() const override { return true; } + bool isFile() const override { return true; } const String& path() const { return m_path; } const String& name() const { return m_name; } + WEBCORE_EXPORT double lastModified() const; - // This returns the current date and time if the file's last modifiecation date is not known (per spec: http://www.w3.org/TR/FileAPI/#dfn-lastModifiedDate). - double lastModifiedDate() const; + static String contentTypeForFile(const String& path); -#if ENABLE(DIRECTORY_UPLOAD) - // Returns the relative path of this file in the context of a directory selection. - const String& webkitRelativePath() const { return m_relativePath; } +#if ENABLE(FILE_REPLACEMENT) + static bool shouldReplaceFile(const String& path); #endif - // Note that this involves synchronous file operation. Think twice before calling this function. - void captureSnapshot(long long& snapshotSize, double& snapshotModificationTime) const; - private: - File(const String& path, ContentTypeLookupPolicy); + WEBCORE_EXPORT explicit File(const String& path); + File(const String& path, const String& nameOverride); + File(Vector<BlobPartVariant>&& blobPartVariants, const String& filename, const PropertyBag&); - // For deserialization. - File(const String& path, const URL& srcURL, const String& type); - File(const String& path, const String& name, ContentTypeLookupPolicy); + File(DeserializationContructor, const String& path, const URL& srcURL, const String& type, const String& name); + + static void computeNameAndContentType(const String& path, const String& nameOverride, String& effectiveName, String& effectiveContentType); +#if ENABLE(FILE_REPLACEMENT) + static void computeNameAndContentTypeForReplacedFile(const String& path, const String& nameOverride, String& effectiveName, String& effectiveContentType); +#endif String m_path; String m_name; -#if ENABLE(DIRECTORY_UPLOAD) - String m_relativePath; -#endif + std::optional<int64_t> m_overrideLastModifiedDate; }; -inline File* toFile(Blob* blob) -{ - ASSERT_WITH_SECURITY_IMPLICATION(!blob || blob->isFile()); - return static_cast<File*>(blob); -} - -inline const File* toFile(const Blob* blob) -{ - ASSERT_WITH_SECURITY_IMPLICATION(!blob || blob->isFile()); - return static_cast<const File*>(blob); -} - } // namespace WebCore -#endif // File_h +SPECIALIZE_TYPE_TRAITS_BEGIN(WebCore::File) + static bool isType(const WebCore::Blob& blob) { return blob.isFile(); } +SPECIALIZE_TYPE_TRAITS_END() diff --git a/Source/WebCore/fileapi/File.idl b/Source/WebCore/fileapi/File.idl index 1d9dc51fc..372bd8155 100644 --- a/Source/WebCore/fileapi/File.idl +++ b/Source/WebCore/fileapi/File.idl @@ -23,15 +23,21 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +typedef (ArrayBufferView or ArrayBuffer) BufferSource; +typedef (BufferSource or Blob or USVString) BlobPart; + +// FIXME: This should be exposed on Workers as well. [ - JSGenerateToNativeObject, + Constructor(sequence<BlobPart> fileBits, USVString fileName, optional FilePropertyBag options), + ExportMacro=WEBCORE_EXPORT, + Exposed=(Window), JSGenerateToJSObject, - JSNoStaticTables + JSGenerateToNativeObject, ] interface File : Blob { readonly attribute DOMString name; -#if !defined(LANGUAGE_GOBJECT) || !LANGUAGE_GOBJECT - readonly attribute Date lastModifiedDate; -#endif - [Conditional=DIRECTORY_UPLOAD] readonly attribute DOMString webkitRelativePath; + readonly attribute long long lastModified; }; +dictionary FilePropertyBag : BlobPropertyBag { + long long lastModified; +}; diff --git a/Source/WebCore/fileapi/FileError.h b/Source/WebCore/fileapi/FileError.h index 7678a5154..5bc57aa9a 100644 --- a/Source/WebCore/fileapi/FileError.h +++ b/Source/WebCore/fileapi/FileError.h @@ -28,12 +28,9 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef FileError_h -#define FileError_h +#pragma once -#if ENABLE(BLOB) - -#include <wtf/PassRefPtr.h> +#include <wtf/Ref.h> #include <wtf/RefCounted.h> namespace WebCore { @@ -56,7 +53,7 @@ public: PATH_EXISTS_ERR = 12, }; - static PassRefPtr<FileError> create(ErrorCode code) { return adoptRef(new FileError(code)); } + static Ref<FileError> create(ErrorCode code) { return adoptRef(*new FileError(code)); } ErrorCode code() const { return m_code; } @@ -69,7 +66,3 @@ private: }; } // namespace WebCore - -#endif // ENABLE(BLOB) - -#endif // FileError_h diff --git a/Source/WebCore/fileapi/FileError.idl b/Source/WebCore/fileapi/FileError.idl index 866ce9274..34fa4acb5 100644 --- a/Source/WebCore/fileapi/FileError.idl +++ b/Source/WebCore/fileapi/FileError.idl @@ -29,12 +29,8 @@ */ [ - Conditional=BLOB, - JSNoStaticTables, ImplementationLacksVTable ] interface FileError { -#if !defined(LANGUAGE_OBJECTIVE_C) - // FIXME: Some of constant names are already defined in DOMException.h for Objective-C binding and we cannot have the same names here (they are translated into a enum in the same namespace). const unsigned short NOT_FOUND_ERR = 1; const unsigned short SECURITY_ERR = 2; const unsigned short ABORT_ERR = 3; @@ -47,6 +43,6 @@ const unsigned short QUOTA_EXCEEDED_ERR = 10; const unsigned short TYPE_MISMATCH_ERR = 11; const unsigned short PATH_EXISTS_ERR = 12; -#endif + readonly attribute unsigned short code; }; diff --git a/Source/WebCore/fileapi/FileException.cpp b/Source/WebCore/fileapi/FileException.cpp index 357fb495d..975d1c708 100644 --- a/Source/WebCore/fileapi/FileException.cpp +++ b/Source/WebCore/fileapi/FileException.cpp @@ -10,7 +10,7 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * 3. Neither the name of Apple Inc. ("Apple") nor the names of * its contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * @@ -27,11 +27,10 @@ */ #include "config.h" - -#if ENABLE(BLOB) - #include "FileException.h" +#include "ExceptionCodeDescription.h" + namespace WebCore { static struct FileExceptionNameDescription { @@ -71,5 +70,3 @@ bool FileException::initializeDescription(ExceptionCode ec, ExceptionCodeDescrip } } // namespace WebCore - -#endif // ENABLE(BLOB) diff --git a/Source/WebCore/fileapi/FileException.h b/Source/WebCore/fileapi/FileException.h index ccf7982df..dc2d15b9a 100644 --- a/Source/WebCore/fileapi/FileException.h +++ b/Source/WebCore/fileapi/FileException.h @@ -28,10 +28,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef FileException_h -#define FileException_h - -#if ENABLE(BLOB) +#pragma once #include "ExceptionBase.h" @@ -39,9 +36,9 @@ namespace WebCore { class FileException : public ExceptionBase { public: - static PassRefPtr<FileException> create(const ExceptionCodeDescription& description) + static Ref<FileException> create(const ExceptionCodeDescription& description) { - return adoptRef(new FileException(description)); + return adoptRef(*new FileException(description)); } static const int FileExceptionOffset = 1100; @@ -79,7 +76,3 @@ private: }; } // namespace WebCore - -#endif // ENABLE(BLOB) - -#endif // FileException_h diff --git a/Source/WebCore/fileapi/FileException.idl b/Source/WebCore/fileapi/FileException.idl index 8ff47c524..416e22584 100644 --- a/Source/WebCore/fileapi/FileException.idl +++ b/Source/WebCore/fileapi/FileException.idl @@ -29,21 +29,15 @@ */ [ - NoInterfaceObject, - Conditional=BLOB, DoNotCheckConstants, - JSNoStaticTables, ImplementationLacksVTable, + NoInterfaceObject, ] exception FileException { + readonly attribute unsigned short code; + readonly attribute DOMString name; + readonly attribute DOMString message; - readonly attribute unsigned short code; - readonly attribute DOMString name; - readonly attribute DOMString message; - -#if defined(LANGUAGE_JAVASCRIPT) && LANGUAGE_JAVASCRIPT - // Override in a Mozilla compatible format [NotEnumerable] DOMString toString(); -#endif // FileExceptionCode const unsigned short NOT_FOUND_ERR = 1; diff --git a/Source/WebCore/fileapi/FileList.h b/Source/WebCore/fileapi/FileList.h index 1e982ee77..7296bc5de 100644 --- a/Source/WebCore/fileapi/FileList.h +++ b/Source/WebCore/fileapi/FileList.h @@ -23,12 +23,10 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef FileList_h -#define FileList_h +#pragma once #include "File.h" #include "ScriptWrappable.h" -#include <wtf/PassRefPtr.h> #include <wtf/RefCounted.h> #include <wtf/RefPtr.h> #include <wtf/Vector.h> @@ -37,25 +35,35 @@ namespace WebCore { class FileList : public ScriptWrappable, public RefCounted<FileList> { public: - static PassRefPtr<FileList> create() + static Ref<FileList> create() { - return adoptRef(new FileList); + return adoptRef(*new FileList); + } + + static Ref<FileList> create(Vector<RefPtr<File>>&& files) + { + return adoptRef(*new FileList(WTFMove(files))); } unsigned length() const { return m_files.size(); } - File* item(unsigned index) const; + WEBCORE_EXPORT File* item(unsigned index) const; bool isEmpty() const { return m_files.isEmpty(); } - void clear() { m_files.clear(); } - void append(PassRefPtr<File> file) { m_files.append(file); } Vector<String> paths() const; private: FileList(); + FileList(Vector<RefPtr<File>>&& files) + : m_files(WTFMove(files)) + { } + + // FileLists can only be changed by their owners. + friend class DataTransfer; + friend class FileInputType; + void append(RefPtr<File>&& file) { m_files.append(WTFMove(file)); } + void clear() { m_files.clear(); } Vector<RefPtr<File>> m_files; }; } // namespace WebCore - -#endif // FileList_h diff --git a/Source/WebCore/fileapi/FileList.idl b/Source/WebCore/fileapi/FileList.idl index 258f9ccb6..42d553814 100644 --- a/Source/WebCore/fileapi/FileList.idl +++ b/Source/WebCore/fileapi/FileList.idl @@ -24,7 +24,6 @@ */ [ - JSNoStaticTables, ImplementationLacksVTable, ] interface FileList { readonly attribute unsigned long length; diff --git a/Source/WebCore/fileapi/FileReader.cpp b/Source/WebCore/fileapi/FileReader.cpp index 0025bc045..ea46dd9d6 100644 --- a/Source/WebCore/fileapi/FileReader.cpp +++ b/Source/WebCore/fileapi/FileReader.cpp @@ -29,12 +29,9 @@ */ #include "config.h" - -#if ENABLE(BLOB) - #include "FileReader.h" -#include "CrossThreadTask.h" +#include "EventNames.h" #include "ExceptionCode.h" #include "File.h" #include "Logging.h" @@ -46,109 +43,107 @@ namespace WebCore { -static const auto progressNotificationInterval = std::chrono::milliseconds(50); +// Fire the progress event at least every 50ms. +static const auto progressNotificationInterval = 50ms; -PassRefPtr<FileReader> FileReader::create(ScriptExecutionContext& context) +Ref<FileReader> FileReader::create(ScriptExecutionContext& context) { - RefPtr<FileReader> fileReader(adoptRef(new FileReader(context))); + auto fileReader = adoptRef(*new FileReader(context)); fileReader->suspendIfNeeded(); - return fileReader.release(); + return fileReader; } FileReader::FileReader(ScriptExecutionContext& context) : ActiveDOMObject(&context) - , m_state(EMPTY) - , m_aborting(false) - , m_readType(FileReaderLoader::ReadAsBinaryString) { } FileReader::~FileReader() { - terminate(); + if (m_loader) + m_loader->cancel(); } -bool FileReader::canSuspend() const +bool FileReader::canSuspendForDocumentSuspension() const { // FIXME: It is not currently possible to suspend a FileReader, so pages with FileReader can not go into page cache. return false; } +const char* FileReader::activeDOMObjectName() const +{ + return "FileReader"; +} + void FileReader::stop() { - terminate(); + if (m_loader) { + m_loader->cancel(); + m_loader = nullptr; + } + m_state = DONE; } -void FileReader::readAsArrayBuffer(Blob* blob, ExceptionCode& ec) +ExceptionOr<void> FileReader::readAsArrayBuffer(Blob* blob) { if (!blob) - return; + return { }; - LOG(FileAPI, "FileReader: reading as array buffer: %s %s\n", blob->url().string().utf8().data(), blob->isFile() ? toFile(blob)->path().utf8().data() : ""); + LOG(FileAPI, "FileReader: reading as array buffer: %s %s\n", blob->url().string().utf8().data(), is<File>(*blob) ? downcast<File>(*blob).path().utf8().data() : ""); - readInternal(blob, FileReaderLoader::ReadAsArrayBuffer, ec); + return readInternal(*blob, FileReaderLoader::ReadAsArrayBuffer); } -void FileReader::readAsBinaryString(Blob* blob, ExceptionCode& ec) +ExceptionOr<void> FileReader::readAsBinaryString(Blob* blob) { if (!blob) - return; + return { }; - LOG(FileAPI, "FileReader: reading as binary: %s %s\n", blob->url().string().utf8().data(), blob->isFile() ? toFile(blob)->path().utf8().data() : ""); + LOG(FileAPI, "FileReader: reading as binary: %s %s\n", blob->url().string().utf8().data(), is<File>(*blob) ? downcast<File>(*blob).path().utf8().data() : ""); - readInternal(blob, FileReaderLoader::ReadAsBinaryString, ec); + return readInternal(*blob, FileReaderLoader::ReadAsBinaryString); } -void FileReader::readAsText(Blob* blob, const String& encoding, ExceptionCode& ec) +ExceptionOr<void> FileReader::readAsText(Blob* blob, const String& encoding) { if (!blob) - return; + return { }; - LOG(FileAPI, "FileReader: reading as text: %s %s\n", blob->url().string().utf8().data(), blob->isFile() ? toFile(blob)->path().utf8().data() : ""); + LOG(FileAPI, "FileReader: reading as text: %s %s\n", blob->url().string().utf8().data(), is<File>(*blob) ? downcast<File>(*blob).path().utf8().data() : ""); m_encoding = encoding; - readInternal(blob, FileReaderLoader::ReadAsText, ec); -} - -void FileReader::readAsText(Blob* blob, ExceptionCode& ec) -{ - readAsText(blob, String(), ec); + return readInternal(*blob, FileReaderLoader::ReadAsText); } -void FileReader::readAsDataURL(Blob* blob, ExceptionCode& ec) +ExceptionOr<void> FileReader::readAsDataURL(Blob* blob) { if (!blob) - return; + return { }; - LOG(FileAPI, "FileReader: reading as data URL: %s %s\n", blob->url().string().utf8().data(), blob->isFile() ? toFile(blob)->path().utf8().data() : ""); + LOG(FileAPI, "FileReader: reading as data URL: %s %s\n", blob->url().string().utf8().data(), is<File>(*blob) ? downcast<File>(*blob).path().utf8().data() : ""); - readInternal(blob, FileReaderLoader::ReadAsDataURL, ec); + return readInternal(*blob, FileReaderLoader::ReadAsDataURL); } -void FileReader::readInternal(Blob* blob, FileReaderLoader::ReadType type, ExceptionCode& ec) +ExceptionOr<void> FileReader::readInternal(Blob& blob, FileReaderLoader::ReadType type) { // If multiple concurrent read methods are called on the same FileReader, INVALID_STATE_ERR should be thrown when the state is LOADING. - if (m_state == LOADING) { - ec = INVALID_STATE_ERR; - return; - } + if (m_state == LOADING) + return Exception { INVALID_STATE_ERR }; setPendingActivity(this); - m_blob = blob; + m_blob = &blob; m_readType = type; m_state = LOADING; - m_error = 0; + m_error = nullptr; - m_loader = std::make_unique<FileReaderLoader>(m_readType, this); + m_loader = std::make_unique<FileReaderLoader>(m_readType, static_cast<FileReaderLoaderClient*>(this)); m_loader->setEncoding(m_encoding); m_loader->setDataType(m_blob->type()); - m_loader->start(scriptExecutionContext(), m_blob.get()); -} + m_loader->start(scriptExecutionContext(), blob); -static void delayedAbort(ScriptExecutionContext*, FileReader* reader) -{ - reader->doAbort(); + return { }; } void FileReader::abort() @@ -160,34 +155,21 @@ void FileReader::abort() m_aborting = true; // Schedule to have the abort done later since abort() might be called from the event handler and we do not want the resource loading code to be in the stack. - scriptExecutionContext()->postTask( - createCallbackTask(&delayedAbort, AllowAccessLater(this))); -} - -void FileReader::doAbort() -{ - ASSERT(m_state != DONE); + scriptExecutionContext()->postTask([this] (ScriptExecutionContext&) { + ASSERT(m_state != DONE); - terminate(); - m_aborting = false; + stop(); + m_aborting = false; - m_error = FileError::create(FileError::ABORT_ERR); + m_error = FileError::create(FileError::ABORT_ERR); - fireEvent(eventNames().errorEvent); - fireEvent(eventNames().abortEvent); - fireEvent(eventNames().loadendEvent); + fireEvent(eventNames().errorEvent); + fireEvent(eventNames().abortEvent); + fireEvent(eventNames().loadendEvent); - // All possible events have fired and we're done, no more pending activity. - unsetPendingActivity(this); -} - -void FileReader::terminate() -{ - if (m_loader) { - m_loader->cancel(); - m_loader = nullptr; - } - m_state = DONE; + // All possible events have fired and we're done, no more pending activity. + unsetPendingActivity(this); + }); } void FileReader::didStartLoading() @@ -197,13 +179,11 @@ void FileReader::didStartLoading() void FileReader::didReceiveData() { - // Fire the progress event at least every 50ms. auto now = std::chrono::steady_clock::now(); if (!m_lastProgressNotificationTime.time_since_epoch().count()) { m_lastProgressNotificationTime = now; return; } - if (now - m_lastProgressNotificationTime > progressNotificationInterval) { fireEvent(eventNames().progressEvent); m_lastProgressNotificationTime = now; @@ -248,20 +228,20 @@ void FileReader::fireEvent(const AtomicString& type) dispatchEvent(ProgressEvent::create(type, true, m_loader ? m_loader->bytesLoaded() : 0, m_loader ? m_loader->totalBytes() : 0)); } -PassRefPtr<ArrayBuffer> FileReader::arrayBufferResult() const +std::optional<Variant<String, RefPtr<JSC::ArrayBuffer>>> FileReader::result() const { if (!m_loader || m_error) - return 0; - return m_loader->arrayBufferResult(); -} - -String FileReader::stringResult() -{ - if (!m_loader || m_error) - return String(); - return m_loader->stringResult(); + return std::nullopt; + if (m_readType == FileReaderLoader::ReadAsArrayBuffer) { + auto result = m_loader->arrayBufferResult(); + if (!result) + return std::nullopt; + return { result }; + } + String result = m_loader->stringResult(); + if (result.isNull()) + return std::nullopt; + return { WTFMove(result) }; } } // namespace WebCore - -#endif // ENABLE(BLOB) diff --git a/Source/WebCore/fileapi/FileReader.h b/Source/WebCore/fileapi/FileReader.h index 789701635..c13a5929b 100644 --- a/Source/WebCore/fileapi/FileReader.h +++ b/Source/WebCore/fileapi/FileReader.h @@ -28,20 +28,15 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef FileReader_h -#define FileReader_h - -#if ENABLE(BLOB) +#pragma once #include "ActiveDOMObject.h" #include "EventTarget.h" +#include "ExceptionOr.h" #include "FileError.h" #include "FileReaderLoader.h" #include "FileReaderLoaderClient.h" #include <chrono> -#include <wtf/Forward.h> -#include <wtf/RefCounted.h> -#include <wtf/text/WTFString.h> namespace JSC { class ArrayBuffer; @@ -50,13 +45,10 @@ class ArrayBuffer; namespace WebCore { class Blob; -class ScriptExecutionContext; - -typedef int ExceptionCode; -class FileReader final : public RefCounted<FileReader>, public ActiveDOMObject, public EventTargetWithInlineData, public FileReaderLoaderClient { +class FileReader final : public RefCounted<FileReader>, public ActiveDOMObject, public EventTargetWithInlineData, private FileReaderLoaderClient { public: - static PassRefPtr<FileReader> create(ScriptExecutionContext&); + static Ref<FileReader> create(ScriptExecutionContext&); virtual ~FileReader(); @@ -66,61 +58,47 @@ public: DONE = 2 }; - void readAsArrayBuffer(Blob*, ExceptionCode&); - void readAsBinaryString(Blob*, ExceptionCode&); - void readAsText(Blob*, const String& encoding, ExceptionCode&); - void readAsText(Blob*, ExceptionCode&); - void readAsDataURL(Blob*, ExceptionCode&); + ExceptionOr<void> readAsArrayBuffer(Blob*); + ExceptionOr<void> readAsBinaryString(Blob*); + ExceptionOr<void> readAsText(Blob*, const String& encoding); + ExceptionOr<void> readAsDataURL(Blob*); void abort(); void doAbort(); ReadyState readyState() const { return m_state; } - PassRefPtr<FileError> error() { return m_error; } + RefPtr<FileError> error() { return m_error; } FileReaderLoader::ReadType readType() const { return m_readType; } - PassRefPtr<JSC::ArrayBuffer> arrayBufferResult() const; - String stringResult(); - - // EventTarget - virtual EventTargetInterface eventTargetInterface() const override { return FileReaderEventTargetInterfaceType; } - virtual ScriptExecutionContext* scriptExecutionContext() const override { return ActiveDOMObject::scriptExecutionContext(); } - - // FileReaderLoaderClient - virtual void didStartLoading() override; - virtual void didReceiveData() override; - virtual void didFinishLoading() override; - virtual void didFail(int errorCode) override; + std::optional<Variant<String, RefPtr<JSC::ArrayBuffer>>> result() const; - using RefCounted<FileReader>::ref; - using RefCounted<FileReader>::deref; - - DEFINE_ATTRIBUTE_EVENT_LISTENER(loadstart); - DEFINE_ATTRIBUTE_EVENT_LISTENER(progress); - DEFINE_ATTRIBUTE_EVENT_LISTENER(load); - DEFINE_ATTRIBUTE_EVENT_LISTENER(abort); - DEFINE_ATTRIBUTE_EVENT_LISTENER(error); - DEFINE_ATTRIBUTE_EVENT_LISTENER(loadend); + using RefCounted::ref; + using RefCounted::deref; private: explicit FileReader(ScriptExecutionContext&); - // ActiveDOMObject - virtual bool canSuspend() const override; - virtual void stop() override; + const char* activeDOMObjectName() const final; + bool canSuspendForDocumentSuspension() const final; + void stop() final; + + EventTargetInterface eventTargetInterface() const final { return FileReaderEventTargetInterfaceType; } + ScriptExecutionContext* scriptExecutionContext() const final { return ActiveDOMObject::scriptExecutionContext(); } + void refEventTarget() final { ref(); } + void derefEventTarget() final { deref(); } - // EventTarget - virtual void refEventTarget() override { ref(); } - virtual void derefEventTarget() override { deref(); } + void didStartLoading() final; + void didReceiveData() final; + void didFinishLoading() final; + void didFail(int errorCode) final; - void terminate(); - void readInternal(Blob*, FileReaderLoader::ReadType, ExceptionCode&); + ExceptionOr<void> readInternal(Blob&, FileReaderLoader::ReadType); void fireErrorEvent(int httpStatusCode); void fireEvent(const AtomicString& type); - ReadyState m_state; - bool m_aborting; + ReadyState m_state { EMPTY }; + bool m_aborting { false }; RefPtr<Blob> m_blob; - FileReaderLoader::ReadType m_readType; + FileReaderLoader::ReadType m_readType { FileReaderLoader::ReadAsBinaryString }; String m_encoding; std::unique_ptr<FileReaderLoader> m_loader; RefPtr<FileError> m_error; @@ -128,7 +106,3 @@ private: }; } // namespace WebCore - -#endif // ENABLE(BLOB) - -#endif // FileReader_h diff --git a/Source/WebCore/fileapi/FileReader.idl b/Source/WebCore/fileapi/FileReader.idl index 6ad56e323..a033a3b8d 100644 --- a/Source/WebCore/fileapi/FileReader.idl +++ b/Source/WebCore/fileapi/FileReader.idl @@ -30,46 +30,34 @@ */ [ - GlobalContext=DOMWindow&WorkerGlobalScope, - Conditional=BLOB, + Exposed=(Window,Worker), ActiveDOMObject, Constructor, ConstructorCallWith=ScriptExecutionContext, - EventTarget, - JSNoStaticTables, -] interface FileReader { +] interface FileReader : EventTarget { // ready states const unsigned short EMPTY = 0; const unsigned short LOADING = 1; const unsigned short DONE = 2; readonly attribute unsigned short readyState; + // FIXME: In all four methods found below, the blob parameter should not be nullable. // async read methods - [RaisesException] void readAsArrayBuffer(Blob blob); - [RaisesException] void readAsBinaryString(Blob blob); - [RaisesException] void readAsText(Blob blob, optional DOMString encoding); - [RaisesException] void readAsDataURL(Blob blob); + [MayThrowException] void readAsArrayBuffer(Blob? blob); + [MayThrowException] void readAsBinaryString(Blob? blob); + [MayThrowException] void readAsText(Blob? blob, optional DOMString encoding); + [MayThrowException] void readAsDataURL(Blob? blob); void abort(); - // file data - [Custom] readonly attribute any result; + readonly attribute (DOMString or ArrayBuffer)? result; readonly attribute FileError error; - // EventTarget interface - void addEventListener(DOMString type, - EventListener listener, - optional boolean useCapture); - void removeEventListener(DOMString type, - EventListener listener, - optional boolean useCapture); - [RaisesException] boolean dispatchEvent(Event evt); - - attribute EventListener onloadstart; - attribute EventListener onprogress; - attribute EventListener onload; - attribute EventListener onabort; - attribute EventListener onerror; - attribute EventListener onloadend; + attribute EventHandler onloadstart; + attribute EventHandler onprogress; + attribute EventHandler onload; + attribute EventHandler onabort; + attribute EventHandler onerror; + attribute EventHandler onloadend; }; diff --git a/Source/WebCore/fileapi/FileReaderLoader.cpp b/Source/WebCore/fileapi/FileReaderLoader.cpp index 007ff70a9..7fd08fea1 100644 --- a/Source/WebCore/fileapi/FileReaderLoader.cpp +++ b/Source/WebCore/fileapi/FileReaderLoader.cpp @@ -30,13 +30,13 @@ #include "config.h" -#if ENABLE(BLOB) - #include "FileReaderLoader.h" #include "Blob.h" #include "BlobURL.h" #include "FileReaderLoaderClient.h" +#include "HTTPHeaderNames.h" +#include "ResourceError.h" #include "ResourceRequest.h" #include "ResourceResponse.h" #include "ScriptExecutionContext.h" @@ -44,7 +44,6 @@ #include "ThreadableBlobRegistry.h" #include "ThreadableLoader.h" #include <runtime/ArrayBuffer.h> -#include <wtf/PassRefPtr.h> #include <wtf/RefPtr.h> #include <wtf/Vector.h> #include <wtf/text/Base64.h> @@ -58,13 +57,10 @@ FileReaderLoader::FileReaderLoader(ReadType readType, FileReaderLoaderClient* cl : m_readType(readType) , m_client(client) , m_isRawDataConverted(false) - , m_stringResult("") + , m_stringResult(emptyString()) , m_variableLength(false) , m_bytesLoaded(0) , m_totalBytes(0) - , m_hasRange(false) - , m_rangeStart(0) - , m_rangeEnd(0) , m_errorCode(0) { } @@ -76,33 +72,33 @@ FileReaderLoader::~FileReaderLoader() ThreadableBlobRegistry::unregisterBlobURL(m_urlForReading); } -void FileReaderLoader::start(ScriptExecutionContext* scriptExecutionContext, Blob* blob) +void FileReaderLoader::start(ScriptExecutionContext* scriptExecutionContext, Blob& blob) { + ASSERT(scriptExecutionContext); + // The blob is read by routing through the request handling layer given a temporary public url. m_urlForReading = BlobURL::createPublicURL(scriptExecutionContext->securityOrigin()); if (m_urlForReading.isEmpty()) { failed(FileError::SECURITY_ERR); return; } - ThreadableBlobRegistry::registerBlobURL(scriptExecutionContext->securityOrigin(), m_urlForReading, blob->url()); + ThreadableBlobRegistry::registerBlobURL(scriptExecutionContext->securityOrigin(), m_urlForReading, blob.url()); // Construct and load the request. ResourceRequest request(m_urlForReading); request.setHTTPMethod("GET"); - if (m_hasRange) - request.setHTTPHeaderField("Range", String::format("bytes=%d-%d", m_rangeStart, m_rangeEnd)); ThreadableLoaderOptions options; options.sendLoadCallbacks = SendCallbacks; - options.sniffContent = DoNotSniffContent; - options.preflightPolicy = ConsiderPreflight; - options.allowCredentials = AllowStoredCredentials; - options.crossOriginRequestPolicy = DenyCrossOriginRequests; + options.dataBufferingPolicy = DoNotBufferData; + options.credentials = FetchOptions::Credentials::Include; + options.mode = FetchOptions::Mode::SameOrigin; + options.contentSecurityPolicyEnforcement = ContentSecurityPolicyEnforcement::DoNotEnforce; if (m_client) - m_loader = ThreadableLoader::create(scriptExecutionContext, this, request, options); + m_loader = ThreadableLoader::create(*scriptExecutionContext, *this, WTFMove(request), options); else - ThreadableLoader::loadResourceSynchronously(scriptExecutionContext, request, *this, options); + ThreadableLoader::loadResourceSynchronously(*scriptExecutionContext, WTFMove(request), *this, options); } void FileReaderLoader::cancel() @@ -121,12 +117,12 @@ void FileReaderLoader::terminate() void FileReaderLoader::cleanup() { - m_loader = 0; + m_loader = nullptr; // If we get any error, we do not need to keep a buffer around. if (m_errorCode) { - m_rawData = 0; - m_stringResult = ""; + m_rawData = nullptr; + m_stringResult = emptyString(); } } @@ -137,16 +133,12 @@ void FileReaderLoader::didReceiveResponse(unsigned long, const ResourceResponse& return; } - unsigned long long length = response.expectedContentLength(); + long long length = response.expectedContentLength(); - // A value larger than INT_MAX means that the content length wasn't - // specified, so the buffer will need to be dynamically grown. - if (length > INT_MAX) { + // A negative value means that the content length wasn't specified, so the buffer will need to be dynamically grown. + if (length < 0) { m_variableLength = true; - if (m_hasRange) - length = 1 + m_rangeEnd - m_rangeStart; - else - length = defaultBufferLength; + length = defaultBufferLength; } // Check that we can cast to unsigned since we have to do @@ -158,7 +150,7 @@ void FileReaderLoader::didReceiveResponse(unsigned long, const ResourceResponse& } ASSERT(!m_rawData); - m_rawData = ArrayBuffer::create(static_cast<unsigned>(length), 1); + m_rawData = ArrayBuffer::tryCreate(static_cast<unsigned>(length), 1); if (!m_rawData) { failed(FileError::NOT_READABLE_ERR); @@ -189,17 +181,26 @@ void FileReaderLoader::didReceiveData(const char* data, int dataLength) return; } if (m_variableLength) { - unsigned long long newLength = m_totalBytes * 2; - if (newLength > std::numeric_limits<unsigned>::max()) - newLength = std::numeric_limits<unsigned>::max(); - RefPtr<ArrayBuffer> newData = - ArrayBuffer::create(static_cast<unsigned>(newLength), 1); + unsigned newLength = m_totalBytes + static_cast<unsigned>(dataLength); + if (newLength < m_totalBytes) { + failed(FileError::NOT_READABLE_ERR); + return; + } + newLength = std::max(newLength, m_totalBytes + m_totalBytes / 4 + 1); + auto newData = ArrayBuffer::tryCreate(newLength, 1); + if (!newData) { + // Not enough memory. + failed(FileError::NOT_READABLE_ERR); + return; + } memcpy(static_cast<char*>(newData->data()), static_cast<char*>(m_rawData->data()), m_bytesLoaded); m_rawData = newData; m_totalBytes = static_cast<unsigned>(newLength); - } else + } else { + // This can only happen if we get more data than indicated in expected content length (i.e. never, unless the networking layer is buggy). length = remainingBufferSpace; + } } if (length <= 0) @@ -227,13 +228,13 @@ void FileReaderLoader::didFinishLoading(unsigned long, double) m_client->didFinishLoading(); } -void FileReaderLoader::didFail(const ResourceError&) +void FileReaderLoader::didFail(const ResourceError& error) { // If we're aborting, do not proceed with normal error handling since it is covered in aborting code. if (m_errorCode == FileError::ABORT_ERR) return; - failed(FileError::NOT_READABLE_ERR); + failed(toErrorCode(static_cast<BlobResourceHandle::Error>(error.errorCode()))); } void FileReaderLoader::failed(int errorCode) @@ -244,32 +245,40 @@ void FileReaderLoader::failed(int errorCode) m_client->didFail(m_errorCode); } +FileError::ErrorCode FileReaderLoader::toErrorCode(BlobResourceHandle::Error error) +{ + switch (error) { + case BlobResourceHandle::Error::NotFoundError: + return FileError::NOT_FOUND_ERR; + default: + return FileError::NOT_READABLE_ERR; + } +} + FileError::ErrorCode FileReaderLoader::httpStatusCodeToErrorCode(int httpStatusCode) { switch (httpStatusCode) { case 403: return FileError::SECURITY_ERR; - case 404: - return FileError::NOT_FOUND_ERR; default: return FileError::NOT_READABLE_ERR; } } -PassRefPtr<ArrayBuffer> FileReaderLoader::arrayBufferResult() const +RefPtr<ArrayBuffer> FileReaderLoader::arrayBufferResult() const { ASSERT(m_readType == ReadAsArrayBuffer); // If the loading is not started or an error occurs, return an empty result. if (!m_rawData || m_errorCode) - return 0; + return nullptr; // If completed, we can simply return our buffer. if (isCompleted()) return m_rawData; // Otherwise, return a copy. - return ArrayBuffer::create(m_rawData.get()); + return ArrayBuffer::create(*m_rawData); } String FileReaderLoader::stringResult() @@ -316,21 +325,18 @@ void FileReaderLoader::convertToText() // requirement in order to be consistent with how WebKit decodes the web content: always has the BOM override the // provided encoding. // FIXME: consider supporting incremental decoding to improve the perf. - StringBuilder builder; if (!m_decoder) m_decoder = TextResourceDecoder::create("text/plain", m_encoding.isValid() ? m_encoding : UTF8Encoding()); - builder.append(m_decoder->decode(static_cast<const char*>(m_rawData->data()), m_bytesLoaded)); - if (isCompleted()) - builder.append(m_decoder->flush()); - - m_stringResult = builder.toString(); + m_stringResult = m_decoder->decodeAndFlush(static_cast<const char*>(m_rawData->data()), m_bytesLoaded); + else + m_stringResult = m_decoder->decode(static_cast<const char*>(m_rawData->data()), m_bytesLoaded); } void FileReaderLoader::convertToDataURL() { StringBuilder builder; - builder.append("data:"); + builder.appendLiteral("data:"); if (!m_bytesLoaded) { m_stringResult = builder.toString(); @@ -338,7 +344,7 @@ void FileReaderLoader::convertToDataURL() } builder.append(m_dataType); - builder.append(";base64,"); + builder.appendLiteral(";base64,"); Vector<char> out; base64Encode(m_rawData->data(), m_bytesLoaded, out); @@ -360,5 +366,3 @@ void FileReaderLoader::setEncoding(const String& encoding) } } // namespace WebCore - -#endif // ENABLE(BLOB) diff --git a/Source/WebCore/fileapi/FileReaderLoader.h b/Source/WebCore/fileapi/FileReaderLoader.h index 435662613..5f4e73ed8 100644 --- a/Source/WebCore/fileapi/FileReaderLoader.h +++ b/Source/WebCore/fileapi/FileReaderLoader.h @@ -28,11 +28,9 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef FileReaderLoader_h -#define FileReaderLoader_h - -#if ENABLE(BLOB) +#pragma once +#include "BlobResourceHandle.h" #include "FileError.h" #include "URL.h" #include "TextEncoding.h" @@ -66,17 +64,17 @@ public: FileReaderLoader(ReadType, FileReaderLoaderClient*); ~FileReaderLoader(); - void start(ScriptExecutionContext*, Blob*); + void start(ScriptExecutionContext*, Blob&); void cancel(); // ThreadableLoaderClient - virtual void didReceiveResponse(unsigned long, const ResourceResponse&); - virtual void didReceiveData(const char*, int); - virtual void didFinishLoading(unsigned long, double); - virtual void didFail(const ResourceError&); + void didReceiveResponse(unsigned long, const ResourceResponse&) override; + void didReceiveData(const char*, int) override; + void didFinishLoading(unsigned long, double) override; + void didFail(const ResourceError&) override; String stringResult(); - PassRefPtr<JSC::ArrayBuffer> arrayBufferResult() const; + RefPtr<JSC::ArrayBuffer> arrayBufferResult() const; unsigned bytesLoaded() const { return m_bytesLoaded; } unsigned totalBytes() const { return m_totalBytes; } int errorCode() const { return m_errorCode; } @@ -94,6 +92,7 @@ private: bool isCompleted() const; static FileError::ErrorCode httpStatusCodeToErrorCode(int); + static FileError::ErrorCode toErrorCode(BlobResourceHandle::Error); ReadType m_readType; FileReaderLoaderClient* m_client; @@ -116,15 +115,7 @@ private: unsigned m_bytesLoaded; unsigned m_totalBytes; - bool m_hasRange; - unsigned m_rangeStart; - unsigned m_rangeEnd; - int m_errorCode; }; } // namespace WebCore - -#endif // ENABLE(BLOB) - -#endif // FileReaderLoader_h diff --git a/Source/WebCore/fileapi/FileReaderLoaderClient.h b/Source/WebCore/fileapi/FileReaderLoaderClient.h index 4acb8ad3a..c2faaba10 100644 --- a/Source/WebCore/fileapi/FileReaderLoaderClient.h +++ b/Source/WebCore/fileapi/FileReaderLoaderClient.h @@ -28,10 +28,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef FileReaderLoaderClient_h -#define FileReaderLoaderClient_h - -#if ENABLE(BLOB) +#pragma once namespace WebCore { @@ -46,7 +43,3 @@ public: }; } // namespace WebCore - -#endif // ENABLE(BLOB) - -#endif // FileReaderLoaderClient_h diff --git a/Source/WebCore/fileapi/FileReaderSync.cpp b/Source/WebCore/fileapi/FileReaderSync.cpp index 2d53afd1b..da475d504 100644 --- a/Source/WebCore/fileapi/FileReaderSync.cpp +++ b/Source/WebCore/fileapi/FileReaderSync.cpp @@ -30,8 +30,6 @@ #include "config.h" -#if ENABLE(BLOB) - #include "FileReaderSync.h" #include "Blob.h" @@ -39,7 +37,6 @@ #include "FileException.h" #include "FileReaderLoader.h" #include <runtime/ArrayBuffer.h> -#include <wtf/PassRefPtr.h> namespace WebCore { @@ -47,63 +44,49 @@ FileReaderSync::FileReaderSync() { } -PassRefPtr<ArrayBuffer> FileReaderSync::readAsArrayBuffer(ScriptExecutionContext* scriptExecutionContext, Blob* blob, ExceptionCode& ec) +ExceptionOr<RefPtr<ArrayBuffer>> FileReaderSync::readAsArrayBuffer(ScriptExecutionContext& scriptExecutionContext, Blob& blob) { - if (!blob) { - ec = NOT_FOUND_ERR; - return 0; - } - FileReaderLoader loader(FileReaderLoader::ReadAsArrayBuffer, 0); - startLoading(scriptExecutionContext, loader, blob, ec); - + auto result = startLoading(scriptExecutionContext, loader, blob); + if (result.hasException()) + return result.releaseException(); return loader.arrayBufferResult(); } -String FileReaderSync::readAsBinaryString(ScriptExecutionContext* scriptExecutionContext, Blob* blob, ExceptionCode& ec) +ExceptionOr<String> FileReaderSync::readAsBinaryString(ScriptExecutionContext& scriptExecutionContext, Blob& blob) { - if (!blob) { - ec = NOT_FOUND_ERR; - return String(); - } - FileReaderLoader loader(FileReaderLoader::ReadAsBinaryString, 0); - startLoading(scriptExecutionContext, loader, blob, ec); - return loader.stringResult(); + return startLoadingString(scriptExecutionContext, loader, blob); } -String FileReaderSync::readAsText(ScriptExecutionContext* scriptExecutionContext, Blob* blob, const String& encoding, ExceptionCode& ec) +ExceptionOr<String> FileReaderSync::readAsText(ScriptExecutionContext& scriptExecutionContext, Blob& blob, const String& encoding) { - if (!blob) { - ec = NOT_FOUND_ERR; - return String(); - } - FileReaderLoader loader(FileReaderLoader::ReadAsText, 0); loader.setEncoding(encoding); - startLoading(scriptExecutionContext, loader, blob, ec); - return loader.stringResult(); + return startLoadingString(scriptExecutionContext, loader, blob); } -String FileReaderSync::readAsDataURL(ScriptExecutionContext* scriptExecutionContext, Blob* blob, ExceptionCode& ec) +ExceptionOr<String> FileReaderSync::readAsDataURL(ScriptExecutionContext& scriptExecutionContext, Blob& blob) { - if (!blob) { - ec = NOT_FOUND_ERR; - return String(); - } - FileReaderLoader loader(FileReaderLoader::ReadAsDataURL, 0); - loader.setDataType(blob->type()); - startLoading(scriptExecutionContext, loader, blob, ec); - return loader.stringResult(); + loader.setDataType(blob.type()); + return startLoadingString(scriptExecutionContext, loader, blob); +} + +ExceptionOr<void> FileReaderSync::startLoading(ScriptExecutionContext& scriptExecutionContext, FileReaderLoader& loader, Blob& blob) +{ + loader.start(&scriptExecutionContext, blob); + if (ExceptionCode code = FileException::ErrorCodeToExceptionCode(loader.errorCode())) + return Exception { code }; + return { }; } -void FileReaderSync::startLoading(ScriptExecutionContext* scriptExecutionContext, FileReaderLoader& loader, Blob* blob, ExceptionCode& ec) +ExceptionOr<String> FileReaderSync::startLoadingString(ScriptExecutionContext& scriptExecutionContext, FileReaderLoader& loader, Blob& blob) { - loader.start(scriptExecutionContext, blob); - ec = FileException::ErrorCodeToExceptionCode(loader.errorCode()); + auto result = startLoading(scriptExecutionContext, loader, blob); + if (result.hasException()) + return result.releaseException(); + return loader.stringResult(); } } // namespace WebCore - -#endif // ENABLE(BLOB) diff --git a/Source/WebCore/fileapi/FileReaderSync.h b/Source/WebCore/fileapi/FileReaderSync.h index 50140efcd..9e25cda8b 100644 --- a/Source/WebCore/fileapi/FileReaderSync.h +++ b/Source/WebCore/fileapi/FileReaderSync.h @@ -28,14 +28,9 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef FileReaderSync_h -#define FileReaderSync_h +#pragma once -#if ENABLE(BLOB) - -#include <wtf/Forward.h> -#include <wtf/RefCounted.h> -#include <wtf/text/WTFString.h> +#include "ExceptionOr.h" namespace JSC { class ArrayBuffer; @@ -47,34 +42,23 @@ class Blob; class FileReaderLoader; class ScriptExecutionContext; -typedef int ExceptionCode; - class FileReaderSync : public RefCounted<FileReaderSync> { public: - static PassRefPtr<FileReaderSync> create() + static Ref<FileReaderSync> create() { - return adoptRef(new FileReaderSync()); + return adoptRef(*new FileReaderSync); } - virtual ~FileReaderSync() { } - - PassRefPtr<JSC::ArrayBuffer> readAsArrayBuffer(ScriptExecutionContext*, Blob*, ExceptionCode&); - String readAsBinaryString(ScriptExecutionContext*, Blob*, ExceptionCode&); - String readAsText(ScriptExecutionContext* scriptExecutionContext, Blob* blob, ExceptionCode& ec) - { - return readAsText(scriptExecutionContext, blob, "", ec); - } - String readAsText(ScriptExecutionContext*, Blob*, const String& encoding, ExceptionCode&); - String readAsDataURL(ScriptExecutionContext*, Blob*, ExceptionCode&); + ExceptionOr<RefPtr<JSC::ArrayBuffer>> readAsArrayBuffer(ScriptExecutionContext&, Blob&); + ExceptionOr<String> readAsBinaryString(ScriptExecutionContext&, Blob&); + ExceptionOr<String> readAsText(ScriptExecutionContext&, Blob&, const String& encoding); + ExceptionOr<String> readAsDataURL(ScriptExecutionContext&, Blob&); private: FileReaderSync(); - void startLoading(ScriptExecutionContext*, FileReaderLoader&, Blob*, ExceptionCode&); + ExceptionOr<void> startLoading(ScriptExecutionContext&, FileReaderLoader&, Blob&); + ExceptionOr<String> startLoadingString(ScriptExecutionContext&, FileReaderLoader&, Blob&); }; } // namespace WebCore - -#endif // ENABLE(BLOB) - -#endif // FileReaderSync_h diff --git a/Source/WebCore/fileapi/FileReaderSync.idl b/Source/WebCore/fileapi/FileReaderSync.idl index 184f32200..664be3ac9 100644 --- a/Source/WebCore/fileapi/FileReaderSync.idl +++ b/Source/WebCore/fileapi/FileReaderSync.idl @@ -29,13 +29,12 @@ */ [ - GlobalContext=WorkerGlobalScope, - Conditional=BLOB, Constructor, - JSNoStaticTables, + Exposed=Worker, + ImplementationLacksVTable, ] interface FileReaderSync { - [CallWith=ScriptExecutionContext, RaisesException] ArrayBuffer readAsArrayBuffer(Blob blob); - [CallWith=ScriptExecutionContext, RaisesException] DOMString readAsBinaryString(Blob blob); - [CallWith=ScriptExecutionContext, RaisesException] DOMString readAsText(Blob blob, optional DOMString encoding); - [CallWith=ScriptExecutionContext, RaisesException] DOMString readAsDataURL(Blob blob); + [CallWith=ScriptExecutionContext, MayThrowException] ArrayBuffer readAsArrayBuffer(Blob blob); + [CallWith=ScriptExecutionContext, MayThrowException] DOMString readAsBinaryString(Blob blob); + [CallWith=ScriptExecutionContext, MayThrowException] DOMString readAsText(Blob blob, optional DOMString encoding = ""); + [CallWith=ScriptExecutionContext, MayThrowException] DOMString readAsDataURL(Blob blob); }; diff --git a/Source/WebCore/fileapi/FileThread.cpp b/Source/WebCore/fileapi/FileThread.cpp deleted file mode 100644 index e43f0e72d..000000000 --- a/Source/WebCore/fileapi/FileThread.cpp +++ /dev/null @@ -1,117 +0,0 @@ -/* - * Copyright (C) 2010 Google Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "config.h" - -#if ENABLE(BLOB) - -#include "FileThread.h" - -#include "Logging.h" -#include <wtf/AutodrainedPool.h> - -namespace WebCore { - -FileThread::FileThread() - : m_threadID(0) -{ - m_selfRef = this; -} - -FileThread::~FileThread() -{ - ASSERT(m_queue.killed()); -} - -bool FileThread::start() -{ - MutexLocker lock(m_threadCreationMutex); - if (m_threadID) - return true; - m_threadID = createThread(FileThread::fileThreadStart, this, "WebCore: File"); - return m_threadID; -} - -void FileThread::stop() -{ - m_queue.kill(); -} - -void FileThread::postTask(std::unique_ptr<Task> task) -{ - m_queue.append(std::move(task)); -} - -class SameInstancePredicate { -public: - SameInstancePredicate(const void* instance) : m_instance(instance) { } - bool operator()(FileThread::Task& task) const { return task.instance() == m_instance; } -private: - const void* m_instance; -}; - -void FileThread::unscheduleTasks(const void* instance) -{ - SameInstancePredicate predicate(instance); - m_queue.removeIf(predicate); -} - -void FileThread::fileThreadStart(void* arg) -{ - FileThread* fileThread = static_cast<FileThread*>(arg); - fileThread->runLoop(); -} - -void FileThread::runLoop() -{ - { - // Wait for FileThread::start() to complete to have m_threadID - // established before starting the main loop. - MutexLocker lock(m_threadCreationMutex); - LOG(FileAPI, "Started FileThread %p", this); - } - - while (auto task = m_queue.waitForMessage()) { - AutodrainedPool pool; - - task->performTask(); - } - - LOG(FileAPI, "About to detach thread %i and clear the ref to FileThread %p, which currently has %i ref(s)", m_threadID, this, refCount()); - - detachThread(m_threadID); - - // Clear the self refptr, possibly resulting in deletion - m_selfRef = 0; -} - -} // namespace WebCore - -#endif // ENABLE(BLOB) diff --git a/Source/WebCore/fileapi/FileThreadTask.h b/Source/WebCore/fileapi/FileThreadTask.h deleted file mode 100644 index a0541dff9..000000000 --- a/Source/WebCore/fileapi/FileThreadTask.h +++ /dev/null @@ -1,206 +0,0 @@ -/* - * Copyright (C) 2010 Google Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef FileThreadTask_h -#define FileThreadTask_h - -#include "CrossThreadCopier.h" -#include "CrossThreadTask.h" -#include "FileThread.h" -#include <wtf/PassRefPtr.h> - -namespace WebCore { - -template<typename T> -class FileThreadTask0 : public FileThread::Task { -public: - typedef void (T::*Method)(); - typedef FileThreadTask0<T> FileThreadTaskImpl; - - FileThreadTask0(T* instance, Method method) - : FileThread::Task(instance) - , m_method(method) - { - } - -private: - virtual void performTask() override - { - (*static_cast<T*>(instance()).*m_method)(); - } - -private: - Method m_method; -}; - -template<typename T, typename P1, typename MP1> -class FileThreadTask1 : public FileThread::Task { -public: - typedef void (T::*Method)(MP1); - typedef FileThreadTask1<T, P1, MP1> FileThreadTaskImpl; - typedef typename CrossThreadTaskTraits<P1>::ParamType Param1; - - FileThreadTask1(T* instance, Method method, Param1 parameter1) - : FileThread::Task(instance) - , m_method(method) - , m_parameter1(parameter1) - { - } - -private: - virtual void performTask() override - { - (*static_cast<T*>(instance()).*m_method)(m_parameter1); - } - -private: - Method m_method; - P1 m_parameter1; -}; - -template<typename T, typename P1, typename MP1, typename P2, typename MP2> -class FileThreadTask2 : public FileThread::Task { -public: - typedef void (T::*Method)(MP1, MP2); - typedef FileThreadTask2<T, P1, MP1, P2, MP2> FileThreadTaskImpl; - typedef typename CrossThreadTaskTraits<P1>::ParamType Param1; - typedef typename CrossThreadTaskTraits<P2>::ParamType Param2; - - FileThreadTask2(T* instance, Method method, Param1 parameter1, Param2 parameter2) - : FileThread::Task(instance) - , m_method(method) - , m_parameter1(parameter1) - , m_parameter2(parameter2) - { - } - -private: - virtual void performTask() override - { - (*static_cast<T*>(instance()).*m_method)(m_parameter1, m_parameter2); - } - -private: - Method m_method; - P1 m_parameter1; - P2 m_parameter2; -}; - -template<typename T, typename P1, typename MP1, typename P2, typename MP2, typename P3, typename MP3> -class FileThreadTask3 : public FileThread::Task { -public: - typedef void (T::*Method)(MP1, MP2, MP3); - typedef FileThreadTask3<T, P1, MP1, P2, MP2, P3, MP3> FileThreadTaskImpl; - typedef typename CrossThreadTaskTraits<P1>::ParamType Param1; - typedef typename CrossThreadTaskTraits<P2>::ParamType Param2; - typedef typename CrossThreadTaskTraits<P3>::ParamType Param3; - - FileThreadTask3(T* instance, Method method, Param1 parameter1, Param2 parameter2, Param3 parameter3) - : FileThread::Task(instance) - , m_method(method) - , m_parameter1(parameter1) - , m_parameter2(parameter2) - , m_parameter3(parameter3) - { - } - -private: - virtual void performTask() override - { - (*static_cast<T*>(instance()).*m_method)(m_parameter1, m_parameter2, m_parameter3); - } - -private: - Method m_method; - P1 m_parameter1; - P2 m_parameter2; - P3 m_parameter3; -}; - -template<typename T> -std::unique_ptr<FileThread::Task> createFileThreadTask( - T* const callee, - void (T::*method)()); - -template<typename T> -std::unique_ptr<FileThread::Task> createFileThreadTask( - T* const callee, - void (T::*method)()) -{ - return std::make_unique<FileThreadTask0<T>>( - callee, - method); -} - -template<typename T, typename P1, typename MP1> -std::unique_ptr<FileThread::Task> createFileThreadTask( - T* const callee, - void (T::*method)(MP1), - const P1& parameter1) -{ - return std::make_unique<FileThreadTask1<T, typename CrossThreadCopier<P1>::Type, MP1>>( - callee, - method, - CrossThreadCopier<P1>::copy(parameter1)); -} - -template<typename T, typename P1, typename MP1, typename P2, typename MP2> -std::unique_ptr<FileThread::Task> createFileThreadTask( - T* const callee, - void (T::*method)(MP1, MP2), - const P1& parameter1, - const P2& parameter2) -{ - return std::make_unique<FileThreadTask2<T, typename CrossThreadCopier<P1>::Type, MP1, typename CrossThreadCopier<P2>::Type, MP2>>( - callee, - method, - CrossThreadCopier<P1>::copy(parameter1), - CrossThreadCopier<P2>::copy(parameter2)); -} - -template<typename T, typename P1, typename MP1, typename P2, typename MP2, typename P3, typename MP3> -std::unique_ptr<FileThread::Task> createFileThreadTask( - T* const callee, - void (T::*method)(MP1, MP2, MP3), - const P1& parameter1, - const P2& parameter2, - const P3& parameter3) -{ - return std::make_unique<FileThreadTask3<T, typename CrossThreadCopier<P1>::Type, MP1, typename CrossThreadCopier<P2>::Type, MP2, typename CrossThreadCopier<P3>::Type, MP3>>( - callee, - method, - CrossThreadCopier<P1>::copy(parameter1), - CrossThreadCopier<P2>::copy(parameter2), - CrossThreadCopier<P3>::copy(parameter3)); -} - -} // namespace WebCore - -#endif // FileThreadTask_h diff --git a/Source/WebCore/fileapi/ThreadableBlobRegistry.cpp b/Source/WebCore/fileapi/ThreadableBlobRegistry.cpp index 19844412e..b6c57a31d 100644 --- a/Source/WebCore/fileapi/ThreadableBlobRegistry.cpp +++ b/Source/WebCore/fileapi/ThreadableBlobRegistry.cpp @@ -1,5 +1,6 @@ /* * Copyright (C) 2010 Google Inc. All rights reserved. + * Copyright (C) 2013, 2014, 2016 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are @@ -31,49 +32,25 @@ #include "config.h" #include "ThreadableBlobRegistry.h" -#include "BlobData.h" +#include "BlobDataFileReference.h" +#include "BlobPart.h" #include "BlobRegistry.h" #include "BlobURL.h" #include "SecurityOrigin.h" #include <mutex> +#include <wtf/CrossThreadQueue.h> +#include <wtf/CrossThreadTask.h> #include <wtf/HashMap.h> #include <wtf/MainThread.h> #include <wtf/RefPtr.h> #include <wtf/ThreadSpecific.h> #include <wtf/text/StringHash.h> +#include <wtf/threads/BinarySemaphore.h> using WTF::ThreadSpecific; namespace WebCore { -struct BlobRegistryContext { - WTF_MAKE_FAST_ALLOCATED; -public: - BlobRegistryContext(const URL& url, std::unique_ptr<BlobData> blobData) - : url(url.copy()) - , blobData(std::move(blobData)) - { - this->blobData->detachFromCurrentThread(); - } - - BlobRegistryContext(const URL& url, const URL& srcURL) - : url(url.copy()) - , srcURL(srcURL.copy()) - { - } - - BlobRegistryContext(const URL& url) - : url(url.copy()) - { - } - - URL url; - URL srcURL; - std::unique_ptr<BlobData> blobData; -}; - -#if ENABLE(BLOB) - typedef HashMap<String, RefPtr<SecurityOrigin>> BlobUrlOriginMap; static ThreadSpecific<BlobUrlOriginMap>& originMap() @@ -87,24 +64,45 @@ static ThreadSpecific<BlobUrlOriginMap>& originMap() return *map; } -static void registerBlobURLTask(void* context) +static void postToMainThread(CrossThreadTask&& task) { - std::unique_ptr<BlobRegistryContext> blobRegistryContext(static_cast<BlobRegistryContext*>(context)); - blobRegistry().registerBlobURL(blobRegistryContext->url, std::move(blobRegistryContext->blobData)); + static std::once_flag onceFlag; + static CrossThreadQueue<CrossThreadTask>* queue; + std::call_once(onceFlag, [] { + queue = new CrossThreadQueue<CrossThreadTask>; + }); + + queue->append(WTFMove(task)); + + callOnMainThread([] { + auto task = queue->tryGetMessage(); + ASSERT(task); + task->performTask(); + }); } -void ThreadableBlobRegistry::registerBlobURL(const URL& url, std::unique_ptr<BlobData> blobData) +void ThreadableBlobRegistry::registerFileBlobURL(const URL& url, const String& path, const String& contentType) { if (isMainThread()) - blobRegistry().registerBlobURL(url, std::move(blobData)); - else - callOnMainThread(®isterBlobURLTask, new BlobRegistryContext(url, std::move(blobData))); + blobRegistry().registerFileBlobURL(url, BlobDataFileReference::create(path), contentType); + else { + callOnMainThread([url = url.isolatedCopy(), path = path.isolatedCopy(), contentType = contentType.isolatedCopy()] { + blobRegistry().registerFileBlobURL(url, BlobDataFileReference::create(path), contentType); + }); + } } -static void registerBlobURLFromTask(void* context) +void ThreadableBlobRegistry::registerBlobURL(const URL& url, Vector<BlobPart>&& blobParts, const String& contentType) { - std::unique_ptr<BlobRegistryContext> blobRegistryContext(static_cast<BlobRegistryContext*>(context)); - blobRegistry().registerBlobURL(blobRegistryContext->url, blobRegistryContext->srcURL); + if (isMainThread()) + blobRegistry().registerBlobURL(url, WTFMove(blobParts), contentType); + else { + for (auto& part : blobParts) + part.detachFromCurrentThread(); + callOnMainThread([url = url.isolatedCopy(), blobParts = WTFMove(blobParts), contentType = contentType.isolatedCopy()]() mutable { + blobRegistry().registerBlobURL(url, WTFMove(blobParts), contentType); + }); + } } void ThreadableBlobRegistry::registerBlobURL(SecurityOrigin* origin, const URL& url, const URL& srcURL) @@ -115,51 +113,65 @@ void ThreadableBlobRegistry::registerBlobURL(SecurityOrigin* origin, const URL& if (isMainThread()) blobRegistry().registerBlobURL(url, srcURL); - else - callOnMainThread(®isterBlobURLFromTask, new BlobRegistryContext(url, srcURL)); + else { + callOnMainThread([url = url.isolatedCopy(), srcURL = srcURL.isolatedCopy()] { + blobRegistry().registerBlobURL(url, srcURL); + }); + } } -static void unregisterBlobURLTask(void* context) +void ThreadableBlobRegistry::registerBlobURLOptionallyFileBacked(const URL& url, const URL& srcURL, const String& fileBackedPath, const String& contentType) { - std::unique_ptr<BlobRegistryContext> blobRegistryContext(static_cast<BlobRegistryContext*>(context)); - blobRegistry().unregisterBlobURL(blobRegistryContext->url); -} - -void ThreadableBlobRegistry::unregisterBlobURL(const URL& url) -{ - if (BlobURL::getOrigin(url) == "null") - originMap()->remove(url.string()); - if (isMainThread()) - blobRegistry().unregisterBlobURL(url); + blobRegistry().registerBlobURLOptionallyFileBacked(url, srcURL, BlobDataFileReference::create(fileBackedPath), contentType); else - callOnMainThread(&unregisterBlobURLTask, new BlobRegistryContext(url)); + postToMainThread(createCrossThreadTask(ThreadableBlobRegistry::registerBlobURLOptionallyFileBacked, url, srcURL, fileBackedPath, contentType)); } -PassRefPtr<SecurityOrigin> ThreadableBlobRegistry::getCachedOrigin(const URL& url) +void ThreadableBlobRegistry::registerBlobURLForSlice(const URL& newURL, const URL& srcURL, long long start, long long end) { - return originMap()->get(url.string()); + if (isMainThread()) + blobRegistry().registerBlobURLForSlice(newURL, srcURL, start, end); + else { + callOnMainThread([newURL = newURL.isolatedCopy(), srcURL = srcURL.isolatedCopy(), start, end] { + blobRegistry().registerBlobURLForSlice(newURL, srcURL, start, end); + }); + } } -#else - -void ThreadableBlobRegistry::registerBlobURL(const URL&, std::unique_ptr<BlobData>) +unsigned long long ThreadableBlobRegistry::blobSize(const URL& url) { + unsigned long long resultSize; + if (isMainThread()) + resultSize = blobRegistry().blobSize(url); + else { + BinarySemaphore semaphore; + callOnMainThread([url = url.isolatedCopy(), &semaphore, &resultSize] { + resultSize = blobRegistry().blobSize(url); + semaphore.signal(); + }); + semaphore.wait(WallTime::infinity()); + } + return resultSize; } -void ThreadableBlobRegistry::registerBlobURL(SecurityOrigin*, const URL&, const URL&) +void ThreadableBlobRegistry::unregisterBlobURL(const URL& url) { -} + if (BlobURL::getOrigin(url) == "null") + originMap()->remove(url.string()); -void ThreadableBlobRegistry::unregisterBlobURL(const URL&) -{ + if (isMainThread()) + blobRegistry().unregisterBlobURL(url); + else { + callOnMainThread([url = url.isolatedCopy()] { + blobRegistry().unregisterBlobURL(url); + }); + } } -PassRefPtr<SecurityOrigin> ThreadableBlobRegistry::getCachedOrigin(const URL&) +RefPtr<SecurityOrigin> ThreadableBlobRegistry::getCachedOrigin(const URL& url) { - return 0; + return originMap()->get(url.string()); } -#endif // ENABL(BLOB) - } // namespace WebCore diff --git a/Source/WebCore/fileapi/ThreadableBlobRegistry.h b/Source/WebCore/fileapi/ThreadableBlobRegistry.h index e2e5c694b..552a5d9b3 100644 --- a/Source/WebCore/fileapi/ThreadableBlobRegistry.h +++ b/Source/WebCore/fileapi/ThreadableBlobRegistry.h @@ -1,5 +1,6 @@ /* * Copyright (C) 2010 Google Inc. All rights reserved. + * Copyright (C) 2013, 2014, 2016 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are @@ -28,28 +29,31 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef ThreadableBlobRegistry_h -#define ThreadableBlobRegistry_h +#pragma once -#include <wtf/PassRefPtr.h> +#include <wtf/Forward.h> +#include <wtf/Vector.h> namespace WebCore { -class BlobData; +class BlobPart; class URL; class SecurityOrigin; class ThreadableBlobRegistry { public: - static void registerBlobURL(const URL&, std::unique_ptr<BlobData>); + static void registerFileBlobURL(const URL&, const String& path, const String& contentType); + static void registerBlobURL(const URL&, Vector<BlobPart>&& blobParts, const String& contentType); static void registerBlobURL(SecurityOrigin*, const URL&, const URL& srcURL); + static void registerBlobURLOptionallyFileBacked(const URL&, const URL& srcURL, const String& fileBackedPath, const String& contentType); + static void registerBlobURLForSlice(const URL& newURL, const URL& srcURL, long long start, long long end); static void unregisterBlobURL(const URL&); + static unsigned long long blobSize(const URL&); + // Returns the origin for the given blob URL. This is because we are not able to embed the unique security origin or the origin of file URL // in the blob URL. - static PassRefPtr<SecurityOrigin> getCachedOrigin(const URL&); + static RefPtr<SecurityOrigin> getCachedOrigin(const URL&); }; } // namespace WebCore - -#endif // ThreadableBlobRegistry_h diff --git a/Source/WebCore/fileapi/WebKitBlobBuilder.cpp b/Source/WebCore/fileapi/WebKitBlobBuilder.cpp deleted file mode 100644 index c47eb1f51..000000000 --- a/Source/WebCore/fileapi/WebKitBlobBuilder.cpp +++ /dev/null @@ -1,156 +0,0 @@ -/* - * Copyright (C) 2010 Google Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "config.h" - -#include "WebKitBlobBuilder.h" - -#include "Blob.h" -#include "Document.h" -#include "ExceptionCode.h" -#include "File.h" -#include "HistogramSupport.h" -#include "LineEnding.h" -#include "ScriptCallStack.h" -#include "TextEncoding.h" -#include <runtime/ArrayBuffer.h> -#include <runtime/ArrayBufferView.h> -#include <wtf/PassRefPtr.h> -#include <wtf/Vector.h> -#include <wtf/text/AtomicString.h> -#include <wtf/text/CString.h> - -namespace WebCore { - -// FIXME: Move this file to BlobBuilder.cpp - -enum BlobConstructorArrayBufferOrView { - BlobConstructorArrayBuffer, - BlobConstructorArrayBufferView, - BlobConstructorArrayBufferOrViewMax, -}; - -BlobBuilder::BlobBuilder() - : m_size(0) -{ -} - -Vector<char>& BlobBuilder::getBuffer() -{ - // If the last item is not a data item, create one. Otherwise, we simply append the new string to the last data item. - if (m_items.isEmpty() || m_items[m_items.size() - 1].type != BlobDataItem::Data) - m_items.append(BlobDataItem(RawData::create())); - - return *m_items[m_items.size() - 1].data->mutableData(); -} - -void BlobBuilder::append(const String& text, const String& endingType) -{ - CString utf8Text = UTF8Encoding().encode(text.deprecatedCharacters(), text.length(), EntitiesForUnencodables); - - Vector<char>& buffer = getBuffer(); - size_t oldSize = buffer.size(); - - if (endingType == "native") - normalizeLineEndingsToNative(utf8Text, buffer); - else { - ASSERT(endingType == "transparent"); - buffer.append(utf8Text.data(), utf8Text.length()); - } - m_size += buffer.size() - oldSize; -} - -#if ENABLE(BLOB) -void BlobBuilder::append(ArrayBuffer* arrayBuffer) -{ - HistogramSupport::histogramEnumeration("WebCore.Blob.constructor.ArrayBufferOrView", BlobConstructorArrayBuffer, BlobConstructorArrayBufferOrViewMax); - - if (!arrayBuffer) - return; - - appendBytesData(arrayBuffer->data(), arrayBuffer->byteLength()); -} - -void BlobBuilder::append(PassRefPtr<ArrayBufferView> arrayBufferView) -{ - HistogramSupport::histogramEnumeration("WebCore.Blob.constructor.ArrayBufferOrView", BlobConstructorArrayBufferView, BlobConstructorArrayBufferOrViewMax); - - if (!arrayBufferView) - return; - - appendBytesData(arrayBufferView->baseAddress(), arrayBufferView->byteLength()); -} -#endif - -void BlobBuilder::append(Blob* blob) -{ - if (!blob) - return; - if (blob->isFile()) { - File* file = toFile(blob); - // If the blob is file that is not snapshoted, capture the snapshot now. - // FIXME: This involves synchronous file operation. We need to figure out how to make it asynchronous. - long long snapshotSize; - double snapshotModificationTime; - file->captureSnapshot(snapshotSize, snapshotModificationTime); - - m_size += snapshotSize; - m_items.append(BlobDataItem(file->path(), 0, snapshotSize, snapshotModificationTime)); - } else { - long long blobSize = static_cast<long long>(blob->size()); - m_size += blobSize; - m_items.append(BlobDataItem(blob->url(), 0, blobSize)); - } -} - -void BlobBuilder::appendBytesData(const void* data, size_t length) -{ - Vector<char>& buffer = getBuffer(); - size_t oldSize = buffer.size(); - buffer.append(static_cast<const char*>(data), length); - m_size += buffer.size() - oldSize; -} - -PassRefPtr<Blob> BlobBuilder::getBlob(const String& contentType) -{ - auto blobData = std::make_unique<BlobData>(); - blobData->setContentType(Blob::normalizedContentType(contentType)); - blobData->swapItems(m_items); - - RefPtr<Blob> blob = Blob::create(std::move(blobData), m_size); - - // After creating a blob from the current blob data, we do not need to keep the data around any more. Instead, we only - // need to keep a reference to the URL of the blob just created. - m_items.append(BlobDataItem(blob->url(), 0, m_size)); - - return blob; -} - -} // namespace WebCore |