Title: [282574] branches/safari-612-branch/Source/WebKit
Revision
282574
Author
[email protected]
Date
2021-09-16 11:48:27 -0700 (Thu, 16 Sep 2021)

Log Message

Cherry-pick r282252. rdar://problem/83184010

    Preconnected socket is sometimes not used for initial request
    https://bugs.webkit.org/show_bug.cgi?id=229686

    Reviewed by Alex Christensen.

    In the previous release, we preconnected to the main resource origin early in page load from
    UIProcess to save ~10-15 ms per page load (https://bugs.webkit.org/show_bug.cgi?id=204992).
    The savings comes from the fact that there's some latency in initiating the request in
    WebProcess and waiting for the nav delegate reply in UIProcess. We hide that latency by
    having the eventual main resource request reuse the early preconnected socket.

    However, this optimization doesn't work for connections to known HTTP/1.1 origins due to
    CFNetwork's in-memory cache of known HTTP/1.1 origins. If an origin is in this cache, and
    a preconnect is still in flight, then the network stack will go wide immediately and issue
    the main resource request on a new socket rather than trying to wait for the preconnect to
    finish and reuse the preconnected socket. Thus the preconneted socket just goes to waste.
    This can also cause issues with single-threaded web servers that serve only one request at
    a time, as the main resource request can get head-of-line blocked by the preconnect that
    is wasted.

    To work around this, this patch tracks a small number of known HTTP/1.1 origins in memory.
    If there is a pending preconnect to an HTTP/1.1 origin and a main resource request to that
    origin comes in, then we block the request from going out until the preconnect finishes.
    This allows the main resource request to utilize the preconnected socket.

    This is worth ~1.25%-2.5% on PLT5 depending on device.

    * NetworkProcess/NetworkLoad.cpp:
    (WebKit::NetworkLoad::didCompleteWithError):
    * NetworkProcess/NetworkLoadScheduler.cpp:
    (WebKit::NetworkLoadScheduler::schedule):
    (WebKit::NetworkLoadScheduler::unschedule):
    (WebKit::NetworkLoadScheduler::scheduleLoad):
    (WebKit::NetworkLoadScheduler::unscheduleLoad):
    (WebKit::NetworkLoadScheduler::scheduleMainResourceLoad):
    (WebKit::NetworkLoadScheduler::unscheduleMainResourceLoad):
    (WebKit::NetworkLoadScheduler::startedPreconnectForMainResource):
    (WebKit::NetworkLoadScheduler::finishedPreconnectForMainResource):
    (WebKit::NetworkLoadScheduler::maybePrunePreconnectInfo):
    (WebKit::NetworkLoadScheduler::isOriginHTTP1X):
    (WebKit::NetworkLoadScheduler::updateOriginProtocolInfo):
    * NetworkProcess/NetworkLoadScheduler.h:
    * NetworkProcess/NetworkProcess.cpp:
    (WebKit::NetworkProcess::preconnectTo):
    * NetworkProcess/PreconnectTask.cpp:
    (WebKit::PreconnectTask::PreconnectTask):
    (WebKit::PreconnectTask::setTimeout):
    (WebKit::PreconnectTask::start):
    * NetworkProcess/PreconnectTask.h:

    git-svn-id: https://svn.webkit.org/repository/webkit/trunk@282252 268f45cc-cd09-0410-ab3c-d52691b4dbfc

Modified Paths

Diff

Modified: branches/safari-612-branch/Source/WebKit/ChangeLog (282573 => 282574)


--- branches/safari-612-branch/Source/WebKit/ChangeLog	2021-09-16 18:48:24 UTC (rev 282573)
+++ branches/safari-612-branch/Source/WebKit/ChangeLog	2021-09-16 18:48:27 UTC (rev 282574)
@@ -1,3 +1,112 @@
+2021-09-16  Russell Epstein  <[email protected]>
+
+        Cherry-pick r282252. rdar://problem/83184010
+
+    Preconnected socket is sometimes not used for initial request
+    https://bugs.webkit.org/show_bug.cgi?id=229686
+    
+    Reviewed by Alex Christensen.
+    
+    In the previous release, we preconnected to the main resource origin early in page load from
+    UIProcess to save ~10-15 ms per page load (https://bugs.webkit.org/show_bug.cgi?id=204992).
+    The savings comes from the fact that there's some latency in initiating the request in
+    WebProcess and waiting for the nav delegate reply in UIProcess. We hide that latency by
+    having the eventual main resource request reuse the early preconnected socket.
+    
+    However, this optimization doesn't work for connections to known HTTP/1.1 origins due to
+    CFNetwork's in-memory cache of known HTTP/1.1 origins. If an origin is in this cache, and
+    a preconnect is still in flight, then the network stack will go wide immediately and issue
+    the main resource request on a new socket rather than trying to wait for the preconnect to
+    finish and reuse the preconnected socket. Thus the preconneted socket just goes to waste.
+    This can also cause issues with single-threaded web servers that serve only one request at
+    a time, as the main resource request can get head-of-line blocked by the preconnect that
+    is wasted.
+    
+    To work around this, this patch tracks a small number of known HTTP/1.1 origins in memory.
+    If there is a pending preconnect to an HTTP/1.1 origin and a main resource request to that
+    origin comes in, then we block the request from going out until the preconnect finishes.
+    This allows the main resource request to utilize the preconnected socket.
+    
+    This is worth ~1.25%-2.5% on PLT5 depending on device.
+    
+    * NetworkProcess/NetworkLoad.cpp:
+    (WebKit::NetworkLoad::didCompleteWithError):
+    * NetworkProcess/NetworkLoadScheduler.cpp:
+    (WebKit::NetworkLoadScheduler::schedule):
+    (WebKit::NetworkLoadScheduler::unschedule):
+    (WebKit::NetworkLoadScheduler::scheduleLoad):
+    (WebKit::NetworkLoadScheduler::unscheduleLoad):
+    (WebKit::NetworkLoadScheduler::scheduleMainResourceLoad):
+    (WebKit::NetworkLoadScheduler::unscheduleMainResourceLoad):
+    (WebKit::NetworkLoadScheduler::startedPreconnectForMainResource):
+    (WebKit::NetworkLoadScheduler::finishedPreconnectForMainResource):
+    (WebKit::NetworkLoadScheduler::maybePrunePreconnectInfo):
+    (WebKit::NetworkLoadScheduler::isOriginHTTP1X):
+    (WebKit::NetworkLoadScheduler::updateOriginProtocolInfo):
+    * NetworkProcess/NetworkLoadScheduler.h:
+    * NetworkProcess/NetworkProcess.cpp:
+    (WebKit::NetworkProcess::preconnectTo):
+    * NetworkProcess/PreconnectTask.cpp:
+    (WebKit::PreconnectTask::PreconnectTask):
+    (WebKit::PreconnectTask::setTimeout):
+    (WebKit::PreconnectTask::start):
+    * NetworkProcess/PreconnectTask.h:
+    
+    
+    git-svn-id: https://svn.webkit.org/repository/webkit/trunk@282252 268f45cc-cd09-0410-ab3c-d52691b4dbfc
+
+    2021-09-09  Ben Nham  <[email protected]>
+
+            Preconnected socket is sometimes not used for initial request
+            https://bugs.webkit.org/show_bug.cgi?id=229686
+
+            Reviewed by Alex Christensen.
+
+            In the previous release, we preconnected to the main resource origin early in page load from
+            UIProcess to save ~10-15 ms per page load (https://bugs.webkit.org/show_bug.cgi?id=204992).
+            The savings comes from the fact that there's some latency in initiating the request in
+            WebProcess and waiting for the nav delegate reply in UIProcess. We hide that latency by
+            having the eventual main resource request reuse the early preconnected socket.
+
+            However, this optimization doesn't work for connections to known HTTP/1.1 origins due to
+            CFNetwork's in-memory cache of known HTTP/1.1 origins. If an origin is in this cache, and
+            a preconnect is still in flight, then the network stack will go wide immediately and issue
+            the main resource request on a new socket rather than trying to wait for the preconnect to
+            finish and reuse the preconnected socket. Thus the preconneted socket just goes to waste.
+            This can also cause issues with single-threaded web servers that serve only one request at
+            a time, as the main resource request can get head-of-line blocked by the preconnect that
+            is wasted.
+
+            To work around this, this patch tracks a small number of known HTTP/1.1 origins in memory.
+            If there is a pending preconnect to an HTTP/1.1 origin and a main resource request to that
+            origin comes in, then we block the request from going out until the preconnect finishes.
+            This allows the main resource request to utilize the preconnected socket.
+
+            This is worth ~1.25%-2.5% on PLT5 depending on device.
+
+            * NetworkProcess/NetworkLoad.cpp:
+            (WebKit::NetworkLoad::didCompleteWithError):
+            * NetworkProcess/NetworkLoadScheduler.cpp:
+            (WebKit::NetworkLoadScheduler::schedule):
+            (WebKit::NetworkLoadScheduler::unschedule):
+            (WebKit::NetworkLoadScheduler::scheduleLoad):
+            (WebKit::NetworkLoadScheduler::unscheduleLoad):
+            (WebKit::NetworkLoadScheduler::scheduleMainResourceLoad):
+            (WebKit::NetworkLoadScheduler::unscheduleMainResourceLoad):
+            (WebKit::NetworkLoadScheduler::startedPreconnectForMainResource):
+            (WebKit::NetworkLoadScheduler::finishedPreconnectForMainResource):
+            (WebKit::NetworkLoadScheduler::maybePrunePreconnectInfo):
+            (WebKit::NetworkLoadScheduler::isOriginHTTP1X):
+            (WebKit::NetworkLoadScheduler::updateOriginProtocolInfo):
+            * NetworkProcess/NetworkLoadScheduler.h:
+            * NetworkProcess/NetworkProcess.cpp:
+            (WebKit::NetworkProcess::preconnectTo):
+            * NetworkProcess/PreconnectTask.cpp:
+            (WebKit::PreconnectTask::PreconnectTask):
+            (WebKit::PreconnectTask::setTimeout):
+            (WebKit::PreconnectTask::start):
+            * NetworkProcess/PreconnectTask.h:
+
 2021-09-09  Russell Epstein  <[email protected]>
 
         Cherry-pick r281792. rdar://problem/82949614

Modified: branches/safari-612-branch/Source/WebKit/NetworkProcess/NetworkLoad.cpp (282573 => 282574)


--- branches/safari-612-branch/Source/WebKit/NetworkProcess/NetworkLoad.cpp	2021-09-16 18:48:24 UTC (rev 282573)
+++ branches/safari-612-branch/Source/WebKit/NetworkProcess/NetworkLoad.cpp	2021-09-16 18:48:27 UTC (rev 282574)
@@ -245,7 +245,7 @@
 void NetworkLoad::didCompleteWithError(const ResourceError& error, const WebCore::NetworkLoadMetrics& networkLoadMetrics)
 {
     if (m_scheduler) {
-        m_scheduler->unschedule(*this);
+        m_scheduler->unschedule(*this, &networkLoadMetrics);
         m_scheduler = nullptr;
     }
 

Modified: branches/safari-612-branch/Source/WebKit/NetworkProcess/NetworkLoadScheduler.cpp (282573 => 282574)


--- branches/safari-612-branch/Source/WebKit/NetworkProcess/NetworkLoadScheduler.cpp	2021-09-16 18:48:24 UTC (rev 282573)
+++ branches/safari-612-branch/Source/WebKit/NetworkProcess/NetworkLoadScheduler.cpp	2021-09-16 18:48:27 UTC (rev 282574)
@@ -26,12 +26,14 @@
 #include "config.h"
 #include "NetworkLoadScheduler.h"
 
+#include "Logging.h"
 #include "NetworkLoad.h"
-#include <wtf/ListHashSet.h>
+#include <WebCore/ResourceError.h>
 
 namespace WebKit {
 
 static constexpr size_t maximumActiveCountForLowPriority = 2;
+static constexpr size_t maximumTrackedHTTP1XOrigins = 128;
 
 class NetworkLoadScheduler::HostContext {
     WTF_MAKE_FAST_ALLOCATED;
@@ -117,6 +119,24 @@
 
 void NetworkLoadScheduler::schedule(NetworkLoad& load)
 {
+    bool isMainFrameMainResource = load.currentRequest().isTopSite();
+    if (isMainFrameMainResource)
+        scheduleMainResourceLoad(load);
+    else
+        scheduleLoad(load);
+}
+
+void NetworkLoadScheduler::unschedule(NetworkLoad& load, const WebCore::NetworkLoadMetrics* metrics)
+{
+    bool isMainFrameMainResource = load.currentRequest().isTopSite();
+    if (isMainFrameMainResource)
+        unscheduleMainResourceLoad(load, metrics);
+    else
+        unscheduleLoad(load);
+}
+
+void NetworkLoadScheduler::scheduleLoad(NetworkLoad& load)
+{
     auto* context = contextForLoad(load);
 
     if (!context) {
@@ -127,12 +147,109 @@
     context->schedule(load);
 }
 
-void NetworkLoadScheduler::unschedule(NetworkLoad& load)
+void NetworkLoadScheduler::unscheduleLoad(NetworkLoad& load)
 {
     if (auto* context = contextForLoad(load))
         context->unschedule(load);
 }
 
+void NetworkLoadScheduler::scheduleMainResourceLoad(NetworkLoad& load)
+{
+    String protocolHostAndPort = load.url().protocolHostAndPort();
+    if (!isOriginHTTP1X(protocolHostAndPort)) {
+        load.start();
+        return;
+    }
+
+    auto iter = m_pendingMainResourcePreconnects.find(protocolHostAndPort);
+    if (iter == m_pendingMainResourcePreconnects.end()) {
+        load.start();
+        return;
+    }
+
+    PendingMainResourcePreconnectInfo& info = iter->value;
+    if (!info.pendingPreconnects) {
+        load.start();
+        return;
+    }
+
+    --info.pendingPreconnects;
+    info.pendingLoads.add(&load);
+    RELEASE_LOG(Network, "%p - NetworkLoadScheduler::scheduleMainResourceLoad deferring load %p; %u pending preconnects; %u pending loads", this, &load, info.pendingPreconnects, info.pendingLoads.size());
+}
+
+void NetworkLoadScheduler::unscheduleMainResourceLoad(NetworkLoad& load, const WebCore::NetworkLoadMetrics* metrics)
+{
+    String protocolHostAndPort = load.url().protocolHostAndPort();
+
+    if (metrics)
+        updateOriginProtocolInfo(protocolHostAndPort, metrics->protocol);
+
+    auto iter = m_pendingMainResourcePreconnects.find(protocolHostAndPort);
+    if (iter == m_pendingMainResourcePreconnects.end())
+        return;
+
+    PendingMainResourcePreconnectInfo& info = iter->value;
+    if (info.pendingLoads.remove(&load))
+        maybePrunePreconnectInfo(iter);
+}
+
+void NetworkLoadScheduler::startedPreconnectForMainResource(const URL& url)
+{
+    auto iter = m_pendingMainResourcePreconnects.find(url.protocolHostAndPort());
+    if (iter != m_pendingMainResourcePreconnects.end()) {
+        PendingMainResourcePreconnectInfo& info = iter->value;
+        info.pendingPreconnects++;
+        return;
+    }
+
+    PendingMainResourcePreconnectInfo info;
+    m_pendingMainResourcePreconnects.add(url.protocolHostAndPort(), WTFMove(info));
+}
+
+void NetworkLoadScheduler::finishedPreconnectForMainResource(const URL& url, const WebCore::ResourceError& error)
+{
+    auto iter = m_pendingMainResourcePreconnects.find(url.protocolHostAndPort());
+    if (iter == m_pendingMainResourcePreconnects.end())
+        return;
+
+    PendingMainResourcePreconnectInfo& info = iter->value;
+    if (!info.pendingLoads.isEmpty()) {
+        NetworkLoad* load = info.pendingLoads.takeFirst();
+        RELEASE_LOG(Network, "%p - NetworkLoadScheduler::finishedPreconnectForMainResource (error: %d) starting delayed main resource load %p; %u pending preconnects; %u total pending loads", this, static_cast<int>(error.type()), load, info.pendingPreconnects, info.pendingLoads.size());
+        load->start();
+    } else
+        --info.pendingPreconnects;
+
+    maybePrunePreconnectInfo(iter);
+}
+
+void NetworkLoadScheduler::maybePrunePreconnectInfo(PendingPreconnectMap::iterator& iter)
+{
+    PendingMainResourcePreconnectInfo& info = iter->value;
+    if (!info.pendingPreconnects && info.pendingLoads.isEmpty())
+        m_pendingMainResourcePreconnects.remove(iter);
+}
+
+
+bool NetworkLoadScheduler::isOriginHTTP1X(const String& protocolHostAndPort)
+{
+    return m_http1XOrigins.contains(protocolHostAndPort);
+}
+
+void NetworkLoadScheduler::updateOriginProtocolInfo(const String& protocolHostAndPort, const String& alpnProtocolID)
+{
+    if (alpnProtocolID != "http/1.1"_s) {
+        m_http1XOrigins.remove(protocolHostAndPort);
+        return;
+    }
+
+    if (m_http1XOrigins.size() >= maximumTrackedHTTP1XOrigins)
+        m_http1XOrigins.remove(m_http1XOrigins.random());
+
+    m_http1XOrigins.add(protocolHostAndPort);
+}
+
 void NetworkLoadScheduler::setResourceLoadSchedulingMode(WebCore::PageIdentifier pageIdentifier, WebCore::LoadSchedulingMode mode)
 {
     switch (mode) {

Modified: branches/safari-612-branch/Source/WebKit/NetworkProcess/NetworkLoadScheduler.h (282573 => 282574)


--- branches/safari-612-branch/Source/WebKit/NetworkProcess/NetworkLoadScheduler.h	2021-09-16 18:48:24 UTC (rev 282573)
+++ branches/safari-612-branch/Source/WebKit/NetworkProcess/NetworkLoadScheduler.h	2021-09-16 18:48:27 UTC (rev 282574)
@@ -26,10 +26,17 @@
 #pragma once
 
 #include <WebCore/LoadSchedulingMode.h>
+#include <WebCore/NetworkLoadMetrics.h>
 #include <WebCore/PageIdentifier.h>
 #include <wtf/HashMap.h>
+#include <wtf/HashSet.h>
+#include <wtf/ListHashSet.h>
 #include <wtf/WeakPtr.h>
 
+namespace WebCore {
+class ResourceError;
+}
+
 namespace WebKit {
 
 class NetworkLoad;
@@ -41,18 +48,41 @@
     ~NetworkLoadScheduler();
 
     void schedule(NetworkLoad&);
-    void unschedule(NetworkLoad&);
+    void unschedule(NetworkLoad&, const WebCore::NetworkLoadMetrics* = nullptr);
 
+    void startedPreconnectForMainResource(const URL&);
+    void finishedPreconnectForMainResource(const URL&, const WebCore::ResourceError&);
+
     void setResourceLoadSchedulingMode(WebCore::PageIdentifier, WebCore::LoadSchedulingMode);
     void prioritizeLoads(const Vector<NetworkLoad*>&);
     void clearPageData(WebCore::PageIdentifier);
 
 private:
+    void scheduleLoad(NetworkLoad&);
+    void unscheduleLoad(NetworkLoad&);
+
+    void scheduleMainResourceLoad(NetworkLoad&);
+    void unscheduleMainResourceLoad(NetworkLoad&, const WebCore::NetworkLoadMetrics*);
+
+    bool isOriginHTTP1X(const String&);
+    void updateOriginProtocolInfo(const String&, const String&);
+
     class HostContext;
     HostContext* contextForLoad(const NetworkLoad&);
 
     using PageContext = HashMap<String, std::unique_ptr<HostContext>>;
     HashMap<WebCore::PageIdentifier, std::unique_ptr<PageContext>> m_pageContexts;
+
+    struct PendingMainResourcePreconnectInfo {
+        unsigned pendingPreconnects {1};
+        ListHashSet<NetworkLoad *> pendingLoads;
+    };
+    using PendingPreconnectMap = HashMap<String, PendingMainResourcePreconnectInfo>;
+    PendingPreconnectMap m_pendingMainResourcePreconnects;
+
+    void maybePrunePreconnectInfo(PendingPreconnectMap::iterator&);
+
+    HashSet<String> m_http1XOrigins;
 };
 
 }

Modified: branches/safari-612-branch/Source/WebKit/NetworkProcess/NetworkProcess.cpp (282573 => 282574)


--- branches/safari-612-branch/Source/WebKit/NetworkProcess/NetworkProcess.cpp	2021-09-16 18:48:24 UTC (rev 282573)
+++ branches/safari-612-branch/Source/WebKit/NetworkProcess/NetworkProcess.cpp	2021-09-16 18:48:27 UTC (rev 282574)
@@ -1381,6 +1381,7 @@
     parameters.request = ResourceRequest { url };
     parameters.request.setIsAppInitiated(lastNavigationWasAppInitiated == LastNavigationWasAppInitiated::Yes);
     parameters.request.setFirstPartyForCookies(url);
+    parameters.request.setPriority(WebCore::ResourceLoadPriority::VeryHigh);
     parameters.webPageProxyID = webPageProxyID;
     parameters.webPageID = webPageID;
     parameters.isNavigatingToAppBoundDomain = isNavigatingToAppBoundDomain;
@@ -1392,7 +1393,12 @@
     parameters.storedCredentialsPolicy = storedCredentialsPolicy;
     parameters.shouldPreconnectOnly = PreconnectOnly::Yes;
 
-    (new PreconnectTask(*networkSession, WTFMove(parameters), [](const WebCore::ResourceError&) { }))->start();
+    networkSession->networkLoadScheduler().startedPreconnectForMainResource(url);
+    auto task = new PreconnectTask(*networkSession, WTFMove(parameters), [networkSession, url](const WebCore::ResourceError& error) {
+        networkSession->networkLoadScheduler().finishedPreconnectForMainResource(url, error);
+    });
+    task->setTimeout(10_s);
+    task->start();
 #else
     UNUSED_PARAM(url);
     UNUSED_PARAM(userAgent);

Modified: branches/safari-612-branch/Source/WebKit/NetworkProcess/PreconnectTask.cpp (282573 => 282574)


--- branches/safari-612-branch/Source/WebKit/NetworkProcess/PreconnectTask.cpp	2021-09-16 18:48:24 UTC (rev 282573)
+++ branches/safari-612-branch/Source/WebKit/NetworkProcess/PreconnectTask.cpp	2021-09-16 18:48:27 UTC (rev 282574)
@@ -41,6 +41,7 @@
 
 PreconnectTask::PreconnectTask(NetworkSession& networkSession, NetworkLoadParameters&& parameters, CompletionHandler<void(const ResourceError&)>&& completionHandler)
     : m_completionHandler(WTFMove(completionHandler))
+    , m_timeout(60_s)
     , m_timeoutTimer([this] { didFinish(ResourceError { String(), 0, m_networkLoad->parameters().request.url(), "Preconnection timed out"_s, ResourceError::Type::Timeout }); })
 {
     RELEASE_LOG(Network, "%p - PreconnectTask::PreconnectTask()", this);
@@ -47,7 +48,6 @@
 
     ASSERT(parameters.shouldPreconnectOnly == PreconnectOnly::Yes);
     m_networkLoad = makeUnique<NetworkLoad>(*this, nullptr, WTFMove(parameters), networkSession);
-    m_timeoutTimer.startOneShot(60000_s);
 }
 
 void PreconnectTask::setH2PingCallback(const URL& url, CompletionHandler<void(Expected<WTF::Seconds, WebCore::ResourceError>&&)>&& completionHandler)
@@ -55,8 +55,14 @@
     m_networkLoad->setH2PingCallback(url, WTFMove(completionHandler));
 }
 
+void PreconnectTask::setTimeout(Seconds timeout)
+{
+    m_timeout = timeout;
+}
+
 void PreconnectTask::start()
 {
+    m_timeoutTimer.startOneShot(m_timeout);
     m_networkLoad->start();
 }
 

Modified: branches/safari-612-branch/Source/WebKit/NetworkProcess/PreconnectTask.h (282573 => 282574)


--- branches/safari-612-branch/Source/WebKit/NetworkProcess/PreconnectTask.h	2021-09-16 18:48:24 UTC (rev 282573)
+++ branches/safari-612-branch/Source/WebKit/NetworkProcess/PreconnectTask.h	2021-09-16 18:48:27 UTC (rev 282574)
@@ -45,6 +45,7 @@
     ~PreconnectTask();
 
     void setH2PingCallback(const URL&, CompletionHandler<void(Expected<WTF::Seconds, WebCore::ResourceError>&&)>&&);
+    void setTimeout(Seconds);
     void start();
 
 private:
@@ -62,6 +63,7 @@
 
     std::unique_ptr<NetworkLoad> m_networkLoad;
     CompletionHandler<void(const WebCore::ResourceError&)> m_completionHandler;
+    Seconds m_timeout;
     WebCore::Timer m_timeoutTimer;
 };
 
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to