<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[210031] trunk</title>
</head>
<body>
<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; }
#msg dl a { font-weight: bold}
#msg dl a:link { color:#fc3; }
#msg dl a:active { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://trac.webkit.org/projects/webkit/changeset/210031">210031</a></dd>
<dt>Author</dt> <dd>aestes@apple.com</dd>
<dt>Date</dt> <dd>2016-12-20 13:18:30 -0800 (Tue, 20 Dec 2016)</dd>
</dl>
<h3>Log Message</h3>
<pre>[Cocoa] REGRESSION (<a href="http://trac.webkit.org/projects/webkit/changeset/209558">r209558</a>): Calling decisionHandler multiple times in webView:decidePolicyForNavigationAction:decisionHandler: leads to a crash
https://bugs.webkit.org/show_bug.cgi?id=165992
Source/WebKit2:
<rdar://problem/29693817>
Reviewed by Brady Eidson.
<a href="http://trac.webkit.org/projects/webkit/changeset/209558">r209558</a> added additional move semantics to the decisionHandler block passed to
-webView:decidePolicyForNavigationAction:decisionHandler:, resulting in a null pointer
dereference in clients that call the decisionHandler block more than once.
None of the completion handlers we expose in the WebKit API are intended to be called more
than once, and we ASSERT in CompletionHandlerCallChecker::didCallCompletionHandler() that
this doesn't happen.
This change strenghtens that protection by returning immediately in completion handlers
called more than once. And in programs linked on or after WebKit 603.1.17, an NSException is
thrown if a completion handler is called a second time, like we do for completion handlers
that are never called.
New API test: WebKit2.DuplicateCompletionHandlerCalls
* Shared/Cocoa/CompletionHandlerCallChecker.h: Declared completionHandlerHasBeenCalled().
* Shared/Cocoa/CompletionHandlerCallChecker.mm:
(WebKit::shouldThrowExceptionForDuplicateCompletionHandlerCall): Added. Returns true if the
program is linked on or after
LibraryVersion::FirstWithExceptionsForDuplicateCompletionHandlerCalls.
(WebKit::CompletionHandlerCallChecker::completionHandlerHasBeenCalled): Added. Returns
whether or not the completion handler has been called. If it has, and
shouldThrowExceptionForDuplicateCompletionHandlerCall() returns true, throws an
NSInternalInconsistencyException.
* UIProcess/API/Cocoa/WKWebView.mm:
(-[WKWebView _setInputDelegate:]): Added an early return if the completion handler has
already been called.
* UIProcess/Cocoa/NavigationState.mm:
(WebKit::NavigationState::NavigationClient::decidePolicyForNavigationAction): Ditto.
(WebKit::NavigationState::NavigationClient::decidePolicyForNavigationResponse): Ditto.
(WebKit::NavigationState::NavigationClient::didReceiveAuthenticationChallenge): Ditto.
* UIProcess/Cocoa/UIDelegate.mm:
(WebKit::UIDelegate::UIClient::runJavaScriptAlert): Ditto.
(WebKit::UIDelegate::UIClient::runJavaScriptConfirm): Ditto.
(WebKit::UIDelegate::UIClient::runJavaScriptPrompt): Ditto.
(WebKit::UIDelegate::UIClient::exceededDatabaseQuota): Ditto.
(WebKit::UIDelegate::UIClient::runOpenPanel): Ditto.
(WebKit::UIDelegate::UIClient::reachedApplicationCacheOriginQuota): Ditto.
* UIProcess/Cocoa/VersionChecks.h: Added
FirstWithExceptionsForDuplicateCompletionHandlerCalls with the version number for 603.1.17.
Tools:
Reviewed by Brady Eidson.
* TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj:
* TestWebKitAPI/Tests/WebKit2Cocoa/DuplicateCompletionHandlerCalls.mm: Added.
(expectException):
(-[DuplicateCompletionHandlerCallsDelegate webView:decidePolicyForNavigationAction:decisionHandler:]):
(-[DuplicateCompletionHandlerCallsDelegate webView:decidePolicyForNavigationResponse:decisionHandler:]):
(-[DuplicateCompletionHandlerCallsDelegate webView:runJavaScriptAlertPanelWithMessage:initiatedByFrame:completionHandler:]):
(-[DuplicateCompletionHandlerCallsDelegate webView:runJavaScriptConfirmPanelWithMessage:initiatedByFrame:completionHandler:]):
(-[DuplicateCompletionHandlerCallsDelegate webView:runJavaScriptTextInputPanelWithPrompt:defaultText:initiatedByFrame:completionHandler:]):
(-[DuplicateCompletionHandlerCallsDelegate _webView:decideDatabaseQuotaForSecurityOrigin:currentQuota:currentOriginUsage:currentDatabaseUsage:expectedUsage:decisionHandler:]):
(-[DuplicateCompletionHandlerCallsDelegate _webView:willSubmitFormValues:userObject:submissionHandler:]):
(TEST):
* TestWebKitAPI/Tests/WebKit2Cocoa/duplicate-completion-handler-calls.html: Added.</pre>
<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkSourceWebKit2ChangeLog">trunk/Source/WebKit2/ChangeLog</a></li>
<li><a href="#trunkSourceWebKit2SharedCocoaCompletionHandlerCallCheckerh">trunk/Source/WebKit2/Shared/Cocoa/CompletionHandlerCallChecker.h</a></li>
<li><a href="#trunkSourceWebKit2SharedCocoaCompletionHandlerCallCheckermm">trunk/Source/WebKit2/Shared/Cocoa/CompletionHandlerCallChecker.mm</a></li>
<li><a href="#trunkSourceWebKit2UIProcessAPICocoaWKWebViewmm">trunk/Source/WebKit2/UIProcess/API/Cocoa/WKWebView.mm</a></li>
<li><a href="#trunkSourceWebKit2UIProcessCocoaNavigationStatemm">trunk/Source/WebKit2/UIProcess/Cocoa/NavigationState.mm</a></li>
<li><a href="#trunkSourceWebKit2UIProcessCocoaUIDelegatemm">trunk/Source/WebKit2/UIProcess/Cocoa/UIDelegate.mm</a></li>
<li><a href="#trunkSourceWebKit2UIProcessCocoaVersionChecksh">trunk/Source/WebKit2/UIProcess/Cocoa/VersionChecks.h</a></li>
<li><a href="#trunkToolsChangeLog">trunk/Tools/ChangeLog</a></li>
<li><a href="#trunkToolsTestWebKitAPITestWebKitAPIxcodeprojprojectpbxproj">trunk/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj</a></li>
</ul>
<h3>Added Paths</h3>
<ul>
<li><a href="#trunkToolsTestWebKitAPITestsWebKit2CocoaDuplicateCompletionHandlerCallsmm">trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/DuplicateCompletionHandlerCalls.mm</a></li>
<li><a href="#trunkToolsTestWebKitAPITestsWebKit2Cocoaduplicatecompletionhandlercallshtml">trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/duplicate-completion-handler-calls.html</a></li>
</ul>
</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkSourceWebKit2ChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit2/ChangeLog (210030 => 210031)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit2/ChangeLog        2016-12-20 21:14:00 UTC (rev 210030)
+++ trunk/Source/WebKit2/ChangeLog        2016-12-20 21:18:30 UTC (rev 210031)
</span><span class="lines">@@ -1,3 +1,52 @@
</span><ins>+2016-12-20 Andy Estes <aestes@apple.com>
+
+ [Cocoa] REGRESSION (r209558): Calling decisionHandler multiple times in webView:decidePolicyForNavigationAction:decisionHandler: leads to a crash
+ https://bugs.webkit.org/show_bug.cgi?id=165992
+ <rdar://problem/29693817>
+
+ Reviewed by Brady Eidson.
+
+ r209558 added additional move semantics to the decisionHandler block passed to
+ -webView:decidePolicyForNavigationAction:decisionHandler:, resulting in a null pointer
+ dereference in clients that call the decisionHandler block more than once.
+
+ None of the completion handlers we expose in the WebKit API are intended to be called more
+ than once, and we ASSERT in CompletionHandlerCallChecker::didCallCompletionHandler() that
+ this doesn't happen.
+
+ This change strenghtens that protection by returning immediately in completion handlers
+ called more than once. And in programs linked on or after WebKit 603.1.17, an NSException is
+ thrown if a completion handler is called a second time, like we do for completion handlers
+ that are never called.
+
+ New API test: WebKit2.DuplicateCompletionHandlerCalls
+
+ * Shared/Cocoa/CompletionHandlerCallChecker.h: Declared completionHandlerHasBeenCalled().
+ * Shared/Cocoa/CompletionHandlerCallChecker.mm:
+ (WebKit::shouldThrowExceptionForDuplicateCompletionHandlerCall): Added. Returns true if the
+ program is linked on or after
+ LibraryVersion::FirstWithExceptionsForDuplicateCompletionHandlerCalls.
+ (WebKit::CompletionHandlerCallChecker::completionHandlerHasBeenCalled): Added. Returns
+ whether or not the completion handler has been called. If it has, and
+ shouldThrowExceptionForDuplicateCompletionHandlerCall() returns true, throws an
+ NSInternalInconsistencyException.
+ * UIProcess/API/Cocoa/WKWebView.mm:
+ (-[WKWebView _setInputDelegate:]): Added an early return if the completion handler has
+ already been called.
+ * UIProcess/Cocoa/NavigationState.mm:
+ (WebKit::NavigationState::NavigationClient::decidePolicyForNavigationAction): Ditto.
+ (WebKit::NavigationState::NavigationClient::decidePolicyForNavigationResponse): Ditto.
+ (WebKit::NavigationState::NavigationClient::didReceiveAuthenticationChallenge): Ditto.
+ * UIProcess/Cocoa/UIDelegate.mm:
+ (WebKit::UIDelegate::UIClient::runJavaScriptAlert): Ditto.
+ (WebKit::UIDelegate::UIClient::runJavaScriptConfirm): Ditto.
+ (WebKit::UIDelegate::UIClient::runJavaScriptPrompt): Ditto.
+ (WebKit::UIDelegate::UIClient::exceededDatabaseQuota): Ditto.
+ (WebKit::UIDelegate::UIClient::runOpenPanel): Ditto.
+ (WebKit::UIDelegate::UIClient::reachedApplicationCacheOriginQuota): Ditto.
+ * UIProcess/Cocoa/VersionChecks.h: Added
+ FirstWithExceptionsForDuplicateCompletionHandlerCalls with the version number for 603.1.17.
+
</ins><span class="cx"> 2016-12-20 Dean Jackson <dino@apple.com>
</span><span class="cx">
</span><span class="cx"> Remove INDIE_UI
</span></span></pre></div>
<a id="trunkSourceWebKit2SharedCocoaCompletionHandlerCallCheckerh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit2/Shared/Cocoa/CompletionHandlerCallChecker.h (210030 => 210031)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit2/Shared/Cocoa/CompletionHandlerCallChecker.h        2016-12-20 21:14:00 UTC (rev 210030)
+++ trunk/Source/WebKit2/Shared/Cocoa/CompletionHandlerCallChecker.h        2016-12-20 21:18:30 UTC (rev 210031)
</span><span class="lines">@@ -39,6 +39,7 @@
</span><span class="cx"> ~CompletionHandlerCallChecker();
</span><span class="cx">
</span><span class="cx"> void didCallCompletionHandler();
</span><ins>+ bool completionHandlerHasBeenCalled() const;
</ins><span class="cx">
</span><span class="cx"> private:
</span><span class="cx"> CompletionHandlerCallChecker(Class delegateClass, SEL delegateMethodSelector);
</span></span></pre></div>
<a id="trunkSourceWebKit2SharedCocoaCompletionHandlerCallCheckermm"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit2/Shared/Cocoa/CompletionHandlerCallChecker.mm (210030 => 210031)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit2/Shared/Cocoa/CompletionHandlerCallChecker.mm        2016-12-20 21:14:00 UTC (rev 210030)
+++ trunk/Source/WebKit2/Shared/Cocoa/CompletionHandlerCallChecker.mm        2016-12-20 21:18:30 UTC (rev 210031)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> /*
</span><del>- * Copyright (C) 2014 Apple Inc. All rights reserved.
</del><ins>+ * Copyright (C) 2014-2016 Apple Inc. All rights reserved.
</ins><span class="cx"> *
</span><span class="cx"> * Redistribution and use in source and binary forms, with or without
</span><span class="cx"> * modification, are permitted provided that the following conditions
</span><span class="lines">@@ -28,8 +28,10 @@
</span><span class="cx">
</span><span class="cx"> #if WK_API_ENABLED
</span><span class="cx">
</span><ins>+#import <mutex>
</ins><span class="cx"> #import <objc/runtime.h>
</span><span class="cx"> #import <wtf/Ref.h>
</span><ins>+#import "VersionChecks.h"
</ins><span class="cx">
</span><span class="cx"> namespace WebKit {
</span><span class="cx">
</span><span class="lines">@@ -60,6 +62,29 @@
</span><span class="cx"> m_didCallCompletionHandler = true;
</span><span class="cx"> }
</span><span class="cx">
</span><ins>+static bool shouldThrowExceptionForDuplicateCompletionHandlerCall()
+{
+ static bool shouldThrowException;
+ static std::once_flag once;
+ std::call_once(once, [] {
+ shouldThrowException = linkedOnOrAfter(LibraryVersion::FirstWithExceptionsForDuplicateCompletionHandlerCalls);
+ });
+ return shouldThrowException;
+}
+
+bool CompletionHandlerCallChecker::completionHandlerHasBeenCalled() const
+{
+ if (!m_didCallCompletionHandler)
+ return false;
+
+ if (shouldThrowExceptionForDuplicateCompletionHandlerCall()) {
+ Class delegateClass = classImplementingDelegateMethod();
+ [NSException raise:NSInternalInconsistencyException format:@"Completion handler passed to %c[%@ %@] was called more than once", class_isMetaClass(delegateClass) ? '+' : '-', NSStringFromClass(delegateClass), NSStringFromSelector(m_delegateMethodSelector)];
+ }
+
+ return true;
+}
+
</ins><span class="cx"> Class CompletionHandlerCallChecker::classImplementingDelegateMethod() const
</span><span class="cx"> {
</span><span class="cx"> Class delegateClass = m_delegateClass;
</span></span></pre></div>
<a id="trunkSourceWebKit2UIProcessAPICocoaWKWebViewmm"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit2/UIProcess/API/Cocoa/WKWebView.mm (210030 => 210031)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit2/UIProcess/API/Cocoa/WKWebView.mm        2016-12-20 21:14:00 UTC (rev 210030)
+++ trunk/Source/WebKit2/UIProcess/API/Cocoa/WKWebView.mm        2016-12-20 21:18:30 UTC (rev 210031)
</span><span class="lines">@@ -3886,6 +3886,8 @@
</span><span class="cx"> RefPtr<WebKit::WebFormSubmissionListenerProxy> localListener = WTFMove(listener);
</span><span class="cx"> RefPtr<WebKit::CompletionHandlerCallChecker> checker = WebKit::CompletionHandlerCallChecker::create(inputDelegate.get(), @selector(_webView:willSubmitFormValues:userObject:submissionHandler:));
</span><span class="cx"> [inputDelegate _webView:m_webView willSubmitFormValues:valueMap.get() userObject:userObject submissionHandler:[localListener, checker] {
</span><ins>+ if (checker->completionHandlerHasBeenCalled())
+ return;
</ins><span class="cx"> checker->didCallCompletionHandler();
</span><span class="cx"> localListener->continueSubmission();
</span><span class="cx"> }];
</span></span></pre></div>
<a id="trunkSourceWebKit2UIProcessCocoaNavigationStatemm"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit2/UIProcess/Cocoa/NavigationState.mm (210030 => 210031)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit2/UIProcess/Cocoa/NavigationState.mm        2016-12-20 21:14:00 UTC (rev 210030)
+++ trunk/Source/WebKit2/UIProcess/Cocoa/NavigationState.mm        2016-12-20 21:18:30 UTC (rev 210031)
</span><span class="lines">@@ -337,6 +337,8 @@
</span><span class="cx"> RefPtr<CompletionHandlerCallChecker> checker = CompletionHandlerCallChecker::create(navigationDelegate.get(), delegateHasWebsitePolicies ? @selector(_webView:decidePolicyForNavigationAction:decisionHandler:) : @selector(webView:decidePolicyForNavigationAction:decisionHandler:));
</span><span class="cx">
</span><span class="cx"> auto decisionHandlerWithPolicies = [localListener = RefPtr<WebFramePolicyListenerProxy>(WTFMove(listener)), localNavigationAction = RefPtr<API::NavigationAction>(&navigationAction), checker = WTFMove(checker), mainFrameURLString](WKNavigationActionPolicy actionPolicy, _WKWebsitePolicies *websitePolicies) mutable {
</span><ins>+ if (checker->completionHandlerHasBeenCalled())
+ return;
</ins><span class="cx"> checker->didCallCompletionHandler();
</span><span class="cx">
</span><span class="cx"> WebsitePolicies policies;
</span><span class="lines">@@ -412,6 +414,8 @@
</span><span class="cx"> RefPtr<WebFramePolicyListenerProxy> localListener = WTFMove(listener);
</span><span class="cx"> RefPtr<CompletionHandlerCallChecker> checker = CompletionHandlerCallChecker::create(navigationDelegate.get(), @selector(webView:decidePolicyForNavigationResponse:decisionHandler:));
</span><span class="cx"> [navigationDelegate webView:m_navigationState.m_webView decidePolicyForNavigationResponse:wrapper(navigationResponse) decisionHandler:[localListener, checker](WKNavigationResponsePolicy responsePolicy) {
</span><ins>+ if (checker->completionHandlerHasBeenCalled())
+ return;
</ins><span class="cx"> checker->didCallCompletionHandler();
</span><span class="cx">
</span><span class="cx"> switch (responsePolicy) {
</span><span class="lines">@@ -647,6 +651,8 @@
</span><span class="cx"> RefPtr<CompletionHandlerCallChecker> checker = CompletionHandlerCallChecker::create(navigationDelegate.get(), @selector(webView:didReceiveAuthenticationChallenge:completionHandler:));
</span><span class="cx"> [static_cast<id <WKNavigationDelegatePrivate>>(navigationDelegate.get()) webView:m_navigationState.m_webView didReceiveAuthenticationChallenge:wrapper(*authenticationChallenge)
</span><span class="cx"> completionHandler:[challenge, checker](NSURLSessionAuthChallengeDisposition disposition, NSURLCredential *credential) {
</span><ins>+ if (checker->completionHandlerHasBeenCalled())
+ return;
</ins><span class="cx"> checker->didCallCompletionHandler();
</span><span class="cx">
</span><span class="cx"> switch (disposition) {
</span></span></pre></div>
<a id="trunkSourceWebKit2UIProcessCocoaUIDelegatemm"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit2/UIProcess/Cocoa/UIDelegate.mm (210030 => 210031)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit2/UIProcess/Cocoa/UIDelegate.mm        2016-12-20 21:14:00 UTC (rev 210030)
+++ trunk/Source/WebKit2/UIProcess/Cocoa/UIDelegate.mm        2016-12-20 21:18:30 UTC (rev 210031)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> /*
</span><del>- * Copyright (C) 2014 Apple Inc. All rights reserved.
</del><ins>+ * Copyright (C) 2014-2016 Apple Inc. All rights reserved.
</ins><span class="cx"> *
</span><span class="cx"> * Redistribution and use in source and binary forms, with or without
</span><span class="cx"> * modification, are permitted provided that the following conditions
</span><span class="lines">@@ -216,6 +216,8 @@
</span><span class="cx">
</span><span class="cx"> RefPtr<CompletionHandlerCallChecker> checker = CompletionHandlerCallChecker::create(delegate.get(), @selector(webView:runJavaScriptAlertPanelWithMessage:initiatedByFrame:completionHandler:));
</span><span class="cx"> [delegate webView:m_uiDelegate.m_webView runJavaScriptAlertPanelWithMessage:message initiatedByFrame:wrapper(API::FrameInfo::create(*webFrameProxy, securityOriginData.securityOrigin())) completionHandler:BlockPtr<void ()>::fromCallable([completionHandler = WTFMove(completionHandler), checker = WTFMove(checker)] {
</span><ins>+ if (checker->completionHandlerHasBeenCalled())
+ return;
</ins><span class="cx"> completionHandler();
</span><span class="cx"> checker->didCallCompletionHandler();
</span><span class="cx"> }).get()];
</span><span class="lines">@@ -236,6 +238,8 @@
</span><span class="cx">
</span><span class="cx"> RefPtr<CompletionHandlerCallChecker> checker = CompletionHandlerCallChecker::create(delegate.get(), @selector(webView:runJavaScriptConfirmPanelWithMessage:initiatedByFrame:completionHandler:));
</span><span class="cx"> [delegate webView:m_uiDelegate.m_webView runJavaScriptConfirmPanelWithMessage:message initiatedByFrame:wrapper(API::FrameInfo::create(*webFrameProxy, securityOriginData.securityOrigin())) completionHandler:BlockPtr<void (BOOL)>::fromCallable([completionHandler = WTFMove(completionHandler), checker = WTFMove(checker)](BOOL result) {
</span><ins>+ if (checker->completionHandlerHasBeenCalled())
+ return;
</ins><span class="cx"> completionHandler(result);
</span><span class="cx"> checker->didCallCompletionHandler();
</span><span class="cx"> }).get()];
</span><span class="lines">@@ -256,6 +260,8 @@
</span><span class="cx">
</span><span class="cx"> RefPtr<CompletionHandlerCallChecker> checker = CompletionHandlerCallChecker::create(delegate.get(), @selector(webView:runJavaScriptTextInputPanelWithPrompt:defaultText:initiatedByFrame:completionHandler:));
</span><span class="cx"> [delegate webView:m_uiDelegate.m_webView runJavaScriptTextInputPanelWithPrompt:message defaultText:defaultValue initiatedByFrame:wrapper(API::FrameInfo::create(*webFrameProxy, securityOriginData.securityOrigin())) completionHandler:BlockPtr<void (NSString *)>::fromCallable([completionHandler = WTFMove(completionHandler), checker = WTFMove(checker)](NSString *result) {
</span><ins>+ if (checker->completionHandlerHasBeenCalled())
+ return;
</ins><span class="cx"> completionHandler(result);
</span><span class="cx"> checker->didCallCompletionHandler();
</span><span class="cx"> }).get()];
</span><span class="lines">@@ -281,6 +287,8 @@
</span><span class="cx"> ASSERT(securityOrigin);
</span><span class="cx"> RefPtr<CompletionHandlerCallChecker> checker = CompletionHandlerCallChecker::create(delegate.get(), @selector(_webView:decideDatabaseQuotaForSecurityOrigin:currentQuota:currentOriginUsage:currentDatabaseUsage:expectedUsage:decisionHandler:));
</span><span class="cx"> [(id <WKUIDelegatePrivate>)delegate _webView:m_uiDelegate.m_webView decideDatabaseQuotaForSecurityOrigin:wrapper(*securityOrigin) currentQuota:currentQuota currentOriginUsage:currentOriginUsage currentDatabaseUsage:currentUsage expectedUsage:expectedUsage decisionHandler:BlockPtr<void (unsigned long long newQuota)>::fromCallable([completionHandler = WTFMove(completionHandler), checker = WTFMove(checker)](unsigned long long newQuota) {
</span><ins>+ if (checker->completionHandlerHasBeenCalled())
+ return;
</ins><span class="cx"> checker->didCallCompletionHandler();
</span><span class="cx"> completionHandler(newQuota);
</span><span class="cx"> }).get()];
</span><span class="lines">@@ -302,6 +310,8 @@
</span><span class="cx"> RefPtr<CompletionHandlerCallChecker> checker = CompletionHandlerCallChecker::create(delegate.get(), @selector(webView:runOpenPanelWithParameters:initiatedByFrame:completionHandler:));
</span><span class="cx">
</span><span class="cx"> [delegate webView:m_uiDelegate.m_webView runOpenPanelWithParameters:wrapper(*openPanelParameters) initiatedByFrame:wrapper(frame) completionHandler:[checker, resultListener](NSArray *URLs) {
</span><ins>+ if (checker->completionHandlerHasBeenCalled())
+ return;
</ins><span class="cx"> checker->didCallCompletionHandler();
</span><span class="cx">
</span><span class="cx"> if (!URLs) {
</span><span class="lines">@@ -460,6 +470,8 @@
</span><span class="cx"> RefPtr<API::SecurityOrigin> apiOrigin = API::SecurityOrigin::create(securityOrigin);
</span><span class="cx">
</span><span class="cx"> [(id <WKUIDelegatePrivate>)delegate _webView:m_uiDelegate.m_webView decideWebApplicationCacheQuotaForSecurityOrigin:wrapper(*apiOrigin) currentQuota:currentQuota totalBytesNeeded:totalBytesNeeded decisionHandler:BlockPtr<void (unsigned long long)>::fromCallable([completionHandler = WTFMove(completionHandler), checker = WTFMove(checker)](unsigned long long newQuota) {
</span><ins>+ if (checker->completionHandlerHasBeenCalled())
+ return;
</ins><span class="cx"> checker->didCallCompletionHandler();
</span><span class="cx"> completionHandler(newQuota);
</span><span class="cx"> }).get()];
</span></span></pre></div>
<a id="trunkSourceWebKit2UIProcessCocoaVersionChecksh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit2/UIProcess/Cocoa/VersionChecks.h (210030 => 210031)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit2/UIProcess/Cocoa/VersionChecks.h        2016-12-20 21:14:00 UTC (rev 210030)
+++ trunk/Source/WebKit2/UIProcess/Cocoa/VersionChecks.h        2016-12-20 21:18:30 UTC (rev 210031)
</span><span class="lines">@@ -23,8 +23,7 @@
</span><span class="cx"> * THE POSSIBILITY OF SUCH DAMAGE.
</span><span class="cx"> */
</span><span class="cx">
</span><del>-#ifndef VersionChecks_h
-#define VersionChecks_h
</del><ins>+#pragma once
</ins><span class="cx">
</span><span class="cx"> namespace WebKit {
</span><span class="cx">
</span><span class="lines">@@ -40,10 +39,9 @@
</span><span class="cx"> enum class LibraryVersion {
</span><span class="cx"> FirstWithNetworkCache = 0x02590116, // 601.1.22
</span><span class="cx"> FirstWithMediaTypesRequiringUserActionForPlayback = 0x025A0121, // 602.1.33
</span><ins>+ FirstWithExceptionsForDuplicateCompletionHandlerCalls = 0x025B0111, // 603.1.17
</ins><span class="cx"> };
</span><span class="cx">
</span><span class="cx"> bool linkedOnOrAfter(LibraryVersion);
</span><span class="cx">
</span><span class="cx"> }
</span><del>-
-#endif
</del></span></pre></div>
<a id="trunkToolsChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Tools/ChangeLog (210030 => 210031)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/ChangeLog        2016-12-20 21:14:00 UTC (rev 210030)
+++ trunk/Tools/ChangeLog        2016-12-20 21:18:30 UTC (rev 210031)
</span><span class="lines">@@ -1,3 +1,23 @@
</span><ins>+2016-12-20 Andy Estes <aestes@apple.com>
+
+ [Cocoa] REGRESSION (r209558): Calling decisionHandler multiple times in webView:decidePolicyForNavigationAction:decisionHandler: leads to a crash
+ https://bugs.webkit.org/show_bug.cgi?id=165992
+
+ Reviewed by Brady Eidson.
+
+ * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj:
+ * TestWebKitAPI/Tests/WebKit2Cocoa/DuplicateCompletionHandlerCalls.mm: Added.
+ (expectException):
+ (-[DuplicateCompletionHandlerCallsDelegate webView:decidePolicyForNavigationAction:decisionHandler:]):
+ (-[DuplicateCompletionHandlerCallsDelegate webView:decidePolicyForNavigationResponse:decisionHandler:]):
+ (-[DuplicateCompletionHandlerCallsDelegate webView:runJavaScriptAlertPanelWithMessage:initiatedByFrame:completionHandler:]):
+ (-[DuplicateCompletionHandlerCallsDelegate webView:runJavaScriptConfirmPanelWithMessage:initiatedByFrame:completionHandler:]):
+ (-[DuplicateCompletionHandlerCallsDelegate webView:runJavaScriptTextInputPanelWithPrompt:defaultText:initiatedByFrame:completionHandler:]):
+ (-[DuplicateCompletionHandlerCallsDelegate _webView:decideDatabaseQuotaForSecurityOrigin:currentQuota:currentOriginUsage:currentDatabaseUsage:expectedUsage:decisionHandler:]):
+ (-[DuplicateCompletionHandlerCallsDelegate _webView:willSubmitFormValues:userObject:submissionHandler:]):
+ (TEST):
+ * TestWebKitAPI/Tests/WebKit2Cocoa/duplicate-completion-handler-calls.html: Added.
+
</ins><span class="cx"> 2016-12-20 Dean Jackson <dino@apple.com>
</span><span class="cx">
</span><span class="cx"> Remove INDIE_UI
</span></span></pre></div>
<a id="trunkToolsTestWebKitAPITestWebKitAPIxcodeprojprojectpbxproj"></a>
<div class="modfile"><h4>Modified: trunk/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj (210030 => 210031)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj        2016-12-20 21:14:00 UTC (rev 210030)
+++ trunk/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj        2016-12-20 21:18:30 UTC (rev 210031)
</span><span class="lines">@@ -462,6 +462,8 @@
</span><span class="cx">                 A14FC5881B8991BF00D107EB /* ContentFiltering.mm in Sources */ = {isa = PBXBuildFile; fileRef = A14FC5861B8991B600D107EB /* ContentFiltering.mm */; };
</span><span class="cx">                 A14FC58B1B89927100D107EB /* ContentFilteringPlugIn.mm in Sources */ = {isa = PBXBuildFile; fileRef = A14FC5891B89927100D107EB /* ContentFilteringPlugIn.mm */; };
</span><span class="cx">                 A14FC5901B8AE36F00D107EB /* TestProtocol.mm in Sources */ = {isa = PBXBuildFile; fileRef = A14FC58E1B8AE36500D107EB /* TestProtocol.mm */; };
</span><ins>+                A155022A1E05020B00A24C57 /* DuplicateCompletionHandlerCalls.mm in Sources */ = {isa = PBXBuildFile; fileRef = A15502281E05020B00A24C57 /* DuplicateCompletionHandlerCalls.mm */; };
+                A155022C1E050D0300A24C57 /* duplicate-completion-handler-calls.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = A155022B1E050BC500A24C57 /* duplicate-completion-handler-calls.html */; };
</ins><span class="cx">                 A16F66BA1C40EB4F00BD4D24 /* ContentFiltering.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = A16F66B91C40EA2000BD4D24 /* ContentFiltering.html */; };
</span><span class="cx">                 A1C4FB731BACD1CA003742D0 /* pages.pages in Copy Resources */ = {isa = PBXBuildFile; fileRef = A1C4FB721BACD1B7003742D0 /* pages.pages */; };
</span><span class="cx">                 A1DF74321C41B65800A2F4D0 /* AlwaysRevalidatedURLSchemes.mm in Sources */ = {isa = PBXBuildFile; fileRef = A1DF74301C41B65800A2F4D0 /* AlwaysRevalidatedURLSchemes.mm */; };
</span><span class="lines">@@ -595,6 +597,7 @@
</span><span class="cx">                         dstSubfolderSpec = 7;
</span><span class="cx">                         files = (
</span><span class="cx">                                 9BD4239C1E04C01C00200395 /* chinese-character-with-image.html in Copy Resources */,
</span><ins>+                                A155022C1E050D0300A24C57 /* duplicate-completion-handler-calls.html in Copy Resources */,
</ins><span class="cx">                                 5110FCF91E01CD8A006F8D0B /* IndexUpgrade.blob in Copy Resources */,
</span><span class="cx">                                 5110FCF61E01CD83006F8D0B /* IndexUpgrade.sqlite3 in Copy Resources */,
</span><span class="cx">                                 5110FCF11E01CD64006F8D0B /* IDBIndexUpgradeToV2.html in Copy Resources */,
</span><span class="lines">@@ -1136,6 +1139,8 @@
</span><span class="cx">                 A14FC5891B89927100D107EB /* ContentFilteringPlugIn.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ContentFilteringPlugIn.mm; sourceTree = "<group>"; };
</span><span class="cx">                 A14FC58D1B8AE36500D107EB /* TestProtocol.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TestProtocol.h; path = cocoa/TestProtocol.h; sourceTree = "<group>"; };
</span><span class="cx">                 A14FC58E1B8AE36500D107EB /* TestProtocol.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = TestProtocol.mm; path = cocoa/TestProtocol.mm; sourceTree = "<group>"; };
</span><ins>+                A15502281E05020B00A24C57 /* DuplicateCompletionHandlerCalls.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = DuplicateCompletionHandlerCalls.mm; sourceTree = "<group>"; };
+                A155022B1E050BC500A24C57 /* duplicate-completion-handler-calls.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = "duplicate-completion-handler-calls.html"; sourceTree = "<group>"; };
</ins><span class="cx">                 A16F66B91C40EA2000BD4D24 /* ContentFiltering.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = ContentFiltering.html; sourceTree = "<group>"; };
</span><span class="cx">                 A18AA8CC1C3FA218009B2B97 /* ContentFiltering.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ContentFiltering.h; sourceTree = "<group>"; };
</span><span class="cx">                 A1A4FE5D18DD3DB700B5EA8A /* Download.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = Download.mm; sourceTree = "<group>"; };
</span><span class="lines">@@ -1461,6 +1466,7 @@
</span><span class="cx">                                 5C2936911D5BF63E00DEAB1E /* CookieAcceptPolicy.mm */,
</span><span class="cx">                                 2DC4CF761D2D9DD800ECCC94 /* DataDetection.mm */,
</span><span class="cx">                                 A1A4FE5D18DD3DB700B5EA8A /* Download.mm */,
</span><ins>+                                A15502281E05020B00A24C57 /* DuplicateCompletionHandlerCalls.mm */,
</ins><span class="cx">                                 2D8104CB1BEC13E70020DA46 /* FindInPage.mm */,
</span><span class="cx">                                 2D1FE0AF1AD465C1006CD9E6 /* FixedLayoutSize.mm */,
</span><span class="cx">                                 CD78E11A1DB7EA360014A2DE /* FullscreenDelegate.mm */,
</span><span class="lines">@@ -1625,6 +1631,7 @@
</span><span class="cx">                                 5714ECB81CA8B58800051AC8 /* DownloadRequestOriginalURL.html */,
</span><span class="cx">                                 5714ECBC1CA8C21800051AC8 /* DownloadRequestOriginalURL2.html */,
</span><span class="cx">                                 5714ECBA1CA8BFD100051AC8 /* DownloadRequestOriginalURLFrame.html */,
</span><ins>+                                A155022B1E050BC500A24C57 /* duplicate-completion-handler-calls.html */,
</ins><span class="cx">                                 9984FACD1CFFB038008D198C /* editable-body.html */,
</span><span class="cx">                                 93575C551D30366E000D604D /* focus-inputs.html */,
</span><span class="cx">                                 F4F405BA1D4C0CF8007A9707 /* full-size-autoplaying-video-with-audio.html */,
</span><span class="lines">@@ -2479,6 +2486,7 @@
</span><span class="cx">                                 7CCE7EEA1A411AE600447C4C /* DidNotHandleKeyDown.cpp in Sources */,
</span><span class="cx">                                 7CCE7EEB1A411AE600447C4C /* DocumentStartUserScriptAlertCrash.cpp in Sources */,
</span><span class="cx">                                 37A22AA71DCAA27200AFBFC4 /* ObservedRenderingProgressEventsAfterCrash.mm in Sources */,
</span><ins>+                                A155022A1E05020B00A24C57 /* DuplicateCompletionHandlerCalls.mm in Sources */,
</ins><span class="cx">                                 7CCE7EBB1A411A7E00447C4C /* DOMHTMLTableCellCellAbove.mm in Sources */,
</span><span class="cx">                                 5C9E56851DF9145400C9EE33 /* WebsitePolicies.mm in Sources */,
</span><span class="cx">                                 2D51A0C71C8BF00C00765C45 /* DOMHTMLVideoElementWrapper.mm in Sources */,
</span></span></pre></div>
<a id="trunkToolsTestWebKitAPITestsWebKit2CocoaDuplicateCompletionHandlerCallsmm"></a>
<div class="addfile"><h4>Added: trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/DuplicateCompletionHandlerCalls.mm (0 => 210031)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/DuplicateCompletionHandlerCalls.mm         (rev 0)
+++ trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/DuplicateCompletionHandlerCalls.mm        2016-12-20 21:18:30 UTC (rev 210031)
</span><span class="lines">@@ -0,0 +1,138 @@
</span><ins>+/*
+ * Copyright (C) 2016 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 <WebKit/WebKit.h>
+
+#if WK_API_ENABLED
+
+#import "PlatformUtilities.h"
+#import "Utilities.h"
+#import <WebKit/WKUIDelegatePrivate.h>
+#import <WebKit/WKWebViewPrivate.h>
+#import <WebKit/_WKInputDelegate.h>
+#import <wtf/RetainPtr.h>
+
+using namespace TestWebKitAPI;
+
+static bool testFinished;
+
+@interface DuplicateCompletionHandlerCallsDelegate : NSObject <WKNavigationDelegate, WKUIDelegate, _WKInputDelegate>
+@end
+
+@implementation DuplicateCompletionHandlerCallsDelegate
+
+static void expectException(void (^completionHandler)())
+{
+ bool exceptionThrown = false;
+ @try {
+ completionHandler();
+ } @catch (NSException *exception) {
+ EXPECT_WK_STREQ(NSInternalInconsistencyException, exception.name);
+ exceptionThrown = true;
+ }
+ EXPECT_TRUE(exceptionThrown);
+}
+
+- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler
+{
+ decisionHandler(WKNavigationActionPolicyAllow);
+
+ expectException(^ {
+ decisionHandler(WKNavigationActionPolicyAllow);
+ });
+}
+
+- (void)webView:(WKWebView *)webView decidePolicyForNavigationResponse:(WKNavigationResponse *)navigationResponse decisionHandler:(void (^)(WKNavigationResponsePolicy))decisionHandler
+{
+ decisionHandler(WKNavigationResponsePolicyAllow);
+
+ expectException(^ {
+ decisionHandler(WKNavigationResponsePolicyAllow);
+ });
+}
+
+- (void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)())completionHandler
+{
+ completionHandler();
+
+ expectException(^ {
+ completionHandler();
+ });
+}
+
+- (void)webView:(WKWebView *)webView runJavaScriptConfirmPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(BOOL))completionHandler
+{
+ completionHandler(YES);
+
+ expectException(^ {
+ completionHandler(YES);
+ });
+}
+
+- (void)webView:(WKWebView *)webView runJavaScriptTextInputPanelWithPrompt:(NSString *)prompt defaultText:(NSString *)defaultText initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(NSString * _Nullable))completionHandler
+{
+ completionHandler(nil);
+
+ expectException(^ {
+ completionHandler(nil);
+ });
+}
+
+- (void)_webView:(WKWebView *)webView decideDatabaseQuotaForSecurityOrigin:(WKSecurityOrigin *)securityOrigin currentQuota:(unsigned long long)currentQuota currentOriginUsage:(unsigned long long)currentOriginUsage currentDatabaseUsage:(unsigned long long)currentUsage expectedUsage:(unsigned long long)expectedUsage decisionHandler:(void (^)(unsigned long long newQuota))decisionHandler
+{
+ decisionHandler(expectedUsage);
+
+ expectException(^ {
+ decisionHandler(expectedUsage);
+ });
+}
+
+- (void)_webView:(WKWebView *)webView willSubmitFormValues:(NSDictionary *)values userObject:(NSObject<NSSecureCoding> *)userObject submissionHandler:(void (^)())submissionHandler
+{
+ submissionHandler();
+
+ expectException(^ {
+ submissionHandler();
+ });
+
+ testFinished = true;
+}
+
+@end
+
+TEST(WebKit2, DuplicateCompletionHandlerCalls)
+{
+ auto webView = adoptNS([[WKWebView alloc] initWithFrame:CGRectMake(0, 0, 800, 600)]);
+ auto delegate = adoptNS([[DuplicateCompletionHandlerCallsDelegate alloc] init]);
+ [webView setNavigationDelegate:delegate.get()];
+ [webView setUIDelegate:delegate.get()];
+ [webView _setInputDelegate:delegate.get()];
+ [webView loadRequest:[NSURLRequest requestWithURL:[[NSBundle mainBundle] URLForResource:@"duplicate-completion-handler-calls" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"]]];
+
+ Util::run(&testFinished);
+}
+
+#endif // WK_API_ENABLED
</ins></span></pre></div>
<a id="trunkToolsTestWebKitAPITestsWebKit2Cocoaduplicatecompletionhandlercallshtml"></a>
<div class="addfile"><h4>Added: trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/duplicate-completion-handler-calls.html (0 => 210031)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/duplicate-completion-handler-calls.html         (rev 0)
+++ trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/duplicate-completion-handler-calls.html        2016-12-20 21:18:30 UTC (rev 210031)
</span><span class="lines">@@ -0,0 +1,9 @@
</span><ins>+<!DOCTYPE html>
+<form action="about:blank"></form>
+<script>
+ alert("alert");
+ confirm("confirm");
+ prompt("prompt");
+ openDatabase("testDatabase", "1", "test database", 1024);
+ document.forms[0].submit();
+</script>
</ins></span></pre>
</div>
</div>
</body>
</html>