blob: 2f90c5b306776b8fb99bc4fc389987a567686993 [file] [log] [blame]
/*
* 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)