1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 // Implements the Chrome Extensions WebNavigation API.
6
7 #include "chrome/browser/extensions/api/web_navigation/web_navigation_api.h"
8
9 #include "base/lazy_instance.h"
10 #include "chrome/browser/chrome_notification_types.h"
11 #include "chrome/browser/extensions/api/web_navigation/web_navigation_api_constants.h"
12 #include "chrome/browser/extensions/api/web_navigation/web_navigation_api_helpers.h"
13 #include "chrome/browser/extensions/extension_tab_util.h"
14 #include "chrome/browser/profiles/profile.h"
15 #include "chrome/browser/tab_contents/retargeting_details.h"
16 #include "chrome/browser/ui/browser.h"
17 #include "chrome/browser/ui/browser_iterator.h"
18 #include "chrome/browser/ui/browser_list.h"
19 #include "chrome/common/extensions/api/web_navigation.h"
20 #include "content/public/browser/navigation_details.h"
21 #include "content/public/browser/notification_service.h"
22 #include "content/public/browser/notification_types.h"
23 #include "content/public/browser/render_frame_host.h"
24 #include "content/public/browser/render_process_host.h"
25 #include "content/public/browser/render_view_host.h"
26 #include "content/public/browser/resource_request_details.h"
27 #include "content/public/browser/web_contents.h"
28 #include "content/public/common/url_constants.h"
29 #include "extensions/browser/event_router.h"
30 #include "extensions/browser/view_type_utils.h"
31 #include "net/base/net_errors.h"
32
33 using content::ResourceType;
34
35 namespace GetFrame = extensions::api::web_navigation::GetFrame;
36 namespace GetAllFrames = extensions::api::web_navigation::GetAllFrames;
37
38 DEFINE_WEB_CONTENTS_USER_DATA_KEY(extensions::WebNavigationTabObserver);
39
40 namespace extensions {
41
42 namespace helpers = web_navigation_api_helpers;
43 namespace keys = web_navigation_api_constants;
44 namespace web_navigation = api::web_navigation;
45
46 namespace {
47
48 typedef std::map<content::WebContents*, WebNavigationTabObserver*>
49 TabObserverMap;
50 static base::LazyInstance<TabObserverMap> g_tab_observer =
51 LAZY_INSTANCE_INITIALIZER;
52
53 } // namespace
54
55 // WebNavigtionEventRouter -------------------------------------------
56
PendingWebContents()57 WebNavigationEventRouter::PendingWebContents::PendingWebContents()
58 : source_web_contents(NULL),
59 source_frame_host(NULL),
60 target_web_contents(NULL),
61 target_url() {
62 }
63
PendingWebContents(content::WebContents * source_web_contents,content::RenderFrameHost * source_frame_host,content::WebContents * target_web_contents,const GURL & target_url)64 WebNavigationEventRouter::PendingWebContents::PendingWebContents(
65 content::WebContents* source_web_contents,
66 content::RenderFrameHost* source_frame_host,
67 content::WebContents* target_web_contents,
68 const GURL& target_url)
69 : source_web_contents(source_web_contents),
70 source_frame_host(source_frame_host),
71 target_web_contents(target_web_contents),
72 target_url(target_url) {
73 }
74
~PendingWebContents()75 WebNavigationEventRouter::PendingWebContents::~PendingWebContents() {}
76
WebNavigationEventRouter(Profile * profile)77 WebNavigationEventRouter::WebNavigationEventRouter(Profile* profile)
78 : profile_(profile) {
79 CHECK(registrar_.IsEmpty());
80 registrar_.Add(this,
81 chrome::NOTIFICATION_RETARGETING,
82 content::NotificationService::AllSources());
83 registrar_.Add(this,
84 chrome::NOTIFICATION_TAB_ADDED,
85 content::NotificationService::AllSources());
86 registrar_.Add(this,
87 content::NOTIFICATION_WEB_CONTENTS_DESTROYED,
88 content::NotificationService::AllSources());
89
90 BrowserList::AddObserver(this);
91 for (chrome::BrowserIterator it; !it.done(); it.Next())
92 OnBrowserAdded(*it);
93 }
94
~WebNavigationEventRouter()95 WebNavigationEventRouter::~WebNavigationEventRouter() {
96 for (chrome::BrowserIterator it; !it.done(); it.Next())
97 OnBrowserRemoved(*it);
98 BrowserList::RemoveObserver(this);
99 }
100
OnBrowserAdded(Browser * browser)101 void WebNavigationEventRouter::OnBrowserAdded(Browser* browser) {
102 if (!profile_->IsSameProfile(browser->profile()))
103 return;
104 browser->tab_strip_model()->AddObserver(this);
105 }
106
OnBrowserRemoved(Browser * browser)107 void WebNavigationEventRouter::OnBrowserRemoved(Browser* browser) {
108 if (!profile_->IsSameProfile(browser->profile()))
109 return;
110 browser->tab_strip_model()->RemoveObserver(this);
111 }
112
TabReplacedAt(TabStripModel * tab_strip_model,content::WebContents * old_contents,content::WebContents * new_contents,int index)113 void WebNavigationEventRouter::TabReplacedAt(
114 TabStripModel* tab_strip_model,
115 content::WebContents* old_contents,
116 content::WebContents* new_contents,
117 int index) {
118 WebNavigationTabObserver* tab_observer =
119 WebNavigationTabObserver::Get(old_contents);
120 if (!tab_observer) {
121 // If you hit this DCHECK(), please add reproduction steps to
122 // http://crbug.com/109464.
123 DCHECK(GetViewType(old_contents) != VIEW_TYPE_TAB_CONTENTS);
124 return;
125 }
126 const FrameNavigationState& frame_navigation_state =
127 tab_observer->frame_navigation_state();
128
129 if (!frame_navigation_state.IsValidUrl(old_contents->GetURL()) ||
130 !frame_navigation_state.IsValidUrl(new_contents->GetURL()))
131 return;
132
133 helpers::DispatchOnTabReplaced(old_contents, profile_, new_contents);
134 }
135
Observe(int type,const content::NotificationSource & source,const content::NotificationDetails & details)136 void WebNavigationEventRouter::Observe(
137 int type,
138 const content::NotificationSource& source,
139 const content::NotificationDetails& details) {
140 switch (type) {
141 case chrome::NOTIFICATION_RETARGETING: {
142 Profile* profile = content::Source<Profile>(source).ptr();
143 if (profile->GetOriginalProfile() == profile_) {
144 Retargeting(
145 content::Details<const RetargetingDetails>(details).ptr());
146 }
147 break;
148 }
149
150 case chrome::NOTIFICATION_TAB_ADDED:
151 TabAdded(content::Details<content::WebContents>(details).ptr());
152 break;
153
154 case content::NOTIFICATION_WEB_CONTENTS_DESTROYED:
155 TabDestroyed(content::Source<content::WebContents>(source).ptr());
156 break;
157
158 default:
159 NOTREACHED();
160 }
161 }
162
Retargeting(const RetargetingDetails * details)163 void WebNavigationEventRouter::Retargeting(const RetargetingDetails* details) {
164 if (details->source_render_frame_id == 0)
165 return;
166 WebNavigationTabObserver* tab_observer =
167 WebNavigationTabObserver::Get(details->source_web_contents);
168 if (!tab_observer) {
169 // If you hit this DCHECK(), please add reproduction steps to
170 // http://crbug.com/109464.
171 DCHECK(GetViewType(details->source_web_contents) != VIEW_TYPE_TAB_CONTENTS);
172 return;
173 }
174 const FrameNavigationState& frame_navigation_state =
175 tab_observer->frame_navigation_state();
176
177 content::RenderFrameHost* frame_host = content::RenderFrameHost::FromID(
178 details->source_web_contents->GetRenderProcessHost()->GetID(),
179 details->source_render_frame_id);
180 if (!frame_navigation_state.CanSendEvents(frame_host))
181 return;
182
183 // If the WebContents isn't yet inserted into a tab strip, we need to delay
184 // the extension event until the WebContents is fully initialized.
185 if (details->not_yet_in_tabstrip) {
186 pending_web_contents_[details->target_web_contents] =
187 PendingWebContents(details->source_web_contents,
188 frame_host,
189 details->target_web_contents,
190 details->target_url);
191 } else {
192 helpers::DispatchOnCreatedNavigationTarget(
193 details->source_web_contents,
194 details->target_web_contents->GetBrowserContext(),
195 frame_host,
196 details->target_web_contents,
197 details->target_url);
198 }
199 }
200
TabAdded(content::WebContents * tab)201 void WebNavigationEventRouter::TabAdded(content::WebContents* tab) {
202 std::map<content::WebContents*, PendingWebContents>::iterator iter =
203 pending_web_contents_.find(tab);
204 if (iter == pending_web_contents_.end())
205 return;
206
207 WebNavigationTabObserver* tab_observer =
208 WebNavigationTabObserver::Get(iter->second.source_web_contents);
209 if (!tab_observer) {
210 NOTREACHED();
211 return;
212 }
213 const FrameNavigationState& frame_navigation_state =
214 tab_observer->frame_navigation_state();
215
216 if (frame_navigation_state.CanSendEvents(iter->second.source_frame_host)) {
217 helpers::DispatchOnCreatedNavigationTarget(
218 iter->second.source_web_contents,
219 iter->second.target_web_contents->GetBrowserContext(),
220 iter->second.source_frame_host,
221 iter->second.target_web_contents,
222 iter->second.target_url);
223 }
224 pending_web_contents_.erase(iter);
225 }
226
TabDestroyed(content::WebContents * tab)227 void WebNavigationEventRouter::TabDestroyed(content::WebContents* tab) {
228 pending_web_contents_.erase(tab);
229 for (std::map<content::WebContents*, PendingWebContents>::iterator i =
230 pending_web_contents_.begin(); i != pending_web_contents_.end(); ) {
231 if (i->second.source_web_contents == tab)
232 pending_web_contents_.erase(i++);
233 else
234 ++i;
235 }
236 }
237
238 // WebNavigationTabObserver ------------------------------------------
239
WebNavigationTabObserver(content::WebContents * web_contents)240 WebNavigationTabObserver::WebNavigationTabObserver(
241 content::WebContents* web_contents)
242 : WebContentsObserver(web_contents),
243 render_view_host_(NULL),
244 pending_render_view_host_(NULL) {
245 g_tab_observer.Get().insert(TabObserverMap::value_type(web_contents, this));
246 registrar_.Add(this,
247 content::NOTIFICATION_RENDER_VIEW_HOST_WILL_CLOSE_RENDER_VIEW,
248 content::NotificationService::AllSources());
249 }
250
~WebNavigationTabObserver()251 WebNavigationTabObserver::~WebNavigationTabObserver() {}
252
253 // static
Get(content::WebContents * web_contents)254 WebNavigationTabObserver* WebNavigationTabObserver::Get(
255 content::WebContents* web_contents) {
256 TabObserverMap::iterator i = g_tab_observer.Get().find(web_contents);
257 return i == g_tab_observer.Get().end() ? NULL : i->second;
258 }
259
GetRenderViewHostInProcess(int process_id) const260 content::RenderViewHost* WebNavigationTabObserver::GetRenderViewHostInProcess(
261 int process_id) const {
262 if (render_view_host_ &&
263 render_view_host_->GetProcess()->GetID() == process_id) {
264 return render_view_host_;
265 }
266 if (pending_render_view_host_ &&
267 pending_render_view_host_->GetProcess()->GetID() == process_id) {
268 return pending_render_view_host_;
269 }
270 return NULL;
271 }
272
Observe(int type,const content::NotificationSource & source,const content::NotificationDetails & details)273 void WebNavigationTabObserver::Observe(
274 int type,
275 const content::NotificationSource& source,
276 const content::NotificationDetails& details) {
277 switch (type) {
278 case content::NOTIFICATION_RENDER_VIEW_HOST_WILL_CLOSE_RENDER_VIEW: {
279 // The RenderView is technically not yet deleted, but the RenderViewHost
280 // already starts to filter out some IPCs. In order to not get confused,
281 // we consider the RenderView dead already now.
282 RenderViewDeleted(content::Source<content::RenderViewHost>(source).ptr());
283 break;
284 }
285
286 default:
287 NOTREACHED();
288 }
289 }
290
RenderFrameDeleted(content::RenderFrameHost * render_frame_host)291 void WebNavigationTabObserver::RenderFrameDeleted(
292 content::RenderFrameHost* render_frame_host) {
293 content::RenderViewHost* render_view_host =
294 render_frame_host->GetRenderViewHost();
295 if (render_view_host != render_view_host_ &&
296 render_view_host != pending_render_view_host_) {
297 return;
298 }
299 if (navigation_state_.CanSendEvents(render_frame_host) &&
300 !navigation_state_.GetNavigationCompleted(render_frame_host)) {
301 helpers::DispatchOnErrorOccurred(
302 web_contents(),
303 render_frame_host,
304 navigation_state_.GetUrl(render_frame_host),
305 net::ERR_ABORTED);
306 }
307 navigation_state_.FrameDetached(render_frame_host);
308 }
309
RenderViewDeleted(content::RenderViewHost * render_view_host)310 void WebNavigationTabObserver::RenderViewDeleted(
311 content::RenderViewHost* render_view_host) {
312 if (render_view_host == render_view_host_) {
313 render_view_host_ = NULL;
314 if (pending_render_view_host_) {
315 render_view_host_ = pending_render_view_host_;
316 pending_render_view_host_ = NULL;
317 }
318 } else if (render_view_host == pending_render_view_host_) {
319 pending_render_view_host_ = NULL;
320 } else {
321 return;
322 }
323 SendErrorEvents(web_contents(), render_view_host, NULL);
324 }
325
AboutToNavigateRenderView(content::RenderViewHost * render_view_host)326 void WebNavigationTabObserver::AboutToNavigateRenderView(
327 content::RenderViewHost* render_view_host) {
328 if (!render_view_host_) {
329 render_view_host_ = render_view_host;
330 } else if (render_view_host != render_view_host_) {
331 if (pending_render_view_host_) {
332 SendErrorEvents(web_contents(), pending_render_view_host_, NULL);
333 }
334 pending_render_view_host_ = render_view_host;
335 }
336 }
337
DidStartProvisionalLoadForFrame(content::RenderFrameHost * render_frame_host,const GURL & validated_url,bool is_error_page,bool is_iframe_srcdoc)338 void WebNavigationTabObserver::DidStartProvisionalLoadForFrame(
339 content::RenderFrameHost* render_frame_host,
340 const GURL& validated_url,
341 bool is_error_page,
342 bool is_iframe_srcdoc) {
343 content::RenderViewHost* render_view_host =
344 render_frame_host->GetRenderViewHost();
345 DVLOG(2) << "DidStartProvisionalLoad("
346 << "render_view_host=" << render_view_host
347 << ", frame_num=" << render_frame_host->GetRoutingID()
348 << ", url=" << validated_url << ")";
349 if (!render_view_host_)
350 render_view_host_ = render_view_host;
351 if (render_view_host != render_view_host_ &&
352 render_view_host != pending_render_view_host_)
353 return;
354
355 navigation_state_.TrackFrame(
356 render_frame_host, validated_url, is_error_page, is_iframe_srcdoc);
357
358 if (!navigation_state_.CanSendEvents(render_frame_host))
359 return;
360
361 helpers::DispatchOnBeforeNavigate(
362 web_contents(),
363 render_frame_host,
364 navigation_state_.GetUrl(render_frame_host));
365 }
366
DidCommitProvisionalLoadForFrame(content::RenderFrameHost * render_frame_host,const GURL & url,ui::PageTransition transition_type)367 void WebNavigationTabObserver::DidCommitProvisionalLoadForFrame(
368 content::RenderFrameHost* render_frame_host,
369 const GURL& url,
370 ui::PageTransition transition_type) {
371 content::RenderViewHost* render_view_host =
372 render_frame_host->GetRenderViewHost();
373 DVLOG(2) << "DidCommitProvisionalLoad("
374 << "render_view_host=" << render_view_host
375 << ", frame_num=" << render_frame_host->GetRoutingID()
376 << ", url=" << url << ")";
377 if (render_view_host != render_view_host_ &&
378 render_view_host != pending_render_view_host_)
379 return;
380
381 bool is_reference_fragment_navigation =
382 IsReferenceFragmentNavigation(render_frame_host, url);
383 bool is_history_state_modification =
384 navigation_state_.GetNavigationCommitted(render_frame_host);
385
386 if (!render_frame_host->GetParent() &&
387 render_view_host_ == render_view_host) {
388 // Changing the reference fragment or the history state using
389 // history.pushState or history.replaceState does not cancel on-going
390 // iframe navigations.
391 if (!is_reference_fragment_navigation && !is_history_state_modification)
392 SendErrorEvents(web_contents(), render_view_host_, render_frame_host);
393 if (pending_render_view_host_) {
394 SendErrorEvents(web_contents(), pending_render_view_host_, NULL);
395 pending_render_view_host_ = NULL;
396 }
397 } else if (pending_render_view_host_ == render_view_host) {
398 SendErrorEvents(web_contents(), render_view_host_, NULL);
399 render_view_host_ = pending_render_view_host_;
400 pending_render_view_host_ = NULL;
401 }
402
403 // Update the URL as it might have changed.
404 navigation_state_.UpdateFrame(render_frame_host, url);
405 navigation_state_.SetNavigationCommitted(render_frame_host);
406
407 if (!navigation_state_.CanSendEvents(render_frame_host))
408 return;
409
410 if (is_reference_fragment_navigation) {
411 helpers::DispatchOnCommitted(
412 web_navigation::OnReferenceFragmentUpdated::kEventName,
413 web_contents(),
414 render_frame_host,
415 navigation_state_.GetUrl(render_frame_host),
416 transition_type);
417 } else if (is_history_state_modification) {
418 helpers::DispatchOnCommitted(
419 web_navigation::OnHistoryStateUpdated::kEventName,
420 web_contents(),
421 render_frame_host,
422 navigation_state_.GetUrl(render_frame_host),
423 transition_type);
424 } else {
425 if (navigation_state_.GetIsServerRedirected(render_frame_host)) {
426 transition_type = ui::PageTransitionFromInt(
427 transition_type | ui::PAGE_TRANSITION_SERVER_REDIRECT);
428 }
429 helpers::DispatchOnCommitted(web_navigation::OnCommitted::kEventName,
430 web_contents(),
431 render_frame_host,
432 navigation_state_.GetUrl(render_frame_host),
433 transition_type);
434 }
435 }
436
DidFailProvisionalLoad(content::RenderFrameHost * render_frame_host,const GURL & validated_url,int error_code,const base::string16 & error_description)437 void WebNavigationTabObserver::DidFailProvisionalLoad(
438 content::RenderFrameHost* render_frame_host,
439 const GURL& validated_url,
440 int error_code,
441 const base::string16& error_description) {
442 content::RenderViewHost* render_view_host =
443 render_frame_host->GetRenderViewHost();
444 DVLOG(2) << "DidFailProvisionalLoad("
445 << "render_view_host=" << render_view_host
446 << ", frame_num=" << render_frame_host->GetRoutingID()
447 << ", url=" << validated_url << ")";
448 if (render_view_host != render_view_host_ &&
449 render_view_host != pending_render_view_host_)
450 return;
451 bool stop_tracking_frames = false;
452 if (render_view_host == pending_render_view_host_) {
453 pending_render_view_host_ = NULL;
454 stop_tracking_frames = true;
455 }
456
457 if (navigation_state_.CanSendEvents(render_frame_host)) {
458 helpers::DispatchOnErrorOccurred(
459 web_contents(),
460 render_frame_host,
461 navigation_state_.GetUrl(render_frame_host),
462 error_code);
463 }
464 navigation_state_.SetErrorOccurredInFrame(render_frame_host);
465 if (stop_tracking_frames) {
466 navigation_state_.StopTrackingFramesInRVH(render_view_host, NULL);
467 }
468 }
469
DocumentLoadedInFrame(content::RenderFrameHost * render_frame_host)470 void WebNavigationTabObserver::DocumentLoadedInFrame(
471 content::RenderFrameHost* render_frame_host) {
472 content::RenderViewHost* render_view_host =
473 render_frame_host->GetRenderViewHost();
474 DVLOG(2) << "DocumentLoadedInFrame("
475 << "render_view_host=" << render_view_host
476 << ", frame_num=" << render_frame_host->GetRoutingID() << ")";
477 if (render_view_host != render_view_host_)
478 return;
479 if (!navigation_state_.CanSendEvents(render_frame_host))
480 return;
481 navigation_state_.SetParsingFinished(render_frame_host);
482 helpers::DispatchOnDOMContentLoaded(
483 web_contents(),
484 render_frame_host,
485 navigation_state_.GetUrl(render_frame_host));
486
487 if (!navigation_state_.GetNavigationCompleted(render_frame_host))
488 return;
489
490 // The load might already have finished by the time we finished parsing. For
491 // compatibility reasons, we artifically delay the load completed signal until
492 // after parsing was completed.
493 helpers::DispatchOnCompleted(web_contents(),
494 render_frame_host,
495 navigation_state_.GetUrl(render_frame_host));
496 }
497
DidFinishLoad(content::RenderFrameHost * render_frame_host,const GURL & validated_url)498 void WebNavigationTabObserver::DidFinishLoad(
499 content::RenderFrameHost* render_frame_host,
500 const GURL& validated_url) {
501 content::RenderViewHost* render_view_host =
502 render_frame_host->GetRenderViewHost();
503 DVLOG(2) << "DidFinishLoad("
504 << "render_view_host=" << render_view_host
505 << ", frame_num=" << render_frame_host->GetRoutingID()
506 << ", url=" << validated_url << ")";
507 if (render_view_host != render_view_host_)
508 return;
509 // When showing replacement content, we might get load signals for frames
510 // that weren't reguarly loaded.
511 if (!navigation_state_.IsValidFrame(render_frame_host))
512 return;
513 navigation_state_.SetNavigationCompleted(render_frame_host);
514 if (!navigation_state_.CanSendEvents(render_frame_host))
515 return;
516 DCHECK(navigation_state_.GetUrl(render_frame_host) == validated_url ||
517 (navigation_state_.GetUrl(render_frame_host) ==
518 GURL(content::kAboutSrcDocURL) &&
519 validated_url == GURL(url::kAboutBlankURL)))
520 << "validated URL is " << validated_url << " but we expected "
521 << navigation_state_.GetUrl(render_frame_host);
522
523 // The load might already have finished by the time we finished parsing. For
524 // compatibility reasons, we artifically delay the load completed signal until
525 // after parsing was completed.
526 if (!navigation_state_.GetParsingFinished(render_frame_host))
527 return;
528 helpers::DispatchOnCompleted(web_contents(),
529 render_frame_host,
530 navigation_state_.GetUrl(render_frame_host));
531 }
532
DidFailLoad(content::RenderFrameHost * render_frame_host,const GURL & validated_url,int error_code,const base::string16 & error_description)533 void WebNavigationTabObserver::DidFailLoad(
534 content::RenderFrameHost* render_frame_host,
535 const GURL& validated_url,
536 int error_code,
537 const base::string16& error_description) {
538 content::RenderViewHost* render_view_host =
539 render_frame_host->GetRenderViewHost();
540 DVLOG(2) << "DidFailLoad("
541 << "render_view_host=" << render_view_host
542 << ", frame_num=" << render_frame_host->GetRoutingID()
543 << ", url=" << validated_url << ")";
544 if (render_view_host != render_view_host_)
545 return;
546 // When showing replacement content, we might get load signals for frames
547 // that weren't reguarly loaded.
548 if (!navigation_state_.IsValidFrame(render_frame_host))
549 return;
550 if (navigation_state_.CanSendEvents(render_frame_host)) {
551 helpers::DispatchOnErrorOccurred(
552 web_contents(),
553 render_frame_host,
554 navigation_state_.GetUrl(render_frame_host),
555 error_code);
556 }
557 navigation_state_.SetErrorOccurredInFrame(render_frame_host);
558 }
559
DidGetRedirectForResourceRequest(content::RenderViewHost * render_view_host,const content::ResourceRedirectDetails & details)560 void WebNavigationTabObserver::DidGetRedirectForResourceRequest(
561 content::RenderViewHost* render_view_host,
562 const content::ResourceRedirectDetails& details) {
563 if (details.resource_type != content::RESOURCE_TYPE_MAIN_FRAME &&
564 details.resource_type != content::RESOURCE_TYPE_SUB_FRAME) {
565 return;
566 }
567 content::RenderFrameHost* render_frame_host =
568 content::RenderFrameHost::FromID(render_view_host->GetProcess()->GetID(),
569 details.render_frame_id);
570 navigation_state_.SetIsServerRedirected(render_frame_host);
571 }
572
DidOpenRequestedURL(content::WebContents * new_contents,const GURL & url,const content::Referrer & referrer,WindowOpenDisposition disposition,ui::PageTransition transition,int64 source_frame_num)573 void WebNavigationTabObserver::DidOpenRequestedURL(
574 content::WebContents* new_contents,
575 const GURL& url,
576 const content::Referrer& referrer,
577 WindowOpenDisposition disposition,
578 ui::PageTransition transition,
579 int64 source_frame_num) {
580 content::RenderFrameHost* render_frame_host =
581 content::RenderFrameHost::FromID(render_view_host_->GetProcess()->GetID(),
582 source_frame_num);
583 if (!navigation_state_.CanSendEvents(render_frame_host))
584 return;
585
586 // We only send the onCreatedNavigationTarget if we end up creating a new
587 // window.
588 if (disposition != SINGLETON_TAB &&
589 disposition != NEW_FOREGROUND_TAB &&
590 disposition != NEW_BACKGROUND_TAB &&
591 disposition != NEW_POPUP &&
592 disposition != NEW_WINDOW &&
593 disposition != OFF_THE_RECORD)
594 return;
595
596 helpers::DispatchOnCreatedNavigationTarget(web_contents(),
597 new_contents->GetBrowserContext(),
598 render_frame_host,
599 new_contents,
600 url);
601 }
602
WebContentsDestroyed()603 void WebNavigationTabObserver::WebContentsDestroyed() {
604 g_tab_observer.Get().erase(web_contents());
605 registrar_.RemoveAll();
606 SendErrorEvents(web_contents(), NULL, NULL);
607 }
608
SendErrorEvents(content::WebContents * web_contents,content::RenderViewHost * render_view_host,content::RenderFrameHost * frame_host_to_skip)609 void WebNavigationTabObserver::SendErrorEvents(
610 content::WebContents* web_contents,
611 content::RenderViewHost* render_view_host,
612 content::RenderFrameHost* frame_host_to_skip) {
613 for (FrameNavigationState::const_iterator it = navigation_state_.begin();
614 it != navigation_state_.end();
615 ++it) {
616 if (!navigation_state_.GetNavigationCompleted(*it) &&
617 navigation_state_.CanSendEvents(*it) && *it != frame_host_to_skip &&
618 (!render_view_host || (*it)->GetRenderViewHost() == render_view_host)) {
619 navigation_state_.SetErrorOccurredInFrame(*it);
620 helpers::DispatchOnErrorOccurred(
621 web_contents, *it, navigation_state_.GetUrl(*it), net::ERR_ABORTED);
622 }
623 }
624 if (render_view_host)
625 navigation_state_.StopTrackingFramesInRVH(render_view_host,
626 frame_host_to_skip);
627 }
628
629 // See also NavigationController::IsURLInPageNavigation.
IsReferenceFragmentNavigation(content::RenderFrameHost * render_frame_host,const GURL & url)630 bool WebNavigationTabObserver::IsReferenceFragmentNavigation(
631 content::RenderFrameHost* render_frame_host,
632 const GURL& url) {
633 GURL existing_url = navigation_state_.GetUrl(render_frame_host);
634 if (existing_url == url)
635 return false;
636
637 url::Replacements<char> replacements;
638 replacements.ClearRef();
639 return existing_url.ReplaceComponents(replacements) ==
640 url.ReplaceComponents(replacements);
641 }
642
RunSync()643 bool WebNavigationGetFrameFunction::RunSync() {
644 scoped_ptr<GetFrame::Params> params(GetFrame::Params::Create(*args_));
645 EXTENSION_FUNCTION_VALIDATE(params.get());
646 int tab_id = params->details.tab_id;
647 int frame_id = params->details.frame_id;
648 int process_id = params->details.process_id;
649
650 SetResult(base::Value::CreateNullValue());
651
652 content::WebContents* web_contents;
653 if (!ExtensionTabUtil::GetTabById(tab_id,
654 GetProfile(),
655 include_incognito(),
656 NULL,
657 NULL,
658 &web_contents,
659 NULL) ||
660 !web_contents) {
661 return true;
662 }
663
664 WebNavigationTabObserver* observer =
665 WebNavigationTabObserver::Get(web_contents);
666 DCHECK(observer);
667
668 const FrameNavigationState& frame_navigation_state =
669 observer->frame_navigation_state();
670
671 content::RenderFrameHost* render_frame_host =
672 frame_id == 0 ? frame_navigation_state.GetLastCommittedMainFrameHost()
673 : content::RenderFrameHost::FromID(process_id, frame_id);
674 if (!frame_navigation_state.IsValidFrame(render_frame_host))
675 return true;
676
677 GURL frame_url = frame_navigation_state.GetUrl(render_frame_host);
678 if (!frame_navigation_state.IsValidUrl(frame_url))
679 return true;
680
681 GetFrame::Results::Details frame_details;
682 frame_details.url = frame_url.spec();
683 frame_details.error_occurred =
684 frame_navigation_state.GetErrorOccurredInFrame(render_frame_host);
685 frame_details.parent_frame_id =
686 helpers::GetFrameId(render_frame_host->GetParent());
687 results_ = GetFrame::Results::Create(frame_details);
688 return true;
689 }
690
RunSync()691 bool WebNavigationGetAllFramesFunction::RunSync() {
692 scoped_ptr<GetAllFrames::Params> params(GetAllFrames::Params::Create(*args_));
693 EXTENSION_FUNCTION_VALIDATE(params.get());
694 int tab_id = params->details.tab_id;
695
696 SetResult(base::Value::CreateNullValue());
697
698 content::WebContents* web_contents;
699 if (!ExtensionTabUtil::GetTabById(tab_id,
700 GetProfile(),
701 include_incognito(),
702 NULL,
703 NULL,
704 &web_contents,
705 NULL) ||
706 !web_contents) {
707 return true;
708 }
709
710 WebNavigationTabObserver* observer =
711 WebNavigationTabObserver::Get(web_contents);
712 DCHECK(observer);
713
714 const FrameNavigationState& navigation_state =
715 observer->frame_navigation_state();
716
717 std::vector<linked_ptr<GetAllFrames::Results::DetailsType> > result_list;
718 for (FrameNavigationState::const_iterator it = navigation_state.begin();
719 it != navigation_state.end(); ++it) {
720 GURL frame_url = navigation_state.GetUrl(*it);
721 if (!navigation_state.IsValidUrl(frame_url))
722 continue;
723 linked_ptr<GetAllFrames::Results::DetailsType> frame(
724 new GetAllFrames::Results::DetailsType());
725 frame->url = frame_url.spec();
726 frame->frame_id = helpers::GetFrameId(*it);
727 frame->parent_frame_id = helpers::GetFrameId((*it)->GetParent());
728 frame->process_id = (*it)->GetRenderViewHost()->GetProcess()->GetID();
729 frame->error_occurred = navigation_state.GetErrorOccurredInFrame(*it);
730 result_list.push_back(frame);
731 }
732 results_ = GetAllFrames::Results::Create(result_list);
733 return true;
734 }
735
WebNavigationAPI(content::BrowserContext * context)736 WebNavigationAPI::WebNavigationAPI(content::BrowserContext* context)
737 : browser_context_(context) {
738 EventRouter* event_router = EventRouter::Get(browser_context_);
739 event_router->RegisterObserver(this,
740 web_navigation::OnBeforeNavigate::kEventName);
741 event_router->RegisterObserver(this, web_navigation::OnCommitted::kEventName);
742 event_router->RegisterObserver(this, web_navigation::OnCompleted::kEventName);
743 event_router->RegisterObserver(
744 this, web_navigation::OnCreatedNavigationTarget::kEventName);
745 event_router->RegisterObserver(
746 this, web_navigation::OnDOMContentLoaded::kEventName);
747 event_router->RegisterObserver(
748 this, web_navigation::OnHistoryStateUpdated::kEventName);
749 event_router->RegisterObserver(this,
750 web_navigation::OnErrorOccurred::kEventName);
751 event_router->RegisterObserver(
752 this, web_navigation::OnReferenceFragmentUpdated::kEventName);
753 event_router->RegisterObserver(this,
754 web_navigation::OnTabReplaced::kEventName);
755 }
756
~WebNavigationAPI()757 WebNavigationAPI::~WebNavigationAPI() {
758 }
759
Shutdown()760 void WebNavigationAPI::Shutdown() {
761 EventRouter::Get(browser_context_)->UnregisterObserver(this);
762 }
763
764 static base::LazyInstance<BrowserContextKeyedAPIFactory<WebNavigationAPI> >
765 g_factory = LAZY_INSTANCE_INITIALIZER;
766
767 // static
768 BrowserContextKeyedAPIFactory<WebNavigationAPI>*
GetFactoryInstance()769 WebNavigationAPI::GetFactoryInstance() {
770 return g_factory.Pointer();
771 }
772
OnListenerAdded(const EventListenerInfo & details)773 void WebNavigationAPI::OnListenerAdded(const EventListenerInfo& details) {
774 web_navigation_event_router_.reset(new WebNavigationEventRouter(
775 Profile::FromBrowserContext(browser_context_)));
776 EventRouter::Get(browser_context_)->UnregisterObserver(this);
777 }
778
779 } // namespace extensions
780