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