| /* |
| * Copyright (C) 2021 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" |
| |
| #if ENABLE(WEB_RTC) |
| |
| #import "HTTPServer.h" |
| #import "PlatformUtilities.h" |
| #import "TestNavigationDelegate.h" |
| #import "TestWKWebView.h" |
| |
| @interface WebRTCMessageHandler : NSObject <WKScriptMessageHandler> |
| - (void)setMessageHandler:(Function<void(WKScriptMessage*)>&&)messageHandler; |
| @end |
| |
| @implementation WebRTCMessageHandler { |
| Function<void(WKScriptMessage*)> _messageHandler; |
| } |
| - (void)setMessageHandler:(Function<void(WKScriptMessage*)>&&)messageHandler { |
| _messageHandler = WTFMove(messageHandler); |
| } |
| - (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message |
| { |
| if (_messageHandler) |
| _messageHandler(message); |
| } |
| @end |
| |
| namespace TestWebKitAPI { |
| |
| static bool isReady = false; |
| |
| TEST(WebKit2, RTCDataChannelPostMessage) |
| { |
| __block bool removedAnyExistingData = false; |
| [[WKWebsiteDataStore defaultDataStore] removeDataOfTypes:[WKWebsiteDataStore allWebsiteDataTypes] modifiedSince:[NSDate distantPast] completionHandler:^() { |
| removedAnyExistingData = true; |
| }]; |
| TestWebKitAPI::Util::run(&removedAnyExistingData); |
| |
| static const char* main = |
| "<script>" |
| "let registration;" |
| "async function register() {" |
| " registration = await navigator.serviceWorker.register('/sw.js');" |
| " if (registration.active) {" |
| " window.webkit.messageHandlers.webrtc.postMessage('READY');" |
| " return;" |
| " }" |
| " worker = registration.installing;" |
| " worker.addEventListener('statechange', function() {" |
| " if (worker.state == 'activated')" |
| " window.webkit.messageHandlers.webrtc.postMessage('READY');" |
| " });" |
| "}" |
| "register();" |
| "" |
| "let channel1, channel2;" |
| "let pc1, pc2;" |
| "async function doTransferDataChannelTest() {" |
| "pc1 = new RTCPeerConnection();" |
| "pc2 = new RTCPeerConnection();" |
| "" |
| "pc1.onicecandidate = (event) => pc2.addIceCandidate(event.candidate);" |
| "pc2.onicecandidate = (event) => pc1.addIceCandidate(event.candidate);" |
| "" |
| "channel1 = pc1.createDataChannel('test');" |
| "registration.active.postMessage({ channel: channel1 }, [channel1]);" |
| "let promise = new Promise(resolve => pc2.ondatachannel = (event) => resolve(event.channel));" |
| "" |
| "const offer = await pc1.createOffer();" |
| "await pc1.setLocalDescription(offer);" |
| "await pc2.setRemoteDescription(offer);" |
| "const answer = await pc2.createAnswer();" |
| "await pc2.setLocalDescription(answer);" |
| "await pc1.setRemoteDescription(answer);" |
| "" |
| "channel2 = await promise;" |
| "if (channel2.readyState === 'closed') {" |
| " window.webkit.messageHandlers.webrtc.postMessage('CLOSED');" |
| " return;" |
| "}" |
| "if (channel2.readyState !== 'open')" |
| " await new Promise(resolve => channel2.onopen = resolve);" |
| "" |
| "promise = new Promise(resolve => navigator.serviceWorker.onmessage = (event) => resolve(event.data));" |
| "channel2.send('TRANSFERED');" |
| "window.webkit.messageHandlers.webrtc.postMessage(await promise);" |
| "}" |
| "function transferDataChannel() {" |
| " doTransferDataChannelTest();" |
| "}" |
| "</script>"; |
| |
| static const char* js = "self.onmessage = (event) => { " |
| " const source = event.source;" |
| " const channel = event.data.channel;" |
| " if (channel.readyState === 'closed')" |
| " source.postMessage('closed');" |
| " channel.onclose = (e) => source.postMessage('close event');" |
| " channel.onmessage = (e) => source.postMessage(e.data);" |
| "};"; |
| |
| HTTPServer server({ |
| { "/", { main } }, |
| { "/sw.js", { {{ "Content-Type", "application/javascript" }}, js } }, |
| { "/", { main } }, |
| }, HTTPServer::Protocol::Https); |
| auto* request = server.request(); |
| |
| auto navigationDelegate = adoptNS([TestNavigationDelegate new]); |
| [navigationDelegate setDidReceiveAuthenticationChallenge:^(WKWebView *, NSURLAuthenticationChallenge *challenge, void (^callback)(NSURLSessionAuthChallengeDisposition, NSURLCredential *)) { |
| callback(NSURLSessionAuthChallengeUseCredential, [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust]); |
| }]; |
| |
| auto configuration = adoptNS([[WKWebViewConfiguration alloc] init]); |
| auto messageHandler = adoptNS([[WebRTCMessageHandler alloc] init]); |
| [[configuration userContentController] addScriptMessageHandler:messageHandler.get() name:@"webrtc"]; |
| |
| auto webView1 = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500) configuration:configuration.get()]); |
| webView1.get().navigationDelegate = navigationDelegate.get(); |
| |
| [messageHandler setMessageHandler:[](WKScriptMessage *message) { |
| EXPECT_WK_STREQ(@"READY", [message body]); |
| isReady = true; |
| }]; |
| isReady = false; |
| [webView1 loadRequest:request]; |
| TestWebKitAPI::Util::run(&isReady); |
| |
| auto webView2 = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500) configuration:configuration.get()]); |
| webView2.get().navigationDelegate = navigationDelegate.get(); |
| |
| [messageHandler setMessageHandler:[](WKScriptMessage *message) { |
| EXPECT_WK_STREQ(@"READY", [message body]); |
| isReady = true; |
| }]; |
| isReady = false; |
| [webView2 loadRequest:request]; |
| TestWebKitAPI::Util::run(&isReady); |
| |
| [messageHandler setMessageHandler:[](WKScriptMessage *message) { |
| EXPECT_WK_STREQ(@"TRANSFERED", [message body]); |
| isReady = true; |
| }]; |
| |
| // Transfer is probably in-process. |
| isReady = false; |
| [webView1 stringByEvaluatingJavaScript:@"transferDataChannel()"]; |
| TestWebKitAPI::Util::run(&isReady); |
| |
| // Transfer is probably out-of-process. |
| isReady = false; |
| [webView2 stringByEvaluatingJavaScript:@"transferDataChannel()"]; |
| TestWebKitAPI::Util::run(&isReady); |
| } |
| |
| } // namespace TestWebKitAPI |
| |
| #endif // ENABLE(WEB_RTC) |