OLD | NEW |
1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 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 "content/browser/frame_host/render_frame_host_impl.h" | 5 #include "content/browser/frame_host/render_frame_host_impl.h" |
6 | 6 |
7 #include "base/macros.h" | 7 #include "base/macros.h" |
8 #include "content/browser/web_contents/web_contents_impl.h" | 8 #include "content/browser/web_contents/web_contents_impl.h" |
| 9 #include "content/common/frame_messages.h" |
| 10 #include "content/public/browser/javascript_dialog_manager.h" |
9 #include "content/public/browser/render_frame_host.h" | 11 #include "content/public/browser/render_frame_host.h" |
10 #include "content/public/browser/web_contents.h" | 12 #include "content/public/browser/web_contents.h" |
11 #include "content/public/common/content_client.h" | 13 #include "content/public/common/content_client.h" |
| 14 #include "content/public/test/browser_test_utils.h" |
12 #include "content/public/test/content_browser_test.h" | 15 #include "content/public/test/content_browser_test.h" |
13 #include "content/public/test/content_browser_test_utils.h" | 16 #include "content/public/test/content_browser_test_utils.h" |
14 #include "content/public/test/test_utils.h" | 17 #include "content/public/test/test_utils.h" |
15 #include "content/shell/browser/shell.h" | 18 #include "content/shell/browser/shell.h" |
16 #include "content/test/test_content_browser_client.h" | 19 #include "content/test/test_content_browser_client.h" |
17 | 20 |
18 namespace content { | 21 namespace content { |
19 | 22 |
20 namespace { | 23 namespace { |
21 | 24 |
(...skipping 127 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
149 EXPECT_EQ(blink::WebPageVisibilityStateVisible, | 152 EXPECT_EQ(blink::WebPageVisibilityStateVisible, |
150 web_contents->GetMainFrame()->GetVisibilityState()); | 153 web_contents->GetMainFrame()->GetVisibilityState()); |
151 | 154 |
152 new_client.EnableVisibilityOverride(blink::WebPageVisibilityStatePrerender); | 155 new_client.EnableVisibilityOverride(blink::WebPageVisibilityStatePrerender); |
153 EXPECT_EQ(blink::WebPageVisibilityStatePrerender, | 156 EXPECT_EQ(blink::WebPageVisibilityStatePrerender, |
154 web_contents->GetMainFrame()->GetVisibilityState()); | 157 web_contents->GetMainFrame()->GetVisibilityState()); |
155 | 158 |
156 SetBrowserClientForTesting(old_client); | 159 SetBrowserClientForTesting(old_client); |
157 } | 160 } |
158 | 161 |
| 162 namespace { |
| 163 |
| 164 class TestJavaScriptDialogManager : public JavaScriptDialogManager, |
| 165 public WebContentsDelegate { |
| 166 public: |
| 167 TestJavaScriptDialogManager() : message_loop_runner_(new MessageLoopRunner) {} |
| 168 ~TestJavaScriptDialogManager() override {} |
| 169 |
| 170 void Wait() { |
| 171 message_loop_runner_->Run(); |
| 172 message_loop_runner_ = new MessageLoopRunner; |
| 173 } |
| 174 |
| 175 DialogClosedCallback& callback() { return callback_; } |
| 176 |
| 177 // WebContentsDelegate |
| 178 |
| 179 JavaScriptDialogManager* GetJavaScriptDialogManager( |
| 180 WebContents* source) override { |
| 181 return this; |
| 182 } |
| 183 |
| 184 // JavaScriptDialogManager |
| 185 |
| 186 void RunJavaScriptDialog(WebContents* web_contents, |
| 187 const GURL& origin_url, |
| 188 JavaScriptDialogType dialog_type, |
| 189 const base::string16& message_text, |
| 190 const base::string16& default_prompt_text, |
| 191 const DialogClosedCallback& callback, |
| 192 bool* did_suppress_message) override {} |
| 193 |
| 194 void RunBeforeUnloadDialog(WebContents* web_contents, |
| 195 bool is_reload, |
| 196 const DialogClosedCallback& callback) override { |
| 197 callback_ = callback; |
| 198 message_loop_runner_->Quit(); |
| 199 } |
| 200 |
| 201 bool HandleJavaScriptDialog(WebContents* web_contents, |
| 202 bool accept, |
| 203 const base::string16* prompt_override) override { |
| 204 return true; |
| 205 } |
| 206 |
| 207 void CancelDialogs(WebContents* web_contents, bool reset_state) override {} |
| 208 |
| 209 private: |
| 210 DialogClosedCallback callback_; |
| 211 |
| 212 // The MessageLoopRunner used to spin the message loop. |
| 213 scoped_refptr<MessageLoopRunner> message_loop_runner_; |
| 214 |
| 215 DISALLOW_COPY_AND_ASSIGN(TestJavaScriptDialogManager); |
| 216 }; |
| 217 |
| 218 class DropBeforeUnloadACKFilter : public BrowserMessageFilter { |
| 219 public: |
| 220 DropBeforeUnloadACKFilter() : BrowserMessageFilter(FrameMsgStart) {} |
| 221 |
| 222 protected: |
| 223 ~DropBeforeUnloadACKFilter() override {} |
| 224 |
| 225 private: |
| 226 // BrowserMessageFilter: |
| 227 bool OnMessageReceived(const IPC::Message& message) override { |
| 228 return message.type() == FrameHostMsg_BeforeUnload_ACK::ID; |
| 229 } |
| 230 |
| 231 DISALLOW_COPY_AND_ASSIGN(DropBeforeUnloadACKFilter); |
| 232 }; |
| 233 |
| 234 } // namespace |
| 235 |
| 236 // Tests that a beforeunload dialog in an iframe doesn't stop the beforeunload |
| 237 // timer of a parent frame. |
| 238 IN_PROC_BROWSER_TEST_F(RenderFrameHostImplBrowserTest, |
| 239 IframeBeforeUnloadParentHang) { |
| 240 WebContentsImpl* wc = static_cast<WebContentsImpl*>(shell()->web_contents()); |
| 241 TestJavaScriptDialogManager dialog_manager; |
| 242 wc->SetDelegate(&dialog_manager); |
| 243 |
| 244 EXPECT_TRUE(NavigateToURL(shell(), GURL("about:blank"))); |
| 245 // Make an iframe with a beforeunload handler. |
| 246 std::string script = |
| 247 "var iframe = document.createElement('iframe');" |
| 248 "document.body.appendChild(iframe);" |
| 249 "iframe.contentWindow.onbeforeunload=function(e){return 'x'};"; |
| 250 EXPECT_TRUE(content::ExecuteScript(wc, script)); |
| 251 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents())); |
| 252 |
| 253 // Force a process switch by going to a privileged page. The beforeunload |
| 254 // timer will be started on the top-level frame but will be paused while the |
| 255 // beforeunload dialog is shown by the subframe. |
| 256 GURL web_ui_page(std::string(kChromeUIScheme) + "://" + |
| 257 std::string(kChromeUIGpuHost)); |
| 258 shell()->LoadURL(web_ui_page); |
| 259 dialog_manager.Wait(); |
| 260 |
| 261 RenderFrameHostImpl* main_frame = |
| 262 static_cast<RenderFrameHostImpl*>(wc->GetMainFrame()); |
| 263 EXPECT_TRUE(main_frame->is_waiting_for_beforeunload_ack()); |
| 264 |
| 265 // Set up a filter to make sure that when the dialog is answered below and the |
| 266 // renderer sends the beforeunload ACK, it gets... ahem... lost. |
| 267 scoped_refptr<DropBeforeUnloadACKFilter> filter = |
| 268 new DropBeforeUnloadACKFilter(); |
| 269 main_frame->GetProcess()->AddFilter(filter.get()); |
| 270 |
| 271 // Answer the dialog. |
| 272 dialog_manager.callback().Run(true, base::string16()); |
| 273 |
| 274 // There will be no beforeunload ACK, so if the beforeunload ACK timer isn't |
| 275 // functioning then the navigation will hang forever and this test will time |
| 276 // out. If this waiting for the load stop works, this test won't time out. |
| 277 EXPECT_TRUE(WaitForLoadStop(wc)); |
| 278 EXPECT_EQ(web_ui_page, wc->GetLastCommittedURL()); |
| 279 |
| 280 wc->SetDelegate(nullptr); |
| 281 wc->SetJavaScriptDialogManagerForTesting(nullptr); |
| 282 } |
| 283 |
159 } // namespace content | 284 } // namespace content |
OLD | NEW |