OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/browser/extensions/extension_tabs_module.h" | 5 #include "chrome/browser/extensions/extension_tabs_module.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 #include <limits> | 8 #include <limits> |
9 #include <vector> | 9 #include <vector> |
10 | 10 |
11 #include "base/base64.h" | 11 #include "base/base64.h" |
12 #include "base/bind.h" | 12 #include "base/bind.h" |
13 #include "base/logging.h" | 13 #include "base/logging.h" |
14 #include "base/memory/ref_counted_memory.h" | 14 #include "base/memory/ref_counted_memory.h" |
15 #include "base/message_loop.h" | 15 #include "base/message_loop.h" |
16 #include "base/stl_util.h" | 16 #include "base/stl_util.h" |
17 #include "base/string16.h" | 17 #include "base/string16.h" |
18 #include "base/string_number_conversions.h" | 18 #include "base/string_number_conversions.h" |
19 #include "base/string_util.h" | 19 #include "base/string_util.h" |
20 #include "base/stringprintf.h" | 20 #include "base/stringprintf.h" |
21 #include "base/utf_string_conversions.h" | 21 #include "base/utf_string_conversions.h" |
22 #include "chrome/browser/extensions/extension_function_dispatcher.h" | 22 #include "chrome/browser/extensions/extension_function_dispatcher.h" |
23 #include "chrome/browser/extensions/extension_host.h" | 23 #include "chrome/browser/extensions/extension_host.h" |
24 #include "chrome/browser/extensions/extension_service.h" | 24 #include "chrome/browser/extensions/extension_service.h" |
25 #include "chrome/browser/extensions/extension_tab_helper.h" | 25 #include "chrome/browser/extensions/extension_tab_helper.h" |
26 #include "chrome/browser/extensions/extension_tab_util.h" | 26 #include "chrome/browser/extensions/extension_tab_util.h" |
27 #include "chrome/browser/extensions/extension_tabs_module_constants.h" | 27 #include "chrome/browser/extensions/extension_tabs_module_constants.h" |
28 #include "chrome/browser/extensions/extension_window_controller.h" | 28 #include "chrome/browser/extensions/extension_window_controller.h" |
29 #include "chrome/browser/extensions/extension_window_list.h" | 29 #include "chrome/browser/extensions/extension_window_list.h" |
| 30 #include "chrome/browser/extensions/script_executor.h" |
30 #include "chrome/browser/prefs/incognito_mode_prefs.h" | 31 #include "chrome/browser/prefs/incognito_mode_prefs.h" |
31 #include "chrome/browser/profiles/profile.h" | 32 #include "chrome/browser/profiles/profile.h" |
32 #include "chrome/browser/sessions/restore_tab_helper.h" | 33 #include "chrome/browser/sessions/restore_tab_helper.h" |
33 #include "chrome/browser/translate/translate_tab_helper.h" | 34 #include "chrome/browser/translate/translate_tab_helper.h" |
34 #include "chrome/browser/ui/browser.h" | 35 #include "chrome/browser/ui/browser.h" |
35 #include "chrome/browser/ui/browser_list.h" | 36 #include "chrome/browser/ui/browser_list.h" |
36 #include "chrome/browser/ui/browser_navigator.h" | 37 #include "chrome/browser/ui/browser_navigator.h" |
37 #include "chrome/browser/ui/browser_window.h" | 38 #include "chrome/browser/ui/browser_window.h" |
38 #include "chrome/browser/ui/extensions/shell_window.h" | 39 #include "chrome/browser/ui/extensions/shell_window.h" |
39 #include "chrome/browser/ui/panels/panel_manager.h" | 40 #include "chrome/browser/ui/panels/panel_manager.h" |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
81 namespace GetLastFocused = extensions::api::windows::GetLastFocused; | 82 namespace GetLastFocused = extensions::api::windows::GetLastFocused; |
82 namespace errors = extension_manifest_errors; | 83 namespace errors = extension_manifest_errors; |
83 namespace keys = extension_tabs_module_constants; | 84 namespace keys = extension_tabs_module_constants; |
84 | 85 |
85 using content::NavigationController; | 86 using content::NavigationController; |
86 using content::NavigationEntry; | 87 using content::NavigationEntry; |
87 using content::OpenURLParams; | 88 using content::OpenURLParams; |
88 using content::Referrer; | 89 using content::Referrer; |
89 using content::RenderViewHost; | 90 using content::RenderViewHost; |
90 using content::WebContents; | 91 using content::WebContents; |
| 92 using extensions::ScriptExecutor; |
91 | 93 |
92 const int CaptureVisibleTabFunction::kDefaultQuality = 90; | 94 const int CaptureVisibleTabFunction::kDefaultQuality = 90; |
93 | 95 |
94 namespace { | 96 namespace { |
95 | 97 |
96 // |error_message| can optionally be passed in a will be set with an appropriate | 98 // |error_message| can optionally be passed in a will be set with an appropriate |
97 // message if the window cannot be found by id. | 99 // message if the window cannot be found by id. |
98 Browser* GetBrowserInProfileWithId(Profile* profile, | 100 Browser* GetBrowserInProfileWithId(Profile* profile, |
99 const int window_id, | 101 const int window_id, |
100 bool include_incognito, | 102 bool include_incognito, |
(...skipping 1070 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1171 return false; | 1173 return false; |
1172 } | 1174 } |
1173 | 1175 |
1174 selection.set_active(active_index); | 1176 selection.set_active(active_index); |
1175 browser->tab_strip_model()->SetSelectionFromModel(selection); | 1177 browser->tab_strip_model()->SetSelectionFromModel(selection); |
1176 result_.reset( | 1178 result_.reset( |
1177 browser->extension_window_controller()->CreateWindowValueWithTabs()); | 1179 browser->extension_window_controller()->CreateWindowValueWithTabs()); |
1178 return true; | 1180 return true; |
1179 } | 1181 } |
1180 | 1182 |
1181 UpdateTabFunction::UpdateTabFunction() : web_contents_(NULL) { | 1183 UpdateTabFunction::UpdateTabFunction() : tab_contents_(NULL) { |
1182 } | 1184 } |
1183 | 1185 |
1184 bool UpdateTabFunction::RunImpl() { | 1186 bool UpdateTabFunction::RunImpl() { |
1185 DictionaryValue* update_props = NULL; | 1187 DictionaryValue* update_props = NULL; |
1186 EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(1, &update_props)); | 1188 EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(1, &update_props)); |
1187 | 1189 |
1188 Value* tab_value = NULL; | 1190 Value* tab_value = NULL; |
1189 if (HasOptionalArgument(0)) { | 1191 if (HasOptionalArgument(0)) { |
1190 EXTENSION_FUNCTION_VALIDATE(args_->Get(0, &tab_value)); | 1192 EXTENSION_FUNCTION_VALIDATE(args_->Get(0, &tab_value)); |
1191 } | 1193 } |
(...skipping 16 matching lines...) Expand all Loading... |
1208 EXTENSION_FUNCTION_VALIDATE(tab_value->GetAsInteger(&tab_id)); | 1210 EXTENSION_FUNCTION_VALIDATE(tab_value->GetAsInteger(&tab_id)); |
1209 } | 1211 } |
1210 | 1212 |
1211 int tab_index = -1; | 1213 int tab_index = -1; |
1212 TabStripModel* tab_strip = NULL; | 1214 TabStripModel* tab_strip = NULL; |
1213 if (!GetTabById(tab_id, profile(), include_incognito(), | 1215 if (!GetTabById(tab_id, profile(), include_incognito(), |
1214 NULL, &tab_strip, &contents, &tab_index, &error_)) { | 1216 NULL, &tab_strip, &contents, &tab_index, &error_)) { |
1215 return false; | 1217 return false; |
1216 } | 1218 } |
1217 | 1219 |
1218 web_contents_ = contents->web_contents(); | 1220 tab_contents_ = contents; |
1219 | 1221 |
1220 // TODO(rafaelw): handle setting remaining tab properties: | 1222 // TODO(rafaelw): handle setting remaining tab properties: |
1221 // -title | 1223 // -title |
1222 // -favIconUrl | 1224 // -favIconUrl |
1223 | 1225 |
1224 // Navigate the tab to a new location if the url is different. | 1226 // Navigate the tab to a new location if the url is different. |
1225 bool is_async = false; | 1227 bool is_async = false; |
1226 if (!UpdateURLIfPresent(update_props, &is_async)) | 1228 if (!UpdateURLIfPresent(update_props, &is_async)) |
1227 return false; | 1229 return false; |
1228 | 1230 |
1229 bool active = false; | 1231 bool active = false; |
1230 // TODO(rafaelw): Setting |active| from js doesn't make much sense. | 1232 // TODO(rafaelw): Setting |active| from js doesn't make much sense. |
1231 // Move tab selection management up to window. | 1233 // Move tab selection management up to window. |
1232 if (update_props->HasKey(keys::kSelectedKey)) | 1234 if (update_props->HasKey(keys::kSelectedKey)) |
1233 EXTENSION_FUNCTION_VALIDATE(update_props->GetBoolean( | 1235 EXTENSION_FUNCTION_VALIDATE(update_props->GetBoolean( |
1234 keys::kSelectedKey, &active)); | 1236 keys::kSelectedKey, &active)); |
1235 | 1237 |
1236 // The 'active' property has replaced 'selected'. | 1238 // The 'active' property has replaced 'selected'. |
1237 if (update_props->HasKey(keys::kActiveKey)) | 1239 if (update_props->HasKey(keys::kActiveKey)) |
1238 EXTENSION_FUNCTION_VALIDATE(update_props->GetBoolean( | 1240 EXTENSION_FUNCTION_VALIDATE(update_props->GetBoolean( |
1239 keys::kActiveKey, &active)); | 1241 keys::kActiveKey, &active)); |
1240 | 1242 |
1241 if (active) { | 1243 if (active) { |
1242 if (tab_strip->active_index() != tab_index) { | 1244 if (tab_strip->active_index() != tab_index) { |
1243 tab_strip->ActivateTabAt(tab_index, false); | 1245 tab_strip->ActivateTabAt(tab_index, false); |
1244 DCHECK_EQ(contents, tab_strip->GetActiveTabContents()); | 1246 DCHECK_EQ(contents, tab_strip->GetActiveTabContents()); |
1245 } | 1247 } |
1246 web_contents_->Focus(); | 1248 tab_contents_->web_contents()->Focus(); |
1247 } | 1249 } |
1248 | 1250 |
1249 if (update_props->HasKey(keys::kHighlightedKey)) { | 1251 if (update_props->HasKey(keys::kHighlightedKey)) { |
1250 bool highlighted = false; | 1252 bool highlighted = false; |
1251 EXTENSION_FUNCTION_VALIDATE(update_props->GetBoolean( | 1253 EXTENSION_FUNCTION_VALIDATE(update_props->GetBoolean( |
1252 keys::kHighlightedKey, &highlighted)); | 1254 keys::kHighlightedKey, &highlighted)); |
1253 if (highlighted != tab_strip->IsTabSelected(tab_index)) | 1255 if (highlighted != tab_strip->IsTabSelected(tab_index)) |
1254 tab_strip->ToggleSelectionAt(tab_index); | 1256 tab_strip->ToggleSelectionAt(tab_index); |
1255 } | 1257 } |
1256 | 1258 |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1306 // Don't let the extension crash the browser or renderers. | 1308 // Don't let the extension crash the browser or renderers. |
1307 if (ExtensionTabUtil::IsCrashURL(url)) { | 1309 if (ExtensionTabUtil::IsCrashURL(url)) { |
1308 error_ = keys::kNoCrashBrowserError; | 1310 error_ = keys::kNoCrashBrowserError; |
1309 return false; | 1311 return false; |
1310 } | 1312 } |
1311 | 1313 |
1312 // JavaScript URLs can do the same kinds of things as cross-origin XHR, so | 1314 // JavaScript URLs can do the same kinds of things as cross-origin XHR, so |
1313 // we need to check host permissions before allowing them. | 1315 // we need to check host permissions before allowing them. |
1314 if (url.SchemeIs(chrome::kJavaScriptScheme)) { | 1316 if (url.SchemeIs(chrome::kJavaScriptScheme)) { |
1315 if (!GetExtension()->CanExecuteScriptOnPage( | 1317 if (!GetExtension()->CanExecuteScriptOnPage( |
1316 web_contents_->GetURL(), NULL, &error_)) { | 1318 tab_contents_->web_contents()->GetURL(), NULL, &error_)) { |
1317 return false; | 1319 return false; |
1318 } | 1320 } |
1319 | 1321 |
1320 ExtensionMsg_ExecuteCode_Params params; | 1322 tab_contents_->extension_script_executor()->ExecuteScript( |
1321 params.request_id = request_id(); | 1323 extension_id(), |
1322 params.extension_id = extension_id(); | 1324 ScriptExecutor::JAVASCRIPT, |
1323 params.is_javascript = true; | 1325 url.path(), |
1324 params.code = url.path(); | 1326 ScriptExecutor::TOP_FRAME, |
1325 params.run_at = UserScript::DOCUMENT_IDLE; | 1327 UserScript::DOCUMENT_IDLE, |
1326 params.all_frames = false; | 1328 ScriptExecutor::MAIN_WORLD, |
1327 params.in_main_world = true; | 1329 base::Bind(&UpdateTabFunction::OnExecuteCodeFinished, this)); |
1328 | |
1329 RenderViewHost* render_view_host = web_contents_->GetRenderViewHost(); | |
1330 render_view_host->Send( | |
1331 new ExtensionMsg_ExecuteCode(render_view_host->GetRoutingID(), params)); | |
1332 | |
1333 Observe(web_contents_); | |
1334 AddRef(); // Balanced in OnExecuteCodeFinished(). | |
1335 | 1330 |
1336 *is_async = true; | 1331 *is_async = true; |
1337 return true; | 1332 return true; |
1338 } | 1333 } |
1339 | 1334 |
1340 web_contents_->GetController().LoadURL( | 1335 tab_contents_->web_contents()->GetController().LoadURL( |
1341 url, content::Referrer(), content::PAGE_TRANSITION_LINK, std::string()); | 1336 url, content::Referrer(), content::PAGE_TRANSITION_LINK, std::string()); |
1342 | 1337 |
1343 // The URL of a tab contents never actually changes to a JavaScript URL, so | 1338 // The URL of a tab contents never actually changes to a JavaScript URL, so |
1344 // this check only makes sense in other cases. | 1339 // this check only makes sense in other cases. |
1345 if (!url.SchemeIs(chrome::kJavaScriptScheme)) | 1340 if (!url.SchemeIs(chrome::kJavaScriptScheme)) |
1346 DCHECK_EQ(url.spec(), web_contents_->GetURL().spec()); | 1341 DCHECK_EQ(url.spec(), tab_contents_->web_contents()->GetURL().spec()); |
1347 | 1342 |
1348 return true; | 1343 return true; |
1349 } | 1344 } |
1350 | 1345 |
1351 void UpdateTabFunction::PopulateResult() { | 1346 void UpdateTabFunction::PopulateResult() { |
1352 if (!has_callback()) | 1347 if (!has_callback()) |
1353 return; | 1348 return; |
1354 | 1349 |
1355 if (GetExtension()->HasAPIPermission(ExtensionAPIPermission::kTab) && | 1350 if (GetExtension()->HasAPIPermission(ExtensionAPIPermission::kTab)) { |
1356 web_contents_ != NULL) { | 1351 result_.reset( |
1357 result_.reset(ExtensionTabUtil::CreateTabValue(web_contents_)); | 1352 ExtensionTabUtil::CreateTabValue(tab_contents_->web_contents())); |
1358 } else { | 1353 } else { |
1359 result_.reset(Value::CreateNullValue()); | 1354 result_.reset(Value::CreateNullValue()); |
1360 } | 1355 } |
1361 } | 1356 } |
1362 | 1357 |
1363 void UpdateTabFunction::WebContentsDestroyed(WebContents* tab) { | 1358 void UpdateTabFunction::OnExecuteCodeFinished(bool success, |
1364 CHECK_EQ(tab, web_contents_); | |
1365 web_contents_ = NULL; | |
1366 } | |
1367 | |
1368 bool UpdateTabFunction::OnMessageReceived(const IPC::Message& message) { | |
1369 if (message.type() != ExtensionHostMsg_ExecuteCodeFinished::ID) | |
1370 return false; | |
1371 | |
1372 int message_request_id = -1; | |
1373 PickleIterator iter(message); | |
1374 if (!message.ReadInt(&iter, &message_request_id)) { | |
1375 NOTREACHED() << "malformed extension message"; | |
1376 return true; | |
1377 } | |
1378 | |
1379 if (message_request_id != request_id()) | |
1380 return false; | |
1381 | |
1382 IPC_BEGIN_MESSAGE_MAP(UpdateTabFunction, message) | |
1383 IPC_MESSAGE_HANDLER(ExtensionHostMsg_ExecuteCodeFinished, | |
1384 OnExecuteCodeFinished) | |
1385 IPC_END_MESSAGE_MAP() | |
1386 return true; | |
1387 } | |
1388 | |
1389 void UpdateTabFunction::OnExecuteCodeFinished(int request_id, | |
1390 bool success, | |
1391 const std::string& error) { | 1359 const std::string& error) { |
1392 if (!error.empty()) { | 1360 if (!error.empty()) { |
1393 CHECK(!success); | 1361 CHECK(!success); |
1394 error_ = error; | 1362 error_ = error; |
1395 } | 1363 } |
1396 | 1364 |
1397 if (success) | 1365 if (success) |
1398 PopulateResult(); | 1366 PopulateResult(); |
1399 SendResponse(success); | 1367 SendResponse(success); |
1400 | |
1401 Observe(NULL); | |
1402 Release(); // Balanced in UpdateURLIfPresent(). | |
1403 } | 1368 } |
1404 | 1369 |
1405 bool MoveTabsFunction::RunImpl() { | 1370 bool MoveTabsFunction::RunImpl() { |
1406 Value* tab_value = NULL; | 1371 Value* tab_value = NULL; |
1407 EXTENSION_FUNCTION_VALIDATE(args_->Get(0, &tab_value)); | 1372 EXTENSION_FUNCTION_VALIDATE(args_->Get(0, &tab_value)); |
1408 | 1373 |
1409 std::vector<int> tab_ids; | 1374 std::vector<int> tab_ids; |
1410 EXTENSION_FUNCTION_VALIDATE(ReadOneOrMoreIntegers(tab_value, &tab_ids)); | 1375 EXTENSION_FUNCTION_VALIDATE(ReadOneOrMoreIntegers(tab_value, &tab_ids)); |
1411 | 1376 |
1412 DictionaryValue* update_props = NULL; | 1377 DictionaryValue* update_props = NULL; |
(...skipping 437 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1850 // called for every API call the extension made. | 1815 // called for every API call the extension made. |
1851 GotLanguage(language); | 1816 GotLanguage(language); |
1852 } | 1817 } |
1853 | 1818 |
1854 void DetectTabLanguageFunction::GotLanguage(const std::string& language) { | 1819 void DetectTabLanguageFunction::GotLanguage(const std::string& language) { |
1855 result_.reset(Value::CreateStringValue(language.c_str())); | 1820 result_.reset(Value::CreateStringValue(language.c_str())); |
1856 SendResponse(true); | 1821 SendResponse(true); |
1857 | 1822 |
1858 Release(); // Balanced in Run() | 1823 Release(); // Balanced in Run() |
1859 } | 1824 } |
OLD | NEW |