1 // Copyright 2013 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/api/feedback_private/feedback_private_api.h"
6
7 #include "base/lazy_instance.h"
8 #include "base/memory/scoped_ptr.h"
9 #include "base/strings/string_number_conversions.h"
10 #include "base/strings/string_util.h"
11 #include "base/strings/utf_string_conversions.h"
12 #include "base/values.h"
13 #include "chrome/browser/extensions/api/feedback_private/feedback_service.h"
14 #include "chrome/browser/profiles/profile.h"
15 #include "chrome/grit/generated_resources.h"
16 #include "components/feedback/tracing_manager.h"
17 #include "extensions/browser/event_router.h"
18 #include "ui/base/l10n/l10n_util.h"
19 #include "ui/base/webui/web_ui_util.h"
20 #include "url/url_util.h"
21
22 using feedback::FeedbackData;
23
24 namespace {
25
26 // Getting the filename of a blob prepends a "C:\fakepath" to the filename.
27 // This is undesirable, strip it if it exists.
StripFakepath(const std::string & path)28 std::string StripFakepath(const std::string& path) {
29 const char kFakePathStr[] = "C:\\fakepath\\";
30 if (StartsWithASCII(path, kFakePathStr, false))
31 return path.substr(arraysize(kFakePathStr) - 1);
32 return path;
33 }
34
35 } // namespace
36
37 namespace extensions {
38
39 namespace feedback_private = api::feedback_private;
40
41 using feedback_private::SystemInformation;
42 using feedback_private::FeedbackInfo;
43
44 char kFeedbackExtensionId[] = "gfdkimpbcpahaombhbimeihdjnejgicl";
45
46 static base::LazyInstance<BrowserContextKeyedAPIFactory<FeedbackPrivateAPI> >
47 g_factory = LAZY_INSTANCE_INITIALIZER;
48
49 // static
50 BrowserContextKeyedAPIFactory<FeedbackPrivateAPI>*
GetFactoryInstance()51 FeedbackPrivateAPI::GetFactoryInstance() {
52 return g_factory.Pointer();
53 }
54
FeedbackPrivateAPI(content::BrowserContext * context)55 FeedbackPrivateAPI::FeedbackPrivateAPI(content::BrowserContext* context)
56 : browser_context_(context), service_(FeedbackService::CreateInstance()) {}
57
~FeedbackPrivateAPI()58 FeedbackPrivateAPI::~FeedbackPrivateAPI() {
59 delete service_;
60 service_ = NULL;
61 }
62
GetService() const63 FeedbackService* FeedbackPrivateAPI::GetService() const {
64 return service_;
65 }
66
RequestFeedback(const std::string & description_template,const std::string & category_tag,const GURL & page_url)67 void FeedbackPrivateAPI::RequestFeedback(
68 const std::string& description_template,
69 const std::string& category_tag,
70 const GURL& page_url) {
71 if (browser_context_ && EventRouter::Get(browser_context_)) {
72 FeedbackInfo info;
73 info.description = description_template;
74 info.category_tag = make_scoped_ptr(new std::string(category_tag));
75 info.page_url = make_scoped_ptr(new std::string(page_url.spec()));
76 info.system_information.reset(new SystemInformationList);
77 // The manager is only available if tracing is enabled.
78 if (TracingManager* manager = TracingManager::Get()) {
79 info.trace_id.reset(new int(manager->RequestTrace()));
80 }
81
82 scoped_ptr<base::ListValue> args(new base::ListValue());
83 args->Append(info.ToValue().release());
84
85 scoped_ptr<Event> event(new Event(
86 feedback_private::OnFeedbackRequested::kEventName, args.Pass()));
87 event->restrict_to_browser_context = browser_context_;
88
89 EventRouter::Get(browser_context_)
90 ->DispatchEventToExtension(kFeedbackExtensionId, event.Pass());
91 }
92 }
93
94 // static
95 base::Closure* FeedbackPrivateGetStringsFunction::test_callback_ = NULL;
96
RunSync()97 bool FeedbackPrivateGetStringsFunction::RunSync() {
98 base::DictionaryValue* dict = new base::DictionaryValue();
99 SetResult(dict);
100
101 #define SET_STRING(id, idr) \
102 dict->SetString(id, l10n_util::GetStringUTF16(idr))
103 SET_STRING("page-title", IDS_FEEDBACK_REPORT_PAGE_TITLE);
104 SET_STRING("page-url", IDS_FEEDBACK_REPORT_URL_LABEL);
105 SET_STRING("screenshot", IDS_FEEDBACK_SCREENSHOT_LABEL);
106 SET_STRING("user-email", IDS_FEEDBACK_USER_EMAIL_LABEL);
107 #if defined(OS_CHROMEOS)
108 SET_STRING("sys-info",
109 IDS_FEEDBACK_INCLUDE_SYSTEM_INFORMATION_AND_METRICS_CHKBOX);
110 #else
111 SET_STRING("sys-info", IDS_FEEDBACK_INCLUDE_SYSTEM_INFORMATION_CHKBOX);
112 #endif
113 SET_STRING("attach-file-label", IDS_FEEDBACK_ATTACH_FILE_LABEL);
114 SET_STRING("attach-file-note", IDS_FEEDBACK_ATTACH_FILE_NOTE);
115 SET_STRING("attach-file-to-big", IDS_FEEDBACK_ATTACH_FILE_TO_BIG);
116 SET_STRING("reading-file", IDS_FEEDBACK_READING_FILE);
117 SET_STRING("send-report", IDS_FEEDBACK_SEND_REPORT);
118 SET_STRING("cancel", IDS_CANCEL);
119 SET_STRING("no-description", IDS_FEEDBACK_NO_DESCRIPTION);
120 SET_STRING("privacy-note", IDS_FEEDBACK_PRIVACY_NOTE);
121 SET_STRING("performance-trace",
122 IDS_FEEDBACK_INCLUDE_PERFORMANCE_TRACE_CHECKBOX);
123 #undef SET_STRING
124
125 webui::SetFontAndTextDirection(dict);
126
127 if (test_callback_ && !test_callback_->is_null())
128 test_callback_->Run();
129
130 return true;
131 }
132
RunSync()133 bool FeedbackPrivateGetUserEmailFunction::RunSync() {
134 FeedbackService* service =
135 FeedbackPrivateAPI::GetFactoryInstance()->Get(GetProfile())->GetService();
136 DCHECK(service);
137 SetResult(new base::StringValue(service->GetUserEmail()));
138 return true;
139 }
140
RunAsync()141 bool FeedbackPrivateGetSystemInformationFunction::RunAsync() {
142 FeedbackService* service =
143 FeedbackPrivateAPI::GetFactoryInstance()->Get(GetProfile())->GetService();
144 DCHECK(service);
145 service->GetSystemInformation(
146 base::Bind(
147 &FeedbackPrivateGetSystemInformationFunction::OnCompleted, this));
148 return true;
149 }
150
OnCompleted(const SystemInformationList & sys_info)151 void FeedbackPrivateGetSystemInformationFunction::OnCompleted(
152 const SystemInformationList& sys_info) {
153 results_ = feedback_private::GetSystemInformation::Results::Create(
154 sys_info);
155 SendResponse(true);
156 }
157
RunAsync()158 bool FeedbackPrivateSendFeedbackFunction::RunAsync() {
159 scoped_ptr<feedback_private::SendFeedback::Params> params(
160 feedback_private::SendFeedback::Params::Create(*args_));
161 EXTENSION_FUNCTION_VALIDATE(params.get());
162
163 const FeedbackInfo &feedback_info = params->feedback;
164
165 std::string attached_file_uuid;
166 if (feedback_info.attached_file_blob_uuid.get() &&
167 !feedback_info.attached_file_blob_uuid->empty())
168 attached_file_uuid = *feedback_info.attached_file_blob_uuid;
169
170 std::string screenshot_uuid;
171 if (feedback_info.screenshot_blob_uuid.get() &&
172 !feedback_info.screenshot_blob_uuid->empty())
173 screenshot_uuid = *feedback_info.screenshot_blob_uuid;
174
175 // Populate feedback data.
176 scoped_refptr<FeedbackData> feedback_data(new FeedbackData());
177 feedback_data->set_context(GetProfile());
178 feedback_data->set_description(feedback_info.description);
179
180 if (feedback_info.category_tag.get())
181 feedback_data->set_category_tag(*feedback_info.category_tag.get());
182 if (feedback_info.page_url.get())
183 feedback_data->set_page_url(*feedback_info.page_url.get());
184 if (feedback_info.email.get())
185 feedback_data->set_user_email(*feedback_info.email.get());
186
187 if (!attached_file_uuid.empty()) {
188 feedback_data->set_attached_filename(
189 StripFakepath((*feedback_info.attached_file.get()).name));
190 feedback_data->set_attached_file_uuid(attached_file_uuid);
191 }
192
193 if (!screenshot_uuid.empty())
194 feedback_data->set_screenshot_uuid(screenshot_uuid);
195
196 if (feedback_info.trace_id.get()) {
197 feedback_data->set_trace_id(*feedback_info.trace_id.get());
198 }
199
200 scoped_ptr<FeedbackData::SystemLogsMap> sys_logs(
201 new FeedbackData::SystemLogsMap);
202 SystemInformationList* sys_info = feedback_info.system_information.get();
203 if (sys_info) {
204 for (SystemInformationList::iterator it = sys_info->begin();
205 it != sys_info->end(); ++it)
206 (*sys_logs.get())[it->get()->key] = it->get()->value;
207 }
208 feedback_data->SetAndCompressSystemInfo(sys_logs.Pass());
209
210 FeedbackService* service =
211 FeedbackPrivateAPI::GetFactoryInstance()->Get(GetProfile())->GetService();
212 DCHECK(service);
213
214 if (feedback_info.send_histograms) {
215 scoped_ptr<std::string> histograms(new std::string);
216 service->GetHistograms(histograms.get());
217 if (!histograms->empty())
218 feedback_data->SetAndCompressHistograms(histograms.Pass());
219 }
220
221 service->SendFeedback(
222 GetProfile(),
223 feedback_data,
224 base::Bind(&FeedbackPrivateSendFeedbackFunction::OnCompleted, this));
225
226 return true;
227 }
228
OnCompleted(bool success)229 void FeedbackPrivateSendFeedbackFunction::OnCompleted(
230 bool success) {
231 results_ = feedback_private::SendFeedback::Results::Create(
232 success ? feedback_private::STATUS_SUCCESS :
233 feedback_private::STATUS_DELAYED);
234 SendResponse(true);
235 }
236
237 } // namespace extensions
238