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" | |
11 #include "content/public/browser/render_frame_host.h" | 9 #include "content/public/browser/render_frame_host.h" |
12 #include "content/public/browser/web_contents.h" | 10 #include "content/public/browser/web_contents.h" |
13 #include "content/public/common/content_client.h" | 11 #include "content/public/common/content_client.h" |
14 #include "content/public/test/browser_test_utils.h" | |
15 #include "content/public/test/content_browser_test.h" | 12 #include "content/public/test/content_browser_test.h" |
16 #include "content/public/test/content_browser_test_utils.h" | 13 #include "content/public/test/content_browser_test_utils.h" |
17 #include "content/public/test/test_utils.h" | 14 #include "content/public/test/test_utils.h" |
18 #include "content/shell/browser/shell.h" | 15 #include "content/shell/browser/shell.h" |
19 #include "content/test/test_content_browser_client.h" | 16 #include "content/test/test_content_browser_client.h" |
20 | 17 |
21 namespace content { | 18 namespace content { |
22 | 19 |
23 namespace { | 20 namespace { |
24 | 21 |
(...skipping 127 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
152 EXPECT_EQ(blink::WebPageVisibilityStateVisible, | 149 EXPECT_EQ(blink::WebPageVisibilityStateVisible, |
153 web_contents->GetMainFrame()->GetVisibilityState()); | 150 web_contents->GetMainFrame()->GetVisibilityState()); |
154 | 151 |
155 new_client.EnableVisibilityOverride(blink::WebPageVisibilityStatePrerender); | 152 new_client.EnableVisibilityOverride(blink::WebPageVisibilityStatePrerender); |
156 EXPECT_EQ(blink::WebPageVisibilityStatePrerender, | 153 EXPECT_EQ(blink::WebPageVisibilityStatePrerender, |
157 web_contents->GetMainFrame()->GetVisibilityState()); | 154 web_contents->GetMainFrame()->GetVisibilityState()); |
158 | 155 |
159 SetBrowserClientForTesting(old_client); | 156 SetBrowserClientForTesting(old_client); |
160 } | 157 } |
161 | 158 |
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 | |
284 } // namespace content | 159 } // namespace content |
OLD | NEW |