ThreadableBlobRegistry.cpp [plain text]
#include "config.h"
#include "ThreadableBlobRegistry.h"
#include "BlobDataFileReference.h"
#include "BlobPart.h"
#include "BlobRegistry.h"
#include "BlobURL.h"
#include "SecurityOrigin.h"
#include <mutex>
#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, Vector<BlobPart> blobParts, const String& contentType)
: url(url.copy())
, contentType(contentType.isolatedCopy())
, blobParts(WTF::move(blobParts))
{
for (BlobPart& part : blobParts)
part.detachFromCurrentThread();
}
BlobRegistryContext(const URL& url, const URL& srcURL)
: url(url.copy())
, srcURL(srcURL.copy())
{
}
BlobRegistryContext(const URL& url)
: url(url.copy())
{
}
BlobRegistryContext(const URL& url, const String& path, const String& contentType)
: url(url.copy())
, path(path.isolatedCopy())
, contentType(contentType.isolatedCopy())
{
}
URL url;
URL srcURL;
String path;
String contentType;
Vector<BlobPart> blobParts;
};
typedef HashMap<String, RefPtr<SecurityOrigin>> BlobUrlOriginMap;
static ThreadSpecific<BlobUrlOriginMap>& originMap()
{
static std::once_flag onceFlag;
static ThreadSpecific<BlobUrlOriginMap>* map;
std::call_once(onceFlag, []{
map = new ThreadSpecific<BlobUrlOriginMap>;
});
return *map;
}
void ThreadableBlobRegistry::registerFileBlobURL(const URL& url, const String& path, const String& contentType)
{
if (isMainThread())
blobRegistry().registerFileBlobURL(url, BlobDataFileReference::create(path), contentType);
else {
BlobRegistryContext* context = new BlobRegistryContext(url, path, contentType);
callOnMainThread([context] {
std::unique_ptr<BlobRegistryContext> blobRegistryContext(context);
blobRegistry().registerFileBlobURL(blobRegistryContext->url, BlobDataFileReference::create(blobRegistryContext->path), blobRegistryContext->contentType);
});
}
}
void ThreadableBlobRegistry::registerBlobURL(const URL& url, Vector<BlobPart> blobParts, const String& contentType)
{
if (isMainThread())
blobRegistry().registerBlobURL(url, WTF::move(blobParts), contentType);
else {
BlobRegistryContext* context = new BlobRegistryContext(url, WTF::move(blobParts), contentType);
callOnMainThread([context] {
std::unique_ptr<BlobRegistryContext> blobRegistryContext(context);
blobRegistry().registerBlobURL(blobRegistryContext->url, WTF::move(blobRegistryContext->blobParts), blobRegistryContext->contentType);
});
}
}
void ThreadableBlobRegistry::registerBlobURL(SecurityOrigin* origin, const URL& url, const URL& srcURL)
{
if (origin && BlobURL::getOrigin(url) == "null")
originMap()->add(url.string(), origin);
if (isMainThread())
blobRegistry().registerBlobURL(url, srcURL);
else {
BlobRegistryContext* context = new BlobRegistryContext(url, srcURL);
callOnMainThread([context] {
std::unique_ptr<BlobRegistryContext> blobRegistryContext(context);
blobRegistry().registerBlobURL(blobRegistryContext->url, blobRegistryContext->srcURL);
});
}
}
void ThreadableBlobRegistry::registerBlobURLForSlice(const URL& newURL, const URL& srcURL, long long start, long long end)
{
if (isMainThread())
blobRegistry().registerBlobURLForSlice(newURL, srcURL, start, end);
else {
BlobRegistryContext* context = new BlobRegistryContext(newURL, srcURL);
callOnMainThread([context, start, end] {
std::unique_ptr<BlobRegistryContext> blobRegistryContext(context);
blobRegistry().registerBlobURLForSlice(blobRegistryContext->url, blobRegistryContext->srcURL, start, end);
});
}
}
unsigned long long ThreadableBlobRegistry::blobSize(const URL& url)
{
unsigned long long resultSize;
if (isMainThread())
resultSize = blobRegistry().blobSize(url);
else {
BlobRegistryContext* context = new BlobRegistryContext(url);
BinarySemaphore semaphore;
callOnMainThread([context, &semaphore, &resultSize] {
std::unique_ptr<BlobRegistryContext> blobRegistryContext(context);
resultSize = blobRegistry().blobSize(blobRegistryContext->url);
semaphore.signal();
});
semaphore.wait(std::numeric_limits<double>::max());
}
return resultSize;
}
void ThreadableBlobRegistry::unregisterBlobURL(const URL& url)
{
if (BlobURL::getOrigin(url) == "null")
originMap()->remove(url.string());
if (isMainThread())
blobRegistry().unregisterBlobURL(url);
else {
BlobRegistryContext* context = new BlobRegistryContext(url);
callOnMainThread([context] {
std::unique_ptr<BlobRegistryContext> blobRegistryContext(context);
blobRegistry().unregisterBlobURL(blobRegistryContext->url);
});
}
}
PassRefPtr<SecurityOrigin> ThreadableBlobRegistry::getCachedOrigin(const URL& url)
{
return originMap()->get(url.string());
}
}