Commit 57e5c3dd authored by Hiroshi Ichikawa's avatar Hiroshi Ichikawa Committed by Commit Bot

Add delegate for certificate errors in CWVWebView.

Bug: 884047
Cq-Include-Trybots: luci.chromium.try:ios-simulator-cronet;luci.chromium.try:ios-simulator-full-configs
Change-Id: I38633533a62eb69d2b1c0ff305d88481f5078f87
Reviewed-on: https://chromium-review.googlesource.com/c/1273176
Commit-Queue: Hiroshi Ichikawa <ichikawa@chromium.org>
Reviewed-by: default avatarEugene But <eugenebut@chromium.org>
Cr-Commit-Position: refs/heads/master@{#602211}
parent 4b0b9b5f
...@@ -76,6 +76,17 @@ NSDictionary* NSDictionaryFromDictionaryValue( ...@@ -76,6 +76,17 @@ NSDictionary* NSDictionaryFromDictionaryValue(
DCHECK(ns_dictionary) << "Failed to convert JSON to NSDictionary"; DCHECK(ns_dictionary) << "Failed to convert JSON to NSDictionary";
return ns_dictionary; return ns_dictionary;
} }
// A WebStateUserData to hold a reference to a corresponding CWVWebView.
class WebViewHolder : public web::WebStateUserData<WebViewHolder> {
public:
explicit WebViewHolder(web::WebState* web_state) {}
CWVWebView* web_view() const { return web_view_; }
void set_web_view(CWVWebView* web_view) { web_view_ = web_view; }
private:
__weak CWVWebView* web_view_ = nil;
};
} // namespace } // namespace
@interface CWVWebView ()<CRWWebStateDelegate, CRWWebStateObserver> { @interface CWVWebView ()<CRWWebStateDelegate, CRWWebStateObserver> {
...@@ -175,6 +186,13 @@ static NSString* gUserAgentProduct = nil; ...@@ -175,6 +186,13 @@ static NSString* gUserAgentProduct = nil;
} }
} }
+ (CWVWebView*)webViewForWebState:(web::WebState*)webState {
WebViewHolder* holder = WebViewHolder::FromWebState(webState);
CWVWebView* webView = holder->web_view();
DCHECK(webView);
return webView;
}
- (instancetype)initWithFrame:(CGRect)frame - (instancetype)initWithFrame:(CGRect)frame
configuration:(CWVWebViewConfiguration*)configuration { configuration:(CWVWebViewConfiguration*)configuration {
self = [super initWithFrame:frame]; self = [super initWithFrame:frame];
...@@ -198,9 +216,12 @@ static NSString* gUserAgentProduct = nil; ...@@ -198,9 +216,12 @@ static NSString* gUserAgentProduct = nil;
} }
- (void)dealloc { - (void)dealloc {
if (_webState && _webStateObserver) { if (_webState) {
_webState->RemoveObserver(_webStateObserver.get()); if (_webStateObserver) {
_webStateObserver.reset(); _webState->RemoveObserver(_webStateObserver.get());
_webStateObserver.reset();
}
WebViewHolder::RemoveFromWebState(_webState.get());
} }
} }
...@@ -557,6 +578,7 @@ static NSString* gUserAgentProduct = nil; ...@@ -557,6 +578,7 @@ static NSString* gUserAgentProduct = nil;
for (const auto& pair : _scriptCommandCallbacks) { for (const auto& pair : _scriptCommandCallbacks) {
_webState->RemoveScriptCommandCallback(pair.first); _webState->RemoveScriptCommandCallback(pair.first);
} }
WebViewHolder::RemoveFromWebState(_webState.get());
if (_webState->GetView().superview == self) { if (_webState->GetView().superview == self) {
// The web view provided by the old |_webState| has been added as a // The web view provided by the old |_webState| has been added as a
// subview. It must be removed and replaced with a new |_webState|'s web // subview. It must be removed and replaced with a new |_webState|'s web
...@@ -577,6 +599,9 @@ static NSString* gUserAgentProduct = nil; ...@@ -577,6 +599,9 @@ static NSString* gUserAgentProduct = nil;
_webState = web::WebState::Create(webStateCreateParams); _webState = web::WebState::Create(webStateCreateParams);
} }
WebViewHolder::CreateForWebState(_webState.get());
WebViewHolder::FromWebState(_webState.get())->set_web_view(self);
if (!_webStateObserver) { if (!_webStateObserver) {
_webStateObserver = std::make_unique<web::WebStateObserverBridge>(self); _webStateObserver = std::make_unique<web::WebStateObserverBridge>(self);
} }
......
...@@ -9,8 +9,19 @@ ...@@ -9,8 +9,19 @@
NS_ASSUME_NONNULL_BEGIN NS_ASSUME_NONNULL_BEGIN
namespace web {
class WebState;
}
@interface CWVWebView () @interface CWVWebView ()
// Returns CWVWebView which corresponds to the given web state.
// It causes an assertion failure if the web state has no corresponding
// CWVWebView.
//
// TODO(crbug.com/896961): Write unit test for this method.
+ (CWVWebView*)webViewForWebState:(web::WebState*)webState;
// This is called by the associated CWVWebViewConfiguration in order to shut // This is called by the associated CWVWebViewConfiguration in order to shut
// down cleanly. See CWVWebViewConfiguration's |shutDown| method for more info. // down cleanly. See CWVWebViewConfiguration's |shutDown| method for more info.
- (void)shutDown; - (void)shutDown;
......
...@@ -29,6 +29,13 @@ class WebViewWebClient : public web::WebClient { ...@@ -29,6 +29,13 @@ class WebViewWebClient : public web::WebClient {
NSString* GetDocumentStartScriptForMainFrame( NSString* GetDocumentStartScriptForMainFrame(
web::BrowserState* browser_state) const override; web::BrowserState* browser_state) const override;
base::string16 GetPluginNotSupportedText() const override; base::string16 GetPluginNotSupportedText() const override;
void AllowCertificateError(
web::WebState* web_state,
int cert_error,
const net::SSLInfo& ssl_info,
const GURL& request_url,
bool overridable,
const base::RepeatingCallback<void(bool)>& callback) override;
private: private:
DISALLOW_COPY_AND_ASSIGN(WebViewWebClient); DISALLOW_COPY_AND_ASSIGN(WebViewWebClient);
......
...@@ -4,15 +4,25 @@ ...@@ -4,15 +4,25 @@
#import "ios/web_view/internal/web_view_web_client.h" #import "ios/web_view/internal/web_view_web_client.h"
#include <dispatch/dispatch.h>
#include "base/logging.h" #include "base/logging.h"
#include "base/mac/bundle_locations.h" #include "base/mac/bundle_locations.h"
#include "base/strings/sys_string_conversions.h" #include "base/strings/sys_string_conversions.h"
#include "base/task/post_task.h"
#include "components/strings/grit/components_strings.h" #include "components/strings/grit/components_strings.h"
#include "ios/web/public/ssl_status.h"
#include "ios/web/public/user_agent.h" #include "ios/web/public/user_agent.h"
#include "ios/web/public/web_task_traits.h"
#include "ios/web/public/web_thread.h"
#import "ios/web_view/internal/cwv_ssl_status_internal.h"
#import "ios/web_view/internal/cwv_web_view_internal.h"
#include "ios/web_view/internal/web_view_browser_state.h" #include "ios/web_view/internal/web_view_browser_state.h"
#import "ios/web_view/internal/web_view_early_page_script_provider.h" #import "ios/web_view/internal/web_view_early_page_script_provider.h"
#import "ios/web_view/internal/web_view_web_main_parts.h" #import "ios/web_view/internal/web_view_web_main_parts.h"
#include "ios/web_view/public/cwv_web_view.h" #import "ios/web_view/public/cwv_navigation_delegate.h"
#import "ios/web_view/public/cwv_web_view.h"
#include "net/cert/cert_status_flags.h"
#include "ui/base/l10n/l10n_util.h" #include "ui/base/l10n/l10n_util.h"
#include "ui/base/resource/resource_bundle.h" #include "ui/base/resource/resource_bundle.h"
...@@ -88,4 +98,45 @@ base::string16 WebViewWebClient::GetPluginNotSupportedText() const { ...@@ -88,4 +98,45 @@ base::string16 WebViewWebClient::GetPluginNotSupportedText() const {
return l10n_util::GetStringUTF16(IDS_PLUGIN_NOT_SUPPORTED); return l10n_util::GetStringUTF16(IDS_PLUGIN_NOT_SUPPORTED);
} }
void WebViewWebClient::AllowCertificateError(
web::WebState* web_state,
int cert_error,
const net::SSLInfo& ssl_info,
const GURL& request_url,
bool overridable,
const base::RepeatingCallback<void(bool)>& callback) {
CWVWebView* web_view = [CWVWebView webViewForWebState:web_state];
base::RepeatingCallback<void(bool)> callback_copy = callback;
SEL selector = @selector
(webView:didFailNavigationWithSSLError:overridable:decisionHandler:);
if ([web_view.navigationDelegate respondsToSelector:selector]) {
// TODO(crbug.com/898037): Pass a more informative error here.
NSError* error = [NSError errorWithDomain:NSURLErrorDomain
code:NSURLErrorSecureConnectionFailed
userInfo:nil];
void (^decisionHandler)(CWVSSLErrorDecision) =
^(CWVSSLErrorDecision decision) {
switch (decision) {
case CWVSSLErrorDecisionOverrideErrorAndReload: {
callback_copy.Run(true);
break;
}
case CWVSSLErrorDecisionDoNothing: {
callback_copy.Run(false);
break;
}
}
};
[web_view.navigationDelegate webView:web_view
didFailNavigationWithSSLError:error
overridable:overridable
decisionHandler:decisionHandler];
} else {
callback_copy.Run(false);
}
}
} // namespace ios_web_view } // namespace ios_web_view
...@@ -10,8 +10,18 @@ ...@@ -10,8 +10,18 @@
#import "cwv_navigation_type.h" #import "cwv_navigation_type.h"
@protocol CRIWVTranslateDelegate; @protocol CRIWVTranslateDelegate;
@class CWVSSLStatus;
@class CWVWebView; @class CWVWebView;
// The decision to pass back to the decision handler from
// -webView:didFailNavigationWithSSLError:overridable:decisionHandler:.
typedef NS_ENUM(NSInteger, CWVSSLErrorDecision) {
// Leave the failure as is and take no further action.
CWVSSLErrorDecisionDoNothing = 0,
// Ignore the error and reload the page.
CWVSSLErrorDecisionOverrideErrorAndReload,
};
// Navigation delegate protocol for CWVWebViews. Allows embedders to hook // Navigation delegate protocol for CWVWebViews. Allows embedders to hook
// page loading and receive events for navigation. // page loading and receive events for navigation.
@protocol CWVNavigationDelegate<NSObject> @protocol CWVNavigationDelegate<NSObject>
...@@ -41,8 +51,27 @@ ...@@ -41,8 +51,27 @@
- (void)webViewDidFinishNavigation:(CWVWebView*)webView; - (void)webViewDidFinishNavigation:(CWVWebView*)webView;
// Notifies the delegate that page load has failed. // Notifies the delegate that page load has failed.
// When the page load has failed due to an SSL certification error,
// -webView:didFailNavigationWithSSLError:overridable:decisionHandler:
// is called instead of this method.
- (void)webView:(CWVWebView*)webView didFailNavigationWithError:(NSError*)error; - (void)webView:(CWVWebView*)webView didFailNavigationWithError:(NSError*)error;
// Notifies the delegate that the page load has failed due to an SSL error. If
// |overridable| is YES, the method can ignore the error and reload the page by
// calling |decisionHandler| with CWVSSLErrorDecisionOverrideErrorAndReload. The
// method can leave the failure as is by calling |decisionHandler| with
// CWVSSLErrorDecisionDoNothing.
//
// Note: When |decisionHandler| is called with
// CWVSSLErrorDecisionOverrideErrorAndReload, it must not be called
// synchronously in the method. It breaks status management and causes an
// assertion failure. It must be called asynchronously to avoid it.
- (void)webView:(CWVWebView*)webView
didFailNavigationWithSSLError:(NSError*)error
overridable:(BOOL)overridable
decisionHandler:
(void (^)(CWVSSLErrorDecision))decisionHandler;
// Notifies the delegate that web view process was terminated // Notifies the delegate that web view process was terminated
// (usually by crashing, though possibly by other means). // (usually by crashing, though possibly by other means).
- (void)webViewWebContentProcessDidTerminate:(CWVWebView*)webView; - (void)webViewWebContentProcessDidTerminate:(CWVWebView*)webView;
......
...@@ -509,6 +509,15 @@ NSString* const kWebViewShellJavaScriptDialogTextFieldAccessibiltyIdentifier = ...@@ -509,6 +509,15 @@ NSString* const kWebViewShellJavaScriptDialogTextFieldAccessibiltyIdentifier =
NSLog(@"%@", NSStringFromSelector(_cmd)); NSLog(@"%@", NSStringFromSelector(_cmd));
} }
- (void)webView:(CWVWebView*)webView
didFailNavigationWithSSLError:(NSError*)error
overridable:(BOOL)overridable
decisionHandler:
(void (^)(CWVSSLErrorDecision))decisionHandler {
NSLog(@"%@", NSStringFromSelector(_cmd));
decisionHandler(CWVSSLErrorDecisionDoNothing);
}
#pragma mark CWVScriptCommandHandler #pragma mark CWVScriptCommandHandler
- (BOOL)webView:(CWVWebView*)webView - (BOOL)webView:(CWVWebView*)webView
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment