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