Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(134)

Side by Side Diff: components/feedback/feedback_common.cc

Issue 296173003: Refactor FeedbackData and add tests. Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 6 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2014 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 "feedback_common.h"
6
7 #include "base/strings/string_util.h"
8 #include "components/feedback/proto/common.pb.h"
9 #include "components/feedback/proto/dom.pb.h"
10 #include "components/feedback/proto/extension.pb.h"
11 #include "components/feedback/proto/math.pb.h"
12
13 namespace {
14
15 const char kMultilineIndicatorString[] = "<multiline>\n";
16 const char kMultilineStartString[] = "---------- START ----------\n";
17 const char kMultilineEndString[] = "---------- END ----------\n\n";
18
19 const size_t kFeedbackMaxLength = 4 * 1024;
20 const size_t kFeedbackMaxLineCount = 40;
21
22 const base::FilePath::CharType kLogsFilename[] =
23 FILE_PATH_LITERAL("system_logs.txt");
24 const char kLogsAttachmentName[] = "system_logs.zip";
25
26 const char kZipExt[] = ".zip";
27
28 const char kPngMimeType[] = "image/png";
29 const char kArbitraryMimeType[] = "application/octet-stream";
30
31 // Converts the system logs into a string that we can compress and send
32 // with the report. This method only converts those logs that we want in
33 // the compressed zip file sent with the report, hence it ignores any logs
34 // below the size threshold of what we want compressed.
35 std::string* LogsToString(const FeedbackCommon::SystemLogsMap& sys_info) {
36 std::string* syslogs_string = new std::string;
37 for (FeedbackCommon::SystemLogsMap::const_iterator it = sys_info.begin();
38 it != sys_info.end();
39 ++it) {
40 std::string key = it->first;
41 std::string value = it->second;
42
43 if (FeedbackCommon::BelowCompressionThreshold(value))
44 continue;
45
46 base::TrimString(key, "\n ", &key);
47 base::TrimString(value, "\n ", &value);
48
49 if (value.find("\n") != std::string::npos) {
50 syslogs_string->append(key + "=" + kMultilineIndicatorString +
51 kMultilineStartString + value + "\n" +
52 kMultilineEndString);
53 } else {
54 syslogs_string->append(key + "=" + value + "\n");
55 }
56 }
57 return syslogs_string;
58 }
59
60 void AddFeedbackData(userfeedback::ExtensionSubmit* feedback_data,
61 const std::string& key,
62 const std::string& value) {
63 // Don't bother with empty keys or values.
64 if (key == "" || value == "")
Zachary Kuznia 2014/05/28 21:39:36 key.empty() || value.empty()
achaulk 2014/05/29 17:22:29 Done.
65 return;
66 // Create log_value object and add it to the web_data object.
67 userfeedback::ProductSpecificData log_value;
68 log_value.set_key(key);
69 log_value.set_value(value);
70 userfeedback::WebData* web_data = feedback_data->mutable_web_data();
71 *(web_data->add_product_specific_data()) = log_value;
72 }
73
74 // Adds data as an attachment to feedback_data if the data is non-empty.
75 void AddAttachment(userfeedback::ExtensionSubmit* feedback_data,
76 const char* name,
77 const std::string& data) {
78 if (data.empty())
79 return;
80
81 userfeedback::ProductSpecificBinaryData* attachment =
82 feedback_data->add_product_specific_binary_data();
83 attachment->set_mime_type(kArbitraryMimeType);
84 attachment->set_name(name);
85 attachment->set_data(data);
86 }
87
88 } // namespace
89
90 FeedbackCommon::AttachedFile::AttachedFile(const std::string& filename)
91 : name(filename) {}
92
93 FeedbackCommon::FeedbackCommon() : product_id_(0) {}
94
95 FeedbackCommon::~FeedbackCommon() {}
96
97 // static
98 bool FeedbackCommon::BelowCompressionThreshold(const std::string& content) {
99 if (content.length() > kFeedbackMaxLength)
100 return false;
101 const size_t line_count = std::count(content.begin(), content.end(), '\n');
102 if (line_count > kFeedbackMaxLineCount)
103 return false;
104 return true;
105 }
106
107 void FeedbackCommon::CompressFile(const base::FilePath& filename,
108 const std::string& zipname,
109 scoped_ptr<std::string> data) {
110 AttachedFile* file = new AttachedFile(zipname);
111 if (file->name.empty()) {
112 // We need to use the UTF8Unsafe methods here to accomodate Windows, which
113 // uses wide strings to store filepaths.
114 file->name = filename.BaseName().AsUTF8Unsafe();
115 file->name.append(kZipExt);
116 }
117 if (feedback_util::ZipString(filename, *(data.get()), &file->data)) {
118 base::AutoLock lock(attachments_lock_);
119 attachments_.push_back(file);
120 } else {
121 delete file;
122 }
123 }
124
125 void FeedbackCommon::AddFile(const std::string& filename,
126 scoped_ptr<std::string> data) {
Zachary Kuznia 2014/05/28 21:39:36 Why doesn't this take const std::string& for data?
achaulk 2014/05/29 17:22:29 I changed the struct to have a scoped_ptr, oversig
127 AttachedFile* file = new AttachedFile(filename);
128 file->data = *(data.get());
129
130 base::AutoLock lock(attachments_lock_);
131 attachments_.push_back(file);
132 }
133
134 void FeedbackCommon::AddLog(const std::string& name, const std::string& value) {
135 if (!logs_.get())
136 logs_ = scoped_ptr<SystemLogsMap>(new SystemLogsMap);
137 (*logs_.get())[name] = value;
138 }
139
140 void FeedbackCommon::AddLogs(scoped_ptr<SystemLogsMap> logs) {
141 if (logs_.get()) {
Zachary Kuznia 2014/05/28 21:39:36 if (logs_)
achaulk 2014/05/29 17:22:29 Done.
142 for (FeedbackCommon::SystemLogsMap::const_iterator i = logs->begin();
Zachary Kuznia 2014/05/28 21:39:36 Why not logs_->insert(logs->begin(), logs->end());
achaulk 2014/05/29 17:22:29 Yeah that works better
143 i != logs->end();
144 ++i) {
145 (*logs_.get())[i->first] = i->second;
146 }
147 } else {
148 logs_ = logs.Pass();
149 }
150 }
151
152 void FeedbackCommon::CompressLogs() {
153 if (!logs_)
154 return;
155 std::string* logs = LogsToString(*logs_.get());
156 if (!logs->empty())
157 CompressFile(
158 base::FilePath(kLogsFilename), kLogsAttachmentName,
159 scoped_ptr<std::string>(logs));
160 }
161
162 void FeedbackCommon::AddFilesAndLogsToReport(
163 userfeedback::ExtensionSubmit* feedback_data) const {
164 if (sys_info()) {
165 for (FeedbackCommon::SystemLogsMap::const_iterator i = sys_info()->begin();
166 i != sys_info()->end();
167 ++i) {
168 if (BelowCompressionThreshold(i->second))
169 AddFeedbackData(feedback_data, i->first, i->second);
170 }
171 }
172
173 for (size_t i = 0; i < attachments(); i++) {
174 const AttachedFile* file = attachment(i);
175 AddAttachment(feedback_data, file->name.c_str(), file->data);
176 }
177 }
178
179 void FeedbackCommon::PrepareReport(
180 userfeedback::ExtensionSubmit* feedback_data) const {
181 // Unused field, needs to be 0 though.
182 feedback_data->set_type_id(0);
183 feedback_data->set_product_id(product_id_);
184
185 userfeedback::CommonData* common_data = feedback_data->mutable_common_data();
186 // We're not using gaia ids, we're using the e-mail field instead.
187 common_data->set_gaia_id(0);
188 common_data->set_user_email(user_email());
189 common_data->set_description(description());
190 common_data->set_source_description_language(locale());
191
192 userfeedback::WebData* web_data = feedback_data->mutable_web_data();
193 web_data->set_url(page_url());
194 web_data->mutable_navigator()->set_user_agent(user_agent());
195
196 AddFilesAndLogsToReport(feedback_data);
197
198 if (image() && image()->size()) {
199 userfeedback::PostedScreenshot screenshot;
200 screenshot.set_mime_type(kPngMimeType);
201
202 // Set that we 'have' dimensions of the screenshot. These dimensions are
203 // ignored by the server but are a 'required' field in the protobuf.
204 userfeedback::Dimensions dimensions;
205 dimensions.set_width(0.0);
206 dimensions.set_height(0.0);
207
208 *(screenshot.mutable_dimensions()) = dimensions;
209 screenshot.set_binary_content(*image());
210
211 *(feedback_data->mutable_screenshot()) = screenshot;
212 }
213
214 if (category_tag().size())
215 feedback_data->set_bucket(category_tag());
216 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698