summaryrefslogtreecommitdiff
path: root/Source/WebCore/fileapi/Blob.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Source/WebCore/fileapi/Blob.cpp')
-rw-r--r--Source/WebCore/fileapi/Blob.cpp197
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