Commit 28b785d1 authored by Livvie Lin's avatar Livvie Lin Committed by Commit Bot

Generate SSL interstitial HTML in PrepareErrorPage

https://chromium-review.googlesource.com/c/chromium/src/+/1769353
added a mode to IOSSSlErrorHandler that returns error HTML in a
callback. This CL calls into IOSSSLErrorHandler::HandleSSLError
from PrepareErrorPage to display the actual interstitial on an
SSL error instead of a generic error page.

Bug: 987407
Change-Id: I472e9012988a0b8fcc3f72d8dbc52aad07c067a6
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1793260
Commit-Queue: Livvie Lin <livvielin@chromium.org>
Reviewed-by: default avatarEugene But <eugenebut@chromium.org>
Reviewed-by: default avatarGauthier Ambard <gambard@chromium.org>
Cr-Commit-Position: refs/heads/master@{#708817}
parent 86fcad92
...@@ -54,13 +54,14 @@ class ChromeWebClient : public web::WebClient { ...@@ -54,13 +54,14 @@ class ChromeWebClient : public web::WebClient {
bool overridable, bool overridable,
int64_t navigation_id, int64_t navigation_id,
const base::Callback<void(bool)>& callback) override; const base::Callback<void(bool)>& callback) override;
void PrepareErrorPage( void PrepareErrorPage(web::WebState* web_state,
web::WebState* web_state, const GURL& url,
const GURL& url, NSError* error,
NSError* error, bool is_post,
bool is_post, bool is_off_the_record,
bool is_off_the_record, const base::Optional<net::SSLInfo>& info,
const base::OnceCallback<void(NSString*)> callback) override; int64_t navigation_id,
base::OnceCallback<void(NSString*)> callback) override;
UIView* GetWindowedContainer() override; UIView* GetWindowedContainer() override;
private: private:
......
...@@ -217,6 +217,8 @@ void ChromeWebClient::PrepareErrorPage( ...@@ -217,6 +217,8 @@ void ChromeWebClient::PrepareErrorPage(
NSError* error, NSError* error,
bool is_post, bool is_post,
bool is_off_the_record, bool is_off_the_record,
const base::Optional<net::SSLInfo>& info,
int64_t navigation_id,
base::OnceCallback<void(NSString*)> callback) { base::OnceCallback<void(NSString*)> callback) {
if (reading_list::IsOfflinePageWithoutNativeContentEnabled()) { if (reading_list::IsOfflinePageWithoutNativeContentEnabled()) {
OfflinePageTabHelper* offline_page_tab_helper = OfflinePageTabHelper* offline_page_tab_helper =
...@@ -238,7 +240,24 @@ void ChromeWebClient::PrepareErrorPage( ...@@ -238,7 +240,24 @@ void ChromeWebClient::PrepareErrorPage(
} }
} }
DCHECK(error); DCHECK(error);
std::move(callback).Run(GetErrorPage(url, error, is_post, is_off_the_record)); __block NSString* error_html = nil;
__block base::OnceCallback<void(NSString*)> error_html_callback =
std::move(callback);
if (info.has_value()) {
base::OnceCallback<void(bool)> proceed_callback;
base::OnceCallback<void(NSString*)> blocking_page_callback =
base::BindOnce(^(NSString* blocking_page_html) {
error_html = blocking_page_html;
std::move(error_html_callback).Run(error_html);
});
IOSSSLErrorHandler::HandleSSLError(
web_state, net::MapCertStatusToNetError(info.value().cert_status),
info.value(), url, info.value().is_fatal_cert_error, navigation_id,
std::move(proceed_callback), std::move(blocking_page_callback));
} else {
std::move(error_html_callback)
.Run(GetErrorPage(url, error, is_post, is_off_the_record));
}
} }
UIView* ChromeWebClient::GetWindowedContainer() { UIView* ChromeWebClient::GetWindowedContainer() {
......
...@@ -202,7 +202,9 @@ TEST_F(ChromeWebClientTest, PrepareErrorPageNonPostNonOtr) { ...@@ -202,7 +202,9 @@ TEST_F(ChromeWebClientTest, PrepareErrorPageNonPostNonOtr) {
web::TestWebState test_web_state; web::TestWebState test_web_state;
web_client.PrepareErrorPage(&test_web_state, GURL(kTestUrl), error, web_client.PrepareErrorPage(&test_web_state, GURL(kTestUrl), error,
/*is_post=*/false, /*is_post=*/false,
/*is_off_the_record=*/false, std::move(callback)); /*is_off_the_record=*/false,
/*info=*/base::nullopt,
/*navigation_id=*/0, std::move(callback));
EXPECT_TRUE(WaitUntilConditionOrTimeout(kWaitForActionTimeout, ^bool { EXPECT_TRUE(WaitUntilConditionOrTimeout(kWaitForActionTimeout, ^bool {
base::RunLoop().RunUntilIdle(); base::RunLoop().RunUntilIdle();
return callback_called; return callback_called;
...@@ -226,7 +228,9 @@ TEST_F(ChromeWebClientTest, PrepareErrorPagePostNonOtr) { ...@@ -226,7 +228,9 @@ TEST_F(ChromeWebClientTest, PrepareErrorPagePostNonOtr) {
web::TestWebState test_web_state; web::TestWebState test_web_state;
web_client.PrepareErrorPage(&test_web_state, GURL(kTestUrl), error, web_client.PrepareErrorPage(&test_web_state, GURL(kTestUrl), error,
/*is_post=*/true, /*is_post=*/true,
/*is_off_the_record=*/false, std::move(callback)); /*is_off_the_record=*/false,
/*info=*/base::nullopt,
/*navigation_id=*/0, std::move(callback));
EXPECT_TRUE(WaitUntilConditionOrTimeout(kWaitForActionTimeout, ^bool { EXPECT_TRUE(WaitUntilConditionOrTimeout(kWaitForActionTimeout, ^bool {
base::RunLoop().RunUntilIdle(); base::RunLoop().RunUntilIdle();
return callback_called; return callback_called;
...@@ -250,7 +254,9 @@ TEST_F(ChromeWebClientTest, PrepareErrorPageNonPostOtr) { ...@@ -250,7 +254,9 @@ TEST_F(ChromeWebClientTest, PrepareErrorPageNonPostOtr) {
web::TestWebState test_web_state; web::TestWebState test_web_state;
web_client.PrepareErrorPage(&test_web_state, GURL(kTestUrl), error, web_client.PrepareErrorPage(&test_web_state, GURL(kTestUrl), error,
/*is_post=*/false, /*is_post=*/false,
/*is_off_the_record=*/true, std::move(callback)); /*is_off_the_record=*/true,
/*info=*/base::nullopt,
/*navigation_id=*/0, std::move(callback));
EXPECT_TRUE(WaitUntilConditionOrTimeout(kWaitForActionTimeout, ^bool { EXPECT_TRUE(WaitUntilConditionOrTimeout(kWaitForActionTimeout, ^bool {
base::RunLoop().RunUntilIdle(); base::RunLoop().RunUntilIdle();
return callback_called; return callback_called;
...@@ -274,7 +280,9 @@ TEST_F(ChromeWebClientTest, PrepareErrorPagePostOtr) { ...@@ -274,7 +280,9 @@ TEST_F(ChromeWebClientTest, PrepareErrorPagePostOtr) {
web::TestWebState test_web_state; web::TestWebState test_web_state;
web_client.PrepareErrorPage(&test_web_state, GURL(kTestUrl), error, web_client.PrepareErrorPage(&test_web_state, GURL(kTestUrl), error,
/*is_post=*/true, /*is_post=*/true,
/*is_off_the_record=*/true, std::move(callback)); /*is_off_the_record=*/true,
/*info=*/base::nullopt,
/*navigation_id=*/0, std::move(callback));
EXPECT_TRUE(WaitUntilConditionOrTimeout(kWaitForActionTimeout, ^bool { EXPECT_TRUE(WaitUntilConditionOrTimeout(kWaitForActionTimeout, ^bool {
base::RunLoop().RunUntilIdle(); base::RunLoop().RunUntilIdle();
return callback_called; return callback_called;
...@@ -283,3 +291,6 @@ TEST_F(ChromeWebClientTest, PrepareErrorPagePostOtr) { ...@@ -283,3 +291,6 @@ TEST_F(ChromeWebClientTest, PrepareErrorPagePostOtr) {
/*is_off_the_record=*/true), /*is_off_the_record=*/true),
page); page);
} }
// TODO(crbug.com/1017406): Add tests for SSL committed interstitials, where
// an SSLInfo value is passed into PrepareErrorPage.
...@@ -713,7 +713,9 @@ void ReportOutOfSyncURLInDidStartProvisionalNavigation( ...@@ -713,7 +713,9 @@ void ReportOutOfSyncURLInDidStartProvisionalNavigation(
// This must be reset at the end, since code above may need information about // This must be reset at the end, since code above may need information about
// the pending load. // the pending load.
self.pendingNavigationInfo = nil; self.pendingNavigationInfo = nil;
_certVerificationErrors->Clear(); if (!web::IsWKWebViewSSLCertError(error)) {
_certVerificationErrors->Clear();
}
// Remove the navigation to immediately get rid of pending item. // Remove the navigation to immediately get rid of pending item.
if (web::WKNavigationState::NONE != if (web::WKNavigationState::NONE !=
[self.navigationStates stateForNavigation:navigation]) { [self.navigationStates stateForNavigation:navigation]) {
...@@ -736,7 +738,11 @@ void ReportOutOfSyncURLInDidStartProvisionalNavigation( ...@@ -736,7 +738,11 @@ void ReportOutOfSyncURLInDidStartProvisionalNavigation(
BOOL committedNavigation = BOOL committedNavigation =
[self.navigationStates isCommittedNavigation:navigation]; [self.navigationStates isCommittedNavigation:navigation];
_certVerificationErrors->Clear(); web::NavigationContextImpl* context =
[self.navigationStates contextForNavigation:navigation];
if (!web::IsWKWebViewSSLCertError(context->GetError())) {
_certVerificationErrors->Clear();
}
// Invariant: Every |navigation| should have a |context|. Note that violation // Invariant: Every |navigation| should have a |context|. Note that violation
// of this invariant is currently observed in production, but the cause is not // of this invariant is currently observed in production, but the cause is not
...@@ -744,8 +750,6 @@ void ReportOutOfSyncURLInDidStartProvisionalNavigation( ...@@ -744,8 +750,6 @@ void ReportOutOfSyncURLInDidStartProvisionalNavigation(
// they arise. // they arise.
// TODO(crbug.com/864769): Remove nullptr checks on |context| in this method // TODO(crbug.com/864769): Remove nullptr checks on |context| in this method
// once the root cause of the invariant violation is found. // once the root cause of the invariant violation is found.
web::NavigationContextImpl* context =
[self.navigationStates contextForNavigation:navigation];
DCHECK(context); DCHECK(context);
UMA_HISTOGRAM_BOOLEAN("IOS.CommittedNavigationHasContext", context); UMA_HISTOGRAM_BOOLEAN("IOS.CommittedNavigationHasContext", context);
...@@ -1030,9 +1034,12 @@ void ReportOutOfSyncURLInDidStartProvisionalNavigation( ...@@ -1030,9 +1034,12 @@ void ReportOutOfSyncURLInDidStartProvisionalNavigation(
[self.delegate navigationHandler:self didFinishNavigation:context]; [self.delegate navigationHandler:self didFinishNavigation:context];
// Remove the navigation to immediately get rid of pending item. // Remove the navigation to immediately get rid of pending item. Navigation
// should not be cleared, however, in the case of a committed interstitial
// for an SSL error.
if (web::WKNavigationState::NONE != if (web::WKNavigationState::NONE !=
[self.navigationStates stateForNavigation:navigation]) { [self.navigationStates stateForNavigation:navigation] &&
!web::IsWKWebViewSSLCertError(context->GetError())) {
[self.navigationStates removeNavigation:navigation]; [self.navigationStates removeNavigation:navigation];
} }
} }
...@@ -1750,7 +1757,7 @@ void ReportOutOfSyncURLInDidStartProvisionalNavigation( ...@@ -1750,7 +1757,7 @@ void ReportOutOfSyncURLInDidStartProvisionalNavigation(
web::NavigationManager* navManager = web::NavigationManager* navManager =
self.webStateImpl->GetNavigationManager(); self.webStateImpl->GetNavigationManager();
web::NavigationItem* lastCommittedItem = navManager->GetLastCommittedItem(); web::NavigationItem* lastCommittedItem = navManager->GetLastCommittedItem();
if (lastCommittedItem) { if (lastCommittedItem && !web::IsWKWebViewSSLCertError(error)) {
// Reset SSL status for last committed navigation to avoid showing security // Reset SSL status for last committed navigation to avoid showing security
// status for error pages. // status for error pages.
if (!lastCommittedItem->GetSSL().Equals(web::SSLStatus())) { if (!lastCommittedItem->GetSSL().Equals(web::SSLStatus())) {
...@@ -1857,7 +1864,7 @@ void ReportOutOfSyncURLInDidStartProvisionalNavigation( ...@@ -1857,7 +1864,7 @@ void ReportOutOfSyncURLInDidStartProvisionalNavigation(
case web::ErrorRetryCommand::kLoadError: case web::ErrorRetryCommand::kLoadError:
[self loadErrorPageForNavigationItem:item [self loadErrorPageForNavigationItem:item
navigationContext:context navigationContext:originalNavigation
webView:webView]; webView:webView];
break; break;
...@@ -1918,13 +1925,52 @@ void ReportOutOfSyncURLInDidStartProvisionalNavigation( ...@@ -1918,13 +1925,52 @@ void ReportOutOfSyncURLInDidStartProvisionalNavigation(
// Loads the error page. // Loads the error page.
- (void)loadErrorPageForNavigationItem:(web::NavigationItemImpl*)item - (void)loadErrorPageForNavigationItem:(web::NavigationItemImpl*)item
navigationContext:(web::NavigationContextImpl*)context navigationContext:(WKNavigation*)navigation
webView:(WKWebView*)webView { webView:(WKWebView*)webView {
web::NavigationContextImpl* context =
[self.navigationStates contextForNavigation:navigation];
NSError* error = context->GetError(); NSError* error = context->GetError();
DCHECK(error); DCHECK(error);
DCHECK_EQ(item->GetUniqueID(), context->GetNavigationItemUniqueID()); DCHECK_EQ(item->GetUniqueID(), context->GetNavigationItemUniqueID());
if (web::IsWKWebViewSSLCertError(error)) { net::SSLInfo info;
base::Optional<net::SSLInfo> ssl_info = base::nullopt;
if (web::IsWKWebViewSSLCertError(error) &&
base::FeatureList::IsEnabled(web::features::kSSLCommittedInterstitials)) {
web::GetSSLInfoFromWKWebViewSSLCertError(error, &info);
ssl_info = base::make_optional<net::SSLInfo>(info);
if (info.cert) {
// Retrieve verification results from _certVerificationErrors cache to
// avoid unnecessary recalculations. Verification results are cached for
// the leaf cert, because the cert chain in
// |didReceiveAuthenticationChallenge:| is the OS constructed chain, while
// |chain| is the chain from the server.
NSArray* chain = error.userInfo[web::kNSErrorPeerCertificateChainKey];
NSURL* requestURL = error.userInfo[web::kNSErrorFailingURLKey];
NSString* host = requestURL.host;
scoped_refptr<net::X509Certificate> leafCert;
if (chain.count && host.length) {
// The complete cert chain may not be available, so the leaf cert is
// used as a key to retrieve _certVerificationErrors, as well as for
// storing the cert decision.
leafCert = web::CreateCertFromChain(@[ chain.firstObject ]);
if (leafCert) {
auto error = _certVerificationErrors->Get(
{leafCert, base::SysNSStringToUTF8(host)});
bool cacheHit = error != _certVerificationErrors->end();
if (cacheHit) {
info.is_fatal_cert_error = error->second.is_recoverable;
info.cert_status = error->second.status;
}
UMA_HISTOGRAM_BOOLEAN("WebController.CertVerificationErrorsCacheHit",
cacheHit);
}
}
}
} else if (web::IsWKWebViewSSLCertError(error) &&
!base::FeatureList::IsEnabled(
web::features::kSSLCommittedInterstitials)) {
// This could happen only if certificate is absent or could not be parsed. // This could happen only if certificate is absent or could not be parsed.
error = web::NetErrorFromError(error, net::ERR_SSL_SERVER_CERT_BAD_FORMAT); error = web::NetErrorFromError(error, net::ERR_SSL_SERVER_CERT_BAD_FORMAT);
#if defined(DEBUG) #if defined(DEBUG)
...@@ -1938,10 +1984,12 @@ void ReportOutOfSyncURLInDidStartProvisionalNavigation( ...@@ -1938,10 +1984,12 @@ void ReportOutOfSyncURLInDidStartProvisionalNavigation(
NSString* failingURLString = NSString* failingURLString =
error.userInfo[NSURLErrorFailingURLStringErrorKey]; error.userInfo[NSURLErrorFailingURLStringErrorKey];
GURL failingURL(base::SysNSStringToUTF8(failingURLString)); GURL failingURL(base::SysNSStringToUTF8(failingURLString));
GURL itemURL = item->GetURL();
int itemID = item->GetUniqueID();
web::GetWebClient()->PrepareErrorPage( web::GetWebClient()->PrepareErrorPage(
self.webStateImpl, failingURL, error, context->IsPost(), self.webStateImpl, failingURL, error, context->IsPost(),
self.webStateImpl->GetBrowserState()->IsOffTheRecord(), self.webStateImpl->GetBrowserState()->IsOffTheRecord(), ssl_info,
base::BindOnce(^(NSString* errorHTML) { context->GetNavigationId(), base::BindOnce(^(NSString* errorHTML) {
if (errorHTML) { if (errorHTML) {
WKNavigation* navigation = WKNavigation* navigation =
[webView loadHTMLString:errorHTML [webView loadHTMLString:errorHTML
...@@ -1952,7 +2000,7 @@ void ReportOutOfSyncURLInDidStartProvisionalNavigation( ...@@ -1952,7 +2000,7 @@ void ReportOutOfSyncURLInDidStartProvisionalNavigation(
/*has_user_gesture=*/false, ui::PAGE_TRANSITION_FIRST, /*has_user_gesture=*/false, ui::PAGE_TRANSITION_FIRST,
/*is_renderer_initiated=*/false); /*is_renderer_initiated=*/false);
loadHTMLContext->SetLoadingErrorPage(true); loadHTMLContext->SetLoadingErrorPage(true);
loadHTMLContext->SetNavigationItemUniqueID(item->GetUniqueID()); loadHTMLContext->SetNavigationItemUniqueID(itemID);
[self.navigationStates setContext:std::move(loadHTMLContext) [self.navigationStates setContext:std::move(loadHTMLContext)
forNavigation:navigation]; forNavigation:navigation];
...@@ -1968,7 +2016,8 @@ void ReportOutOfSyncURLInDidStartProvisionalNavigation( ...@@ -1968,7 +2016,8 @@ void ReportOutOfSyncURLInDidStartProvisionalNavigation(
// released after // released after
// |self.navigationManagerImpl->CommitPendingItem(context->ReleaseItem()|. // |self.navigationManagerImpl->CommitPendingItem(context->ReleaseItem()|.
// Remove this once navigation refactor is done. // Remove this once navigation refactor is done.
GURL itemURL = item->GetURL(); web::NavigationContextImpl* context =
[self.navigationStates contextForNavigation:navigation];
self.navigationManagerImpl->CommitPendingItem(context->ReleaseItem()); self.navigationManagerImpl->CommitPendingItem(context->ReleaseItem());
if (web::GetWebClient()->IsSlimNavigationManagerEnabled()) { if (web::GetWebClient()->IsSlimNavigationManagerEnabled()) {
[self.delegate navigationHandler:self [self.delegate navigationHandler:self
...@@ -1996,6 +2045,19 @@ void ReportOutOfSyncURLInDidStartProvisionalNavigation( ...@@ -1996,6 +2045,19 @@ void ReportOutOfSyncURLInDidStartProvisionalNavigation(
self.webStateImpl->OnNavigationFinished(context); self.webStateImpl->OnNavigationFinished(context);
} }
// For SSL cert error pages, SSLStatus needs to be set manually because
// the placeholder navigation for the error page is committed and
// there is no server trust (since there's no network navigation), which
// is required to create a cert in CRWSSLStatusUpdater.
if (web::IsWKWebViewSSLCertError(context->GetError())) {
web::SSLStatus& SSLStatus =
self.navigationManagerImpl->GetLastCommittedItem()->GetSSL();
SSLStatus.cert_status = info.cert_status;
SSLStatus.certificate = info.cert;
SSLStatus.security_style = web::SECURITY_STYLE_AUTHENTICATION_BROKEN;
self.webStateImpl->DidChangeVisibleSecurityState();
}
[self.delegate navigationHandler:self [self.delegate navigationHandler:self
didCompleteLoadWithSuccess:NO didCompleteLoadWithSuccess:NO
forContext:context]; forContext:context];
......
...@@ -57,6 +57,8 @@ class TestWebClient : public web::WebClient { ...@@ -57,6 +57,8 @@ class TestWebClient : public web::WebClient {
NSError* error, NSError* error,
bool is_post, bool is_post,
bool is_off_the_record, bool is_off_the_record,
const base::Optional<net::SSLInfo>& info,
int64_t navigation_id,
base::OnceCallback<void(NSString*)> callback) override; base::OnceCallback<void(NSString*)> callback) override;
UIView* GetWindowedContainer() override; UIView* GetWindowedContainer() override;
......
...@@ -104,6 +104,8 @@ void TestWebClient::PrepareErrorPage( ...@@ -104,6 +104,8 @@ void TestWebClient::PrepareErrorPage(
NSError* error, NSError* error,
bool is_post, bool is_post,
bool is_off_the_record, bool is_off_the_record,
const base::Optional<net::SSLInfo>& info,
int64_t navigation_id,
base::OnceCallback<void(NSString*)> callback) { base::OnceCallback<void(NSString*)> callback) {
std::move(callback).Run(base::SysUTF8ToNSString(testing::GetErrorText( std::move(callback).Run(base::SysUTF8ToNSString(testing::GetErrorText(
web_state, url, base::SysNSStringToUTF8(error.domain), error.code, web_state, url, base::SysNSStringToUTF8(error.domain), error.code,
......
...@@ -168,12 +168,17 @@ class WebClient { ...@@ -168,12 +168,17 @@ class WebClient {
// when a navigation error occurs. |error| is always a valid pointer. The // when a navigation error occurs. |error| is always a valid pointer. The
// string passed to |callback| will be nil if no error page should be // string passed to |callback| will be nil if no error page should be
// displayed. Otherwise, this string will contain the details of the error // displayed. Otherwise, this string will contain the details of the error
// and maybe links to more info. // and maybe links to more info. |info| will have a value for SSL cert errors
// and otherwise be nullopt. |navigation_id| is passed into this method so
// that in the case of an SSL cert error, the blocking page can be associated
// with the tab.
virtual void PrepareErrorPage(WebState* web_state, virtual void PrepareErrorPage(WebState* web_state,
const GURL& url, const GURL& url,
NSError* error, NSError* error,
bool is_post, bool is_post,
bool is_off_the_record, bool is_off_the_record,
const base::Optional<net::SSLInfo>& info,
int64_t navigation_id,
base::OnceCallback<void(NSString*)> callback); base::OnceCallback<void(NSString*)> callback);
// Allows upper layers to inject experimental flags to the web layer. // Allows upper layers to inject experimental flags to the web layer.
......
...@@ -105,6 +105,8 @@ void WebClient::PrepareErrorPage(WebState* web_state, ...@@ -105,6 +105,8 @@ void WebClient::PrepareErrorPage(WebState* web_state,
NSError* error, NSError* error,
bool is_post, bool is_post,
bool is_off_the_record, bool is_off_the_record,
const base::Optional<net::SSLInfo>& info,
int64_t navigation_id,
base::OnceCallback<void(NSString*)> callback) { base::OnceCallback<void(NSString*)> callback) {
DCHECK(error); DCHECK(error);
std::move(callback).Run(error.localizedDescription); std::move(callback).Run(error.localizedDescription);
......
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
#import <Foundation/Foundation.h> #import <Foundation/Foundation.h>
#include "net/ssl/ssl_info.h"
#include "testing/gtest_mac.h" #include "testing/gtest_mac.h"
#include "testing/platform_test.h" #include "testing/platform_test.h"
#include "url/gurl.h" #include "url/gurl.h"
...@@ -26,11 +27,14 @@ TEST_F(WebClientTest, PrepareErrorPage) { ...@@ -26,11 +27,14 @@ TEST_F(WebClientTest, PrepareErrorPage) {
code:NSURLErrorNotConnectedToInternet code:NSURLErrorNotConnectedToInternet
userInfo:@{NSLocalizedDescriptionKey : description}]; userInfo:@{NSLocalizedDescriptionKey : description}];
base::Optional<net::SSLInfo> info = base::nullopt;
__block bool callback_called = false; __block bool callback_called = false;
__block NSString* html = nil; __block NSString* html = nil;
web_client.PrepareErrorPage(/*web_state*/ nullptr, GURL::EmptyGURL(), error, web_client.PrepareErrorPage(/*web_state*/ nullptr, GURL::EmptyGURL(), error,
/*is_post=*/false, /*is_post=*/false,
/*is_off_the_record=*/false, /*is_off_the_record=*/false,
/*info=*/info,
/*navigation_id=*/0,
base::BindOnce(^(NSString* error_html) { base::BindOnce(^(NSString* error_html) {
html = error_html; html = error_html;
callback_called = true; callback_called = true;
......
...@@ -8,11 +8,14 @@ ...@@ -8,11 +8,14 @@
#include "ios/web/common/features.h" #include "ios/web/common/features.h"
#import "ios/web/public/navigation/navigation_manager.h" #import "ios/web/public/navigation/navigation_manager.h"
#include "ios/web/public/security/certificate_policy_cache.h" #include "ios/web/public/security/certificate_policy_cache.h"
#include "ios/web/public/security/security_style.h"
#include "ios/web/public/security/ssl_status.h"
#import "ios/web/public/session/crw_session_certificate_policy_cache_storage.h" #import "ios/web/public/session/crw_session_certificate_policy_cache_storage.h"
#import "ios/web/public/session/crw_session_storage.h" #import "ios/web/public/session/crw_session_storage.h"
#include "ios/web/public/session/session_certificate_policy_cache.h" #include "ios/web/public/session/session_certificate_policy_cache.h"
#import "ios/web/public/test/error_test_util.h" #import "ios/web/public/test/error_test_util.h"
#import "ios/web/public/test/fakes/test_web_client.h" #import "ios/web/public/test/fakes/test_web_client.h"
#include "ios/web/public/test/fakes/test_web_state_observer.h"
#import "ios/web/public/test/navigation_test_util.h" #import "ios/web/public/test/navigation_test_util.h"
#import "ios/web/public/test/web_test_with_web_state.h" #import "ios/web/public/test/web_test_with_web_state.h"
#import "ios/web/public/test/web_view_content_test_util.h" #import "ios/web/public/test/web_view_content_test_util.h"
...@@ -71,6 +74,8 @@ class BadSslResponseTest : public WebTestWithWebState, ...@@ -71,6 +74,8 @@ class BadSslResponseTest : public WebTestWithWebState,
void SetUp() override { void SetUp() override {
WebTestWithWebState::SetUp(); WebTestWithWebState::SetUp();
web_state_observer_ = std::make_unique<TestWebStateObserver>(web_state());
ASSERT_TRUE(https_server_.Start()); ASSERT_TRUE(https_server_.Start());
} }
...@@ -88,8 +93,13 @@ class BadSslResponseTest : public WebTestWithWebState, ...@@ -88,8 +93,13 @@ class BadSslResponseTest : public WebTestWithWebState,
return static_cast<TestWebClient*>(GetWebClient()); return static_cast<TestWebClient*>(GetWebClient());
} }
TestDidChangeVisibleSecurityStateInfo* security_state_info() {
return web_state_observer_->did_change_visible_security_state_info();
}
net::test_server::EmbeddedTestServer https_server_; net::test_server::EmbeddedTestServer https_server_;
base::test::ScopedFeatureList scoped_feature_list_; base::test::ScopedFeatureList scoped_feature_list_;
std::unique_ptr<TestWebStateObserver> web_state_observer_;
DISALLOW_COPY_AND_ASSIGN(BadSslResponseTest); DISALLOW_COPY_AND_ASSIGN(BadSslResponseTest);
}; };
...@@ -239,6 +249,10 @@ TEST_P(BadSslResponseTest, ShowSSLErrorPageCommittedInterstitial) { ...@@ -239,6 +249,10 @@ TEST_P(BadSslResponseTest, ShowSSLErrorPageCommittedInterstitial) {
testing::GetErrorText(web_state(), url, "NSURLErrorDomain", testing::GetErrorText(web_state(), url, "NSURLErrorDomain",
/*error_code=*/NSURLErrorServerCertificateUntrusted, /*error_code=*/NSURLErrorServerCertificateUntrusted,
/*is_post=*/false, /*is_otr=*/false))); /*is_post=*/false, /*is_otr=*/false)));
ASSERT_TRUE(security_state_info());
ASSERT_TRUE(security_state_info()->visible_ssl_status);
EXPECT_EQ(SECURITY_STYLE_AUTHENTICATION_BROKEN,
security_state_info()->visible_ssl_status->security_style);
} }
// Tests navigation to a page with self signed SSL cert and allowing the load // Tests navigation to a page with self signed SSL cert and allowing the load
......
...@@ -1820,7 +1820,13 @@ typedef void (^ViewportStateCompletion)(const web::PageViewportState*); ...@@ -1820,7 +1820,13 @@ typedef void (^ViewportStateCompletion)(const web::PageViewportState*);
// |webView:didCommitNavigation:| callback. // |webView:didCommitNavigation:| callback.
return; return;
} }
[self updateSSLStatusForCurrentNavigationItem]; web::NavigationItem* item =
self.webStateImpl->GetNavigationManager()->GetLastCommittedItem();
// SSLStatus is manually set in CRWWKNavigationHandler for SSL errors, so
// skip calling the update method in these cases.
if (item && !net::IsCertStatusError(item->GetSSL().cert_status)) {
[self updateSSLStatusForCurrentNavigationItem];
}
} }
// Called when WKWebView title has been changed. // Called when WKWebView title has been changed.
......
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