Add new certificateProvider extension API.
[chromium-blink-merge.git] / chrome / browser / extensions / api / web_navigation / web_navigation_api.cc
blob2e8522fb0e484f0f6572bcc9d02a8bc66339bad1
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_frame_host.h"
24 #include "content/public/browser/render_process_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 using content::ResourceType;
34 namespace GetFrame = extensions::api::web_navigation::GetFrame;
35 namespace GetAllFrames = extensions::api::web_navigation::GetAllFrames;
37 DEFINE_WEB_CONTENTS_USER_DATA_KEY(extensions::WebNavigationTabObserver);
39 namespace extensions {
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_host(NULL),
59 target_web_contents(NULL),
60 target_url() {
63 WebNavigationEventRouter::PendingWebContents::PendingWebContents(
64 content::WebContents* source_web_contents,
65 content::RenderFrameHost* source_frame_host,
66 content::WebContents* target_web_contents,
67 const GURL& target_url)
68 : source_web_contents(source_web_contents),
69 source_frame_host(source_frame_host),
70 target_web_contents(target_web_contents),
71 target_url(target_url) {
74 WebNavigationEventRouter::PendingWebContents::~PendingWebContents() {}
76 WebNavigationEventRouter::WebNavigationEventRouter(Profile* profile)
77 : profile_(profile) {
78 CHECK(registrar_.IsEmpty());
79 registrar_.Add(this,
80 chrome::NOTIFICATION_RETARGETING,
81 content::NotificationService::AllSources());
82 registrar_.Add(this,
83 chrome::NOTIFICATION_TAB_ADDED,
84 content::NotificationService::AllSources());
85 registrar_.Add(this,
86 content::NOTIFICATION_WEB_CONTENTS_DESTROYED,
87 content::NotificationService::AllSources());
89 BrowserList::AddObserver(this);
90 for (chrome::BrowserIterator it; !it.done(); it.Next())
91 OnBrowserAdded(*it);
94 WebNavigationEventRouter::~WebNavigationEventRouter() {
95 for (chrome::BrowserIterator it; !it.done(); it.Next())
96 OnBrowserRemoved(*it);
97 BrowserList::RemoveObserver(this);
100 void WebNavigationEventRouter::OnBrowserAdded(Browser* browser) {
101 if (!profile_->IsSameProfile(browser->profile()))
102 return;
103 browser->tab_strip_model()->AddObserver(this);
106 void WebNavigationEventRouter::OnBrowserRemoved(Browser* browser) {
107 if (!profile_->IsSameProfile(browser->profile()))
108 return;
109 browser->tab_strip_model()->RemoveObserver(this);
112 void WebNavigationEventRouter::TabReplacedAt(
113 TabStripModel* tab_strip_model,
114 content::WebContents* old_contents,
115 content::WebContents* new_contents,
116 int index) {
117 WebNavigationTabObserver* tab_observer =
118 WebNavigationTabObserver::Get(old_contents);
119 if (!tab_observer) {
120 // If you hit this DCHECK(), please add reproduction steps to
121 // http://crbug.com/109464.
122 DCHECK(GetViewType(old_contents) != VIEW_TYPE_TAB_CONTENTS);
123 return;
125 if (!FrameNavigationState::IsValidUrl(old_contents->GetURL()) ||
126 !FrameNavigationState::IsValidUrl(new_contents->GetURL()))
127 return;
129 helpers::DispatchOnTabReplaced(old_contents, profile_, new_contents);
132 void WebNavigationEventRouter::Observe(
133 int type,
134 const content::NotificationSource& source,
135 const content::NotificationDetails& details) {
136 switch (type) {
137 case chrome::NOTIFICATION_RETARGETING: {
138 Profile* profile = content::Source<Profile>(source).ptr();
139 if (profile->GetOriginalProfile() == profile_) {
140 Retargeting(
141 content::Details<const RetargetingDetails>(details).ptr());
143 break;
146 case chrome::NOTIFICATION_TAB_ADDED:
147 TabAdded(content::Details<content::WebContents>(details).ptr());
148 break;
150 case content::NOTIFICATION_WEB_CONTENTS_DESTROYED:
151 TabDestroyed(content::Source<content::WebContents>(source).ptr());
152 break;
154 default:
155 NOTREACHED();
159 void WebNavigationEventRouter::Retargeting(const RetargetingDetails* details) {
160 if (details->source_render_frame_id == 0)
161 return;
162 WebNavigationTabObserver* tab_observer =
163 WebNavigationTabObserver::Get(details->source_web_contents);
164 if (!tab_observer) {
165 // If you hit this DCHECK(), please add reproduction steps to
166 // http://crbug.com/109464.
167 DCHECK(GetViewType(details->source_web_contents) != VIEW_TYPE_TAB_CONTENTS);
168 return;
170 const FrameNavigationState& frame_navigation_state =
171 tab_observer->frame_navigation_state();
173 content::RenderFrameHost* frame_host = content::RenderFrameHost::FromID(
174 details->source_web_contents->GetRenderProcessHost()->GetID(),
175 details->source_render_frame_id);
176 if (!frame_navigation_state.CanSendEvents(frame_host))
177 return;
179 // If the WebContents isn't yet inserted into a tab strip, we need to delay
180 // the extension event until the WebContents is fully initialized.
181 if (details->not_yet_in_tabstrip) {
182 pending_web_contents_[details->target_web_contents] =
183 PendingWebContents(details->source_web_contents,
184 frame_host,
185 details->target_web_contents,
186 details->target_url);
187 } else {
188 helpers::DispatchOnCreatedNavigationTarget(
189 details->source_web_contents,
190 details->target_web_contents->GetBrowserContext(),
191 frame_host,
192 details->target_web_contents,
193 details->target_url);
197 void WebNavigationEventRouter::TabAdded(content::WebContents* tab) {
198 std::map<content::WebContents*, PendingWebContents>::iterator iter =
199 pending_web_contents_.find(tab);
200 if (iter == pending_web_contents_.end())
201 return;
203 WebNavigationTabObserver* tab_observer =
204 WebNavigationTabObserver::Get(iter->second.source_web_contents);
205 if (!tab_observer) {
206 NOTREACHED();
207 return;
209 const FrameNavigationState& frame_navigation_state =
210 tab_observer->frame_navigation_state();
212 if (frame_navigation_state.CanSendEvents(iter->second.source_frame_host)) {
213 helpers::DispatchOnCreatedNavigationTarget(
214 iter->second.source_web_contents,
215 iter->second.target_web_contents->GetBrowserContext(),
216 iter->second.source_frame_host,
217 iter->second.target_web_contents,
218 iter->second.target_url);
220 pending_web_contents_.erase(iter);
223 void WebNavigationEventRouter::TabDestroyed(content::WebContents* tab) {
224 pending_web_contents_.erase(tab);
225 for (std::map<content::WebContents*, PendingWebContents>::iterator i =
226 pending_web_contents_.begin(); i != pending_web_contents_.end(); ) {
227 if (i->second.source_web_contents == tab)
228 pending_web_contents_.erase(i++);
229 else
230 ++i;
234 // WebNavigationTabObserver ------------------------------------------
236 WebNavigationTabObserver::WebNavigationTabObserver(
237 content::WebContents* web_contents)
238 : WebContentsObserver(web_contents) {
239 g_tab_observer.Get().insert(TabObserverMap::value_type(web_contents, this));
240 navigation_state_.FrameHostCreated(web_contents->GetMainFrame());
243 WebNavigationTabObserver::~WebNavigationTabObserver() {}
245 // static
246 WebNavigationTabObserver* WebNavigationTabObserver::Get(
247 content::WebContents* web_contents) {
248 TabObserverMap::iterator i = g_tab_observer.Get().find(web_contents);
249 return i == g_tab_observer.Get().end() ? NULL : i->second;
252 void WebNavigationTabObserver::RenderFrameDeleted(
253 content::RenderFrameHost* render_frame_host) {
254 if (navigation_state_.CanSendEvents(render_frame_host) &&
255 !navigation_state_.GetNavigationCompleted(render_frame_host)) {
256 helpers::DispatchOnErrorOccurred(
257 web_contents(),
258 render_frame_host,
259 navigation_state_.GetUrl(render_frame_host),
260 net::ERR_ABORTED);
261 navigation_state_.SetErrorOccurredInFrame(render_frame_host);
265 void WebNavigationTabObserver::FrameDeleted(
266 content::RenderFrameHost* render_frame_host) {
267 navigation_state_.FrameHostDeleted(render_frame_host);
270 void WebNavigationTabObserver::RenderFrameHostChanged(
271 content::RenderFrameHost* old_host,
272 content::RenderFrameHost* new_host) {
273 if (old_host) {
274 RenderFrameDeleted(old_host);
275 navigation_state_.FrameHostDeleted(old_host);
278 navigation_state_.FrameHostCreated(new_host);
281 void WebNavigationTabObserver::DidStartProvisionalLoadForFrame(
282 content::RenderFrameHost* render_frame_host,
283 const GURL& validated_url,
284 bool is_error_page,
285 bool is_iframe_srcdoc) {
286 DVLOG(2) << "DidStartProvisionalLoad("
287 << "render_frame_host=" << render_frame_host
288 << ", frame_num=" << render_frame_host->GetRoutingID()
289 << ", url=" << validated_url << ")";
290 navigation_state_.StartTrackingNavigation(render_frame_host, validated_url,
291 is_error_page, is_iframe_srcdoc);
293 if (!navigation_state_.CanSendEvents(render_frame_host))
294 return;
296 helpers::DispatchOnBeforeNavigate(
297 web_contents(),
298 render_frame_host,
299 navigation_state_.GetUrl(render_frame_host));
302 void WebNavigationTabObserver::DidCommitProvisionalLoadForFrame(
303 content::RenderFrameHost* render_frame_host,
304 const GURL& url,
305 ui::PageTransition transition_type) {
306 DVLOG(2) << "DidCommitProvisionalLoad("
307 << "render_frame_host=" << render_frame_host
308 << ", frame_num=" << render_frame_host->GetRoutingID()
309 << ", url=" << url << ")";
310 bool is_reference_fragment_navigation =
311 IsReferenceFragmentNavigation(render_frame_host, url);
312 bool is_history_state_modification =
313 navigation_state_.GetNavigationCommitted(render_frame_host);
315 // Update the URL as it might have changed.
316 navigation_state_.UpdateFrame(render_frame_host, url);
317 navigation_state_.SetNavigationCommitted(render_frame_host);
319 if (!navigation_state_.CanSendEvents(render_frame_host))
320 return;
322 events::HistogramValue histogram_value = events::UNKNOWN;
323 std::string event_name;
324 if (is_reference_fragment_navigation) {
325 histogram_value = events::WEB_NAVIGATION_ON_REFERENCE_FRAGMENT_UPDATED;
326 event_name = web_navigation::OnReferenceFragmentUpdated::kEventName;
327 } else if (is_history_state_modification) {
328 histogram_value = events::WEB_NAVIGATION_ON_HISTORY_STATE_UPDATED;
329 event_name = web_navigation::OnHistoryStateUpdated::kEventName;
330 } else {
331 if (navigation_state_.GetIsServerRedirected(render_frame_host)) {
332 transition_type = ui::PageTransitionFromInt(
333 transition_type | ui::PAGE_TRANSITION_SERVER_REDIRECT);
335 histogram_value = events::WEB_NAVIGATION_ON_COMMITTED;
336 event_name = web_navigation::OnCommitted::kEventName;
338 helpers::DispatchOnCommitted(
339 histogram_value, event_name, web_contents(), render_frame_host,
340 navigation_state_.GetUrl(render_frame_host), transition_type);
343 void WebNavigationTabObserver::DidFailProvisionalLoad(
344 content::RenderFrameHost* render_frame_host,
345 const GURL& validated_url,
346 int error_code,
347 const base::string16& error_description,
348 bool was_ignored_by_handler) {
349 DVLOG(2) << "DidFailProvisionalLoad("
350 << "render_frame_host=" << render_frame_host
351 << ", frame_num=" << render_frame_host->GetRoutingID()
352 << ", url=" << validated_url << ")";
353 if (navigation_state_.CanSendEvents(render_frame_host)) {
354 helpers::DispatchOnErrorOccurred(
355 web_contents(),
356 render_frame_host,
357 navigation_state_.GetUrl(render_frame_host),
358 error_code);
360 navigation_state_.SetErrorOccurredInFrame(render_frame_host);
363 void WebNavigationTabObserver::DocumentLoadedInFrame(
364 content::RenderFrameHost* render_frame_host) {
365 DVLOG(2) << "DocumentLoadedInFrame("
366 << "render_frame_host=" << render_frame_host
367 << ", frame_num=" << render_frame_host->GetRoutingID() << ")";
368 if (!navigation_state_.CanSendEvents(render_frame_host))
369 return;
370 navigation_state_.SetParsingFinished(render_frame_host);
371 helpers::DispatchOnDOMContentLoaded(
372 web_contents(),
373 render_frame_host,
374 navigation_state_.GetUrl(render_frame_host));
376 if (!navigation_state_.GetNavigationCompleted(render_frame_host))
377 return;
379 // The load might already have finished by the time we finished parsing. For
380 // compatibility reasons, we artifically delay the load completed signal until
381 // after parsing was completed.
382 helpers::DispatchOnCompleted(web_contents(),
383 render_frame_host,
384 navigation_state_.GetUrl(render_frame_host));
387 void WebNavigationTabObserver::DidFinishLoad(
388 content::RenderFrameHost* render_frame_host,
389 const GURL& validated_url) {
390 DVLOG(2) << "DidFinishLoad("
391 << "render_frame_host=" << render_frame_host
392 << ", frame_num=" << render_frame_host->GetRoutingID()
393 << ", url=" << validated_url << ")";
394 // When showing replacement content, we might get load signals for frames
395 // that weren't reguarly loaded.
396 if (!navigation_state_.IsValidFrame(render_frame_host))
397 return;
398 navigation_state_.SetNavigationCompleted(render_frame_host);
399 if (!navigation_state_.CanSendEvents(render_frame_host))
400 return;
401 DCHECK(navigation_state_.GetUrl(render_frame_host) == validated_url ||
402 (navigation_state_.GetUrl(render_frame_host) ==
403 GURL(content::kAboutSrcDocURL) &&
404 validated_url == GURL(url::kAboutBlankURL)))
405 << "validated URL is " << validated_url << " but we expected "
406 << navigation_state_.GetUrl(render_frame_host);
408 // The load might already have finished by the time we finished parsing. For
409 // compatibility reasons, we artifically delay the load completed signal until
410 // after parsing was completed.
411 if (!navigation_state_.GetParsingFinished(render_frame_host))
412 return;
413 helpers::DispatchOnCompleted(web_contents(),
414 render_frame_host,
415 navigation_state_.GetUrl(render_frame_host));
418 void WebNavigationTabObserver::DidFailLoad(
419 content::RenderFrameHost* render_frame_host,
420 const GURL& validated_url,
421 int error_code,
422 const base::string16& error_description,
423 bool was_ignored_by_handler) {
424 DVLOG(2) << "DidFailLoad("
425 << "render_frame_host=" << render_frame_host
426 << ", frame_num=" << render_frame_host->GetRoutingID()
427 << ", url=" << validated_url << ")";
428 // When showing replacement content, we might get load signals for frames
429 // that weren't reguarly loaded.
430 if (!navigation_state_.IsValidFrame(render_frame_host))
431 return;
432 if (navigation_state_.CanSendEvents(render_frame_host)) {
433 helpers::DispatchOnErrorOccurred(
434 web_contents(),
435 render_frame_host,
436 navigation_state_.GetUrl(render_frame_host),
437 error_code);
439 navigation_state_.SetErrorOccurredInFrame(render_frame_host);
442 void WebNavigationTabObserver::DidGetRedirectForResourceRequest(
443 content::RenderFrameHost* render_frame_host,
444 const content::ResourceRedirectDetails& details) {
445 if (details.resource_type != content::RESOURCE_TYPE_MAIN_FRAME &&
446 details.resource_type != content::RESOURCE_TYPE_SUB_FRAME) {
447 return;
449 navigation_state_.SetIsServerRedirected(render_frame_host);
452 void WebNavigationTabObserver::DidOpenRequestedURL(
453 content::WebContents* new_contents,
454 content::RenderFrameHost* source_render_frame_host,
455 const GURL& url,
456 const content::Referrer& referrer,
457 WindowOpenDisposition disposition,
458 ui::PageTransition transition) {
459 if (!navigation_state_.CanSendEvents(source_render_frame_host))
460 return;
462 // We only send the onCreatedNavigationTarget if we end up creating a new
463 // window.
464 if (disposition != SINGLETON_TAB &&
465 disposition != NEW_FOREGROUND_TAB &&
466 disposition != NEW_BACKGROUND_TAB &&
467 disposition != NEW_POPUP &&
468 disposition != NEW_WINDOW &&
469 disposition != OFF_THE_RECORD)
470 return;
472 helpers::DispatchOnCreatedNavigationTarget(web_contents(),
473 new_contents->GetBrowserContext(),
474 source_render_frame_host,
475 new_contents,
476 url);
479 void WebNavigationTabObserver::WebContentsDestroyed() {
480 g_tab_observer.Get().erase(web_contents());
481 registrar_.RemoveAll();
484 // See also NavigationController::IsURLInPageNavigation.
485 bool WebNavigationTabObserver::IsReferenceFragmentNavigation(
486 content::RenderFrameHost* render_frame_host,
487 const GURL& url) {
488 GURL existing_url = navigation_state_.GetUrl(render_frame_host);
489 if (existing_url == url)
490 return false;
492 url::Replacements<char> replacements;
493 replacements.ClearRef();
494 return existing_url.ReplaceComponents(replacements) ==
495 url.ReplaceComponents(replacements);
498 bool WebNavigationGetFrameFunction::RunSync() {
499 scoped_ptr<GetFrame::Params> params(GetFrame::Params::Create(*args_));
500 EXTENSION_FUNCTION_VALIDATE(params.get());
501 int tab_id = params->details.tab_id;
502 int frame_id = params->details.frame_id;
503 int process_id = params->details.process_id;
505 SetResult(base::Value::CreateNullValue());
507 content::WebContents* web_contents;
508 if (!ExtensionTabUtil::GetTabById(tab_id,
509 GetProfile(),
510 include_incognito(),
511 NULL,
512 NULL,
513 &web_contents,
514 NULL) ||
515 !web_contents) {
516 return true;
519 WebNavigationTabObserver* observer =
520 WebNavigationTabObserver::Get(web_contents);
521 DCHECK(observer);
523 const FrameNavigationState& frame_navigation_state =
524 observer->frame_navigation_state();
526 content::RenderFrameHost* render_frame_host =
527 frame_id == 0 ? web_contents->GetMainFrame()
528 : content::RenderFrameHost::FromID(process_id, frame_id);
529 if (!frame_navigation_state.IsValidFrame(render_frame_host))
530 return true;
532 GURL frame_url = frame_navigation_state.GetUrl(render_frame_host);
533 if (!frame_navigation_state.IsValidUrl(frame_url))
534 return true;
536 GetFrame::Results::Details frame_details;
537 frame_details.url = frame_url.spec();
538 frame_details.error_occurred =
539 frame_navigation_state.GetErrorOccurredInFrame(render_frame_host);
540 frame_details.parent_frame_id =
541 helpers::GetFrameId(render_frame_host->GetParent());
542 results_ = GetFrame::Results::Create(frame_details);
543 return true;
546 bool WebNavigationGetAllFramesFunction::RunSync() {
547 scoped_ptr<GetAllFrames::Params> params(GetAllFrames::Params::Create(*args_));
548 EXTENSION_FUNCTION_VALIDATE(params.get());
549 int tab_id = params->details.tab_id;
551 SetResult(base::Value::CreateNullValue());
553 content::WebContents* web_contents;
554 if (!ExtensionTabUtil::GetTabById(tab_id,
555 GetProfile(),
556 include_incognito(),
557 NULL,
558 NULL,
559 &web_contents,
560 NULL) ||
561 !web_contents) {
562 return true;
565 WebNavigationTabObserver* observer =
566 WebNavigationTabObserver::Get(web_contents);
567 DCHECK(observer);
569 const FrameNavigationState& navigation_state =
570 observer->frame_navigation_state();
572 std::vector<linked_ptr<GetAllFrames::Results::DetailsType> > result_list;
573 for (FrameNavigationState::const_iterator it = navigation_state.begin();
574 it != navigation_state.end(); ++it) {
575 GURL frame_url = navigation_state.GetUrl(*it);
576 if (!navigation_state.IsValidUrl(frame_url))
577 continue;
578 linked_ptr<GetAllFrames::Results::DetailsType> frame(
579 new GetAllFrames::Results::DetailsType());
580 frame->url = frame_url.spec();
581 frame->frame_id = helpers::GetFrameId(*it);
582 frame->parent_frame_id = helpers::GetFrameId((*it)->GetParent());
583 frame->process_id = (*it)->GetProcess()->GetID();
584 frame->error_occurred = navigation_state.GetErrorOccurredInFrame(*it);
585 result_list.push_back(frame);
587 results_ = GetAllFrames::Results::Create(result_list);
588 return true;
591 WebNavigationAPI::WebNavigationAPI(content::BrowserContext* context)
592 : browser_context_(context) {
593 EventRouter* event_router = EventRouter::Get(browser_context_);
594 event_router->RegisterObserver(this,
595 web_navigation::OnBeforeNavigate::kEventName);
596 event_router->RegisterObserver(this, web_navigation::OnCommitted::kEventName);
597 event_router->RegisterObserver(this, web_navigation::OnCompleted::kEventName);
598 event_router->RegisterObserver(
599 this, web_navigation::OnCreatedNavigationTarget::kEventName);
600 event_router->RegisterObserver(
601 this, web_navigation::OnDOMContentLoaded::kEventName);
602 event_router->RegisterObserver(
603 this, web_navigation::OnHistoryStateUpdated::kEventName);
604 event_router->RegisterObserver(this,
605 web_navigation::OnErrorOccurred::kEventName);
606 event_router->RegisterObserver(
607 this, web_navigation::OnReferenceFragmentUpdated::kEventName);
608 event_router->RegisterObserver(this,
609 web_navigation::OnTabReplaced::kEventName);
612 WebNavigationAPI::~WebNavigationAPI() {
615 void WebNavigationAPI::Shutdown() {
616 EventRouter::Get(browser_context_)->UnregisterObserver(this);
619 static base::LazyInstance<BrowserContextKeyedAPIFactory<WebNavigationAPI> >
620 g_factory = LAZY_INSTANCE_INITIALIZER;
622 // static
623 BrowserContextKeyedAPIFactory<WebNavigationAPI>*
624 WebNavigationAPI::GetFactoryInstance() {
625 return g_factory.Pointer();
628 void WebNavigationAPI::OnListenerAdded(const EventListenerInfo& details) {
629 web_navigation_event_router_.reset(new WebNavigationEventRouter(
630 Profile::FromBrowserContext(browser_context_)));
631 EventRouter::Get(browser_context_)->UnregisterObserver(this);
634 } // namespace extensions