Index: WebCore/platform/network/BlobRegistryImpl.cpp |
=================================================================== |
--- WebCore/platform/network/BlobRegistryImpl.cpp (revision 140218) |
+++ WebCore/platform/network/BlobRegistryImpl.cpp (working copy) |
@@ -40,26 +40,28 @@ |
#include "ResourceLoader.h" |
#include "ResourceRequest.h" |
#include "ResourceResponse.h" |
+#include "SecurityOrigin.h" |
#include <wtf/MainThread.h> |
#include <wtf/StdLibExtras.h> |
namespace WebCore { |
-#if !PLATFORM(CHROMIUM) |
BlobRegistry& blobRegistry() |
{ |
- ASSERT(isMainThread()); |
- DEFINE_STATIC_LOCAL(BlobRegistryImpl, instance, ()); |
- return instance; |
+ // TODO: would be nice to ensure that this is first accessed on the main thread. |
+ AtomicallyInitializedStatic(BlobRegistryImpl&, intance = *new BlobRegistryImpl); |
+ return intance; |
} |
static PassRefPtr<ResourceHandle> createResourceHandle(const ResourceRequest& request, ResourceHandleClient* client) |
{ |
+ ASSERT(isMainThread()); |
return static_cast<BlobRegistryImpl&>(blobRegistry()).createResourceHandle(request, client); |
} |
static void registerBlobResourceHandleConstructor() |
{ |
+ ASSERT(isMainThread()); |
static bool didRegister = false; |
if (!didRegister) { |
ResourceHandle::registerBuiltinConstructor("blob", createResourceHandle); |
@@ -67,15 +69,9 @@ |
} |
} |
-#else |
- |
-static void registerBlobResourceHandleConstructor() |
-{ |
-} |
-#endif |
- |
bool BlobRegistryImpl::shouldLoadResource(const ResourceRequest& request) const |
{ |
+ ASSERT(isMainThread()); |
// If the resource is not fetched using the GET method, bail out. |
if (!equalIgnoringCase(request.httpMethod(), "GET")) |
return false; |
@@ -88,7 +84,7 @@ |
if (!shouldLoadResource(request)) |
return 0; |
- RefPtr<BlobResourceHandle> handle = BlobResourceHandle::create(m_blobs.get(request.url().string()), request, client); |
+ RefPtr<BlobResourceHandle> handle = BlobResourceHandle::create(getBlobDataFromURL(request.url()), request, client); |
handle->start(); |
return handle.release(); |
} |
@@ -98,26 +94,10 @@ |
if (!shouldLoadResource(request)) |
return false; |
- BlobResourceHandle::loadResourceSynchronously(m_blobs.get(request.url().string()), request, error, response, data); |
+ BlobResourceHandle::loadResourceSynchronously(getBlobDataFromURL(request.url()), request, error, response, data); |
return true; |
} |
-void BlobRegistryImpl::appendStorageItems(BlobStorageData* blobStorageData, const BlobDataItemList& items) |
-{ |
- for (BlobDataItemList::const_iterator iter = items.begin(); iter != items.end(); ++iter) { |
- if (iter->type == BlobDataItem::Data) |
- blobStorageData->m_data.appendData(iter->data, iter->offset, iter->length); |
-#if ENABLE(FILE_SYSTEM) |
- else if (iter->type == BlobDataItem::URL) |
- blobStorageData->m_data.appendURL(iter->url, iter->offset, iter->length, iter->expectedModificationTime); |
-#endif |
- else { |
- ASSERT(iter->type == BlobDataItem::File); |
- blobStorageData->m_data.appendFile(iter->path, iter->offset, iter->length, iter->expectedModificationTime); |
- } |
- } |
-} |
- |
void BlobRegistryImpl::appendStorageItems(BlobStorageData* blobStorageData, const BlobDataItemList& items, long long offset, long long length) |
{ |
ASSERT(length != BlobDataItem::toEndOfFile); |
@@ -139,76 +119,156 @@ |
blobStorageData->m_data.appendData(iter->data, iter->offset + offset, newLength); |
#if ENABLE(FILE_SYSTEM) |
else if (iter->type == BlobDataItem::URL) |
- blobStorageData->m_data.appendURL(iter->url, iter->offset + offset, newLength, iter->expectedModificationTime); |
+ blobStorageData->m_data.appendURL(iter->url.copy(), iter->offset + offset, newLength, iter->expectedModificationTime); |
#endif |
else { |
ASSERT(iter->type == BlobDataItem::File); |
- blobStorageData->m_data.appendFile(iter->path, iter->offset + offset, newLength, iter->expectedModificationTime); |
+ blobStorageData->m_data.appendFile(iter->path.isolatedCopy(), iter->offset + offset, newLength, iter->expectedModificationTime); |
} |
length -= newLength; |
offset = 0; |
} |
} |
-void BlobRegistryImpl::registerBlobURL(const KURL& url, PassOwnPtr<BlobData> blobData) |
+void BlobRegistryImpl::registerBlobData(const String& uuid, PassOwnPtr<BlobData> blobData) |
{ |
- ASSERT(isMainThread()); |
- registerBlobResourceHandleConstructor(); |
- |
- RefPtr<BlobStorageData> blobStorageData = BlobStorageData::create(blobData->contentType(), blobData->contentDisposition()); |
- |
// The blob data is stored in the "canonical" way. That is, it only contains a list of Data and File items. |
// 1) The Data item is denoted by the raw data and the range. |
// 2) The File item is denoted by the file path, the range and the expected modification time. |
// 3) The URL item is denoted by the URL, the range and the expected modification time. |
// All the Blob items in the passing blob data are resolved and expanded into a set of Data and File items. |
+ RefPtr<BlobStorageData> blobStorageData = BlobStorageData::create(blobData->contentType(), blobData->contentDisposition()); |
for (BlobDataItemList::const_iterator iter = blobData->items().begin(); iter != blobData->items().end(); ++iter) { |
switch (iter->type) { |
case BlobDataItem::Data: |
+ // FIXME: Can we avoid making this copy of the data? |
blobStorageData->m_data.appendData(iter->data, 0, iter->data->length()); |
break; |
case BlobDataItem::File: |
- blobStorageData->m_data.appendFile(iter->path, iter->offset, iter->length, iter->expectedModificationTime); |
+ blobStorageData->m_data.appendFile(iter->path.isolatedCopy(), iter->offset, iter->length, iter->expectedModificationTime); |
break; |
#if ENABLE(FILE_SYSTEM) |
case BlobDataItem::URL: |
- blobStorageData->m_data.appendURL(iter->url, iter->offset, iter->length, iter->expectedModificationTime); |
+ blobStorageData->m_data.appendURL(iter->url.copy(), iter->offset, iter->length, iter->expectedModificationTime); |
break; |
#endif |
- case BlobDataItem::Blob: |
- if (m_blobs.contains(iter->url.string())) |
- appendStorageItems(blobStorageData.get(), m_blobs.get(iter->url.string())->items(), iter->offset, iter->length); |
+ case BlobDataItem::Blob: { |
+ RefPtr<BlobStorageData> other = getBlobDataFromUUID(iter->blobDataHandle->uuid()); |
+ if (other) |
+ appendStorageItems(blobStorageData.get(), other->items(), iter->offset, iter->length); |
+ } |
break; |
} |
} |
- m_blobs.set(url.string(), blobStorageData); |
+ |
+ MutexLocker locker(m_mutex); |
+ ASSERT(m_blobs.find(uuid) == m_blobs.end()); |
+ m_blobs.set(uuid.isolatedCopy(), std::make_pair(1, blobStorageData)); |
} |
-void BlobRegistryImpl::registerBlobURL(const KURL& url, const KURL& srcURL) |
+void BlobRegistryImpl::addBlobDataRef(const String& uuid) |
{ |
- ASSERT(isMainThread()); |
- registerBlobResourceHandleConstructor(); |
+ MutexLocker locker(m_mutex); |
+ BlobMap::iterator found = m_blobs.find(uuid); |
+ ASSERT(found != m_blobs.end()); |
+ found->value.first += 1; |
+} |
- RefPtr<BlobStorageData> src = m_blobs.get(srcURL.string()); |
- ASSERT(src); |
- if (!src) |
- return; |
+void BlobRegistryImpl::removeBlobDataRef(const String& uuid) |
+{ |
+ MutexLocker locker(m_mutex); |
+ BlobMap::iterator found = m_blobs.find(uuid); |
+ ASSERT(found != m_blobs.end()); |
+ found->value.first -= 1; |
+ if (found->value.first == 0) |
+ m_blobs.remove(found); |
+} |
- m_blobs.set(url.string(), src); |
+// Helper to access the blob url map on the main thread only when registering/revoking urls. |
+class BlobRegistryImpl::URLRegistrationHelper { |
+public: |
+ URLRegistrationHelper(BlobRegistryImpl* registry, const KURL& url, PassRefPtr<BlobDataHandle> dataHandle = 0) |
+ : registry(registry) |
+ , url(url.copy()) |
+ , dataHandle(dataHandle) |
+ { |
+ } |
+ |
+ static void registerURLTask(void* context) |
+ { |
+ OwnPtr<URLRegistrationHelper> helper = adoptPtr(static_cast<URLRegistrationHelper*>(context)); |
+ helper->registerURL(); |
+ } |
+ |
+ static void revokeURLTask(void* context) |
+ { |
+ OwnPtr<URLRegistrationHelper> helper = adoptPtr(static_cast<URLRegistrationHelper*>(context)); |
+ helper->revokeURL(); |
+ } |
+ |
+ void registerURL() |
+ { |
+ ASSERT(isMainThread()); |
+ registerBlobResourceHandleConstructor(); |
+ registry->m_publicURLs.set(url, dataHandle); |
+ } |
+ |
+ void revokeURL() |
+ { |
+ ASSERT(isMainThread()); |
+ registry->m_publicURLs.remove(url); |
+ } |
+ |
+ BlobRegistryImpl* registry; |
+ KURL url; |
+ RefPtr<BlobDataHandle> dataHandle; // NULL for revoke tasks. |
+}; |
+ |
+ |
+void BlobRegistryImpl::registerPublicBlobURL(SecurityOrigin* origin, const KURL& url, PassRefPtr<BlobDataHandle> dataHandle) |
+{ |
+ // The cached origin has thread affinity so we must fiddle with it's registration on the current thread. |
+ BlobRegistry::setCachedUniqueOrigin(url, origin); |
+ |
+ // But the blob map is only accessed on the main thread. |
+ OwnPtr<URLRegistrationHelper> helper = adoptPtr(new URLRegistrationHelper(this, url, dataHandle)); |
+ if (isMainThread()) |
+ helper->registerURL(); |
+ else |
+ callOnMainThread(&URLRegistrationHelper::registerURLTask, helper.leakPtr()); |
} |
-void BlobRegistryImpl::unregisterBlobURL(const KURL& url) |
+void BlobRegistryImpl::revokePublicBlobURL(const KURL& url) |
{ |
- ASSERT(isMainThread()); |
- m_blobs.remove(url.string()); |
+ BlobRegistry::clearCachedUniqueOrigin(url); |
+ |
+ OwnPtr<URLRegistrationHelper> helper = adoptPtr(new URLRegistrationHelper(this, url)); |
+ if (isMainThread()) |
+ helper->revokeURL(); |
+ else |
+ callOnMainThread(&URLRegistrationHelper::revokeURLTask, helper.leakPtr()); |
} |
+PassRefPtr<SecurityOrigin> BlobRegistryImpl::cachedUniqueOrigin(const KURL& url) |
+{ |
+ return BlobRegistry::getCachedUniqueOrigin(url); |
+} |
+ |
+PassRefPtr<BlobStorageData> BlobRegistryImpl::getBlobDataFromUUID(const String& uuid) const |
+{ |
+ MutexLocker locker(m_mutex); |
+ return m_blobs.get(uuid).second; |
+} |
+ |
PassRefPtr<BlobStorageData> BlobRegistryImpl::getBlobDataFromURL(const KURL& url) const |
{ |
ASSERT(isMainThread()); |
- return m_blobs.get(url.string()); |
+ RefPtr<BlobDataHandle> dataHandle = m_publicURLs.get(url.string()); |
+ if (!dataHandle) |
+ return 0; |
+ return getBlobDataFromUUID(dataHandle->uuid()); |
} |
} // namespace WebCore |