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.
5 // Implements the Chrome Extensions WebNavigation API.
7 #include "chrome/browser/extensions/api/web_navigation/web_navigation_api.h"
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_process_host.h"
24 #include "content/public/browser/render_view_host.h"
25 #include "content/public/browser/resource_request_details.h"
26 #include "content/public/browser/web_contents.h"
27 #include "content/public/common/url_constants.h"
28 #include "extensions/browser/event_router.h"
29 #include "extensions/browser/extension_system.h"
30 #include "extensions/browser/view_type_utils.h"
31 #include "net/base/net_errors.h"
33 namespace GetFrame = extensions::api::web_navigation::GetFrame;
34 namespace GetAllFrames = extensions::api::web_navigation::GetAllFrames;
36 DEFINE_WEB_CONTENTS_USER_DATA_KEY(extensions::WebNavigationTabObserver);
38 namespace extensions {
40 #if !defined(OS_ANDROID)
42 namespace helpers = web_navigation_api_helpers;
43 namespace keys = web_navigation_api_constants;
44 namespace web_navigation = api::web_navigation;
48 typedef std::map<content::WebContents*, WebNavigationTabObserver*>
50 static base::LazyInstance<TabObserverMap> g_tab_observer =
51 LAZY_INSTANCE_INITIALIZER;
55 // WebNavigtionEventRouter -------------------------------------------
57 WebNavigationEventRouter::PendingWebContents::PendingWebContents()
58 : source_web_contents(NULL),
60 source_frame_is_main_frame(false),
61 target_web_contents(NULL),
65 WebNavigationEventRouter::PendingWebContents::PendingWebContents(
66 content::WebContents* source_web_contents,
67 int64 source_frame_id,
68 bool source_frame_is_main_frame,
69 content::WebContents* target_web_contents,
70 const GURL& target_url)
71 : source_web_contents(source_web_contents),
72 source_frame_id(source_frame_id),
73 source_frame_is_main_frame(source_frame_is_main_frame),
74 target_web_contents(target_web_contents),
75 target_url(target_url) {
78 WebNavigationEventRouter::PendingWebContents::~PendingWebContents() {}
80 WebNavigationEventRouter::WebNavigationEventRouter(Profile* profile)
82 CHECK(registrar_.IsEmpty());
84 chrome::NOTIFICATION_RETARGETING,
85 content::NotificationService::AllSources());
87 chrome::NOTIFICATION_TAB_ADDED,
88 content::NotificationService::AllSources());
90 content::NOTIFICATION_WEB_CONTENTS_DESTROYED,
91 content::NotificationService::AllSources());
93 BrowserList::AddObserver(this);
94 for (chrome::BrowserIterator it; !it.done(); it.Next())
98 WebNavigationEventRouter::~WebNavigationEventRouter() {
99 for (chrome::BrowserIterator it; !it.done(); it.Next())
100 OnBrowserRemoved(*it);
101 BrowserList::RemoveObserver(this);
104 void WebNavigationEventRouter::OnBrowserAdded(Browser* browser) {
105 if (!profile_->IsSameProfile(browser->profile()))
107 browser->tab_strip_model()->AddObserver(this);
110 void WebNavigationEventRouter::OnBrowserRemoved(Browser* browser) {
111 if (!profile_->IsSameProfile(browser->profile()))
113 browser->tab_strip_model()->RemoveObserver(this);
116 void WebNavigationEventRouter::TabReplacedAt(
117 TabStripModel* tab_strip_model,
118 content::WebContents* old_contents,
119 content::WebContents* new_contents,
121 WebNavigationTabObserver* tab_observer =
122 WebNavigationTabObserver::Get(old_contents);
124 // If you hit this DCHECK(), please add reproduction steps to
125 // http://crbug.com/109464.
126 DCHECK(GetViewType(old_contents) != VIEW_TYPE_TAB_CONTENTS);
129 const FrameNavigationState& frame_navigation_state =
130 tab_observer->frame_navigation_state();
132 if (!frame_navigation_state.IsValidUrl(old_contents->GetURL()) ||
133 !frame_navigation_state.IsValidUrl(new_contents->GetURL()))
136 helpers::DispatchOnTabReplaced(old_contents, profile_, new_contents);
139 void WebNavigationEventRouter::Observe(
141 const content::NotificationSource& source,
142 const content::NotificationDetails& details) {
144 case chrome::NOTIFICATION_RETARGETING: {
145 Profile* profile = content::Source<Profile>(source).ptr();
146 if (profile->GetOriginalProfile() == profile_) {
148 content::Details<const RetargetingDetails>(details).ptr());
153 case chrome::NOTIFICATION_TAB_ADDED:
154 TabAdded(content::Details<content::WebContents>(details).ptr());
157 case content::NOTIFICATION_WEB_CONTENTS_DESTROYED:
158 TabDestroyed(content::Source<content::WebContents>(source).ptr());
166 void WebNavigationEventRouter::Retargeting(const RetargetingDetails* details) {
167 if (details->source_frame_id == 0)
169 WebNavigationTabObserver* tab_observer =
170 WebNavigationTabObserver::Get(details->source_web_contents);
172 // If you hit this DCHECK(), please add reproduction steps to
173 // http://crbug.com/109464.
174 DCHECK(GetViewType(details->source_web_contents) != VIEW_TYPE_TAB_CONTENTS);
177 const FrameNavigationState& frame_navigation_state =
178 tab_observer->frame_navigation_state();
180 FrameNavigationState::FrameID frame_id(
181 details->source_frame_id,
182 details->source_web_contents->GetRenderViewHost());
183 if (!frame_navigation_state.CanSendEvents(frame_id))
186 // If the WebContents isn't yet inserted into a tab strip, we need to delay
187 // the extension event until the WebContents is fully initialized.
188 if (details->not_yet_in_tabstrip) {
189 pending_web_contents_[details->target_web_contents] =
191 details->source_web_contents,
192 details->source_frame_id,
193 frame_navigation_state.IsMainFrame(frame_id),
194 details->target_web_contents,
195 details->target_url);
197 helpers::DispatchOnCreatedNavigationTarget(
198 details->source_web_contents,
199 details->target_web_contents->GetBrowserContext(),
200 details->source_frame_id,
201 frame_navigation_state.IsMainFrame(frame_id),
202 details->target_web_contents,
203 details->target_url);
207 void WebNavigationEventRouter::TabAdded(content::WebContents* tab) {
208 std::map<content::WebContents*, PendingWebContents>::iterator iter =
209 pending_web_contents_.find(tab);
210 if (iter == pending_web_contents_.end())
213 WebNavigationTabObserver* tab_observer =
214 WebNavigationTabObserver::Get(iter->second.source_web_contents);
219 const FrameNavigationState& frame_navigation_state =
220 tab_observer->frame_navigation_state();
222 FrameNavigationState::FrameID frame_id(
223 iter->second.source_frame_id,
224 iter->second.source_web_contents->GetRenderViewHost());
225 if (frame_navigation_state.CanSendEvents(frame_id)) {
226 helpers::DispatchOnCreatedNavigationTarget(
227 iter->second.source_web_contents,
228 iter->second.target_web_contents->GetBrowserContext(),
229 iter->second.source_frame_id,
230 iter->second.source_frame_is_main_frame,
231 iter->second.target_web_contents,
232 iter->second.target_url);
234 pending_web_contents_.erase(iter);
237 void WebNavigationEventRouter::TabDestroyed(content::WebContents* tab) {
238 pending_web_contents_.erase(tab);
239 for (std::map<content::WebContents*, PendingWebContents>::iterator i =
240 pending_web_contents_.begin(); i != pending_web_contents_.end(); ) {
241 if (i->second.source_web_contents == tab)
242 pending_web_contents_.erase(i++);
248 // WebNavigationTabObserver ------------------------------------------
250 WebNavigationTabObserver::WebNavigationTabObserver(
251 content::WebContents* web_contents)
252 : WebContentsObserver(web_contents),
253 render_view_host_(NULL),
254 pending_render_view_host_(NULL) {
255 g_tab_observer.Get().insert(TabObserverMap::value_type(web_contents, this));
257 content::NOTIFICATION_RENDER_VIEW_HOST_WILL_CLOSE_RENDER_VIEW,
258 content::NotificationService::AllSources());
261 WebNavigationTabObserver::~WebNavigationTabObserver() {}
264 WebNavigationTabObserver* WebNavigationTabObserver::Get(
265 content::WebContents* web_contents) {
266 TabObserverMap::iterator i = g_tab_observer.Get().find(web_contents);
267 return i == g_tab_observer.Get().end() ? NULL : i->second;
270 content::RenderViewHost* WebNavigationTabObserver::GetRenderViewHostInProcess(
271 int process_id) const {
272 if (render_view_host_ &&
273 render_view_host_->GetProcess()->GetID() == process_id) {
274 return render_view_host_;
276 if (pending_render_view_host_ &&
277 pending_render_view_host_->GetProcess()->GetID() == process_id) {
278 return pending_render_view_host_;
283 void WebNavigationTabObserver::Observe(
285 const content::NotificationSource& source,
286 const content::NotificationDetails& details) {
288 case content::NOTIFICATION_RENDER_VIEW_HOST_WILL_CLOSE_RENDER_VIEW: {
289 // The RenderView is technically not yet deleted, but the RenderViewHost
290 // already starts to filter out some IPCs. In order to not get confused,
291 // we consider the RenderView dead already now.
292 RenderViewDeleted(content::Source<content::RenderViewHost>(source).ptr());
301 void WebNavigationTabObserver::RenderViewDeleted(
302 content::RenderViewHost* render_view_host) {
303 if (render_view_host == render_view_host_) {
304 render_view_host_ = NULL;
305 if (pending_render_view_host_) {
306 render_view_host_ = pending_render_view_host_;
307 pending_render_view_host_ = NULL;
309 } else if (render_view_host == pending_render_view_host_) {
310 pending_render_view_host_ = NULL;
315 web_contents(), render_view_host, FrameNavigationState::FrameID());
318 void WebNavigationTabObserver::AboutToNavigateRenderView(
319 content::RenderViewHost* render_view_host) {
320 if (!render_view_host_) {
321 render_view_host_ = render_view_host;
322 } else if (render_view_host != render_view_host_) {
323 if (pending_render_view_host_) {
324 SendErrorEvents(web_contents(),
325 pending_render_view_host_,
326 FrameNavigationState::FrameID());
328 pending_render_view_host_ = render_view_host;
332 void WebNavigationTabObserver::DidStartProvisionalLoadForFrame(
334 int64 parent_frame_num,
336 const GURL& validated_url,
338 bool is_iframe_srcdoc,
339 content::RenderViewHost* render_view_host) {
340 DVLOG(2) << "DidStartProvisionalLoad("
341 << "render_view_host=" << render_view_host
342 << ", frame_num=" << frame_num
343 << ", url=" << validated_url << ")";
344 if (!render_view_host_)
345 render_view_host_ = render_view_host;
346 if (render_view_host != render_view_host_ &&
347 render_view_host != pending_render_view_host_)
350 FrameNavigationState::FrameID frame_id(frame_num, render_view_host);
351 FrameNavigationState::FrameID parent_frame_id(
352 parent_frame_num, render_view_host);
354 navigation_state_.TrackFrame(frame_id,
361 if (!navigation_state_.CanSendEvents(frame_id))
364 helpers::DispatchOnBeforeNavigate(
366 render_view_host->GetProcess()->GetID(),
370 navigation_state_.IsMainFrame(parent_frame_id),
371 navigation_state_.GetUrl(frame_id));
374 void WebNavigationTabObserver::DidCommitProvisionalLoadForFrame(
376 const base::string16& frame_unique_name,
379 content::PageTransition transition_type,
380 content::RenderViewHost* render_view_host) {
381 DVLOG(2) << "DidCommitProvisionalLoad("
382 << "render_view_host=" << render_view_host
383 << ", frame_num=" << frame_num
384 << ", url=" << url << ")";
385 if (render_view_host != render_view_host_ &&
386 render_view_host != pending_render_view_host_)
388 FrameNavigationState::FrameID frame_id(frame_num, render_view_host);
390 bool is_reference_fragment_navigation =
391 IsReferenceFragmentNavigation(frame_id, url);
392 bool is_history_state_modification =
393 navigation_state_.GetNavigationCommitted(frame_id);
395 if (is_main_frame && render_view_host_ == render_view_host) {
396 // Changing the reference fragment or the history state using
397 // history.pushState or history.replaceState does not cancel on-going
398 // iframe navigations.
399 if (!is_reference_fragment_navigation && !is_history_state_modification)
400 SendErrorEvents(web_contents(), render_view_host_, frame_id);
401 if (pending_render_view_host_) {
402 SendErrorEvents(web_contents(),
403 pending_render_view_host_,
404 FrameNavigationState::FrameID());
405 pending_render_view_host_ = NULL;
407 } else if (pending_render_view_host_ == render_view_host) {
409 web_contents(), render_view_host_, FrameNavigationState::FrameID());
410 render_view_host_ = pending_render_view_host_;
411 pending_render_view_host_ = NULL;
414 // Update the URL as it might have changed.
415 navigation_state_.UpdateFrame(frame_id, url);
416 navigation_state_.SetNavigationCommitted(frame_id);
418 if (!navigation_state_.CanSendEvents(frame_id))
421 if (is_reference_fragment_navigation) {
422 helpers::DispatchOnCommitted(
423 web_navigation::OnReferenceFragmentUpdated::kEventName,
427 navigation_state_.GetUrl(frame_id),
429 } else if (is_history_state_modification) {
430 helpers::DispatchOnCommitted(
431 web_navigation::OnHistoryStateUpdated::kEventName,
435 navigation_state_.GetUrl(frame_id),
438 if (navigation_state_.GetIsServerRedirected(frame_id)) {
439 transition_type = static_cast<content::PageTransition>(
440 transition_type | content::PAGE_TRANSITION_SERVER_REDIRECT);
442 helpers::DispatchOnCommitted(
443 web_navigation::OnCommitted::kEventName,
447 navigation_state_.GetUrl(frame_id),
452 void WebNavigationTabObserver::DidFailProvisionalLoad(
454 const base::string16& frame_unique_id,
456 const GURL& validated_url,
458 const base::string16& error_description,
459 content::RenderViewHost* render_view_host) {
460 DVLOG(2) << "DidFailProvisionalLoad("
461 << "render_view_host=" << render_view_host
462 << ", frame_num=" << frame_num
463 << ", url=" << validated_url << ")";
464 if (render_view_host != render_view_host_ &&
465 render_view_host != pending_render_view_host_)
467 bool stop_tracking_frames = false;
468 if (render_view_host == pending_render_view_host_) {
469 pending_render_view_host_ = NULL;
470 stop_tracking_frames = true;
473 FrameNavigationState::FrameID frame_id(frame_num, render_view_host);
474 if (navigation_state_.CanSendEvents(frame_id)) {
475 helpers::DispatchOnErrorOccurred(
477 render_view_host->GetProcess()->GetID(),
478 navigation_state_.GetUrl(frame_id),
483 navigation_state_.SetErrorOccurredInFrame(frame_id);
484 if (stop_tracking_frames) {
485 navigation_state_.StopTrackingFramesInRVH(render_view_host,
486 FrameNavigationState::FrameID());
490 void WebNavigationTabObserver::DocumentLoadedInFrame(
492 content::RenderViewHost* render_view_host) {
493 DVLOG(2) << "DocumentLoadedInFrame("
494 << "render_view_host=" << render_view_host
495 << ", frame_num=" << frame_num << ")";
496 if (render_view_host != render_view_host_)
498 FrameNavigationState::FrameID frame_id(frame_num, render_view_host);
499 if (!navigation_state_.CanSendEvents(frame_id))
501 navigation_state_.SetParsingFinished(frame_id);
502 helpers::DispatchOnDOMContentLoaded(web_contents(),
503 navigation_state_.GetUrl(frame_id),
504 navigation_state_.IsMainFrame(frame_id),
507 if (!navigation_state_.GetNavigationCompleted(frame_id))
510 // The load might already have finished by the time we finished parsing. For
511 // compatibility reasons, we artifically delay the load completed signal until
512 // after parsing was completed.
513 helpers::DispatchOnCompleted(web_contents(),
514 navigation_state_.GetUrl(frame_id),
515 navigation_state_.IsMainFrame(frame_id),
519 void WebNavigationTabObserver::DidFinishLoad(
521 const GURL& validated_url,
523 content::RenderViewHost* render_view_host) {
524 DVLOG(2) << "DidFinishLoad("
525 << "render_view_host=" << render_view_host
526 << ", frame_num=" << frame_num
527 << ", url=" << validated_url << ")";
528 if (render_view_host != render_view_host_)
530 FrameNavigationState::FrameID frame_id(frame_num, render_view_host);
531 // When showing replacement content, we might get load signals for frames
532 // that weren't reguarly loaded.
533 if (!navigation_state_.IsValidFrame(frame_id))
535 navigation_state_.SetNavigationCompleted(frame_id);
536 if (!navigation_state_.CanSendEvents(frame_id))
539 navigation_state_.GetUrl(frame_id) == validated_url ||
540 (navigation_state_.GetUrl(frame_id) == GURL(content::kAboutSrcDocURL) &&
541 validated_url == GURL(content::kAboutBlankURL)))
542 << "validated URL is " << validated_url << " but we expected "
543 << navigation_state_.GetUrl(frame_id);
544 DCHECK_EQ(navigation_state_.IsMainFrame(frame_id), is_main_frame);
546 // The load might already have finished by the time we finished parsing. For
547 // compatibility reasons, we artifically delay the load completed signal until
548 // after parsing was completed.
549 if (!navigation_state_.GetParsingFinished(frame_id))
551 helpers::DispatchOnCompleted(web_contents(),
552 navigation_state_.GetUrl(frame_id),
557 void WebNavigationTabObserver::DidFailLoad(
559 const GURL& validated_url,
562 const base::string16& error_description,
563 content::RenderViewHost* render_view_host) {
564 DVLOG(2) << "DidFailLoad("
565 << "render_view_host=" << render_view_host
566 << ", frame_num=" << frame_num
567 << ", url=" << validated_url << ")";
568 if (render_view_host != render_view_host_)
570 FrameNavigationState::FrameID frame_id(frame_num, render_view_host);
571 // When showing replacement content, we might get load signals for frames
572 // that weren't reguarly loaded.
573 if (!navigation_state_.IsValidFrame(frame_id))
575 if (navigation_state_.CanSendEvents(frame_id)) {
576 helpers::DispatchOnErrorOccurred(
578 render_view_host->GetProcess()->GetID(),
579 navigation_state_.GetUrl(frame_id),
584 navigation_state_.SetErrorOccurredInFrame(frame_id);
587 void WebNavigationTabObserver::DidGetRedirectForResourceRequest(
588 content::RenderViewHost* render_view_host,
589 const content::ResourceRedirectDetails& details) {
590 if (details.resource_type != ResourceType::MAIN_FRAME &&
591 details.resource_type != ResourceType::SUB_FRAME) {
594 FrameNavigationState::FrameID frame_id(details.frame_id, render_view_host);
595 navigation_state_.SetIsServerRedirected(frame_id);
598 void WebNavigationTabObserver::DidOpenRequestedURL(
599 content::WebContents* new_contents,
601 const content::Referrer& referrer,
602 WindowOpenDisposition disposition,
603 content::PageTransition transition,
604 int64 source_frame_num) {
605 FrameNavigationState::FrameID frame_id(source_frame_num, render_view_host_);
606 if (!navigation_state_.CanSendEvents(frame_id))
609 // We only send the onCreatedNavigationTarget if we end up creating a new
611 if (disposition != SINGLETON_TAB &&
612 disposition != NEW_FOREGROUND_TAB &&
613 disposition != NEW_BACKGROUND_TAB &&
614 disposition != NEW_POPUP &&
615 disposition != NEW_WINDOW &&
616 disposition != OFF_THE_RECORD)
619 helpers::DispatchOnCreatedNavigationTarget(
621 new_contents->GetBrowserContext(),
623 navigation_state_.IsMainFrame(frame_id),
628 void WebNavigationTabObserver::FrameDetached(
629 content::RenderViewHost* render_view_host,
631 if (render_view_host != render_view_host_ &&
632 render_view_host != pending_render_view_host_) {
635 FrameNavigationState::FrameID frame_id(frame_num, render_view_host);
636 if (navigation_state_.CanSendEvents(frame_id) &&
637 !navigation_state_.GetNavigationCompleted(frame_id)) {
638 helpers::DispatchOnErrorOccurred(
640 render_view_host->GetProcess()->GetID(),
641 navigation_state_.GetUrl(frame_id),
643 navigation_state_.IsMainFrame(frame_id),
646 navigation_state_.FrameDetached(frame_id);
649 void WebNavigationTabObserver::WebContentsDestroyed(content::WebContents* tab) {
650 g_tab_observer.Get().erase(tab);
651 registrar_.RemoveAll();
652 SendErrorEvents(tab, NULL, FrameNavigationState::FrameID());
655 void WebNavigationTabObserver::SendErrorEvents(
656 content::WebContents* web_contents,
657 content::RenderViewHost* render_view_host,
658 FrameNavigationState::FrameID id_to_skip) {
659 for (FrameNavigationState::const_iterator frame = navigation_state_.begin();
660 frame != navigation_state_.end(); ++frame) {
661 if (!navigation_state_.GetNavigationCompleted(*frame) &&
662 navigation_state_.CanSendEvents(*frame) &&
663 *frame != id_to_skip &&
664 (!render_view_host || frame->render_view_host == render_view_host)) {
665 navigation_state_.SetErrorOccurredInFrame(*frame);
666 helpers::DispatchOnErrorOccurred(
668 frame->render_view_host->GetProcess()->GetID(),
669 navigation_state_.GetUrl(*frame),
671 navigation_state_.IsMainFrame(*frame),
675 if (render_view_host)
676 navigation_state_.StopTrackingFramesInRVH(render_view_host, id_to_skip);
679 // See also NavigationController::IsURLInPageNavigation.
680 bool WebNavigationTabObserver::IsReferenceFragmentNavigation(
681 FrameNavigationState::FrameID frame_id,
683 GURL existing_url = navigation_state_.GetUrl(frame_id);
684 if (existing_url == url)
687 url_canon::Replacements<char> replacements;
688 replacements.ClearRef();
689 return existing_url.ReplaceComponents(replacements) ==
690 url.ReplaceComponents(replacements);
693 bool WebNavigationGetFrameFunction::RunImpl() {
694 scoped_ptr<GetFrame::Params> params(GetFrame::Params::Create(*args_));
695 EXTENSION_FUNCTION_VALIDATE(params.get());
696 int tab_id = params->details.tab_id;
697 int frame_id = params->details.frame_id;
698 int process_id = params->details.process_id;
700 SetResult(base::Value::CreateNullValue());
702 content::WebContents* web_contents;
703 if (!ExtensionTabUtil::GetTabById(tab_id,
714 WebNavigationTabObserver* observer =
715 WebNavigationTabObserver::Get(web_contents);
718 const FrameNavigationState& frame_navigation_state =
719 observer->frame_navigation_state();
722 frame_id = frame_navigation_state.GetMainFrameID().frame_num;
724 content::RenderViewHost* render_view_host =
725 observer->GetRenderViewHostInProcess(process_id);
726 if (!render_view_host)
729 FrameNavigationState::FrameID internal_frame_id(frame_id, render_view_host);
730 if (!frame_navigation_state.IsValidFrame(internal_frame_id))
733 GURL frame_url = frame_navigation_state.GetUrl(internal_frame_id);
734 if (!frame_navigation_state.IsValidUrl(frame_url))
737 GetFrame::Results::Details frame_details;
738 frame_details.url = frame_url.spec();
739 frame_details.error_occurred =
740 frame_navigation_state.GetErrorOccurredInFrame(internal_frame_id);
741 FrameNavigationState::FrameID parent_frame_id =
742 frame_navigation_state.GetParentFrameID(internal_frame_id);
743 frame_details.parent_frame_id = helpers::GetFrameId(
744 frame_navigation_state.IsMainFrame(parent_frame_id),
745 parent_frame_id.frame_num);
746 results_ = GetFrame::Results::Create(frame_details);
750 bool WebNavigationGetAllFramesFunction::RunImpl() {
751 scoped_ptr<GetAllFrames::Params> params(GetAllFrames::Params::Create(*args_));
752 EXTENSION_FUNCTION_VALIDATE(params.get());
753 int tab_id = params->details.tab_id;
755 SetResult(base::Value::CreateNullValue());
757 content::WebContents* web_contents;
758 if (!ExtensionTabUtil::GetTabById(tab_id,
769 WebNavigationTabObserver* observer =
770 WebNavigationTabObserver::Get(web_contents);
773 const FrameNavigationState& navigation_state =
774 observer->frame_navigation_state();
776 std::vector<linked_ptr<GetAllFrames::Results::DetailsType> > result_list;
777 for (FrameNavigationState::const_iterator it = navigation_state.begin();
778 it != navigation_state.end(); ++it) {
779 FrameNavigationState::FrameID frame_id = *it;
780 FrameNavigationState::FrameID parent_frame_id =
781 navigation_state.GetParentFrameID(frame_id);
782 GURL frame_url = navigation_state.GetUrl(frame_id);
783 if (!navigation_state.IsValidUrl(frame_url))
785 linked_ptr<GetAllFrames::Results::DetailsType> frame(
786 new GetAllFrames::Results::DetailsType());
787 frame->url = frame_url.spec();
788 frame->frame_id = helpers::GetFrameId(
789 navigation_state.IsMainFrame(frame_id), frame_id.frame_num);
790 frame->parent_frame_id = helpers::GetFrameId(
791 navigation_state.IsMainFrame(parent_frame_id),
792 parent_frame_id.frame_num);
793 frame->process_id = frame_id.render_view_host->GetProcess()->GetID();
794 frame->error_occurred = navigation_state.GetErrorOccurredInFrame(frame_id);
795 result_list.push_back(frame);
797 results_ = GetAllFrames::Results::Create(result_list);
801 WebNavigationAPI::WebNavigationAPI(Profile* profile)
802 : profile_(profile) {
803 ExtensionSystem::Get(profile_)->event_router()->RegisterObserver(
804 this, web_navigation::OnBeforeNavigate::kEventName);
805 ExtensionSystem::Get(profile_)->event_router()->RegisterObserver(
806 this, web_navigation::OnCommitted::kEventName);
807 ExtensionSystem::Get(profile_)->event_router()->RegisterObserver(
808 this, web_navigation::OnCompleted::kEventName);
809 ExtensionSystem::Get(profile_)->event_router()->RegisterObserver(
810 this, web_navigation::OnCreatedNavigationTarget::kEventName);
811 ExtensionSystem::Get(profile_)->event_router()->RegisterObserver(
812 this, web_navigation::OnDOMContentLoaded::kEventName);
813 ExtensionSystem::Get(profile_)->event_router()->RegisterObserver(
814 this, web_navigation::OnHistoryStateUpdated::kEventName);
815 ExtensionSystem::Get(profile_)->event_router()->RegisterObserver(
816 this, web_navigation::OnErrorOccurred::kEventName);
817 ExtensionSystem::Get(profile_)->event_router()->RegisterObserver(
818 this, web_navigation::OnReferenceFragmentUpdated::kEventName);
819 ExtensionSystem::Get(profile_)->event_router()->RegisterObserver(
820 this, web_navigation::OnTabReplaced::kEventName);
823 WebNavigationAPI::~WebNavigationAPI() {
826 void WebNavigationAPI::Shutdown() {
827 ExtensionSystem::Get(profile_)->event_router()->UnregisterObserver(this);
830 static base::LazyInstance<ProfileKeyedAPIFactory<WebNavigationAPI> >
831 g_factory = LAZY_INSTANCE_INITIALIZER;
834 ProfileKeyedAPIFactory<WebNavigationAPI>*
835 WebNavigationAPI::GetFactoryInstance() {
836 return g_factory.Pointer();
839 void WebNavigationAPI::OnListenerAdded(const EventListenerInfo& details) {
840 web_navigation_event_router_.reset(new WebNavigationEventRouter(profile_));
841 ExtensionSystem::Get(profile_)->event_router()->UnregisterObserver(this);
846 } // namespace extensions