• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "chrome/browser/extensions/execute_code_in_tab_function.h"
6 
7 #include "base/callback.h"
8 #include "base/string_util.h"
9 #include "base/utf_string_conversions.h"
10 #include "chrome/browser/extensions/extension_service.h"
11 #include "chrome/browser/extensions/extension_tabs_module.h"
12 #include "chrome/browser/extensions/extension_tabs_module_constants.h"
13 #include "chrome/browser/extensions/file_reader.h"
14 #include "chrome/browser/profiles/profile.h"
15 #include "chrome/browser/ui/browser.h"
16 #include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h"
17 #include "chrome/common/extensions/extension.h"
18 #include "chrome/common/extensions/extension_constants.h"
19 #include "chrome/common/extensions/extension_error_utils.h"
20 #include "chrome/common/extensions/extension_messages.h"
21 #include "content/browser/renderer_host/render_view_host.h"
22 #include "content/browser/tab_contents/tab_contents.h"
23 #include "content/browser/renderer_host/render_view_host.h"
24 #include "content/common/notification_service.h"
25 
26 namespace keys = extension_tabs_module_constants;
27 
ExecuteCodeInTabFunction()28 ExecuteCodeInTabFunction::ExecuteCodeInTabFunction()
29     : ALLOW_THIS_IN_INITIALIZER_LIST(registrar_(this)),
30       execute_tab_id_(-1),
31       all_frames_(false) {
32 }
33 
~ExecuteCodeInTabFunction()34 ExecuteCodeInTabFunction::~ExecuteCodeInTabFunction() {
35 }
36 
RunImpl()37 bool ExecuteCodeInTabFunction::RunImpl() {
38   DictionaryValue* script_info;
39   EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(1, &script_info));
40   size_t number_of_value = script_info->size();
41   if (number_of_value == 0) {
42     error_ = keys::kNoCodeOrFileToExecuteError;
43     return false;
44   } else {
45     bool has_code = script_info->HasKey(keys::kCodeKey);
46     bool has_file = script_info->HasKey(keys::kFileKey);
47     if (has_code && has_file) {
48       error_ = keys::kMoreThanOneValuesError;
49       return false;
50     } else if (!has_code && !has_file) {
51       error_ = keys::kNoCodeOrFileToExecuteError;
52       return false;
53     }
54   }
55 
56   execute_tab_id_ = -1;
57   Browser* browser = NULL;
58   TabContentsWrapper* contents = NULL;
59 
60   // If |tab_id| is specified, look for it. Otherwise default to selected tab
61   // in the current window.
62   Value* tab_value = NULL;
63   EXTENSION_FUNCTION_VALIDATE(args_->Get(0, &tab_value));
64   if (tab_value->IsType(Value::TYPE_NULL)) {
65     browser = GetCurrentBrowser();
66     if (!browser) {
67       error_ = keys::kNoCurrentWindowError;
68       return false;
69     }
70     if (!ExtensionTabUtil::GetDefaultTab(browser, &contents, &execute_tab_id_))
71       return false;
72   } else {
73     EXTENSION_FUNCTION_VALIDATE(tab_value->GetAsInteger(&execute_tab_id_));
74     if (!ExtensionTabUtil::GetTabById(execute_tab_id_, profile(),
75                                       include_incognito(),
76                                       &browser, NULL, &contents, NULL)) {
77       return false;
78     }
79   }
80 
81   // NOTE: This can give the wrong answer due to race conditions, but it is OK,
82   // we check again in the renderer.
83   CHECK(browser);
84   CHECK(contents);
85   if (!GetExtension()->CanExecuteScriptOnPage(
86           contents->tab_contents()->GetURL(), NULL, &error_)) {
87     return false;
88   }
89 
90   if (script_info->HasKey(keys::kAllFramesKey)) {
91     if (!script_info->GetBoolean(keys::kAllFramesKey, &all_frames_))
92       return false;
93   }
94 
95   std::string code_string;
96   if (script_info->HasKey(keys::kCodeKey)) {
97     if (!script_info->GetString(keys::kCodeKey, &code_string))
98       return false;
99   }
100 
101   if (!code_string.empty()) {
102     if (!Execute(code_string))
103       return false;
104     return true;
105   }
106 
107   std::string relative_path;
108   if (script_info->HasKey(keys::kFileKey)) {
109     if (!script_info->GetString(keys::kFileKey, &relative_path))
110       return false;
111     resource_ = GetExtension()->GetResource(relative_path);
112   }
113   if (resource_.extension_root().empty() || resource_.relative_path().empty()) {
114     error_ = keys::kNoCodeOrFileToExecuteError;
115     return false;
116   }
117 
118   scoped_refptr<FileReader> file_reader(new FileReader(
119       resource_, NewCallback(this, &ExecuteCodeInTabFunction::DidLoadFile)));
120   file_reader->Start();
121   AddRef();  // Keep us alive until DidLoadFile is called.
122 
123   return true;
124 }
125 
DidLoadFile(bool success,const std::string & data)126 void ExecuteCodeInTabFunction::DidLoadFile(bool success,
127                                            const std::string& data) {
128   if (success) {
129     Execute(data);
130   } else {
131 #if defined(OS_POSIX)
132     // TODO(viettrungluu): bug: there's no particular reason the path should be
133     // UTF-8, in which case this may fail.
134     error_ = ExtensionErrorUtils::FormatErrorMessage(keys::kLoadFileError,
135         resource_.relative_path().value());
136 #elif defined(OS_WIN)
137     error_ = ExtensionErrorUtils::FormatErrorMessage(keys::kLoadFileError,
138         WideToUTF8(resource_.relative_path().value()));
139 #endif  // OS_WIN
140     SendResponse(false);
141   }
142   Release();  // Balance the AddRef taken in RunImpl
143 }
144 
Execute(const std::string & code_string)145 bool ExecuteCodeInTabFunction::Execute(const std::string& code_string) {
146   TabContentsWrapper* contents = NULL;
147   Browser* browser = NULL;
148 
149   bool success = ExtensionTabUtil::GetTabById(
150       execute_tab_id_, profile(), include_incognito(), &browser, NULL,
151       &contents, NULL) && contents && browser;
152 
153   if (!success) {
154     SendResponse(false);
155     return false;
156   }
157 
158   const Extension* extension = GetExtension();
159   if (!extension) {
160     SendResponse(false);
161     return false;
162   }
163 
164   bool is_js_code = true;
165   std::string function_name = name();
166   if (function_name == TabsInsertCSSFunction::function_name()) {
167     is_js_code = false;
168   } else if (function_name != TabsExecuteScriptFunction::function_name()) {
169     DCHECK(false);
170   }
171 
172   ExtensionMsg_ExecuteCode_Params params;
173   params.request_id = request_id();
174   params.extension_id = extension->id();
175   params.is_javascript = is_js_code;
176   params.code = code_string;
177   params.all_frames = all_frames_;
178   params.in_main_world = false;
179   contents->render_view_host()->Send(new ExtensionMsg_ExecuteCode(
180       contents->render_view_host()->routing_id(), params));
181 
182   registrar_.Observe(contents->tab_contents());
183   AddRef();  // balanced in OnExecuteCodeFinished()
184   return true;
185 }
186 
OnMessageReceived(const IPC::Message & message)187 bool ExecuteCodeInTabFunction::OnMessageReceived(const IPC::Message& message) {
188   if (message.type() != ExtensionHostMsg_ExecuteCodeFinished::ID)
189     return false;
190 
191   int message_request_id;
192   void* iter = NULL;
193   if (!message.ReadInt(&iter, &message_request_id)) {
194     NOTREACHED() << "malformed extension message";
195     return true;
196   }
197 
198   if (message_request_id != request_id())
199     return false;
200 
201   IPC_BEGIN_MESSAGE_MAP(ExecuteCodeInTabFunction, message)
202     IPC_MESSAGE_HANDLER(ExtensionHostMsg_ExecuteCodeFinished,
203                         OnExecuteCodeFinished)
204   IPC_END_MESSAGE_MAP()
205   return true;
206 }
207 
OnExecuteCodeFinished(int request_id,bool success,const std::string & error)208 void ExecuteCodeInTabFunction::OnExecuteCodeFinished(int request_id,
209                                                      bool success,
210                                                      const std::string& error) {
211   if (!error.empty()) {
212     CHECK(!success);
213     error_ = error;
214   }
215 
216   SendResponse(success);
217 
218   registrar_.Observe(NULL);
219   Release();  // balanced in Execute()
220 }
221