| 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 <vector> | 8 #include <vector> |
| 9 | 9 |
| 10 #include "base/base64.h" | 10 #include "base/base64.h" |
| 11 #include "base/bind.h" | 11 #include "base/bind.h" |
| 12 #include "base/logging.h" | 12 #include "base/logging.h" |
| 13 #include "base/memory/ref_counted_memory.h" | 13 #include "base/memory/ref_counted_memory.h" |
| 14 #include "base/message_loop.h" | 14 #include "base/message_loop.h" |
| 15 #include "base/stl_util.h" | 15 #include "base/stl_util.h" |
| 16 #include "base/string16.h" | 16 #include "base/string16.h" |
| 17 #include "base/string_number_conversions.h" | 17 #include "base/string_number_conversions.h" |
| 18 #include "base/string_util.h" | 18 #include "base/string_util.h" |
| 19 #include "base/stringprintf.h" | 19 #include "base/stringprintf.h" |
| 20 #include "base/utf_string_conversions.h" | 20 #include "base/utf_string_conversions.h" |
| 21 #include "chrome/browser/extensions/extension_function_dispatcher.h" | 21 #include "chrome/browser/extensions/extension_function_dispatcher.h" |
| 22 #include "chrome/browser/extensions/extension_host.h" | 22 #include "chrome/browser/extensions/extension_host.h" |
| 23 #include "chrome/browser/extensions/script_executor.h" |
| 23 #include "chrome/browser/extensions/extension_service.h" | 24 #include "chrome/browser/extensions/extension_service.h" |
| 24 #include "chrome/browser/extensions/extension_tab_helper.h" | 25 #include "chrome/browser/extensions/extension_tab_helper.h" |
| 25 #include "chrome/browser/extensions/extension_tab_util.h" | 26 #include "chrome/browser/extensions/extension_tab_util.h" |
| 26 #include "chrome/browser/extensions/extension_tabs_module_constants.h" | 27 #include "chrome/browser/extensions/extension_tabs_module_constants.h" |
| 27 #include "chrome/browser/extensions/extension_window_controller.h" | 28 #include "chrome/browser/extensions/extension_window_controller.h" |
| 28 #include "chrome/browser/extensions/extension_window_list.h" | 29 #include "chrome/browser/extensions/extension_window_list.h" |
| 29 #include "chrome/browser/prefs/incognito_mode_prefs.h" | 30 #include "chrome/browser/prefs/incognito_mode_prefs.h" |
| 30 #include "chrome/browser/profiles/profile.h" | 31 #include "chrome/browser/profiles/profile.h" |
| 31 #include "chrome/browser/sessions/restore_tab_helper.h" | 32 #include "chrome/browser/sessions/restore_tab_helper.h" |
| 32 #include "chrome/browser/tabs/tab_strip_model.h" | 33 #include "chrome/browser/tabs/tab_strip_model.h" |
| (...skipping 1136 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1169 return false; | 1170 return false; |
| 1170 } | 1171 } |
| 1171 | 1172 |
| 1172 selection.set_active(active_index); | 1173 selection.set_active(active_index); |
| 1173 browser->tabstrip_model()->SetSelectionFromModel(selection); | 1174 browser->tabstrip_model()->SetSelectionFromModel(selection); |
| 1174 result_.reset( | 1175 result_.reset( |
| 1175 browser->extension_window_controller()->CreateWindowValueWithTabs()); | 1176 browser->extension_window_controller()->CreateWindowValueWithTabs()); |
| 1176 return true; | 1177 return true; |
| 1177 } | 1178 } |
| 1178 | 1179 |
| 1179 UpdateTabFunction::UpdateTabFunction() : web_contents_(NULL) { | 1180 UpdateTabFunction::UpdateTabFunction() : tab_contents_(NULL) { |
| 1180 } | 1181 } |
| 1181 | 1182 |
| 1182 bool UpdateTabFunction::RunImpl() { | 1183 bool UpdateTabFunction::RunImpl() { |
| 1183 DictionaryValue* update_props = NULL; | 1184 DictionaryValue* update_props = NULL; |
| 1184 EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(1, &update_props)); | 1185 EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(1, &update_props)); |
| 1185 | 1186 |
| 1186 Value* tab_value = NULL; | 1187 Value* tab_value = NULL; |
| 1187 if (HasOptionalArgument(0)) { | 1188 if (HasOptionalArgument(0)) { |
| 1188 EXTENSION_FUNCTION_VALIDATE(args_->Get(0, &tab_value)); | 1189 EXTENSION_FUNCTION_VALIDATE(args_->Get(0, &tab_value)); |
| 1189 } | 1190 } |
| (...skipping 16 matching lines...) Expand all Loading... |
| 1206 EXTENSION_FUNCTION_VALIDATE(tab_value->GetAsInteger(&tab_id)); | 1207 EXTENSION_FUNCTION_VALIDATE(tab_value->GetAsInteger(&tab_id)); |
| 1207 } | 1208 } |
| 1208 | 1209 |
| 1209 int tab_index = -1; | 1210 int tab_index = -1; |
| 1210 TabStripModel* tab_strip = NULL; | 1211 TabStripModel* tab_strip = NULL; |
| 1211 if (!GetTabById(tab_id, profile(), include_incognito(), | 1212 if (!GetTabById(tab_id, profile(), include_incognito(), |
| 1212 NULL, &tab_strip, &contents, &tab_index, &error_)) { | 1213 NULL, &tab_strip, &contents, &tab_index, &error_)) { |
| 1213 return false; | 1214 return false; |
| 1214 } | 1215 } |
| 1215 | 1216 |
| 1216 web_contents_ = contents->web_contents(); | 1217 tab_contents_ = contents; |
| 1217 | 1218 |
| 1218 // TODO(rafaelw): handle setting remaining tab properties: | 1219 // TODO(rafaelw): handle setting remaining tab properties: |
| 1219 // -title | 1220 // -title |
| 1220 // -favIconUrl | 1221 // -favIconUrl |
| 1221 | 1222 |
| 1222 // Navigate the tab to a new location if the url is different. | 1223 // Navigate the tab to a new location if the url is different. |
| 1223 bool is_async = false; | 1224 bool is_async = false; |
| 1224 if (!UpdateURLIfPresent(update_props, &is_async)) | 1225 if (!UpdateURLIfPresent(update_props, &is_async)) |
| 1225 return false; | 1226 return false; |
| 1226 | 1227 |
| 1227 bool active = false; | 1228 bool active = false; |
| 1228 // TODO(rafaelw): Setting |active| from js doesn't make much sense. | 1229 // TODO(rafaelw): Setting |active| from js doesn't make much sense. |
| 1229 // Move tab selection management up to window. | 1230 // Move tab selection management up to window. |
| 1230 if (update_props->HasKey(keys::kSelectedKey)) | 1231 if (update_props->HasKey(keys::kSelectedKey)) |
| 1231 EXTENSION_FUNCTION_VALIDATE(update_props->GetBoolean( | 1232 EXTENSION_FUNCTION_VALIDATE(update_props->GetBoolean( |
| 1232 keys::kSelectedKey, &active)); | 1233 keys::kSelectedKey, &active)); |
| 1233 | 1234 |
| 1234 // The 'active' property has replaced 'selected'. | 1235 // The 'active' property has replaced 'selected'. |
| 1235 if (update_props->HasKey(keys::kActiveKey)) | 1236 if (update_props->HasKey(keys::kActiveKey)) |
| 1236 EXTENSION_FUNCTION_VALIDATE(update_props->GetBoolean( | 1237 EXTENSION_FUNCTION_VALIDATE(update_props->GetBoolean( |
| 1237 keys::kActiveKey, &active)); | 1238 keys::kActiveKey, &active)); |
| 1238 | 1239 |
| 1239 if (active) { | 1240 if (active) { |
| 1240 if (tab_strip->active_index() != tab_index) { | 1241 if (tab_strip->active_index() != tab_index) { |
| 1241 tab_strip->ActivateTabAt(tab_index, false); | 1242 tab_strip->ActivateTabAt(tab_index, false); |
| 1242 DCHECK_EQ(contents, tab_strip->GetActiveTabContents()); | 1243 DCHECK_EQ(contents, tab_strip->GetActiveTabContents()); |
| 1243 } | 1244 } |
| 1244 web_contents_->Focus(); | 1245 tab_contents_->web_contents()->Focus(); |
| 1245 } | 1246 } |
| 1246 | 1247 |
| 1247 if (update_props->HasKey(keys::kHighlightedKey)) { | 1248 if (update_props->HasKey(keys::kHighlightedKey)) { |
| 1248 bool highlighted = false; | 1249 bool highlighted = false; |
| 1249 EXTENSION_FUNCTION_VALIDATE(update_props->GetBoolean( | 1250 EXTENSION_FUNCTION_VALIDATE(update_props->GetBoolean( |
| 1250 keys::kHighlightedKey, &highlighted)); | 1251 keys::kHighlightedKey, &highlighted)); |
| 1251 if (highlighted != tab_strip->IsTabSelected(tab_index)) | 1252 if (highlighted != tab_strip->IsTabSelected(tab_index)) |
| 1252 tab_strip->ToggleSelectionAt(tab_index); | 1253 tab_strip->ToggleSelectionAt(tab_index); |
| 1253 } | 1254 } |
| 1254 | 1255 |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1304 // Don't let the extension crash the browser or renderers. | 1305 // Don't let the extension crash the browser or renderers. |
| 1305 if (ExtensionTabUtil::IsCrashURL(url)) { | 1306 if (ExtensionTabUtil::IsCrashURL(url)) { |
| 1306 error_ = keys::kNoCrashBrowserError; | 1307 error_ = keys::kNoCrashBrowserError; |
| 1307 return false; | 1308 return false; |
| 1308 } | 1309 } |
| 1309 | 1310 |
| 1310 // JavaScript URLs can do the same kinds of things as cross-origin XHR, so | 1311 // JavaScript URLs can do the same kinds of things as cross-origin XHR, so |
| 1311 // we need to check host permissions before allowing them. | 1312 // we need to check host permissions before allowing them. |
| 1312 if (url.SchemeIs(chrome::kJavaScriptScheme)) { | 1313 if (url.SchemeIs(chrome::kJavaScriptScheme)) { |
| 1313 if (!GetExtension()->CanExecuteScriptOnPage( | 1314 if (!GetExtension()->CanExecuteScriptOnPage( |
| 1314 web_contents_->GetURL(), NULL, &error_)) { | 1315 tab_contents_->web_contents()->GetURL(), NULL, &error_)) { |
| 1315 return false; | 1316 return false; |
| 1316 } | 1317 } |
| 1317 | 1318 |
| 1318 ExtensionMsg_ExecuteCode_Params params; | 1319 tab_contents_->extension_script_executor()->ExecuteScript( |
| 1319 params.request_id = request_id(); | 1320 extension_id(), |
| 1320 params.extension_id = extension_id(); | 1321 true, |
| 1321 params.is_javascript = true; | 1322 url.path(), |
| 1322 params.code = url.path(); | 1323 false, |
| 1323 params.run_at = UserScript::DOCUMENT_IDLE; | 1324 UserScript::DOCUMENT_IDLE, |
| 1324 params.all_frames = false; | 1325 true, |
| 1325 params.in_main_world = true; | 1326 base::Bind(&UpdateTabFunction::OnExecuteCodeFinished, this)); |
| 1326 | |
| 1327 RenderViewHost* render_view_host = web_contents_->GetRenderViewHost(); | |
| 1328 render_view_host->Send( | |
| 1329 new ExtensionMsg_ExecuteCode(render_view_host->GetRoutingID(), params)); | |
| 1330 | |
| 1331 Observe(web_contents_); | |
| 1332 AddRef(); // Balanced in OnExecuteCodeFinished(). | |
| 1333 | 1327 |
| 1334 *is_async = true; | 1328 *is_async = true; |
| 1335 return true; | 1329 return true; |
| 1336 } | 1330 } |
| 1337 | 1331 |
| 1338 web_contents_->GetController().LoadURL( | 1332 tab_contents_->web_contents()->GetController().LoadURL( |
| 1339 url, content::Referrer(), content::PAGE_TRANSITION_LINK, std::string()); | 1333 url, content::Referrer(), content::PAGE_TRANSITION_LINK, std::string()); |
| 1340 | 1334 |
| 1341 // The URL of a tab contents never actually changes to a JavaScript URL, so | 1335 // The URL of a tab contents never actually changes to a JavaScript URL, so |
| 1342 // this check only makes sense in other cases. | 1336 // this check only makes sense in other cases. |
| 1343 if (!url.SchemeIs(chrome::kJavaScriptScheme)) | 1337 if (!url.SchemeIs(chrome::kJavaScriptScheme)) |
| 1344 DCHECK_EQ(url.spec(), web_contents_->GetURL().spec()); | 1338 DCHECK_EQ(url.spec(), tab_contents_->web_contents()->GetURL().spec()); |
| 1345 | 1339 |
| 1346 return true; | 1340 return true; |
| 1347 } | 1341 } |
| 1348 | 1342 |
| 1349 void UpdateTabFunction::PopulateResult() { | 1343 void UpdateTabFunction::PopulateResult() { |
| 1350 if (!has_callback()) | 1344 if (!has_callback()) |
| 1351 return; | 1345 return; |
| 1352 | 1346 |
| 1353 if (GetExtension()->HasAPIPermission(ExtensionAPIPermission::kTab) && | 1347 if (GetExtension()->HasAPIPermission(ExtensionAPIPermission::kTab)) { |
| 1354 web_contents_ != NULL) { | 1348 result_.reset( |
| 1355 result_.reset(ExtensionTabUtil::CreateTabValue(web_contents_)); | 1349 ExtensionTabUtil::CreateTabValue(tab_contents_->web_contents())); |
| 1356 } else { | 1350 } else { |
| 1357 result_.reset(Value::CreateNullValue()); | 1351 result_.reset(Value::CreateNullValue()); |
| 1358 } | 1352 } |
| 1359 } | 1353 } |
| 1360 | 1354 |
| 1361 void UpdateTabFunction::WebContentsDestroyed(WebContents* tab) { | 1355 void UpdateTabFunction::OnExecuteCodeFinished(bool success, |
| 1362 CHECK_EQ(tab, web_contents_); | |
| 1363 web_contents_ = NULL; | |
| 1364 } | |
| 1365 | |
| 1366 bool UpdateTabFunction::OnMessageReceived(const IPC::Message& message) { | |
| 1367 if (message.type() != ExtensionHostMsg_ExecuteCodeFinished::ID) | |
| 1368 return false; | |
| 1369 | |
| 1370 int message_request_id = -1; | |
| 1371 PickleIterator iter(message); | |
| 1372 if (!message.ReadInt(&iter, &message_request_id)) { | |
| 1373 NOTREACHED() << "malformed extension message"; | |
| 1374 return true; | |
| 1375 } | |
| 1376 | |
| 1377 if (message_request_id != request_id()) | |
| 1378 return false; | |
| 1379 | |
| 1380 IPC_BEGIN_MESSAGE_MAP(UpdateTabFunction, message) | |
| 1381 IPC_MESSAGE_HANDLER(ExtensionHostMsg_ExecuteCodeFinished, | |
| 1382 OnExecuteCodeFinished) | |
| 1383 IPC_END_MESSAGE_MAP() | |
| 1384 return true; | |
| 1385 } | |
| 1386 | |
| 1387 void UpdateTabFunction::OnExecuteCodeFinished(int request_id, | |
| 1388 bool success, | |
| 1389 const std::string& error) { | 1356 const std::string& error) { |
| 1390 if (!error.empty()) { | 1357 if (!error.empty()) { |
| 1391 CHECK(!success); | 1358 CHECK(!success); |
| 1392 error_ = error; | 1359 error_ = error; |
| 1393 } | 1360 } |
| 1394 | 1361 |
| 1395 if (success) | 1362 if (success) |
| 1396 PopulateResult(); | 1363 PopulateResult(); |
| 1397 SendResponse(success); | 1364 SendResponse(success); |
| 1398 | |
| 1399 Observe(NULL); | |
| 1400 Release(); // Balanced in UpdateURLIfPresent(). | |
| 1401 } | 1365 } |
| 1402 | 1366 |
| 1403 bool MoveTabsFunction::RunImpl() { | 1367 bool MoveTabsFunction::RunImpl() { |
| 1404 Value* tab_value = NULL; | 1368 Value* tab_value = NULL; |
| 1405 EXTENSION_FUNCTION_VALIDATE(args_->Get(0, &tab_value)); | 1369 EXTENSION_FUNCTION_VALIDATE(args_->Get(0, &tab_value)); |
| 1406 | 1370 |
| 1407 std::vector<int> tab_ids; | 1371 std::vector<int> tab_ids; |
| 1408 EXTENSION_FUNCTION_VALIDATE(ReadOneOrMoreIntegers(tab_value, &tab_ids)); | 1372 EXTENSION_FUNCTION_VALIDATE(ReadOneOrMoreIntegers(tab_value, &tab_ids)); |
| 1409 | 1373 |
| 1410 DictionaryValue* update_props = NULL; | 1374 DictionaryValue* update_props = NULL; |
| (...skipping 436 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1847 // called for every API call the extension made. | 1811 // called for every API call the extension made. |
| 1848 GotLanguage(language); | 1812 GotLanguage(language); |
| 1849 } | 1813 } |
| 1850 | 1814 |
| 1851 void DetectTabLanguageFunction::GotLanguage(const std::string& language) { | 1815 void DetectTabLanguageFunction::GotLanguage(const std::string& language) { |
| 1852 result_.reset(Value::CreateStringValue(language.c_str())); | 1816 result_.reset(Value::CreateStringValue(language.c_str())); |
| 1853 SendResponse(true); | 1817 SendResponse(true); |
| 1854 | 1818 |
| 1855 Release(); // Balanced in Run() | 1819 Release(); // Balanced in Run() |
| 1856 } | 1820 } |
| OLD | NEW |