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): Clean this up (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 // Updates |style| and |certStatus| for Navigation Item wich has given | |
davidben
2015/10/12 23:21:50
Perhaps:
// Updates |security_style| and |cert_st
Eugene But (OOO till 7-30)
2015/10/13 20:40:33
Done.
| |
263 // |navigationItemID|, |host| and represents given |certChain|. | |
264 - (void)updateSSLStatusForNavigationItemWithID:(int)navigationItemID | |
265 certChain:(NSArray*)certChain | |
266 host:(NSString*)host | |
267 withSecurityStyle:(web::SecurityStyle)style | |
268 certStatus:(net::CertStatus)certStatus; | |
269 | |
270 // Asynchronously obtains SSL status from given |certChain| and |host| and | |
271 // updates current navigation item. | |
272 - (void)scheduleSSLStatusUpdateUsingCertChain:(NSArray*)chain | |
273 host:(NSString*)host; | |
274 | |
253 #if !defined(ENABLE_CHROME_NET_STACK_FOR_WKWEBVIEW) | 275 #if !defined(ENABLE_CHROME_NET_STACK_FOR_WKWEBVIEW) |
254 // Updates SSL status for the current navigation item based on the information | 276 // Updates SSL status for the current navigation item based on the information |
255 // provided by web view. | 277 // provided by web view. |
256 - (void)updateSSLStatusForCurrentNavigationItem; | 278 - (void)updateSSLStatusForCurrentNavigationItem; |
257 #endif | 279 #endif |
258 | 280 |
281 // Reports "WebController.WKWebViewHasCertForSecureConnection" UMA. | |
282 - (void)reportHasCertForSecureConnectionUMAWithValue:(bool)value; | |
283 | |
259 // Registers load request with empty referrer and link or client redirect | 284 // Registers load request with empty referrer and link or client redirect |
260 // transition based on user interaction state. | 285 // transition based on user interaction state. |
261 - (void)registerLoadRequest:(const GURL&)url; | 286 - (void)registerLoadRequest:(const GURL&)url; |
262 | 287 |
263 // Called when a non-document-changing URL change occurs. Updates the | 288 // Called when a non-document-changing URL change occurs. Updates the |
264 // _documentURL, and informs the superclass of the change. | 289 // _documentURL, and informs the superclass of the change. |
265 - (void)URLDidChangeWithoutDocumentChange:(const GURL&)URL; | 290 - (void)URLDidChangeWithoutDocumentChange:(const GURL&)URL; |
266 | 291 |
267 // Returns new autoreleased instance of WKUserContentController which has | 292 // Returns new autoreleased instance of WKUserContentController which has |
268 // early page script. | 293 // early page script. |
(...skipping 588 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
857 - (void)addActivityIndicatorTask { | 882 - (void)addActivityIndicatorTask { |
858 [[CRWNetworkActivityIndicatorManager sharedInstance] | 883 [[CRWNetworkActivityIndicatorManager sharedInstance] |
859 startNetworkTaskForGroup:[self activityIndicatorGroupID]]; | 884 startNetworkTaskForGroup:[self activityIndicatorGroupID]]; |
860 } | 885 } |
861 | 886 |
862 - (void)clearActivityIndicatorTasks { | 887 - (void)clearActivityIndicatorTasks { |
863 [[CRWNetworkActivityIndicatorManager sharedInstance] | 888 [[CRWNetworkActivityIndicatorManager sharedInstance] |
864 clearNetworkTasksForGroup:[self activityIndicatorGroupID]]; | 889 clearNetworkTasksForGroup:[self activityIndicatorGroupID]]; |
865 } | 890 } |
866 | 891 |
892 - (void)updateSSLStatusForNavigationItemWithID:(int)navigationItemID | |
893 certChain:(NSArray*)chain | |
davidben
2015/10/12 23:21:50
Here you use chain but in the prototype, it's cert
Eugene But (OOO till 7-30)
2015/10/13 20:40:33
Changed predeclaration. Longer argument name makes
| |
894 host:(NSString*)host | |
895 withSecurityStyle:(web::SecurityStyle)style | |
896 certStatus:(net::CertStatus)certStatus { | |
897 web::NavigationManager* navigationManager = | |
898 self.webStateImpl->GetNavigationManager(); | |
899 | |
900 // The searched item almost always be the last one, so walk backward rather | |
901 // than forward. | |
902 for (int i = navigationManager->GetEntryCount() - 1; 0 <= i; i--) { | |
903 web::NavigationItem* item = navigationManager->GetItemAtIndex(i); | |
904 if (item->GetUniqueID() != navigationItemID) | |
905 continue; | |
906 | |
907 // NavigationItem's UniqueID is preserved even after redirects, so | |
908 // checking that cert and URL matche is necessary. | |
davidben
2015/10/12 23:21:50
matche -> match
Eugene But (OOO till 7-30)
2015/10/13 20:40:33
Done.
| |
909 scoped_refptr<net::X509Certificate> cert(web::CreateCertFromChain(chain)); | |
910 int certID = | |
911 web::CertStore::GetInstance()->StoreCert(cert.get(), self.certGroupID); | |
912 std::string GURLHost = base::SysNSStringToUTF8(host); | |
913 web::SSLStatus& SSLStatus = item->GetSSL(); | |
914 if (SSLStatus.cert_id == certID && item->GetURL().host() == GURLHost) { | |
915 web::SSLStatus previousSSLStatus = item->GetSSL(); | |
916 SSLStatus.cert_status = certStatus; | |
917 SSLStatus.security_style = style; | |
918 if (navigationManager->GetCurrentEntryIndex() == i && | |
919 !previousSSLStatus.Equals(SSLStatus)) { | |
920 [self didUpdateSSLStatusForCurrentNavigationItem]; | |
921 } | |
922 } | |
923 return; | |
924 } | |
925 } | |
926 | |
927 - (void)scheduleSSLStatusUpdateUsingCertChain:(NSArray*)chain | |
928 host:(NSString*)host { | |
929 // Use Navigation Item's unique ID to locate requested item after | |
930 // obtaining cert status asynchronously. | |
931 int itemID = self.webStateImpl->GetNavigationManager() | |
932 ->GetLastCommittedItem() | |
933 ->GetUniqueID(); | |
934 | |
935 base::WeakNSObject<CRWWKWebViewWebController> weakSelf(self); | |
936 void (^SSLStatusResponse)(web::SecurityStyle, net::CertStatus) = | |
937 ^(web::SecurityStyle style, net::CertStatus certStatus) { | |
938 base::scoped_nsobject<CRWWKWebViewWebController> strongSelf( | |
939 [weakSelf retain]); | |
940 if (!strongSelf || [strongSelf isBeingDestroyed]) { | |
941 return; | |
942 } | |
943 [strongSelf updateSSLStatusForNavigationItemWithID:itemID | |
944 certChain:chain | |
945 host:host | |
946 withSecurityStyle:style | |
947 certStatus:certStatus]; | |
948 }; | |
949 | |
950 [_certVerificationController | |
951 querySSLStatusForTrust:web::CreateServerTrustFromChain(chain, host) | |
952 host:host | |
953 completionHandler:SSLStatusResponse]; | |
954 } | |
955 | |
867 #if !defined(ENABLE_CHROME_NET_STACK_FOR_WKWEBVIEW) | 956 #if !defined(ENABLE_CHROME_NET_STACK_FOR_WKWEBVIEW) |
957 | |
868 - (void)updateSSLStatusForCurrentNavigationItem { | 958 - (void)updateSSLStatusForCurrentNavigationItem { |
869 if ([self isBeingDestroyed]) | 959 if ([self isBeingDestroyed]) |
870 return; | 960 return; |
871 | 961 |
872 DCHECK(self.webStateImpl); | |
873 web::NavigationItem* item = | 962 web::NavigationItem* item = |
874 self.webStateImpl->GetNavigationManagerImpl().GetLastCommittedItem(); | 963 self.webStateImpl->GetNavigationManagerImpl().GetLastCommittedItem(); |
875 if (!item) | 964 if (!item) |
876 return; | 965 return; |
877 | 966 |
878 web::SSLStatus previousSSLStatus = item->GetSSL(); | 967 web::SSLStatus previousSSLStatus = item->GetSSL(); |
879 web::SSLStatus& SSLStatus = item->GetSSL(); | 968 web::SSLStatus& SSLStatus = item->GetSSL(); |
davidben
2015/10/12 23:21:50
I don't think the C++ style guide allows non-const
Eugene But (OOO till 7-30)
2015/10/13 20:40:33
C++ Style Guide does not allow non-const Reference
davidben
2015/10/15 17:46:12
Hrm, me neither. Interesting. I don't think I've e
Eugene But (OOO till 7-30)
2015/10/15 22:59:34
I realize that non-const ref led to come confusion
| |
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 | 969 |
888 if (base::ios::IsRunningOnIOS9OrLater()) { | 970 // Starting from iOS9 WKWebView blocks active mixed content, so if |
889 scoped_refptr<net::X509Certificate> cert(web::CreateCertFromChain( | 971 // |hasOnlySecureContent| returns NO it means passive content. |
890 [_wkWebView performSelector:@selector(certificateChain)])); | 972 // On iOS8 there is no way to determine if web view has active mixed content. |
891 if (cert) { | 973 SSLStatus.content_status = [_wkWebView hasOnlySecureContent] |
892 SSLStatus.cert_id = web::CertStore::GetInstance()->StoreCert( | 974 ? web::SSLStatus::NORMAL_CONTENT |
893 cert.get(), self.certGroupID); | 975 : web::SSLStatus::DISPLAYED_INSECURE_CONTENT; |
894 } else { | 976 |
895 SSLStatus.security_style = web::SECURITY_STYLE_UNAUTHENTICATED; | 977 // Try updating SSLStatus for current NavigationItem asynchronously. |
896 SSLStatus.cert_id = 0; | 978 scoped_refptr<net::X509Certificate> cert; |
979 if (base::ios::IsRunningOnIOS9OrLater() && | |
980 item->GetURL().SchemeIsCryptographic()) { | |
981 NSArray* chain = [_wkWebView certificateChain]; | |
982 cert = web::CreateCertFromChain(chain); | |
983 if (cert) { | |
984 int oldCertID = SSLStatus.cert_id; | |
985 SSLStatus.cert_id = web::CertStore::GetInstance()->StoreCert( | |
986 cert.get(), self.certGroupID); | |
987 // Only recompute the SSLStatus information if the certificate has since | |
988 // changed. | |
989 if (oldCertID != SSLStatus.cert_id || | |
990 item->GetURL().host() != _documentURL.host()) { | |
davidben
2015/10/12 23:21:50
Does this check even do anything? item->GetURL() i
davidben
2015/10/12 23:25:55
Right, a related problem here is: is it possible f
Eugene But (OOO till 7-30)
2015/10/13 20:40:33
I check host, so we can recalculate SSL status aft
Eugene But (OOO till 7-30)
2015/10/13 20:40:33
_documentURL.host() can not change w/o calling upd
davidben
2015/10/15 17:46:12
If they're already synchronized, how can this chec
Eugene But (OOO till 7-30)
2015/10/15 22:59:34
Yes, the update flow is:
1.) webView:didCommitNavi
| |
991 NSString* host = base::SysUTF8ToNSString(_documentURL.host()); | |
992 [self scheduleSSLStatusUpdateUsingCertChain:chain host:host]; | |
davidben
2015/10/12 23:21:50
Because this is asynchronous (and unless we decide
Eugene But (OOO till 7-30)
2015/10/13 20:40:33
I think that clearing cert_status and using web::S
| |
993 [self reportHasCertForSecureConnectionUMAWithValue:true]; | |
897 } | 994 } |
898 } | 995 } |
899 } else { | 996 } |
900 SSLStatus.security_style = web::SECURITY_STYLE_UNAUTHENTICATED; | 997 |
998 if (!cert) { | |
901 SSLStatus.cert_id = 0; | 999 SSLStatus.cert_id = 0; |
1000 if (!item->GetURL().SchemeIsCryptographic()) { | |
1001 // HTTP or other non-secure connection. | |
1002 SSLStatus.security_style = web::SECURITY_STYLE_UNAUTHENTICATED; | |
1003 } else if (base::ios::IsRunningOnIOS9OrLater()) { | |
1004 // HTTPS, iOS9 and no certificate (this use-case has not been observed). | |
1005 [self reportHasCertForSecureConnectionUMAWithValue:false]; | |
davidben
2015/10/12 23:21:50
This line will also run every time updateSSLStatus
Eugene But (OOO till 7-30)
2015/10/13 20:40:33
Done.
| |
1006 SSLStatus.security_style = web::SECURITY_STYLE_UNKNOWN; | |
1007 } else { | |
1008 // HTTPS, iOS8. | |
1009 // iOS8 cannot load unauthenticated HTTPS content. | |
1010 SSLStatus.security_style = web::SECURITY_STYLE_AUTHENTICATED; | |
1011 } | |
902 } | 1012 } |
903 | 1013 |
904 if (!previousSSLStatus.Equals(SSLStatus)) { | 1014 if (!previousSSLStatus.Equals(SSLStatus)) { |
905 [self didUpdateSSLStatusForCurrentNavigationItem]; | 1015 [self didUpdateSSLStatusForCurrentNavigationItem]; |
906 } | 1016 } |
907 } | 1017 } |
1018 | |
908 #endif // !defined(ENABLE_CHROME_NET_STACK_FOR_WKWEBVIEW) | 1019 #endif // !defined(ENABLE_CHROME_NET_STACK_FOR_WKWEBVIEW) |
909 | 1020 |
1021 - (void)reportHasCertForSecureConnectionUMAWithValue:(bool)value { | |
1022 UMA_HISTOGRAM_BOOLEAN("WebController.WKWebViewHasCertForSecureConnection", | |
1023 value); | |
1024 } | |
1025 | |
910 - (void)registerLoadRequest:(const GURL&)url { | 1026 - (void)registerLoadRequest:(const GURL&)url { |
911 // If load request is registered via WKWebViewWebController, assume transition | 1027 // If load request is registered via WKWebViewWebController, assume transition |
912 // is link or client redirect as other transitions will already be registered | 1028 // is link or client redirect as other transitions will already be registered |
913 // by web controller or delegates. | 1029 // by web controller or delegates. |
914 // TODO(stuartmorgan): Remove guesswork and replace with information from | 1030 // TODO(stuartmorgan): Remove guesswork and replace with information from |
915 // decidePolicyForNavigationAction:. | 1031 // decidePolicyForNavigationAction:. |
916 ui::PageTransition transition = self.userInteractionRegistered | 1032 ui::PageTransition transition = self.userInteractionRegistered |
917 ? ui::PAGE_TRANSITION_LINK | 1033 ? ui::PAGE_TRANSITION_LINK |
918 : ui::PAGE_TRANSITION_CLIENT_REDIRECT; | 1034 : ui::PAGE_TRANSITION_CLIENT_REDIRECT; |
919 // The referrer is not known yet, and will be updated later. | 1035 // The referrer is not known yet, and will be updated later. |
(...skipping 462 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1382 (void (^)(NSURLSessionAuthChallengeDisposition disposition, | 1498 (void (^)(NSURLSessionAuthChallengeDisposition disposition, |
1383 NSURLCredential *credential))completionHandler { | 1499 NSURLCredential *credential))completionHandler { |
1384 if (![challenge.protectionSpace.authenticationMethod | 1500 if (![challenge.protectionSpace.authenticationMethod |
1385 isEqual:NSURLAuthenticationMethodServerTrust]) { | 1501 isEqual:NSURLAuthenticationMethodServerTrust]) { |
1386 completionHandler(NSURLSessionAuthChallengePerformDefaultHandling, nil); | 1502 completionHandler(NSURLSessionAuthChallengePerformDefaultHandling, nil); |
1387 return; | 1503 return; |
1388 } | 1504 } |
1389 | 1505 |
1390 SecTrustRef trust = challenge.protectionSpace.serverTrust; | 1506 SecTrustRef trust = challenge.protectionSpace.serverTrust; |
1391 scoped_refptr<net::X509Certificate> cert = web::CreateCertFromTrust(trust); | 1507 scoped_refptr<net::X509Certificate> cert = web::CreateCertFromTrust(trust); |
1508 // TODO(eugenebut): pass SecTrustRef instead of cert. | |
1392 [_certVerificationController | 1509 [_certVerificationController |
1393 decidePolicyForCert:cert | 1510 decidePolicyForCert:cert |
1394 host:challenge.protectionSpace.host | 1511 host:challenge.protectionSpace.host |
1395 completionHandler:^(web::CertAcceptPolicy policy, | 1512 completionHandler:^(web::CertAcceptPolicy policy, |
1396 net::CertStatus status) { | 1513 net::CertStatus status) { |
1397 completionHandler(NSURLSessionAuthChallengeRejectProtectionSpace, | 1514 completionHandler(NSURLSessionAuthChallengeRejectProtectionSpace, |
1398 nil); | 1515 nil); |
1399 }]; | 1516 }]; |
1400 } | 1517 } |
1401 | 1518 |
(...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1488 placeholderText:defaultText | 1605 placeholderText:defaultText |
1489 requestURL: | 1606 requestURL: |
1490 net::GURLWithNSURL(frame.request.URL) | 1607 net::GURLWithNSURL(frame.request.URL) |
1491 completionHandler:completionHandler]; | 1608 completionHandler:completionHandler]; |
1492 } else if (completionHandler) { | 1609 } else if (completionHandler) { |
1493 completionHandler(nil); | 1610 completionHandler(nil); |
1494 } | 1611 } |
1495 } | 1612 } |
1496 | 1613 |
1497 @end | 1614 @end |
OLD | NEW |