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
3// found in the LICENSE file.
4
5#include "extensions/browser/warning_set.h"
6
7#include "base/files/file_path.h"
8#include "base/strings/string_util.h"
9#include "base/strings/utf_string_conversions.h"
10#include "content/public/browser/browser_thread.h"
11#include "extensions/common/extension.h"
12#include "extensions/common/extension_set.h"
13#include "extensions/common/extensions_client.h"
14#include "extensions/strings/grit/extensions_strings.h"
15#include "net/base/escape.h"
16#include "ui/base/l10n/l10n_util.h"
17
18using content::BrowserThread;
19
20namespace {
21// Prefix for message parameters indicating that the parameter needs to
22// be translated from an extension id to the extension name.
23const char kTranslate[] = "TO_TRANSLATE:";
24const size_t kMaxNumberOfParameters = 4;
25}
26
27namespace extensions {
28
29//
30// Warning
31//
32
33Warning::Warning(
34    WarningType type,
35    const std::string& extension_id,
36    int message_id,
37    const std::vector<std::string>& message_parameters)
38    : type_(type),
39      extension_id_(extension_id),
40      message_id_(message_id),
41      message_parameters_(message_parameters) {
42  // These are invalid here because they do not have corresponding warning
43  // messages in the UI.
44  CHECK_NE(type, kInvalid);
45  CHECK_NE(type, kMaxWarningType);
46  CHECK_LE(message_parameters.size(), kMaxNumberOfParameters);
47}
48
49Warning::Warning(const Warning& other)
50  : type_(other.type_),
51    extension_id_(other.extension_id_),
52    message_id_(other.message_id_),
53    message_parameters_(other.message_parameters_) {}
54
55Warning::~Warning() {
56}
57
58Warning& Warning::operator=(const Warning& other) {
59  type_ = other.type_;
60  extension_id_ = other.extension_id_;
61  message_id_ = other.message_id_;
62  message_parameters_ = other.message_parameters_;
63  return *this;
64}
65
66// static
67Warning Warning::CreateNetworkDelayWarning(
68    const std::string& extension_id) {
69  std::vector<std::string> message_parameters;
70  message_parameters.push_back(ExtensionsClient::Get()->GetProductName());
71  return Warning(
72      kNetworkDelay,
73      extension_id,
74      IDS_EXTENSION_WARNINGS_NETWORK_DELAY,
75      message_parameters);
76}
77
78// static
79Warning Warning::CreateNetworkConflictWarning(const std::string& extension_id) {
80  std::vector<std::string> message_parameters;
81  return Warning(
82      kNetworkConflict,
83      extension_id,
84      IDS_EXTENSION_WARNINGS_NETWORK_CONFLICT,
85      message_parameters);
86}
87
88// static
89Warning Warning::CreateRedirectConflictWarning(
90    const std::string& extension_id,
91    const std::string& winning_extension_id,
92    const GURL& attempted_redirect_url,
93    const GURL& winning_redirect_url) {
94  std::vector<std::string> message_parameters;
95  message_parameters.push_back(attempted_redirect_url.spec());
96  message_parameters.push_back(kTranslate + winning_extension_id);
97  message_parameters.push_back(winning_redirect_url.spec());
98  return Warning(
99      kRedirectConflict,
100      extension_id,
101      IDS_EXTENSION_WARNINGS_REDIRECT_CONFLICT,
102      message_parameters);
103}
104
105// static
106Warning Warning::CreateRequestHeaderConflictWarning(
107    const std::string& extension_id,
108    const std::string& winning_extension_id,
109    const std::string& conflicting_header) {
110  std::vector<std::string> message_parameters;
111  message_parameters.push_back(conflicting_header);
112  message_parameters.push_back(kTranslate + winning_extension_id);
113  return Warning(
114      kNetworkConflict,
115      extension_id,
116      IDS_EXTENSION_WARNINGS_REQUEST_HEADER_CONFLICT,
117      message_parameters);
118}
119
120// static
121Warning Warning::CreateResponseHeaderConflictWarning(
122    const std::string& extension_id,
123    const std::string& winning_extension_id,
124    const std::string& conflicting_header) {
125  std::vector<std::string> message_parameters;
126  message_parameters.push_back(conflicting_header);
127  message_parameters.push_back(kTranslate + winning_extension_id);
128  return Warning(
129      kNetworkConflict,
130      extension_id,
131      IDS_EXTENSION_WARNINGS_RESPONSE_HEADER_CONFLICT,
132      message_parameters);
133}
134
135// static
136Warning Warning::CreateCredentialsConflictWarning(
137    const std::string& extension_id,
138    const std::string& winning_extension_id) {
139  std::vector<std::string> message_parameters;
140  message_parameters.push_back(kTranslate + winning_extension_id);
141  return Warning(
142      kNetworkConflict,
143      extension_id,
144      IDS_EXTENSION_WARNINGS_CREDENTIALS_CONFLICT,
145      message_parameters);
146}
147
148// static
149Warning Warning::CreateRepeatedCacheFlushesWarning(
150    const std::string& extension_id) {
151  std::vector<std::string> message_parameters;
152  message_parameters.push_back(ExtensionsClient::Get()->GetProductName());
153  return Warning(
154      kRepeatedCacheFlushes,
155      extension_id,
156      IDS_EXTENSION_WARNINGS_NETWORK_DELAY,
157      message_parameters);
158}
159
160// static
161Warning Warning::CreateDownloadFilenameConflictWarning(
162    const std::string& losing_extension_id,
163    const std::string& winning_extension_id,
164    const base::FilePath& losing_filename,
165    const base::FilePath& winning_filename) {
166  std::vector<std::string> message_parameters;
167  message_parameters.push_back(base::UTF16ToUTF8(
168      losing_filename.LossyDisplayName()));
169  message_parameters.push_back(kTranslate + winning_extension_id);
170  message_parameters.push_back(base::UTF16ToUTF8(
171      winning_filename.LossyDisplayName()));
172  return Warning(
173      kDownloadFilenameConflict,
174      losing_extension_id,
175      IDS_EXTENSION_WARNINGS_DOWNLOAD_FILENAME_CONFLICT,
176      message_parameters);
177}
178
179// static
180Warning Warning::CreateReloadTooFrequentWarning(
181    const std::string& extension_id) {
182  std::vector<std::string> message_parameters;
183  return Warning(kReloadTooFrequent,
184                          extension_id,
185                          IDS_EXTENSION_WARNING_RELOAD_TOO_FREQUENT,
186                          message_parameters);
187}
188
189std::string Warning::GetLocalizedMessage(const ExtensionSet* extensions) const {
190  DCHECK_CURRENTLY_ON(BrowserThread::UI);
191
192  // These parameters may be unsafe (URLs and Extension names) and need
193  // to be HTML-escaped before being embedded in the UI. Also extension IDs
194  // are translated to full extension names.
195  std::vector<base::string16> final_parameters;
196  for (size_t i = 0; i < message_parameters_.size(); ++i) {
197    std::string message = message_parameters_[i];
198    if (StartsWithASCII(message, kTranslate, true)) {
199      std::string extension_id = message.substr(sizeof(kTranslate) - 1);
200      const extensions::Extension* extension =
201          extensions->GetByID(extension_id);
202      message = extension ? extension->name() : extension_id;
203    }
204    final_parameters.push_back(base::UTF8ToUTF16(net::EscapeForHTML(message)));
205  }
206
207  COMPILE_ASSERT(kMaxNumberOfParameters == 4u, YouNeedToAddMoreCaseStatements);
208  switch (final_parameters.size()) {
209    case 0:
210      return l10n_util::GetStringUTF8(message_id_);
211    case 1:
212      return l10n_util::GetStringFUTF8(message_id_, final_parameters[0]);
213    case 2:
214      return l10n_util::GetStringFUTF8(message_id_, final_parameters[0],
215          final_parameters[1]);
216    case 3:
217      return l10n_util::GetStringFUTF8(message_id_, final_parameters[0],
218          final_parameters[1], final_parameters[2]);
219    case 4:
220      return l10n_util::GetStringFUTF8(message_id_, final_parameters[0],
221          final_parameters[1], final_parameters[2], final_parameters[3]);
222    default:
223      NOTREACHED();
224      return std::string();
225  }
226}
227
228bool operator<(const Warning& a, const Warning& b) {
229  if (a.extension_id() != b.extension_id())
230    return a.extension_id() < b.extension_id();
231  return a.warning_type() < b.warning_type();
232}
233
234}  // namespace extensions
235