execute_code_in_tab_function.cc revision 21d179b334e59e9a3bfcaed4c4430bef1bc5759d
1731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick// Copyright (c) 2010 The Chromium Authors. All rights reserved.
2c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Use of this source code is governed by a BSD-style license that can be
3c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// found in the LICENSE file.
4c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
5c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/extensions/execute_code_in_tab_function.h"
6c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
7c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/callback.h"
8c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/string_util.h"
93345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "base/utf_string_conversions.h"
10c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/extensions/extension_tabs_module.h"
11c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/extensions/extension_tabs_module_constants.h"
1221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#include "chrome/browser/extensions/extension_service.h"
13c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/extensions/file_reader.h"
1421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#include "chrome/browser/profiles/profile.h"
15c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/tab_contents/tab_contents.h"
164a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch#include "chrome/browser/ui/browser.h"
1721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h"
18c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/common/extensions/extension.h"
19c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/common/extensions/extension_constants.h"
20c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/common/extensions/extension_error_utils.h"
213345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "chrome/common/notification_service.h"
22c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
23c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochnamespace keys = extension_tabs_module_constants;
24c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
253345a6884c488ff3a535c2c9acdd33d74b37e311Iain MerrickExecuteCodeInTabFunction::ExecuteCodeInTabFunction()
263345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    : execute_tab_id_(-1),
273345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      all_frames_(false) {
283345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
293345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
303345a6884c488ff3a535c2c9acdd33d74b37e311Iain MerrickExecuteCodeInTabFunction::~ExecuteCodeInTabFunction() {
313345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
323345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
33c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool ExecuteCodeInTabFunction::RunImpl() {
34c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DictionaryValue* script_info;
35c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(1, &script_info));
36c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  size_t number_of_value = script_info->size();
37c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (number_of_value == 0) {
38c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    error_ = keys::kNoCodeOrFileToExecuteError;
39c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
40c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  } else {
41c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    bool has_code = script_info->HasKey(keys::kCodeKey);
42c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    bool has_file = script_info->HasKey(keys::kFileKey);
43c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (has_code && has_file) {
44c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      error_ = keys::kMoreThanOneValuesError;
45c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return false;
46c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    } else if (!has_code && !has_file) {
47c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      error_ = keys::kNoCodeOrFileToExecuteError;
48c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return false;
49c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
50c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
51c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
52c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  execute_tab_id_ = -1;
53c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  Browser* browser = NULL;
54201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  TabContentsWrapper* contents = NULL;
55c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
56c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // If |tab_id| is specified, look for it. Otherwise default to selected tab
57c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // in the current window.
58c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  Value* tab_value = NULL;
59c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXTENSION_FUNCTION_VALIDATE(args_->Get(0, &tab_value));
60c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (tab_value->IsType(Value::TYPE_NULL)) {
61c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    browser = GetCurrentBrowser();
62c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (!browser) {
63c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      error_ = keys::kNoCurrentWindowError;
64c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return false;
65c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
66c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (!ExtensionTabUtil::GetDefaultTab(browser, &contents, &execute_tab_id_))
67c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return false;
68c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  } else {
69c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    EXTENSION_FUNCTION_VALIDATE(tab_value->GetAsInteger(&execute_tab_id_));
70c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (!ExtensionTabUtil::GetTabById(execute_tab_id_, profile(),
71c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                      include_incognito(),
72c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                      &browser, NULL, &contents, NULL)) {
73c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return false;
74c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
75c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
76c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
77c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(browser);
78c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(contents);
79c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
80c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // NOTE: This can give the wrong answer due to race conditions, but it is OK,
81c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // we check again in the renderer.
82513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  const Extension* extension = GetExtension();
83731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  const std::vector<URLPattern> host_permissions =
84731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      extension->host_permissions();
85731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  if (!Extension::CanExecuteScriptOnPage(
86201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch        contents->tab_contents()->GetURL(),
87731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick        extension->CanExecuteScriptEverywhere(),
88731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick        &host_permissions,
89731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick        NULL,
90731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick        &error_)) {
91c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
92731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  }
93c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
94c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (script_info->HasKey(keys::kAllFramesKey)) {
95c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (!script_info->GetBoolean(keys::kAllFramesKey, &all_frames_))
96c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return false;
97c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
98c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
99c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  std::string code_string;
100c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (script_info->HasKey(keys::kCodeKey)) {
101c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (!script_info->GetString(keys::kCodeKey, &code_string))
102c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return false;
103c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
104c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
105c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!code_string.empty()) {
106c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (!Execute(code_string))
107c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return false;
108c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return true;
109c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
110c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
111c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  std::string relative_path;
112c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (script_info->HasKey(keys::kFileKey)) {
113c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (!script_info->GetString(keys::kFileKey, &relative_path))
114c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return false;
115c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    resource_ = GetExtension()->GetResource(relative_path);
116c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
117c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (resource_.extension_root().empty() || resource_.relative_path().empty()) {
118c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    error_ = keys::kNoCodeOrFileToExecuteError;
119c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
120c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
121c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
122c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  scoped_refptr<FileReader> file_reader(new FileReader(
123c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      resource_, NewCallback(this, &ExecuteCodeInTabFunction::DidLoadFile)));
124c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  file_reader->Start();
125c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  AddRef();  // Keep us alive until DidLoadFile is called.
126c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
127c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return true;
128c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
129c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
130c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid ExecuteCodeInTabFunction::DidLoadFile(bool success,
131c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                           const std::string& data) {
132c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (success) {
133c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    Execute(data);
134c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  } else {
135c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#if defined(OS_POSIX)
1363345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    // TODO(viettrungluu): bug: there's no particular reason the path should be
1373345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    // UTF-8, in which case this may fail.
138c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    error_ = ExtensionErrorUtils::FormatErrorMessage(keys::kLoadFileError,
139c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        resource_.relative_path().value());
140c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#elif defined(OS_WIN)
141c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    error_ = ExtensionErrorUtils::FormatErrorMessage(keys::kLoadFileError,
142c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        WideToUTF8(resource_.relative_path().value()));
143c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#endif  // OS_WIN
144c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    SendResponse(false);
145c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
146c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  Release();  // Balance the AddRef taken in RunImpl
147c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
148c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
149c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool ExecuteCodeInTabFunction::Execute(const std::string& code_string) {
150201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  TabContentsWrapper* contents = NULL;
151c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  Browser* browser = NULL;
152c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
153c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  bool success = ExtensionTabUtil::GetTabById(
154c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      execute_tab_id_, profile(), include_incognito(), &browser, NULL,
155c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      &contents, NULL) && contents && browser;
156c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
157c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!success) {
158c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    SendResponse(false);
159c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
160c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
161c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
162513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  const Extension* extension = GetExtension();
163c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!extension) {
164c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    SendResponse(false);
165c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
166c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
167c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
168c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  bool is_js_code = true;
169c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  std::string function_name = name();
170c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (function_name == TabsInsertCSSFunction::function_name()) {
171c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    is_js_code = false;
172c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  } else if (function_name != TabsExecuteScriptFunction::function_name()) {
173c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    DCHECK(false);
174c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
175201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  if (!contents->tab_contents()->ExecuteCode(request_id(), extension->id(),
176201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch      is_js_code, code_string, all_frames_)) {
177c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    SendResponse(false);
178c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
179c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
180c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  registrar_.Add(this, NotificationType::TAB_CODE_EXECUTED,
181c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                 NotificationService::AllSources());
182c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  AddRef();  // balanced in Observe()
183c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return true;
184c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
185c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
186c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid ExecuteCodeInTabFunction::Observe(NotificationType type,
187c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                       const NotificationSource& source,
188c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                       const NotificationDetails& details) {
189c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  std::pair<int, bool>* result_details =
190c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      Details<std::pair<int, bool> >(details).ptr();
191c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (result_details->first == request_id()) {
192c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    SendResponse(result_details->second);
193c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    Release();  // balanced in Execute()
194c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
195c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
196