1/*
2 * Copyright (C) 2010 Google Inc. All rights reserved.
3 * Copyright (C) 2013, 2014, 2016 Apple Inc. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
7 * met:
8 *
9 * * Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * * Redistributions in binary form must reproduce the above
12 * copyright notice, this list of conditions and the following disclaimer
13 * in the documentation and/or other materials provided with the
14 * distribution.
15 * * Neither the name of Google Inc. nor the names of its
16 * contributors may be used to endorse or promote products derived from
17 * this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 */
31
32#include "config.h"
33#include "ThreadableBlobRegistry.h"
34
35#include "BlobDataFileReference.h"
36#include "BlobPart.h"
37#include "BlobRegistry.h"
38#include "BlobURL.h"
39#include "SecurityOrigin.h"
40#include <mutex>
41#include <wtf/CrossThreadQueue.h>
42#include <wtf/CrossThreadTask.h>
43#include <wtf/HashMap.h>
44#include <wtf/MainThread.h>
45#include <wtf/RefPtr.h>
46#include <wtf/ThreadSpecific.h>
47#include <wtf/text/StringHash.h>
48#include <wtf/threads/BinarySemaphore.h>
49
50using WTF::ThreadSpecific;
51
52namespace WebCore {
53
54typedef HashMap<String, RefPtr<SecurityOrigin>> BlobUrlOriginMap;
55
56static ThreadSpecific<BlobUrlOriginMap>& originMap()
57{
58 static std::once_flag onceFlag;
59 static ThreadSpecific<BlobUrlOriginMap>* map;
60 std::call_once(onceFlag, []{
61 map = new ThreadSpecific<BlobUrlOriginMap>;
62 });
63
64 return *map;
65}
66
67static void postToMainThread(CrossThreadTask&& task)
68{
69 static std::once_flag onceFlag;
70 static CrossThreadQueue<CrossThreadTask>* queue;
71 std::call_once(onceFlag, [] {
72 queue = new CrossThreadQueue<CrossThreadTask>;
73 });
74
75 queue->append(WTFMove(task));
76
77 callOnMainThread([] {
78 auto task = queue->tryGetMessage();
79 ASSERT(task);
80 task->performTask();
81 });
82}
83
84void ThreadableBlobRegistry::registerFileBlobURL(const URL& url, const String& path, const String& contentType)
85{
86 if (isMainThread())
87 blobRegistry().registerFileBlobURL(url, BlobDataFileReference::create(path), contentType);
88 else {
89 callOnMainThread([url = url.isolatedCopy(), path = path.isolatedCopy(), contentType = contentType.isolatedCopy()] {
90 blobRegistry().registerFileBlobURL(url, BlobDataFileReference::create(path), contentType);
91 });
92 }
93}
94
95void ThreadableBlobRegistry::registerBlobURL(const URL& url, Vector<BlobPart>&& blobParts, const String& contentType)
96{
97 if (isMainThread())
98 blobRegistry().registerBlobURL(url, WTFMove(blobParts), contentType);
99 else {
100 for (auto& part : blobParts)
101 part.detachFromCurrentThread();
102 callOnMainThread([url = url.isolatedCopy(), blobParts = WTFMove(blobParts), contentType = contentType.isolatedCopy()]() mutable {
103 blobRegistry().registerBlobURL(url, WTFMove(blobParts), contentType);
104 });
105 }
106}
107
108void ThreadableBlobRegistry::registerBlobURL(SecurityOrigin* origin, const URL& url, const URL& srcURL)
109{
110 // If the blob URL contains null origin, as in the context with unique security origin or file URL, save the mapping between url and origin so that the origin can be retrived when doing security origin check.
111 if (origin && BlobURL::getOrigin(url) == "null")
112 originMap()->add(url.string(), origin);
113
114 if (isMainThread())
115 blobRegistry().registerBlobURL(url, srcURL);
116 else {
117 callOnMainThread([url = url.isolatedCopy(), srcURL = srcURL.isolatedCopy()] {
118 blobRegistry().registerBlobURL(url, srcURL);
119 });
120 }
121}
122
123void ThreadableBlobRegistry::registerBlobURLOptionallyFileBacked(const URL& url, const URL& srcURL, const String& fileBackedPath, const String& contentType)
124{
125 if (isMainThread())
126 blobRegistry().registerBlobURLOptionallyFileBacked(url, srcURL, BlobDataFileReference::create(fileBackedPath), contentType);
127 else
128 postToMainThread(createCrossThreadTask(ThreadableBlobRegistry::registerBlobURLOptionallyFileBacked, url, srcURL, fileBackedPath, contentType));
129}
130
131void ThreadableBlobRegistry::registerBlobURLForSlice(const URL& newURL, const URL& srcURL, long long start, long long end)
132{
133 if (isMainThread())
134 blobRegistry().registerBlobURLForSlice(newURL, srcURL, start, end);
135 else {
136 callOnMainThread([newURL = newURL.isolatedCopy(), srcURL = srcURL.isolatedCopy(), start, end] {
137 blobRegistry().registerBlobURLForSlice(newURL, srcURL, start, end);
138 });
139 }
140}
141
142unsigned long long ThreadableBlobRegistry::blobSize(const URL& url)
143{
144 unsigned long long resultSize;
145 if (isMainThread())
146 resultSize = blobRegistry().blobSize(url);
147 else {
148 BinarySemaphore semaphore;
149 callOnMainThread([url = url.isolatedCopy(), &semaphore, &resultSize] {
150 resultSize = blobRegistry().blobSize(url);
151 semaphore.signal();
152 });
153 semaphore.wait();
154 }
155 return resultSize;
156}
157
158void ThreadableBlobRegistry::unregisterBlobURL(const URL& url)
159{
160 if (BlobURL::getOrigin(url) == "null")
161 originMap()->remove(url.string());
162
163 if (isMainThread())
164 blobRegistry().unregisterBlobURL(url);
165 else {
166 callOnMainThread([url = url.isolatedCopy()] {
167 blobRegistry().unregisterBlobURL(url);
168 });
169 }
170}
171
172RefPtr<SecurityOrigin> ThreadableBlobRegistry::getCachedOrigin(const URL& url)
173{
174 return originMap()->get(url.string());
175}
176
177} // namespace WebCore
178