Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(369)

Side by Side Diff: chrome/browser/extensions/extension_tabs_module.cc

Issue 9225010: Fix callback for chrome.tabs.update with javascript URLs. (Closed) Base URL: http://git.chromium.org/chromium/src.git@master
Patch Set: nits Created 8 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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"
(...skipping 1040 matching lines...) Expand 10 before | Expand all | Expand 10 after
1051 error_ = keys::kNoHighlightedTabError; 1051 error_ = keys::kNoHighlightedTabError;
1052 return false; 1052 return false;
1053 } 1053 }
1054 1054
1055 selection.set_active(active_index); 1055 selection.set_active(active_index);
1056 browser->tabstrip_model()->SetSelectionFromModel(selection); 1056 browser->tabstrip_model()->SetSelectionFromModel(selection);
1057 result_.reset(ExtensionTabUtil::CreateWindowValue(browser, true)); 1057 result_.reset(ExtensionTabUtil::CreateWindowValue(browser, true));
1058 return true; 1058 return true;
1059 } 1059 }
1060 1060
1061 UpdateTabFunction::UpdateTabFunction() { 1061 UpdateTabFunction::UpdateTabFunction() : web_contents_(NULL) {
1062 } 1062 }
1063 1063
1064 bool UpdateTabFunction::RunImpl() { 1064 bool UpdateTabFunction::RunImpl() {
1065 DictionaryValue* update_props = NULL; 1065 DictionaryValue* update_props = NULL;
1066 EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(1, &update_props)); 1066 EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(1, &update_props));
1067 1067
1068 Value* tab_value = NULL; 1068 Value* tab_value = NULL;
1069 if (HasOptionalArgument(0)) { 1069 if (HasOptionalArgument(0)) {
1070 EXTENSION_FUNCTION_VALIDATE(args_->Get(0, &tab_value)); 1070 EXTENSION_FUNCTION_VALIDATE(args_->Get(0, &tab_value));
1071 } 1071 }
(...skipping 15 matching lines...) Expand all
1087 } else { 1087 } else {
1088 EXTENSION_FUNCTION_VALIDATE(tab_value->GetAsInteger(&tab_id)); 1088 EXTENSION_FUNCTION_VALIDATE(tab_value->GetAsInteger(&tab_id));
1089 } 1089 }
1090 1090
1091 int tab_index = -1; 1091 int tab_index = -1;
1092 TabStripModel* tab_strip = NULL; 1092 TabStripModel* tab_strip = NULL;
1093 if (!GetTabById(tab_id, profile(), include_incognito(), 1093 if (!GetTabById(tab_id, profile(), include_incognito(),
1094 NULL, &tab_strip, &contents, &tab_index, &error_)) { 1094 NULL, &tab_strip, &contents, &tab_index, &error_)) {
1095 return false; 1095 return false;
1096 } 1096 }
1097 NavigationController& controller = contents->web_contents()->GetController(); 1097
1098 web_contents_ = contents->web_contents();
1099 NavigationController& controller = web_contents_->GetController();
1098 1100
1099 // TODO(rafaelw): handle setting remaining tab properties: 1101 // TODO(rafaelw): handle setting remaining tab properties:
1100 // -title 1102 // -title
1101 // -favIconUrl 1103 // -favIconUrl
1102 1104
1105 // We wait to fire the callback when executing 'javascript:' URLs in tabs.
1106 bool is_async = false;
1107
1103 // Navigate the tab to a new location if the url is different. 1108 // Navigate the tab to a new location if the url is different.
1104 std::string url_string; 1109 std::string url_string;
1105 if (update_props->HasKey(keys::kUrlKey)) { 1110 if (update_props->HasKey(keys::kUrlKey)) {
1106 EXTENSION_FUNCTION_VALIDATE(update_props->GetString( 1111 EXTENSION_FUNCTION_VALIDATE(update_props->GetString(
1107 keys::kUrlKey, &url_string)); 1112 keys::kUrlKey, &url_string));
1108 GURL url = ResolvePossiblyRelativeURL(url_string, GetExtension()); 1113 GURL url = ResolvePossiblyRelativeURL(url_string, GetExtension());
1109 1114
1110 if (!url.is_valid()) { 1115 if (!url.is_valid()) {
1111 error_ = ExtensionErrorUtils::FormatErrorMessage(keys::kInvalidUrlError, 1116 error_ = ExtensionErrorUtils::FormatErrorMessage(keys::kInvalidUrlError,
1112 url_string); 1117 url_string);
1113 return false; 1118 return false;
1114 } 1119 }
1115 1120
1116 // Don't let the extension crash the browser or renderers. 1121 // Don't let the extension crash the browser or renderers.
1117 if (IsCrashURL(url)) { 1122 if (IsCrashURL(url)) {
1118 error_ = keys::kNoCrashBrowserError; 1123 error_ = keys::kNoCrashBrowserError;
1119 return false; 1124 return false;
1120 } 1125 }
1121 1126
1122 // JavaScript URLs can do the same kinds of things as cross-origin XHR, so 1127 // JavaScript URLs can do the same kinds of things as cross-origin XHR, so
1123 // we need to check host permissions before allowing them. 1128 // we need to check host permissions before allowing them.
1124 if (url.SchemeIs(chrome::kJavaScriptScheme)) { 1129 if (url.SchemeIs(chrome::kJavaScriptScheme)) {
1125 if (!GetExtension()->CanExecuteScriptOnPage( 1130 if (!GetExtension()->CanExecuteScriptOnPage(
1126 contents->web_contents()->GetURL(), NULL, &error_)) { 1131 web_contents_->GetURL(), NULL, &error_)) {
1127 return false; 1132 return false;
1128 } 1133 }
1129 1134
1130 ExtensionMsg_ExecuteCode_Params params; 1135 ExtensionMsg_ExecuteCode_Params params;
1131 params.request_id = request_id(); 1136 params.request_id = request_id();
1132 params.extension_id = extension_id(); 1137 params.extension_id = extension_id();
1133 params.is_javascript = true; 1138 params.is_javascript = true;
1134 params.code = url.path(); 1139 params.code = url.path();
1135 params.all_frames = false; 1140 params.all_frames = false;
1136 params.in_main_world = true; 1141 params.in_main_world = true;
1137 1142
1138 RenderViewHost* render_view_host = 1143 RenderViewHost* render_view_host = web_contents_->GetRenderViewHost();
1139 contents->web_contents()->GetRenderViewHost();
1140 render_view_host->Send( 1144 render_view_host->Send(
1141 new ExtensionMsg_ExecuteCode(render_view_host->routing_id(), 1145 new ExtensionMsg_ExecuteCode(render_view_host->routing_id(),
1142 params)); 1146 params));
1143 1147
1144 Observe(contents->web_contents()); 1148 Observe(web_contents_);
1145 AddRef(); // balanced in Observe() 1149 AddRef(); // Balanced in OnExecuteCodeFinished().
1146 1150
1147 return true; 1151 is_async = true;
1148 } 1152 }
1149 1153
1150 controller.LoadURL( 1154 controller.LoadURL(
1151 url, content::Referrer(), content::PAGE_TRANSITION_LINK, std::string()); 1155 url, content::Referrer(), content::PAGE_TRANSITION_LINK, std::string());
1152 1156
1153 // The URL of a tab contents never actually changes to a JavaScript URL, so 1157 // The URL of a tab contents never actually changes to a JavaScript URL, so
1154 // this check only makes sense in other cases. 1158 // this check only makes sense in other cases.
1155 if (!url.SchemeIs(chrome::kJavaScriptScheme)) 1159 if (!url.SchemeIs(chrome::kJavaScriptScheme))
1156 DCHECK_EQ(url.spec(), contents->web_contents()->GetURL().spec()); 1160 DCHECK_EQ(url.spec(), web_contents_->GetURL().spec());
1157 } 1161 }
1158 1162
1159 bool active = false; 1163 bool active = false;
1160 // TODO(rafaelw): Setting |active| from js doesn't make much sense. 1164 // TODO(rafaelw): Setting |active| from js doesn't make much sense.
1161 // Move tab selection management up to window. 1165 // Move tab selection management up to window.
1162 if (update_props->HasKey(keys::kSelectedKey)) 1166 if (update_props->HasKey(keys::kSelectedKey))
1163 EXTENSION_FUNCTION_VALIDATE(update_props->GetBoolean( 1167 EXTENSION_FUNCTION_VALIDATE(update_props->GetBoolean(
1164 keys::kSelectedKey, &active)); 1168 keys::kSelectedKey, &active));
1165 1169
1166 // The 'active' property has replaced 'selected'. 1170 // The 'active' property has replaced 'selected'.
1167 if (update_props->HasKey(keys::kActiveKey)) 1171 if (update_props->HasKey(keys::kActiveKey))
1168 EXTENSION_FUNCTION_VALIDATE(update_props->GetBoolean( 1172 EXTENSION_FUNCTION_VALIDATE(update_props->GetBoolean(
1169 keys::kActiveKey, &active)); 1173 keys::kActiveKey, &active));
1170 1174
1171 if (active) { 1175 if (active) {
1172 if (tab_strip->active_index() != tab_index) { 1176 if (tab_strip->active_index() != tab_index) {
1173 tab_strip->ActivateTabAt(tab_index, false); 1177 tab_strip->ActivateTabAt(tab_index, false);
1174 DCHECK_EQ(contents, tab_strip->GetActiveTabContents()); 1178 DCHECK_EQ(contents, tab_strip->GetActiveTabContents());
1175 } 1179 }
1176 contents->web_contents()->Focus(); 1180 web_contents_->Focus();
1177 } 1181 }
1178 1182
1179 if (update_props->HasKey(keys::kHighlightedKey)) { 1183 if (update_props->HasKey(keys::kHighlightedKey)) {
1180 bool highlighted = false; 1184 bool highlighted = false;
1181 EXTENSION_FUNCTION_VALIDATE(update_props->GetBoolean( 1185 EXTENSION_FUNCTION_VALIDATE(update_props->GetBoolean(
1182 keys::kHighlightedKey, &highlighted)); 1186 keys::kHighlightedKey, &highlighted));
1183 if (highlighted != tab_strip->IsTabSelected(tab_index)) 1187 if (highlighted != tab_strip->IsTabSelected(tab_index))
1184 tab_strip->ToggleSelectionAt(tab_index); 1188 tab_strip->ToggleSelectionAt(tab_index);
1185 } 1189 }
1186 1190
(...skipping 15 matching lines...) Expand all
1202 TabContentsWrapper* opener_contents = NULL; 1206 TabContentsWrapper* opener_contents = NULL;
1203 if (!ExtensionTabUtil::GetTabById( 1207 if (!ExtensionTabUtil::GetTabById(
1204 opener_id, profile(), include_incognito(), 1208 opener_id, profile(), include_incognito(),
1205 NULL, NULL, &opener_contents, NULL)) 1209 NULL, NULL, &opener_contents, NULL))
1206 return false; 1210 return false;
1207 1211
1208 tab_strip->SetOpenerOfTabContentsAt( 1212 tab_strip->SetOpenerOfTabContentsAt(
1209 tab_index, &opener_contents->web_contents()->GetController()); 1213 tab_index, &opener_contents->web_contents()->GetController());
1210 } 1214 }
1211 1215
1212 if (has_callback()) { 1216 if (!is_async) {
1213 if (GetExtension()->HasAPIPermission(ExtensionAPIPermission::kTab)) { 1217 PopulateResult();
1214 result_.reset(ExtensionTabUtil::CreateTabValue(contents->web_contents(), 1218 SendResponse(true);
1215 tab_strip,
1216 tab_index));
1217 } else {
1218 result_.reset(Value::CreateNullValue());
1219 }
1220 } 1219 }
1220 return true;
1221 }
1221 1222
1222 SendResponse(true); 1223 void UpdateTabFunction::PopulateResult() {
1223 return true; 1224 if (!has_callback())
1225 return;
1226
1227 if (GetExtension()->HasAPIPermission(ExtensionAPIPermission::kTab) &&
1228 web_contents_ != NULL) {
1229 result_.reset(ExtensionTabUtil::CreateTabValue(web_contents_));
1230 } else {
1231 result_.reset(Value::CreateNullValue());
1232 }
1233 }
1234
1235 void UpdateTabFunction::WebContentsDestroyed(WebContents* tab) {
1236 CHECK_EQ(tab, web_contents_);
1237 web_contents_ = NULL;
1224 } 1238 }
1225 1239
1226 bool UpdateTabFunction::OnMessageReceived(const IPC::Message& message) { 1240 bool UpdateTabFunction::OnMessageReceived(const IPC::Message& message) {
1227 if (message.type() != ExtensionHostMsg_ExecuteCodeFinished::ID) 1241 if (message.type() != ExtensionHostMsg_ExecuteCodeFinished::ID)
1228 return false; 1242 return false;
1229 1243
1230 int message_request_id = -1; 1244 int message_request_id = -1;
1231 void* iter = NULL; 1245 void* iter = NULL;
1232 if (!message.ReadInt(&iter, &message_request_id)) { 1246 if (!message.ReadInt(&iter, &message_request_id)) {
1233 NOTREACHED() << "malformed extension message"; 1247 NOTREACHED() << "malformed extension message";
(...skipping 11 matching lines...) Expand all
1245 } 1259 }
1246 1260
1247 void UpdateTabFunction::OnExecuteCodeFinished(int request_id, 1261 void UpdateTabFunction::OnExecuteCodeFinished(int request_id,
1248 bool success, 1262 bool success,
1249 const std::string& error) { 1263 const std::string& error) {
1250 if (!error.empty()) { 1264 if (!error.empty()) {
1251 CHECK(!success); 1265 CHECK(!success);
1252 error_ = error; 1266 error_ = error;
1253 } 1267 }
1254 1268
1269 if (success)
1270 PopulateResult();
1255 SendResponse(success); 1271 SendResponse(success);
1256 1272
1257 Observe(NULL); 1273 Observe(NULL);
1258 Release(); // balanced in Execute() 1274 Release(); // Balanced in RunImpl().
1259 } 1275 }
1260 1276
1261 bool MoveTabsFunction::RunImpl() { 1277 bool MoveTabsFunction::RunImpl() {
1262 Value* tab_value = NULL; 1278 Value* tab_value = NULL;
1263 EXTENSION_FUNCTION_VALIDATE(args_->Get(0, &tab_value)); 1279 EXTENSION_FUNCTION_VALIDATE(args_->Get(0, &tab_value));
1264 1280
1265 std::vector<int> tab_ids; 1281 std::vector<int> tab_ids;
1266 EXTENSION_FUNCTION_VALIDATE(ReadOneOrMoreIntegers(tab_value, &tab_ids)); 1282 EXTENSION_FUNCTION_VALIDATE(ReadOneOrMoreIntegers(tab_value, &tab_ids));
1267 1283
1268 DictionaryValue* update_props = NULL; 1284 DictionaryValue* update_props = NULL;
(...skipping 420 matching lines...) Expand 10 before | Expand all | Expand 10 after
1689 // called for every API call the extension made. 1705 // called for every API call the extension made.
1690 GotLanguage(language); 1706 GotLanguage(language);
1691 } 1707 }
1692 1708
1693 void DetectTabLanguageFunction::GotLanguage(const std::string& language) { 1709 void DetectTabLanguageFunction::GotLanguage(const std::string& language) {
1694 result_.reset(Value::CreateStringValue(language.c_str())); 1710 result_.reset(Value::CreateStringValue(language.c_str()));
1695 SendResponse(true); 1711 SendResponse(true);
1696 1712
1697 Release(); // Balanced in Run() 1713 Release(); // Balanced in Run()
1698 } 1714 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698