Skip to content
Permalink
Browse files
Do not route the navigation preload response body to the service work…
…er if we can avoid it

https://bugs.webkit.org/show_bug.cgi?id=241122
rdar://problem/94141714

Patch by Youenn Fablet <youennf@gmail.com> on 2022-06-13
Reviewed by Chris Dumez.

To further optimize navigation preload, we always start the preload as soon as possible.
In addition to that, we no longer pipe the body through the service worker in the common case:
- When the preload receives the response, it sends it to the service worker that will resolve the preload promise.
- The service worker is then expected to synchronously provide it to the FetchEvent.
- If the fetch event gets the preload response and the preload response has not been started to load in the service worker,
  the service worker instructs network process to let the preload directly go to the WebProcess.
- The preload response body might be loaded in the service worker if the response is cloned or if the service worker does not instruct
  the fetch event to use the preload fast enough. We schedule one task for the body to actually be loaded in the service worker.
- Set service worker navigation preload redirection fetchStart based on the navigation preloader start to continue passing
  LayoutTests/imported/w3c/web-platform-tests/service-workers/service-worker/navigation-preload/resource-timing.https.html.

We store the preload response/error in WebServiceWorkerFetchTaskClient as the preload response might be received between the time the fetch event
is received and the time the fetch event is dispatched.

* LayoutTests/http/wpt/service-workers/navigation-optimization-worker.js: Added.
(async doTest):
* LayoutTests/http/wpt/service-workers/navigation-optimization.https-expected.txt: Added.
* LayoutTests/http/wpt/service-workers/navigation-optimization.https.html: Added.
* LayoutTests/http/wpt/service-workers/resources/navigation-optimization.py: Added.
(main):
* LayoutTests/http/wpt/service-workers/resources/service-worker-iframe-preload-script.py:
(main):
* LayoutTests/http/wpt/service-workers/service-worker-iframe-preload.https-expected.txt:
* LayoutTests/http/wpt/service-workers/service-worker-iframe-preload.https.html:
* Source/WebCore/Headers.cmake:
* Source/WebCore/Modules/fetch/FetchResponse.cpp:
(WebCore::FetchResponse::createFetchResponse):
(WebCore::FetchResponse::fetch):
(WebCore::FetchResponse::startLoader):
(WebCore::FetchResponse::setReceivedInternalResponse):
(WebCore::FetchResponse::BodyLoader::didReceiveResponse):
(WebCore::FetchResponse::markAsDisturbed):
* Source/WebCore/Modules/fetch/FetchResponse.h:
* Source/WebCore/WebCore.xcodeproj/project.pbxproj:
* Source/WebCore/bindings/js/JSFetchEventCustom.cpp:
* Source/WebCore/testing/ServiceWorkerInternals.cpp:
* Source/WebCore/workers/service/FetchEvent.cpp:
(WebCore::FetchEvent::preloadResponse):
(WebCore::FetchEvent::navigationPreloadIsReady):
(WebCore::FetchEvent::navigationPreloadFailed):
* Source/WebCore/workers/service/FetchEvent.h:
* Source/WebCore/workers/service/context/ServiceWorkerFetch.cpp:
(WebCore::ServiceWorkerFetch::processResponse):
(WebCore::ServiceWorkerFetch::dispatchFetchEvent):
* Source/WebCore/workers/service/context/ServiceWorkerFetch.h:
* Source/WebCore/workers/service/context/ServiceWorkerThreadProxy.cpp:
(WebCore::ServiceWorkerThreadProxy::navigationPreloadIsReady):
(WebCore::ServiceWorkerThreadProxy::navigationPreloadFailed):
* Source/WebCore/workers/service/context/ServiceWorkerThreadProxy.h:
* Source/WebKit/NetworkProcess/ServiceWorker/ServiceWorkerFetchTask.cpp:
(WebKit::ServiceWorkerFetchTask::ServiceWorkerFetchTask):
(WebKit::ServiceWorkerFetchTask::startFetch):
(WebKit::ServiceWorkerFetchTask::usePreload):
(WebKit::ServiceWorkerFetchTask::loadResponseFromPreloader):
(WebKit::ServiceWorkerFetchTask::preloadResponseIsReady):
* Source/WebKit/NetworkProcess/ServiceWorker/ServiceWorkerFetchTask.h:
* Source/WebKit/NetworkProcess/ServiceWorker/ServiceWorkerFetchTask.messages.in:
* Source/WebKit/NetworkProcess/ServiceWorker/ServiceWorkerNavigationPreloader.cpp:
(WebKit::ServiceWorkerNavigationPreloader::ServiceWorkerNavigationPreloader):
(WebKit::ServiceWorkerNavigationPreloader::didReceiveResponse):
(WebKit::ServiceWorkerNavigationPreloader::waitForResponse):
* Source/WebKit/WebProcess/Storage/WebSWContextManagerConnection.cpp:
(WebKit::WebSWContextManagerConnection::navigationPreloadIsReady):
(WebKit::WebSWContextManagerConnection::navigationPreloadFailed):
* Source/WebKit/WebProcess/Storage/WebSWContextManagerConnection.h:
* Source/WebKit/WebProcess/Storage/WebSWContextManagerConnection.messages.in:
* Source/WebKit/WebProcess/Storage/WebServiceWorkerFetchTaskClient.cpp:
(WebKit::WebServiceWorkerFetchTaskClient::navigationPreloadIsReady):
(WebKit::WebServiceWorkerFetchTaskClient::navigationPreloadFailed):
(WebKit::WebServiceWorkerFetchTaskClient::usePreload):
(WebKit::WebServiceWorkerFetchTaskClient::cleanup):
* Source/WebKit/WebProcess/Storage/WebServiceWorkerFetchTaskClient.h:

Canonical link: https://commits.webkit.org/251493@main
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@295488 268f45cc-cd09-0410-ab3c-d52691b4dbfc
  • Loading branch information
youennf authored and webkit-commit-queue committed Jun 13, 2022
1 parent cea1d90 commit b93bc2b70af6a276b242b1731f0c8f6f15174c20
Show file tree
Hide file tree
Showing 31 changed files with 410 additions and 81 deletions.
@@ -0,0 +1,19 @@
async function doTest(event)
{
if (event.preloadResponse) {
event.respondWith(event.preloadResponse.then((response) => {
if (event.request.url.includes("get-body")) {
const clone = response.clone();
clone.body.getReader();
return response;
}
if (self.internals)
setTimeout(() => internals.terminate(), 0);
return response;
}));
return;
}
event.respondWith(fetch(event.request));
}

self.addEventListener("fetch", doTest);
@@ -0,0 +1,6 @@


PASS Setup worker
PASS Make sure a load that is transferred in network process continues even if service worker gets terminated.
PASS Make sure a load that a preload response can be read right away.

@@ -0,0 +1,49 @@
<html>
<head>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/service-workers/service-worker/resources/test-helpers.sub.js"></script>
</head>
<body>
<script>
promise_test(async (test) => {
const scope = "resources";
const registration = await navigator.serviceWorker.register("navigation-optimization-worker.js", { scope : scope });
activeWorker = registration.active;
if (activeWorker)
return;
activeWorker = registration.installing;
await new Promise(resolve => {
activeWorker.addEventListener('statechange', () => {
if (activeWorker.state === "activated")
resolve();
});
});

await registration.navigationPreload.enable();
}, "Setup worker");

promise_test(async (test) => {
const promise1 = new Promise((resolve, reject) => { window.callback1 = resolve; setTimeout(() => reject("callback1"), 4000); });
const promise2 = new Promise((resolve, reject) => { window.callback2 = resolve; setTimeout(() => reject("callback2"), 5000); });

// The iframe is responsible to call callback1 and callback2.
with_iframe("/WebKit/service-workers/resources/navigation-optimization.py?delay=1.0");

await promise1;
await promise2;
}, "Make sure a load that is transferred in network process continues even if service worker gets terminated.");

promise_test(async (test) => {
const promise1 = new Promise((resolve, reject) => { window.callback1 = resolve; setTimeout(() => reject("callback1"), 4000); });
const promise2 = new Promise((resolve, reject) => { window.callback2 = resolve; setTimeout(() => reject("callback2"), 5000); });

// The iframe is responsible to call callback1 and callback2.
with_iframe("/WebKit/service-workers/resources/navigation-optimization.py?get-body");

await promise1;
await promise2;
}, "Make sure a load that a preload response can be read right away.");
</script>
</body>
</html>
@@ -0,0 +1,14 @@
import time

def main(request, response):
delay = 0.05
headers = []
if b"delay" in request.GET:
delay = float(request.GET.first(b"delay"))
response.headers.set(b"Content-type", b"text/html")
response.headers.append(b"Access-Control-Allow-Origin", b"*")
response.write_status_headers()
response.writer.write_content("<script>parent.callback1();</script>")
time.sleep(delay)
response.writer.write_content("<script>parent.callback2();</script>")
time.sleep(delay)
@@ -17,7 +17,7 @@ def main(request, response):
if not value:
response.headers.set(b"Cache-Control", b"no-cache")
response.headers.set(b"Content-Type", b"text/html")
return "<html><body><script>window.value = 'nothing';</script></body></html>"
return "nothing"

response.headers.set(b"Cache-Control", b"no-cache")
response.headers.set(b"Content-Type", b"text/ascii")
@@ -1,5 +1,5 @@


PASS Setup activating worker
PASS Service worker load uses preload if available and fetch event was not handled
PASS Service worker load uses preload that starts as soon as possible

@@ -64,11 +64,11 @@
activeWorker.postMessage("fetch");

const response = await fetchPromise;
assert_equals(await response.text(), "before-navigation");
assert_equals(await response.text(), "nothing");

const frame = await iframePromise;
assert_equals(frame.contentWindow.value, "nothing");
}, "Service worker load uses preload if available and fetch event was not handled");
assert_equals(frame.contentWindow.document.body.innerText, "before-navigation");
}, "Service worker load uses preload that starts as soon as possible");
</script>
</body>
</html>
@@ -1,3 +1,4 @@
import time
import zlib

def main(request, response):
@@ -164,11 +164,11 @@ set(WebCore_PRIVATE_FRAMEWORK_HEADERS

Modules/fetch/FetchBodyConsumer.h
Modules/fetch/FetchBodySource.h
Modules/fetch/FetchRequestCredentials.h
Modules/fetch/FetchHeaders.h
Modules/fetch/FetchIdentifier.h
Modules/fetch/FetchLoader.h
Modules/fetch/FetchLoaderClient.h
Modules/fetch/FetchRequestCredentials.h

Modules/filesystemaccess/FileSystemDirectoryHandle.h
Modules/filesystemaccess/FileSystemFileHandle.h
@@ -425,6 +425,7 @@ set(WebCore_PRIVATE_FRAMEWORK_HEADERS
bindings/js/BufferSource.h
bindings/js/CachedScriptFetcher.h
bindings/js/CommonVM.h
bindings/js/DOMPromiseProxy.h
bindings/js/DOMWrapperWorld.h
bindings/js/ExceptionDetails.h
bindings/js/GCController.h
@@ -2026,6 +2027,9 @@ set(WebCore_PRIVATE_FRAMEWORK_HEADERS
workers/WorkerThreadType.h
workers/WorkerType.h

workers/service/ExtendableEvent.h
workers/service/ExtendableEventInit.h
workers/service/FetchEvent.h
workers/service/NavigationPreloadState.h
workers/service/SWClientConnection.h
workers/service/ServiceWorkerClientData.h
@@ -235,15 +235,8 @@ void FetchResponse::addAbortSteps(Ref<AbortSignal>&& signal)
});
}

void FetchResponse::fetch(ScriptExecutionContext& context, FetchRequest& request, NotificationCallback&& responseCallback, const String& initiator)
Ref<FetchResponse> FetchResponse::createFetchResponse(ScriptExecutionContext& context, FetchRequest& request, NotificationCallback&& responseCallback)
{
if (request.isReadableStreamBody()) {
responseCallback(Exception { NotSupportedError, "ReadableStream uploading is not supported"_s });
return;
}

InspectorInstrumentation::willFetch(context, request.url().string());

auto response = adoptRef(*new FetchResponse(&context, FetchBody { }, FetchHeaders::create(FetchHeaders::Guard::Immutable), { }));
response->suspendIfNeeded();

@@ -252,8 +245,26 @@ void FetchResponse::fetch(ScriptExecutionContext& context, FetchRequest& request
response->addAbortSteps(request.signal());

response->m_bodyLoader = makeUnique<BodyLoader>(response.get(), WTFMove(responseCallback));
if (!response->m_bodyLoader->start(context, request, initiator))
response->m_bodyLoader = nullptr;
return response;
}

void FetchResponse::fetch(ScriptExecutionContext& context, FetchRequest& request, NotificationCallback&& responseCallback, const String& initiator)
{
if (request.isReadableStreamBody()) {
responseCallback(Exception { NotSupportedError, "ReadableStream uploading is not supported"_s });
return;
}

auto response = createFetchResponse(context, request, WTFMove(responseCallback));
response->startLoader(context, request, initiator);
}

void FetchResponse::startLoader(ScriptExecutionContext& context, FetchRequest& request, const String& initiator)
{
InspectorInstrumentation::willFetch(context, request.url().string());

if (m_bodyLoader && !m_bodyLoader->start(context, request, initiator))
m_bodyLoader = nullptr;
}

const String& FetchResponse::url() const
@@ -322,6 +333,26 @@ void FetchResponse::BodyLoader::didFail(const ResourceError& error)
}
}

static std::atomic<uint64_t> nextOpaqueLoadIdentifier;
void FetchResponse::setReceivedInternalResponse(const ResourceResponse& resourceResponse, FetchOptions::Credentials credentials)
{
if (m_hasInitializedInternalResponse)
return;

m_hasInitializedInternalResponse = true;
auto performCheck = credentials == FetchOptions::Credentials::Include ? ResourceResponse::PerformExposeAllHeadersCheck::No : ResourceResponse::PerformExposeAllHeadersCheck::Yes;
m_filteredResponse = ResourceResponseBase::filter(resourceResponse, performCheck);
m_internalResponse = resourceResponse;
m_internalResponse.setType(m_filteredResponse->type());
if (resourceResponse.tainting() == ResourceResponse::Tainting::Opaque) {
m_opaqueLoadIdentifier = ++nextOpaqueLoadIdentifier;
setBodyAsOpaque();
}

m_headers->filterAndFill(m_filteredResponse->httpHeaderFields(), FetchHeaders::Guard::Response);
updateContentType();
}

FetchResponse::BodyLoader::BodyLoader(FetchResponse& response, NotificationCallback&& responseCallback)
: m_response(response)
, m_responseCallback(WTFMove(responseCallback))
@@ -333,20 +364,9 @@ FetchResponse::BodyLoader::~BodyLoader()
{
}

static uint64_t nextOpaqueLoadIdentifier { 0 };
void FetchResponse::BodyLoader::didReceiveResponse(const ResourceResponse& resourceResponse)
{
auto performCheck = m_credentials == FetchOptions::Credentials::Include ? ResourceResponse::PerformExposeAllHeadersCheck::No : ResourceResponse::PerformExposeAllHeadersCheck::Yes;
m_response.m_filteredResponse = ResourceResponseBase::filter(resourceResponse, performCheck);
m_response.m_internalResponse = resourceResponse;
m_response.m_internalResponse.setType(m_response.m_filteredResponse->type());
if (resourceResponse.tainting() == ResourceResponse::Tainting::Opaque) {
m_response.m_opaqueLoadIdentifier = ++nextOpaqueLoadIdentifier;
m_response.setBodyAsOpaque();
}

m_response.m_headers->filterAndFill(m_response.m_filteredResponse->httpHeaderFields(), FetchHeaders::Guard::Response);
m_response.updateContentType();
m_response.setReceivedInternalResponse(resourceResponse, m_credentials);

if (auto responseCallback = WTFMove(m_responseCallback))
responseCallback(Ref { m_response });
@@ -385,7 +405,16 @@ bool FetchResponse::BodyLoader::start(ScriptExecutionContext& context, const Fet
m_credentials = request.fetchOptions().credentials;
m_loader = makeUnique<FetchLoader>(*this, &m_response.m_body->consumer());
m_loader->start(context, request, initiator);
return m_loader->isStarted();

if (!m_loader->isStarted())
return false;

if (m_shouldStartStreaming) {
auto data = m_loader->startStreaming();
ASSERT_UNUSED(data, !data);
}

return true;
}

void FetchResponse::BodyLoader::stop()
@@ -399,7 +428,7 @@ void FetchResponse::BodyLoader::consumeDataByChunk(ConsumeDataByChunkCallback&&
{
ASSERT(!m_consumeDataCallback);
m_consumeDataCallback = WTFMove(consumeDataCallback);
auto data = m_loader->startStreaming();
auto data = startStreaming();
if (!data)
return;

@@ -421,6 +450,12 @@ FetchResponse::ResponseData FetchResponse::consumeBody()
return body().take();
}

void FetchResponse::markAsDisturbed()
{
ASSERT(!m_isDisturbed);
m_isDisturbed = true;
}

void FetchResponse::consumeBodyReceivedByChunk(ConsumeDataByChunkCallback&& callback)
{
ASSERT(isBodyReceivedByChunk());
@@ -518,7 +553,11 @@ void FetchResponse::feedStream()

RefPtr<FragmentedSharedBuffer> FetchResponse::BodyLoader::startStreaming()
{
ASSERT(m_loader);
if (!m_loader) {
m_shouldStartStreaming = true;
return nullptr;
}

return m_loader->startStreaming();
}

@@ -65,6 +65,7 @@ class FetchResponse final : public FetchBodyOwner {

using NotificationCallback = Function<void(ExceptionOr<Ref<FetchResponse>>&&)>;
static void fetch(ScriptExecutionContext&, FetchRequest&, NotificationCallback&&, const String& initiator);
static Ref<FetchResponse> createFetchResponse(ScriptExecutionContext&, FetchRequest&, NotificationCallback&&);

void startConsumingStream(unsigned);
void consumeChunk(Ref<JSC::Uint8Array>&&);
@@ -113,6 +114,12 @@ class FetchResponse final : public FetchBodyOwner {
bool hasWasmMIMEType() const;

const NetworkLoadMetrics& networkLoadMetrics() const { return m_networkLoadMetrics; }
void setReceivedInternalResponse(const ResourceResponse&, FetchOptions::Credentials);
void startLoader(ScriptExecutionContext&, FetchRequest&, const String& initiator);

void setIsNavigationPreload(bool isNavigationPreload) { m_isNavigationPreload = isNavigationPreload; }
bool isAvailableNavigationPreload() const { return m_isNavigationPreload && m_bodyLoader && !m_bodyLoader->hasLoader() && !hasReadableStreamBody(); }
void markAsDisturbed();

private:
FetchResponse(ScriptExecutionContext*, std::optional<FetchBody>&&, Ref<FetchHeaders>&&, ResourceResponse&&);
@@ -137,6 +144,8 @@ class FetchResponse final : public FetchBodyOwner {

void consumeDataByChunk(ConsumeDataByChunkCallback&&);

bool hasLoader() const { return !!m_loader; }

RefPtr<FragmentedSharedBuffer> startStreaming();
NotificationCallback takeNotificationCallback() { return WTFMove(m_responseCallback); }
ConsumeDataByChunkCallback takeConsumeDataCallback() { return WTFMove(m_consumeDataCallback); }
@@ -154,6 +163,7 @@ class FetchResponse final : public FetchBodyOwner {
std::unique_ptr<FetchLoader> m_loader;
Ref<PendingActivity<FetchResponse>> m_pendingActivity;
FetchOptions::Credentials m_credentials;
bool m_shouldStartStreaming { false };
};

mutable std::optional<ResourceResponse> m_filteredResponse;
@@ -165,6 +175,8 @@ class FetchResponse final : public FetchBodyOwner {
uint64_t m_opaqueLoadIdentifier { 0 };
RefPtr<AbortSignal> m_abortSignal;
NetworkLoadMetrics m_networkLoadMetrics;
bool m_hasInitializedInternalResponse { false };
bool m_isNavigationPreload { false };
};

} // namespace WebCore
@@ -1174,6 +1174,9 @@
4181C64A255B4C2800AEB0FF /* RTCRtpSFrameTransform.h in Headers */ = {isa = PBXBuildFile; fileRef = 4181C644255B4C2700AEB0FF /* RTCRtpSFrameTransform.h */; };
418205471E53E98C00D62207 /* RTCController.h in Headers */ = {isa = PBXBuildFile; fileRef = 418205451E53C8CD00D62207 /* RTCController.h */; settings = {ATTRIBUTES = (Private, ); }; };
4184F5161EAF05A800F18BF0 /* OrientationNotifier.h in Headers */ = {isa = PBXBuildFile; fileRef = 4184F5151EAF059800F18BF0 /* OrientationNotifier.h */; settings = {ATTRIBUTES = (Private, ); }; };
41860F0D2847A49600E4A395 /* FetchEvent.h in Headers */ = {isa = PBXBuildFile; fileRef = 41AF37881F8C1E7900111C31 /* FetchEvent.h */; settings = {ATTRIBUTES = (Private, ); }; };
41860F0E2847A58B00E4A395 /* ExtendableEvent.h in Headers */ = {isa = PBXBuildFile; fileRef = 41AF378A1F8C1E7A00111C31 /* ExtendableEvent.h */; settings = {ATTRIBUTES = (Private, ); }; };
41860F0F2847A5BE00E4A395 /* ExtendableEventInit.h in Headers */ = {isa = PBXBuildFile; fileRef = 4131F3B41F955BC30059995A /* ExtendableEventInit.h */; settings = {ATTRIBUTES = (Private, ); }; };
4186BD3E213EE3400001826F /* LibWebRTCUtils.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 41D1A049213EDDFD0063FB6B /* LibWebRTCUtils.cpp */; };
4186BD3F213EE3430001826F /* LibWebRTCRtpSenderBackend.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 41D1A04B213EDDFE0063FB6B /* LibWebRTCRtpSenderBackend.cpp */; };
4186BD40213EE3450001826F /* LibWebRTCRtpReceiverBackend.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 41D1A04A213EDDFE0063FB6B /* LibWebRTCRtpReceiverBackend.cpp */; };
@@ -2508,7 +2511,7 @@
7C4C96DF1AD4483500363572 /* JSReadableStreamBYOBReader.h in Headers */ = {isa = PBXBuildFile; fileRef = 7C4C96DB1AD4483500363572 /* JSReadableStreamBYOBReader.h */; };
7C4C96DF1AD4483500365A50 /* JSReadableStreamDefaultReader.h in Headers */ = {isa = PBXBuildFile; fileRef = 7C4C96DB1AD4483500365A50 /* JSReadableStreamDefaultReader.h */; };
7C514E0324AF805E0050710F /* ColorConversion.h in Headers */ = {isa = PBXBuildFile; fileRef = 7C514E0024AF80580050710F /* ColorConversion.h */; settings = {ATTRIBUTES = (Private, ); }; };
7C516AD41F3525200034B6BF /* DOMPromiseProxy.h in Headers */ = {isa = PBXBuildFile; fileRef = 7C516AD21F3525200034B6BF /* DOMPromiseProxy.h */; };
7C516AD41F3525200034B6BF /* DOMPromiseProxy.h in Headers */ = {isa = PBXBuildFile; fileRef = 7C516AD21F3525200034B6BF /* DOMPromiseProxy.h */; settings = {ATTRIBUTES = (Private, ); }; };
7C5222961E1DAE03002CB8F7 /* IDLTypes.h in Headers */ = {isa = PBXBuildFile; fileRef = 7C5222951E1DADF8002CB8F7 /* IDLTypes.h */; settings = {ATTRIBUTES = (Private, ); }; };
7C5222991E1DAE1C002CB8F7 /* ActiveDOMCallback.h in Headers */ = {isa = PBXBuildFile; fileRef = 7C5222981E1DAE16002CB8F7 /* ActiveDOMCallback.h */; settings = {ATTRIBUTES = (Private, ); }; };
7C52229E1E1DAE47002CB8F7 /* RuntimeEnabledFeatures.h in Headers */ = {isa = PBXBuildFile; fileRef = 7C52229C1E1DAE47002CB8F7 /* RuntimeEnabledFeatures.h */; settings = {ATTRIBUTES = (Private, ); }; };
@@ -36470,6 +36473,7 @@
BCEA485A097D93020094C9E4 /* LegacyInlineTextBox.h in Headers */,
E4E94D6122FF158A00DD191F /* LegacyLineLayout.h in Headers */,
F44A5F591FED38F2007F5944 /* LegacyNSPasteboardTypes.h in Headers */,
41860F0E2847A58B00E4A395 /* ExtendableEvent.h in Headers */,
A185B42A1E8211A100DC9118 /* LegacyPreviewLoader.h in Headers */,
A10DBF4718F92317000D70C6 /* LegacyPreviewLoaderClient.h in Headers */,
436708C312D9CA4B00044234 /* LegacyRenderSVGContainer.h in Headers */,
@@ -37145,6 +37149,7 @@
550A0BCA085F6039007353D6 /* QualifiedName.h in Headers */,
83C1F5941EDF69D300410D27 /* QualifiedNameCache.h in Headers */,
CD20ED3C27878FFB0038BE44 /* QueuedVideoOutput.h in Headers */,
41860F0F2847A5BE00E4A395 /* ExtendableEventInit.h in Headers */,
A15E31F41E0CB0B5004B371C /* QuickLook.h in Headers */,
9BAEE92C22388A7D004157A9 /* Quirks.h in Headers */,
379E371713736A6600B9E919 /* QuotedPrintable.h in Headers */,
@@ -38166,6 +38171,7 @@
97AABD1714FA09D5007457AE /* ThreadableWebSocketChannel.h in Headers */,
97AABD1914FA09D5007457AE /* ThreadableWebSocketChannelClientWrapper.h in Headers */,
51DF6D7E0B92A16D00C2DC85 /* ThreadCheck.h in Headers */,
41860F0D2847A49600E4A395 /* FetchEvent.h in Headers */,
0F6383DE18615B29003E5DB5 /* ThreadedScrollingTree.h in Headers */,
E1FF57A30F01255B00891EBB /* ThreadGlobalData.h in Headers */,
51D7EFEA1BDE8F8C00E93E10 /* ThreadSafeDataBuffer.h in Headers */,

0 comments on commit b93bc2b

Please sign in to comment.