Enable Enterprise enrollment on desktop builds.
[chromium-blink-merge.git] / chrome / browser / extensions / api / web_navigation / web_navigation_api.cc
blob26e86ad4196a42e84ef459303285b702c3d58751
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/view_type_utils.h"
30 #include "net/base/net_errors.h"
32 namespace GetFrame = extensions::api::web_navigation::GetFrame;
33 namespace GetAllFrames = extensions::api::web_navigation::GetAllFrames;
35 DEFINE_WEB_CONTENTS_USER_DATA_KEY(extensions::WebNavigationTabObserver);
37 namespace extensions {
39 #if !defined(OS_ANDROID)
41 namespace helpers = web_navigation_api_helpers;
42 namespace keys = web_navigation_api_constants;
43 namespace web_navigation = api::web_navigation;
45 namespace {
47 typedef std::map<content::WebContents*, WebNavigationTabObserver*>
48 TabObserverMap;
49 static base::LazyInstance<TabObserverMap> g_tab_observer =
50 LAZY_INSTANCE_INITIALIZER;
52 } // namespace
54 // WebNavigtionEventRouter -------------------------------------------
56 WebNavigationEventRouter::PendingWebContents::PendingWebContents()
57 : source_web_contents(NULL),
58 source_frame_id(0),
59 source_frame_is_main_frame(false),
60 target_web_contents(NULL),
61 target_url() {
64 WebNavigationEventRouter::PendingWebContents::PendingWebContents(
65 content::WebContents* source_web_contents,
66 int64 source_frame_id,
67 bool source_frame_is_main_frame,
68 content::WebContents* target_web_contents,
69 const GURL& target_url)
70 : source_web_contents(source_web_contents),
71 source_frame_id(source_frame_id),
72 source_frame_is_main_frame(source_frame_is_main_frame),
73 target_web_contents(target_web_contents),
74 target_url(target_url) {
77 WebNavigationEventRouter::PendingWebContents::~PendingWebContents() {}
79 WebNavigationEventRouter::WebNavigationEventRouter(Profile* profile)
80 : profile_(profile) {
81 CHECK(registrar_.IsEmpty());
82 registrar_.Add(this,
83 chrome::NOTIFICATION_RETARGETING,
84 content::NotificationService::AllSources());
85 registrar_.Add(this,
86 chrome::NOTIFICATION_TAB_ADDED,
87 content::NotificationService::AllSources());
88 registrar_.Add(this,
89 content::NOTIFICATION_WEB_CONTENTS_DESTROYED,
90 content::NotificationService::AllSources());
92 BrowserList::AddObserver(this);
93 for (chrome::BrowserIterator it; !it.done(); it.Next())
94 OnBrowserAdded(*it);
97 WebNavigationEventRouter::~WebNavigationEventRouter() {
98 for (chrome::BrowserIterator it; !it.done(); it.Next())
99 OnBrowserRemoved(*it);
100 BrowserList::RemoveObserver(this);
103 void WebNavigationEventRouter::OnBrowserAdded(Browser* browser) {
104 if (!profile_->IsSameProfile(browser->profile()))
105 return;
106 browser->tab_strip_model()->AddObserver(this);
109 void WebNavigationEventRouter::OnBrowserRemoved(Browser* browser) {
110 if (!profile_->IsSameProfile(browser->profile()))
111 return;
112 browser->tab_strip_model()->RemoveObserver(this);
115 void WebNavigationEventRouter::TabReplacedAt(
116 TabStripModel* tab_strip_model,
117 content::WebContents* old_contents,
118 content::WebContents* new_contents,
119 int index) {
120 WebNavigationTabObserver* tab_observer =
121 WebNavigationTabObserver::Get(old_contents);
122 if (!tab_observer) {
123 // If you hit this DCHECK(), please add reproduction steps to
124 // http://crbug.com/109464.
125 DCHECK(GetViewType(old_contents) != VIEW_TYPE_TAB_CONTENTS);
126 return;
128 const FrameNavigationState& frame_navigation_state =
129 tab_observer->frame_navigation_state();
131 if (!frame_navigation_state.IsValidUrl(old_contents->GetURL()) ||
132 !frame_navigation_state.IsValidUrl(new_contents->GetURL()))
133 return;
135 helpers::DispatchOnTabReplaced(old_contents, profile_, new_contents);
138 void WebNavigationEventRouter::Observe(
139 int type,
140 const content::NotificationSource& source,
141 const content::NotificationDetails& details) {
142 switch (type) {
143 case chrome::NOTIFICATION_RETARGETING: {
144 Profile* profile = content::Source<Profile>(source).ptr();
145 if (profile->GetOriginalProfile() == profile_) {
146 Retargeting(
147 content::Details<const RetargetingDetails>(details).ptr());
149 break;
152 case chrome::NOTIFICATION_TAB_ADDED:
153 TabAdded(content::Details<content::WebContents>(details).ptr());
154 break;
156 case content::NOTIFICATION_WEB_CONTENTS_DESTROYED:
157 TabDestroyed(content::Source<content::WebContents>(source).ptr());
158 break;
160 default:
161 NOTREACHED();
165 void WebNavigationEventRouter::Retargeting(const RetargetingDetails* details) {
166 if (details->source_render_frame_id == 0)
167 return;
168 WebNavigationTabObserver* tab_observer =
169 WebNavigationTabObserver::Get(details->source_web_contents);
170 if (!tab_observer) {
171 // If you hit this DCHECK(), please add reproduction steps to
172 // http://crbug.com/109464.
173 DCHECK(GetViewType(details->source_web_contents) != VIEW_TYPE_TAB_CONTENTS);
174 return;
176 const FrameNavigationState& frame_navigation_state =
177 tab_observer->frame_navigation_state();
179 FrameNavigationState::FrameID frame_id(
180 details->source_render_frame_id,
181 details->source_web_contents->GetRenderViewHost());
182 if (!frame_navigation_state.CanSendEvents(frame_id))
183 return;
185 // If the WebContents isn't yet inserted into a tab strip, we need to delay
186 // the extension event until the WebContents is fully initialized.
187 if (details->not_yet_in_tabstrip) {
188 pending_web_contents_[details->target_web_contents] =
189 PendingWebContents(
190 details->source_web_contents,
191 details->source_render_frame_id,
192 frame_navigation_state.IsMainFrame(frame_id),
193 details->target_web_contents,
194 details->target_url);
195 } else {
196 helpers::DispatchOnCreatedNavigationTarget(
197 details->source_web_contents,
198 details->target_web_contents->GetBrowserContext(),
199 details->source_render_frame_id,
200 frame_navigation_state.IsMainFrame(frame_id),
201 details->target_web_contents,
202 details->target_url);
206 void WebNavigationEventRouter::TabAdded(content::WebContents* tab) {
207 std::map<content::WebContents*, PendingWebContents>::iterator iter =
208 pending_web_contents_.find(tab);
209 if (iter == pending_web_contents_.end())
210 return;
212 WebNavigationTabObserver* tab_observer =
213 WebNavigationTabObserver::Get(iter->second.source_web_contents);
214 if (!tab_observer) {
215 NOTREACHED();
216 return;
218 const FrameNavigationState& frame_navigation_state =
219 tab_observer->frame_navigation_state();
221 FrameNavigationState::FrameID frame_id(
222 iter->second.source_frame_id,
223 iter->second.source_web_contents->GetRenderViewHost());
224 if (frame_navigation_state.CanSendEvents(frame_id)) {
225 helpers::DispatchOnCreatedNavigationTarget(
226 iter->second.source_web_contents,
227 iter->second.target_web_contents->GetBrowserContext(),
228 iter->second.source_frame_id,
229 iter->second.source_frame_is_main_frame,
230 iter->second.target_web_contents,
231 iter->second.target_url);
233 pending_web_contents_.erase(iter);
236 void WebNavigationEventRouter::TabDestroyed(content::WebContents* tab) {
237 pending_web_contents_.erase(tab);
238 for (std::map<content::WebContents*, PendingWebContents>::iterator i =
239 pending_web_contents_.begin(); i != pending_web_contents_.end(); ) {
240 if (i->second.source_web_contents == tab)
241 pending_web_contents_.erase(i++);
242 else
243 ++i;
247 // WebNavigationTabObserver ------------------------------------------
249 WebNavigationTabObserver::WebNavigationTabObserver(
250 content::WebContents* web_contents)
251 : WebContentsObserver(web_contents),
252 render_view_host_(NULL),
253 pending_render_view_host_(NULL) {
254 g_tab_observer.Get().insert(TabObserverMap::value_type(web_contents, this));
255 registrar_.Add(this,
256 content::NOTIFICATION_RENDER_VIEW_HOST_WILL_CLOSE_RENDER_VIEW,
257 content::NotificationService::AllSources());
260 WebNavigationTabObserver::~WebNavigationTabObserver() {}
262 // static
263 WebNavigationTabObserver* WebNavigationTabObserver::Get(
264 content::WebContents* web_contents) {
265 TabObserverMap::iterator i = g_tab_observer.Get().find(web_contents);
266 return i == g_tab_observer.Get().end() ? NULL : i->second;
269 content::RenderViewHost* WebNavigationTabObserver::GetRenderViewHostInProcess(
270 int process_id) const {
271 if (render_view_host_ &&
272 render_view_host_->GetProcess()->GetID() == process_id) {
273 return render_view_host_;
275 if (pending_render_view_host_ &&
276 pending_render_view_host_->GetProcess()->GetID() == process_id) {
277 return pending_render_view_host_;
279 return NULL;
282 void WebNavigationTabObserver::Observe(
283 int type,
284 const content::NotificationSource& source,
285 const content::NotificationDetails& details) {
286 switch (type) {
287 case content::NOTIFICATION_RENDER_VIEW_HOST_WILL_CLOSE_RENDER_VIEW: {
288 // The RenderView is technically not yet deleted, but the RenderViewHost
289 // already starts to filter out some IPCs. In order to not get confused,
290 // we consider the RenderView dead already now.
291 RenderViewDeleted(content::Source<content::RenderViewHost>(source).ptr());
292 break;
295 default:
296 NOTREACHED();
300 void WebNavigationTabObserver::RenderViewDeleted(
301 content::RenderViewHost* render_view_host) {
302 if (render_view_host == render_view_host_) {
303 render_view_host_ = NULL;
304 if (pending_render_view_host_) {
305 render_view_host_ = pending_render_view_host_;
306 pending_render_view_host_ = NULL;
308 } else if (render_view_host == pending_render_view_host_) {
309 pending_render_view_host_ = NULL;
310 } else {
311 return;
313 SendErrorEvents(
314 web_contents(), render_view_host, FrameNavigationState::FrameID());
317 void WebNavigationTabObserver::AboutToNavigateRenderView(
318 content::RenderViewHost* render_view_host) {
319 if (!render_view_host_) {
320 render_view_host_ = render_view_host;
321 } else if (render_view_host != render_view_host_) {
322 if (pending_render_view_host_) {
323 SendErrorEvents(web_contents(),
324 pending_render_view_host_,
325 FrameNavigationState::FrameID());
327 pending_render_view_host_ = render_view_host;
331 void WebNavigationTabObserver::DidStartProvisionalLoadForFrame(
332 int64 frame_num,
333 int64 parent_frame_num,
334 bool is_main_frame,
335 const GURL& validated_url,
336 bool is_error_page,
337 bool is_iframe_srcdoc,
338 content::RenderViewHost* render_view_host) {
339 DVLOG(2) << "DidStartProvisionalLoad("
340 << "render_view_host=" << render_view_host
341 << ", frame_num=" << frame_num
342 << ", url=" << validated_url << ")";
343 if (!render_view_host_)
344 render_view_host_ = render_view_host;
345 if (render_view_host != render_view_host_ &&
346 render_view_host != pending_render_view_host_)
347 return;
349 FrameNavigationState::FrameID frame_id(frame_num, render_view_host);
350 FrameNavigationState::FrameID parent_frame_id(
351 parent_frame_num, render_view_host);
353 navigation_state_.TrackFrame(frame_id,
354 parent_frame_id,
355 validated_url,
356 is_main_frame,
357 is_error_page,
358 is_iframe_srcdoc);
360 if (!navigation_state_.CanSendEvents(frame_id))
361 return;
363 helpers::DispatchOnBeforeNavigate(
364 web_contents(),
365 render_view_host->GetProcess()->GetID(),
366 frame_num,
367 is_main_frame,
368 parent_frame_num,
369 navigation_state_.IsMainFrame(parent_frame_id),
370 navigation_state_.GetUrl(frame_id));
373 void WebNavigationTabObserver::DidCommitProvisionalLoadForFrame(
374 int64 frame_num,
375 const base::string16& frame_unique_name,
376 bool is_main_frame,
377 const GURL& url,
378 content::PageTransition transition_type,
379 content::RenderViewHost* render_view_host) {
380 DVLOG(2) << "DidCommitProvisionalLoad("
381 << "render_view_host=" << render_view_host
382 << ", frame_num=" << frame_num
383 << ", url=" << url << ")";
384 if (render_view_host != render_view_host_ &&
385 render_view_host != pending_render_view_host_)
386 return;
387 FrameNavigationState::FrameID frame_id(frame_num, render_view_host);
389 bool is_reference_fragment_navigation =
390 IsReferenceFragmentNavigation(frame_id, url);
391 bool is_history_state_modification =
392 navigation_state_.GetNavigationCommitted(frame_id);
394 if (is_main_frame && render_view_host_ == render_view_host) {
395 // Changing the reference fragment or the history state using
396 // history.pushState or history.replaceState does not cancel on-going
397 // iframe navigations.
398 if (!is_reference_fragment_navigation && !is_history_state_modification)
399 SendErrorEvents(web_contents(), render_view_host_, frame_id);
400 if (pending_render_view_host_) {
401 SendErrorEvents(web_contents(),
402 pending_render_view_host_,
403 FrameNavigationState::FrameID());
404 pending_render_view_host_ = NULL;
406 } else if (pending_render_view_host_ == render_view_host) {
407 SendErrorEvents(
408 web_contents(), render_view_host_, FrameNavigationState::FrameID());
409 render_view_host_ = pending_render_view_host_;
410 pending_render_view_host_ = NULL;
413 // Update the URL as it might have changed.
414 navigation_state_.UpdateFrame(frame_id, url);
415 navigation_state_.SetNavigationCommitted(frame_id);
417 if (!navigation_state_.CanSendEvents(frame_id))
418 return;
420 if (is_reference_fragment_navigation) {
421 helpers::DispatchOnCommitted(
422 web_navigation::OnReferenceFragmentUpdated::kEventName,
423 web_contents(),
424 frame_num,
425 is_main_frame,
426 navigation_state_.GetUrl(frame_id),
427 transition_type);
428 } else if (is_history_state_modification) {
429 helpers::DispatchOnCommitted(
430 web_navigation::OnHistoryStateUpdated::kEventName,
431 web_contents(),
432 frame_num,
433 is_main_frame,
434 navigation_state_.GetUrl(frame_id),
435 transition_type);
436 } else {
437 if (navigation_state_.GetIsServerRedirected(frame_id)) {
438 transition_type = static_cast<content::PageTransition>(
439 transition_type | content::PAGE_TRANSITION_SERVER_REDIRECT);
441 helpers::DispatchOnCommitted(
442 web_navigation::OnCommitted::kEventName,
443 web_contents(),
444 frame_num,
445 is_main_frame,
446 navigation_state_.GetUrl(frame_id),
447 transition_type);
451 void WebNavigationTabObserver::DidFailProvisionalLoad(
452 int64 frame_num,
453 const base::string16& frame_unique_id,
454 bool is_main_frame,
455 const GURL& validated_url,
456 int error_code,
457 const base::string16& error_description,
458 content::RenderViewHost* render_view_host) {
459 DVLOG(2) << "DidFailProvisionalLoad("
460 << "render_view_host=" << render_view_host
461 << ", frame_num=" << frame_num
462 << ", url=" << validated_url << ")";
463 if (render_view_host != render_view_host_ &&
464 render_view_host != pending_render_view_host_)
465 return;
466 bool stop_tracking_frames = false;
467 if (render_view_host == pending_render_view_host_) {
468 pending_render_view_host_ = NULL;
469 stop_tracking_frames = true;
472 FrameNavigationState::FrameID frame_id(frame_num, render_view_host);
473 if (navigation_state_.CanSendEvents(frame_id)) {
474 helpers::DispatchOnErrorOccurred(
475 web_contents(),
476 render_view_host->GetProcess()->GetID(),
477 navigation_state_.GetUrl(frame_id),
478 frame_num,
479 is_main_frame,
480 error_code);
482 navigation_state_.SetErrorOccurredInFrame(frame_id);
483 if (stop_tracking_frames) {
484 navigation_state_.StopTrackingFramesInRVH(render_view_host,
485 FrameNavigationState::FrameID());
489 void WebNavigationTabObserver::DocumentLoadedInFrame(
490 int64 frame_num,
491 content::RenderViewHost* render_view_host) {
492 DVLOG(2) << "DocumentLoadedInFrame("
493 << "render_view_host=" << render_view_host
494 << ", frame_num=" << frame_num << ")";
495 if (render_view_host != render_view_host_)
496 return;
497 FrameNavigationState::FrameID frame_id(frame_num, render_view_host);
498 if (!navigation_state_.CanSendEvents(frame_id))
499 return;
500 navigation_state_.SetParsingFinished(frame_id);
501 helpers::DispatchOnDOMContentLoaded(web_contents(),
502 navigation_state_.GetUrl(frame_id),
503 navigation_state_.IsMainFrame(frame_id),
504 frame_num);
506 if (!navigation_state_.GetNavigationCompleted(frame_id))
507 return;
509 // The load might already have finished by the time we finished parsing. For
510 // compatibility reasons, we artifically delay the load completed signal until
511 // after parsing was completed.
512 helpers::DispatchOnCompleted(web_contents(),
513 navigation_state_.GetUrl(frame_id),
514 navigation_state_.IsMainFrame(frame_id),
515 frame_num);
518 void WebNavigationTabObserver::DidFinishLoad(
519 int64 frame_num,
520 const GURL& validated_url,
521 bool is_main_frame,
522 content::RenderViewHost* render_view_host) {
523 DVLOG(2) << "DidFinishLoad("
524 << "render_view_host=" << render_view_host
525 << ", frame_num=" << frame_num
526 << ", url=" << validated_url << ")";
527 if (render_view_host != render_view_host_)
528 return;
529 FrameNavigationState::FrameID frame_id(frame_num, render_view_host);
530 // When showing replacement content, we might get load signals for frames
531 // that weren't reguarly loaded.
532 if (!navigation_state_.IsValidFrame(frame_id))
533 return;
534 navigation_state_.SetNavigationCompleted(frame_id);
535 if (!navigation_state_.CanSendEvents(frame_id))
536 return;
537 DCHECK(
538 navigation_state_.GetUrl(frame_id) == validated_url ||
539 (navigation_state_.GetUrl(frame_id) == GURL(content::kAboutSrcDocURL) &&
540 validated_url == GURL(content::kAboutBlankURL)))
541 << "validated URL is " << validated_url << " but we expected "
542 << navigation_state_.GetUrl(frame_id);
543 DCHECK_EQ(navigation_state_.IsMainFrame(frame_id), is_main_frame);
545 // The load might already have finished by the time we finished parsing. For
546 // compatibility reasons, we artifically delay the load completed signal until
547 // after parsing was completed.
548 if (!navigation_state_.GetParsingFinished(frame_id))
549 return;
550 helpers::DispatchOnCompleted(web_contents(),
551 navigation_state_.GetUrl(frame_id),
552 is_main_frame,
553 frame_num);
556 void WebNavigationTabObserver::DidFailLoad(
557 int64 frame_num,
558 const GURL& validated_url,
559 bool is_main_frame,
560 int error_code,
561 const base::string16& error_description,
562 content::RenderViewHost* render_view_host) {
563 DVLOG(2) << "DidFailLoad("
564 << "render_view_host=" << render_view_host
565 << ", frame_num=" << frame_num
566 << ", url=" << validated_url << ")";
567 if (render_view_host != render_view_host_)
568 return;
569 FrameNavigationState::FrameID frame_id(frame_num, render_view_host);
570 // When showing replacement content, we might get load signals for frames
571 // that weren't reguarly loaded.
572 if (!navigation_state_.IsValidFrame(frame_id))
573 return;
574 if (navigation_state_.CanSendEvents(frame_id)) {
575 helpers::DispatchOnErrorOccurred(
576 web_contents(),
577 render_view_host->GetProcess()->GetID(),
578 navigation_state_.GetUrl(frame_id),
579 frame_num,
580 is_main_frame,
581 error_code);
583 navigation_state_.SetErrorOccurredInFrame(frame_id);
586 void WebNavigationTabObserver::DidGetRedirectForResourceRequest(
587 content::RenderViewHost* render_view_host,
588 const content::ResourceRedirectDetails& details) {
589 if (details.resource_type != ResourceType::MAIN_FRAME &&
590 details.resource_type != ResourceType::SUB_FRAME) {
591 return;
593 FrameNavigationState::FrameID frame_id(details.render_frame_id,
594 render_view_host);
595 navigation_state_.SetIsServerRedirected(frame_id);
598 void WebNavigationTabObserver::DidOpenRequestedURL(
599 content::WebContents* new_contents,
600 const GURL& url,
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))
607 return;
609 // We only send the onCreatedNavigationTarget if we end up creating a new
610 // window.
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)
617 return;
619 helpers::DispatchOnCreatedNavigationTarget(
620 web_contents(),
621 new_contents->GetBrowserContext(),
622 source_frame_num,
623 navigation_state_.IsMainFrame(frame_id),
624 new_contents,
625 url);
628 void WebNavigationTabObserver::FrameDetached(
629 content::RenderViewHost* render_view_host,
630 int64 frame_num) {
631 if (render_view_host != render_view_host_ &&
632 render_view_host != pending_render_view_host_) {
633 return;
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(
639 web_contents(),
640 render_view_host->GetProcess()->GetID(),
641 navigation_state_.GetUrl(frame_id),
642 frame_num,
643 navigation_state_.IsMainFrame(frame_id),
644 net::ERR_ABORTED);
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(
667 web_contents,
668 frame->render_view_host->GetProcess()->GetID(),
669 navigation_state_.GetUrl(*frame),
670 frame->frame_num,
671 navigation_state_.IsMainFrame(*frame),
672 net::ERR_ABORTED);
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,
682 const GURL& url) {
683 GURL existing_url = navigation_state_.GetUrl(frame_id);
684 if (existing_url == url)
685 return false;
687 url::Replacements<char> replacements;
688 replacements.ClearRef();
689 return existing_url.ReplaceComponents(replacements) ==
690 url.ReplaceComponents(replacements);
693 bool WebNavigationGetFrameFunction::RunSync() {
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,
704 GetProfile(),
705 include_incognito(),
706 NULL,
707 NULL,
708 &web_contents,
709 NULL) ||
710 !web_contents) {
711 return true;
714 WebNavigationTabObserver* observer =
715 WebNavigationTabObserver::Get(web_contents);
716 DCHECK(observer);
718 const FrameNavigationState& frame_navigation_state =
719 observer->frame_navigation_state();
721 if (frame_id == 0)
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)
727 return true;
729 FrameNavigationState::FrameID internal_frame_id(frame_id, render_view_host);
730 if (!frame_navigation_state.IsValidFrame(internal_frame_id))
731 return true;
733 GURL frame_url = frame_navigation_state.GetUrl(internal_frame_id);
734 if (!frame_navigation_state.IsValidUrl(frame_url))
735 return true;
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);
747 return true;
750 bool WebNavigationGetAllFramesFunction::RunSync() {
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,
759 GetProfile(),
760 include_incognito(),
761 NULL,
762 NULL,
763 &web_contents,
764 NULL) ||
765 !web_contents) {
766 return true;
769 WebNavigationTabObserver* observer =
770 WebNavigationTabObserver::Get(web_contents);
771 DCHECK(observer);
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))
784 continue;
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);
798 return true;
801 WebNavigationAPI::WebNavigationAPI(content::BrowserContext* context)
802 : browser_context_(context) {
803 EventRouter* event_router = EventRouter::Get(browser_context_);
804 event_router->RegisterObserver(this,
805 web_navigation::OnBeforeNavigate::kEventName);
806 event_router->RegisterObserver(this, web_navigation::OnCommitted::kEventName);
807 event_router->RegisterObserver(this, web_navigation::OnCompleted::kEventName);
808 event_router->RegisterObserver(
809 this, web_navigation::OnCreatedNavigationTarget::kEventName);
810 event_router->RegisterObserver(
811 this, web_navigation::OnDOMContentLoaded::kEventName);
812 event_router->RegisterObserver(
813 this, web_navigation::OnHistoryStateUpdated::kEventName);
814 event_router->RegisterObserver(this,
815 web_navigation::OnErrorOccurred::kEventName);
816 event_router->RegisterObserver(
817 this, web_navigation::OnReferenceFragmentUpdated::kEventName);
818 event_router->RegisterObserver(this,
819 web_navigation::OnTabReplaced::kEventName);
822 WebNavigationAPI::~WebNavigationAPI() {
825 void WebNavigationAPI::Shutdown() {
826 EventRouter::Get(browser_context_)->UnregisterObserver(this);
829 static base::LazyInstance<BrowserContextKeyedAPIFactory<WebNavigationAPI> >
830 g_factory = LAZY_INSTANCE_INITIALIZER;
832 // static
833 BrowserContextKeyedAPIFactory<WebNavigationAPI>*
834 WebNavigationAPI::GetFactoryInstance() {
835 return g_factory.Pointer();
838 void WebNavigationAPI::OnListenerAdded(const EventListenerInfo& details) {
839 web_navigation_event_router_.reset(new WebNavigationEventRouter(
840 Profile::FromBrowserContext(browser_context_)));
841 EventRouter::Get(browser_context_)->UnregisterObserver(this);
844 #endif // OS_ANDROID
846 } // namespace extensions