| OLD | NEW |
| 1 // Copyright 2012 The Chromium Authors. All rights reserved. | 1 // Copyright 2012 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_web_controller.h" | 5 #import "ios/web/web_state/ui/crw_web_controller.h" |
| 6 | 6 |
| 7 #import <WebKit/WebKit.h> | 7 #import <WebKit/WebKit.h> |
| 8 | 8 |
| 9 #include <utility> | 9 #include <utility> |
| 10 | 10 |
| (...skipping 13 matching lines...) Expand all Loading... |
| 24 #import "ios/web/public/test/fakes/test_web_view_content_view.h" | 24 #import "ios/web/public/test/fakes/test_web_view_content_view.h" |
| 25 #import "ios/web/public/web_state/crw_web_controller_observer.h" | 25 #import "ios/web/public/web_state/crw_web_controller_observer.h" |
| 26 #import "ios/web/public/web_state/ui/crw_content_view.h" | 26 #import "ios/web/public/web_state/ui/crw_content_view.h" |
| 27 #import "ios/web/public/web_state/ui/crw_native_content.h" | 27 #import "ios/web/public/web_state/ui/crw_native_content.h" |
| 28 #import "ios/web/public/web_state/ui/crw_native_content_provider.h" | 28 #import "ios/web/public/web_state/ui/crw_native_content_provider.h" |
| 29 #import "ios/web/public/web_state/ui/crw_web_view_content_view.h" | 29 #import "ios/web/public/web_state/ui/crw_web_view_content_view.h" |
| 30 #include "ios/web/public/web_state/url_verification_constants.h" | 30 #include "ios/web/public/web_state/url_verification_constants.h" |
| 31 #include "ios/web/public/web_state/web_state_observer.h" | 31 #include "ios/web/public/web_state/web_state_observer.h" |
| 32 #import "ios/web/test/web_test_with_web_controller.h" | 32 #import "ios/web/test/web_test_with_web_controller.h" |
| 33 #import "ios/web/test/wk_web_view_crash_utils.h" | 33 #import "ios/web/test/wk_web_view_crash_utils.h" |
| 34 #import "ios/web/web_state/blocked_popup_info.h" | |
| 35 #import "ios/web/web_state/ui/crw_web_controller_container_view.h" | 34 #import "ios/web/web_state/ui/crw_web_controller_container_view.h" |
| 36 #import "ios/web/web_state/web_state_impl.h" | 35 #import "ios/web/web_state/web_state_impl.h" |
| 37 #import "ios/web/web_state/wk_web_view_security_util.h" | 36 #import "ios/web/web_state/wk_web_view_security_util.h" |
| 38 #import "net/base/mac/url_conversions.h" | 37 #import "net/base/mac/url_conversions.h" |
| 39 #include "net/ssl/ssl_info.h" | 38 #include "net/ssl/ssl_info.h" |
| 40 #include "net/test/cert_test_util.h" | 39 #include "net/test/cert_test_util.h" |
| 41 #include "net/test/test_data_directory.h" | 40 #include "net/test/test_data_directory.h" |
| 42 #include "testing/gtest/include/gtest/gtest.h" | 41 #include "testing/gtest/include/gtest/gtest.h" |
| 43 #import "testing/gtest_mac.h" | 42 #import "testing/gtest_mac.h" |
| 44 #include "third_party/ocmock/OCMock/OCMock.h" | 43 #include "third_party/ocmock/OCMock/OCMock.h" |
| 45 #include "third_party/ocmock/gtest_support.h" | 44 #include "third_party/ocmock/gtest_support.h" |
| 46 #include "third_party/ocmock/ocmock_extensions.h" | 45 #include "third_party/ocmock/ocmock_extensions.h" |
| 47 #import "ui/base/test/ios/ui_view_test_utils.h" | 46 #import "ui/base/test/ios/ui_view_test_utils.h" |
| 48 | 47 |
| 49 using web::NavigationManagerImpl; | 48 using web::NavigationManagerImpl; |
| 50 | 49 |
| 51 @interface CRWWebController (PrivateAPI) | 50 @interface CRWWebController (PrivateAPI) |
| 52 @property(nonatomic, readwrite) web::PageDisplayState pageDisplayState; | 51 @property(nonatomic, readwrite) web::PageDisplayState pageDisplayState; |
| 53 - (GURL)URLForHistoryNavigationFromItem:(web::NavigationItem*)fromItem | 52 - (GURL)URLForHistoryNavigationFromItem:(web::NavigationItem*)fromItem |
| 54 toItem:(web::NavigationItem*)toItem; | 53 toItem:(web::NavigationItem*)toItem; |
| 55 @end | 54 @end |
| 56 | 55 |
| 57 // Used to mock CRWWebDelegate methods with C++ params. | 56 // Used to mock CRWWebDelegate methods with C++ params. |
| 58 @interface MockInteractionLoader : OCMockComplexTypeHelper | 57 @interface MockInteractionLoader : OCMockComplexTypeHelper |
| 59 // popupURL passed to webController:shouldBlockPopupWithURL:sourceURL: | |
| 60 // Used for testing. | |
| 61 @property(nonatomic, assign) GURL popupURL; | |
| 62 // sourceURL passed to webController:shouldBlockPopupWithURL:sourceURL: | |
| 63 // Used for testing. | |
| 64 @property(nonatomic, assign) GURL sourceURL; | |
| 65 // Whether or not the delegate should block popups. | 58 // Whether or not the delegate should block popups. |
| 66 @property(nonatomic, assign) BOOL blockPopups; | 59 @property(nonatomic, assign) BOOL blockPopups; |
| 67 // A web controller that will be returned by webPageOrdered... methods. | 60 // A web controller that will be returned by webPageOrdered... methods. |
| 68 @property(nonatomic, assign) CRWWebController* childWebController; | 61 @property(nonatomic, assign) CRWWebController* childWebController; |
| 69 // Blocked popup info received in |webController:didBlockPopup:| call. | 62 |
| 70 // nullptr if that delegate method was not called. | 63 // Values of arguments passed to |
| 71 @property(nonatomic, readonly) web::BlockedPopupInfo* blockedPopupInfo; | 64 // |webController:createWebControllerForURL:openerURL:initiatedByUser:|. |
| 65 @property(nonatomic, readonly) CRWWebController* webController; |
| 66 @property(nonatomic, readonly) GURL childURL; |
| 67 @property(nonatomic, readonly) GURL openerURL; |
| 68 @property(nonatomic, readonly) BOOL initiatedByUser; |
| 72 @end | 69 @end |
| 73 | 70 |
| 74 @implementation MockInteractionLoader { | 71 @implementation MockInteractionLoader |
| 75 // Backs up the property with the same name. | 72 |
| 76 std::unique_ptr<web::BlockedPopupInfo> _blockedPopupInfo; | |
| 77 } | |
| 78 @synthesize popupURL = _popupURL; | |
| 79 @synthesize sourceURL = _sourceURL; | |
| 80 @synthesize blockPopups = _blockPopups; | 73 @synthesize blockPopups = _blockPopups; |
| 81 @synthesize childWebController = _childWebController; | 74 @synthesize childWebController = _childWebController; |
| 82 | 75 @synthesize webController = _webController; |
| 83 typedef void (^webPageOrderedOpenBlankBlockType)(); | 76 @synthesize childURL = _childURL; |
| 84 typedef void (^webPageOrderedOpenBlockType)(const GURL&, | 77 @synthesize openerURL = _openerURL; |
| 85 const web::Referrer&, | 78 @synthesize initiatedByUser = _initiatedByUser; |
| 86 NSString*, | |
| 87 BOOL); | |
| 88 | 79 |
| 89 - (instancetype)initWithRepresentedObject:(id)representedObject { | 80 - (instancetype)initWithRepresentedObject:(id)representedObject { |
| 90 self = [super initWithRepresentedObject:representedObject]; | 81 self = [super initWithRepresentedObject:representedObject]; |
| 91 if (self) { | 82 if (self) { |
| 92 _blockPopups = YES; | 83 _blockPopups = YES; |
| 93 } | 84 } |
| 94 return self; | 85 return self; |
| 95 } | 86 } |
| 96 | 87 |
| 97 - (CRWWebController*)webPageOrderedOpen { | 88 - (CRWWebController*)webController:(CRWWebController*)webController |
| 98 static_cast<webPageOrderedOpenBlankBlockType>([self blockForSelector:_cmd])(); | 89 createWebControllerForURL:(const GURL&)childURL |
| 99 return _childWebController; | 90 openerURL:(const GURL&)openerURL |
| 100 } | 91 initiatedByUser:(BOOL)initiatedByUser { |
| 92 _webController = webController; |
| 93 _childURL = childURL; |
| 94 _openerURL = openerURL; |
| 95 _initiatedByUser = initiatedByUser; |
| 101 | 96 |
| 102 - (CRWWebController*)webPageOrderedOpen:(const GURL&)url | 97 return (_blockPopups && !initiatedByUser) ? nil : _childWebController; |
| 103 referrer:(const web::Referrer&)referrer | |
| 104 windowName:(NSString*)windowName | |
| 105 inBackground:(BOOL)inBackground { | |
| 106 static_cast<webPageOrderedOpenBlockType>([self blockForSelector:_cmd])( | |
| 107 url, referrer, windowName, inBackground); | |
| 108 return _childWebController; | |
| 109 } | 98 } |
| 110 | 99 |
| 111 typedef BOOL (^openExternalURLBlockType)(const GURL&); | 100 typedef BOOL (^openExternalURLBlockType)(const GURL&); |
| 112 | 101 |
| 113 - (BOOL)openExternalURL:(const GURL&)url { | 102 - (BOOL)openExternalURL:(const GURL&)url { |
| 114 return static_cast<openExternalURLBlockType>([self blockForSelector:_cmd])( | 103 return static_cast<openExternalURLBlockType>([self blockForSelector:_cmd])( |
| 115 url); | 104 url); |
| 116 } | 105 } |
| 117 | 106 |
| 118 - (BOOL)webController:(CRWWebController*)webController | 107 - (BOOL)webController:(CRWWebController*)webController |
| 119 shouldBlockPopupWithURL:(const GURL&)popupURL | |
| 120 sourceURL:(const GURL&)sourceURL { | |
| 121 self.popupURL = popupURL; | |
| 122 self.sourceURL = sourceURL; | |
| 123 return _blockPopups; | |
| 124 } | |
| 125 | |
| 126 - (void)webController:(CRWWebController*)webController | |
| 127 didBlockPopup:(const web::BlockedPopupInfo&)blockedPopupInfo { | |
| 128 _blockedPopupInfo.reset(new web::BlockedPopupInfo(blockedPopupInfo)); | |
| 129 } | |
| 130 | |
| 131 - (web::BlockedPopupInfo*)blockedPopupInfo { | |
| 132 return _blockedPopupInfo.get(); | |
| 133 } | |
| 134 - (BOOL)webController:(CRWWebController*)webController | |
| 135 shouldOpenURL:(const GURL&)URL | 108 shouldOpenURL:(const GURL&)URL |
| 136 mainDocumentURL:(const GURL&)mainDocumentURL | 109 mainDocumentURL:(const GURL&)mainDocumentURL |
| 137 linkClicked:(BOOL)linkClicked { | 110 linkClicked:(BOOL)linkClicked { |
| 138 return YES; | 111 return YES; |
| 139 } | 112 } |
| 140 @end | 113 @end |
| 141 | 114 |
| 142 @interface CountingObserver : NSObject<CRWWebControllerObserver> | 115 @interface CountingObserver : NSObject<CRWWebControllerObserver> |
| 143 | 116 |
| 144 @property(nonatomic, readonly) int pageLoadedCount; | 117 @property(nonatomic, readonly) int pageLoadedCount; |
| (...skipping 762 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 907 [delegate_ setChildWebController:child_web_state_->GetWebController()]; | 880 [delegate_ setChildWebController:child_web_state_->GetWebController()]; |
| 908 | 881 |
| 909 // Configure child web controller's session controller mock. | 882 // Configure child web controller's session controller mock. |
| 910 id sessionController = | 883 id sessionController = |
| 911 [OCMockObject niceMockForClass:[CRWSessionController class]]; | 884 [OCMockObject niceMockForClass:[CRWSessionController class]]; |
| 912 BOOL yes = YES; | 885 BOOL yes = YES; |
| 913 [[[sessionController stub] andReturnValue:OCMOCK_VALUE(yes)] isOpenedByDOM]; | 886 [[[sessionController stub] andReturnValue:OCMOCK_VALUE(yes)] isOpenedByDOM]; |
| 914 child_web_state_->GetNavigationManagerImpl().SetSessionController( | 887 child_web_state_->GetNavigationManagerImpl().SetSessionController( |
| 915 sessionController); | 888 sessionController); |
| 916 | 889 |
| 917 LoadHtml(@"<html><body></body></html>"); | 890 LoadHtml(@"<html><body></body></html>", GURL("http://test")); |
| 918 } | 891 } |
| 919 void TearDown() override { | 892 void TearDown() override { |
| 920 EXPECT_OCMOCK_VERIFY(delegate_); | 893 EXPECT_OCMOCK_VERIFY(delegate_); |
| 921 [web_controller() setDelegate:nil]; | 894 [web_controller() setDelegate:nil]; |
| 922 | 895 |
| 923 web::WebTestWithWebController::TearDown(); | 896 web::WebTestWithWebController::TearDown(); |
| 924 } | 897 } |
| 925 // Executes JavaScript that opens a new window and returns evaluation result | 898 // Executes JavaScript that opens a new window and returns evaluation result |
| 926 // as a string. | 899 // as a string. |
| 927 id OpenWindowByDOM() { | 900 id OpenWindowByDOM() { |
| 928 NSString* const kOpenWindowScript = | 901 NSString* const kOpenWindowScript = |
| 929 @"var w = window.open('javascript:void(0);', target='_blank');" | 902 @"var w = window.open('javascript:void(0);', target='_blank');" |
| 930 "w ? w.toString() : null;"; | 903 "w ? w.toString() : null;"; |
| 931 id windowJSObject = ExecuteJavaScript(kOpenWindowScript); | 904 id windowJSObject = ExecuteJavaScript(kOpenWindowScript); |
| 932 WaitForBackgroundTasks(); | 905 WaitForBackgroundTasks(); |
| 933 return windowJSObject; | 906 return windowJSObject; |
| 934 } | 907 } |
| 935 // A CRWWebDelegate mock used for testing. | 908 // A CRWWebDelegate mock used for testing. |
| 936 base::scoped_nsobject<id> delegate_; | 909 base::scoped_nsobject<id> delegate_; |
| 937 // A child WebState used for testing. | 910 // A child WebState used for testing. |
| 938 std::unique_ptr<web::WebStateImpl> child_web_state_; | 911 std::unique_ptr<web::WebStateImpl> child_web_state_; |
| 939 }; | 912 }; |
| 940 | 913 |
| 941 // Tests that absence of web delegate is handled gracefully. | 914 // Tests that absence of web delegate is handled gracefully. |
| 942 TEST_F(CRWWebControllerWindowOpenTest, NoDelegate) { | 915 TEST_F(CRWWebControllerWindowOpenTest, NoDelegate) { |
| 943 [web_controller() setDelegate:nil]; | 916 [web_controller() setDelegate:nil]; |
| 944 | 917 |
| 945 EXPECT_NSEQ([NSNull null], OpenWindowByDOM()); | 918 EXPECT_NSEQ([NSNull null], OpenWindowByDOM()); |
| 946 | 919 |
| 947 EXPECT_FALSE([delegate_ blockedPopupInfo]); | 920 EXPECT_FALSE([delegate_ webController]); |
| 921 EXPECT_FALSE([delegate_ childURL].is_valid()); |
| 922 EXPECT_FALSE([delegate_ openerURL].is_valid()); |
| 923 EXPECT_FALSE([delegate_ initiatedByUser]); |
| 948 } | 924 } |
| 949 | 925 |
| 950 // Tests that window.open triggered by user gesture opens a new non-popup | 926 // Tests that window.open triggered by user gesture opens a new non-popup |
| 951 // window. | 927 // window. |
| 952 TEST_F(CRWWebControllerWindowOpenTest, OpenWithUserGesture) { | 928 TEST_F(CRWWebControllerWindowOpenTest, OpenWithUserGesture) { |
| 953 SEL selector = @selector(webPageOrderedOpen); | |
| 954 [delegate_ onSelector:selector | |
| 955 callBlockExpectation:^(){ | |
| 956 }]; | |
| 957 | |
| 958 [web_controller() touched:YES]; | 929 [web_controller() touched:YES]; |
| 959 EXPECT_NSEQ(@"[object Window]", OpenWindowByDOM()); | 930 EXPECT_NSEQ(@"[object Window]", OpenWindowByDOM()); |
| 960 EXPECT_FALSE([delegate_ blockedPopupInfo]); | 931 |
| 932 EXPECT_EQ(web_controller(), [delegate_ webController]); |
| 933 EXPECT_EQ("javascript:void(0);", [delegate_ childURL].spec()); |
| 934 EXPECT_EQ("http://test/", [delegate_ openerURL].spec()); |
| 935 EXPECT_TRUE([delegate_ initiatedByUser]); |
| 961 } | 936 } |
| 962 | 937 |
| 963 // Tests that window.open executed w/o user gesture does not open a new window. | 938 // Tests that window.open executed w/o user gesture does not open a new window. |
| 964 // Once the blocked popup is allowed a new window is opened. | 939 // Once the blocked popup is allowed a new window is opened. |
| 965 TEST_F(CRWWebControllerWindowOpenTest, AllowPopup) { | 940 TEST_F(CRWWebControllerWindowOpenTest, AllowPopup) { |
| 966 SEL selector = | |
| 967 @selector(webPageOrderedOpen:referrer:windowName:inBackground:); | |
| 968 [delegate_ onSelector:selector | |
| 969 callBlockExpectation:^(const GURL& new_window_url, | |
| 970 const web::Referrer& referrer, | |
| 971 NSString* obsoleted_window_name, | |
| 972 BOOL in_background) { | |
| 973 EXPECT_EQ("javascript:void(0);", new_window_url.spec()); | |
| 974 EXPECT_EQ("", referrer.url.spec()); | |
| 975 EXPECT_FALSE(in_background); | |
| 976 }]; | |
| 977 | |
| 978 ASSERT_FALSE([web_controller() userIsInteracting]); | 941 ASSERT_FALSE([web_controller() userIsInteracting]); |
| 979 EXPECT_NSEQ([NSNull null], OpenWindowByDOM()); | 942 EXPECT_NSEQ([NSNull null], OpenWindowByDOM()); |
| 980 base::test::ios::WaitUntilCondition(^bool() { | |
| 981 return [delegate_ blockedPopupInfo]; | |
| 982 }); | |
| 983 | 943 |
| 984 if ([delegate_ blockedPopupInfo]) | 944 EXPECT_EQ(web_controller(), [delegate_ webController]); |
| 985 [delegate_ blockedPopupInfo]->ShowPopup(); | 945 EXPECT_EQ("javascript:void(0);", [delegate_ childURL].spec()); |
| 986 | 946 EXPECT_EQ("http://test/", [delegate_ openerURL].spec()); |
| 987 EXPECT_EQ("", [delegate_ sourceURL].spec()); | 947 EXPECT_FALSE([delegate_ initiatedByUser]); |
| 988 EXPECT_EQ("javascript:void(0);", [delegate_ popupURL].spec()); | |
| 989 } | 948 } |
| 990 | 949 |
| 991 // Tests that window.open executed w/o user gesture opens a new window, assuming | 950 // Tests that window.open executed w/o user gesture opens a new window, assuming |
| 992 // that delegate allows popups. | 951 // that delegate allows popups. |
| 993 TEST_F(CRWWebControllerWindowOpenTest, DontBlockPopup) { | 952 TEST_F(CRWWebControllerWindowOpenTest, DontBlockPopup) { |
| 994 [delegate_ setBlockPopups:NO]; | 953 [delegate_ setBlockPopups:NO]; |
| 995 SEL selector = @selector(webPageOrderedOpen); | 954 EXPECT_NSEQ(@"[object Window]", OpenWindowByDOM()); |
| 996 [delegate_ onSelector:selector | |
| 997 callBlockExpectation:^(){ | |
| 998 }]; | |
| 999 | 955 |
| 1000 EXPECT_NSEQ(@"[object Window]", OpenWindowByDOM()); | 956 EXPECT_EQ(web_controller(), [delegate_ webController]); |
| 1001 EXPECT_FALSE([delegate_ blockedPopupInfo]); | 957 EXPECT_EQ("javascript:void(0);", [delegate_ childURL].spec()); |
| 1002 | 958 EXPECT_EQ("http://test/", [delegate_ openerURL].spec()); |
| 1003 EXPECT_EQ("", [delegate_ sourceURL].spec()); | 959 EXPECT_FALSE([delegate_ initiatedByUser]); |
| 1004 EXPECT_EQ("javascript:void(0);", [delegate_ popupURL].spec()); | |
| 1005 } | 960 } |
| 1006 | 961 |
| 1007 // Tests that window.open executed w/o user gesture does not open a new window. | 962 // Tests that window.open executed w/o user gesture does not open a new window. |
| 1008 TEST_F(CRWWebControllerWindowOpenTest, BlockPopup) { | 963 TEST_F(CRWWebControllerWindowOpenTest, BlockPopup) { |
| 1009 ASSERT_FALSE([web_controller() userIsInteracting]); | 964 ASSERT_FALSE([web_controller() userIsInteracting]); |
| 1010 EXPECT_NSEQ([NSNull null], OpenWindowByDOM()); | 965 EXPECT_NSEQ([NSNull null], OpenWindowByDOM()); |
| 1011 base::test::ios::WaitUntilCondition(^bool() { | |
| 1012 return [delegate_ blockedPopupInfo]; | |
| 1013 }); | |
| 1014 | 966 |
| 1015 EXPECT_EQ("", [delegate_ sourceURL].spec()); | 967 EXPECT_EQ(web_controller(), [delegate_ webController]); |
| 1016 EXPECT_EQ("javascript:void(0);", [delegate_ popupURL].spec()); | 968 EXPECT_EQ("javascript:void(0);", [delegate_ childURL].spec()); |
| 969 EXPECT_EQ("http://test/", [delegate_ openerURL].spec()); |
| 970 EXPECT_FALSE([delegate_ initiatedByUser]); |
| 1017 }; | 971 }; |
| 1018 | 972 |
| 1019 // Fixture class to test WKWebView crashes. | 973 // Fixture class to test WKWebView crashes. |
| 1020 class CRWWebControllerWebProcessTest : public web::WebTestWithWebController { | 974 class CRWWebControllerWebProcessTest : public web::WebTestWithWebController { |
| 1021 protected: | 975 protected: |
| 1022 void SetUp() override { | 976 void SetUp() override { |
| 1023 web::WebTestWithWebController::SetUp(); | 977 web::WebTestWithWebController::SetUp(); |
| 1024 webView_.reset([web::BuildTerminatedWKWebView() retain]); | 978 webView_.reset([web::BuildTerminatedWKWebView() retain]); |
| 1025 base::scoped_nsobject<TestWebViewContentView> webViewContentView( | 979 base::scoped_nsobject<TestWebViewContentView> webViewContentView( |
| 1026 [[TestWebViewContentView alloc] | 980 [[TestWebViewContentView alloc] |
| (...skipping 28 matching lines...) Expand all Loading... |
| 1055 }; | 1009 }; |
| 1056 | 1010 |
| 1057 RenderProcessGoneObserver observer(web_state()); | 1011 RenderProcessGoneObserver observer(web_state()); |
| 1058 web::SimulateWKWebViewCrash(webView_); | 1012 web::SimulateWKWebViewCrash(webView_); |
| 1059 observer.WaitForRenderProcessGone(); | 1013 observer.WaitForRenderProcessGone(); |
| 1060 | 1014 |
| 1061 EXPECT_FALSE([web_controller() isViewAlive]); | 1015 EXPECT_FALSE([web_controller() isViewAlive]); |
| 1062 }; | 1016 }; |
| 1063 | 1017 |
| 1064 } // namespace | 1018 } // namespace |
| OLD | NEW |