blob: e7c7d62cd0cb2da1bdf71e76cf90c8553b3bad6a [file] [log] [blame]
/*
* 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)
* 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(MEDIA_STREAM) && PLATFORM(MAC)
#import "DeprecatedGlobalValues.h"
#import "PlatformUtilities.h"
#import "Test.h"
#import "TestWKWebView.h"
#import <WebKit/WKPreferencesPrivate.h>
#import <WebKit/WKUIDelegatePrivate.h>
#import <WebKit/WKWebView.h>
#import <WebKit/WKWebViewConfiguration.h>
#import <WebKit/WKWebViewConfigurationPrivate.h>
static bool shouldDeny = false;
static _WKCaptureDevices requestedDevices = 0;
@interface GetDisplayMediaMessageHandler : NSObject <WKScriptMessageHandler>
@end
@implementation GetDisplayMediaMessageHandler
- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message
{
lastScriptMessage = message;
receivedScriptMessage = true;
}
@end
@interface GetDisplayMediaUIDelegate : NSObject<WKUIDelegate>
- (void)_webView:(WKWebView *)webView requestUserMediaAuthorizationForDevices:(_WKCaptureDevices)devices url:(NSURL *)url mainFrameURL:(NSURL *)mainFrameURL decisionHandler:(void (^)(BOOL authorized))decisionHandler;
- (void)_webView:(WKWebView *)webView checkUserMediaPermissionForURL:(NSURL *)url mainFrameURL:(NSURL *)mainFrameURL frameIdentifier:(NSUInteger)frameIdentifier decisionHandler:(void (^)(NSString *salt, BOOL authorized))decisionHandler;
@end
@implementation GetDisplayMediaUIDelegate
- (void)_webView:(WKWebView *)webView requestUserMediaAuthorizationForDevices:(_WKCaptureDevices)devices url:(NSURL *)url mainFrameURL:(NSURL *)mainFrameURL decisionHandler:(void (^)(BOOL authorized))decisionHandler
{
wasPrompted = true;
if (shouldDeny) {
decisionHandler(NO);
return;
}
requestedDevices = devices;
BOOL needsMicrophoneAuthorization = !!(requestedDevices & _WKCaptureDeviceMicrophone);
BOOL needsCameraAuthorization = !!(requestedDevices & _WKCaptureDeviceCamera);
BOOL needsDisplayCaptureAuthorization = !!(requestedDevices & _WKCaptureDeviceDisplay);
if (!needsMicrophoneAuthorization && !needsCameraAuthorization && !needsDisplayCaptureAuthorization) {
decisionHandler(NO);
return;
}
decisionHandler(YES);
}
- (void)_webView:(WKWebView *)webView checkUserMediaPermissionForURL:(NSURL *)url mainFrameURL:(NSURL *)mainFrameURL frameIdentifier:(NSUInteger)frameIdentifier decisionHandler:(void (^)(NSString *salt, BOOL authorized))decisionHandler
{
decisionHandler(@"0x987654321", YES);
}
@end
namespace TestWebKitAPI {
class GetDisplayMediaTest : public testing::Test {
public:
virtual void SetUp()
{
m_configuration = adoptNS([[WKWebViewConfiguration alloc] init]);
auto context = adoptWK(TestWebKitAPI::Util::createContextForInjectedBundleTest("InternalsInjectedBundleTest"));
m_configuration.get().processPool = (WKProcessPool *)context.get();
auto handler = adoptNS([[GetDisplayMediaMessageHandler alloc] init]);
[[m_configuration userContentController] addScriptMessageHandler:handler.get() name:@"testHandler"];
auto preferences = [m_configuration preferences];
preferences._mediaCaptureRequiresSecureConnection = NO;
m_configuration.get()._mediaCaptureEnabled = YES;
preferences._mockCaptureDevicesEnabled = YES;
preferences._screenCaptureEnabled = YES;
m_webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:m_configuration.get() addToWindow:YES]);
m_uiDelegate = adoptNS([[GetDisplayMediaUIDelegate alloc] init]);
m_webView.get().UIDelegate = m_uiDelegate.get();
[m_webView focus];
[m_webView synchronouslyLoadTestPageNamed:@"getDisplayMedia"];
}
bool haveStream(bool expected)
{
int retryCount = 10;
while (retryCount--) {
auto result = [m_webView stringByEvaluatingJavaScript:@"haveStream()"];
if (result.boolValue == expected)
return YES;
TestWebKitAPI::Util::spinRunLoop(10);
}
return NO;
}
void promptForCapture(NSString* constraints, bool shouldSucceed)
{
[m_webView stringByEvaluatingJavaScript:@"stop()"];
EXPECT_TRUE(haveStream(false));
wasPrompted = false;
receivedScriptMessage = false;
NSString *script = [NSString stringWithFormat:@"promptForCapture(%@)", constraints];
[m_webView stringByEvaluatingJavaScript:script];
TestWebKitAPI::Util::run(&receivedScriptMessage);
if (shouldSucceed) {
EXPECT_STREQ([(NSString *)[lastScriptMessage body] UTF8String], "allowed");
EXPECT_TRUE(haveStream(true));
EXPECT_TRUE(wasPrompted);
} else {
EXPECT_STREQ([(NSString *)[lastScriptMessage body] UTF8String], "denied");
EXPECT_TRUE(haveStream(false));
if (shouldDeny)
EXPECT_TRUE(wasPrompted);
else
EXPECT_FALSE(wasPrompted);
}
}
RetainPtr<WKWebViewConfiguration> m_configuration;
RetainPtr<GetDisplayMediaUIDelegate> m_uiDelegate;
RetainPtr<TestWKWebView> m_webView;
};
TEST_F(GetDisplayMediaTest, BasicPrompt)
{
promptForCapture(@"{ audio: true, video: true }", true);
promptForCapture(@"{ audio: true, video: false }", false);
promptForCapture(@"{ audio: false, video: true }", true);
promptForCapture(@"{ audio: false, video: false }", false);
}
TEST_F(GetDisplayMediaTest, Constraints)
{
promptForCapture(@"{ video: {width: 640} }", true);
promptForCapture(@"{ video: true, audio: { volume: 0.5 } }", true);
promptForCapture(@"{ video: {height: 480}, audio: true }", true);
promptForCapture(@"{ video: {width: { exact: 640} } }", false);
}
TEST_F(GetDisplayMediaTest, PromptOnceAfterDenial)
{
promptForCapture(@"{ video: true }", true);
shouldDeny = true;
promptForCapture(@"{ video: true }", false);
shouldDeny = false;
promptForCapture(@"{ video: true }", true);
}
} // namespace TestWebKitAPI
#endif // ENABLE(MEDIA_STREAM) && PLATFORM(MAC)