| 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 |