OLD | NEW |
1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2006-2008 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 "chrome/browser/interstitial_page.h" | 5 #include "chrome/browser/interstitial_page.h" |
6 | 6 |
7 #include "chrome/browser/browser.h" | 7 #include "chrome/browser/browser.h" |
8 #include "chrome/browser/browser_list.h" | 8 #include "chrome/browser/browser_list.h" |
9 #include "chrome/browser/browser_resources.h" | 9 #include "chrome/browser/browser_resources.h" |
10 #include "chrome/browser/dom_operation_notification_details.h" | 10 #include "chrome/browser/dom_operation_notification_details.h" |
11 #include "chrome/browser/navigation_controller.h" | 11 #include "chrome/browser/navigation_controller.h" |
12 #include "chrome/browser/navigation_entry.h" | 12 #include "chrome/browser/navigation_entry.h" |
13 #include "chrome/browser/render_widget_host_view_win.h" | 13 #include "chrome/browser/render_widget_host_view_win.h" |
14 #include "chrome/browser/web_contents.h" | 14 #include "chrome/browser/web_contents.h" |
15 #include "chrome/browser/web_contents_view_win.h" | 15 #include "chrome/browser/web_contents_view_win.h" |
16 #include "chrome/views/window.h" | 16 #include "chrome/views/window.h" |
17 #include "chrome/views/window_delegate.h" | 17 #include "chrome/views/window_delegate.h" |
18 #include "net/base/escape.h" | 18 #include "net/base/escape.h" |
19 | 19 |
| 20 enum ResourceRequestAction { |
| 21 BLOCK, |
| 22 RESUME, |
| 23 CANCEL |
| 24 }; |
| 25 |
| 26 namespace { |
| 27 |
| 28 class ResourceRequestTask : public Task { |
| 29 public: |
| 30 ResourceRequestTask(RenderViewHost* render_view_host, |
| 31 ResourceRequestAction action) |
| 32 : action_(action), |
| 33 process_id_(render_view_host->process()->host_id()), |
| 34 render_view_host_id_(render_view_host->routing_id()), |
| 35 resource_dispatcher_host_( |
| 36 g_browser_process->resource_dispatcher_host()) { |
| 37 } |
| 38 |
| 39 virtual void Run() { |
| 40 switch (action_) { |
| 41 case BLOCK: |
| 42 resource_dispatcher_host_->BlockRequestsForRenderView( |
| 43 process_id_, render_view_host_id_); |
| 44 break; |
| 45 case RESUME: |
| 46 resource_dispatcher_host_->ResumeBlockedRequestsForRenderView( |
| 47 process_id_, render_view_host_id_); |
| 48 break; |
| 49 case CANCEL: |
| 50 resource_dispatcher_host_->CancelBlockedRequestsForRenderView( |
| 51 process_id_, render_view_host_id_); |
| 52 break; |
| 53 default: |
| 54 NOTREACHED(); |
| 55 } |
| 56 } |
| 57 |
| 58 private: |
| 59 ResourceRequestAction action_; |
| 60 int process_id_; |
| 61 int render_view_host_id_; |
| 62 ResourceDispatcherHost* resource_dispatcher_host_; |
| 63 |
| 64 DISALLOW_COPY_AND_ASSIGN(ResourceRequestTask); |
| 65 }; |
| 66 |
| 67 } // namespace |
| 68 |
20 // static | 69 // static |
21 InterstitialPage::InterstitialPageMap* | 70 InterstitialPage::InterstitialPageMap* |
22 InterstitialPage::tab_to_interstitial_page_ = NULL; | 71 InterstitialPage::tab_to_interstitial_page_ = NULL; |
23 | 72 |
24 InterstitialPage::InterstitialPage(WebContents* tab, | 73 InterstitialPage::InterstitialPage(WebContents* tab, |
25 bool new_navigation, | 74 bool new_navigation, |
26 const GURL& url) | 75 const GURL& url) |
27 : tab_(tab), | 76 : tab_(tab), |
28 url_(url), | 77 url_(url), |
29 action_taken_(false), | 78 action_taken_(false), |
30 enabled_(true), | 79 enabled_(true), |
31 new_navigation_(new_navigation), | 80 new_navigation_(new_navigation), |
32 render_view_host_(NULL), | 81 render_view_host_(NULL), |
33 should_revert_tab_title_(false) { | 82 should_revert_tab_title_(false), |
| 83 ui_loop_(MessageLoop::current()) { |
34 InitInterstitialPageMap(); | 84 InitInterstitialPageMap(); |
35 // It would be inconsistent to create an interstitial with no new navigation | 85 // It would be inconsistent to create an interstitial with no new navigation |
36 // (which is the case when the interstitial was triggered by a sub-resource on | 86 // (which is the case when the interstitial was triggered by a sub-resource on |
37 // a page) when we have a pending entry (in the process of loading a new top | 87 // a page) when we have a pending entry (in the process of loading a new top |
38 // frame). | 88 // frame). |
39 DCHECK(new_navigation || !tab->controller()->GetPendingEntry()); | 89 DCHECK(new_navigation || !tab->controller()->GetPendingEntry()); |
40 } | 90 } |
41 | 91 |
42 InterstitialPage::~InterstitialPage() { | 92 InterstitialPage::~InterstitialPage() { |
43 InterstitialPageMap::iterator iter = tab_to_interstitial_page_->find(tab_); | 93 InterstitialPageMap::iterator iter = tab_to_interstitial_page_->find(tab_); |
44 DCHECK(iter != tab_to_interstitial_page_->end()); | 94 DCHECK(iter != tab_to_interstitial_page_->end()); |
45 tab_to_interstitial_page_->erase(iter); | 95 tab_to_interstitial_page_->erase(iter); |
46 DCHECK(!render_view_host_); | 96 DCHECK(!render_view_host_); |
47 } | 97 } |
48 | 98 |
49 void InterstitialPage::Show() { | 99 void InterstitialPage::Show() { |
50 // If an interstitial is already showing, close it before showing the new one. | 100 // If an interstitial is already showing, close it before showing the new one. |
51 if (tab_->interstitial_page()) | 101 if (tab_->interstitial_page()) |
52 tab_->interstitial_page()->DontProceed(); | 102 tab_->interstitial_page()->DontProceed(); |
53 | 103 |
| 104 // Block the resource requests for the render view host while it is hidden. |
| 105 TakeActionOnResourceDispatcher(BLOCK); |
| 106 // We need to be notified when the RenderViewHost is destroyed so we can |
| 107 // cancel the blocked requests. We cannot do that on |
| 108 // NOTIFY_TAB_CONTENTS_DESTROYED as at that point the RenderViewHost has |
| 109 // already been destroyed. |
| 110 notification_registrar_.Add( |
| 111 this, NOTIFY_RENDER_WIDGET_HOST_DESTROYED, |
| 112 Source<RenderWidgetHost>(tab_->render_view_host())); |
| 113 |
54 // Update the tab_to_interstitial_page_ map. | 114 // Update the tab_to_interstitial_page_ map. |
55 InterstitialPageMap::const_iterator iter = | 115 InterstitialPageMap::const_iterator iter = |
56 tab_to_interstitial_page_->find(tab_); | 116 tab_to_interstitial_page_->find(tab_); |
57 DCHECK(iter == tab_to_interstitial_page_->end()); | 117 DCHECK(iter == tab_to_interstitial_page_->end()); |
58 (*tab_to_interstitial_page_)[tab_] = this; | 118 (*tab_to_interstitial_page_)[tab_] = this; |
59 | 119 |
60 if (new_navigation_) { | 120 if (new_navigation_) { |
61 NavigationEntry* entry = new NavigationEntry(TAB_CONTENTS_WEB); | 121 NavigationEntry* entry = new NavigationEntry(TAB_CONTENTS_WEB); |
62 entry->set_url(url_); | 122 entry->set_url(url_); |
63 entry->set_display_url(url_); | 123 entry->set_display_url(url_); |
(...skipping 30 matching lines...) Expand all Loading... |
94 if (!new_navigation_ && should_revert_tab_title_) { | 154 if (!new_navigation_ && should_revert_tab_title_) { |
95 entry->set_title(original_tab_title_); | 155 entry->set_title(original_tab_title_); |
96 tab_->NotifyNavigationStateChanged(TabContents::INVALIDATE_TITLE); | 156 tab_->NotifyNavigationStateChanged(TabContents::INVALIDATE_TITLE); |
97 } | 157 } |
98 delete this; | 158 delete this; |
99 } | 159 } |
100 | 160 |
101 void InterstitialPage::Observe(NotificationType type, | 161 void InterstitialPage::Observe(NotificationType type, |
102 const NotificationSource& source, | 162 const NotificationSource& source, |
103 const NotificationDetails& details) { | 163 const NotificationDetails& details) { |
104 if (type == NOTIFY_NAV_ENTRY_PENDING) { | 164 switch (type) { |
105 // We are navigating away from the interstitial. Make sure clicking on the | 165 case NOTIFY_NAV_ENTRY_PENDING: |
106 // interstitial will have no effect. | 166 // We are navigating away from the interstitial. Make sure clicking on |
107 Disable(); | 167 // the interstitial will have no effect. |
108 return; | 168 Disable(); |
109 } | 169 break; |
110 DCHECK(type == NOTIFY_TAB_CONTENTS_DESTROYED || | 170 case NOTIFY_RENDER_WIDGET_HOST_DESTROYED: |
111 type == NOTIFY_NAV_ENTRY_COMMITTED); | 171 // The RenderViewHost is being destroyed (as part of the tab being closed) |
112 if (!action_taken_) { | 172 // make sure we clear the blocked requests. |
113 // We are navigating away from the interstitial or closing a tab with an | 173 DCHECK(Source<RenderViewHost>(source).ptr() == tab_->render_view_host()); |
114 // interstitial. Default to DontProceed(). We don't just call Hide as | 174 TakeActionOnResourceDispatcher(CANCEL); |
115 // subclasses will almost certainly override DontProceed to do some work | 175 break; |
116 // (ex: close pending connections). | 176 case NOTIFY_TAB_CONTENTS_DESTROYED: |
117 DontProceed(); | 177 case NOTIFY_NAV_ENTRY_COMMITTED: |
118 } else { | 178 if (!action_taken_) { |
119 // User decided to proceed and either the navigation was committed or the | 179 // We are navigating away from the interstitial or closing a tab with an |
120 // tab was closed before that. | 180 // interstitial. Default to DontProceed(). We don't just call Hide as |
121 Hide(); | 181 // subclasses will almost certainly override DontProceed to do some work |
122 // WARNING: we are now deleted! | 182 // (ex: close pending connections). |
| 183 DontProceed(); |
| 184 } else { |
| 185 // User decided to proceed and either the navigation was committed or |
| 186 // the tab was closed before that. |
| 187 Hide(); |
| 188 // WARNING: we are now deleted! |
| 189 } |
| 190 break; |
| 191 default: |
| 192 NOTREACHED(); |
123 } | 193 } |
124 } | 194 } |
125 | 195 |
126 RenderViewHost* InterstitialPage::CreateRenderViewHost() { | 196 RenderViewHost* InterstitialPage::CreateRenderViewHost() { |
127 RenderViewHost* render_view_host = new RenderViewHost( | 197 RenderViewHost* render_view_host = new RenderViewHost( |
128 SiteInstance::CreateSiteInstance(tab()->profile()), | 198 SiteInstance::CreateSiteInstance(tab()->profile()), |
129 this, MSG_ROUTING_NONE, NULL); | 199 this, MSG_ROUTING_NONE, NULL); |
130 RenderWidgetHostViewWin* view = | 200 RenderWidgetHostViewWin* view = |
131 new RenderWidgetHostViewWin(render_view_host); | 201 new RenderWidgetHostViewWin(render_view_host); |
132 render_view_host->set_view(view); | 202 render_view_host->set_view(view); |
(...skipping 10 matching lines...) Expand all Loading... |
143 } | 213 } |
144 | 214 |
145 void InterstitialPage::Proceed() { | 215 void InterstitialPage::Proceed() { |
146 DCHECK(!action_taken_); | 216 DCHECK(!action_taken_); |
147 Disable(); | 217 Disable(); |
148 action_taken_ = true; | 218 action_taken_ = true; |
149 | 219 |
150 // Resumes the throbber. | 220 // Resumes the throbber. |
151 tab_->SetIsLoading(true, NULL); | 221 tab_->SetIsLoading(true, NULL); |
152 | 222 |
| 223 // If this is a new navigation, the old page is going away, so we cancel any |
| 224 // blocked requests for it. If it is not a new navigation, then it means the |
| 225 // interstitial was shown as a result of a resource loading in the page. |
| 226 // Since the user wants to proceed, we'll let any blocked request go through. |
| 227 if (new_navigation_) |
| 228 TakeActionOnResourceDispatcher(CANCEL); |
| 229 else |
| 230 TakeActionOnResourceDispatcher(RESUME); |
| 231 |
153 // No need to hide if we are a new navigation, we'll get hidden when the | 232 // No need to hide if we are a new navigation, we'll get hidden when the |
154 // navigation is committed. | 233 // navigation is committed. |
155 if (!new_navigation_) { | 234 if (!new_navigation_) { |
156 Hide(); | 235 Hide(); |
157 // WARNING: we are now deleted! | 236 // WARNING: we are now deleted! |
158 } | 237 } |
159 } | 238 } |
160 | 239 |
161 void InterstitialPage::DontProceed() { | 240 void InterstitialPage::DontProceed() { |
162 DCHECK(!action_taken_); | 241 DCHECK(!action_taken_); |
163 Disable(); | 242 Disable(); |
164 action_taken_ = true; | 243 action_taken_ = true; |
165 | 244 |
| 245 // If this is a new navigation, we are returning to the original page, so we |
| 246 // resume blocked requests for it. If it is not a new navigation, then it |
| 247 // means the interstitial was shown as a result of a resource loading in the |
| 248 // page and we won't return to the original page, so we cancel blocked |
| 249 // requests in that case. |
| 250 if (new_navigation_) |
| 251 TakeActionOnResourceDispatcher(RESUME); |
| 252 else |
| 253 TakeActionOnResourceDispatcher(CANCEL); |
| 254 |
166 if (new_navigation_) { | 255 if (new_navigation_) { |
167 // Since no navigation happens we have to discard the transient entry | 256 // Since no navigation happens we have to discard the transient entry |
168 // explicitely. Note that by calling DiscardNonCommittedEntries() we also | 257 // explicitely. Note that by calling DiscardNonCommittedEntries() we also |
169 // discard the pending entry, which is what we want, since the navigation is | 258 // discard the pending entry, which is what we want, since the navigation is |
170 // cancelled. | 259 // cancelled. |
171 tab_->controller()->DiscardNonCommittedEntries(); | 260 tab_->controller()->DiscardNonCommittedEntries(); |
172 } | 261 } |
173 | 262 |
174 Hide(); | 263 Hide(); |
175 // WARNING: we are now deleted! | 264 // WARNING: we are now deleted! |
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
229 should_revert_tab_title_ = true; | 318 should_revert_tab_title_ = true; |
230 } | 319 } |
231 entry->set_title(title); | 320 entry->set_title(title); |
232 tab_->NotifyNavigationStateChanged(TabContents::INVALIDATE_TITLE); | 321 tab_->NotifyNavigationStateChanged(TabContents::INVALIDATE_TITLE); |
233 } | 322 } |
234 | 323 |
235 void InterstitialPage::Disable() { | 324 void InterstitialPage::Disable() { |
236 enabled_ = false; | 325 enabled_ = false; |
237 } | 326 } |
238 | 327 |
| 328 void InterstitialPage::TakeActionOnResourceDispatcher( |
| 329 ResourceRequestAction action) { |
| 330 DCHECK(MessageLoop::current() == ui_loop_) << |
| 331 "TakeActionOnResourceDispatcher should be called on the main thread."; |
| 332 // The tab might not have a render_view_host if it was closed (in which case, |
| 333 // we have taken care of the blocked requests when processing |
| 334 // NOTIFY_RENDER_WIDGET_HOST_DESTROYED. |
| 335 // Also we need to test there is an IO thread, as when unit-tests we don't |
| 336 // have one. |
| 337 if (tab_->render_view_host() && g_browser_process->io_thread()) { |
| 338 g_browser_process->io_thread()->message_loop()->PostTask( |
| 339 FROM_HERE, new ResourceRequestTask(tab_->render_view_host(), action)); |
| 340 } |
| 341 } |
| 342 |
239 // static | 343 // static |
240 void InterstitialPage::InitInterstitialPageMap() { | 344 void InterstitialPage::InitInterstitialPageMap() { |
241 if (!tab_to_interstitial_page_) | 345 if (!tab_to_interstitial_page_) |
242 tab_to_interstitial_page_ = new InterstitialPageMap; | 346 tab_to_interstitial_page_ = new InterstitialPageMap; |
243 } | 347 } |
244 | 348 |
245 // static | 349 // static |
246 InterstitialPage* InterstitialPage::GetInterstitialPage( | 350 InterstitialPage* InterstitialPage::GetInterstitialPage( |
247 WebContents* web_contents) { | 351 WebContents* web_contents) { |
248 InitInterstitialPageMap(); | 352 InitInterstitialPageMap(); |
249 InterstitialPageMap::const_iterator iter = | 353 InterstitialPageMap::const_iterator iter = |
250 tab_to_interstitial_page_->find(web_contents); | 354 tab_to_interstitial_page_->find(web_contents); |
251 if (iter == tab_to_interstitial_page_->end()) | 355 if (iter == tab_to_interstitial_page_->end()) |
252 return NULL; | 356 return NULL; |
253 | 357 |
254 return iter->second; | 358 return iter->second; |
255 } | 359 } |
OLD | NEW |