| OLD | NEW |
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 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 #include "base/macros.h" | 5 #include "base/macros.h" |
| 6 #include "base/run_loop.h" | 6 #include "base/run_loop.h" |
| 7 #include "base/strings/pattern.h" | 7 #include "base/strings/pattern.h" |
| 8 #include "base/strings/utf_string_conversions.h" | 8 #include "base/strings/utf_string_conversions.h" |
| 9 #include "base/values.h" | 9 #include "base/values.h" |
| 10 #include "build/build_config.h" | 10 #include "build/build_config.h" |
| (...skipping 921 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 932 WaitForAppModalDialog(shell()); | 932 WaitForAppModalDialog(shell()); |
| 933 | 933 |
| 934 // Have the cross-site navigation commit. The main RenderFrameHost should | 934 // Have the cross-site navigation commit. The main RenderFrameHost should |
| 935 // still be loading after that. | 935 // still be loading after that. |
| 936 cross_site_delayer.WaitForNavigationFinished(); | 936 cross_site_delayer.WaitForNavigationFinished(); |
| 937 EXPECT_TRUE(shell()->web_contents()->IsLoading()); | 937 EXPECT_TRUE(shell()->web_contents()->IsLoading()); |
| 938 } | 938 } |
| 939 | 939 |
| 940 namespace { | 940 namespace { |
| 941 | 941 |
| 942 // Test implementation of WebContentsDelegate that handles and automatically | |
| 943 // cancels beforeunload dialogs. This class also listens for | |
| 944 // NavigationStateChanged(INVALIDATE_TYPE_URL) and records the state of | |
| 945 // GetVisibleURL(). | |
| 946 class DialogDismissingWebContentsDelegate : public JavaScriptDialogManager, | |
| 947 public WebContentsDelegate { | |
| 948 public: | |
| 949 DialogDismissingWebContentsDelegate() | |
| 950 : message_loop_runner_(new MessageLoopRunner) {} | |
| 951 ~DialogDismissingWebContentsDelegate() override {} | |
| 952 | |
| 953 void WaitForDialogDismissed() { | |
| 954 message_loop_runner_->Run(); | |
| 955 message_loop_runner_ = new MessageLoopRunner; | |
| 956 } | |
| 957 | |
| 958 // The recent of values of web_contents()->GetVisibleURL(), recorded each time | |
| 959 // this WebContentsDelegate gets an INVALIDATE_TYPE_URL event. | |
| 960 std::vector<GURL> GetAndClearVisibleUrlInvalidations() { | |
| 961 return std::move(visible_url_invalidations_); | |
| 962 } | |
| 963 | |
| 964 // WebContentsDelegate | |
| 965 | |
| 966 JavaScriptDialogManager* GetJavaScriptDialogManager( | |
| 967 WebContents* source) override { | |
| 968 return this; | |
| 969 } | |
| 970 void NavigationStateChanged(WebContents* web_contents, | |
| 971 InvalidateTypes invalidate_types) override { | |
| 972 if (invalidate_types & INVALIDATE_TYPE_URL) { | |
| 973 visible_url_invalidations_.push_back(web_contents->GetVisibleURL()); | |
| 974 } | |
| 975 } | |
| 976 | |
| 977 // JavaScriptDialogManager | |
| 978 | |
| 979 void RunJavaScriptDialog(WebContents* web_contents, | |
| 980 const GURL& origin_url, | |
| 981 JavaScriptDialogType dialog_type, | |
| 982 const base::string16& message_text, | |
| 983 const base::string16& default_prompt_text, | |
| 984 const DialogClosedCallback& callback, | |
| 985 bool* did_suppress_message) override {} | |
| 986 | |
| 987 void RunBeforeUnloadDialog(WebContents* web_contents, | |
| 988 bool is_reload, | |
| 989 const DialogClosedCallback& callback) override { | |
| 990 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, | |
| 991 base::Bind(callback, false, base::string16())); | |
| 992 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, | |
| 993 message_loop_runner_->QuitClosure()); | |
| 994 } | |
| 995 | |
| 996 bool HandleJavaScriptDialog(WebContents* web_contents, | |
| 997 bool accept, | |
| 998 const base::string16* prompt_override) override { | |
| 999 return true; | |
| 1000 } | |
| 1001 | |
| 1002 void CancelDialogs(WebContents* web_contents, bool reset_state) override {} | |
| 1003 | |
| 1004 private: | |
| 1005 std::vector<GURL> visible_url_invalidations_; | |
| 1006 | |
| 1007 // The MessageLoopRunner used to spin the message loop. | |
| 1008 scoped_refptr<MessageLoopRunner> message_loop_runner_; | |
| 1009 | |
| 1010 DISALLOW_COPY_AND_ASSIGN(DialogDismissingWebContentsDelegate); | |
| 1011 }; | |
| 1012 | |
| 1013 } // namespace | |
| 1014 | |
| 1015 // Test that if a BeforeUnload dialog is destroyed due to the commit of a | |
| 1016 // same-site or cross-site navigation, it will not reset the loading state. | |
| 1017 IN_PROC_BROWSER_TEST_F(WebContentsImplBrowserTest, | |
| 1018 DismissingBeforeUnloadDialogInvalidatesUrl) { | |
| 1019 ASSERT_TRUE(embedded_test_server()->Start()); | |
| 1020 const GURL kStartURL(embedded_test_server()->GetURL( | |
| 1021 "foo.com", "/render_frame_host/beforeunload.html")); | |
| 1022 const GURL kSameSiteURL( | |
| 1023 embedded_test_server()->GetURL("foo.com", "/title1.html")); | |
| 1024 const GURL kCrossSiteURL( | |
| 1025 embedded_test_server()->GetURL("bar.com", "/title1.html")); | |
| 1026 | |
| 1027 // Navigate to a first web page with a BeforeUnload event listener. | |
| 1028 EXPECT_TRUE(NavigateToURL(shell(), kStartURL)); | |
| 1029 | |
| 1030 DialogDismissingWebContentsDelegate web_contents_delegate; | |
| 1031 shell()->web_contents()->SetDelegate(&web_contents_delegate); | |
| 1032 PrepContentsForBeforeUnloadTest(shell()->web_contents()); | |
| 1033 | |
| 1034 // Start a same-site navigation that is cancelled because of the beforeunload | |
| 1035 // dialog. INVALIDATE_TYPE_URL should be sent to the delegate after the | |
| 1036 // cancellation, so that the location bar resets to the original URL. | |
| 1037 shell()->LoadURL(kSameSiteURL); | |
| 1038 EXPECT_EQ(kSameSiteURL, shell()->web_contents()->GetVisibleURL()); | |
| 1039 web_contents_delegate.WaitForDialogDismissed(); | |
| 1040 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents())); | |
| 1041 EXPECT_EQ(std::vector<GURL>{kStartURL}, | |
| 1042 web_contents_delegate.GetAndClearVisibleUrlInvalidations()); | |
| 1043 | |
| 1044 // Start a cross-site navigation that is cancelled because of the beforeunload | |
| 1045 // dialog. INVALIDATE_TYPE_URL should be sent to the delegate after the | |
| 1046 // cancellation, so that the location bar resets to the original URL. | |
| 1047 shell()->LoadURL(kCrossSiteURL); | |
| 1048 EXPECT_EQ(kCrossSiteURL, shell()->web_contents()->GetVisibleURL()); | |
| 1049 web_contents_delegate.WaitForDialogDismissed(); | |
| 1050 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents())); | |
| 1051 EXPECT_EQ(std::vector<GURL>{kStartURL}, | |
| 1052 web_contents_delegate.GetAndClearVisibleUrlInvalidations()); | |
| 1053 | |
| 1054 // Now clear the unload handler and re-try the navigations, which should now | |
| 1055 // succeed. INVALIDATE_TYPE_URL should happen on commit, with the value of the | |
| 1056 // new URL. | |
| 1057 EXPECT_TRUE(ExecuteScript(shell(), | |
| 1058 "window.onbeforeunload=function(e){return null;}")); | |
| 1059 shell()->LoadURL(kSameSiteURL); | |
| 1060 EXPECT_EQ(kSameSiteURL, shell()->web_contents()->GetVisibleURL()); | |
| 1061 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents())); | |
| 1062 EXPECT_EQ(kSameSiteURL, shell()->web_contents()->GetVisibleURL()); | |
| 1063 EXPECT_EQ(std::vector<GURL>{kSameSiteURL}, | |
| 1064 web_contents_delegate.GetAndClearVisibleUrlInvalidations()); | |
| 1065 | |
| 1066 shell()->LoadURL(kCrossSiteURL); | |
| 1067 EXPECT_EQ(kCrossSiteURL, shell()->web_contents()->GetVisibleURL()); | |
| 1068 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents())); | |
| 1069 EXPECT_EQ(kCrossSiteURL, shell()->web_contents()->GetVisibleURL()); | |
| 1070 EXPECT_EQ(std::vector<GURL>{kCrossSiteURL}, | |
| 1071 web_contents_delegate.GetAndClearVisibleUrlInvalidations()); | |
| 1072 | |
| 1073 // Clear the test delegates. | |
| 1074 static_cast<WebContentsImpl*>(shell()->web_contents()) | |
| 1075 ->SetJavaScriptDialogManagerForTesting(nullptr); | |
| 1076 shell()->web_contents()->SetDelegate(shell()); | |
| 1077 } | |
| 1078 | |
| 1079 namespace { | |
| 1080 | |
| 1081 class TestJavaScriptDialogManager : public JavaScriptDialogManager, | 942 class TestJavaScriptDialogManager : public JavaScriptDialogManager, |
| 1082 public WebContentsDelegate { | 943 public WebContentsDelegate { |
| 1083 public: | 944 public: |
| 1084 TestJavaScriptDialogManager() | 945 TestJavaScriptDialogManager() |
| 1085 : is_fullscreen_(false), message_loop_runner_(new MessageLoopRunner) {} | 946 : is_fullscreen_(false), message_loop_runner_(new MessageLoopRunner) {} |
| 1086 ~TestJavaScriptDialogManager() override {} | 947 ~TestJavaScriptDialogManager() override {} |
| 1087 | 948 |
| 1088 void Wait() { | 949 void Wait() { |
| 1089 message_loop_runner_->Run(); | 950 message_loop_runner_->Run(); |
| 1090 message_loop_runner_ = new MessageLoopRunner; | 951 message_loop_runner_ = new MessageLoopRunner; |
| (...skipping 509 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1600 EXPECT_TRUE(content::ExecuteScript(wc, script)); | 1461 EXPECT_TRUE(content::ExecuteScript(wc, script)); |
| 1601 EXPECT_TRUE(NavigateToURL(shell(), url)); | 1462 EXPECT_TRUE(NavigateToURL(shell(), url)); |
| 1602 dialog_manager.Wait(); | 1463 dialog_manager.Wait(); |
| 1603 EXPECT_FALSE(wc->IsFullscreenForCurrentTab()); | 1464 EXPECT_FALSE(wc->IsFullscreenForCurrentTab()); |
| 1604 | 1465 |
| 1605 wc->SetDelegate(nullptr); | 1466 wc->SetDelegate(nullptr); |
| 1606 wc->SetJavaScriptDialogManagerForTesting(nullptr); | 1467 wc->SetJavaScriptDialogManagerForTesting(nullptr); |
| 1607 } | 1468 } |
| 1608 | 1469 |
| 1609 } // namespace content | 1470 } // namespace content |
| OLD | NEW |