source: webkit/trunk/Source/WebCore/fileapi/Blob.cpp

Last change on this file was 294978, checked in by Chris Dumez, 3 years ago

Refactor opaque root logic in WebCore in preparation for Node GC optimizations
https://bugs.webkit.org/show_bug.cgi?id=240998

Reviewed by Geoffrey Garen.

Refactor opaque root logic in WebCore in preparation for Node GC optimizations.
Introduce addWebCoreOpaqueRoot() / containsWebCoreOpaqueRoot() functions for
WebCore to deal with opaque roots, instead of interacting with the SlotVisitor
directly. This introduce a nice central point in WebCore where we will be
able to set / check flags on Node to speed up GC.

Also introduce a WebCoreOpaqueRoot type to replace void* as type of opaque
roots in WebCore. This is useful because we will need to know whether an
opaque root in a Node or not in a future patch.

There is no expected behavior change from this patch, this is just pure
refactoring to make it a lot easier for us to optimize Node gargabe collection.

  • Source/WebCore/Modules/fetch/FetchRequest.cpp:

(WebCore::root):

  • Source/WebCore/Modules/fetch/FetchRequest.h:
  • Source/WebCore/Modules/indexeddb/IDBIndex.cpp:

(WebCore::IDBIndex::opaqueRoot):
(WebCore::root):

  • Source/WebCore/Modules/indexeddb/IDBIndex.h:
  • Source/WebCore/Modules/indexeddb/IDBIndex.idl:
  • Source/WebCore/Modules/indexeddb/IDBObjectStore.cpp:

(WebCore::IDBObjectStore::visitReferencedIndexes const):
(WebCore::root):

  • Source/WebCore/Modules/indexeddb/IDBObjectStore.h:
  • Source/WebCore/Modules/indexeddb/IDBRequest.cpp:

(WebCore::root):

  • Source/WebCore/Modules/indexeddb/IDBRequest.h:
  • Source/WebCore/Modules/indexeddb/IDBTransaction.cpp:

(WebCore::IDBTransaction::visitReferencedObjectStores const):

  • Source/WebCore/Modules/mediasource/SourceBuffer.cpp:

(WebCore::SourceBuffer::opaqueRoot):

  • Source/WebCore/Modules/mediasource/SourceBuffer.h:
  • Source/WebCore/Modules/mediasource/SourceBufferList.cpp:

(WebCore::root):

  • Source/WebCore/Modules/mediasource/SourceBufferList.h:
  • Source/WebCore/Modules/remoteplayback/RemotePlayback.cpp:

(WebCore::RemotePlayback::opaqueRootConcurrently const):

  • Source/WebCore/Modules/remoteplayback/RemotePlayback.h:
  • Source/WebCore/Modules/webaudio/AudioBuffer.cpp:

(WebCore::root):

  • Source/WebCore/Modules/webaudio/AudioBuffer.h:
  • Source/WebCore/Modules/webaudio/AudioWorkletGlobalScope.cpp:

(WebCore::AudioWorkletGlobalScope::visitProcessors):

  • Source/WebCore/Modules/webaudio/AudioWorkletProcessor.cpp:

(WebCore::root):

  • Source/WebCore/Modules/webaudio/AudioWorkletProcessor.h:
  • Source/WebCore/Modules/webxr/WebXRSession.cpp:

(WebCore::root):

  • Source/WebCore/Modules/webxr/WebXRSession.h:
  • Source/WebCore/Sources.txt:
  • Source/WebCore/WebCore.xcodeproj/project.pbxproj:
  • Source/WebCore/bindings/js/JSAbortSignalCustom.cpp:

(WebCore::JSAbortSignalOwner::isReachableFromOpaqueRoots):

  • Source/WebCore/bindings/js/JSAttrCustom.cpp:

(WebCore::JSAttr::visitAdditionalChildren):

  • Source/WebCore/bindings/js/JSAudioBufferSourceNodeCustom.cpp:

(WebCore::JSAudioBufferSourceNode::visitAdditionalChildren):

  • Source/WebCore/bindings/js/JSCSSRuleCustom.cpp:

(WebCore::JSCSSRule::visitAdditionalChildren):

  • Source/WebCore/bindings/js/JSCSSRuleCustom.h:

(WebCore::root):

  • Source/WebCore/bindings/js/JSCSSRuleListCustom.cpp:

(WebCore::JSCSSRuleListOwner::isReachableFromOpaqueRoots):

  • Source/WebCore/bindings/js/JSCSSStyleDeclarationCustom.cpp:

(WebCore::root):
(WebCore::JSCSSStyleDeclaration::visitAdditionalChildren):

  • Source/WebCore/bindings/js/JSCSSStyleDeclarationCustom.h:
  • Source/WebCore/bindings/js/JSCanvasRenderingContext2DCustom.cpp:

(WebCore::JSCanvasRenderingContext2DOwner::isReachableFromOpaqueRoots):
(WebCore::JSCanvasRenderingContext2D::visitAdditionalChildren):

  • Source/WebCore/bindings/js/JSDOMQuadCustom.cpp:

(WebCore::JSDOMQuad::visitAdditionalChildren):

  • Source/WebCore/bindings/js/JSDOMWindowCustom.cpp:

(WebCore::JSDOMWindow::visitAdditionalChildren):

  • Source/WebCore/bindings/js/JSDeprecatedCSSOMValueCustom.cpp:

(WebCore::JSDeprecatedCSSOMValueOwner::isReachableFromOpaqueRoots):

  • Source/WebCore/bindings/js/JSDocumentCustom.cpp:

(WebCore::JSDocument::visitAdditionalChildren):

  • Source/WebCore/bindings/js/JSFetchEventCustom.cpp:

(WebCore::JSFetchEvent::visitAdditionalChildren):

  • Source/WebCore/bindings/js/JSHTMLCanvasElementCustom.cpp:

(WebCore::JSHTMLCanvasElement::visitAdditionalChildren):

  • Source/WebCore/bindings/js/JSHTMLTemplateElementCustom.cpp:

(WebCore::JSHTMLTemplateElement::visitAdditionalChildren):

  • Source/WebCore/bindings/js/JSIDBCursorCustom.cpp:

(WebCore::JSIDBCursor::visitAdditionalChildren):

  • Source/WebCore/bindings/js/JSIDBIndexCustom.cpp: Removed.

(WebCore::JSIDBIndex::visitAdditionalChildren): Deleted.

  • Source/WebCore/bindings/js/JSIntersectionObserverCustom.cpp:

(WebCore::JSIntersectionObserver::visitAdditionalChildren):

  • Source/WebCore/bindings/js/JSIntersectionObserverEntryCustom.cpp:

(WebCore::JSIntersectionObserverEntry::visitAdditionalChildren):

  • Source/WebCore/bindings/js/JSMediaListCustom.h:

(WebCore::root):

  • Source/WebCore/bindings/js/JSMessageChannelCustom.cpp:

(WebCore::JSMessageChannel::visitAdditionalChildren):

  • Source/WebCore/bindings/js/JSMessagePortCustom.cpp:

(WebCore::JSMessagePort::visitAdditionalChildren):

  • Source/WebCore/bindings/js/JSNavigatorCustom.cpp:

(WebCore::JSNavigator::visitAdditionalChildren):

  • Source/WebCore/bindings/js/JSNodeCustom.cpp:

(WebCore::JSNodeOwner::isReachableFromOpaqueRoots):
(WebCore::JSNode::visitAdditionalChildren):

  • Source/WebCore/bindings/js/JSNodeCustom.h:

(WebCore::root):

  • Source/WebCore/bindings/js/JSNodeIteratorCustom.cpp:

(WebCore::JSNodeIterator::visitAdditionalChildren):

  • Source/WebCore/bindings/js/JSNodeListCustom.cpp:

(WebCore::JSNodeListOwner::isReachableFromOpaqueRoots):

  • Source/WebCore/bindings/js/JSOffscreenCanvasRenderingContext2DCustom.cpp:

(WebCore::root):
(WebCore::JSOffscreenCanvasRenderingContext2DOwner::isReachableFromOpaqueRoots):
(WebCore::JSOffscreenCanvasRenderingContext2D::visitAdditionalChildren):

  • Source/WebCore/bindings/js/JSPaintRenderingContext2DCustom.cpp:

(WebCore::root):
(WebCore::JSPaintRenderingContext2DOwner::isReachableFromOpaqueRoots):
(WebCore::JSPaintRenderingContext2D::visitAdditionalChildren):

  • Source/WebCore/bindings/js/JSResizeObserverEntryCustom.cpp:

(WebCore::JSResizeObserverEntry::visitAdditionalChildren):

  • Source/WebCore/bindings/js/JSSVGViewSpecCustom.cpp:

(WebCore::JSSVGViewSpec::visitAdditionalChildren):

  • Source/WebCore/bindings/js/JSServiceWorkerGlobalScopeCustom.cpp:

(WebCore::JSServiceWorkerGlobalScope::visitAdditionalChildren):

  • Source/WebCore/bindings/js/JSStyleSheetCustom.cpp:

(WebCore::JSStyleSheet::visitAdditionalChildren):

  • Source/WebCore/bindings/js/JSStyleSheetCustom.h:

(WebCore::root):

  • Source/WebCore/bindings/js/JSTextTrackCueCustom.cpp:

(WebCore::JSTextTrackCueOwner::isReachableFromOpaqueRoots):
(WebCore::JSTextTrackCue::visitAdditionalChildren):

  • Source/WebCore/bindings/js/JSTreeWalkerCustom.cpp:

(WebCore::JSTreeWalker::visitAdditionalChildren):

  • Source/WebCore/bindings/js/JSUndoItemCustom.cpp:

(WebCore::JSUndoItemOwner::isReachableFromOpaqueRoots):

  • Source/WebCore/bindings/js/JSWebGL2RenderingContextCustom.cpp:

(WebCore::JSWebGL2RenderingContext::visitAdditionalChildren):

  • Source/WebCore/bindings/js/JSWebGLRenderingContextCustom.cpp:

(WebCore::JSWebGLRenderingContext::visitAdditionalChildren):

  • Source/WebCore/bindings/js/JSWebXRSessionCustom.cpp:

(WebCore::JSWebXRSession::visitAdditionalChildren):

  • Source/WebCore/bindings/js/JSWorkerGlobalScopeCustom.cpp:

(WebCore::JSWorkerGlobalScope::visitAdditionalChildren):

  • Source/WebCore/bindings/js/JSWorkerNavigatorCustom.cpp:

(WebCore::JSWorkerNavigator::visitAdditionalChildren):

  • Source/WebCore/bindings/js/JSXMLHttpRequestCustom.cpp:

(WebCore::JSXMLHttpRequest::visitAdditionalChildren):

  • Source/WebCore/bindings/js/JSXPathResultCustom.cpp:

(WebCore::JSXPathResult::visitAdditionalChildren):

  • Source/WebCore/bindings/js/WebCoreOpaqueRoot.h: Added.

(WebCore::WebCoreOpaqueRoot::WebCoreOpaqueRoot):
(WebCore::WebCoreOpaqueRoot::isNode const):
(WebCore::WebCoreOpaqueRoot::pointer const):
(WebCore::addWebCoreOpaqueRoot):
(WebCore::containsWebCoreOpaqueRoot):

  • Source/WebCore/bindings/scripts/CodeGeneratorJS.pm:

(GenerateImplementation):

  • Source/WebCore/bindings/scripts/test/JS/JSTestGenerateAddOpaqueRoot.cpp:

(WebCore::JSTestGenerateAddOpaqueRoot::visitChildrenImpl):

  • Source/WebCore/bindings/scripts/test/JS/JSTestGenerateIsReachable.cpp:

(WebCore::JSTestGenerateIsReachableOwner::isReachableFromOpaqueRoots):

  • Source/WebCore/crypto/CryptoKey.cpp:

(WebCore::root):

  • Source/WebCore/crypto/CryptoKey.h:
  • Source/WebCore/dom/AbortController.cpp:

(WebCore::AbortController::opaqueRoot):

  • Source/WebCore/dom/AbortController.h:
  • Source/WebCore/dom/AbortController.idl:
  • Source/WebCore/dom/AbortSignal.cpp:

(WebCore::root):

  • Source/WebCore/dom/AbortSignal.h:
  • Source/WebCore/dom/DOMPointReadOnly.cpp:

(WebCore::root):

  • Source/WebCore/dom/DOMPointReadOnly.h:
  • Source/WebCore/dom/DOMRectReadOnly.cpp:

(WebCore::root):

  • Source/WebCore/dom/DOMRectReadOnly.h:
  • Source/WebCore/dom/DocumentInlines.h:

(WebCore::Node::opaqueRoot const):

  • Source/WebCore/dom/MessagePort.cpp:

(WebCore::root):

  • Source/WebCore/dom/MessagePort.h:
  • Source/WebCore/dom/MutationObserverRegistration.cpp:

(WebCore::MutationObserverRegistration::isReachableFromOpaqueRoots const):

  • Source/WebCore/dom/MutationRecord.cpp:
  • Source/WebCore/dom/Node.cpp:

(WebCore::Node::traverseToOpaqueRoot const):

  • Source/WebCore/dom/Node.h:

(WebCore::Node::opaqueRoot const): Deleted.

  • Source/WebCore/dom/NodeFilter.h:

(WebCore::root):

  • Source/WebCore/dom/Range.cpp:

(WebCore::Range::visitNodesConcurrently const):

  • Source/WebCore/dom/ScriptExecutionContext.cpp:

(WebCore::root):

  • Source/WebCore/dom/ScriptExecutionContext.h:
  • Source/WebCore/dom/StaticRange.cpp:

(WebCore::StaticRange::visitNodesConcurrently const):

  • Source/WebCore/fileapi/Blob.cpp:

(WebCore::root):

  • Source/WebCore/fileapi/Blob.h:
  • Source/WebCore/html/CanvasBase.cpp:

(WebCore::root):

  • Source/WebCore/html/CanvasBase.h:
  • Source/WebCore/html/HTMLCanvasElement.cpp:

(WebCore::root):

  • Source/WebCore/html/HTMLCanvasElement.h:
  • Source/WebCore/html/HTMLMediaElement.h:
  • Source/WebCore/html/canvas/WebGL2RenderingContext.cpp:

(WebCore::WebGL2RenderingContext::addMembersToOpaqueRoots):

  • Source/WebCore/html/canvas/WebGLFramebuffer.cpp:
  • Source/WebCore/html/canvas/WebGLObject.cpp:

(WebCore::root):

  • Source/WebCore/html/canvas/WebGLObject.h:
  • Source/WebCore/html/canvas/WebGLProgram.cpp:

(WebCore::WebGLProgram::addMembersToOpaqueRoots):

  • Source/WebCore/html/canvas/WebGLRenderingContextBase.cpp:

(WebCore::WebGLRenderingContextBase::addMembersToOpaqueRoots):
(WebCore::root):

  • Source/WebCore/html/canvas/WebGLRenderingContextBase.h:
  • Source/WebCore/html/canvas/WebGLTransformFeedback.cpp:

(WebCore::WebGLTransformFeedback::addMembersToOpaqueRoots):

  • Source/WebCore/html/canvas/WebGLVertexArrayObjectBase.cpp:

(WebCore::WebGLVertexArrayObjectBase::addMembersToOpaqueRoots):
(WebCore::root):

  • Source/WebCore/html/canvas/WebGLVertexArrayObjectBase.h:
  • Source/WebCore/html/track/TrackBase.cpp:

(WebCore::TrackBase::opaqueRoot):

  • Source/WebCore/html/track/TrackBase.h:

(WebCore::root):

  • Source/WebCore/html/track/TrackListBase.cpp:

(WebCore::TrackListBase::opaqueRoot):

  • Source/WebCore/html/track/TrackListBase.h:

(WebCore::root):

  • Source/WebCore/page/DOMWindow.cpp:

(WebCore::root):

  • Source/WebCore/page/DOMWindow.h:
  • Source/WebCore/page/IntersectionObserver.cpp:

(WebCore::IntersectionObserver::isReachableFromOpaqueRoots const):

  • Source/WebCore/page/NavigatorBase.cpp:

(WebCore::root):

  • Source/WebCore/page/NavigatorBase.h:
  • Source/WebCore/page/ResizeObserver.cpp:

(WebCore::ResizeObserver::isReachableFromOpaqueRoots const):

  • Source/WebCore/workers/WorkerLocation.cpp:

(WebCore::root):

  • Source/WebCore/workers/WorkerLocation.h:

(WebCore::WorkerLocation::create):
(WebCore::WorkerLocation::url const):
(WebCore::WorkerLocation::WorkerLocation):

  • Source/WebCore/workers/service/ServiceWorkerClients.cpp:

(WebCore::root):

  • Source/WebCore/workers/service/ServiceWorkerClients.h:
  • Source/WebCore/workers/service/ServiceWorkerRegistration.cpp:

(WebCore::root):

  • Source/WebCore/workers/service/ServiceWorkerRegistration.h:
  • Source/WebCore/xml/XMLHttpRequestUpload.cpp:

(WebCore::root):

  • Source/WebCore/xml/XMLHttpRequestUpload.h:

Canonical link: https://commits.webkit.org/251082@main

  • Property svn:eol-style set to native
File size: 11.6 KB
Line 
1/*
2 * Copyright (C) 2010 Google Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
6 * met:
7 *
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above
11 * copyright notice, this list of conditions and the following disclaimer
12 * in the documentation and/or other materials provided with the
13 * distribution.
14 * * Neither the name of Google Inc. nor the names of its
15 * contributors may be used to endorse or promote products derived from
16 * this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31#include "config.h"
32#include "Blob.h"
33
34#include "BlobBuilder.h"
35#include "BlobLoader.h"
36#include "BlobPart.h"
37#include "BlobURL.h"
38#include "File.h"
39#include "JSDOMPromiseDeferred.h"
40#include "PolicyContainer.h"
41#include "ReadableStream.h"
42#include "ReadableStreamSource.h"
43#include "ScriptExecutionContext.h"
44#include "SharedBuffer.h"
45#include "ThreadableBlobRegistry.h"
46#include "WebCoreOpaqueRoot.h"
47#include <wtf/IsoMallocInlines.h>
48#include <wtf/NeverDestroyed.h>
49#include <wtf/ThreadSafeRefCounted.h>
50#include <wtf/text/CString.h>
51
52namespace WebCore {
53
54WTF_MAKE_ISO_ALLOCATED_IMPL(Blob);
55
56class BlobURLRegistry final : public URLRegistry {
57public:
58 void registerURL(ScriptExecutionContext&, const URL&, URLRegistrable&) final;
59 void unregisterURL(const URL&) final;
60
61 static URLRegistry& registry();
62};
63
64void BlobURLRegistry::registerURL(ScriptExecutionContext& context, const URL& publicURL, URLRegistrable& blob)
65{
66 ASSERT(&blob.registry() == this);
67 ThreadableBlobRegistry::registerBlobURL(context.securityOrigin(), context.policyContainer(), publicURL, static_cast<Blob&>(blob).url());
68}
69
70void BlobURLRegistry::unregisterURL(const URL& url)
71{
72 ThreadableBlobRegistry::unregisterBlobURL(url);
73}
74
75URLRegistry& BlobURLRegistry::registry()
76{
77 static NeverDestroyed<BlobURLRegistry> instance;
78 return instance;
79}
80
81Blob::Blob(UninitializedContructor, ScriptExecutionContext* context, URL&& url, String&& type)
82 : ActiveDOMObject(context)
83 , m_type(WTFMove(type))
84 , m_internalURL(WTFMove(url))
85{
86}
87
88Blob::Blob(ScriptExecutionContext* context)
89 : ActiveDOMObject(context)
90 , m_size(0)
91 , m_internalURL(BlobURL::createInternalURL())
92{
93 ThreadableBlobRegistry::registerBlobURL(m_internalURL, { }, { });
94}
95
96static Vector<BlobPart> buildBlobData(Vector<BlobPartVariant>&& blobPartVariants, const BlobPropertyBag& propertyBag)
97{
98 BlobBuilder builder(propertyBag.endings);
99 for (auto& blobPartVariant : blobPartVariants) {
100 WTF::switchOn(blobPartVariant,
101 [&] (auto& part) {
102 builder.append(WTFMove(part));
103 }
104 );
105 }
106 return builder.finalize();
107}
108
109Blob::Blob(ScriptExecutionContext& context, Vector<BlobPartVariant>&& blobPartVariants, const BlobPropertyBag& propertyBag)
110 : ActiveDOMObject(&context)
111 , m_type(normalizedContentType(propertyBag.type))
112 , m_internalURL(BlobURL::createInternalURL())
113{
114 ThreadableBlobRegistry::registerBlobURL(m_internalURL, buildBlobData(WTFMove(blobPartVariants), propertyBag), m_type);
115}
116
117Blob::Blob(ScriptExecutionContext* context, Vector<uint8_t>&& data, const String& contentType)
118 : ActiveDOMObject(context)
119 , m_type(contentType)
120 , m_size(data.size())
121 , m_internalURL(BlobURL::createInternalURL())
122{
123 ThreadableBlobRegistry::registerBlobURL(m_internalURL, { BlobPart(WTFMove(data)) }, contentType);
124}
125
126Blob::Blob(ReferencingExistingBlobConstructor, ScriptExecutionContext* context, const Blob& blob)
127 : ActiveDOMObject(context)
128 , m_type(blob.type())
129 , m_size(blob.size())
130 , m_internalURL(BlobURL::createInternalURL())
131{
132 ThreadableBlobRegistry::registerBlobURL(m_internalURL, { BlobPart(blob.url()) } , m_type);
133}
134
135Blob::Blob(DeserializationContructor, ScriptExecutionContext* context, const URL& srcURL, const String& type, std::optional<unsigned long long> size, const String& fileBackedPath)
136 : ActiveDOMObject(context)
137 , m_type(normalizedContentType(type))
138 , m_size(size)
139 , m_internalURL(BlobURL::createInternalURL())
140{
141 if (fileBackedPath.isEmpty())
142 ThreadableBlobRegistry::registerBlobURL(nullptr, { }, m_internalURL, srcURL);
143 else
144 ThreadableBlobRegistry::registerBlobURLOptionallyFileBacked(m_internalURL, srcURL, fileBackedPath, m_type);
145}
146
147Blob::Blob(ScriptExecutionContext* context, const URL& srcURL, long long start, long long end, const String& type)
148 : ActiveDOMObject(context)
149 , m_type(normalizedContentType(type))
150 , m_internalURL(BlobURL::createInternalURL())
151 // m_size is not necessarily equal to end - start so we do not initialize it here.
152{
153 ThreadableBlobRegistry::registerBlobURLForSlice(m_internalURL, srcURL, start, end, m_type);
154}
155
156Blob::~Blob()
157{
158 ThreadableBlobRegistry::unregisterBlobURL(m_internalURL);
159 while (!m_blobLoaders.isEmpty())
160 (*m_blobLoaders.begin())->cancel();
161}
162
163Ref<Blob> Blob::slice(long long start, long long end, const String& contentType) const
164{
165 auto blob = adoptRef(*new Blob(scriptExecutionContext(), m_internalURL, start, end, contentType));
166 blob->suspendIfNeeded();
167 return blob;
168}
169
170unsigned long long Blob::size() const
171{
172 if (!m_size) {
173 // FIXME: JavaScript cannot represent sizes as large as unsigned long long, we need to
174 // come up with an exception to throw if file size is not representable.
175 unsigned long long actualSize = ThreadableBlobRegistry::blobSize(m_internalURL);
176 m_size = isInBounds<long long>(actualSize) ? actualSize : 0;
177 }
178
179 return *m_size;
180}
181
182bool Blob::isValidContentType(const String& contentType)
183{
184 // FIXME: Do we really want to treat the empty string and null string as valid content types?
185 unsigned length = contentType.length();
186 for (unsigned i = 0; i < length; ++i) {
187 if (contentType[i] < 0x20 || contentType[i] > 0x7e)
188 return false;
189 }
190 return true;
191}
192
193String Blob::normalizedContentType(const String& contentType)
194{
195 if (!isValidContentType(contentType))
196 return emptyString();
197 return contentType.convertToASCIILowercase();
198}
199
200void Blob::loadBlob(FileReaderLoader::ReadType readType, CompletionHandler<void(BlobLoader&)>&& completionHandler)
201{
202 auto blobLoader = makeUnique<BlobLoader>([this, pendingActivity = makePendingActivity(*this), completionHandler = WTFMove(completionHandler)](BlobLoader& blobLoader) mutable {
203 completionHandler(blobLoader);
204 m_blobLoaders.take(&blobLoader);
205 });
206
207 blobLoader->start(*this, scriptExecutionContext(), readType);
208
209 if (blobLoader->isLoading())
210 m_blobLoaders.add(WTFMove(blobLoader));
211}
212
213void Blob::text(Ref<DeferredPromise>&& promise)
214{
215 loadBlob(FileReaderLoader::ReadAsText, [promise = WTFMove(promise)](BlobLoader& blobLoader) mutable {
216 if (auto optionalErrorCode = blobLoader.errorCode()) {
217 promise->reject(Exception { *optionalErrorCode });
218 return;
219 }
220 promise->resolve<IDLDOMString>(blobLoader.stringResult());
221 });
222}
223
224void Blob::arrayBuffer(Ref<DeferredPromise>&& promise)
225{
226 loadBlob(FileReaderLoader::ReadAsArrayBuffer, [promise = WTFMove(promise)](BlobLoader& blobLoader) mutable {
227 if (auto optionalErrorCode = blobLoader.errorCode()) {
228 promise->reject(Exception { *optionalErrorCode });
229 return;
230 }
231 auto arrayBuffer = blobLoader.arrayBufferResult();
232 if (!arrayBuffer) {
233 promise->reject(Exception { InvalidStateError });
234 return;
235 }
236 promise->resolve<IDLArrayBuffer>(*arrayBuffer);
237 });
238}
239
240ExceptionOr<Ref<ReadableStream>> Blob::stream()
241{
242 class BlobStreamSource : public FileReaderLoaderClient, public ReadableStreamSource {
243 public:
244 BlobStreamSource(ScriptExecutionContext& scriptExecutionContext, Blob& blob)
245 : m_loader(makeUniqueRef<FileReaderLoader>(FileReaderLoader::ReadType::ReadAsBinaryChunks, this))
246 {
247 m_loader->start(&scriptExecutionContext, blob);
248 }
249
250 private:
251 // ReadableStreamSource
252 void setActive() final { }
253 void setInactive() final { }
254 void doStart() final
255 {
256 m_isStarted = true;
257 if (m_exception)
258 controller().error(*m_exception);
259 }
260
261 void doPull() final { }
262 void doCancel() final
263 {
264 m_loader->cancel();
265 }
266
267 // FileReaderLoaderClient
268 void didStartLoading() final { }
269 void didReceiveData() final { }
270 void didReceiveBinaryChunk(const SharedBuffer& buffer) final
271 {
272 if (!controller().enqueue(buffer.tryCreateArrayBuffer()))
273 doCancel();
274 }
275 void didFinishLoading() final
276 {
277 controller().close();
278 }
279 void didFail(ExceptionCode code) final
280 {
281 Exception exception { code };
282 if (!m_isStarted) {
283 m_exception = WTFMove(exception);
284 return;
285 }
286 controller().error(exception);
287 }
288
289 UniqueRef<FileReaderLoader> m_loader;
290 bool m_isStarted { false };
291 std::optional<Exception> m_exception;
292 };
293
294 auto* context = scriptExecutionContext();
295 auto* globalObject = context ? context->globalObject() : nullptr;
296 if (!globalObject)
297 return Exception { InvalidStateError };
298 return ReadableStream::create(*globalObject, adoptRef(*new BlobStreamSource(*context, *this)));
299}
300
301#if ASSERT_ENABLED
302bool Blob::isNormalizedContentType(const String& contentType)
303{
304 // FIXME: Do we really want to treat the empty string and null string as valid content types?
305 unsigned length = contentType.length();
306 for (size_t i = 0; i < length; ++i) {
307 if (contentType[i] < 0x20 || contentType[i] > 0x7e)
308 return false;
309 if (isASCIIUpper(contentType[i]))
310 return false;
311 }
312 return true;
313}
314
315bool Blob::isNormalizedContentType(const CString& contentType)
316{
317 // FIXME: Do we really want to treat the empty string and null string as valid content types?
318 size_t length = contentType.length();
319 const char* characters = contentType.data();
320 for (size_t i = 0; i < length; ++i) {
321 if (characters[i] < 0x20 || characters[i] > 0x7e)
322 return false;
323 if (isASCIIUpper(characters[i]))
324 return false;
325 }
326 return true;
327}
328#endif // ASSERT_ENABLED
329
330URLRegistry& Blob::registry() const
331{
332 return BlobURLRegistry::registry();
333}
334
335const char* Blob::activeDOMObjectName() const
336{
337 return "Blob";
338}
339
340BlobURLHandle Blob::handle() const
341{
342 return BlobURLHandle { m_internalURL };
343}
344
345WebCoreOpaqueRoot root(Blob* blob)
346{
347 return WebCoreOpaqueRoot { blob };
348}
349
350} // namespace WebCore
Note: See TracBrowser for help on using the repository browser.