1a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)// Copyright (c) 2013 The Chromium Authors. All rights reserved.
2a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
3a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)// found in the LICENSE file.
4a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
5a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)#include "chrome/browser/extensions/api/execute_code_function.h"
6a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
7a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)#include "chrome/browser/extensions/api/tabs/tabs_constants.h"
8a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)#include "chrome/browser/extensions/script_executor.h"
9a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)#include "chrome/common/extensions/api/i18n/default_locale_handler.h"
10a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)#include "chrome/common/extensions/extension_file_util.h"
11a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)#include "chrome/common/extensions/extension_messages.h"
12a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)#include "chrome/common/extensions/message_bundle.h"
13a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)#include "extensions/browser/file_reader.h"
14a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)#include "extensions/common/error_utils.h"
15a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
16a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)namespace extensions {
17a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
18a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)namespace keys = tabs_constants;
19a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)using api::tabs::InjectDetails;
20a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
21a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)ExecuteCodeFunction::ExecuteCodeFunction() {
22a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)}
23a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
24a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)ExecuteCodeFunction::~ExecuteCodeFunction() {
25a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)}
26a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
27a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)void ExecuteCodeFunction::DidLoadFile(bool success,
28a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)                                      const std::string& data) {
29a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  const Extension* extension = GetExtension();
30a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
31a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  // Check if the file is CSS and needs localization.
32a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  if (success &&
33a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)      ShouldInsertCSS() &&
34a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)      extension != NULL &&
35a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)      data.find(MessageBundle::kMessageBegin) != std::string::npos) {
36a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    content::BrowserThread::PostTask(
37a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)        content::BrowserThread::FILE, FROM_HERE,
38a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)        base::Bind(&ExecuteCodeFunction::LocalizeCSS, this,
39a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)                   data,
40a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)                   extension->id(),
41a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)                   extension->path(),
42a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)                   LocaleInfo::GetDefaultLocale(extension)));
43a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  } else {
44a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    DidLoadAndLocalizeFile(success, data);
45a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  }
46a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)}
47a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
48a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)void ExecuteCodeFunction::LocalizeCSS(
49a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    const std::string& data,
50a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    const std::string& extension_id,
51a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    const base::FilePath& extension_path,
52a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    const std::string& extension_default_locale) {
53a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  scoped_ptr<SubstitutionMap> localization_messages(
54a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)      extension_file_util::LoadMessageBundleSubstitutionMap(
55a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)          extension_path, extension_id, extension_default_locale));
56a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
57a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  // We need to do message replacement on the data, so it has to be mutable.
58a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  std::string css_data = data;
59a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  std::string error;
60a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  MessageBundle::ReplaceMessagesWithExternalDictionary(*localization_messages,
61a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)                                                       &css_data,
62a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)                                                       &error);
63a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
64a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  // Call back DidLoadAndLocalizeFile on the UI thread. The success parameter
65a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  // is always true, because if loading had failed, we wouldn't have had
66a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  // anything to localize.
67a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  content::BrowserThread::PostTask(
68a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)      content::BrowserThread::UI, FROM_HERE,
69a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)      base::Bind(&ExecuteCodeFunction::DidLoadAndLocalizeFile, this,
70a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)                 true, css_data));
71a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)}
72a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
73a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)void ExecuteCodeFunction::DidLoadAndLocalizeFile(bool success,
74a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)                                                 const std::string& data) {
75a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  if (success) {
76a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    if (!Execute(data))
77a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)      SendResponse(false);
78a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  } else {
79a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    // TODO(viettrungluu): bug: there's no particular reason the path should be
80a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    // UTF-8, in which case this may fail.
81a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    error_ = ErrorUtils::FormatErrorMessage(keys::kLoadFileError,
82a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)        resource_.relative_path().AsUTF8Unsafe());
83a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    SendResponse(false);
84a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  }
85a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)}
86a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
87a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)bool ExecuteCodeFunction::Execute(const std::string& code_string) {
88a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  ScriptExecutor* executor = GetScriptExecutor();
89a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  if (!executor)
90a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    return false;
91a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
92a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  const Extension* extension = GetExtension();
93a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  if (!extension)
94a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    return false;
95a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
96a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  ScriptExecutor::ScriptType script_type = ScriptExecutor::JAVASCRIPT;
97a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  if (ShouldInsertCSS())
98a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    script_type = ScriptExecutor::CSS;
99a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
100a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  ScriptExecutor::FrameScope frame_scope =
101a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)      details_->all_frames.get() && *details_->all_frames ?
102a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)          ScriptExecutor::ALL_FRAMES :
103a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)          ScriptExecutor::TOP_FRAME;
104a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
105a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  UserScript::RunLocation run_at =
106a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)      UserScript::UNDEFINED;
107a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  switch (details_->run_at) {
108a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    case InjectDetails::RUN_AT_NONE:
109a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    case InjectDetails::RUN_AT_DOCUMENT_IDLE:
110a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)      run_at = UserScript::DOCUMENT_IDLE;
111a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)      break;
112a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    case InjectDetails::RUN_AT_DOCUMENT_START:
113a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)      run_at = UserScript::DOCUMENT_START;
114a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)      break;
115a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    case InjectDetails::RUN_AT_DOCUMENT_END:
116a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)      run_at = UserScript::DOCUMENT_END;
117a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)      break;
118a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  }
119a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  CHECK_NE(UserScript::UNDEFINED, run_at);
120a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
121a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  executor->ExecuteScript(
122a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)      extension->id(),
123a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)      script_type,
124a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)      code_string,
125a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)      frame_scope,
126a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)      run_at,
127a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)      ScriptExecutor::ISOLATED_WORLD,
128a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)      IsWebView(),
129a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)      base::Bind(&ExecuteCodeFunction::OnExecuteCodeFinished, this));
130a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  return true;
131a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)}
132a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
133a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)bool ExecuteCodeFunction::HasPermission() {
134a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  return true;
135a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)}
136a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
137a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)bool ExecuteCodeFunction::RunImpl() {
138a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  EXTENSION_FUNCTION_VALIDATE(Init());
139a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
140a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  if (!details_->code.get() && !details_->file.get()) {
141a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    error_ = keys::kNoCodeOrFileToExecuteError;
142a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    return false;
143a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  }
144a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  if (details_->code.get() && details_->file.get()) {
145a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    error_ = keys::kMoreThanOneValuesError;
146a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    return false;
147a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  }
148a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
149a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  if (!CanExecuteScriptOnPage())
150a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    return false;
151a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
152a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  if (details_->code.get())
153a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    return Execute(*details_->code);
154a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
155a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  if (!details_->file.get())
156a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    return false;
157a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  resource_ = GetExtension()->GetResource(*details_->file);
158a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
159a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  if (resource_.extension_root().empty() || resource_.relative_path().empty()) {
160a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    error_ = keys::kNoCodeOrFileToExecuteError;
161a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    return false;
162a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  }
163a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
164a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  scoped_refptr<FileReader> file_reader(new FileReader(
165a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)      resource_, base::Bind(&ExecuteCodeFunction::DidLoadFile, this)));
166a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  file_reader->Start();
167a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
168a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  return true;
169a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)}
170a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
171a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)void ExecuteCodeFunction::OnExecuteCodeFinished(
172a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    const std::string& error,
173a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    int32 on_page_id,
174a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    const GURL& on_url,
175eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    const base::ListValue& result) {
176a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  if (!error.empty())
177a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    SetError(error);
178a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
179a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  SendResponse(error.empty());
180a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)}
181a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
182a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)}  // namespace extensions
183