Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #import "ios/web/web_state/ui/crw_wk_web_view_web_controller.h" | 5 #import "ios/web/web_state/ui/crw_wk_web_view_web_controller.h" |
| 6 | 6 |
| 7 #import <WebKit/WebKit.h> | 7 #import <WebKit/WebKit.h> |
| 8 | 8 |
| 9 #include "base/ios/ios_util.h" | 9 #include "base/ios/ios_util.h" |
| 10 #include "base/ios/weak_nsobject.h" | 10 #include "base/ios/weak_nsobject.h" |
| 11 #include "base/json/json_reader.h" | 11 #include "base/json/json_reader.h" |
| 12 #import "base/mac/scoped_nsobject.h" | 12 #import "base/mac/scoped_nsobject.h" |
| 13 #include "base/macros.h" | 13 #include "base/macros.h" |
| 14 #include "base/metrics/histogram_macros.h" | |
| 14 #include "base/strings/sys_string_conversions.h" | 15 #include "base/strings/sys_string_conversions.h" |
| 15 #include "base/values.h" | 16 #include "base/values.h" |
| 16 #import "ios/net/http_response_headers_util.h" | 17 #import "ios/net/http_response_headers_util.h" |
| 17 #import "ios/web/crw_network_activity_indicator_manager.h" | 18 #import "ios/web/crw_network_activity_indicator_manager.h" |
| 18 #import "ios/web/navigation/crw_session_controller.h" | 19 #import "ios/web/navigation/crw_session_controller.h" |
| 19 #import "ios/web/navigation/crw_session_entry.h" | 20 #import "ios/web/navigation/crw_session_entry.h" |
| 20 #include "ios/web/navigation/navigation_item_impl.h" | 21 #include "ios/web/navigation/navigation_item_impl.h" |
| 21 #include "ios/web/navigation/web_load_params.h" | 22 #include "ios/web/navigation/web_load_params.h" |
| 22 #import "ios/web/net/crw_cert_verification_controller.h" | 23 #import "ios/web/net/crw_cert_verification_controller.h" |
| 23 #include "ios/web/public/cert_store.h" | 24 #include "ios/web/public/cert_store.h" |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 75 userInfo:userInfo]; | 76 userInfo:userInfo]; |
| 76 } | 77 } |
| 77 WKWebViewErrorSource WKWebViewErrorSourceFromError(NSError* error) { | 78 WKWebViewErrorSource WKWebViewErrorSourceFromError(NSError* error) { |
| 78 DCHECK(error); | 79 DCHECK(error); |
| 79 return static_cast<WKWebViewErrorSource>( | 80 return static_cast<WKWebViewErrorSource>( |
| 80 [error.userInfo[kWKWebViewErrorSourceKey] integerValue]); | 81 [error.userInfo[kWKWebViewErrorSourceKey] integerValue]); |
| 81 } | 82 } |
| 82 | 83 |
| 83 } // namespace | 84 } // namespace |
| 84 | 85 |
| 86 #if !defined(__IPHONE_9_0) || __IPHONE_OS_VERSION_MAX_ALLOWED < __IPHONE_9_0 | |
| 87 // Predeclare iOS9 API so calls are compiled on iOS8 bots. | |
| 88 // TODO(eugenebut): cleanup this (crbug.com/523365). | |
| 89 @interface WKWebView (CRWIOS9API) | |
| 90 @property(nonatomic, readonly, copy) NSArray* certificateChain; | |
| 91 @end | |
| 92 #endif | |
| 93 | |
| 85 @interface CRWWKWebViewWebController () <WKNavigationDelegate, | 94 @interface CRWWKWebViewWebController () <WKNavigationDelegate, |
| 86 WKScriptMessageHandler, | 95 WKScriptMessageHandler, |
| 87 WKUIDelegate> { | 96 WKUIDelegate> { |
| 88 // The WKWebView managed by this instance. | 97 // The WKWebView managed by this instance. |
| 89 base::scoped_nsobject<WKWebView> _wkWebView; | 98 base::scoped_nsobject<WKWebView> _wkWebView; |
| 90 | 99 |
| 91 // The Watch Dog that detects and reports WKWebView crashes. | 100 // The Watch Dog that detects and reports WKWebView crashes. |
| 92 base::scoped_nsobject<CRWWKWebViewCrashDetector> _crashDetector; | 101 base::scoped_nsobject<CRWWKWebViewCrashDetector> _crashDetector; |
| 93 | 102 |
| 94 // The actual URL of the document object (i.e., the last committed URL). | 103 // The actual URL of the document object (i.e., the last committed URL). |
| (...skipping 148 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 243 // Called when a load ends in an SSL error and certificate chain. | 252 // Called when a load ends in an SSL error and certificate chain. |
| 244 - (void)handleSSLCertError:(NSError*)error; | 253 - (void)handleSSLCertError:(NSError*)error; |
| 245 #endif | 254 #endif |
| 246 | 255 |
| 247 // Adds an activity indicator tasks for this web controller. | 256 // Adds an activity indicator tasks for this web controller. |
| 248 - (void)addActivityIndicatorTask; | 257 - (void)addActivityIndicatorTask; |
| 249 | 258 |
| 250 // Clears all activity indicator tasks for this web controller. | 259 // Clears all activity indicator tasks for this web controller. |
| 251 - (void)clearActivityIndicatorTasks; | 260 - (void)clearActivityIndicatorTasks; |
| 252 | 261 |
| 262 // Obtains SSL status from given |certChain| and |host| and updates current | |
| 263 // navigation item. | |
| 264 - (void)updateCurrentNavigationItemSSLStatusUsingCertChain:(NSArray*)chain | |
| 265 host:(NSString*)host; | |
| 266 | |
| 253 #if !defined(ENABLE_CHROME_NET_STACK_FOR_WKWEBVIEW) | 267 #if !defined(ENABLE_CHROME_NET_STACK_FOR_WKWEBVIEW) |
| 254 // Updates SSL status for the current navigation item based on the information | 268 // Updates SSL status for the current navigation item based on the information |
| 255 // provided by web view. | 269 // provided by web view. |
| 256 - (void)updateSSLStatusForCurrentNavigationItem; | 270 - (void)updateSSLStatusForCurrentNavigationItem; |
| 257 #endif | 271 #endif |
| 258 | 272 |
| 273 // Reports "WebController.WKWebViewHasCertForSecureConnection" UMA. | |
| 274 - (void)reportHasCertForSecureConnectionUMAWithValue:(bool)value; | |
| 275 | |
| 259 // Registers load request with empty referrer and link or client redirect | 276 // Registers load request with empty referrer and link or client redirect |
| 260 // transition based on user interaction state. | 277 // transition based on user interaction state. |
| 261 - (void)registerLoadRequest:(const GURL&)url; | 278 - (void)registerLoadRequest:(const GURL&)url; |
| 262 | 279 |
| 263 // Called when a non-document-changing URL change occurs. Updates the | 280 // Called when a non-document-changing URL change occurs. Updates the |
| 264 // _documentURL, and informs the superclass of the change. | 281 // _documentURL, and informs the superclass of the change. |
| 265 - (void)URLDidChangeWithoutDocumentChange:(const GURL&)URL; | 282 - (void)URLDidChangeWithoutDocumentChange:(const GURL&)URL; |
| 266 | 283 |
| 267 // Returns new autoreleased instance of WKUserContentController which has | 284 // Returns new autoreleased instance of WKUserContentController which has |
| 268 // early page script. | 285 // early page script. |
| (...skipping 588 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 857 - (void)addActivityIndicatorTask { | 874 - (void)addActivityIndicatorTask { |
| 858 [[CRWNetworkActivityIndicatorManager sharedInstance] | 875 [[CRWNetworkActivityIndicatorManager sharedInstance] |
| 859 startNetworkTaskForGroup:[self activityIndicatorGroupID]]; | 876 startNetworkTaskForGroup:[self activityIndicatorGroupID]]; |
| 860 } | 877 } |
| 861 | 878 |
| 862 - (void)clearActivityIndicatorTasks { | 879 - (void)clearActivityIndicatorTasks { |
| 863 [[CRWNetworkActivityIndicatorManager sharedInstance] | 880 [[CRWNetworkActivityIndicatorManager sharedInstance] |
| 864 clearNetworkTasksForGroup:[self activityIndicatorGroupID]]; | 881 clearNetworkTasksForGroup:[self activityIndicatorGroupID]]; |
| 865 } | 882 } |
| 866 | 883 |
| 884 - (void)updateCurrentNavigationItemSSLStatusUsingCertChain:(NSArray*)chain | |
|
davidben
2015/10/07 20:16:30
Nit: I'd maybe name this something with the word "
davidben
2015/10/07 20:16:30
Should this also be under the ifdef?
stuartmorgan
2015/10/07 22:30:14
+1. "begin" could also work.
Eugene But (OOO till 7-30)
2015/10/08 16:53:32
We will drop ENABLE_CHROME_NET_STACK_FOR_WKWEBVIEW
Eugene But (OOO till 7-30)
2015/10/08 16:53:32
Done.
| |
| 885 host:(NSString*)host { | |
| 886 // Use Navigation Item's unique ID to locate requested item after | |
| 887 // obtaining cert status asynchronously. | |
| 888 web::NavigationItem* item = | |
| 889 self.webStateImpl->GetNavigationManager()->GetLastCommittedItem(); | |
| 890 if (!item) | |
|
stuartmorgan
2015/10/07 22:30:14
Is this something that should actually be possible
Eugene But (OOO till 7-30)
2015/10/08 16:53:32
Currently not possible. In Chromium DCHECKs are no
| |
| 891 return; | |
| 892 int itemID = item->GetUniqueID(); | |
| 893 | |
| 894 base::WeakNSObject<CRWWKWebViewWebController> weakSelf(self); | |
| 895 void (^SSLStatusResponse)(web::SecurityStyle, net::CertStatus) = ^( | |
| 896 web::SecurityStyle style, net::CertStatus certStatus) { | |
| 897 base::scoped_nsobject<CRWWKWebViewWebController> strongSelf( | |
| 898 [weakSelf retain]); | |
| 899 if (!strongSelf || [strongSelf isBeingDestroyed]) { | |
| 900 return; | |
| 901 } | |
|
stuartmorgan
2015/10/07 22:30:14
Could you pull everything after this into a helper
Eugene But (OOO till 7-30)
2015/10/08 16:53:32
Done.
| |
| 902 | |
| 903 web::NavigationManager* navigationManager = | |
| 904 [strongSelf webStateImpl]->GetNavigationManager(); | |
| 905 | |
| 906 scoped_refptr<net::X509Certificate> cert(web::CreateCertFromChain(chain)); | |
| 907 int certID = | |
| 908 web::CertStore::GetInstance()->StoreCert(cert.get(), self.certGroupID); | |
| 909 std::string GURLHost = base::SysNSStringToUTF8(host); | |
| 910 for (int i = 0; i < navigationManager->GetEntryCount(); i++) { | |
|
stuartmorgan
2015/10/07 22:30:14
It should almost always be the last entry, so walk
Eugene But (OOO till 7-30)
2015/10/08 16:53:33
Done.
| |
| 911 web::NavigationItem* item = navigationManager->GetItemAtIndex(i); | |
| 912 web::SSLStatus& SSLStatus = item->GetSSL(); | |
| 913 // NavigationItem's UniqueID is preserved even after redirects, so | |
| 914 // checking that URL and cert matches is necessary. | |
| 915 if (itemID == item->GetUniqueID() && SSLStatus.cert_id == certID && | |
|
stuartmorgan
2015/10/07 22:30:14
Flip the first check around; it's backward relativ
Eugene But (OOO till 7-30)
2015/10/08 16:53:32
Done.
| |
| 916 item->GetURL().host() == GURLHost) { | |
| 917 web::SSLStatus previousSSLStatus = item->GetSSL(); | |
| 918 SSLStatus.cert_status = certStatus; | |
| 919 SSLStatus.security_style = style; | |
| 920 if (navigationManager->GetCurrentEntryIndex() == i && | |
| 921 !previousSSLStatus.Equals(SSLStatus)) { | |
| 922 [strongSelf didUpdateSSLStatusForCurrentNavigationItem]; | |
| 923 } | |
| 924 return; | |
|
stuartmorgan
2015/10/07 22:30:14
You actually want to return after finding an itemI
Eugene But (OOO till 7-30)
2015/10/08 16:53:32
Done.
| |
| 925 } | |
| 926 } | |
| 927 }; | |
| 928 | |
| 929 [_certVerificationController | |
| 930 querySSLStatusForTrust:web::CreateServerTrustFromChain(chain, host) | |
| 931 host:host | |
| 932 completionHandler:SSLStatusResponse]; | |
| 933 } | |
| 934 | |
| 867 #if !defined(ENABLE_CHROME_NET_STACK_FOR_WKWEBVIEW) | 935 #if !defined(ENABLE_CHROME_NET_STACK_FOR_WKWEBVIEW) |
| 936 | |
| 868 - (void)updateSSLStatusForCurrentNavigationItem { | 937 - (void)updateSSLStatusForCurrentNavigationItem { |
| 869 if ([self isBeingDestroyed]) | 938 if ([self isBeingDestroyed]) |
| 870 return; | 939 return; |
| 871 | 940 |
| 872 DCHECK(self.webStateImpl); | |
| 873 web::NavigationItem* item = | 941 web::NavigationItem* item = |
| 874 self.webStateImpl->GetNavigationManagerImpl().GetLastCommittedItem(); | 942 self.webStateImpl->GetNavigationManagerImpl().GetLastCommittedItem(); |
| 875 if (!item) | 943 if (!item) |
| 876 return; | 944 return; |
| 877 | 945 |
| 878 web::SSLStatus previousSSLStatus = item->GetSSL(); | 946 web::SSLStatus previousSSLStatus = item->GetSSL(); |
| 879 web::SSLStatus& SSLStatus = item->GetSSL(); | 947 web::SSLStatus& SSLStatus = item->GetSSL(); |
| 880 if (item->GetURL().SchemeIsCryptographic()) { | |
| 881 // TODO(eugenebut): Do not set security style to authenticated once | |
| 882 // proceeding with bad ssl cert is implemented. | |
| 883 SSLStatus.security_style = web::SECURITY_STYLE_AUTHENTICATED; | |
| 884 SSLStatus.content_status = [_wkWebView hasOnlySecureContent] | |
| 885 ? web::SSLStatus::NORMAL_CONTENT | |
| 886 : web::SSLStatus::DISPLAYED_INSECURE_CONTENT; | |
| 887 | 948 |
| 888 if (base::ios::IsRunningOnIOS9OrLater()) { | 949 // Starting from iOS9 WKWebView blocks active mixed content, so if |
| 889 scoped_refptr<net::X509Certificate> cert(web::CreateCertFromChain( | 950 // |hasOnlySecureContent| returns NO it means passive content. |
| 890 [_wkWebView performSelector:@selector(certificateChain)])); | 951 // On iOS8 there is no way to determine if web view has active mixed content. |
| 891 if (cert) { | 952 SSLStatus.content_status = [_wkWebView hasOnlySecureContent] |
| 892 SSLStatus.cert_id = web::CertStore::GetInstance()->StoreCert( | 953 ? web::SSLStatus::NORMAL_CONTENT |
| 893 cert.get(), self.certGroupID); | 954 : web::SSLStatus::DISPLAYED_INSECURE_CONTENT; |
| 894 } else { | 955 |
| 895 SSLStatus.security_style = web::SECURITY_STYLE_UNAUTHENTICATED; | 956 // Try updating SSLStatus for current NavigationItem asynchronously. |
| 896 SSLStatus.cert_id = 0; | 957 scoped_refptr<net::X509Certificate> cert; |
| 958 if (base::ios::IsRunningOnIOS9OrLater() && | |
| 959 item->GetURL().SchemeIsCryptographic()) { | |
| 960 NSArray* chain = [_wkWebView certificateChain]; | |
| 961 cert = web::CreateCertFromChain(chain); | |
| 962 if (cert) { | |
| 963 [self reportHasCertForSecureConnectionUMAWithValue:true]; | |
|
davidben
2015/10/07 20:16:30
Should this be in line 968? Seems you don't want t
Eugene But (OOO till 7-30)
2015/10/08 16:53:32
Done.
| |
| 964 int oldCertID = SSLStatus.cert_id; | |
| 965 SSLStatus.cert_id = web::CertStore::GetInstance()->StoreCert( | |
| 966 cert.get(), self.certGroupID); | |
| 967 if (oldCertID != SSLStatus.cert_id || | |
|
davidben
2015/10/07 20:16:30
Could you add a comment here like:
// Only reco
davidben
2015/10/07 20:16:30
If events cause updateSSLStatusForCurrentNavigatio
Eugene But (OOO till 7-30)
2015/10/08 16:53:32
If |updateSSLStatusForCurrentNavigationItem| is ca
Eugene But (OOO till 7-30)
2015/10/08 16:53:32
Done.
davidben
2015/10/12 23:21:50
Only if the asynchronous update process has comple
Eugene But (OOO till 7-30)
2015/10/13 20:40:33
How come? This method (updateSSLStatusForCurrentNa
davidben
2015/10/15 17:46:12
Ah, no, you're right. I'd missed that line 965 act
| |
| 968 item->GetURL().host() != _documentURL.host()) { | |
| 969 NSString* host = base::SysUTF8ToNSString(_documentURL.host()); | |
| 970 [self updateCurrentNavigationItemSSLStatusUsingCertChain:chain | |
| 971 host:host]; | |
| 897 } | 972 } |
| 898 } | 973 } |
| 899 } else { | 974 } |
| 900 SSLStatus.security_style = web::SECURITY_STYLE_UNAUTHENTICATED; | 975 |
| 976 if (!cert) { | |
| 901 SSLStatus.cert_id = 0; | 977 SSLStatus.cert_id = 0; |
| 978 if (!item->GetURL().SchemeIsCryptographic()) { | |
| 979 // HTTP or other non-secure connection. | |
| 980 SSLStatus.security_style = web::SECURITY_STYLE_UNAUTHENTICATED; | |
| 981 } else if (base::ios::IsRunningOnIOS9OrLater()) { | |
| 982 // HTTPS, iOS9 and no certificate (this use-case has not been observed). | |
| 983 [self reportHasCertForSecureConnectionUMAWithValue:false]; | |
| 984 SSLStatus.security_style = web::SECURITY_STYLE_UNKNOWN; | |
| 985 } else { | |
| 986 // HTTPS, iOS8. | |
| 987 // iOS8 cannot load unauthenticated HTTPS content. | |
| 988 SSLStatus.security_style = web::SECURITY_STYLE_AUTHENTICATED; | |
| 989 } | |
| 902 } | 990 } |
| 903 | 991 |
| 904 if (!previousSSLStatus.Equals(SSLStatus)) { | 992 if (!previousSSLStatus.Equals(SSLStatus)) { |
| 905 [self didUpdateSSLStatusForCurrentNavigationItem]; | 993 [self didUpdateSSLStatusForCurrentNavigationItem]; |
| 906 } | 994 } |
| 907 } | 995 } |
| 996 | |
| 997 - (void)reportHasCertForSecureConnectionUMAWithValue:(bool)value { | |
| 998 UMA_HISTOGRAM_BOOLEAN("WebController.WKWebViewHasCertForSecureConnection", | |
| 999 value); | |
| 1000 } | |
| 1001 | |
| 908 #endif // !defined(ENABLE_CHROME_NET_STACK_FOR_WKWEBVIEW) | 1002 #endif // !defined(ENABLE_CHROME_NET_STACK_FOR_WKWEBVIEW) |
| 909 | 1003 |
| 910 - (void)registerLoadRequest:(const GURL&)url { | 1004 - (void)registerLoadRequest:(const GURL&)url { |
| 911 // If load request is registered via WKWebViewWebController, assume transition | 1005 // If load request is registered via WKWebViewWebController, assume transition |
| 912 // is link or client redirect as other transitions will already be registered | 1006 // is link or client redirect as other transitions will already be registered |
| 913 // by web controller or delegates. | 1007 // by web controller or delegates. |
| 914 // TODO(stuartmorgan): Remove guesswork and replace with information from | 1008 // TODO(stuartmorgan): Remove guesswork and replace with information from |
| 915 // decidePolicyForNavigationAction:. | 1009 // decidePolicyForNavigationAction:. |
| 916 ui::PageTransition transition = self.userInteractionRegistered | 1010 ui::PageTransition transition = self.userInteractionRegistered |
| 917 ? ui::PAGE_TRANSITION_LINK | 1011 ? ui::PAGE_TRANSITION_LINK |
| (...skipping 466 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1384 if (![challenge.protectionSpace.authenticationMethod | 1478 if (![challenge.protectionSpace.authenticationMethod |
| 1385 isEqual:NSURLAuthenticationMethodServerTrust]) { | 1479 isEqual:NSURLAuthenticationMethodServerTrust]) { |
| 1386 completionHandler(NSURLSessionAuthChallengePerformDefaultHandling, nil); | 1480 completionHandler(NSURLSessionAuthChallengePerformDefaultHandling, nil); |
| 1387 return; | 1481 return; |
| 1388 } | 1482 } |
| 1389 | 1483 |
| 1390 SecTrustRef trust = challenge.protectionSpace.serverTrust; | 1484 SecTrustRef trust = challenge.protectionSpace.serverTrust; |
| 1391 scoped_refptr<net::X509Certificate> cert = web::CreateCertFromTrust(trust); | 1485 scoped_refptr<net::X509Certificate> cert = web::CreateCertFromTrust(trust); |
| 1392 [_certVerificationController | 1486 [_certVerificationController |
| 1393 decidePolicyForCert:cert | 1487 decidePolicyForCert:cert |
| 1394 host:challenge.protectionSpace.host | 1488 host:challenge.protectionSpace.host |
|
davidben
2015/10/07 20:16:30
I'm assuming this will be switched to pass in the
Eugene But (OOO till 7-30)
2015/10/08 16:53:32
Yes, SecTrustRef will be passed.
See other CL: htt
| |
| 1395 completionHandler:^(web::CertAcceptPolicy policy, | 1489 completionHandler:^(web::CertAcceptPolicy policy, |
| 1396 net::CertStatus status) { | 1490 net::CertStatus status) { |
| 1397 completionHandler(NSURLSessionAuthChallengeRejectProtectionSpace, | 1491 completionHandler(NSURLSessionAuthChallengeRejectProtectionSpace, |
| 1398 nil); | 1492 nil); |
| 1399 }]; | 1493 }]; |
| 1400 } | 1494 } |
| 1401 | 1495 |
| 1402 - (void)webViewWebContentProcessDidTerminate:(WKWebView*)webView { | 1496 - (void)webViewWebContentProcessDidTerminate:(WKWebView*)webView { |
| 1403 [self webViewWebProcessDidCrash]; | 1497 [self webViewWebProcessDidCrash]; |
| 1404 } | 1498 } |
| (...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1488 placeholderText:defaultText | 1582 placeholderText:defaultText |
| 1489 requestURL: | 1583 requestURL: |
| 1490 net::GURLWithNSURL(frame.request.URL) | 1584 net::GURLWithNSURL(frame.request.URL) |
| 1491 completionHandler:completionHandler]; | 1585 completionHandler:completionHandler]; |
| 1492 } else if (completionHandler) { | 1586 } else if (completionHandler) { |
| 1493 completionHandler(nil); | 1587 completionHandler(nil); |
| 1494 } | 1588 } |
| 1495 } | 1589 } |
| 1496 | 1590 |
| 1497 @end | 1591 @end |
| OLD | NEW |