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 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 |
| 259 // Registers load request with empty referrer and link or client redirect | 275 // Registers load request with empty referrer and link or client redirect |
| 260 // transition based on user interaction state. | 276 // transition based on user interaction state. |
| 261 - (void)registerLoadRequest:(const GURL&)url; | 277 - (void)registerLoadRequest:(const GURL&)url; |
| 262 | 278 |
| (...skipping 594 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 857 - (void)addActivityIndicatorTask { | 873 - (void)addActivityIndicatorTask { |
| 858 [[CRWNetworkActivityIndicatorManager sharedInstance] | 874 [[CRWNetworkActivityIndicatorManager sharedInstance] |
| 859 startNetworkTaskForGroup:[self activityIndicatorGroupID]]; | 875 startNetworkTaskForGroup:[self activityIndicatorGroupID]]; |
| 860 } | 876 } |
| 861 | 877 |
| 862 - (void)clearActivityIndicatorTasks { | 878 - (void)clearActivityIndicatorTasks { |
| 863 [[CRWNetworkActivityIndicatorManager sharedInstance] | 879 [[CRWNetworkActivityIndicatorManager sharedInstance] |
| 864 clearNetworkTasksForGroup:[self activityIndicatorGroupID]]; | 880 clearNetworkTasksForGroup:[self activityIndicatorGroupID]]; |
| 865 } | 881 } |
| 866 | 882 |
| 883 - (void)updateSSLStatusForNavigationItemWithID:(int)navigationItemID | |
| 884 certChain:(NSArray*)chain | |
| 885 host:(NSString*)host | |
| 886 withSecurityStyle:(web::SecurityStyle)style | |
| 887 certStatus:(net::CertStatus)certStatus { | |
| 888 web::NavigationManager* navigationManager = | |
| 889 self.webStateImpl->GetNavigationManager(); | |
| 890 | |
| 891 // The searched item almost always be the last one, so walk backward rather | |
| 892 // than forward. | |
| 893 for (int i = navigationManager->GetEntryCount() - 1; 0 <= i; i--) { | |
| 894 web::NavigationItem* item = navigationManager->GetItemAtIndex(i); | |
| 895 if (item->GetUniqueID() != navigationItemID) | |
| 896 continue; | |
| 897 | |
| 898 // NavigationItem's UniqueID is preserved even after redirects, so | |
| 899 // checking that cert and URL match is necessary. | |
| 900 scoped_refptr<net::X509Certificate> cert(web::CreateCertFromChain(chain)); | |
| 901 int certID = | |
| 902 web::CertStore::GetInstance()->StoreCert(cert.get(), self.certGroupID); | |
| 903 std::string GURLHost = base::SysNSStringToUTF8(host); | |
| 904 web::SSLStatus& SSLStatus = item->GetSSL(); | |
| 905 if (SSLStatus.cert_id == certID && item->GetURL().host() == GURLHost) { | |
| 906 web::SSLStatus previousSSLStatus = item->GetSSL(); | |
| 907 SSLStatus.cert_status = certStatus; | |
| 908 SSLStatus.security_style = style; | |
| 909 if (navigationManager->GetCurrentEntryIndex() == i && | |
| 910 !previousSSLStatus.Equals(SSLStatus)) { | |
| 911 [self didUpdateSSLStatusForCurrentNavigationItem]; | |
| 912 } | |
| 913 } | |
| 914 return; | |
| 915 } | |
| 916 } | |
| 917 | |
| 918 - (void)scheduleSSLStatusUpdateUsingCertChain:(NSArray*)chain | |
| 919 host:(NSString*)host { | |
| 920 // Use Navigation Item's unique ID to locate requested item after | |
| 921 // obtaining cert status asynchronously. | |
| 922 int itemID = self.webStateImpl->GetNavigationManager() | |
| 923 ->GetLastCommittedItem() | |
| 924 ->GetUniqueID(); | |
| 925 | |
| 926 base::WeakNSObject<CRWWKWebViewWebController> weakSelf(self); | |
| 927 void (^SSLStatusResponse)(web::SecurityStyle, net::CertStatus) = | |
| 928 ^(web::SecurityStyle style, net::CertStatus certStatus) { | |
| 929 base::scoped_nsobject<CRWWKWebViewWebController> strongSelf( | |
| 930 [weakSelf retain]); | |
| 931 if (!strongSelf || [strongSelf isBeingDestroyed]) { | |
| 932 return; | |
| 933 } | |
| 934 [strongSelf updateSSLStatusForNavigationItemWithID:itemID | |
| 935 certChain:chain | |
| 936 host:host | |
| 937 withSecurityStyle:style | |
| 938 certStatus:certStatus]; | |
| 939 }; | |
| 940 | |
| 941 [_certVerificationController | |
| 942 querySSLStatusForTrust:web::CreateServerTrustFromChain(chain, host) | |
| 943 host:host | |
| 944 completionHandler:SSLStatusResponse]; | |
| 945 } | |
| 946 | |
| 867 #if !defined(ENABLE_CHROME_NET_STACK_FOR_WKWEBVIEW) | 947 #if !defined(ENABLE_CHROME_NET_STACK_FOR_WKWEBVIEW) |
| 948 | |
| 868 - (void)updateSSLStatusForCurrentNavigationItem { | 949 - (void)updateSSLStatusForCurrentNavigationItem { |
| 869 if ([self isBeingDestroyed]) | 950 if ([self isBeingDestroyed]) |
| 870 return; | 951 return; |
| 871 | 952 |
| 872 DCHECK(self.webStateImpl); | |
| 873 web::NavigationItem* item = | 953 web::NavigationItem* item = |
| 874 self.webStateImpl->GetNavigationManagerImpl().GetLastCommittedItem(); | 954 self.webStateImpl->GetNavigationManagerImpl().GetLastCommittedItem(); |
| 875 if (!item) | 955 if (!item) |
| 876 return; | 956 return; |
| 877 | 957 |
| 878 web::SSLStatus previousSSLStatus = item->GetSSL(); | 958 web::SSLStatus previousSSLStatus = item->GetSSL(); |
| 879 web::SSLStatus& SSLStatus = item->GetSSL(); | 959 |
| 960 // Starting from iOS9 WKWebView blocks active mixed content, so if | |
| 961 // |hasOnlySecureContent| returns NO it means passive content. | |
| 962 item->GetSSL().content_status = | |
| 963 [_wkWebView hasOnlySecureContent] | |
| 964 ? web::SSLStatus::NORMAL_CONTENT | |
| 965 : web::SSLStatus::DISPLAYED_INSECURE_CONTENT; | |
| 966 | |
| 967 // Try updating SSLStatus for current NavigationItem asynchronously. | |
| 968 scoped_refptr<net::X509Certificate> cert; | |
| 880 if (item->GetURL().SchemeIsCryptographic()) { | 969 if (item->GetURL().SchemeIsCryptographic()) { |
| 881 // TODO(eugenebut): Do not set security style to authenticated once | 970 NSArray* chain = [_wkWebView certificateChain]; |
| 882 // proceeding with bad ssl cert is implemented. | 971 cert = web::CreateCertFromChain(chain); |
| 883 SSLStatus.security_style = web::SECURITY_STYLE_AUTHENTICATED; | 972 if (cert) { |
| 884 SSLStatus.content_status = [_wkWebView hasOnlySecureContent] | 973 int oldCertID = item->GetSSL().cert_id; |
| 885 ? web::SSLStatus::NORMAL_CONTENT | 974 std::string oldHost = item->GetSSL().cert_status_host; |
| 886 : web::SSLStatus::DISPLAYED_INSECURE_CONTENT; | 975 item->GetSSL().cert_id = web::CertStore::GetInstance()->StoreCert( |
| 976 cert.get(), self.certGroupID); | |
| 977 item->GetSSL().cert_status_host = _documentURL.host(); | |
| 978 // Only recompute the SSLStatus information if the certificate or host has | |
| 979 // since changed. Host can be changed in case of redirect. | |
| 980 if (oldCertID != item->GetSSL().cert_id || | |
| 981 oldHost != item->GetSSL().cert_status_host) { | |
| 982 // Real SSL status is unknown, reset cert status and security style. | |
| 983 // they will be asynchronously updated in | |
|
davidben
2015/10/16 00:15:20
they -> They
Eugene But (OOO till 7-30)
2015/10/16 02:25:35
Done.
| |
| 984 // |scheduleSSLStatusUpdateUsingCertChain|. | |
| 985 item->GetSSL().cert_status = net::CertStatus(); | |
| 986 item->GetSSL().security_style = web::SECURITY_STYLE_UNKNOWN; | |
| 887 | 987 |
| 888 if (base::ios::IsRunningOnIOS9OrLater()) { | 988 NSString* host = base::SysUTF8ToNSString(_documentURL.host()); |
| 889 scoped_refptr<net::X509Certificate> cert(web::CreateCertFromChain( | 989 [self scheduleSSLStatusUpdateUsingCertChain:chain host:host]; |
| 890 [_wkWebView performSelector:@selector(certificateChain)])); | |
| 891 if (cert) { | |
| 892 SSLStatus.cert_id = web::CertStore::GetInstance()->StoreCert( | |
| 893 cert.get(), self.certGroupID); | |
| 894 } else { | |
| 895 SSLStatus.security_style = web::SECURITY_STYLE_UNAUTHENTICATED; | |
| 896 SSLStatus.cert_id = 0; | |
| 897 } | 990 } |
| 898 } | 991 } |
| 899 } else { | |
| 900 SSLStatus.security_style = web::SECURITY_STYLE_UNAUTHENTICATED; | |
| 901 SSLStatus.cert_id = 0; | |
| 902 } | 992 } |
| 903 | 993 |
| 904 if (!previousSSLStatus.Equals(SSLStatus)) { | 994 if (!cert) { |
| 995 item->GetSSL().cert_id = 0; | |
| 996 if (!item->GetURL().SchemeIsCryptographic()) { | |
| 997 // HTTP or other non-secure connection. | |
| 998 item->GetSSL().security_style = web::SECURITY_STYLE_UNAUTHENTICATED; | |
| 999 } else { | |
| 1000 // HTTPS, no certificate (this use-case has not been observed). | |
| 1001 item->GetSSL().security_style = web::SECURITY_STYLE_UNKNOWN; | |
| 1002 } | |
| 1003 } | |
| 1004 | |
| 1005 if (!previousSSLStatus.Equals(item->GetSSL())) { | |
| 905 [self didUpdateSSLStatusForCurrentNavigationItem]; | 1006 [self didUpdateSSLStatusForCurrentNavigationItem]; |
| 906 } | 1007 } |
| 907 } | 1008 } |
| 1009 | |
| 908 #endif // !defined(ENABLE_CHROME_NET_STACK_FOR_WKWEBVIEW) | 1010 #endif // !defined(ENABLE_CHROME_NET_STACK_FOR_WKWEBVIEW) |
| 909 | 1011 |
| 910 - (void)registerLoadRequest:(const GURL&)url { | 1012 - (void)registerLoadRequest:(const GURL&)url { |
| 911 // If load request is registered via WKWebViewWebController, assume transition | 1013 // If load request is registered via WKWebViewWebController, assume transition |
| 912 // is link or client redirect as other transitions will already be registered | 1014 // is link or client redirect as other transitions will already be registered |
| 913 // by web controller or delegates. | 1015 // by web controller or delegates. |
| 914 // TODO(stuartmorgan): Remove guesswork and replace with information from | 1016 // TODO(stuartmorgan): Remove guesswork and replace with information from |
| 915 // decidePolicyForNavigationAction:. | 1017 // decidePolicyForNavigationAction:. |
| 916 ui::PageTransition transition = self.userInteractionRegistered | 1018 ui::PageTransition transition = self.userInteractionRegistered |
| 917 ? ui::PAGE_TRANSITION_LINK | 1019 ? ui::PAGE_TRANSITION_LINK |
| 918 : ui::PAGE_TRANSITION_CLIENT_REDIRECT; | 1020 : ui::PAGE_TRANSITION_CLIENT_REDIRECT; |
| 919 // The referrer is not known yet, and will be updated later. | 1021 // The referrer is not known yet, and will be updated later. |
| 920 const web::Referrer emptyReferrer; | 1022 const web::Referrer emptyReferrer; |
| 921 [self registerLoadRequest:url referrer:emptyReferrer transition:transition]; | 1023 [self registerLoadRequest:url referrer:emptyReferrer transition:transition]; |
| 922 } | 1024 } |
| 923 | 1025 |
| 924 - (void)URLDidChangeWithoutDocumentChange:(const GURL&)newURL { | 1026 - (void)URLDidChangeWithoutDocumentChange:(const GURL&)newURL { |
| 925 DCHECK(newURL == net::GURLWithNSURL([_wkWebView URL])); | 1027 DCHECK(newURL == net::GURLWithNSURL([_wkWebView URL])); |
| 1028 DCHECK_EQ(_documentURL.host(), newURL.host()); | |
| 926 _documentURL = newURL; | 1029 _documentURL = newURL; |
| 927 // If called during window.history.pushState or window.history.replaceState | 1030 // If called during window.history.pushState or window.history.replaceState |
| 928 // JavaScript evaluation, only update the document URL. This callback does not | 1031 // 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 | 1032 // 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 | 1033 // navigation entry for this page change. Web controller will sync with |
| 931 // history changes when a window.history.didPushState or | 1034 // history changes when a window.history.didPushState or |
| 932 // window.history.didReplaceState message is received, which should happen in | 1035 // window.history.didReplaceState message is received, which should happen in |
| 933 // the next runloop. | 1036 // the next runloop. |
| 934 if (!_changingHistoryState) { | 1037 if (!_changingHistoryState) { |
| 935 [self registerLoadRequest:_documentURL]; | 1038 [self registerLoadRequest:_documentURL]; |
| (...skipping 413 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1349 // This is the point where the document's URL has actually changed. | 1452 // This is the point where the document's URL has actually changed. |
| 1350 _documentURL = net::GURLWithNSURL([_wkWebView URL]); | 1453 _documentURL = net::GURLWithNSURL([_wkWebView URL]); |
| 1351 DCHECK(_documentURL == self.lastRegisteredRequestURL); | 1454 DCHECK(_documentURL == self.lastRegisteredRequestURL); |
| 1352 [self webPageChanged]; | 1455 [self webPageChanged]; |
| 1353 | 1456 |
| 1354 [self updateCurrentBackForwardListItemHolder]; | 1457 [self updateCurrentBackForwardListItemHolder]; |
| 1355 | 1458 |
| 1356 #if !defined(ENABLE_CHROME_NET_STACK_FOR_WKWEBVIEW) | 1459 #if !defined(ENABLE_CHROME_NET_STACK_FOR_WKWEBVIEW) |
| 1357 [self updateSSLStatusForCurrentNavigationItem]; | 1460 [self updateSSLStatusForCurrentNavigationItem]; |
| 1358 #endif | 1461 #endif |
| 1462 | |
| 1463 // Report cases where SSL cert is missing for a secure connection. | |
| 1464 if (_documentURL.SchemeIsCryptographic()) { | |
| 1465 scoped_refptr<net::X509Certificate> cert = | |
| 1466 web::CreateCertFromChain([_wkWebView certificateChain]); | |
| 1467 UMA_HISTOGRAM_BOOLEAN("WebController.WKWebViewHasCertForSecureConnection", | |
| 1468 cert); | |
| 1469 } | |
| 1359 } | 1470 } |
| 1360 | 1471 |
| 1361 - (void)webView:(WKWebView *)webView | 1472 - (void)webView:(WKWebView *)webView |
| 1362 didFinishNavigation:(WKNavigation *)navigation { | 1473 didFinishNavigation:(WKNavigation *)navigation { |
| 1363 DCHECK(!self.isHalted); | 1474 DCHECK(!self.isHalted); |
| 1364 // Trigger JavaScript driven post-document-load-completion tasks. | 1475 // Trigger JavaScript driven post-document-load-completion tasks. |
| 1365 // TODO(jyquinn): Investigate using WKUserScriptInjectionTimeAtDocumentEnd to | 1476 // TODO(jyquinn): Investigate using WKUserScriptInjectionTimeAtDocumentEnd to |
| 1366 // inject this material at the appropriate time rather than invoking here. | 1477 // inject this material at the appropriate time rather than invoking here. |
| 1367 web::EvaluateJavaScript(webView, | 1478 web::EvaluateJavaScript(webView, |
| 1368 @"__gCrWeb.didFinishNavigation()", nil); | 1479 @"__gCrWeb.didFinishNavigation()", nil); |
| (...skipping 13 matching lines...) Expand all 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 |