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

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: . Created 8 years, 11 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 1013 matching lines...) Expand 10 before | Expand all | Expand 10 after
1024 error_ = keys::kNoHighlightedTabError; 1024 error_ = keys::kNoHighlightedTabError;
1025 return false; 1025 return false;
1026 } 1026 }
1027 1027
1028 selection.set_active(active_index); 1028 selection.set_active(active_index);
1029 browser->tabstrip_model()->SetSelectionFromModel(selection); 1029 browser->tabstrip_model()->SetSelectionFromModel(selection);
1030 result_.reset(ExtensionTabUtil::CreateWindowValue(browser, true)); 1030 result_.reset(ExtensionTabUtil::CreateWindowValue(browser, true));
1031 return true; 1031 return true;
1032 } 1032 }
1033 1033
1034 UpdateTabFunction::UpdateTabFunction() { 1034 UpdateTabFunction::UpdateTabFunction()
1035 : web_contents_(NULL),
1036 tab_strip_(NULL),
1037 tab_index_(-1) {
1035 } 1038 }
1036 1039
1037 bool UpdateTabFunction::RunImpl() { 1040 bool UpdateTabFunction::RunImpl() {
1038 DictionaryValue* update_props = NULL; 1041 DictionaryValue* update_props = NULL;
1039 EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(1, &update_props)); 1042 EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(1, &update_props));
1040 1043
1041 Value* tab_value = NULL; 1044 Value* tab_value = NULL;
1042 if (HasOptionalArgument(0)) { 1045 if (HasOptionalArgument(0)) {
1043 EXTENSION_FUNCTION_VALIDATE(args_->Get(0, &tab_value)); 1046 EXTENSION_FUNCTION_VALIDATE(args_->Get(0, &tab_value));
1044 } 1047 }
1045 1048
1046 int tab_id = -1; 1049 int tab_id = -1;
1047 TabContentsWrapper* contents = NULL; 1050 TabContentsWrapper* contents = NULL;
1048 if (tab_value == NULL || tab_value->IsType(Value::TYPE_NULL)) { 1051 if (tab_value == NULL || tab_value->IsType(Value::TYPE_NULL)) {
1049 Browser* browser = GetCurrentBrowser(); 1052 Browser* browser = GetCurrentBrowser();
1050 if (!browser) { 1053 if (!browser) {
1051 error_ = keys::kNoCurrentWindowError; 1054 error_ = keys::kNoCurrentWindowError;
1052 return false; 1055 return false;
1053 } 1056 }
1054 contents = browser->tabstrip_model()->GetActiveTabContents(); 1057 contents = browser->tabstrip_model()->GetActiveTabContents();
1055 if (!contents) { 1058 if (!contents) {
1056 error_ = keys::kNoSelectedTabError; 1059 error_ = keys::kNoSelectedTabError;
1057 return false; 1060 return false;
1058 } 1061 }
1059 tab_id = ExtensionTabUtil::GetTabId(contents->web_contents()); 1062 tab_id = ExtensionTabUtil::GetTabId(contents->web_contents());
1060 } else { 1063 } else {
1061 EXTENSION_FUNCTION_VALIDATE(tab_value->GetAsInteger(&tab_id)); 1064 EXTENSION_FUNCTION_VALIDATE(tab_value->GetAsInteger(&tab_id));
1062 } 1065 }
1063 1066
1064 int tab_index = -1;
1065 TabStripModel* tab_strip = NULL;
1066 if (!GetTabById(tab_id, profile(), include_incognito(), 1067 if (!GetTabById(tab_id, profile(), include_incognito(),
1067 NULL, &tab_strip, &contents, &tab_index, &error_)) { 1068 NULL, &tab_strip_, &contents, &tab_index_, &error_)) {
1068 return false; 1069 return false;
1069 } 1070 }
1070 NavigationController& controller = contents->web_contents()->GetController(); 1071
1072 web_contents_ = contents->web_contents();
Mihai Parparita -not on Chrome 2012/01/27 23:03:20 Is it safe to hold on to this pointer? I'm thinkin
jstritar 2012/01/30 16:28:05 Done. I also updated it so we don't need to hold o
1073 NavigationController& controller = web_contents_->GetController();
1071 1074
1072 // TODO(rafaelw): handle setting remaining tab properties: 1075 // TODO(rafaelw): handle setting remaining tab properties:
1073 // -title 1076 // -title
1074 // -favIconUrl 1077 // -favIconUrl
1075 1078
1079 // We wait to fire the callback when executing 'javascript:' URLs in tabs.
1080 bool is_async = false;
1081
1076 // Navigate the tab to a new location if the url is different. 1082 // Navigate the tab to a new location if the url is different.
1077 std::string url_string; 1083 std::string url_string;
1078 if (update_props->HasKey(keys::kUrlKey)) { 1084 if (update_props->HasKey(keys::kUrlKey)) {
1079 EXTENSION_FUNCTION_VALIDATE(update_props->GetString( 1085 EXTENSION_FUNCTION_VALIDATE(update_props->GetString(
1080 keys::kUrlKey, &url_string)); 1086 keys::kUrlKey, &url_string));
1081 GURL url = ResolvePossiblyRelativeURL(url_string, GetExtension()); 1087 GURL url = ResolvePossiblyRelativeURL(url_string, GetExtension());
1082 1088
1083 if (!url.is_valid()) { 1089 if (!url.is_valid()) {
1084 error_ = ExtensionErrorUtils::FormatErrorMessage(keys::kInvalidUrlError, 1090 error_ = ExtensionErrorUtils::FormatErrorMessage(keys::kInvalidUrlError,
1085 url_string); 1091 url_string);
1086 return false; 1092 return false;
1087 } 1093 }
1088 1094
1089 // Don't let the extension crash the browser or renderers. 1095 // Don't let the extension crash the browser or renderers.
1090 if (IsCrashURL(url)) { 1096 if (IsCrashURL(url)) {
1091 error_ = keys::kNoCrashBrowserError; 1097 error_ = keys::kNoCrashBrowserError;
1092 return false; 1098 return false;
1093 } 1099 }
1094 1100
1095 // JavaScript URLs can do the same kinds of things as cross-origin XHR, so 1101 // JavaScript URLs can do the same kinds of things as cross-origin XHR, so
1096 // we need to check host permissions before allowing them. 1102 // we need to check host permissions before allowing them.
1097 if (url.SchemeIs(chrome::kJavaScriptScheme)) { 1103 if (url.SchemeIs(chrome::kJavaScriptScheme)) {
1098 if (!GetExtension()->CanExecuteScriptOnPage( 1104 if (!GetExtension()->CanExecuteScriptOnPage(
1099 contents->web_contents()->GetURL(), NULL, &error_)) { 1105 web_contents_->GetURL(), NULL, &error_)) {
1100 return false; 1106 return false;
1101 } 1107 }
1102 1108
1103 ExtensionMsg_ExecuteCode_Params params; 1109 ExtensionMsg_ExecuteCode_Params params;
1104 params.request_id = request_id(); 1110 params.request_id = request_id();
1105 params.extension_id = extension_id(); 1111 params.extension_id = extension_id();
1106 params.is_javascript = true; 1112 params.is_javascript = true;
1107 params.code = url.path(); 1113 params.code = url.path();
1108 params.all_frames = false; 1114 params.all_frames = false;
1109 params.in_main_world = true; 1115 params.in_main_world = true;
1110 1116
1111 RenderViewHost* render_view_host = 1117 RenderViewHost* render_view_host = web_contents_->GetRenderViewHost();
1112 contents->web_contents()->GetRenderViewHost();
1113 render_view_host->Send( 1118 render_view_host->Send(
1114 new ExtensionMsg_ExecuteCode(render_view_host->routing_id(), 1119 new ExtensionMsg_ExecuteCode(render_view_host->routing_id(),
1115 params)); 1120 params));
1116 1121
1117 Observe(contents->web_contents()); 1122 Observe(web_contents_);
1118 AddRef(); // balanced in Observe() 1123 AddRef(); // Balanced in OnExecuteCodeFinished().
1119 1124
1120 return true; 1125 is_async = true;
1121 } 1126 }
1122 1127
1123 controller.LoadURL( 1128 controller.LoadURL(
1124 url, content::Referrer(), content::PAGE_TRANSITION_LINK, std::string()); 1129 url, content::Referrer(), content::PAGE_TRANSITION_LINK, std::string());
1125 1130
1126 // The URL of a tab contents never actually changes to a JavaScript URL, so 1131 // The URL of a tab contents never actually changes to a JavaScript URL, so
1127 // this check only makes sense in other cases. 1132 // this check only makes sense in other cases.
1128 if (!url.SchemeIs(chrome::kJavaScriptScheme)) 1133 if (!url.SchemeIs(chrome::kJavaScriptScheme))
1129 DCHECK_EQ(url.spec(), contents->web_contents()->GetURL().spec()); 1134 DCHECK_EQ(url.spec(), web_contents_->GetURL().spec());
1130 } 1135 }
1131 1136
1132 bool active = false; 1137 bool active = false;
1133 // TODO(rafaelw): Setting |active| from js doesn't make much sense. 1138 // TODO(rafaelw): Setting |active| from js doesn't make much sense.
1134 // Move tab selection management up to window. 1139 // Move tab selection management up to window.
1135 if (update_props->HasKey(keys::kSelectedKey)) 1140 if (update_props->HasKey(keys::kSelectedKey))
1136 EXTENSION_FUNCTION_VALIDATE(update_props->GetBoolean( 1141 EXTENSION_FUNCTION_VALIDATE(update_props->GetBoolean(
1137 keys::kSelectedKey, &active)); 1142 keys::kSelectedKey, &active));
1138 1143
1139 // The 'active' property has replaced 'selected'. 1144 // The 'active' property has replaced 'selected'.
1140 if (update_props->HasKey(keys::kActiveKey)) 1145 if (update_props->HasKey(keys::kActiveKey))
1141 EXTENSION_FUNCTION_VALIDATE(update_props->GetBoolean( 1146 EXTENSION_FUNCTION_VALIDATE(update_props->GetBoolean(
1142 keys::kActiveKey, &active)); 1147 keys::kActiveKey, &active));
1143 1148
1144 if (active) { 1149 if (active) {
1145 if (tab_strip->active_index() != tab_index) { 1150 if (tab_strip_->active_index() != tab_index_) {
1146 tab_strip->ActivateTabAt(tab_index, false); 1151 tab_strip_->ActivateTabAt(tab_index_, false);
1147 DCHECK_EQ(contents, tab_strip->GetActiveTabContents()); 1152 DCHECK_EQ(contents, tab_strip_->GetActiveTabContents());
1148 } 1153 }
1149 contents->web_contents()->Focus(); 1154 web_contents_->Focus();
1150 } 1155 }
1151 1156
1152 bool highlighted = false; 1157 bool highlighted = false;
1153 if (update_props->HasKey(keys::kHighlightedKey)) { 1158 if (update_props->HasKey(keys::kHighlightedKey)) {
1154 EXTENSION_FUNCTION_VALIDATE(update_props->GetBoolean( 1159 EXTENSION_FUNCTION_VALIDATE(update_props->GetBoolean(
1155 keys::kHighlightedKey, &highlighted)); 1160 keys::kHighlightedKey, &highlighted));
1156 if (highlighted != tab_strip->IsTabSelected(tab_index)) 1161 if (highlighted != tab_strip_->IsTabSelected(tab_index_))
1157 tab_strip->ToggleSelectionAt(tab_index); 1162 tab_strip_->ToggleSelectionAt(tab_index_);
1158 } 1163 }
1159 1164
1160 bool pinned = false; 1165 bool pinned = false;
1161 if (update_props->HasKey(keys::kPinnedKey)) { 1166 if (update_props->HasKey(keys::kPinnedKey)) {
1162 EXTENSION_FUNCTION_VALIDATE(update_props->GetBoolean(keys::kPinnedKey, 1167 EXTENSION_FUNCTION_VALIDATE(update_props->GetBoolean(keys::kPinnedKey,
1163 &pinned)); 1168 &pinned));
1164 tab_strip->SetTabPinned(tab_index, pinned); 1169 tab_strip_->SetTabPinned(tab_index_, pinned);
1165 1170
1166 // Update the tab index because it may move when being pinned. 1171 // Update the tab index because it may move when being pinned.
1167 tab_index = tab_strip->GetIndexOfTabContents(contents); 1172 tab_index_ = tab_strip_->GetIndexOfTabContents(contents);
1168 } 1173 }
1169 1174
1170 if (has_callback()) { 1175 if (!is_async) {
1171 if (GetExtension()->HasAPIPermission(ExtensionAPIPermission::kTab)) { 1176 PopulateResult();
1172 result_.reset(ExtensionTabUtil::CreateTabValue(contents->web_contents(), 1177 SendResponse(true);
1173 tab_strip,
1174 tab_index));
1175 } else {
1176 result_.reset(Value::CreateNullValue());
1177 }
1178 } 1178 }
1179 return true;
1180 }
1179 1181
1180 SendResponse(true); 1182 void UpdateTabFunction::PopulateResult() {
1181 return true; 1183 if (!has_callback())
1184 return;
1185
1186 if (GetExtension()->HasAPIPermission(ExtensionAPIPermission::kTab)) {
1187 result_.reset(ExtensionTabUtil::CreateTabValue(
1188 web_contents_, tab_strip_, tab_index_));
1189 } else {
1190 result_.reset(Value::CreateNullValue());
1191 }
1182 } 1192 }
1183 1193
1184 bool UpdateTabFunction::OnMessageReceived(const IPC::Message& message) { 1194 bool UpdateTabFunction::OnMessageReceived(const IPC::Message& message) {
1185 if (message.type() != ExtensionHostMsg_ExecuteCodeFinished::ID) 1195 if (message.type() != ExtensionHostMsg_ExecuteCodeFinished::ID)
1186 return false; 1196 return false;
1187 1197
1188 int message_request_id = -1; 1198 int message_request_id = -1;
1189 void* iter = NULL; 1199 void* iter = NULL;
1190 if (!message.ReadInt(&iter, &message_request_id)) { 1200 if (!message.ReadInt(&iter, &message_request_id)) {
1191 NOTREACHED() << "malformed extension message"; 1201 NOTREACHED() << "malformed extension message";
(...skipping 11 matching lines...) Expand all
1203 } 1213 }
1204 1214
1205 void UpdateTabFunction::OnExecuteCodeFinished(int request_id, 1215 void UpdateTabFunction::OnExecuteCodeFinished(int request_id,
1206 bool success, 1216 bool success,
1207 const std::string& error) { 1217 const std::string& error) {
1208 if (!error.empty()) { 1218 if (!error.empty()) {
1209 CHECK(!success); 1219 CHECK(!success);
1210 error_ = error; 1220 error_ = error;
1211 } 1221 }
1212 1222
1223 if (success)
1224 PopulateResult();
1213 SendResponse(success); 1225 SendResponse(success);
1214 1226
1215 Observe(NULL); 1227 Observe(NULL);
1216 Release(); // balanced in Execute() 1228 Release(); // Balanced in RunImpl().
1217 } 1229 }
1218 1230
1219 bool MoveTabsFunction::RunImpl() { 1231 bool MoveTabsFunction::RunImpl() {
1220 Value* tab_value = NULL; 1232 Value* tab_value = NULL;
1221 EXTENSION_FUNCTION_VALIDATE(args_->Get(0, &tab_value)); 1233 EXTENSION_FUNCTION_VALIDATE(args_->Get(0, &tab_value));
1222 1234
1223 std::vector<int> tab_ids; 1235 std::vector<int> tab_ids;
1224 EXTENSION_FUNCTION_VALIDATE(ReadOneOrMoreIntegers(tab_value, &tab_ids)); 1236 EXTENSION_FUNCTION_VALIDATE(ReadOneOrMoreIntegers(tab_value, &tab_ids));
1225 1237
1226 DictionaryValue* update_props = NULL; 1238 DictionaryValue* update_props = NULL;
(...skipping 420 matching lines...) Expand 10 before | Expand all | Expand 10 after
1647 // called for every API call the extension made. 1659 // called for every API call the extension made.
1648 GotLanguage(language); 1660 GotLanguage(language);
1649 } 1661 }
1650 1662
1651 void DetectTabLanguageFunction::GotLanguage(const std::string& language) { 1663 void DetectTabLanguageFunction::GotLanguage(const std::string& language) {
1652 result_.reset(Value::CreateStringValue(language.c_str())); 1664 result_.reset(Value::CreateStringValue(language.c_str()));
1653 SendResponse(true); 1665 SendResponse(true);
1654 1666
1655 Release(); // Balanced in Run() 1667 Release(); // Balanced in Run()
1656 } 1668 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698