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 219 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
243 // Called when a load ends in an SSL error and certificate chain. | 244 // Called when a load ends in an SSL error and certificate chain. |
244 - (void)handleSSLCertError:(NSError*)error; | 245 - (void)handleSSLCertError:(NSError*)error; |
245 #endif | 246 #endif |
246 | 247 |
247 // Adds an activity indicator tasks for this web controller. | 248 // Adds an activity indicator tasks for this web controller. |
248 - (void)addActivityIndicatorTask; | 249 - (void)addActivityIndicatorTask; |
249 | 250 |
250 // Clears all activity indicator tasks for this web controller. | 251 // Clears all activity indicator tasks for this web controller. |
251 - (void)clearActivityIndicatorTasks; | 252 - (void)clearActivityIndicatorTasks; |
252 | 253 |
254 // Updates |security_style| and |cert_status| for the NavigationItem with ID | |
255 // |navigationItemID|, if URL and certificate chain still match |host| and | |
256 // |certChain|. | |
257 - (void)updateSSLStatusForNavigationItemWithID:(int)navigationItemID | |
258 certChain:(NSArray*)chain | |
259 host:(NSString*)host | |
260 withSecurityStyle:(web::SecurityStyle)style | |
261 certStatus:(net::CertStatus)certStatus; | |
262 | |
263 // Asynchronously obtains SSL status from given |certChain| and |host| and | |
264 // updates current navigation item. Before scheduling update changes SSLStatus' | |
265 // cert_status and security_style to default. | |
266 - (void)scheduleSSLStatusUpdateUsingCertChain:(NSArray*)chain | |
267 host:(NSString*)host; | |
268 | |
253 #if !defined(ENABLE_CHROME_NET_STACK_FOR_WKWEBVIEW) | 269 #if !defined(ENABLE_CHROME_NET_STACK_FOR_WKWEBVIEW) |
254 // Updates SSL status for the current navigation item based on the information | 270 // Updates SSL status for the current navigation item based on the information |
255 // provided by web view. | 271 // provided by web view. |
256 - (void)updateSSLStatusForCurrentNavigationItem; | 272 - (void)updateSSLStatusForCurrentNavigationItem; |
257 #endif | 273 #endif |
258 | 274 |
275 // Reports "WebController.WKWebViewHasCertForSecureConnection" UMA. | |
276 - (void)reportHasCertForSecureConnectionUMAWithValue:(bool)value; | |
277 | |
259 // Registers load request with empty referrer and link or client redirect | 278 // Registers load request with empty referrer and link or client redirect |
260 // transition based on user interaction state. | 279 // transition based on user interaction state. |
261 - (void)registerLoadRequest:(const GURL&)url; | 280 - (void)registerLoadRequest:(const GURL&)url; |
262 | 281 |
263 // Called when a non-document-changing URL change occurs. Updates the | 282 // Called when a non-document-changing URL change occurs. Updates the |
264 // _documentURL, and informs the superclass of the change. | 283 // _documentURL, and informs the superclass of the change. |
265 - (void)URLDidChangeWithoutDocumentChange:(const GURL&)URL; | 284 - (void)URLDidChangeWithoutDocumentChange:(const GURL&)URL; |
266 | 285 |
267 // Returns new autoreleased instance of WKUserContentController which has | 286 // Returns new autoreleased instance of WKUserContentController which has |
268 // early page script. | 287 // early page script. |
(...skipping 588 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
857 - (void)addActivityIndicatorTask { | 876 - (void)addActivityIndicatorTask { |
858 [[CRWNetworkActivityIndicatorManager sharedInstance] | 877 [[CRWNetworkActivityIndicatorManager sharedInstance] |
859 startNetworkTaskForGroup:[self activityIndicatorGroupID]]; | 878 startNetworkTaskForGroup:[self activityIndicatorGroupID]]; |
860 } | 879 } |
861 | 880 |
862 - (void)clearActivityIndicatorTasks { | 881 - (void)clearActivityIndicatorTasks { |
863 [[CRWNetworkActivityIndicatorManager sharedInstance] | 882 [[CRWNetworkActivityIndicatorManager sharedInstance] |
864 clearNetworkTasksForGroup:[self activityIndicatorGroupID]]; | 883 clearNetworkTasksForGroup:[self activityIndicatorGroupID]]; |
865 } | 884 } |
866 | 885 |
886 - (void)updateSSLStatusForNavigationItemWithID:(int)navigationItemID | |
887 certChain:(NSArray*)chain | |
888 host:(NSString*)host | |
889 withSecurityStyle:(web::SecurityStyle)style | |
890 certStatus:(net::CertStatus)certStatus { | |
891 web::NavigationManager* navigationManager = | |
892 self.webStateImpl->GetNavigationManager(); | |
893 | |
894 // The searched item almost always be the last one, so walk backward rather | |
895 // than forward. | |
896 for (int i = navigationManager->GetEntryCount() - 1; 0 <= i; i--) { | |
897 web::NavigationItem* item = navigationManager->GetItemAtIndex(i); | |
898 if (item->GetUniqueID() != navigationItemID) | |
899 continue; | |
900 | |
901 // NavigationItem's UniqueID is preserved even after redirects, so | |
902 // checking that cert and URL match is necessary. | |
903 scoped_refptr<net::X509Certificate> cert(web::CreateCertFromChain(chain)); | |
904 int certID = | |
905 web::CertStore::GetInstance()->StoreCert(cert.get(), self.certGroupID); | |
906 std::string GURLHost = base::SysNSStringToUTF8(host); | |
907 web::SSLStatus& SSLStatus = item->GetSSL(); | |
908 if (SSLStatus.cert_id == certID && item->GetURL().host() == GURLHost) { | |
909 web::SSLStatus previousSSLStatus = item->GetSSL(); | |
910 SSLStatus.cert_status = certStatus; | |
911 SSLStatus.security_style = style; | |
912 if (navigationManager->GetCurrentEntryIndex() == i && | |
913 !previousSSLStatus.Equals(SSLStatus)) { | |
914 [self didUpdateSSLStatusForCurrentNavigationItem]; | |
915 } | |
916 } | |
917 return; | |
918 } | |
919 } | |
920 | |
921 - (void)scheduleSSLStatusUpdateUsingCertChain:(NSArray*)chain | |
922 host:(NSString*)host { | |
923 // Real SSL status is unknown, reset cert status and security style. Keep | |
924 // cert_id, which works as a guard to prevent re-entry into this method. | |
davidben
2015/10/15 17:46:12
I don't understand what this comment is saying. By
Eugene But (OOO till 7-30)
2015/10/15 22:59:34
Moved the code.
| |
925 web::NavigationItem* item = | |
926 self.webStateImpl->GetNavigationManager()->GetLastCommittedItem(); | |
927 item->GetSSL().cert_status = net::CertStatus(); | |
928 item->GetSSL().security_style = web::SECURITY_STYLE_UNKNOWN; | |
929 | |
930 // Use Navigation Item's unique ID to locate requested item after | |
931 // obtaining cert status asynchronously. | |
932 int itemID = item->GetUniqueID(); | |
933 | |
934 base::WeakNSObject<CRWWKWebViewWebController> weakSelf(self); | |
935 void (^SSLStatusResponse)(web::SecurityStyle, net::CertStatus) = | |
936 ^(web::SecurityStyle style, net::CertStatus certStatus) { | |
937 base::scoped_nsobject<CRWWKWebViewWebController> strongSelf( | |
938 [weakSelf retain]); | |
939 if (!strongSelf || [strongSelf isBeingDestroyed]) { | |
940 return; | |
941 } | |
942 [strongSelf updateSSLStatusForNavigationItemWithID:itemID | |
943 certChain:chain | |
944 host:host | |
945 withSecurityStyle:style | |
946 certStatus:certStatus]; | |
947 }; | |
948 | |
949 [_certVerificationController | |
950 querySSLStatusForTrust:web::CreateServerTrustFromChain(chain, host) | |
951 host:host | |
952 completionHandler:SSLStatusResponse]; | |
953 } | |
954 | |
867 #if !defined(ENABLE_CHROME_NET_STACK_FOR_WKWEBVIEW) | 955 #if !defined(ENABLE_CHROME_NET_STACK_FOR_WKWEBVIEW) |
956 | |
868 - (void)updateSSLStatusForCurrentNavigationItem { | 957 - (void)updateSSLStatusForCurrentNavigationItem { |
869 if ([self isBeingDestroyed]) | 958 if ([self isBeingDestroyed]) |
870 return; | 959 return; |
871 | 960 |
872 DCHECK(self.webStateImpl); | |
873 web::NavigationItem* item = | 961 web::NavigationItem* item = |
874 self.webStateImpl->GetNavigationManagerImpl().GetLastCommittedItem(); | 962 self.webStateImpl->GetNavigationManagerImpl().GetLastCommittedItem(); |
875 if (!item) | 963 if (!item) |
876 return; | 964 return; |
877 | 965 |
878 web::SSLStatus previousSSLStatus = item->GetSSL(); | 966 web::SSLStatus previousSSLStatus = item->GetSSL(); |
879 web::SSLStatus& SSLStatus = item->GetSSL(); | 967 web::SSLStatus& SSLStatus = item->GetSSL(); |
968 | |
969 // Starting from iOS9 WKWebView blocks active mixed content, so if | |
970 // |hasOnlySecureContent| returns NO it means passive content. | |
971 SSLStatus.content_status = [_wkWebView hasOnlySecureContent] | |
972 ? web::SSLStatus::NORMAL_CONTENT | |
973 : web::SSLStatus::DISPLAYED_INSECURE_CONTENT; | |
974 | |
975 // Try updating SSLStatus for current NavigationItem asynchronously. | |
976 scoped_refptr<net::X509Certificate> cert; | |
880 if (item->GetURL().SchemeIsCryptographic()) { | 977 if (item->GetURL().SchemeIsCryptographic()) { |
881 // TODO(eugenebut): Do not set security style to authenticated once | 978 NSArray* chain = [_wkWebView certificateChain]; |
882 // proceeding with bad ssl cert is implemented. | 979 cert = web::CreateCertFromChain(chain); |
883 SSLStatus.security_style = web::SECURITY_STYLE_AUTHENTICATED; | 980 if (cert) { |
884 SSLStatus.content_status = [_wkWebView hasOnlySecureContent] | 981 int oldCertID = SSLStatus.cert_id; |
885 ? web::SSLStatus::NORMAL_CONTENT | 982 SSLStatus.cert_id = web::CertStore::GetInstance()->StoreCert( |
886 : web::SSLStatus::DISPLAYED_INSECURE_CONTENT; | 983 cert.get(), self.certGroupID); |
887 | 984 // Only recompute the SSLStatus information if the certificate or host has |
888 if (base::ios::IsRunningOnIOS9OrLater()) { | 985 // since changed. Host can be changed in case of redirect. |
889 scoped_refptr<net::X509Certificate> cert(web::CreateCertFromChain( | 986 if (oldCertID != SSLStatus.cert_id || |
890 [_wkWebView performSelector:@selector(certificateChain)])); | 987 item->GetURL().host() != _documentURL.host()) { |
891 if (cert) { | 988 NSString* host = base::SysUTF8ToNSString(_documentURL.host()); |
892 SSLStatus.cert_id = web::CertStore::GetInstance()->StoreCert( | 989 [self scheduleSSLStatusUpdateUsingCertChain:chain host:host]; |
893 cert.get(), self.certGroupID); | 990 [self reportHasCertForSecureConnectionUMAWithValue:true]; |
894 } else { | |
895 SSLStatus.security_style = web::SECURITY_STYLE_UNAUTHENTICATED; | |
896 SSLStatus.cert_id = 0; | |
897 } | 991 } |
898 } | 992 } |
899 } else { | 993 } |
900 SSLStatus.security_style = web::SECURITY_STYLE_UNAUTHENTICATED; | 994 |
995 if (!cert) { | |
901 SSLStatus.cert_id = 0; | 996 SSLStatus.cert_id = 0; |
997 if (!item->GetURL().SchemeIsCryptographic()) { | |
998 // HTTP or other non-secure connection. | |
999 SSLStatus.security_style = web::SECURITY_STYLE_UNAUTHENTICATED; | |
1000 } else { | |
1001 // HTTPS, no certificate (this use-case has not been observed). | |
1002 SSLStatus.security_style = web::SECURITY_STYLE_UNKNOWN; | |
1003 if (!previousSSLStatus.Equals(SSLStatus)) { | |
1004 [self reportHasCertForSecureConnectionUMAWithValue:false]; | |
davidben
2015/10/15 17:46:12
If all that changed was hasSecureContent, this wil
Eugene But (OOO till 7-30)
2015/10/15 22:59:34
That's a good suggestion. Done.
| |
1005 } | |
1006 } | |
902 } | 1007 } |
903 | 1008 |
904 if (!previousSSLStatus.Equals(SSLStatus)) { | 1009 if (!previousSSLStatus.Equals(SSLStatus)) { |
905 [self didUpdateSSLStatusForCurrentNavigationItem]; | 1010 [self didUpdateSSLStatusForCurrentNavigationItem]; |
906 } | 1011 } |
907 } | 1012 } |
1013 | |
908 #endif // !defined(ENABLE_CHROME_NET_STACK_FOR_WKWEBVIEW) | 1014 #endif // !defined(ENABLE_CHROME_NET_STACK_FOR_WKWEBVIEW) |
909 | 1015 |
1016 - (void)reportHasCertForSecureConnectionUMAWithValue:(bool)value { | |
1017 UMA_HISTOGRAM_BOOLEAN("WebController.WKWebViewHasCertForSecureConnection", | |
1018 value); | |
1019 } | |
1020 | |
910 - (void)registerLoadRequest:(const GURL&)url { | 1021 - (void)registerLoadRequest:(const GURL&)url { |
911 // If load request is registered via WKWebViewWebController, assume transition | 1022 // If load request is registered via WKWebViewWebController, assume transition |
912 // is link or client redirect as other transitions will already be registered | 1023 // is link or client redirect as other transitions will already be registered |
913 // by web controller or delegates. | 1024 // by web controller or delegates. |
914 // TODO(stuartmorgan): Remove guesswork and replace with information from | 1025 // TODO(stuartmorgan): Remove guesswork and replace with information from |
915 // decidePolicyForNavigationAction:. | 1026 // decidePolicyForNavigationAction:. |
916 ui::PageTransition transition = self.userInteractionRegistered | 1027 ui::PageTransition transition = self.userInteractionRegistered |
917 ? ui::PAGE_TRANSITION_LINK | 1028 ? ui::PAGE_TRANSITION_LINK |
918 : ui::PAGE_TRANSITION_CLIENT_REDIRECT; | 1029 : ui::PAGE_TRANSITION_CLIENT_REDIRECT; |
919 // The referrer is not known yet, and will be updated later. | 1030 // The referrer is not known yet, and will be updated later. |
920 const web::Referrer emptyReferrer; | 1031 const web::Referrer emptyReferrer; |
921 [self registerLoadRequest:url referrer:emptyReferrer transition:transition]; | 1032 [self registerLoadRequest:url referrer:emptyReferrer transition:transition]; |
922 } | 1033 } |
923 | 1034 |
924 - (void)URLDidChangeWithoutDocumentChange:(const GURL&)newURL { | 1035 - (void)URLDidChangeWithoutDocumentChange:(const GURL&)newURL { |
925 DCHECK(newURL == net::GURLWithNSURL([_wkWebView URL])); | 1036 DCHECK(newURL == net::GURLWithNSURL([_wkWebView URL])); |
926 _documentURL = newURL; | 1037 _documentURL = newURL; |
davidben
2015/10/15 17:46:12
This should probably also have a DCHECK that _docu
Eugene But (OOO till 7-30)
2015/10/15 22:59:34
Yes it should. Done.
| |
927 // If called during window.history.pushState or window.history.replaceState | 1038 // If called during window.history.pushState or window.history.replaceState |
928 // JavaScript evaluation, only update the document URL. This callback does not | 1039 // JavaScript evaluation, only update the document URL. This callback does not |
929 // have any information about the state object and cannot create (or edit) the | 1040 // have any information about the state object and cannot create (or edit) the |
930 // navigation entry for this page change. Web controller will sync with | 1041 // navigation entry for this page change. Web controller will sync with |
931 // history changes when a window.history.didPushState or | 1042 // history changes when a window.history.didPushState or |
932 // window.history.didReplaceState message is received, which should happen in | 1043 // window.history.didReplaceState message is received, which should happen in |
933 // the next runloop. | 1044 // the next runloop. |
934 if (!_changingHistoryState) { | 1045 if (!_changingHistoryState) { |
935 [self registerLoadRequest:_documentURL]; | 1046 [self registerLoadRequest:_documentURL]; |
936 [self didStartLoadingURL:_documentURL updateHistory:YES]; | 1047 [self didStartLoadingURL:_documentURL updateHistory:YES]; |
(...skipping 154 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1091 // TODO(eugenebut): use WKWebView progress even if Chrome net stack is enabled. | 1202 // TODO(eugenebut): use WKWebView progress even if Chrome net stack is enabled. |
1092 - (void)webViewEstimatedProgressDidChange { | 1203 - (void)webViewEstimatedProgressDidChange { |
1093 if ([self.delegate respondsToSelector: | 1204 if ([self.delegate respondsToSelector: |
1094 @selector(webController:didUpdateProgress:)]) { | 1205 @selector(webController:didUpdateProgress:)]) { |
1095 [self.delegate webController:self | 1206 [self.delegate webController:self |
1096 didUpdateProgress:[_wkWebView estimatedProgress]]; | 1207 didUpdateProgress:[_wkWebView estimatedProgress]]; |
1097 } | 1208 } |
1098 } | 1209 } |
1099 | 1210 |
1100 - (void)webViewSecurityFeaturesDidChange { | 1211 - (void)webViewSecurityFeaturesDidChange { |
1101 if (self.loadPhase == web::LOAD_REQUESTED) { | 1212 if (self.loadPhase == web::LOAD_REQUESTED) { |
davidben
2015/10/15 17:46:12
Existing issue (probably ought to be separate), bu
stuartmorgan
2015/10/15 22:02:27
IIRC it's because we get told about changes relate
Eugene But (OOO till 7-30)
2015/10/15 22:59:34
WKWebView API is weird. certificateChain, URL, or
davidben
2015/10/16 00:15:20
Gotcha. Sigh. :-) I guess the situation is what it
| |
1102 // Do not update SSL Status for pending load. It will be updated in | 1213 // Do not update SSL Status for pending load. It will be updated in |
1103 // |webView:didCommitNavigation:| callback. | 1214 // |webView:didCommitNavigation:| callback. |
1104 return; | 1215 return; |
1105 } | 1216 } |
1106 [self updateSSLStatusForCurrentNavigationItem]; | 1217 [self updateSSLStatusForCurrentNavigationItem]; |
1107 } | 1218 } |
1108 | 1219 |
1109 #endif // !defined(ENABLE_CHROME_NET_STACK_FOR_WKWEBVIEW) | 1220 #endif // !defined(ENABLE_CHROME_NET_STACK_FOR_WKWEBVIEW) |
1110 | 1221 |
1111 - (void)webViewLoadingStateDidChange { | 1222 - (void)webViewLoadingStateDidChange { |
(...skipping 270 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1382 (void (^)(NSURLSessionAuthChallengeDisposition disposition, | 1493 (void (^)(NSURLSessionAuthChallengeDisposition disposition, |
1383 NSURLCredential *credential))completionHandler { | 1494 NSURLCredential *credential))completionHandler { |
1384 if (![challenge.protectionSpace.authenticationMethod | 1495 if (![challenge.protectionSpace.authenticationMethod |
1385 isEqual:NSURLAuthenticationMethodServerTrust]) { | 1496 isEqual:NSURLAuthenticationMethodServerTrust]) { |
1386 completionHandler(NSURLSessionAuthChallengePerformDefaultHandling, nil); | 1497 completionHandler(NSURLSessionAuthChallengePerformDefaultHandling, nil); |
1387 return; | 1498 return; |
1388 } | 1499 } |
1389 | 1500 |
1390 SecTrustRef trust = challenge.protectionSpace.serverTrust; | 1501 SecTrustRef trust = challenge.protectionSpace.serverTrust; |
1391 scoped_refptr<net::X509Certificate> cert = web::CreateCertFromTrust(trust); | 1502 scoped_refptr<net::X509Certificate> cert = web::CreateCertFromTrust(trust); |
1503 // TODO(eugenebut): pass SecTrustRef instead of cert. | |
1392 [_certVerificationController | 1504 [_certVerificationController |
1393 decidePolicyForCert:cert | 1505 decidePolicyForCert:cert |
1394 host:challenge.protectionSpace.host | 1506 host:challenge.protectionSpace.host |
1395 completionHandler:^(web::CertAcceptPolicy policy, | 1507 completionHandler:^(web::CertAcceptPolicy policy, |
1396 net::CertStatus status) { | 1508 net::CertStatus status) { |
1397 completionHandler(NSURLSessionAuthChallengeRejectProtectionSpace, | 1509 completionHandler(NSURLSessionAuthChallengeRejectProtectionSpace, |
1398 nil); | 1510 nil); |
1399 }]; | 1511 }]; |
1400 } | 1512 } |
1401 | 1513 |
(...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1488 placeholderText:defaultText | 1600 placeholderText:defaultText |
1489 requestURL: | 1601 requestURL: |
1490 net::GURLWithNSURL(frame.request.URL) | 1602 net::GURLWithNSURL(frame.request.URL) |
1491 completionHandler:completionHandler]; | 1603 completionHandler:completionHandler]; |
1492 } else if (completionHandler) { | 1604 } else if (completionHandler) { |
1493 completionHandler(nil); | 1605 completionHandler(nil); |
1494 } | 1606 } |
1495 } | 1607 } |
1496 | 1608 |
1497 @end | 1609 @end |
OLD | NEW |