Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / extensions / api / web_navigation / web_navigation_api.cc
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
57 WebNavigationEventRouter::PendingWebContents::PendingWebContents()
58     : source_web_contents(NULL),
59       source_frame_host(NULL),
60       target_web_contents(NULL),
61       target_url() {
62 }
63
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
75 WebNavigationEventRouter::PendingWebContents::~PendingWebContents() {}
76
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
95 WebNavigationEventRouter::~WebNavigationEventRouter() {
96   for (chrome::BrowserIterator it; !it.done(); it.Next())
97     OnBrowserRemoved(*it);
98   BrowserList::RemoveObserver(this);
99 }
100
101 void WebNavigationEventRouter::OnBrowserAdded(Browser* browser) {
102   if (!profile_->IsSameProfile(browser->profile()))
103     return;
104   browser->tab_strip_model()->AddObserver(this);
105 }
106
107 void WebNavigationEventRouter::OnBrowserRemoved(Browser* browser) {
108   if (!profile_->IsSameProfile(browser->profile()))
109     return;
110   browser->tab_strip_model()->RemoveObserver(this);
111 }
112
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
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
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
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
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
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
251 WebNavigationTabObserver::~WebNavigationTabObserver() {}
252
253 // static
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
260 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
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
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
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
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
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
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
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
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
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
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
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
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
603 void WebNavigationTabObserver::WebContentsDestroyed() {
604   g_tab_observer.Get().erase(web_contents());
605   registrar_.RemoveAll();
606   SendErrorEvents(web_contents(), NULL, NULL);
607 }
608
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.
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
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
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
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
757 WebNavigationAPI::~WebNavigationAPI() {
758 }
759
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>*
769 WebNavigationAPI::GetFactoryInstance() {
770   return g_factory.Pointer();
771 }
772
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