Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(412)

Side by Side Diff: chrome/browser/extensions/extension_webnavigation_api.cc

Issue 9959097: Move webNavigation extension api into a separate directory (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 8 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
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/extension_webnavigation_api.h"
8
9 #include "base/json/json_writer.h"
10 #include "base/lazy_instance.h"
11 #include "base/string_number_conversions.h"
12 #include "base/time.h"
13 #include "base/values.h"
14 #include "chrome/browser/extensions/extension_event_router.h"
15 #include "chrome/browser/extensions/extension_tab_util.h"
16 #include "chrome/browser/extensions/extension_webnavigation_api_constants.h"
17 #include "chrome/browser/profiles/profile.h"
18 #include "chrome/browser/tab_contents/retargeting_details.h"
19 #include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h"
20 #include "chrome/common/chrome_notification_types.h"
21 #include "chrome/common/url_constants.h"
22 #include "content/public/browser/resource_request_details.h"
23 #include "content/public/browser/navigation_details.h"
24 #include "content/public/browser/notification_service.h"
25 #include "content/public/browser/notification_types.h"
26 #include "content/public/browser/render_view_host.h"
27 #include "content/public/browser/render_view_host_delegate.h"
28 #include "content/public/browser/web_contents.h"
29 #include "net/base/net_errors.h"
30
31 namespace keys = extension_webnavigation_api_constants;
32
33 using content::BrowserContext;
34 using content::ResourceRedirectDetails;
35 using content::WebContents;
36
37 namespace {
38
39 typedef std::map<WebContents*, ExtensionWebNavigationTabObserver*>
40 TabObserverMap;
41 static base::LazyInstance<TabObserverMap> g_tab_observer =
42 LAZY_INSTANCE_INITIALIZER;
43
44 // URL schemes for which we'll send events.
45 const char* kValidSchemes[] = {
46 chrome::kHttpScheme,
47 chrome::kHttpsScheme,
48 chrome::kFileScheme,
49 chrome::kFtpScheme,
50 chrome::kJavaScriptScheme,
51 chrome::kDataScheme,
52 };
53
54 // Returns the frame ID as it will be passed to the extension:
55 // 0 if the navigation happens in the main frame, or the frame ID
56 // modulo 32 bits otherwise.
57 // Keep this in sync with the GetFrameId() function in
58 // extension_webrequest_api.cc.
59 int GetFrameId(bool is_main_frame, int64 frame_id) {
60 return is_main_frame ? 0 : static_cast<int>(frame_id);
61 }
62
63 // Returns |time| as milliseconds since the epoch.
64 double MilliSecondsFromTime(const base::Time& time) {
65 return 1000 * time.ToDoubleT();
66 }
67
68 // Dispatches events to the extension message service.
69 void DispatchEvent(BrowserContext* browser_context,
70 const char* event_name,
71 const std::string& json_args) {
72 Profile* profile = Profile::FromBrowserContext(browser_context);
73 if (profile && profile->GetExtensionEventRouter()) {
74 profile->GetExtensionEventRouter()->DispatchEventToRenderers(
75 event_name, json_args, profile, GURL());
76 }
77 }
78
79 // Constructs and dispatches an onBeforeNavigate event.
80 void DispatchOnBeforeNavigate(WebContents* web_contents,
81 int64 frame_id,
82 bool is_main_frame,
83 const GURL& validated_url) {
84 ListValue args;
85 DictionaryValue* dict = new DictionaryValue();
86 dict->SetInteger(keys::kTabIdKey, ExtensionTabUtil::GetTabId(web_contents));
87 dict->SetString(keys::kUrlKey, validated_url.spec());
88 dict->SetInteger(keys::kFrameIdKey, GetFrameId(is_main_frame, frame_id));
89 dict->SetDouble(keys::kTimeStampKey, MilliSecondsFromTime(base::Time::Now()));
90 args.Append(dict);
91
92 std::string json_args;
93 base::JSONWriter::Write(&args, &json_args);
94 DispatchEvent(web_contents->GetBrowserContext(),
95 keys::kOnBeforeNavigate,
96 json_args);
97 }
98
99 // Constructs and dispatches an onCommitted or onReferenceFragmentUpdated
100 // event.
101 void DispatchOnCommitted(const char* event_name,
102 WebContents* web_contents,
103 int64 frame_id,
104 bool is_main_frame,
105 const GURL& url,
106 content::PageTransition transition_type) {
107 ListValue args;
108 DictionaryValue* dict = new DictionaryValue();
109 dict->SetInteger(keys::kTabIdKey, ExtensionTabUtil::GetTabId(web_contents));
110 dict->SetString(keys::kUrlKey, url.spec());
111 dict->SetInteger(keys::kFrameIdKey, GetFrameId(is_main_frame, frame_id));
112 dict->SetString(
113 keys::kTransitionTypeKey,
114 content::PageTransitionGetCoreTransitionString(transition_type));
115 ListValue* qualifiers = new ListValue();
116 if (transition_type & content::PAGE_TRANSITION_CLIENT_REDIRECT)
117 qualifiers->Append(Value::CreateStringValue("client_redirect"));
118 if (transition_type & content::PAGE_TRANSITION_SERVER_REDIRECT)
119 qualifiers->Append(Value::CreateStringValue("server_redirect"));
120 if (transition_type & content::PAGE_TRANSITION_FORWARD_BACK)
121 qualifiers->Append(Value::CreateStringValue("forward_back"));
122 if (transition_type & content::PAGE_TRANSITION_FROM_ADDRESS_BAR)
123 qualifiers->Append(Value::CreateStringValue("from_address_bar"));
124 dict->Set(keys::kTransitionQualifiersKey, qualifiers);
125 dict->SetDouble(keys::kTimeStampKey, MilliSecondsFromTime(base::Time::Now()));
126 args.Append(dict);
127
128 std::string json_args;
129 base::JSONWriter::Write(&args, &json_args);
130 DispatchEvent(web_contents->GetBrowserContext(), event_name, json_args);
131 }
132
133 // Constructs and dispatches an onDOMContentLoaded event.
134 void DispatchOnDOMContentLoaded(WebContents* web_contents,
135 const GURL& url,
136 bool is_main_frame,
137 int64 frame_id) {
138 ListValue args;
139 DictionaryValue* dict = new DictionaryValue();
140 dict->SetInteger(keys::kTabIdKey,
141 ExtensionTabUtil::GetTabId(web_contents));
142 dict->SetString(keys::kUrlKey, url.spec());
143 dict->SetInteger(keys::kFrameIdKey, GetFrameId(is_main_frame, frame_id));
144 dict->SetDouble(keys::kTimeStampKey, MilliSecondsFromTime(base::Time::Now()));
145 args.Append(dict);
146
147 std::string json_args;
148 base::JSONWriter::Write(&args, &json_args);
149 DispatchEvent(web_contents->GetBrowserContext(),
150 keys::kOnDOMContentLoaded,
151 json_args);
152 }
153
154 // Constructs and dispatches an onCompleted event.
155 void DispatchOnCompleted(WebContents* web_contents,
156 const GURL& url,
157 bool is_main_frame,
158 int64 frame_id) {
159 ListValue args;
160 DictionaryValue* dict = new DictionaryValue();
161 dict->SetInteger(keys::kTabIdKey,
162 ExtensionTabUtil::GetTabId(web_contents));
163 dict->SetString(keys::kUrlKey, url.spec());
164 dict->SetInteger(keys::kFrameIdKey, GetFrameId(is_main_frame, frame_id));
165 dict->SetDouble(keys::kTimeStampKey, MilliSecondsFromTime(base::Time::Now()));
166 args.Append(dict);
167
168 std::string json_args;
169 base::JSONWriter::Write(&args, &json_args);
170 DispatchEvent(web_contents->GetBrowserContext(),
171 keys::kOnCompleted, json_args);
172 }
173
174 // Constructs and dispatches an onCreatedNavigationTarget event.
175 void DispatchOnCreatedNavigationTarget(
176 WebContents* web_contents,
177 BrowserContext* browser_context,
178 int64 source_frame_id,
179 bool source_frame_is_main_frame,
180 WebContents* target_web_contents,
181 const GURL& target_url) {
182 // Check that the tab is already inserted into a tab strip model. This code
183 // path is exercised by ExtensionApiTest.WebNavigationRequestOpenTab.
184 DCHECK(ExtensionTabUtil::GetTabById(
185 ExtensionTabUtil::GetTabId(target_web_contents),
186 Profile::FromBrowserContext(target_web_contents->GetBrowserContext()),
187 false, NULL, NULL, NULL, NULL));
188
189 ListValue args;
190 DictionaryValue* dict = new DictionaryValue();
191 dict->SetInteger(keys::kSourceTabIdKey,
192 ExtensionTabUtil::GetTabId(web_contents));
193 dict->SetInteger(keys::kSourceFrameIdKey,
194 GetFrameId(source_frame_is_main_frame, source_frame_id));
195 dict->SetString(keys::kUrlKey, target_url.possibly_invalid_spec());
196 dict->SetInteger(keys::kTabIdKey,
197 ExtensionTabUtil::GetTabId(target_web_contents));
198 dict->SetDouble(keys::kTimeStampKey, MilliSecondsFromTime(base::Time::Now()));
199 args.Append(dict);
200
201 std::string json_args;
202 base::JSONWriter::Write(&args, &json_args);
203 DispatchEvent(
204 browser_context, keys::kOnCreatedNavigationTarget, json_args);
205 }
206
207 // Constructs and dispatches an onErrorOccurred event.
208 void DispatchOnErrorOccurred(WebContents* web_contents,
209 const GURL& url,
210 int64 frame_id,
211 bool is_main_frame,
212 int error_code) {
213 ListValue args;
214 DictionaryValue* dict = new DictionaryValue();
215 dict->SetInteger(keys::kTabIdKey, ExtensionTabUtil::GetTabId(web_contents));
216 dict->SetString(keys::kUrlKey, url.spec());
217 dict->SetInteger(keys::kFrameIdKey, GetFrameId(is_main_frame, frame_id));
218 dict->SetString(keys::kErrorKey, net::ErrorToString(error_code));
219 dict->SetDouble(keys::kTimeStampKey, MilliSecondsFromTime(base::Time::Now()));
220 args.Append(dict);
221
222 std::string json_args;
223 base::JSONWriter::Write(&args, &json_args);
224 DispatchEvent(web_contents->GetBrowserContext(),
225 keys::kOnErrorOccurred,
226 json_args);
227 }
228
229 } // namespace
230
231
232 // FrameNavigationState -------------------------------------------------------
233
234 // static
235 bool FrameNavigationState::allow_extension_scheme_ = false;
236
237 FrameNavigationState::FrameNavigationState()
238 : main_frame_id_(-1) {
239 }
240
241 FrameNavigationState::~FrameNavigationState() {}
242
243 bool FrameNavigationState::CanSendEvents(int64 frame_id) const {
244 FrameIdToStateMap::const_iterator frame_state =
245 frame_state_map_.find(frame_id);
246 if (frame_state == frame_state_map_.end() ||
247 frame_state->second.error_occurred) {
248 return false;
249 }
250 return IsValidUrl(frame_state->second.url);
251 }
252
253 bool FrameNavigationState::IsValidUrl(const GURL& url) const {
254 for (unsigned i = 0; i < arraysize(kValidSchemes); ++i) {
255 if (url.scheme() == kValidSchemes[i])
256 return true;
257 }
258 // Allow about:blank.
259 if (url.spec() == chrome::kAboutBlankURL)
260 return true;
261 if (allow_extension_scheme_ && url.scheme() == chrome::kExtensionScheme)
262 return true;
263 return false;
264 }
265
266 void FrameNavigationState::TrackFrame(int64 frame_id,
267 const GURL& url,
268 bool is_main_frame,
269 bool is_error_page) {
270 if (is_main_frame) {
271 frame_state_map_.clear();
272 frame_ids_.clear();
273 }
274 FrameState& frame_state = frame_state_map_[frame_id];
275 frame_state.error_occurred = is_error_page;
276 frame_state.url = url;
277 frame_state.is_main_frame = is_main_frame;
278 frame_state.is_navigating = true;
279 frame_state.is_committed = false;
280 frame_state.is_server_redirected = false;
281 if (is_main_frame) {
282 main_frame_id_ = frame_id;
283 }
284 frame_ids_.insert(frame_id);
285 }
286
287 void FrameNavigationState::UpdateFrame(int64 frame_id, const GURL& url) {
288 FrameIdToStateMap::iterator frame_state = frame_state_map_.find(frame_id);
289 if (frame_state == frame_state_map_.end()) {
290 NOTREACHED();
291 return;
292 }
293 frame_state->second.url = url;
294 }
295
296 bool FrameNavigationState::IsValidFrame(int64 frame_id) const {
297 FrameIdToStateMap::const_iterator frame_state =
298 frame_state_map_.find(frame_id);
299 return (frame_state != frame_state_map_.end());
300 }
301
302 GURL FrameNavigationState::GetUrl(int64 frame_id) const {
303 FrameIdToStateMap::const_iterator frame_state =
304 frame_state_map_.find(frame_id);
305 if (frame_state == frame_state_map_.end()) {
306 NOTREACHED();
307 return GURL();
308 }
309 return frame_state->second.url;
310 }
311
312 bool FrameNavigationState::IsMainFrame(int64 frame_id) const {
313 return main_frame_id_ != -1 && main_frame_id_ == frame_id;
314 }
315
316 int64 FrameNavigationState::GetMainFrameID() const {
317 return main_frame_id_;
318 }
319
320 void FrameNavigationState::SetErrorOccurredInFrame(int64 frame_id) {
321 DCHECK(frame_state_map_.find(frame_id) != frame_state_map_.end());
322 frame_state_map_[frame_id].error_occurred = true;
323 }
324
325 bool FrameNavigationState::GetErrorOccurredInFrame(int64 frame_id) const {
326 FrameIdToStateMap::const_iterator frame_state =
327 frame_state_map_.find(frame_id);
328 return (frame_state == frame_state_map_.end() ||
329 frame_state->second.error_occurred);
330 }
331
332 void FrameNavigationState::SetNavigationCompleted(int64 frame_id) {
333 DCHECK(frame_state_map_.find(frame_id) != frame_state_map_.end());
334 frame_state_map_[frame_id].is_navigating = false;
335 }
336
337 bool FrameNavigationState::GetNavigationCompleted(int64 frame_id) const {
338 FrameIdToStateMap::const_iterator frame_state =
339 frame_state_map_.find(frame_id);
340 return (frame_state == frame_state_map_.end() ||
341 !frame_state->second.is_navigating);
342 }
343
344 void FrameNavigationState::SetNavigationCommitted(int64 frame_id) {
345 DCHECK(frame_state_map_.find(frame_id) != frame_state_map_.end());
346 frame_state_map_[frame_id].is_committed = true;
347 }
348
349 bool FrameNavigationState::GetNavigationCommitted(int64 frame_id) const {
350 FrameIdToStateMap::const_iterator frame_state =
351 frame_state_map_.find(frame_id);
352 return (frame_state != frame_state_map_.end() &&
353 frame_state->second.is_committed);
354 }
355
356 void FrameNavigationState::SetIsServerRedirected(int64 frame_id) {
357 DCHECK(frame_state_map_.find(frame_id) != frame_state_map_.end());
358 frame_state_map_[frame_id].is_server_redirected = true;
359 }
360
361 bool FrameNavigationState::GetIsServerRedirected(int64 frame_id) const {
362 FrameIdToStateMap::const_iterator frame_state =
363 frame_state_map_.find(frame_id);
364 return (frame_state != frame_state_map_.end() &&
365 frame_state->second.is_server_redirected);
366 }
367
368
369 // ExtensionWebNavigtionEventRouter -------------------------------------------
370
371 ExtensionWebNavigationEventRouter::PendingWebContents::PendingWebContents()
372 : source_web_contents(NULL),
373 source_frame_id(0),
374 source_frame_is_main_frame(false),
375 target_web_contents(NULL),
376 target_url() {
377 }
378
379 ExtensionWebNavigationEventRouter::PendingWebContents::PendingWebContents(
380 WebContents* source_web_contents,
381 int64 source_frame_id,
382 bool source_frame_is_main_frame,
383 WebContents* target_web_contents,
384 const GURL& target_url)
385 : source_web_contents(source_web_contents),
386 source_frame_id(source_frame_id),
387 source_frame_is_main_frame(source_frame_is_main_frame),
388 target_web_contents(target_web_contents),
389 target_url(target_url) {
390 }
391
392 ExtensionWebNavigationEventRouter::PendingWebContents::~PendingWebContents() {}
393
394 ExtensionWebNavigationEventRouter::ExtensionWebNavigationEventRouter(
395 Profile* profile) : profile_(profile) {}
396
397 ExtensionWebNavigationEventRouter::~ExtensionWebNavigationEventRouter() {}
398
399 void ExtensionWebNavigationEventRouter::Init() {
400 if (registrar_.IsEmpty()) {
401 registrar_.Add(this,
402 chrome::NOTIFICATION_RETARGETING,
403 content::NotificationService::AllSources());
404 registrar_.Add(this,
405 content::NOTIFICATION_TAB_ADDED,
406 content::NotificationService::AllSources());
407 registrar_.Add(this,
408 content::NOTIFICATION_WEB_CONTENTS_DESTROYED,
409 content::NotificationService::AllSources());
410 }
411 }
412
413 void ExtensionWebNavigationEventRouter::Observe(
414 int type,
415 const content::NotificationSource& source,
416 const content::NotificationDetails& details) {
417 switch (type) {
418 case chrome::NOTIFICATION_RETARGETING: {
419 Profile* profile = content::Source<Profile>(source).ptr();
420 if (profile->GetOriginalProfile() == profile_) {
421 Retargeting(
422 content::Details<const RetargetingDetails>(details).ptr());
423 }
424 break;
425 }
426
427 case content::NOTIFICATION_TAB_ADDED:
428 TabAdded(content::Details<WebContents>(details).ptr());
429 break;
430
431 case content::NOTIFICATION_WEB_CONTENTS_DESTROYED:
432 TabDestroyed(content::Source<WebContents>(source).ptr());
433 break;
434
435 default:
436 NOTREACHED();
437 }
438 }
439
440 void ExtensionWebNavigationEventRouter::Retargeting(
441 const RetargetingDetails* details) {
442 if (details->source_frame_id == 0)
443 return;
444 ExtensionWebNavigationTabObserver* tab_observer =
445 ExtensionWebNavigationTabObserver::Get(details->source_web_contents);
446 if (!tab_observer) {
447 // If you hit this DCHECK(), please add reproduction steps to
448 // http://crbug.com/109464.
449 DCHECK(details->source_web_contents->GetViewType() !=
450 content::VIEW_TYPE_TAB_CONTENTS);
451 return;
452 }
453 const FrameNavigationState& frame_navigation_state =
454 tab_observer->frame_navigation_state();
455
456 if (!frame_navigation_state.CanSendEvents(details->source_frame_id))
457 return;
458
459 // If the WebContents was created as a response to an IPC from a renderer
460 // (and therefore doesn't yet have a wrapper), or if it isn't yet inserted
461 // into a tab strip, we need to delay the extension event until the
462 // WebContents is fully initialized.
463 if ((TabContentsWrapper::GetCurrentWrapperForContents(
464 details->target_web_contents) == NULL) ||
465 details->not_yet_in_tabstrip) {
466 pending_web_contents_[details->target_web_contents] =
467 PendingWebContents(
468 details->source_web_contents,
469 details->source_frame_id,
470 frame_navigation_state.IsMainFrame(details->source_frame_id),
471 details->target_web_contents,
472 details->target_url);
473 } else {
474 DispatchOnCreatedNavigationTarget(
475 details->source_web_contents,
476 details->target_web_contents->GetBrowserContext(),
477 details->source_frame_id,
478 frame_navigation_state.IsMainFrame(details->source_frame_id),
479 details->target_web_contents,
480 details->target_url);
481 }
482 }
483
484 void ExtensionWebNavigationEventRouter::TabAdded(WebContents* tab) {
485 std::map<WebContents*, PendingWebContents>::iterator iter =
486 pending_web_contents_.find(tab);
487 if (iter == pending_web_contents_.end())
488 return;
489
490 DispatchOnCreatedNavigationTarget(
491 iter->second.source_web_contents,
492 iter->second.target_web_contents->GetBrowserContext(),
493 iter->second.source_frame_id,
494 iter->second.source_frame_is_main_frame,
495 iter->second.target_web_contents,
496 iter->second.target_url);
497 pending_web_contents_.erase(iter);
498 }
499
500 void ExtensionWebNavigationEventRouter::TabDestroyed(WebContents* tab) {
501 pending_web_contents_.erase(tab);
502 for (std::map<WebContents*, PendingWebContents>::iterator i =
503 pending_web_contents_.begin(); i != pending_web_contents_.end(); ) {
504 if (i->second.source_web_contents == tab)
505 pending_web_contents_.erase(i++);
506 else
507 ++i;
508 }
509 }
510
511 // ExtensionWebNavigationTabObserver ------------------------------------------
512
513 ExtensionWebNavigationTabObserver::ExtensionWebNavigationTabObserver(
514 WebContents* web_contents)
515 : WebContentsObserver(web_contents) {
516 g_tab_observer.Get().insert(TabObserverMap::value_type(web_contents, this));
517 registrar_.Add(this,
518 content::NOTIFICATION_RESOURCE_RECEIVED_REDIRECT,
519 content::Source<WebContents>(web_contents));
520 }
521
522 ExtensionWebNavigationTabObserver::~ExtensionWebNavigationTabObserver() {}
523
524 // static
525 ExtensionWebNavigationTabObserver* ExtensionWebNavigationTabObserver::Get(
526 WebContents* web_contents) {
527 TabObserverMap::iterator i = g_tab_observer.Get().find(web_contents);
528 return i == g_tab_observer.Get().end() ? NULL : i->second;
529 }
530
531 void ExtensionWebNavigationTabObserver::Observe(
532 int type,
533 const content::NotificationSource& source,
534 const content::NotificationDetails& details) {
535 switch (type) {
536 case content::NOTIFICATION_RESOURCE_RECEIVED_REDIRECT: {
537 ResourceRedirectDetails* resource_redirect_details =
538 content::Details<ResourceRedirectDetails>(details).ptr();
539 ResourceType::Type resource_type =
540 resource_redirect_details->resource_type;
541 if (resource_type == ResourceType::MAIN_FRAME ||
542 resource_type == ResourceType::SUB_FRAME) {
543 int64 frame_id = resource_redirect_details->frame_id;
544 if (!navigation_state_.CanSendEvents(frame_id))
545 return;
546 navigation_state_.SetIsServerRedirected(frame_id);
547 }
548 break;
549 }
550
551 default:
552 NOTREACHED();
553 }
554 }
555
556 void ExtensionWebNavigationTabObserver::DidStartProvisionalLoadForFrame(
557 int64 frame_id,
558 bool is_main_frame,
559 const GURL& validated_url,
560 bool is_error_page,
561 content::RenderViewHost* render_view_host) {
562 // Ignore navigations of sub frames, if the main frame isn't committed yet.
563 // This might happen if a sub frame triggers a navigation for both the main
564 // frame and itself. Since the sub frame is about to be deleted, and there's
565 // no way for an extension to tell that these navigations belong to an old
566 // frame, we just suppress the events here.
567 int64 main_frame_id = navigation_state_.GetMainFrameID();
568 if (!is_main_frame &&
569 !navigation_state_.GetNavigationCommitted(main_frame_id)) {
570 return;
571 }
572
573 navigation_state_.TrackFrame(frame_id,
574 validated_url,
575 is_main_frame,
576 is_error_page);
577 if (!navigation_state_.CanSendEvents(frame_id))
578 return;
579 DispatchOnBeforeNavigate(
580 web_contents(), frame_id, is_main_frame, validated_url);
581 }
582
583 void ExtensionWebNavigationTabObserver::DidCommitProvisionalLoadForFrame(
584 int64 frame_id,
585 bool is_main_frame,
586 const GURL& url,
587 content::PageTransition transition_type) {
588 if (!navigation_state_.CanSendEvents(frame_id))
589 return;
590
591 bool is_reference_fragment_navigation =
592 IsReferenceFragmentNavigation(frame_id, url);
593
594 // Update the URL as it might have changed.
595 navigation_state_.UpdateFrame(frame_id, url);
596 navigation_state_.SetNavigationCommitted(frame_id);
597
598 if (is_reference_fragment_navigation) {
599 DispatchOnCommitted(
600 keys::kOnReferenceFragmentUpdated,
601 web_contents(),
602 frame_id,
603 is_main_frame,
604 url,
605 transition_type);
606 navigation_state_.SetNavigationCompleted(frame_id);
607 } else {
608 if (navigation_state_.GetIsServerRedirected(frame_id)) {
609 transition_type = static_cast<content::PageTransition>(
610 transition_type | content::PAGE_TRANSITION_SERVER_REDIRECT);
611 }
612 DispatchOnCommitted(
613 keys::kOnCommitted,
614 web_contents(),
615 frame_id,
616 is_main_frame,
617 url,
618 transition_type);
619 }
620 }
621
622 void ExtensionWebNavigationTabObserver::DidFailProvisionalLoad(
623 int64 frame_id,
624 bool is_main_frame,
625 const GURL& validated_url,
626 int error_code,
627 const string16& error_description) {
628 if (!navigation_state_.CanSendEvents(frame_id))
629 return;
630 navigation_state_.SetErrorOccurredInFrame(frame_id);
631 DispatchOnErrorOccurred(
632 web_contents(), validated_url, frame_id, is_main_frame, error_code);
633 }
634
635 void ExtensionWebNavigationTabObserver::DocumentLoadedInFrame(
636 int64 frame_id) {
637 if (!navigation_state_.CanSendEvents(frame_id))
638 return;
639 DispatchOnDOMContentLoaded(web_contents(),
640 navigation_state_.GetUrl(frame_id),
641 navigation_state_.IsMainFrame(frame_id),
642 frame_id);
643 }
644
645 void ExtensionWebNavigationTabObserver::DidFinishLoad(
646 int64 frame_id,
647 const GURL& validated_url,
648 bool is_main_frame) {
649 if (!navigation_state_.CanSendEvents(frame_id))
650 return;
651 navigation_state_.SetNavigationCompleted(frame_id);
652 DCHECK_EQ(navigation_state_.GetUrl(frame_id), validated_url);
653 DCHECK_EQ(navigation_state_.IsMainFrame(frame_id), is_main_frame);
654 DispatchOnCompleted(web_contents(),
655 validated_url,
656 is_main_frame,
657 frame_id);
658 }
659
660 void ExtensionWebNavigationTabObserver::DidOpenRequestedURL(
661 WebContents* new_contents,
662 const GURL& url,
663 const content::Referrer& referrer,
664 WindowOpenDisposition disposition,
665 content::PageTransition transition,
666 int64 source_frame_id) {
667 if (!navigation_state_.CanSendEvents(source_frame_id))
668 return;
669
670 // We only send the onCreatedNavigationTarget if we end up creating a new
671 // window.
672 if (disposition != SINGLETON_TAB &&
673 disposition != NEW_FOREGROUND_TAB &&
674 disposition != NEW_BACKGROUND_TAB &&
675 disposition != NEW_POPUP &&
676 disposition != NEW_WINDOW &&
677 disposition != OFF_THE_RECORD)
678 return;
679
680 DispatchOnCreatedNavigationTarget(
681 web_contents(),
682 new_contents->GetBrowserContext(),
683 source_frame_id,
684 navigation_state_.IsMainFrame(source_frame_id),
685 new_contents,
686 url);
687 }
688
689 void ExtensionWebNavigationTabObserver::WebContentsDestroyed(WebContents* tab) {
690 g_tab_observer.Get().erase(tab);
691 for (FrameNavigationState::const_iterator frame = navigation_state_.begin();
692 frame != navigation_state_.end(); ++frame) {
693 if (!navigation_state_.GetNavigationCompleted(*frame) &&
694 navigation_state_.CanSendEvents(*frame)) {
695 DispatchOnErrorOccurred(
696 tab,
697 navigation_state_.GetUrl(*frame),
698 *frame,
699 navigation_state_.IsMainFrame(*frame),
700 net::ERR_ABORTED);
701 }
702 }
703 }
704
705 // See also NavigationController::IsURLInPageNavigation.
706 bool ExtensionWebNavigationTabObserver::IsReferenceFragmentNavigation(
707 int64 frame_id,
708 const GURL& url) {
709 GURL existing_url = navigation_state_.GetUrl(frame_id);
710 if (existing_url == url)
711 return false;
712
713 url_canon::Replacements<char> replacements;
714 replacements.ClearRef();
715 return existing_url.ReplaceComponents(replacements) ==
716 url.ReplaceComponents(replacements);
717 }
718
719 bool GetFrameFunction::RunImpl() {
720 DictionaryValue* details;
721 EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(0, &details));
722 DCHECK(details);
723
724 int tab_id;
725 int frame_id;
726 EXTENSION_FUNCTION_VALIDATE(details->GetInteger(keys::kTabIdKey, &tab_id));
727 EXTENSION_FUNCTION_VALIDATE(
728 details->GetInteger(keys::kFrameIdKey, &frame_id));
729
730 result_.reset(Value::CreateNullValue());
731
732 TabContentsWrapper* wrapper;
733 if (!ExtensionTabUtil::GetTabById(
734 tab_id, profile(), include_incognito(), NULL, NULL, &wrapper, NULL) ||
735 !wrapper) {
736 return true;
737 }
738
739 WebContents* web_contents = wrapper->web_contents();
740 ExtensionWebNavigationTabObserver* observer =
741 ExtensionWebNavigationTabObserver::Get(web_contents);
742 DCHECK(observer);
743
744 const FrameNavigationState& frame_navigation_state =
745 observer->frame_navigation_state();
746
747 if (frame_id == 0)
748 frame_id = frame_navigation_state.GetMainFrameID();
749 if (!frame_navigation_state.IsValidFrame(frame_id))
750 return true;
751
752 GURL frame_url = frame_navigation_state.GetUrl(frame_id);
753 if (!frame_navigation_state.IsValidUrl(frame_url))
754 return true;
755
756 DictionaryValue* resultDict = new DictionaryValue();
757 resultDict->SetString(keys::kUrlKey, frame_url.spec());
758 resultDict->SetBoolean(
759 keys::kErrorOccurredKey,
760 frame_navigation_state.GetErrorOccurredInFrame(frame_id));
761 result_.reset(resultDict);
762 return true;
763 }
764
765 bool GetAllFramesFunction::RunImpl() {
766 DictionaryValue* details;
767 EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(0, &details));
768 DCHECK(details);
769
770 int tab_id;
771 EXTENSION_FUNCTION_VALIDATE(details->GetInteger(keys::kTabIdKey, &tab_id));
772
773 result_.reset(Value::CreateNullValue());
774
775 TabContentsWrapper* wrapper;
776 if (!ExtensionTabUtil::GetTabById(
777 tab_id, profile(), include_incognito(), NULL, NULL, &wrapper, NULL) ||
778 !wrapper) {
779 return true;
780 }
781
782 WebContents* web_contents = wrapper->web_contents();
783 ExtensionWebNavigationTabObserver* observer =
784 ExtensionWebNavigationTabObserver::Get(web_contents);
785 DCHECK(observer);
786
787 const FrameNavigationState& navigation_state =
788 observer->frame_navigation_state();
789
790 ListValue* resultList = new ListValue();
791 for (FrameNavigationState::const_iterator frame = navigation_state.begin();
792 frame != navigation_state.end(); ++frame) {
793 GURL frame_url = navigation_state.GetUrl(*frame);
794 if (!navigation_state.IsValidUrl(frame_url))
795 continue;
796 DictionaryValue* frameDict = new DictionaryValue();
797 frameDict->SetString(keys::kUrlKey, frame_url.spec());
798 frameDict->SetInteger(
799 keys::kFrameIdKey,
800 GetFrameId(navigation_state.IsMainFrame(*frame), *frame));
801 frameDict->SetBoolean(
802 keys::kErrorOccurredKey,
803 navigation_state.GetErrorOccurredInFrame(*frame));
804 resultList->Append(frameDict);
805 }
806 result_.reset(resultList);
807 return true;
808 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698