Use NSURLSession for WebSocket
authoryouenn@apple.com <youenn@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 13 Jun 2019 01:04:16 +0000 (01:04 +0000)
committeryouenn@apple.com <youenn@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 13 Jun 2019 01:04:16 +0000 (01:04 +0000)
https://bugs.webkit.org/show_bug.cgi?id=198568

Reviewed by Geoffrey Garen.

Source/WebCore:

Add a runtime flag to either choose the new WebSocket code path or the previously existing one.
The switch is done at WebSocket channel API level which offers the necessary high level API to abstract the two code paths.
By default, we continue using the current WebSocket implementation.
Covered by manual testing on current WebSocket tests.

* Modules/websockets/ThreadableWebSocketChannel.cpp:
(WebCore::ThreadableWebSocketChannel::create):
* Modules/websockets/WebSocketChannel.cpp:
(WebCore::WebSocketChannel::document):
* Modules/websockets/WebSocketChannel.h:
* WebCore.xcodeproj/project.pbxproj:
* page/RuntimeEnabledFeatures.h:
(WebCore::RuntimeEnabledFeatures::isNSURLSessionWebSocketEnabled const):
(WebCore::RuntimeEnabledFeatures::setIsNSURLSessionWebSocketEnabled):
* page/SocketProvider.cpp:
(WebCore::SocketProvider::createWebSocketChannel):
* page/SocketProvider.h:

Source/WebKit:

Implement socket channel provider on WebProcess level by sending IPC to NetworkProcess.
On NetworkProcess side, use NSURLSession API to implement the WebSocket functionality.
This is a partial implementation:
- inspector integration is not working.
- some error cases are not well handled or are not producing the same error messages.
- some features are not implemented (extensions, subprotocols, handshake authentication challenge, cookie handling...).

* CMakeLists.txt:
* DerivedSources-input.xcfilelist:
* DerivedSources-output.xcfilelist:
* DerivedSources.make:
* NetworkProcess/NetworkConnectionToWebProcess.cpp:
(WebKit::NetworkConnectionToWebProcess::didReceiveMessage):
(WebKit::NetworkConnectionToWebProcess::createSocketChannel):
(WebKit::NetworkConnectionToWebProcess::removeSocketChannel):
* NetworkProcess/NetworkConnectionToWebProcess.h:
* NetworkProcess/NetworkConnectionToWebProcess.messages.in:
* NetworkProcess/NetworkSession.cpp:
(WebKit::NetworkSession::createWebSocketTask):
* NetworkProcess/NetworkSession.h:
(WebKit::NetworkSession::removeWebSocketTask):
(WebKit::NetworkSession::addWebSocketTask):
* NetworkProcess/NetworkSocketChannel.cpp: Added.
(WebKit::NetworkSocketChannel::create):
(WebKit::NetworkSocketChannel::NetworkSocketChannel):
(WebKit::NetworkSocketChannel::~NetworkSocketChannel):
(WebKit::NetworkSocketChannel::sendString):
(WebKit::NetworkSocketChannel::sendData):
(WebKit::NetworkSocketChannel::finishClosingIfPossible):
(WebKit::NetworkSocketChannel::close):
(WebKit::NetworkSocketChannel::didConnect):
(WebKit::NetworkSocketChannel::didReceiveText):
(WebKit::NetworkSocketChannel::didReceiveBinaryData):
(WebKit::NetworkSocketChannel::didClose):
(WebKit::NetworkSocketChannel::messageSenderConnection const):
* NetworkProcess/NetworkSocketChannel.h: Added.
* NetworkProcess/NetworkSocketChannel.messages.in: Added.
* NetworkProcess/NetworkSocketStream.messages.in:
* NetworkProcess/WebSocketTask.h: Added.
(WebKit::WebSocketTask::sendString):
(WebKit::WebSocketTask::sendData):
(WebKit::WebSocketTask::close):
(WebKit::WebSocketTask::cancel):
(WebKit::WebSocketTask::resume):
* NetworkProcess/cocoa/NetworkSessionCocoa.h:
* NetworkProcess/cocoa/NetworkSessionCocoa.mm:
(-[WKNetworkSessionDelegate existingWebSocketTask:]):
(-[WKNetworkSessionDelegate URLSession:webSocketTask:didOpenWithProtocol:]):
(-[WKNetworkSessionDelegate URLSession:webSocketTask:didCloseWithCode:reason:]):
(WebKit::NetworkSessionCocoa::continueDidReceiveChallenge):
(WebKit::NetworkSessionCocoa::createWebSocketTask):
(WebKit::NetworkSessionCocoa::addWebSocketTask):
(WebKit::NetworkSessionCocoa::removeWebSocketTask):
(WebKit::NetworkSessionCocoa::webSocketDataTaskForIdentifier):
* NetworkProcess/cocoa/WebSocketTaskCocoa.h: Added.
* NetworkProcess/cocoa/WebSocketTaskCocoa.mm: Added.
(WebKit::WebSocketTask::WebSocketTask):
(WebKit::WebSocketTask::~WebSocketTask):
(WebKit::WebSocketTask::readNextMessage):
(WebKit::WebSocketTask::cancel):
(WebKit::WebSocketTask::resume):
(WebKit::WebSocketTask::didConnect):
(WebKit::WebSocketTask::didClose):
(WebKit::WebSocketTask::sendString):
(WebKit::WebSocketTask::sendData):
(WebKit::WebSocketTask::close):
(WebKit::WebSocketTask::identifier const):
* Shared/WebPreferences.yaml:
* WebKit.xcodeproj/project.pbxproj:
* WebProcess/Network/NetworkProcessConnection.cpp:
(WebKit::NetworkProcessConnection::didReceiveMessage):
* WebProcess/Network/WebSocketChannel.cpp: Added.
(WebKit::WebSocketChannel::create):
(WebKit::WebSocketChannel::WebSocketChannel):
(WebKit::WebSocketChannel::~WebSocketChannel):
(WebKit::WebSocketChannel::messageSenderConnection const):
(WebKit::WebSocketChannel::messageSenderDestinationID const):
(WebKit::WebSocketChannel::subprotocol):
(WebKit::WebSocketChannel::extensions):
(WebKit::WebSocketChannel::connect):
(WebKit::WebSocketChannel::send):
(WebKit::WebSocketChannel::bufferedAmount const):
(WebKit::WebSocketChannel::close):
(WebKit::WebSocketChannel::fail):
(WebKit::WebSocketChannel::disconnect):
(WebKit::WebSocketChannel::didConnect):
(WebKit::WebSocketChannel::didReceiveText):
(WebKit::WebSocketChannel::didReceiveBinaryData):
(WebKit::WebSocketChannel::didClose):
(WebKit::WebSocketChannel::didFail):
(WebKit::WebSocketChannel::networkProcessCrashed):
* WebProcess/Network/WebSocketChannel.h: Added.
* WebProcess/Network/WebSocketChannel.messages.in: Added.
* WebProcess/Network/WebSocketChannelManager.cpp: Added.
(WebKit::WebSocketChannelManager::createWebSocketChannel):
(WebKit::WebSocketChannelManager::networkProcessCrashed):
(WebKit::WebSocketChannelManager::didReceiveMessage):
* WebProcess/Network/WebSocketChannelManager.h: Added.
* WebProcess/Network/WebSocketProvider.cpp:
(WebKit::WebSocketProvider::createWebSocketChannel):
* WebProcess/Network/WebSocketProvider.h:
* WebProcess/Network/WebSocketStream.cpp:
* WebProcess/Network/WebSocketStream.messages.in:
* WebProcess/WebProcess.cpp:
(WebKit::WebProcess::networkProcessConnectionClosed):
* WebProcess/WebProcess.h:
(WebKit::WebProcess::webSocketChannelManager):

Source/WTF:

* wtf/Platform.h:
Introduce compile flag for WebSocket NSURLSession

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

49 files changed:
Source/WTF/ChangeLog
Source/WTF/wtf/Platform.h
Source/WebCore/ChangeLog
Source/WebCore/Headers.cmake
Source/WebCore/Modules/websockets/ThreadableWebSocketChannel.cpp
Source/WebCore/Modules/websockets/ThreadableWebSocketChannel.h
Source/WebCore/Modules/websockets/WebSocket.cpp
Source/WebCore/Modules/websockets/WebSocket.h
Source/WebCore/Modules/websockets/WebSocketChannel.cpp
Source/WebCore/Modules/websockets/WebSocketChannel.h
Source/WebCore/Modules/websockets/WorkerThreadableWebSocketChannel.cpp
Source/WebCore/Modules/websockets/WorkerThreadableWebSocketChannel.h
Source/WebCore/WebCore.xcodeproj/project.pbxproj
Source/WebCore/page/RuntimeEnabledFeatures.h
Source/WebCore/page/SocketProvider.cpp
Source/WebCore/page/SocketProvider.h
Source/WebKit/CMakeLists.txt
Source/WebKit/ChangeLog
Source/WebKit/DerivedSources-input.xcfilelist
Source/WebKit/DerivedSources-output.xcfilelist
Source/WebKit/DerivedSources.make
Source/WebKit/NetworkProcess/NetworkConnectionToWebProcess.cpp
Source/WebKit/NetworkProcess/NetworkConnectionToWebProcess.h
Source/WebKit/NetworkProcess/NetworkConnectionToWebProcess.messages.in
Source/WebKit/NetworkProcess/NetworkSession.cpp
Source/WebKit/NetworkProcess/NetworkSession.h
Source/WebKit/NetworkProcess/NetworkSocketChannel.cpp [new file with mode: 0644]
Source/WebKit/NetworkProcess/NetworkSocketChannel.h [new file with mode: 0644]
Source/WebKit/NetworkProcess/NetworkSocketChannel.messages.in [new file with mode: 0644]
Source/WebKit/NetworkProcess/WebSocketTask.h [new file with mode: 0644]
Source/WebKit/NetworkProcess/cocoa/NetworkSessionCocoa.h
Source/WebKit/NetworkProcess/cocoa/NetworkSessionCocoa.mm
Source/WebKit/NetworkProcess/cocoa/WebSocketTaskCocoa.h [new file with mode: 0644]
Source/WebKit/NetworkProcess/cocoa/WebSocketTaskCocoa.mm [new file with mode: 0644]
Source/WebKit/Shared/WebPreferences.yaml
Source/WebKit/Sources.txt
Source/WebKit/SourcesGTK.txt
Source/WebKit/WebKit.xcodeproj/project.pbxproj
Source/WebKit/WebProcess/Network/NetworkProcessConnection.cpp
Source/WebKit/WebProcess/Network/WebSocketChannel.cpp [new file with mode: 0644]
Source/WebKit/WebProcess/Network/WebSocketChannel.h [new file with mode: 0644]
Source/WebKit/WebProcess/Network/WebSocketChannel.messages.in [new file with mode: 0644]
Source/WebKit/WebProcess/Network/WebSocketChannelManager.cpp [new file with mode: 0644]
Source/WebKit/WebProcess/Network/WebSocketChannelManager.h [new file with mode: 0644]
Source/WebKit/WebProcess/Network/WebSocketProvider.cpp
Source/WebKit/WebProcess/Network/WebSocketProvider.h
Source/WebKit/WebProcess/WebCoreSupport/ios/WebPreviewLoaderClient.h
Source/WebKit/WebProcess/WebProcess.cpp
Source/WebKit/WebProcess/WebProcess.h

index d384290..72eea33 100644 (file)
@@ -1,3 +1,13 @@
+2019-06-12  Youenn Fablet  <youenn@apple.com>
+
+        Use NSURLSession for WebSocket
+        https://bugs.webkit.org/show_bug.cgi?id=198568
+
+        Reviewed by Geoffrey Garen.
+
+        * wtf/Platform.h:
+        Introduce compile flag for WebSocket NSURLSession
+
 2019-06-12  Commit Queue  <commit-queue@webkit.org>
 
         Unreviewed, rolling out r246322.
index 83d3673..9d43bff 100644 (file)
 #define USE_REALPATH_FOR_DLOPEN_PREFLIGHT 1
 #endif
 
+#if (PLATFORM(MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 101500) || (PLATFORM(IOS_FAMILY) && __IPHONE_OS_VERSION_MIN_REQUIRED >= 130000) || (PLATFORM(WATCHOS) && __WATCH_OS_VERSION_MIN_REQUIRED >= 60000) || (PLATFORM(APPLETV) && __TV_OS_VERSION_MIN_REQUIRED >= 130000)
+#define HAVE_NSURLSESSION_WEBSOCKET 1
+#endif
+
 #if (PLATFORM(MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 101500) || (PLATFORM(IOS) && __IPHONE_OS_VERSION_MIN_REQUIRED >= 130000) || (PLATFORM(WATCHOS) && __WATCH_OS_VERSION_MIN_REQUIRED >= 60000) || (PLATFORM(APPLETV) && __TV_OS_VERSION_MIN_REQUIRED >= 130000)
 #define HAVE_AVPLAYER_RESOURCE_CONSERVATION_LEVEL 1
 #endif
index 546c486..cd10c31 100644 (file)
@@ -1,3 +1,28 @@
+2019-06-12  Youenn Fablet  <youenn@apple.com>
+
+        Use NSURLSession for WebSocket
+        https://bugs.webkit.org/show_bug.cgi?id=198568
+
+        Reviewed by Geoffrey Garen.
+
+        Add a runtime flag to either choose the new WebSocket code path or the previously existing one.
+        The switch is done at WebSocket channel API level which offers the necessary high level API to abstract the two code paths.
+        By default, we continue using the current WebSocket implementation.
+        Covered by manual testing on current WebSocket tests.
+
+        * Modules/websockets/ThreadableWebSocketChannel.cpp:
+        (WebCore::ThreadableWebSocketChannel::create):
+        * Modules/websockets/WebSocketChannel.cpp:
+        (WebCore::WebSocketChannel::document):
+        * Modules/websockets/WebSocketChannel.h:
+        * WebCore.xcodeproj/project.pbxproj:
+        * page/RuntimeEnabledFeatures.h:
+        (WebCore::RuntimeEnabledFeatures::isNSURLSessionWebSocketEnabled const):
+        (WebCore::RuntimeEnabledFeatures::setIsNSURLSessionWebSocketEnabled):
+        * page/SocketProvider.cpp:
+        (WebCore::SocketProvider::createWebSocketChannel):
+        * page/SocketProvider.h:
+
 2019-06-12  Myles C. Maxfield  <mmaxfield@apple.com>
 
         [WHLSL] Educate the property resolver about IndexExpressions
index effa3e2..34e8341 100644 (file)
@@ -149,6 +149,16 @@ set(WebCore_PRIVATE_FRAMEWORK_HEADERS
     Modules/webdatabase/DatabaseTracker.h
     Modules/webdatabase/OriginLock.h
 
+    Modules/websockets/ThreadableWebSocketChannel.h
+    Modules/websockets/WebSocketChannel.h
+    Modules/websockets/WebSocketChannelClient.h
+    Modules/websockets/WebSocketDeflateFramer.h
+    Modules/websockets/WebSocketDeflater.h
+    Modules/websockets/WebSocketExtensionDispatcher.h
+    Modules/websockets/WebSocketExtensionProcessor.h
+    Modules/websockets/WebSocketFrame.h
+    Modules/websockets/WebSocketHandshake.h
+
     accessibility/AXObjectCache.h
     accessibility/AXTextStateChangeIntent.h
     accessibility/AccessibilityListBox.h
@@ -506,6 +516,7 @@ set(WebCore_PRIVATE_FRAMEWORK_HEADERS
     fileapi/BlobPropertyBag.h
     fileapi/File.h
     fileapi/FileList.h
+    fileapi/FileReaderLoaderClient.h
 
     history/BackForwardClient.h
     history/BackForwardController.h
index 8299bb9..7142ea9 100644 (file)
 #include "config.h"
 #include "ThreadableWebSocketChannel.h"
 
+#include "ContentRuleListResults.h"
 #include "Document.h"
+#include "Page.h"
+#include "RuntimeEnabledFeatures.h"
 #include "ScriptExecutionContext.h"
+#include "SocketProvider.h"
 #include "ThreadableWebSocketChannelClientWrapper.h"
+#include "UserContentProvider.h"
 #include "WebSocketChannel.h"
 #include "WebSocketChannelClient.h"
 #include "WorkerGlobalScope.h"
@@ -51,7 +56,56 @@ Ref<ThreadableWebSocketChannel> ThreadableWebSocketChannel::create(ScriptExecuti
         return WorkerThreadableWebSocketChannel::create(workerGlobalScope, client, makeString("webSocketChannelMode", runLoop.createUniqueId()), provider);
     }
 
-    return WebSocketChannel::create(downcast<Document>(context), client, provider);
+    auto& document = downcast<Document>(context);
+
+#if HAVE(NSURLSESSION_WEBSOCKET)
+    if (RuntimeEnabledFeatures::sharedFeatures().isNSURLSessionWebSocketEnabled()) {
+        if (auto channel = provider.createWebSocketChannel(document, client))
+            return channel.releaseNonNull();
+    }
+#endif
+    return WebSocketChannel::create(document, client, provider);
+}
+
+Optional<ThreadableWebSocketChannel::ValidatedURL> ThreadableWebSocketChannel::validateURL(Document& document, const URL& requestedURL)
+{
+    ValidatedURL validatedURL { requestedURL, true };
+#if ENABLE(CONTENT_EXTENSIONS)
+    if (auto* page = document.page()) {
+        if (auto* documentLoader = document.loader()) {
+            auto results = page->userContentProvider().processContentRuleListsForLoad(validatedURL.url, ContentExtensions::ResourceType::Raw, *documentLoader);
+            if (results.summary.blockedLoad)
+                return { };
+            if (results.summary.madeHTTPS) {
+                ASSERT(validatedURL.url.protocolIs("ws"));
+                validatedURL.url.setProtocol("wss");
+            }
+            validatedURL.areCookiesAllowed = !results.summary.blockedCookies;
+        }
+    }
+#endif
+    return validatedURL;
+}
+
+Optional<ResourceRequest> ThreadableWebSocketChannel::webSocketConnectRequest(Document& document, const URL& url)
+{
+    auto validatedURL = validateURL(document, url);
+    if (!validatedURL)
+        return { };
+
+    ResourceRequest request { validatedURL->url };
+    request.setHTTPUserAgent(document.userAgent(validatedURL->url));
+    request.setDomainForCachePartition(document.domainForCachePartition());
+    request.setAllowCookies(validatedURL->areCookiesAllowed);
+
+    // Add no-cache headers to avoid compatibility issue.
+    // There are some proxies that rewrite "Connection: upgrade"
+    // to "Connection: close" in the response if a request doesn't contain
+    // these headers.
+    request.addHTTPHeaderField(HTTPHeaderName::Pragma, "no-cache");
+    request.addHTTPHeaderField(HTTPHeaderName::CacheControl, "no-cache");
+
+    return request;
 }
 
 } // namespace WebCore
index a85dfd7..8e65f95 100644 (file)
@@ -32,6 +32,7 @@
 
 #include <wtf/Forward.h>
 #include <wtf/Noncopyable.h>
+#include <wtf/URL.h>
 
 namespace JSC {
 class ArrayBuffer;
@@ -40,6 +41,8 @@ class ArrayBuffer;
 namespace WebCore {
 
 class Blob;
+class Document;
+class ResourceRequest;
 class ScriptExecutionContext;
 class SocketProvider;
 class WebSocketChannelClient;
@@ -57,7 +60,8 @@ public:
         SendFail
     };
 
-    virtual void connect(const URL&, const String& protocol) = 0;
+    enum class ConnectStatus { KO, OK };
+    virtual ConnectStatus connect(const URL&, const String& protocol) = 0;
     virtual String subprotocol() = 0; // Will be available after didConnect() callback is invoked.
     virtual String extensions() = 0; // Will be available after didConnect() callback is invoked.
     virtual SendResult send(const String& message) = 0;
@@ -79,6 +83,13 @@ protected:
     virtual ~ThreadableWebSocketChannel() = default;
     virtual void refThreadableWebSocketChannel() = 0;
     virtual void derefThreadableWebSocketChannel() = 0;
+
+    struct ValidatedURL {
+        URL url;
+        bool areCookiesAllowed { true };
+    };
+    static Optional<ValidatedURL> validateURL(Document&, const URL&);
+    WEBCORE_EXPORT static Optional<ResourceRequest> webSocketConnectRequest(Document&, const URL&);
 };
 
 } // namespace WebCore
index 2a03524..f13791c 100644 (file)
@@ -205,6 +205,21 @@ ExceptionOr<void> WebSocket::connect(const String& url, const String& protocol)
     return connect(url, Vector<String> { 1, protocol });
 }
 
+void WebSocket::failAsynchronously()
+{
+    m_pendingActivity = makePendingActivity(*this);
+
+    // We must block this connection. Instead of throwing an exception, we indicate this
+    // using the error event. But since this code executes as part of the WebSocket's
+    // constructor, we have to wait until the constructor has completed before firing the
+    // event; otherwise, users can't connect to the event.
+
+    scriptExecutionContext()->postTask([this, protectedThis = makeRef(*this)](auto&) {
+        this->dispatchOrQueueErrorEvent();
+        this->stop();
+    });
+}
+
 ExceptionOr<void> WebSocket::connect(const String& url, const Vector<String>& protocols)
 {
     LOG(Network, "WebSocket %p connect() url='%s'", this, url.utf8().data());
@@ -291,18 +306,7 @@ ExceptionOr<void> WebSocket::connect(const String& url, const Vector<String>& pr
         Document& document = downcast<Document>(context);
         RefPtr<Frame> frame = document.frame();
         if (!frame || !frame->loader().mixedContentChecker().canRunInsecureContent(document.securityOrigin(), m_url)) {
-            m_pendingActivity = makePendingActivity(*this);
-
-            // We must block this connection. Instead of throwing an exception, we indicate this
-            // using the error event. But since this code executes as part of the WebSocket's
-            // constructor, we have to wait until the constructor has completed before firing the
-            // event; otherwise, users can't connect to the event.
-
-            document.postTask([this, protectedThis = makeRef(*this)](auto&) {
-                this->dispatchOrQueueErrorEvent();
-                this->stop();
-            });
-
+            failAsynchronously();
             return { };
         }
     }
@@ -311,7 +315,11 @@ ExceptionOr<void> WebSocket::connect(const String& url, const Vector<String>& pr
     if (!protocols.isEmpty())
         protocolString = joinStrings(protocols, subprotocolSeparator());
 
-    m_channel->connect(m_url, protocolString);
+    if (m_channel->connect(m_url, protocolString) == ThreadableWebSocketChannel::ConnectStatus::KO) {
+        failAsynchronously();
+        return { };
+    }
+
     m_pendingActivity = makePendingActivity(*this);
 
     return { };
index 55cc4c0..86efff7 100644 (file)
@@ -128,6 +128,8 @@ private:
 
     size_t getFramingOverhead(size_t payloadSize);
 
+    void failAsynchronously();
+
     enum class BinaryType { Blob, ArrayBuffer };
 
     RefPtr<ThreadableWebSocketChannel> m_channel;
index b4ccc89..6071440 100644 (file)
@@ -81,46 +81,28 @@ WebSocketChannel::~WebSocketChannel()
     LOG(Network, "WebSocketChannel %p dtor", this);
 }
 
-void WebSocketChannel::connect(const URL& requestedURL, const String& protocol)
+WebSocketChannel::ConnectStatus WebSocketChannel::connect(const URL& requestedURL, const String& protocol)
 {
     LOG(Network, "WebSocketChannel %p connect()", this);
 
-    URL url = requestedURL;
-#if ENABLE(CONTENT_EXTENSIONS)
-    if (auto* page = m_document->page()) {
-        if (auto* documentLoader = m_document->loader()) {
-            auto results = page->userContentProvider().processContentRuleListsForLoad(url, ContentExtensions::ResourceType::Raw, *documentLoader);
-            if (results.summary.blockedLoad) {
-                Ref<WebSocketChannel> protectedThis(*this);
-                callOnMainThread([protectedThis = WTFMove(protectedThis)] {
-                    if (protectedThis->m_client)
-                        protectedThis->m_client->didReceiveMessageError();
-                });
-                return;
-            }
-            if (results.summary.madeHTTPS) {
-                ASSERT(url.protocolIs("ws"));
-                url.setProtocol("wss");
-                if (m_client)
-                    m_client->didUpgradeURL();
-            }
-            if (results.summary.blockedCookies)
-                m_allowCookies = false;
-        }
-    }
-#endif
-    
+    auto validatedURL = validateURL(*m_document, requestedURL);
+    if (!validatedURL)
+        return ConnectStatus::KO;
     ASSERT(!m_handle);
     ASSERT(!m_suspended);
-    
+
+    if (validatedURL->url != requestedURL && m_client)
+        m_client->didUpgradeURL();
+
+    m_allowCookies = validatedURL->areCookiesAllowed;
     String userAgent = m_document->userAgent(m_document->url());
     String clientOrigin = m_document->securityOrigin().toString();
-    m_handshake = std::make_unique<WebSocketHandshake>(url, protocol, userAgent, clientOrigin, m_allowCookies);
+    m_handshake = std::make_unique<WebSocketHandshake>(validatedURL->url, protocol, userAgent, clientOrigin, m_allowCookies);
     m_handshake->reset();
     if (m_deflateFramer.canDeflate())
         m_handshake->addExtensionProcessor(m_deflateFramer.createExtensionProcessor());
     if (m_identifier)
-        InspectorInstrumentation::didCreateWebSocket(m_document.get(), m_identifier, url);
+        InspectorInstrumentation::didCreateWebSocket(m_document.get(), m_identifier, validatedURL->url);
 
     if (Frame* frame = m_document->frame()) {
         ref();
@@ -129,6 +111,12 @@ void WebSocketChannel::connect(const URL& requestedURL, const String& protocol)
         String partition = m_document->domainForCachePartition();
         m_handle = m_socketProvider->createSocketStreamHandle(m_handshake->url(), *this, sessionID, partition, frame->loader().networkingContext());
     }
+    return ConnectStatus::OK;
+}
+
+Document* WebSocketChannel::document()
+{
+    return m_document.get();
 }
 
 String WebSocketChannel::subprotocol()
index 49bab54..b159303 100644 (file)
@@ -56,7 +56,7 @@ class SocketStreamHandle;
 class SocketStreamError;
 class WebSocketChannelClient;
 
-class WebSocketChannel : public RefCounted<WebSocketChannel>, public SocketStreamHandleClient, public ThreadableWebSocketChannel, public FileReaderLoaderClient
+class WebSocketChannel final : public RefCounted<WebSocketChannel>, public SocketStreamHandleClient, public ThreadableWebSocketChannel, public FileReaderLoaderClient
 {
     WTF_MAKE_FAST_ALLOCATED;
 public:
@@ -68,19 +68,19 @@ public:
     bool send(const char* data, int length);
 
     // ThreadableWebSocketChannel functions.
-    void connect(const URL&, const String& protocol) override;
-    String subprotocol() override;
-    String extensions() override;
-    ThreadableWebSocketChannel::SendResult send(const String& message) override;
-    ThreadableWebSocketChannel::SendResult send(const JSC::ArrayBuffer&, unsigned byteOffset, unsigned byteLength) override;
-    ThreadableWebSocketChannel::SendResult send(Blob&) override;
-    unsigned bufferedAmount() const override;
-    void close(int code, const String& reason) override; // Start closing handshake.
-    void fail(const String& reason) override;
-    void disconnect() override;
-
-    void suspend() override;
-    void resume() override;
+    ConnectStatus connect(const URL&, const String& protocol) final;
+    String subprotocol() final;
+    String extensions() final;
+    ThreadableWebSocketChannel::SendResult send(const String& message) final;
+    ThreadableWebSocketChannel::SendResult send(const JSC::ArrayBuffer&, unsigned byteOffset, unsigned byteLength) final;
+    ThreadableWebSocketChannel::SendResult send(Blob&) final;
+    unsigned bufferedAmount() const final;
+    void close(int code, const String& reason) final; // Start closing handshake.
+    void fail(const String& reason) final;
+    void disconnect() final;
+
+    void suspend() final;
+    void resume() final;
 
     // SocketStreamHandleClient functions.
     void didOpenSocketStream(SocketStreamHandle&) final;
@@ -124,7 +124,7 @@ public:
     using RefCounted<WebSocketChannel>::ref;
     using RefCounted<WebSocketChannel>::deref;
 
-    Document* document() { return m_document.get(); }
+    Document* document();
     
 protected:
     void refThreadableWebSocketChannel() override { ref(); }
index 8421b14..1dd39a9 100644 (file)
@@ -63,10 +63,12 @@ WorkerThreadableWebSocketChannel::~WorkerThreadableWebSocketChannel()
         m_bridge->disconnect();
 }
 
-void WorkerThreadableWebSocketChannel::connect(const URL& url, const String& protocol)
+WorkerThreadableWebSocketChannel::ConnectStatus WorkerThreadableWebSocketChannel::connect(const URL& url, const String& protocol)
 {
     if (m_bridge)
         m_bridge->connect(url, protocol);
+    // connect is called asynchronously, so we do not have any possibility for synchronous errors.
+    return ConnectStatus::OK;
 }
 
 String WorkerThreadableWebSocketChannel::subprotocol()
@@ -155,12 +157,12 @@ WorkerThreadableWebSocketChannel::Peer::~Peer()
         m_mainWebSocketChannel->disconnect();
 }
 
-void WorkerThreadableWebSocketChannel::Peer::connect(const URL& url, const String& protocol)
+WorkerThreadableWebSocketChannel::ConnectStatus WorkerThreadableWebSocketChannel::Peer::connect(const URL& url, const String& protocol)
 {
     ASSERT(isMainThread());
     if (!m_mainWebSocketChannel)
-        return;
-    m_mainWebSocketChannel->connect(url, protocol);
+        return WorkerThreadableWebSocketChannel::ConnectStatus::KO;
+    return m_mainWebSocketChannel->connect(url, protocol);
 }
 
 void WorkerThreadableWebSocketChannel::Peer::send(const String& message)
@@ -403,7 +405,8 @@ void WorkerThreadableWebSocketChannel::Bridge::connect(const URL& url, const Str
         ASSERT_UNUSED(context, context.isDocument());
         ASSERT(peer);
 
-        peer->connect(url, protocol);
+        if (peer->connect(url, protocol) == ThreadableWebSocketChannel::ConnectStatus::KO)
+            peer->didReceiveMessageError();
     });
 }
 
index 3895e44..354877c 100644 (file)
@@ -45,7 +45,7 @@ class WorkerGlobalScope;
 class WorkerLoaderProxy;
 class WorkerRunLoop;
 
-class WorkerThreadableWebSocketChannel : public RefCounted<WorkerThreadableWebSocketChannel>, public ThreadableWebSocketChannel {
+class WorkerThreadableWebSocketChannel final : public RefCounted<WorkerThreadableWebSocketChannel>, public ThreadableWebSocketChannel {
     WTF_MAKE_FAST_ALLOCATED;
 public:
     static Ref<ThreadableWebSocketChannel> create(WorkerGlobalScope& workerGlobalScope, WebSocketChannelClient& client, const String& taskMode, SocketProvider& provider)
@@ -55,18 +55,18 @@ public:
     virtual ~WorkerThreadableWebSocketChannel();
 
     // ThreadableWebSocketChannel functions.
-    void connect(const URL&, const String& protocol) override;
-    String subprotocol() override;
-    String extensions() override;
-    ThreadableWebSocketChannel::SendResult send(const String& message) override;
-    ThreadableWebSocketChannel::SendResult send(const JSC::ArrayBuffer&, unsigned byteOffset, unsigned byteLength) override;
-    ThreadableWebSocketChannel::SendResult send(Blob&) override;
-    unsigned bufferedAmount() const override;
-    void close(int code, const String& reason) override;
-    void fail(const String& reason) override;
-    void disconnect() override; // Will suppress didClose().
-    void suspend() override;
-    void resume() override;
+    ConnectStatus connect(const URL&, const String& protocol) final;
+    String subprotocol() final;
+    String extensions() final;
+    ThreadableWebSocketChannel::SendResult send(const String& message) final;
+    ThreadableWebSocketChannel::SendResult send(const JSC::ArrayBuffer&, unsigned byteOffset, unsigned byteLength) final;
+    ThreadableWebSocketChannel::SendResult send(Blob&) final;
+    unsigned bufferedAmount() const final;
+    void close(int code, const String& reason) final;
+    void fail(const String& reason) final;
+    void disconnect() final; // Will suppress didClose().
+    void suspend() final;
+    void resume() final;
 
     // Generated by the bridge.  The Peer and its bridge should have identical
     // lifetimes.
@@ -76,7 +76,7 @@ public:
         Peer(Ref<ThreadableWebSocketChannelClientWrapper>&&, WorkerLoaderProxy&, ScriptExecutionContext&, const String& taskMode, SocketProvider&);
         ~Peer();
 
-        void connect(const URL&, const String& protocol);
+        ConnectStatus connect(const URL&, const String& protocol);
         void send(const String& message);
         void send(const JSC::ArrayBuffer&);
         void send(Blob&);
index b65799a..43007e6 100644 (file)
                97AABD1E14FA09D5007457AE /* WebSocketChannel.h in Headers */ = {isa = PBXBuildFile; fileRef = 97AABD0314FA09D5007457AE /* WebSocketChannel.h */; settings = {ATTRIBUTES = (Private, ); }; };
                97AABD1F14FA09D5007457AE /* WebSocketChannelClient.h in Headers */ = {isa = PBXBuildFile; fileRef = 97AABD0414FA09D5007457AE /* WebSocketChannelClient.h */; settings = {ATTRIBUTES = (Private, ); }; };
                97AABD2114FA09D5007457AE /* WebSocketDeflater.h in Headers */ = {isa = PBXBuildFile; fileRef = 97AABD0614FA09D5007457AE /* WebSocketDeflater.h */; settings = {ATTRIBUTES = (Private, ); }; };
-               97AABD2314FA09D5007457AE /* WebSocketExtensionDispatcher.h in Headers */ = {isa = PBXBuildFile; fileRef = 97AABD0814FA09D5007457AE /* WebSocketExtensionDispatcher.h */; };
+               97AABD2314FA09D5007457AE /* WebSocketExtensionDispatcher.h in Headers */ = {isa = PBXBuildFile; fileRef = 97AABD0814FA09D5007457AE /* WebSocketExtensionDispatcher.h */; settings = {ATTRIBUTES = (Private, ); }; };
                97AABD2414FA09D5007457AE /* WebSocketExtensionProcessor.h in Headers */ = {isa = PBXBuildFile; fileRef = 97AABD0914FA09D5007457AE /* WebSocketExtensionProcessor.h */; settings = {ATTRIBUTES = (Private, ); }; };
                97AABD2514FA09D5007457AE /* WebSocketFrame.h in Headers */ = {isa = PBXBuildFile; fileRef = 97AABD0A14FA09D5007457AE /* WebSocketFrame.h */; settings = {ATTRIBUTES = (Private, ); }; };
-               97AABD2714FA09D5007457AE /* WebSocketHandshake.h in Headers */ = {isa = PBXBuildFile; fileRef = 97AABD0C14FA09D5007457AE /* WebSocketHandshake.h */; };
+               97AABD2714FA09D5007457AE /* WebSocketHandshake.h in Headers */ = {isa = PBXBuildFile; fileRef = 97AABD0C14FA09D5007457AE /* WebSocketHandshake.h */; settings = {ATTRIBUTES = (Private, ); }; };
                97AABD2D14FA09D5007457AE /* WorkerThreadableWebSocketChannel.h in Headers */ = {isa = PBXBuildFile; fileRef = 97AABD1214FA09D5007457AE /* WorkerThreadableWebSocketChannel.h */; settings = {ATTRIBUTES = (Private, ); }; };
                97B8FFD116AE7F960038388D /* CharacterReferenceParserInlines.h in Headers */ = {isa = PBXBuildFile; fileRef = 97B8FFCF16AE7F920038388D /* CharacterReferenceParserInlines.h */; };
                97BC69DD1505F076001B74AC /* ChangeVersionWrapper.h in Headers */ = {isa = PBXBuildFile; fileRef = 97BC69D91505F076001B74AC /* ChangeVersionWrapper.h */; };
index 1b9ddac..82554b9 100644 (file)
@@ -365,6 +365,11 @@ public:
 
     WEBCORE_EXPORT static RuntimeEnabledFeatures& sharedFeatures();
 
+#if HAVE(NSURLSESSION_WEBSOCKET)
+    bool isNSURLSessionWebSocketEnabled() const { return m_isNSURLSessionWebSocketEnabled; }
+    void setIsNSURLSessionWebSocketEnabled(bool isEnabled) { m_isNSURLSessionWebSocketEnabled = isEnabled; }
+#endif
+
 private:
     // Never instantiate.
     RuntimeEnabledFeatures();
@@ -550,6 +555,10 @@ private:
 
     bool m_linkPreloadResponsiveImagesEnabled { false };
 
+#if HAVE(NSURLSESSION_WEBSOCKET)
+    bool m_isNSURLSessionWebSocketEnabled { false };
+#endif
+
     friend class WTF::NeverDestroyed<RuntimeEnabledFeatures>;
 };
 
index 46af7f4..803ac83 100644 (file)
@@ -27,6 +27,7 @@
 #include "SocketProvider.h"
 
 #include "SocketStreamHandleImpl.h"
+#include "ThreadableWebSocketChannel.h"
 
 namespace WebCore {
     
@@ -34,5 +35,10 @@ Ref<SocketStreamHandle> SocketProvider::createSocketStreamHandle(const URL& url,
 {
     return SocketStreamHandleImpl::create(url, client, sessionID, credentialPartition, { }, provider);
 }
-    
+
+RefPtr<ThreadableWebSocketChannel> SocketProvider::createWebSocketChannel(Document&, WebSocketChannelClient&)
+{
+    return nullptr;
+}
+
 }
index e016b4d..5f56f15 100644 (file)
 
 namespace WebCore {
 
+class ThreadableWebSocketChannel;
+class ScriptExecutionContext;
 class StorageSessionProvider;
 class ScriptExecutionContext;
 class SocketStreamHandle;
 class SocketStreamHandleClient;
+class WebSocketChannelClient;
 
 class WEBCORE_EXPORT SocketProvider : public ThreadSafeRefCounted<SocketProvider> {
 public:
     static Ref<SocketProvider> create() { return adoptRef(*new SocketProvider); }
     virtual Ref<SocketStreamHandle> createSocketStreamHandle(const URL&, SocketStreamHandleClient&, PAL::SessionID, const String& credentialPartition, const StorageSessionProvider*);
+
+    virtual RefPtr<ThreadableWebSocketChannel> createWebSocketChannel(Document&, WebSocketChannelClient&);
+
     virtual ~SocketProvider() { };
 };
 
index b8e08c1..6f79c86 100644 (file)
@@ -111,6 +111,7 @@ set(WebKit_MESSAGES_IN_FILES
     NetworkProcess/NetworkContentRuleListManager.messages.in
     NetworkProcess/NetworkProcess.messages.in
     NetworkProcess/NetworkResourceLoader.messages.in
+    NetworkProcess/NetworkSocketChannel.messages.in
     NetworkProcess/NetworkSocketStream.messages.in
 
     NetworkProcess/ServiceWorker/ServiceWorkerFetchTask.messages.in
@@ -176,6 +177,7 @@ set(WebKit_MESSAGES_IN_FILES
 
     WebProcess/Network/NetworkProcessConnection.messages.in
     WebProcess/Network/WebResourceLoader.messages.in
+    WebProcess/Network/WebSocketChannel.messages.in
     WebProcess/Network/WebSocketStream.messages.in
 
     WebProcess/Notifications/WebNotificationManager.messages.in
index 2bcf9d1..c9ef58c 100644 (file)
@@ -1,3 +1,118 @@
+2019-06-12  Youenn Fablet  <youenn@apple.com>
+
+        Use NSURLSession for WebSocket
+        https://bugs.webkit.org/show_bug.cgi?id=198568
+
+        Reviewed by Geoffrey Garen.
+
+        Implement socket channel provider on WebProcess level by sending IPC to NetworkProcess.
+        On NetworkProcess side, use NSURLSession API to implement the WebSocket functionality. 
+        This is a partial implementation:
+        - inspector integration is not working.
+        - some error cases are not well handled or are not producing the same error messages.
+        - some features are not implemented (extensions, subprotocols, handshake authentication challenge, cookie handling...).
+
+        * CMakeLists.txt:
+        * DerivedSources-input.xcfilelist:
+        * DerivedSources-output.xcfilelist:
+        * DerivedSources.make:
+        * NetworkProcess/NetworkConnectionToWebProcess.cpp:
+        (WebKit::NetworkConnectionToWebProcess::didReceiveMessage):
+        (WebKit::NetworkConnectionToWebProcess::createSocketChannel):
+        (WebKit::NetworkConnectionToWebProcess::removeSocketChannel):
+        * NetworkProcess/NetworkConnectionToWebProcess.h:
+        * NetworkProcess/NetworkConnectionToWebProcess.messages.in:
+        * NetworkProcess/NetworkSession.cpp:
+        (WebKit::NetworkSession::createWebSocketTask):
+        * NetworkProcess/NetworkSession.h:
+        (WebKit::NetworkSession::removeWebSocketTask):
+        (WebKit::NetworkSession::addWebSocketTask):
+        * NetworkProcess/NetworkSocketChannel.cpp: Added.
+        (WebKit::NetworkSocketChannel::create):
+        (WebKit::NetworkSocketChannel::NetworkSocketChannel):
+        (WebKit::NetworkSocketChannel::~NetworkSocketChannel):
+        (WebKit::NetworkSocketChannel::sendString):
+        (WebKit::NetworkSocketChannel::sendData):
+        (WebKit::NetworkSocketChannel::finishClosingIfPossible):
+        (WebKit::NetworkSocketChannel::close):
+        (WebKit::NetworkSocketChannel::didConnect):
+        (WebKit::NetworkSocketChannel::didReceiveText):
+        (WebKit::NetworkSocketChannel::didReceiveBinaryData):
+        (WebKit::NetworkSocketChannel::didClose):
+        (WebKit::NetworkSocketChannel::messageSenderConnection const):
+        * NetworkProcess/NetworkSocketChannel.h: Added.
+        * NetworkProcess/NetworkSocketChannel.messages.in: Added.
+        * NetworkProcess/NetworkSocketStream.messages.in:
+        * NetworkProcess/WebSocketTask.h: Added.
+        (WebKit::WebSocketTask::sendString):
+        (WebKit::WebSocketTask::sendData):
+        (WebKit::WebSocketTask::close):
+        (WebKit::WebSocketTask::cancel):
+        (WebKit::WebSocketTask::resume):
+        * NetworkProcess/cocoa/NetworkSessionCocoa.h:
+        * NetworkProcess/cocoa/NetworkSessionCocoa.mm:
+        (-[WKNetworkSessionDelegate existingWebSocketTask:]):
+        (-[WKNetworkSessionDelegate URLSession:webSocketTask:didOpenWithProtocol:]):
+        (-[WKNetworkSessionDelegate URLSession:webSocketTask:didCloseWithCode:reason:]):
+        (WebKit::NetworkSessionCocoa::continueDidReceiveChallenge):
+        (WebKit::NetworkSessionCocoa::createWebSocketTask):
+        (WebKit::NetworkSessionCocoa::addWebSocketTask):
+        (WebKit::NetworkSessionCocoa::removeWebSocketTask):
+        (WebKit::NetworkSessionCocoa::webSocketDataTaskForIdentifier):
+        * NetworkProcess/cocoa/WebSocketTaskCocoa.h: Added.
+        * NetworkProcess/cocoa/WebSocketTaskCocoa.mm: Added.
+        (WebKit::WebSocketTask::WebSocketTask):
+        (WebKit::WebSocketTask::~WebSocketTask):
+        (WebKit::WebSocketTask::readNextMessage):
+        (WebKit::WebSocketTask::cancel):
+        (WebKit::WebSocketTask::resume):
+        (WebKit::WebSocketTask::didConnect):
+        (WebKit::WebSocketTask::didClose):
+        (WebKit::WebSocketTask::sendString):
+        (WebKit::WebSocketTask::sendData):
+        (WebKit::WebSocketTask::close):
+        (WebKit::WebSocketTask::identifier const):
+        * Shared/WebPreferences.yaml:
+        * WebKit.xcodeproj/project.pbxproj:
+        * WebProcess/Network/NetworkProcessConnection.cpp:
+        (WebKit::NetworkProcessConnection::didReceiveMessage):
+        * WebProcess/Network/WebSocketChannel.cpp: Added.
+        (WebKit::WebSocketChannel::create):
+        (WebKit::WebSocketChannel::WebSocketChannel):
+        (WebKit::WebSocketChannel::~WebSocketChannel):
+        (WebKit::WebSocketChannel::messageSenderConnection const):
+        (WebKit::WebSocketChannel::messageSenderDestinationID const):
+        (WebKit::WebSocketChannel::subprotocol):
+        (WebKit::WebSocketChannel::extensions):
+        (WebKit::WebSocketChannel::connect):
+        (WebKit::WebSocketChannel::send):
+        (WebKit::WebSocketChannel::bufferedAmount const):
+        (WebKit::WebSocketChannel::close):
+        (WebKit::WebSocketChannel::fail):
+        (WebKit::WebSocketChannel::disconnect):
+        (WebKit::WebSocketChannel::didConnect):
+        (WebKit::WebSocketChannel::didReceiveText):
+        (WebKit::WebSocketChannel::didReceiveBinaryData):
+        (WebKit::WebSocketChannel::didClose):
+        (WebKit::WebSocketChannel::didFail):
+        (WebKit::WebSocketChannel::networkProcessCrashed):
+        * WebProcess/Network/WebSocketChannel.h: Added.
+        * WebProcess/Network/WebSocketChannel.messages.in: Added.
+        * WebProcess/Network/WebSocketChannelManager.cpp: Added.
+        (WebKit::WebSocketChannelManager::createWebSocketChannel):
+        (WebKit::WebSocketChannelManager::networkProcessCrashed):
+        (WebKit::WebSocketChannelManager::didReceiveMessage):
+        * WebProcess/Network/WebSocketChannelManager.h: Added.
+        * WebProcess/Network/WebSocketProvider.cpp:
+        (WebKit::WebSocketProvider::createWebSocketChannel):
+        * WebProcess/Network/WebSocketProvider.h:
+        * WebProcess/Network/WebSocketStream.cpp:
+        * WebProcess/Network/WebSocketStream.messages.in:
+        * WebProcess/WebProcess.cpp:
+        (WebKit::WebProcess::networkProcessConnectionClosed):
+        * WebProcess/WebProcess.h:
+        (WebKit::WebProcess::webSocketChannelManager):
+
 2019-06-12  Sihui Liu  <sihui_liu@apple.com>
 
         Add assertions to help debug crash at WebKit::HistoryEntryDataEncoder::operator<<
index e4f4b2b..0fb8423 100644 (file)
@@ -20,6 +20,7 @@ $(PROJECT_DIR)/NetworkProcess/NetworkConnectionToWebProcess.messages.in
 $(PROJECT_DIR)/NetworkProcess/NetworkContentRuleListManager.messages.in
 $(PROJECT_DIR)/NetworkProcess/NetworkProcess.messages.in
 $(PROJECT_DIR)/NetworkProcess/NetworkResourceLoader.messages.in
+$(PROJECT_DIR)/NetworkProcess/NetworkSocketChannel.messages.in
 $(PROJECT_DIR)/NetworkProcess/NetworkSocketStream.messages.in
 $(PROJECT_DIR)/NetworkProcess/ServiceWorker/ServiceWorkerFetchTask.messages.in
 $(PROJECT_DIR)/NetworkProcess/ServiceWorker/WebSWServerConnection.messages.in
@@ -95,6 +96,7 @@ $(PROJECT_DIR)/WebProcess/FullScreen/WebFullScreenManager.messages.in
 $(PROJECT_DIR)/WebProcess/Geolocation/WebGeolocationManager.messages.in
 $(PROJECT_DIR)/WebProcess/Network/NetworkProcessConnection.messages.in
 $(PROJECT_DIR)/WebProcess/Network/WebResourceLoader.messages.in
+$(PROJECT_DIR)/WebProcess/Network/WebSocketChannel.messages.in
 $(PROJECT_DIR)/WebProcess/Network/WebSocketStream.messages.in
 $(PROJECT_DIR)/WebProcess/Network/webrtc/WebMDNSRegister.messages.in
 $(PROJECT_DIR)/WebProcess/Network/webrtc/WebRTCMonitor.messages.in
index 426b867..fe0a6c0 100644 (file)
@@ -48,6 +48,8 @@ $(BUILT_PRODUCTS_DIR)/DerivedSources/WebKit2/NetworkRTCSocketMessageReceiver.cpp
 $(BUILT_PRODUCTS_DIR)/DerivedSources/WebKit2/NetworkRTCSocketMessages.h
 $(BUILT_PRODUCTS_DIR)/DerivedSources/WebKit2/NetworkResourceLoaderMessageReceiver.cpp
 $(BUILT_PRODUCTS_DIR)/DerivedSources/WebKit2/NetworkResourceLoaderMessages.h
+$(BUILT_PRODUCTS_DIR)/DerivedSources/WebKit2/NetworkSocketChannelMessageReceiver.cpp
+$(BUILT_PRODUCTS_DIR)/DerivedSources/WebKit2/NetworkSocketChannelMessages.h
 $(BUILT_PRODUCTS_DIR)/DerivedSources/WebKit2/NetworkSocketStreamMessageReceiver.cpp
 $(BUILT_PRODUCTS_DIR)/DerivedSources/WebKit2/NetworkSocketStreamMessages.h
 $(BUILT_PRODUCTS_DIR)/DerivedSources/WebKit2/PlaybackSessionManagerMessageReceiver.cpp
@@ -192,6 +194,8 @@ $(BUILT_PRODUCTS_DIR)/DerivedSources/WebKit2/WebSWServerConnectionMessageReceive
 $(BUILT_PRODUCTS_DIR)/DerivedSources/WebKit2/WebSWServerConnectionMessages.h
 $(BUILT_PRODUCTS_DIR)/DerivedSources/WebKit2/WebSWServerToContextConnectionMessageReceiver.cpp
 $(BUILT_PRODUCTS_DIR)/DerivedSources/WebKit2/WebSWServerToContextConnectionMessages.h
+$(BUILT_PRODUCTS_DIR)/DerivedSources/WebKit2/WebSocketChannelMessageReceiver.cpp
+$(BUILT_PRODUCTS_DIR)/DerivedSources/WebKit2/WebSocketChannelMessages.h
 $(BUILT_PRODUCTS_DIR)/DerivedSources/WebKit2/WebSocketStreamMessageReceiver.cpp
 $(BUILT_PRODUCTS_DIR)/DerivedSources/WebKit2/WebSocketStreamMessages.h
 $(BUILT_PRODUCTS_DIR)/DerivedSources/WebKit2/WebUserContentControllerMessageReceiver.cpp
index c11b3f8..5393c5b 100644 (file)
@@ -116,6 +116,7 @@ MESSAGE_RECEIVERS = \
     NetworkRTCProvider \
     NetworkRTCSocket \
     NetworkResourceLoader \
+    NetworkSocketChannel \
     NetworkSocketStream \
     PlaybackSessionManager \
     PlaybackSessionManagerProxy \
@@ -182,6 +183,7 @@ MESSAGE_RECEIVERS = \
     WebSWContextManagerConnection \
     WebSWServerConnection \
     WebSWServerToContextConnection \
+    WebSocketChannel \
     WebSocketStream \
     WebUserContentController \
     WebUserContentControllerProxy \
index 92c8b7a..560e6fd 100644 (file)
@@ -41,6 +41,8 @@
 #include "NetworkResourceLoader.h"
 #include "NetworkResourceLoaderMessages.h"
 #include "NetworkSession.h"
+#include "NetworkSocketChannel.h"
+#include "NetworkSocketChannelMessages.h"
 #include "NetworkSocketStream.h"
 #include "NetworkSocketStreamMessages.h"
 #include "PingLoad.h"
@@ -157,6 +159,12 @@ void NetworkConnectionToWebProcess::didReceiveMessage(IPC::Connection& connectio
         return;
     }
 
+    if (decoder.messageReceiverName() == Messages::NetworkSocketChannel::messageReceiverName()) {
+        if (auto* channel = m_networkSocketChannels.get(decoder.destinationID()))
+            channel->didReceiveMessage(connection, decoder);
+        return;
+    }
+
     if (decoder.messageReceiverName() == Messages::NetworkProcess::messageReceiverName()) {
         m_networkProcess->didReceiveNetworkProcessMessage(connection, decoder);
         return;
@@ -347,10 +355,17 @@ void NetworkConnectionToWebProcess::createSocketStream(URL&& url, PAL::SessionID
     m_networkSocketStreams.set(identifier, NetworkSocketStream::create(m_networkProcess.get(), WTFMove(url), sessionID, cachePartition, identifier, m_connection, WTFMove(token)));
 }
 
-void NetworkConnectionToWebProcess::destroySocketStream(uint64_t identifier)
+void NetworkConnectionToWebProcess::createSocketChannel(PAL::SessionID sessionID, const ResourceRequest& request, const String& protocol, uint64_t identifier)
+{
+    ASSERT(!m_networkSocketChannels.contains(identifier));
+    if (auto channel = NetworkSocketChannel::create(*this, sessionID, request, protocol, identifier))
+        m_networkSocketChannels.add(identifier, WTFMove(channel));
+}
+
+void NetworkConnectionToWebProcess::removeSocketChannel(uint64_t identifier)
 {
-    ASSERT(m_networkSocketStreams.get(identifier));
-    m_networkSocketStreams.remove(identifier);
+    ASSERT(m_networkSocketChannels.contains(identifier));
+    m_networkSocketChannels.remove(identifier);
 }
 
 void NetworkConnectionToWebProcess::cleanupForSuspension(Function<void()>&& completionHandler)
index ae9f5db..c0bafe8 100644 (file)
@@ -60,6 +60,7 @@ namespace WebKit {
 
 class NetworkProcess;
 class NetworkResourceLoader;
+class NetworkSocketChannel;
 class NetworkSocketStream;
 class WebIDBConnectionToClient;
 class WebSWServerConnection;
@@ -149,6 +150,8 @@ public:
     void webPageWasRemoved(PAL::SessionID, WebCore::PageIdentifier);
     void webProcessSessionChanged(PAL::SessionID newSessionID, const Vector<WebCore::PageIdentifier>& pages);
 
+    void removeSocketChannel(uint64_t identifier);
+
 private:
     NetworkConnectionToWebProcess(NetworkProcess&, IPC::Connection::Identifier);
 
@@ -195,8 +198,9 @@ private:
     void setCaptureExtraNetworkLoadMetricsEnabled(bool);
 
     void createSocketStream(URL&&, PAL::SessionID, String cachePartition, uint64_t);
-    void destroySocketStream(uint64_t);
-    
+
+    void createSocketChannel(PAL::SessionID, const WebCore::ResourceRequest&, const String& protocol, uint64_t identifier);
+
     void ensureLegacyPrivateBrowsingSession();
 
 #if ENABLE(INDEXED_DATABASE)
@@ -284,6 +288,7 @@ private:
     Ref<NetworkProcess> m_networkProcess;
 
     HashMap<uint64_t, RefPtr<NetworkSocketStream>> m_networkSocketStreams;
+    HashMap<uint64_t, std::unique_ptr<NetworkSocketChannel>> m_networkSocketChannels;
     NetworkResourceLoadMap m_networkResourceLoaders;
     HashMap<String, RefPtr<WebCore::BlobDataFileReference>> m_blobDataFileReferences;
     Vector<ResourceNetworkActivityTracker> m_networkActivityTrackers;
index 833e74f..22077ea 100644 (file)
@@ -52,6 +52,7 @@ messages -> NetworkConnectionToWebProcess LegacyReceiver {
     SetCaptureExtraNetworkLoadMetricsEnabled(bool enabled)
 
     CreateSocketStream(URL url, PAL::SessionID sessionID, String cachePartition, uint64_t identifier)
+    CreateSocketChannel(PAL::SessionID sessionID, WebCore::ResourceRequest request, String protocol, uint64_t identifier)
 
     EnsureLegacyPrivateBrowsingSession()
 
index 1d0a8ab..3544fa4 100644 (file)
@@ -36,6 +36,8 @@
 #include "WebPageProxy.h"
 #include "WebPageProxyMessages.h"
 #include "WebProcessProxy.h"
+#include "WebSocketTask.h"
+#include <WebCore/AdClickAttribution.h>
 #include <WebCore/CookieJar.h>
 #include <WebCore/NetworkStorageSession.h>
 #include <WebCore/ResourceRequest.h>
@@ -204,4 +206,9 @@ void NetworkSession::removeKeptAliveLoad(NetworkResourceLoader& loader)
     m_keptAliveLoads.remove(loader);
 }
 
+std::unique_ptr<WebSocketTask> NetworkSession::createWebSocketTask(NetworkSocketChannel&, const WebCore::ResourceRequest&, const String& protocol)
+{
+    return nullptr;
+}
+
 } // namespace WebKit
index 8ca7e31..f9d22ab 100644 (file)
@@ -53,7 +53,9 @@ class NetworkDataTask;
 class NetworkProcess;
 class NetworkResourceLoader;
 class StorageManager;
+class NetworkSocketChannel;
 class WebResourceLoadStatisticsStore;
+class WebSocketTask;
 struct NetworkSessionCreationParameters;
 
 enum class WebsiteDataType;
@@ -101,6 +103,10 @@ public:
     PrefetchCache& prefetchCache() { return m_prefetchCache; }
     void clearPrefetchCache() { m_prefetchCache.clear(); }
 
+    virtual std::unique_ptr<WebSocketTask> createWebSocketTask(NetworkSocketChannel&, const WebCore::ResourceRequest&, const String& protocol);
+    virtual void removeWebSocketTask(WebSocketTask&) { }
+    virtual void addWebSocketTask(WebSocketTask&) { }
+
 protected:
     NetworkSession(NetworkProcess&, PAL::SessionID, const String& localStorageDirectory, SandboxExtension::Handle&);
 
diff --git a/Source/WebKit/NetworkProcess/NetworkSocketChannel.cpp b/Source/WebKit/NetworkProcess/NetworkSocketChannel.cpp
new file mode 100644 (file)
index 0000000..9483ada
--- /dev/null
@@ -0,0 +1,125 @@
+/*
+ * Copyright (C) 2019 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "NetworkSocketChannel.h"
+
+#include "DataReference.h"
+#include "NetworkConnectionToWebProcess.h"
+#include "NetworkProcess.h"
+#include "NetworkSession.h"
+#include "WebSocketChannelMessages.h"
+#include "WebSocketTask.h"
+
+namespace WebKit {
+using namespace WebCore;
+
+std::unique_ptr<NetworkSocketChannel> NetworkSocketChannel::create(NetworkConnectionToWebProcess& connection, PAL::SessionID sessionID, const ResourceRequest& request, const String& protocol, uint64_t identifier)
+{
+    auto result = std::make_unique<NetworkSocketChannel>(connection, connection.networkProcess().networkSession(sessionID), request, protocol, identifier);
+    if (!result->m_socket) {
+        result->didClose(0, "Cannot create a web socket task"_s);
+        return nullptr;
+    }
+    return result;
+}
+
+NetworkSocketChannel::NetworkSocketChannel(NetworkConnectionToWebProcess& connection, RefPtr<NetworkSession>&& session, const ResourceRequest& request, const String& protocol, uint64_t identifier)
+    : m_connectionToWebProcess(connection)
+    , m_identifier(identifier)
+    , m_session(WTFMove(session))
+{
+    if (!m_session)
+        return;
+
+    m_socket = m_session->createWebSocketTask(*this, request, protocol);
+
+    m_session->addWebSocketTask(*m_socket);
+    m_socket->resume();
+}
+
+NetworkSocketChannel::~NetworkSocketChannel()
+{
+    if (!m_socket)
+        return;
+
+    m_socket->cancel();
+    m_session->removeWebSocketTask(*m_socket);
+}
+
+void NetworkSocketChannel::sendString(const String& message, CompletionHandler<void()>&& callback)
+{
+    m_socket->sendString(message, WTFMove(callback));
+}
+
+void NetworkSocketChannel::sendData(const IPC::DataReference& data, CompletionHandler<void()>&& callback)
+{
+    m_socket->sendData(data, WTFMove(callback));
+}
+
+void NetworkSocketChannel::finishClosingIfPossible()
+{
+    if (m_state == State::Open) {
+        m_state = State::Closing;
+        return;
+    }
+    ASSERT(m_state == State::Closing);
+    m_state = State::Closed;
+    m_connectionToWebProcess.removeSocketChannel(m_identifier);
+}
+
+void NetworkSocketChannel::close(int32_t code, const String& reason)
+{
+    m_socket->close(code, reason);
+    finishClosingIfPossible();
+}
+
+void NetworkSocketChannel::didConnect()
+{
+    send(Messages::WebSocketChannel::DidConnect { });
+}
+
+void NetworkSocketChannel::didReceiveText(const String& text)
+{
+    send(Messages::WebSocketChannel::DidReceiveText { text });
+}
+
+void NetworkSocketChannel::didReceiveBinaryData(const uint8_t* data, size_t length)
+{
+    send(Messages::WebSocketChannel::DidReceiveBinaryData { { data, length } });
+}
+
+void NetworkSocketChannel::didClose(unsigned short code, const String& reason)
+{
+    send(Messages::WebSocketChannel::DidClose { code, reason });
+    finishClosingIfPossible();
+}
+
+IPC::Connection* NetworkSocketChannel::messageSenderConnection() const
+{
+    return &m_connectionToWebProcess.connection();
+}
+
+} // namespace WebKit
diff --git a/Source/WebKit/NetworkProcess/NetworkSocketChannel.h b/Source/WebKit/NetworkProcess/NetworkSocketChannel.h
new file mode 100644 (file)
index 0000000..d076937
--- /dev/null
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2019 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include "MessageReceiver.h"
+#include "MessageSender.h"
+#include <pal/SessionID.h>
+#include <wtf/CompletionHandler.h>
+
+namespace WebCore {
+class ResourceRequest;
+}
+
+namespace IPC {
+class Connection;
+class Decoder;
+class DataReference;
+}
+
+namespace WebKit {
+
+class WebSocketTask;
+class NetworkConnectionToWebProcess;
+class NetworkProcess;
+class NetworkSession;
+
+class NetworkSocketChannel : public IPC::MessageSender, public IPC::MessageReceiver {
+public:
+    static std::unique_ptr<NetworkSocketChannel> create(NetworkConnectionToWebProcess&, PAL::SessionID, const WebCore::ResourceRequest&, const String& protocol, uint64_t identifier);
+
+    NetworkSocketChannel(NetworkConnectionToWebProcess&, RefPtr<NetworkSession>&&, const WebCore::ResourceRequest&, const String& protocol, uint64_t identifier);
+    ~NetworkSocketChannel();
+
+    void didReceiveMessage(IPC::Connection&, IPC::Decoder&);
+
+    friend class WebSocketTask;
+
+private:
+    void didConnect();
+    void didReceiveText(const String&);
+    void didReceiveBinaryData(const uint8_t* data, size_t length);
+    void didClose(unsigned short code, const String& reason);
+
+    void sendString(const String&, CompletionHandler<void()>&&);
+    void sendData(const IPC::DataReference&, CompletionHandler<void()>&&);
+    void close(int32_t code, const String& reason);
+
+    IPC::Connection* messageSenderConnection() const final;
+    uint64_t messageSenderDestinationID() const final { return m_identifier; }
+
+    void finishClosingIfPossible();
+
+    NetworkConnectionToWebProcess& m_connectionToWebProcess;
+    uint64_t m_identifier;
+    RefPtr<NetworkSession> m_session;
+    std::unique_ptr<WebSocketTask> m_socket;
+
+    enum class State { Open, Closing, Closed };
+    State m_state { State::Open };
+};
+
+} // namespace WebKit
diff --git a/Source/WebKit/NetworkProcess/NetworkSocketChannel.messages.in b/Source/WebKit/NetworkProcess/NetworkSocketChannel.messages.in
new file mode 100644 (file)
index 0000000..7de834d
--- /dev/null
@@ -0,0 +1,27 @@
+# Copyright (C) 2019 Apple Inc. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1.  Redistributions of source code must retain the above copyright
+#     notice, this list of conditions and the following disclaimer.
+# 2.  Redistributions in binary form must reproduce the above copyright
+#     notice, this list of conditions and the following disclaimer in the
+#     documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR
+# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+messages -> NetworkSocketChannel {
+    SendString(String message) -> () Async
+    SendData(IPC::DataReference data) -> () Async
+    Close(int32_t code, String reason)
+}
diff --git a/Source/WebKit/NetworkProcess/WebSocketTask.h b/Source/WebKit/NetworkProcess/WebSocketTask.h
new file mode 100644 (file)
index 0000000..939f601
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2019 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#if PLATFORM(COCOA) && HAVE(NSURLSESSION_WEBSOCKET)
+#include "WebSocketTaskCocoa.h"
+#else
+
+namespace WebKit {
+
+class WebSocketTask {
+public:
+    typedef uint64_t TaskIdentifier;
+
+    void sendString(const String&, CompletionHandler<void()>&&) { }
+    void sendData(const IPC::DataReference&, CompletionHandler<void()>&&) { }
+    void close(int32_t code, const String& reason) { }
+
+    void cancel() { }
+    void resume() { }
+};
+
+} // namespace WebKit
+
+#endif
index b144a1f..3e13770 100644 (file)
@@ -31,10 +31,12 @@ OBJC_CLASS NSURLSession;
 OBJC_CLASS NSURLSessionDownloadTask;
 OBJC_CLASS NSOperationQueue;
 OBJC_CLASS WKNetworkSessionDelegate;
+OBJC_CLASS WKNetworkSessionWebSocketDelegate;
 
 #include "DownloadID.h"
 #include "NetworkDataTaskCocoa.h"
 #include "NetworkSession.h"
+#include "WebSocketTask.h"
 #include <WebCore/NetworkLoadMetrics.h>
 #include <wtf/HashMap.h>
 
@@ -63,6 +65,8 @@ public:
     NetworkDataTaskCocoa* dataTaskForIdentifier(NetworkDataTaskCocoa::TaskIdentifier, WebCore::StoredCredentialsPolicy);
     NSURLSessionDownloadTask* downloadTaskWithResumeData(NSData*);
 
+    WebSocketTask* webSocketDataTaskForIdentifier(WebSocketTask::TaskIdentifier);
+
     void addDownloadID(NetworkDataTaskCocoa::TaskIdentifier, DownloadID);
     DownloadID downloadID(NetworkDataTaskCocoa::TaskIdentifier);
     DownloadID takeDownloadID(NetworkDataTaskCocoa::TaskIdentifier);
@@ -83,10 +87,19 @@ private:
     bool shouldLogCookieInformation() const override { return m_shouldLogCookieInformation; }
     Seconds loadThrottleLatency() const override { return m_loadThrottleLatency; }
 
+#if HAVE(NSURLSESSION_WEBSOCKET)
+    std::unique_ptr<WebSocketTask> createWebSocketTask(NetworkSocketChannel&, const WebCore::ResourceRequest&, const String& protocol) final;
+    void addWebSocketTask(WebSocketTask&) final;
+    void removeWebSocketTask(WebSocketTask&) final;
+#endif
+
     HashMap<NetworkDataTaskCocoa::TaskIdentifier, NetworkDataTaskCocoa*> m_dataTaskMapWithCredentials;
     HashMap<NetworkDataTaskCocoa::TaskIdentifier, NetworkDataTaskCocoa*> m_dataTaskMapWithoutState;
     HashMap<NetworkDataTaskCocoa::TaskIdentifier, NetworkDataTaskCocoa*> m_dataTaskMapEphemeralStatelessCookieless;
     HashMap<NetworkDataTaskCocoa::TaskIdentifier, DownloadID> m_downloadMap;
+#if HAVE(NSURLSESSION_WEBSOCKET)
+    HashMap<NetworkDataTaskCocoa::TaskIdentifier, WebSocketTask*> m_webSocketDataTaskMap;
+#endif
 
     RetainPtr<NSURLSession> m_sessionWithCredentialStorage;
     RetainPtr<WKNetworkSessionDelegate> m_sessionWithCredentialStorageDelegate;
index 2aec543..26250d6 100644 (file)
@@ -35,6 +35,7 @@
 #import "NetworkLoad.h"
 #import "NetworkProcess.h"
 #import "NetworkSessionCreationParameters.h"
+#import "WebSocketTask.h"
 #import <Foundation/NSURLSession.h>
 #import <WebCore/Credential.h>
 #import <WebCore/FormDataStreamMac.h>
@@ -323,7 +324,11 @@ static String stringForSSLCipher(SSLCipherSuite cipher)
 }
 #endif
 
-@interface WKNetworkSessionDelegate : NSObject <NSURLSessionDataDelegate> {
+@interface WKNetworkSessionDelegate : NSObject <NSURLSessionDataDelegate
+#if HAVE(NSURLSESSION_WEBSOCKET)
+    , NSURLSessionWebSocketDelegate
+#endif
+> {
     RefPtr<WebKit::NetworkSessionCocoa> _session;
     bool _withCredentials;
 }
@@ -807,6 +812,34 @@ static inline void processServerTrustEvaluation(NetworkSessionCocoa *session, NS
     }
 }
 
+#if HAVE(NSURLSESSION_WEBSOCKET)
+- (WebSocketTask*)existingWebSocketTask:(NSURLSessionWebSocketTask *)task
+{
+    if (!_session)
+        return nullptr;
+
+    if (!task)
+        return nullptr;
+
+    return _session->webSocketDataTaskForIdentifier(task.taskIdentifier);
+}
+
+
+- (void)URLSession:(NSURLSession *)session webSocketTask:(NSURLSessionWebSocketTask *)task didOpenWithProtocol:(NSString *) protocol
+{
+    if (auto* webSocketTask = [self existingWebSocketTask:task])
+        webSocketTask->didConnect();
+}
+
+- (void)URLSession:(NSURLSession *)session webSocketTask:(NSURLSessionWebSocketTask *)task didCloseWithCode:(NSURLSessionWebSocketCloseCode)closeCode reason:(NSData *)reason
+{
+    if (auto* webSocketTask = [self existingWebSocketTask:task]) {
+        auto reason = adoptNS([[NSString alloc] initWithData:[task closeReason] encoding:NSUTF8StringEncoding]);
+        webSocketTask->didClose(closeCode, reason.get());
+    }
+}
+#endif
+
 @end
 
 namespace WebKit {
@@ -1141,6 +1174,14 @@ bool NetworkSessionCocoa::allowsSpecificHTTPSCertificateForHost(const WebCore::A
 void NetworkSessionCocoa::continueDidReceiveChallenge(const WebCore::AuthenticationChallenge& challenge, NetworkDataTaskCocoa::TaskIdentifier taskIdentifier, NetworkDataTaskCocoa* networkDataTask, CompletionHandler<void(WebKit::AuthenticationChallengeDisposition, const WebCore::Credential&)>&& completionHandler)
 {
     if (!networkDataTask) {
+#if HAVE(NSURLSESSION_WEBSOCKET)
+        if (auto* webSocketTask = webSocketDataTaskForIdentifier(taskIdentifier)) {
+            // FIXME: Handle challenges for web socket.
+            completionHandler(AuthenticationChallengeDisposition::PerformDefaultHandling, { });
+            return;
+        }
+#endif
+
         auto downloadID = this->downloadID(taskIdentifier);
         if (downloadID.downloadID()) {
             if (auto* download = networkProcess().downloadManager().download(downloadID)) {
@@ -1199,4 +1240,30 @@ DMFWebsitePolicyMonitor *NetworkSessionCocoa::deviceManagementPolicyMonitor()
 #endif
 }
 
+#if HAVE(NSURLSESSION_WEBSOCKET)
+std::unique_ptr<WebSocketTask> NetworkSessionCocoa::createWebSocketTask(NetworkSocketChannel& channel, const WebCore::ResourceRequest& request, const String& protocol)
+{
+    // FIXME: Use protocol.
+    RetainPtr<NSURLSessionWebSocketTask> task = [m_sessionWithCredentialStorage.get() webSocketTaskWithRequest: request.nsURLRequest(WebCore::HTTPBodyUpdatePolicy::DoNotUpdateHTTPBody)];
+    return std::make_unique<WebSocketTask>(channel, WTFMove(task));
+}
+
+void NetworkSessionCocoa::addWebSocketTask(WebSocketTask& task)
+{
+    ASSERT(!m_webSocketDataTaskMap.contains(task.identifier()));
+    m_webSocketDataTaskMap.add(task.identifier(), &task);
+}
+
+void NetworkSessionCocoa::removeWebSocketTask(WebSocketTask& task)
+{
+    ASSERT(m_webSocketDataTaskMap.contains(task.identifier()));
+    m_webSocketDataTaskMap.remove(task.identifier());
+}
+
+WebSocketTask* NetworkSessionCocoa::webSocketDataTaskForIdentifier(WebSocketTask::TaskIdentifier identifier)
+{
+    return m_webSocketDataTaskMap.get(identifier);
+}
+
+#endif
 }
diff --git a/Source/WebKit/NetworkProcess/cocoa/WebSocketTaskCocoa.h b/Source/WebKit/NetworkProcess/cocoa/WebSocketTaskCocoa.h
new file mode 100644 (file)
index 0000000..852fe52
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2019 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#if HAVE(NSURLSESSION_WEBSOCKET)
+
+#include <wtf/RetainPtr.h>
+#include <wtf/WeakPtr.h>
+
+OBJC_CLASS NSURLSessionWebSocketTask;
+
+namespace IPC {
+class DataReference;
+}
+
+namespace WebKit {
+class NetworkSession;
+class NetworkSocketChannel;
+
+class WebSocketTask : public CanMakeWeakPtr<WebSocketTask> {
+public:
+    WebSocketTask(NetworkSocketChannel&, RetainPtr<NSURLSessionWebSocketTask>&&);
+    ~WebSocketTask();
+
+    void sendString(const String&, CompletionHandler<void()>&&);
+    void sendData(const IPC::DataReference&, CompletionHandler<void()>&&);
+    void close(int32_t code, const String& reason);
+
+    void didConnect();
+    void didClose(unsigned short code, const String& reason);
+
+    void cancel();
+    void resume();
+
+    typedef uint64_t TaskIdentifier;
+    TaskIdentifier identifier() const;
+
+private:
+    void readNextMessage();
+
+    NetworkSocketChannel& m_channel;
+    RetainPtr<NSURLSessionWebSocketTask> m_task;
+    bool m_receivedDidClose { false };
+};
+
+} // namespace WebKit
+
+#endif
diff --git a/Source/WebKit/NetworkProcess/cocoa/WebSocketTaskCocoa.mm b/Source/WebKit/NetworkProcess/cocoa/WebSocketTaskCocoa.mm
new file mode 100644 (file)
index 0000000..2f167d3
--- /dev/null
@@ -0,0 +1,132 @@
+/*
+ * Copyright (C) 2016-2018 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#import "config.h"
+#import "WebSocketTaskCocoa.h"
+
+#if HAVE(NSURLSESSION_WEBSOCKET)
+
+#import "DataReference.h"
+#import "NetworkSocketChannel.h"
+#import <Foundation/NSURLSession.h>
+#import <WebCore/WebSocketChannel.h>
+#import <wtf/BlockPtr.h>
+
+namespace WebKit {
+
+WebSocketTask::WebSocketTask(NetworkSocketChannel& channel, RetainPtr<NSURLSessionWebSocketTask>&& task)
+    : m_channel(channel)
+    , m_task(WTFMove(task))
+{
+    readNextMessage();
+}
+
+WebSocketTask::~WebSocketTask()
+{
+}
+
+void WebSocketTask::readNextMessage()
+{
+    [m_task receiveMessageWithCompletionHandler: makeBlockPtr([this, weakThis = makeWeakPtr(this)](NSURLSessionWebSocketMessage* _Nullable message, NSError * _Nullable error) {
+        if (!weakThis)
+            return;
+
+        if (error) {
+            // FIXME: the error code is probably not a correct WebSocket code.
+            didClose([error code], [error localizedDescription]);
+            return;
+        }
+        if (!message) {
+            // FIXME: this is a workaround and we should probably never get there.
+            didClose(1000, "Unknown error");
+            return;
+        }
+        if (message.type == NSURLSessionWebSocketMessageTypeString)
+            m_channel.didReceiveText(message.string);
+        else
+            m_channel.didReceiveBinaryData(static_cast<const uint8_t*>(message.data.bytes), message.data.length);
+
+        readNextMessage();
+    }).get()];
+}
+
+void WebSocketTask::cancel()
+{
+    [m_task cancel];
+}
+
+void WebSocketTask::resume()
+{
+    [m_task resume];
+}
+
+void WebSocketTask::didConnect()
+{
+    m_channel.didConnect();
+}
+
+void WebSocketTask::didClose(unsigned short code, const String& reason)
+{
+    if (m_receivedDidClose)
+        return;
+
+    m_receivedDidClose = true;
+    m_channel.didClose(code, reason);
+}
+
+void WebSocketTask::sendString(const String& text , CompletionHandler<void()>&& callback)
+{
+    auto message = adoptNS([[NSURLSessionWebSocketMessage alloc] initWithString: text]);
+    [m_task sendMessage: message.get() completionHandler: makeBlockPtr([callback = WTFMove(callback)](NSError * _Nullable) mutable {
+        callback();
+    }).get()];
+}
+
+void WebSocketTask::sendData(const IPC::DataReference& data, CompletionHandler<void()>&& callback)
+{
+    auto nsData = adoptNS([[NSData alloc] initWithBytes:data.data() length:data.size()]);
+    auto message = adoptNS([[NSURLSessionWebSocketMessage alloc] initWithData: nsData.get()]);
+    [m_task sendMessage: message.get() completionHandler: makeBlockPtr([callback = WTFMove(callback)](NSError * _Nullable) mutable {
+        callback();
+    }).get()];
+}
+
+void WebSocketTask::close(int32_t code, const String& reason)
+{
+    // FIXME: Should NSURLSession provide a way to call cancelWithCloseCode without any specific code.
+    if (code == WebCore::WebSocketChannel::CloseEventCodeNotSpecified)
+        code = 1005;
+    auto nsData = adoptNS([[NSData alloc] initWithBytes:reason.utf8().data() length:reason.sizeInBytes()]);
+    [m_task cancelWithCloseCode: (NSURLSessionWebSocketCloseCode)code reason: nsData.get()];
+}
+
+WebSocketTask::TaskIdentifier WebSocketTask::identifier() const
+{
+    return [m_task taskIdentifier];
+}
+
+}
+
+#endif
index 5ec408b..11794c8 100644 (file)
@@ -1695,6 +1695,15 @@ LinkPreloadResponsiveImagesEnabled:
   webcoreBinding: RuntimeEnabledFeatures
   category: experimental
 
+IsNSURLSessionWebSocketEnabled:
+  type: bool
+  defaultValue: false
+  humanReadableName: "NSURLSession WebSocket"
+  humanReadableDescription: "Use NSURLSession WebSocket API"
+  category: internal
+  webcoreBinding: RuntimeEnabledFeatures
+  condition: HAVE(NSURLSESSION_WEBSOCKET)
+
 # Deprecated
 
 ICECandidateFilteringEnabled:
index 4a6ab5e..2d77ea0 100644 (file)
@@ -39,6 +39,7 @@ NetworkProcess/NetworkResourceLoadMap.cpp
 NetworkProcess/NetworkResourceLoader.cpp
 NetworkProcess/NetworkSession.cpp
 NetworkProcess/NetworkSessionCreationParameters.cpp
+NetworkProcess/NetworkSocketChannel.cpp
 NetworkProcess/NetworkSocketStream.cpp
 NetworkProcess/PingLoad.cpp
 NetworkProcess/PreconnectTask.cpp
@@ -482,6 +483,8 @@ WebProcess/MediaStream/UserMediaPermissionRequestManager.cpp
 WebProcess/Network/NetworkProcessConnection.cpp
 WebProcess/Network/WebLoaderStrategy.cpp
 WebProcess/Network/WebResourceLoader.cpp
+WebProcess/Network/WebSocketChannel.cpp
+WebProcess/Network/WebSocketChannelManager.cpp
 WebProcess/Network/WebSocketProvider.cpp
 WebProcess/Network/WebSocketStream.cpp
 
index 8d4e044..fbad27d 100644 (file)
@@ -420,7 +420,7 @@ WebProcess/WebPage/gtk/WebInspectorUIGtk.cpp
 WebProcess/WebPage/gtk/WebPageGtk.cpp
 WebProcess/WebPage/gtk/WebPrintOperationGtk.cpp
 
-WebProcess/WebPage/libwpe/AcceleratedSurfaceLibWPE.cpp
+WebProcess/WebPage/libwpe/AcceleratedSurfaceLibWPE.cpp @no-unify
 
 WebProcess/glib/WebProcessGLib.cpp
 
index 4bd2d8e..5878a14 100644 (file)
                31BA924E148831260062EDB5 /* WebNotificationManagerMessages.h in Headers */ = {isa = PBXBuildFile; fileRef = 31BA9249148830810062EDB5 /* WebNotificationManagerMessages.h */; };
                31D5929F166E060000E6BF02 /* WebPlugInClient.h in Headers */ = {isa = PBXBuildFile; fileRef = 31D5929D166E060000E6BF02 /* WebPlugInClient.h */; };
                31D755C11D91B81500843BD1 /* WKTextChecker.h in Headers */ = {isa = PBXBuildFile; fileRef = 314888FF1D91B11D00377042 /* WKTextChecker.h */; settings = {ATTRIBUTES = (Private, ); }; };
+               31F060E11654318500F3281C /* NetworkSocketChannelMessageReceiver.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 31F060DD1654317500F3281C /* NetworkSocketChannelMessageReceiver.cpp */; };
                330934471315B9220097A7BC /* WebCookieManagerMessageReceiver.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 330934431315B9220097A7BC /* WebCookieManagerMessageReceiver.cpp */; };
                330934481315B9220097A7BC /* WebCookieManagerMessages.h in Headers */ = {isa = PBXBuildFile; fileRef = 330934441315B9220097A7BC /* WebCookieManagerMessages.h */; };
                330934491315B9220097A7BC /* WebCookieManagerProxyMessageReceiver.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 330934451315B9220097A7BC /* WebCookieManagerProxyMessageReceiver.cpp */; };
                4112EDE020E407A500BEA92A /* com.ftsafe.NPAPI-Core-Safe-SoftKeybaord.plugin.rfc1034identifier.sb in Copy Plug-in Sandbox Profiles */ = {isa = PBXBuildFile; fileRef = 4112EDD220E4077300BEA92A /* com.ftsafe.NPAPI-Core-Safe-SoftKeybaord.plugin.rfc1034identifier.sb */; };
                411A8DDB20DDD1AC0060D34F /* WKMockMediaDevice.h in Headers */ = {isa = PBXBuildFile; fileRef = 411A8DD920DDB6050060D34F /* WKMockMediaDevice.h */; settings = {ATTRIBUTES = (Private, ); }; };
                411B22641E371BA6004F7363 /* LibWebRTCNetwork.h in Headers */ = {isa = PBXBuildFile; fileRef = 411B22621E371244004F7363 /* LibWebRTCNetwork.h */; };
+               41287D4E225D1ECB009A3E26 /* WebSocketTaskCocoa.mm in Sources */ = {isa = PBXBuildFile; fileRef = 41287D4B225C05C4009A3E26 /* WebSocketTaskCocoa.mm */; };
                413075AB1DE85F330039EC69 /* NetworkRTCSocket.h in Headers */ = {isa = PBXBuildFile; fileRef = 413075991DE84FB00039EC69 /* NetworkRTCSocket.h */; };
                413075AC1DE85F370039EC69 /* NetworkRTCMonitor.h in Headers */ = {isa = PBXBuildFile; fileRef = 4130759B1DE84FB00039EC69 /* NetworkRTCMonitor.h */; };
                413075AD1DE85F580039EC69 /* LibWebRTCSocket.h in Headers */ = {isa = PBXBuildFile; fileRef = 413075A01DE85EE70039EC69 /* LibWebRTCSocket.h */; };
                414DD37A20BF49A5006959FB /* com.cisco.webex.plugin.gpc64.sb in Copy Plug-in Sandbox Profiles */ = {isa = PBXBuildFile; fileRef = 414DD37820BF43EA006959FB /* com.cisco.webex.plugin.gpc64.sb */; };
                414DEDD71F9EDDE50047C40D /* ServiceWorkerProcessProxy.h in Headers */ = {isa = PBXBuildFile; fileRef = 414DEDD51F9EDDDF0047C40D /* ServiceWorkerProcessProxy.h */; };
                4157E4B020E2ECDF00A6C0D7 /* com.google.o1dbrowserplugin.sb in Copy Plug-in Sandbox Profiles */ = {isa = PBXBuildFile; fileRef = 4157E4AF20E2EC9800A6C0D7 /* com.google.o1dbrowserplugin.sb */; };
+               417915AF2256BB7500D6F97E /* WebSocketChannel.h in Headers */ = {isa = PBXBuildFile; fileRef = 417915AD2256BB7400D6F97E /* WebSocketChannel.h */; };
+               417915B12256C0D600D6F97E /* WebSocketChannelManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 417915B02256C0D600D6F97E /* WebSocketChannelManager.h */; };
+               417915B92257046F00D6F97E /* NetworkSocketChannel.h in Headers */ = {isa = PBXBuildFile; fileRef = 417915B62257046E00D6F97E /* NetworkSocketChannel.h */; };
                41897ED11F415D680016FA42 /* WebCacheStorageConnection.h in Headers */ = {isa = PBXBuildFile; fileRef = 41897ECD1F415D5C0016FA42 /* WebCacheStorageConnection.h */; };
                41897ED81F415D8A0016FA42 /* CacheStorageEngine.h in Headers */ = {isa = PBXBuildFile; fileRef = 41897ED21F415D850016FA42 /* CacheStorageEngine.h */; };
                41897EDA1F415D8A0016FA42 /* CacheStorageEngineConnection.h in Headers */ = {isa = PBXBuildFile; fileRef = 41897ED41F415D850016FA42 /* CacheStorageEngineConnection.h */; };
                41DC459C1E3DBB2800B11F51 /* LibWebRTCSocketClient.h in Headers */ = {isa = PBXBuildFile; fileRef = 41DC459A1E3DBB2400B11F51 /* LibWebRTCSocketClient.h */; };
                41DC459F1E3DBDA500B11F51 /* WebRTCSocket.h in Headers */ = {isa = PBXBuildFile; fileRef = 41FAF5F31E3BFE7F001AE678 /* WebRTCSocket.h */; };
                41DE7C6C22278F1E00532B65 /* ServiceWorkerFetchTask.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 41518536222704F6005430C6 /* ServiceWorkerFetchTask.cpp */; };
+               41F060E11654318500F3281C /* WebSocketChannelMessageReceiver.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 41F060DD1654317500F3281C /* WebSocketChannelMessageReceiver.cpp */; };
                41FABD2A1F4DE001006A6C97 /* CacheStorageEngineCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 41FABD281F4DDFDC006A6C97 /* CacheStorageEngineCache.h */; };
                41FAF5F51E3C0649001AE678 /* WebRTCResolver.h in Headers */ = {isa = PBXBuildFile; fileRef = 41FAF5F41E3C0641001AE678 /* WebRTCResolver.h */; };
                41FAF5F81E3C1021001AE678 /* LibWebRTCResolver.h in Headers */ = {isa = PBXBuildFile; fileRef = 41FAF5F61E3C0B47001AE678 /* LibWebRTCResolver.h */; };
                31D5929D166E060000E6BF02 /* WebPlugInClient.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WebPlugInClient.h; sourceTree = "<group>"; };
                31EA25D0134F78B2005B1452 /* NativeWebMouseEventMac.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = NativeWebMouseEventMac.mm; sourceTree = "<group>"; };
                31EA25D3134F78D6005B1452 /* NativeWebMouseEvent.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NativeWebMouseEvent.h; sourceTree = "<group>"; };
+               31F060DD1654317500F3281C /* NetworkSocketChannelMessageReceiver.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = NetworkSocketChannelMessageReceiver.cpp; path = DerivedSources/WebKit2/NetworkSocketChannelMessageReceiver.cpp; sourceTree = BUILT_PRODUCTS_DIR; };
                32DBCF5E0370ADEE00C91783 /* WebKit2Prefix.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WebKit2Prefix.h; sourceTree = "<group>"; };
                330934431315B9220097A7BC /* WebCookieManagerMessageReceiver.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = WebCookieManagerMessageReceiver.cpp; path = DerivedSources/WebKit2/WebCookieManagerMessageReceiver.cpp; sourceTree = BUILT_PRODUCTS_DIR; };
                330934441315B9220097A7BC /* WebCookieManagerMessages.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = WebCookieManagerMessages.h; path = DerivedSources/WebKit2/WebCookieManagerMessages.h; sourceTree = BUILT_PRODUCTS_DIR; };
                411A8DD920DDB6050060D34F /* WKMockMediaDevice.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WKMockMediaDevice.h; sourceTree = "<group>"; };
                411A8DDA20DDB6050060D34F /* WKMockMediaDevice.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WKMockMediaDevice.cpp; sourceTree = "<group>"; };
                411B22621E371244004F7363 /* LibWebRTCNetwork.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = LibWebRTCNetwork.h; path = Network/webrtc/LibWebRTCNetwork.h; sourceTree = "<group>"; };
+               41287D4B225C05C4009A3E26 /* WebSocketTaskCocoa.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = WebSocketTaskCocoa.mm; sourceTree = "<group>"; };
+               41287D4C225C05C5009A3E26 /* WebSocketTaskCocoa.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WebSocketTaskCocoa.h; sourceTree = "<group>"; };
+               41287D4D225C161F009A3E26 /* WebSocketTask.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WebSocketTask.h; sourceTree = "<group>"; };
                413075981DE84FB00039EC69 /* NetworkRTCSocket.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = NetworkRTCSocket.cpp; sourceTree = "<group>"; };
                413075991DE84FB00039EC69 /* NetworkRTCSocket.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NetworkRTCSocket.h; sourceTree = "<group>"; };
                4130759A1DE84FB00039EC69 /* NetworkRTCMonitor.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = NetworkRTCMonitor.cpp; sourceTree = "<group>"; };
                4151E5C31FBB90A900E47E2D /* FormDataReference.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FormDataReference.h; sourceTree = "<group>"; };
                4157853021276B6F00DD3800 /* copy-webcontent-resources-to-private-headers.sh */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; path = "copy-webcontent-resources-to-private-headers.sh"; sourceTree = "<group>"; };
                4157E4AF20E2EC9800A6C0D7 /* com.google.o1dbrowserplugin.sb */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = com.google.o1dbrowserplugin.sb; sourceTree = "<group>"; };
+               417915AC2256BB7400D6F97E /* WebSocketChannel.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = WebSocketChannel.cpp; path = Network/WebSocketChannel.cpp; sourceTree = "<group>"; };
+               417915AD2256BB7400D6F97E /* WebSocketChannel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = WebSocketChannel.h; path = Network/WebSocketChannel.h; sourceTree = "<group>"; };
+               417915B02256C0D600D6F97E /* WebSocketChannelManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = WebSocketChannelManager.h; path = Network/WebSocketChannelManager.h; sourceTree = "<group>"; };
+               417915B22256C2E200D6F97E /* WebSocketChannelManager.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = WebSocketChannelManager.cpp; path = Network/WebSocketChannelManager.cpp; sourceTree = "<group>"; };
+               417915B42256D1A700D6F97E /* WebSocketChannel.messages.in */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = WebSocketChannel.messages.in; path = Network/WebSocketChannel.messages.in; sourceTree = "<group>"; };
+               417915B62257046E00D6F97E /* NetworkSocketChannel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NetworkSocketChannel.h; sourceTree = "<group>"; };
+               417915B72257046E00D6F97E /* NetworkSocketChannel.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = NetworkSocketChannel.cpp; sourceTree = "<group>"; };
+               417915B82257046E00D6F97E /* NetworkSocketChannel.messages.in */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = NetworkSocketChannel.messages.in; sourceTree = "<group>"; };
                41897ECC1F415D5C0016FA42 /* WebCacheStorageProvider.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = WebCacheStorageProvider.cpp; sourceTree = "<group>"; };
                41897ECD1F415D5C0016FA42 /* WebCacheStorageConnection.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = WebCacheStorageConnection.h; sourceTree = "<group>"; };
                41897ECE1F415D5C0016FA42 /* WebCacheStorageConnection.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = WebCacheStorageConnection.cpp; sourceTree = "<group>"; };
                41DC459A1E3DBB2400B11F51 /* LibWebRTCSocketClient.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LibWebRTCSocketClient.h; sourceTree = "<group>"; };
                41DC459D1E3DBCF000B11F51 /* WebRTCSocket.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = WebRTCSocket.cpp; path = Network/webrtc/WebRTCSocket.cpp; sourceTree = "<group>"; };
                41DC45A01E3DC53C00B11F51 /* WebRTCResolver.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = WebRTCResolver.cpp; path = Network/webrtc/WebRTCResolver.cpp; sourceTree = "<group>"; };
+               41F060DD1654317500F3281C /* WebSocketChannelMessageReceiver.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = WebSocketChannelMessageReceiver.cpp; path = DerivedSources/WebKit2/WebSocketChannelMessageReceiver.cpp; sourceTree = BUILT_PRODUCTS_DIR; };
                41FABD281F4DDFDC006A6C97 /* CacheStorageEngineCache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CacheStorageEngineCache.h; sourceTree = "<group>"; };
                41FAF5F31E3BFE7F001AE678 /* WebRTCSocket.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = WebRTCSocket.h; path = Network/webrtc/WebRTCSocket.h; sourceTree = "<group>"; };
                41FAF5F41E3C0641001AE678 /* WebRTCResolver.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = WebRTCResolver.h; path = Network/webrtc/WebRTCResolver.h; sourceTree = "<group>"; };
                                510AFFB716542048001BA05E /* WebResourceLoader.cpp */,
                                510AFFB816542048001BA05E /* WebResourceLoader.h */,
                                510AFFCE16542CBD001BA05E /* WebResourceLoader.messages.in */,
+                               417915AC2256BB7400D6F97E /* WebSocketChannel.cpp */,
+                               417915AD2256BB7400D6F97E /* WebSocketChannel.h */,
+                               417915B42256D1A700D6F97E /* WebSocketChannel.messages.in */,
+                               417915B22256C2E200D6F97E /* WebSocketChannelManager.cpp */,
+                               417915B02256C0D600D6F97E /* WebSocketChannelManager.h */,
                                5C7706731D111D8B0012700F /* WebSocketProvider.cpp */,
                                5C7C88DC1D0F41A0009D2F6D /* WebSocketProvider.h */,
                                5C0B177A1E7C884F00E9123C /* WebSocketStream.cpp */,
                                5C20CB9E1BB0DD1800895BB1 /* NetworkSession.h */,
                                5C89DF5621AF61FF004645E8 /* NetworkSessionCreationParameters.cpp */,
                                5C84CF901F96AC4E00B6705A /* NetworkSessionCreationParameters.h */,
+                               417915B72257046E00D6F97E /* NetworkSocketChannel.cpp */,
+                               417915B62257046E00D6F97E /* NetworkSocketChannel.h */,
+                               417915B82257046E00D6F97E /* NetworkSocketChannel.messages.in */,
                                5C0B177D1E7C886700E9123C /* NetworkSocketStream.cpp */,
                                5C0B177E1E7C886700E9123C /* NetworkSocketStream.h */,
                                5C0B177F1E7C886700E9123C /* NetworkSocketStream.messages.in */,
                                83A0ED331F747CC7003299EB /* PreconnectTask.cpp */,
                                83A0ED321F747CC6003299EB /* PreconnectTask.h */,
                                E1B78470163F24690007B692 /* RemoteNetworkingContext.h */,
+                               41287D4D225C161F009A3E26 /* WebSocketTask.h */,
                        );
                        path = NetworkProcess;
                        sourceTree = "<group>";
                                7EC4F0F918E4A945008056AF /* NetworkProcessCocoa.mm */,
                                532159501DBAE6D70054AA3C /* NetworkSessionCocoa.h */,
                                5C20CB9B1BB0DCD200895BB1 /* NetworkSessionCocoa.mm */,
+                               41287D4C225C05C5009A3E26 /* WebSocketTaskCocoa.h */,
+                               41287D4B225C05C4009A3E26 /* WebSocketTaskCocoa.mm */,
                        );
                        path = cocoa;
                        sourceTree = "<group>";
                                51F060DD1654317500F3281E /* NetworkRTCMonitorMessageReceiver.cpp */,
                                51F060DD1654317500F3282E /* NetworkRTCProviderMessageReceiver.cpp */,
                                51F060DD1654317500F3281D /* NetworkRTCSocketMessageReceiver.cpp */,
+                               31F060DD1654317500F3281C /* NetworkSocketChannelMessageReceiver.cpp */,
                                5C0B17741E7C879C00E9123C /* NetworkSocketStreamMessageReceiver.cpp */,
                                5C0B17751E7C879C00E9123C /* NetworkSocketStreamMessages.h */,
                                1A2D8437127F65D5001EB962 /* NPObjectMessageReceiverMessageReceiver.cpp */,
                                51F060DD1654317500F3281F /* WebRTCMonitorMessageReceiver.cpp */,
                                51F060DD1654317500F3282C /* WebRTCResolverMessageReceiver.cpp */,
                                51F060DD1654317500F3281C /* WebRTCSocketMessageReceiver.cpp */,
+                               41F060DD1654317500F3281C /* WebSocketChannelMessageReceiver.cpp */,
                                5C0B17761E7C879C00E9123C /* WebSocketStreamMessageReceiver.cpp */,
                                5C0B17771E7C879C00E9123C /* WebSocketStreamMessages.h */,
                                517A530E1F47A84300DCDC0A /* WebSWClientConnectionMessageReceiver.cpp */,
                                413075AB1DE85F330039EC69 /* NetworkRTCSocket.h in Headers */,
                                5C20CBA01BB1ECD800895BB1 /* NetworkSession.h in Headers */,
                                532159551DBAE7290054AA3C /* NetworkSessionCocoa.h in Headers */,
+                               417915B92257046F00D6F97E /* NetworkSocketChannel.h in Headers */,
                                31A2EC5614899C0900810D71 /* NotificationPermissionRequest.h in Headers */,
                                3131261F148FF82C00BA2A39 /* NotificationPermissionRequestManager.h in Headers */,
                                31A2EC521489981900810D71 /* NotificationPermissionRequestManagerProxy.h in Headers */,
                                F430E9422247335F005FE053 /* WebsiteMetaViewportPolicy.h in Headers */,
                                0EDE85032004E75D00030560 /* WebsitePopUpPolicy.h in Headers */,
                                71FB810B2260627E00323677 /* WebsiteSimulatedMouseEventsDispatchPolicy.h in Headers */,
+                               417915AF2256BB7500D6F97E /* WebSocketChannel.h in Headers */,
+                               417915B12256C0D600D6F97E /* WebSocketChannelManager.h in Headers */,
                                C149380922347104000CD707 /* WebSpeechSynthesisClient.h in Headers */,
                                836034A01ACB34D600626549 /* WebSQLiteDatabaseTracker.h in Headers */,
                                1A52C0F81A38CDC70016160A /* WebStorageNamespaceProvider.h in Headers */,
                                51F060E11654318500F3281E /* NetworkRTCMonitorMessageReceiver.cpp in Sources */,
                                51F060E11654318500F3282E /* NetworkRTCProviderMessageReceiver.cpp in Sources */,
                                51F060E11654318500F3281D /* NetworkRTCSocketMessageReceiver.cpp in Sources */,
+                               31F060E11654318500F3281C /* NetworkSocketChannelMessageReceiver.cpp in Sources */,
                                5C0B17781E7C880E00E9123C /* NetworkSocketStreamMessageReceiver.cpp in Sources */,
                                2D92A790212B6AD400F493FD /* NPIdentifierData.cpp in Sources */,
                                2D913446212CF9F000128AFD /* NPJSObject.cpp in Sources */,
                                51F060E11654318500F3281F /* WebRTCMonitorMessageReceiver.cpp in Sources */,
                                51F060E11654318500F3282C /* WebRTCResolverMessageReceiver.cpp in Sources */,
                                51F060E11654318500F3281C /* WebRTCSocketMessageReceiver.cpp in Sources */,
+                               41F060E11654318500F3281C /* WebSocketChannelMessageReceiver.cpp in Sources */,
                                5C0B17791E7C882100E9123C /* WebSocketStreamMessageReceiver.cpp in Sources */,
+                               41287D4E225D1ECB009A3E26 /* WebSocketTaskCocoa.mm in Sources */,
                                517A530F1F47A86200DCDC0A /* WebSWClientConnectionMessageReceiver.cpp in Sources */,
                                460F488F1F996F7100CF4B87 /* WebSWContextManagerConnectionMessageReceiver.cpp in Sources */,
                                9356F2DF2152B72300E6D5DF /* WebSWOriginStore.cpp in Sources */,
index 3c6de39..90b4b54 100644 (file)
@@ -51,6 +51,8 @@
 #include "WebSWContextManagerConnection.h"
 #include "WebSWContextManagerConnectionMessages.h"
 #include "WebServiceWorkerProvider.h"
+#include "WebSocketChannel.h"
+#include "WebSocketChannelMessages.h"
 #include "WebSocketStream.h"
 #include "WebSocketStreamMessages.h"
 #include <WebCore/CachedResource.h>
@@ -88,6 +90,10 @@ void NetworkProcessConnection::didReceiveMessage(IPC::Connection& connection, IP
             stream->didReceiveMessage(connection, decoder);
         return;
     }
+    if (decoder.messageReceiverName() == Messages::WebSocketChannel::messageReceiverName()) {
+        WebProcess::singleton().webSocketChannelManager().didReceiveMessage(connection, decoder);
+        return;
+    }
     if (decoder.messageReceiverName() == Messages::WebPage::messageReceiverName()) {
         if (auto* webPage = WebProcess::singleton().webPage(makeObjectIdentifier<PageIdentifierType>(decoder.destinationID())))
             webPage->didReceiveWebPageMessage(connection, decoder);
diff --git a/Source/WebKit/WebProcess/Network/WebSocketChannel.cpp b/Source/WebKit/WebProcess/Network/WebSocketChannel.cpp
new file mode 100644 (file)
index 0000000..bc222e4
--- /dev/null
@@ -0,0 +1,274 @@
+/*
+ * Copyright (C) 2019 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or othe r materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "WebSocketChannel.h"
+
+#include "DataReference.h"
+#include "NetworkConnectionToWebProcessMessages.h"
+#include "NetworkProcessConnection.h"
+#include "NetworkSocketChannelMessages.h"
+#include "WebCoreArgumentCoders.h"
+#include "WebProcess.h"
+#include <WebCore/Document.h>
+#include <WebCore/NotImplemented.h>
+#include <WebCore/WebSocketChannel.h>
+#include <WebCore/WebSocketChannelClient.h>
+#include <pal/SessionID.h>
+
+namespace WebKit {
+
+Ref<WebSocketChannel> WebSocketChannel::create(WebCore::Document& document, WebCore::WebSocketChannelClient& client)
+{
+    return adoptRef(*new WebSocketChannel(document, client));
+}
+
+WebSocketChannel::WebSocketChannel(WebCore::Document& document, WebCore::WebSocketChannelClient& client)
+    : m_document(makeWeakPtr(document))
+    , m_client(makeWeakPtr(client))
+{
+}
+
+WebSocketChannel::~WebSocketChannel()
+{
+}
+
+IPC::Connection* WebSocketChannel::messageSenderConnection() const
+{
+    return &WebProcess::singleton().ensureNetworkProcessConnection().connection();
+}
+
+uint64_t WebSocketChannel::messageSenderDestinationID() const
+{
+    return identifier();
+}
+
+String WebSocketChannel::subprotocol()
+{
+    // FIXME: support subprotocol.
+    return emptyString();
+}
+
+String WebSocketChannel::extensions()
+{
+    // FIXME: support extensions.
+    return emptyString();
+}
+
+WebSocketChannel::ConnectStatus WebSocketChannel::connect(const URL& url, const String& protocol)
+{
+    if (!m_document)
+        return ConnectStatus::KO;
+
+    auto request = webSocketConnectRequest(*m_document, url);
+    if (!request)
+        return ConnectStatus::KO;
+
+    if (request->url() != url && m_client)
+        m_client->didUpgradeURL();
+
+    MessageSender::send(Messages::NetworkConnectionToWebProcess::CreateSocketChannel { m_document->sessionID(), *request, protocol, identifier() });
+    return ConnectStatus::OK;
+}
+
+WebSocketChannel::SendResult WebSocketChannel::send(const String& message)
+{
+    auto byteLength = message.sizeInBytes();
+    m_bufferedAmount += byteLength;
+    if (m_client)
+        m_client->didUpdateBufferedAmount(m_bufferedAmount);
+
+    CompletionHandler<void()> completionHandler = [this, protectedThis = makeRef(*this), byteLength] {
+        ASSERT(m_bufferedAmount >= byteLength);
+        m_bufferedAmount -= byteLength;
+        if (m_client)
+            m_client->didUpdateBufferedAmount(m_bufferedAmount);
+    };
+    sendWithAsyncReply(Messages::NetworkSocketChannel::SendString { message }, WTFMove(completionHandler));
+    return SendSuccess;
+}
+
+WebSocketChannel::SendResult WebSocketChannel::send(const JSC::ArrayBuffer& binaryData, unsigned byteOffset, unsigned byteLength)
+{
+    m_bufferedAmount += byteLength;
+    if (m_client)
+        m_client->didUpdateBufferedAmount(m_bufferedAmount);
+
+    CompletionHandler<void()> completionHandler = [this, protectedThis = makeRef(*this), byteLength] {
+        ASSERT(m_bufferedAmount >= byteLength);
+        m_bufferedAmount -= byteLength;
+        if (m_client)
+            m_client->didUpdateBufferedAmount(m_bufferedAmount);
+    };
+    sendWithAsyncReply(Messages::NetworkSocketChannel::SendData { IPC::DataReference { static_cast<const uint8_t*>(binaryData.data()) + byteOffset, byteLength } }, WTFMove(completionHandler));
+    return SendSuccess;
+}
+
+WebSocketChannel::SendResult WebSocketChannel::send(WebCore::Blob&)
+{
+    notImplemented();
+    return SendFail;
+}
+
+unsigned WebSocketChannel::bufferedAmount() const
+{
+    return m_bufferedAmount;
+}
+
+void WebSocketChannel::close(int code, const String& reason)
+{
+    m_isClosing = true;
+    if (m_client)
+        m_client->didStartClosingHandshake();
+
+    ASSERT(code >= 0 || code == WebCore::WebSocketChannel::CloseEventCodeNotSpecified);
+
+    MessageSender::send(Messages::NetworkSocketChannel::Close { code, reason });
+}
+
+void WebSocketChannel::fail(const String& reason)
+{
+    MessageSender::send(Messages::NetworkSocketChannel::Close { 0, reason });
+}
+
+void WebSocketChannel::disconnect()
+{
+    m_client = nullptr;
+    m_document = nullptr;
+    m_pendingTasks.clear();
+
+    MessageSender::send(Messages::NetworkSocketChannel::Close { 0, { } });
+}
+
+void WebSocketChannel::didConnect()
+{
+    if (m_isClosing)
+        return;
+
+    if (!m_client)
+        return;
+
+    if (m_isSuspended) {
+        enqueueTask([this] {
+            didConnect();
+        });
+        return;
+    }
+
+    m_client->didConnect();
+}
+
+void WebSocketChannel::didReceiveText(const String& message)
+{
+    if (m_isClosing)
+        return;
+
+    if (!m_client)
+        return;
+
+    if (m_isSuspended) {
+        enqueueTask([this, message] {
+            didReceiveText(message);
+        });
+        return;
+    }
+
+    m_client->didReceiveMessage(message);
+}
+
+void WebSocketChannel::didReceiveBinaryData(const IPC::DataReference& data)
+{
+    if (m_isClosing)
+        return;
+
+    if (!m_client)
+        return;
+
+    if (m_isSuspended) {
+        enqueueTask([this, data = data.vector()]() mutable {
+            if (!m_isClosing && m_client)
+                m_client->didReceiveBinaryData(WTFMove(data));
+        });
+        return;
+    }
+    m_client->didReceiveBinaryData(data.vector());
+}
+
+void WebSocketChannel::didClose(unsigned short code, const String& reason)
+{
+    if (!m_client)
+        return;
+
+    if (m_isSuspended) {
+        enqueueTask([this, code, reason] {
+            didClose(code, reason);
+        });
+        return;
+    }
+
+    if (code == WebCore::WebSocketChannel::CloseEventCodeNormalClosure)
+        m_client->didStartClosingHandshake();
+
+    m_client->didClose(m_bufferedAmount, (m_isClosing || code == WebCore::WebSocketChannel::CloseEventCodeNormalClosure) ? WebCore::WebSocketChannelClient::ClosingHandshakeComplete : WebCore::WebSocketChannelClient::ClosingHandshakeIncomplete, code, reason);
+}
+
+void WebSocketChannel::didFail()
+{
+    if (!m_client)
+        return;
+
+    if (m_isSuspended) {
+        enqueueTask([this] {
+            didFail();
+        });
+        return;
+    }
+
+    m_client->didReceiveMessageError();
+}
+
+void WebSocketChannel::networkProcessCrashed()
+{
+    didFail();
+}
+
+void WebSocketChannel::suspend()
+{
+    m_isSuspended = true;
+}
+
+void WebSocketChannel::resume()
+{
+    m_isSuspended = false;
+    while (!m_isSuspended && !m_pendingTasks.isEmpty())
+        m_pendingTasks.takeFirst()();
+}
+
+void WebSocketChannel::enqueueTask(Function<void()>&& task)
+{
+    m_pendingTasks.append(WTFMove(task));
+}
+
+} // namespace WebKit
diff --git a/Source/WebKit/WebProcess/Network/WebSocketChannel.h b/Source/WebKit/WebProcess/Network/WebSocketChannel.h
new file mode 100644 (file)
index 0000000..e4de9c2
--- /dev/null
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2019 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include "MessageReceiver.h"
+#include "MessageSender.h"
+#include <WebCore/ThreadableWebSocketChannel.h>
+#include <pal/SessionID.h>
+#include <wtf/Deque.h>
+#include <wtf/Identified.h>
+#include <wtf/WeakPtr.h>
+
+namespace IPC {
+class Connection;
+class Decoder;
+class DataReference;
+}
+
+namespace WebKit {
+
+class WebSocketChannel : public IPC::MessageSender, public IPC::MessageReceiver, public WebCore::ThreadableWebSocketChannel, public RefCounted<WebSocketChannel>, public Identified<WebSocketChannel> {
+public:
+    static Ref<WebSocketChannel> create(WebCore::Document&, WebCore::WebSocketChannelClient&);
+    ~WebSocketChannel();
+
+    void didReceiveMessage(IPC::Connection&, IPC::Decoder&);
+
+    void networkProcessCrashed();
+    void didFail();
+
+    using RefCounted<WebSocketChannel>::ref;
+    using RefCounted<WebSocketChannel>::deref;
+
+private:
+    WebSocketChannel(WebCore::Document&, WebCore::WebSocketChannelClient&);
+
+    // ThreadableWebSocketChannel
+    ConnectStatus connect(const URL&, const String& protocol) final;
+    String subprotocol() final;
+    String extensions() final;
+    SendResult send(const String& message) final;
+    SendResult send(const JSC::ArrayBuffer&, unsigned byteOffset, unsigned byteLength) final;
+    SendResult send(WebCore::Blob&) final;
+    unsigned bufferedAmount() const final;
+    void close(int code, const String& reason) final;
+    void fail(const String& reason) final;
+    void disconnect() final;
+    void suspend() final;
+    void resume() final;
+    void refThreadableWebSocketChannel() final { ref(); }
+    void derefThreadableWebSocketChannel() final { deref(); }
+
+    // Message receivers
+    void didConnect();
+    void didReceiveText(const String&);
+    void didReceiveBinaryData(const IPC::DataReference&);
+    void didClose(unsigned short code, const String&);
+
+    // MessageSender
+    IPC::Connection* messageSenderConnection() const final;
+    uint64_t messageSenderDestinationID() const final;
+
+    void enqueueTask(Function<void()>&&);
+
+    WeakPtr<WebCore::Document> m_document;
+    WeakPtr<WebCore::WebSocketChannelClient> m_client;
+    size_t m_bufferedAmount { 0 };
+    bool m_isClosing { false };
+    bool m_isSuspended { false };
+    Deque<Function<void()>> m_pendingTasks;
+};
+
+} // namespace WebKit
diff --git a/Source/WebKit/WebProcess/Network/WebSocketChannel.messages.in b/Source/WebKit/WebProcess/Network/WebSocketChannel.messages.in
new file mode 100644 (file)
index 0000000..7ef413b
--- /dev/null
@@ -0,0 +1,28 @@
+# Copyright (C) 2017 Apple Inc. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1.  Redistributions of source code must retain the above copyright
+#     notice, this list of conditions and the following disclaimer.
+# 2.  Redistributions in binary form must reproduce the above copyright
+#     notice, this list of conditions and the following disclaimer in the
+#     documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR
+# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) A RISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+messages -> WebSocketChannel {
+    DidConnect()
+    DidClose(unsigned short code, String reason)
+    DidReceiveText(String message)
+    DidReceiveBinaryData(IPC::DataReference data)
+}
diff --git a/Source/WebKit/WebProcess/Network/WebSocketChannelManager.cpp b/Source/WebKit/WebProcess/Network/WebSocketChannelManager.cpp
new file mode 100644 (file)
index 0000000..942005b
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2019 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "WebSocketChannelManager.h"
+
+namespace WebKit {
+
+RefPtr<WebCore::ThreadableWebSocketChannel> WebSocketChannelManager::createWebSocketChannel(WebCore::Document& document, WebCore::WebSocketChannelClient& client)
+{
+    auto channel = WebSocketChannel::create(document, client);
+    m_channels.add(channel->identifier(), channel.copyRef());
+    return channel;
+}
+
+void WebSocketChannelManager::networkProcessCrashed()
+{
+    auto channels = WTFMove(m_channels);
+    for (auto& channel : channels.values())
+        channel->networkProcessCrashed();
+}
+
+void WebSocketChannelManager::didReceiveMessage(IPC::Connection& connection, IPC::Decoder& decoder)
+{
+    auto iterator = m_channels.find(decoder.destinationID());
+    if (iterator != m_channels.end())
+        iterator->value->didReceiveMessage(connection, decoder);
+}
+
+} // namespace WebKit
diff --git a/Source/WebKit/WebProcess/Network/WebSocketChannelManager.h b/Source/WebKit/WebProcess/Network/WebSocketChannelManager.h
new file mode 100644 (file)
index 0000000..7dc04af
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2019 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include "WebSocketChannel.h"
+
+namespace IPC {
+class Connection;
+class Decoder;
+}
+
+namespace WebCore {
+class Document;
+class ThreadableWebSocketChannel;
+}
+
+namespace WebKit {
+
+class WebSocketChannelManager {
+public:
+    WebSocketChannelManager() = default;
+    RefPtr<WebCore::ThreadableWebSocketChannel> createWebSocketChannel(WebCore::Document&, WebCore::WebSocketChannelClient&);
+
+    void networkProcessCrashed();
+    void didReceiveMessage(IPC::Connection&, IPC::Decoder&);
+
+private:
+    HashMap<uint64_t, Ref<WebSocketChannel>> m_channels;
+};
+
+} // namespace WebKit
index 54709db..1f856c1 100644 (file)
@@ -31,6 +31,8 @@
 #include "config.h"
 #include "WebSocketProvider.h"
 
+#include "WebProcess.h"
+#include "WebSocketChannelManager.h"
 #include "WebSocketStream.h"
 
 namespace WebKit {
@@ -41,4 +43,9 @@ Ref<SocketStreamHandle> WebSocketProvider::createSocketStreamHandle(const URL& u
     return WebSocketStream::create(url, client, sessionID, credentialPartition);
 }
 
+RefPtr<ThreadableWebSocketChannel> WebSocketProvider::createWebSocketChannel(Document& document, WebSocketChannelClient& client)
+{
+    return WebProcess::singleton().webSocketChannelManager().createWebSocketChannel(document, client);
+}
+
 } // namespace WebKit
index 290b99c..73e4ce8 100644 (file)
@@ -33,6 +33,7 @@ class WebSocketProvider final : public WebCore::SocketProvider {
 public:
     static Ref<WebSocketProvider> create() { return adoptRef(*new WebSocketProvider); }
     Ref<WebCore::SocketStreamHandle> createSocketStreamHandle(const URL&, WebCore::SocketStreamHandleClient&, PAL::SessionID, const String& credentialPartition, const WebCore::StorageSessionProvider*) final;
+    RefPtr<WebCore::ThreadableWebSocketChannel> createWebSocketChannel(WebCore::Document&, WebCore::WebSocketChannelClient&) final;
     virtual ~WebSocketProvider() { }
 };
 
index be887ad..8a8a984 100644 (file)
@@ -26,6 +26,7 @@
 #pragma once
 
 #include "QuickLookDocumentData.h"
+#include <WebCore/PageIdentifier.h>
 #include <WebCore/PreviewLoaderClient.h>
 #include <wtf/text/WTFString.h>
 
index 6174b0a..2805513 100644 (file)
@@ -1316,6 +1316,7 @@ void WebProcess::networkProcessConnectionClosed(NetworkProcessConnection* connec
 
     m_webLoaderStrategy.networkProcessCrashed();
     WebSocketStream::networkProcessCrashed();
+    m_webSocketChannelManager.networkProcessCrashed();
 
     for (auto& page : m_pageMap.values()) {
         page->stopAllURLSchemeTasks();
index 8b63f29..a644421 100644 (file)
@@ -38,6 +38,7 @@
 #include "WebInspectorInterruptDispatcher.h"
 #include "WebProcessCreationParameters.h"
 #include "WebSQLiteDatabaseTracker.h"
+#include "WebSocketChannelManager.h"
 #include <WebCore/ActivityState.h>
 #include <WebCore/PageIdentifier.h>
 #include <WebCore/RegistrableDomain.h>
@@ -266,6 +267,7 @@ public:
     WebAutomationSessionProxy* automationSessionProxy() { return m_automationSessionProxy.get(); }
 
     WebCacheStorageProvider& cacheStorageProvider() { return m_cacheStorageProvider.get(); }
+    WebSocketChannelManager& webSocketChannelManager() { return m_webSocketChannelManager; }
 
 #if PLATFORM(IOS_FAMILY)
     void accessibilityProcessSuspendedNotification(bool);
@@ -499,6 +501,7 @@ private:
     WebLoaderStrategy& m_webLoaderStrategy;
 
     Ref<WebCacheStorageProvider> m_cacheStorageProvider;
+    WebSocketChannelManager m_webSocketChannelManager;
 
     std::unique_ptr<LibWebRTCNetwork> m_libWebRTCNetwork;