Home | History | Annotate | Download | only in web_navigation
      1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 // Implements the Chrome Extensions WebNavigation API.
      6 
      7 #include "chrome/browser/extensions/api/web_navigation/web_navigation_api_helpers.h"
      8 
      9 #include "base/json/json_writer.h"
     10 #include "base/strings/string_number_conversions.h"
     11 #include "base/time/time.h"
     12 #include "base/values.h"
     13 #include "chrome/browser/extensions/api/web_navigation/web_navigation_api_constants.h"
     14 #include "chrome/browser/extensions/event_router.h"
     15 #include "chrome/browser/extensions/extension_system.h"
     16 #include "chrome/browser/extensions/extension_tab_util.h"
     17 #include "chrome/browser/profiles/profile.h"
     18 #include "content/public/browser/render_process_host.h"
     19 #include "content/public/browser/render_view_host.h"
     20 #include "content/public/browser/web_contents.h"
     21 #include "extensions/common/event_filtering_info.h"
     22 #include "net/base/net_errors.h"
     23 
     24 namespace extensions {
     25 
     26 namespace keys = web_navigation_api_constants;
     27 
     28 namespace web_navigation_api_helpers {
     29 
     30 namespace {
     31 
     32 // Returns |time| as milliseconds since the epoch.
     33 double MilliSecondsFromTime(const base::Time& time) {
     34   return 1000 * time.ToDoubleT();
     35 }
     36 
     37 // Dispatches events to the extension message service.
     38 void DispatchEvent(content::BrowserContext* browser_context,
     39                    const char* event_name,
     40                    scoped_ptr<base::ListValue> args,
     41                    const GURL& url) {
     42   EventFilteringInfo info;
     43   info.SetURL(url);
     44 
     45   Profile* profile = Profile::FromBrowserContext(browser_context);
     46   if (profile && extensions::ExtensionSystem::Get(profile)->event_router()) {
     47     scoped_ptr<Event> event(new Event(event_name, args.Pass()));
     48     event->restrict_to_profile = profile;
     49     event->filter_info = info;
     50     ExtensionSystem::Get(profile)->event_router()->BroadcastEvent(event.Pass());
     51   }
     52 }
     53 
     54 }  // namespace
     55 
     56 int GetFrameId(bool is_main_frame, int64 frame_id) {
     57   return is_main_frame ? 0 : static_cast<int>(frame_id);
     58 }
     59 
     60 // Constructs and dispatches an onBeforeNavigate event.
     61 void DispatchOnBeforeNavigate(content::WebContents* web_contents,
     62                               int render_process_id,
     63                               int64 frame_id,
     64                               bool is_main_frame,
     65                               int64 parent_frame_id,
     66                               bool parent_is_main_frame,
     67                               const GURL& validated_url) {
     68   scoped_ptr<base::ListValue> args(new base::ListValue());
     69   base::DictionaryValue* dict = new base::DictionaryValue();
     70   dict->SetInteger(keys::kTabIdKey, ExtensionTabUtil::GetTabId(web_contents));
     71   dict->SetString(keys::kUrlKey, validated_url.spec());
     72   dict->SetInteger(keys::kProcessIdKey, render_process_id);
     73   dict->SetInteger(keys::kFrameIdKey, GetFrameId(is_main_frame, frame_id));
     74   dict->SetInteger(keys::kParentFrameIdKey,
     75                    GetFrameId(parent_is_main_frame, parent_frame_id));
     76   dict->SetDouble(keys::kTimeStampKey, MilliSecondsFromTime(base::Time::Now()));
     77   args->Append(dict);
     78 
     79   DispatchEvent(web_contents->GetBrowserContext(),
     80                 keys::kOnBeforeNavigate,
     81                 args.Pass(),
     82                 validated_url);
     83 }
     84 
     85 // Constructs and dispatches an onCommitted or onReferenceFragmentUpdated
     86 // event.
     87 void DispatchOnCommitted(const char* event_name,
     88                          content::WebContents* web_contents,
     89                          int64 frame_id,
     90                          bool is_main_frame,
     91                          const GURL& url,
     92                          content::PageTransition transition_type) {
     93   scoped_ptr<base::ListValue> args(new base::ListValue());
     94   base::DictionaryValue* dict = new base::DictionaryValue();
     95   dict->SetInteger(keys::kTabIdKey, ExtensionTabUtil::GetTabId(web_contents));
     96   dict->SetString(keys::kUrlKey, url.spec());
     97   dict->SetInteger(keys::kProcessIdKey,
     98                    web_contents->GetRenderViewHost()->GetProcess()->GetID());
     99   dict->SetInteger(keys::kFrameIdKey, GetFrameId(is_main_frame, frame_id));
    100   dict->SetString(
    101       keys::kTransitionTypeKey,
    102       content::PageTransitionGetCoreTransitionString(transition_type));
    103   base::ListValue* qualifiers = new base::ListValue();
    104   if (transition_type & content::PAGE_TRANSITION_CLIENT_REDIRECT)
    105     qualifiers->Append(Value::CreateStringValue("client_redirect"));
    106   if (transition_type & content::PAGE_TRANSITION_SERVER_REDIRECT)
    107     qualifiers->Append(Value::CreateStringValue("server_redirect"));
    108   if (transition_type & content::PAGE_TRANSITION_FORWARD_BACK)
    109     qualifiers->Append(Value::CreateStringValue("forward_back"));
    110   if (transition_type & content::PAGE_TRANSITION_FROM_ADDRESS_BAR)
    111     qualifiers->Append(Value::CreateStringValue("from_address_bar"));
    112   dict->Set(keys::kTransitionQualifiersKey, qualifiers);
    113   dict->SetDouble(keys::kTimeStampKey, MilliSecondsFromTime(base::Time::Now()));
    114   args->Append(dict);
    115 
    116   DispatchEvent(web_contents->GetBrowserContext(), event_name, args.Pass(),
    117                 url);
    118 }
    119 
    120 // Constructs and dispatches an onDOMContentLoaded event.
    121 void DispatchOnDOMContentLoaded(content::WebContents* web_contents,
    122                                 const GURL& url,
    123                                 bool is_main_frame,
    124                                 int64 frame_id) {
    125   scoped_ptr<base::ListValue> args(new base::ListValue());
    126   base::DictionaryValue* dict = new base::DictionaryValue();
    127   dict->SetInteger(keys::kTabIdKey,
    128                    ExtensionTabUtil::GetTabId(web_contents));
    129   dict->SetString(keys::kUrlKey, url.spec());
    130   dict->SetInteger(keys::kProcessIdKey,
    131                    web_contents->GetRenderViewHost()->GetProcess()->GetID());
    132   dict->SetInteger(keys::kFrameIdKey, GetFrameId(is_main_frame, frame_id));
    133   dict->SetDouble(keys::kTimeStampKey, MilliSecondsFromTime(base::Time::Now()));
    134   args->Append(dict);
    135 
    136   DispatchEvent(web_contents->GetBrowserContext(),
    137                 keys::kOnDOMContentLoaded,
    138                 args.Pass(),
    139                 url);
    140 }
    141 
    142 // Constructs and dispatches an onCompleted event.
    143 void DispatchOnCompleted(content::WebContents* web_contents,
    144                          const GURL& url,
    145                          bool is_main_frame,
    146                          int64 frame_id) {
    147   scoped_ptr<base::ListValue> args(new base::ListValue());
    148   base::DictionaryValue* dict = new base::DictionaryValue();
    149   dict->SetInteger(keys::kTabIdKey,
    150                    ExtensionTabUtil::GetTabId(web_contents));
    151   dict->SetString(keys::kUrlKey, url.spec());
    152   dict->SetInteger(keys::kProcessIdKey,
    153                    web_contents->GetRenderViewHost()->GetProcess()->GetID());
    154   dict->SetInteger(keys::kFrameIdKey, GetFrameId(is_main_frame, frame_id));
    155   dict->SetDouble(keys::kTimeStampKey, MilliSecondsFromTime(base::Time::Now()));
    156   args->Append(dict);
    157 
    158   DispatchEvent(web_contents->GetBrowserContext(), keys::kOnCompleted,
    159                 args.Pass(), url);
    160 }
    161 
    162 // Constructs and dispatches an onCreatedNavigationTarget event.
    163 void DispatchOnCreatedNavigationTarget(
    164     content::WebContents* web_contents,
    165     content::BrowserContext* browser_context,
    166     int64 source_frame_id,
    167     bool source_frame_is_main_frame,
    168     content::WebContents* target_web_contents,
    169     const GURL& target_url) {
    170   // Check that the tab is already inserted into a tab strip model. This code
    171   // path is exercised by ExtensionApiTest.WebNavigationRequestOpenTab.
    172   DCHECK(ExtensionTabUtil::GetTabById(
    173       ExtensionTabUtil::GetTabId(target_web_contents),
    174       Profile::FromBrowserContext(target_web_contents->GetBrowserContext()),
    175       false, NULL, NULL, NULL, NULL));
    176 
    177   scoped_ptr<base::ListValue> args(new base::ListValue());
    178   base::DictionaryValue* dict = new base::DictionaryValue();
    179   dict->SetInteger(keys::kSourceTabIdKey,
    180                    ExtensionTabUtil::GetTabId(web_contents));
    181   dict->SetInteger(keys::kSourceProcessIdKey,
    182                    web_contents->GetRenderViewHost()->GetProcess()->GetID());
    183   dict->SetInteger(keys::kSourceFrameIdKey,
    184       GetFrameId(source_frame_is_main_frame, source_frame_id));
    185   dict->SetString(keys::kUrlKey, target_url.possibly_invalid_spec());
    186   dict->SetInteger(keys::kTabIdKey,
    187                    ExtensionTabUtil::GetTabId(target_web_contents));
    188   dict->SetDouble(keys::kTimeStampKey, MilliSecondsFromTime(base::Time::Now()));
    189   args->Append(dict);
    190 
    191   DispatchEvent(browser_context, keys::kOnCreatedNavigationTarget, args.Pass(),
    192                 target_url);
    193 }
    194 
    195 // Constructs and dispatches an onErrorOccurred event.
    196 void DispatchOnErrorOccurred(content::WebContents* web_contents,
    197                              int render_process_id,
    198                              const GURL& url,
    199                              int64 frame_id,
    200                              bool is_main_frame,
    201                              int error_code) {
    202   scoped_ptr<base::ListValue> args(new base::ListValue());
    203   base::DictionaryValue* dict = new base::DictionaryValue();
    204   dict->SetInteger(keys::kTabIdKey, ExtensionTabUtil::GetTabId(web_contents));
    205   dict->SetString(keys::kUrlKey, url.spec());
    206   dict->SetInteger(keys::kProcessIdKey, render_process_id);
    207   dict->SetInteger(keys::kFrameIdKey, GetFrameId(is_main_frame, frame_id));
    208   dict->SetString(keys::kErrorKey, net::ErrorToString(error_code));
    209   dict->SetDouble(keys::kTimeStampKey, MilliSecondsFromTime(base::Time::Now()));
    210   args->Append(dict);
    211 
    212   DispatchEvent(web_contents->GetBrowserContext(), keys::kOnErrorOccurred,
    213                 args.Pass(), url);
    214 }
    215 
    216 // Constructs and dispatches an onTabReplaced event.
    217 void DispatchOnTabReplaced(
    218     content::WebContents* old_web_contents,
    219     content::BrowserContext* browser_context,
    220     content::WebContents* new_web_contents) {
    221   scoped_ptr<base::ListValue> args(new base::ListValue());
    222   base::DictionaryValue* dict = new base::DictionaryValue();
    223   dict->SetInteger(keys::kReplacedTabIdKey,
    224                    ExtensionTabUtil::GetTabId(old_web_contents));
    225   dict->SetInteger(keys::kTabIdKey,
    226                    ExtensionTabUtil::GetTabId(new_web_contents));
    227   dict->SetDouble(keys::kTimeStampKey, MilliSecondsFromTime(base::Time::Now()));
    228   args->Append(dict);
    229 
    230   DispatchEvent(browser_context, keys::kOnTabReplaced, args.Pass(), GURL());
    231 }
    232 
    233 }  // namespace web_navigation_api_helpers
    234 
    235 }  // namespace extensions
    236