diff options
Diffstat (limited to 'Source/WebCore/fileapi/Blob.cpp')
-rw-r--r-- | Source/WebCore/fileapi/Blob.cpp | 197 |
1 files changed, 79 insertions, 118 deletions
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 |