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

Side by Side Diff: components/update_client/update_response.cc

Issue 808773005: Move most of the component updater artifacts to update_client. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 5 years, 11 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 "components/update_client/update_response.h"
6
7 #include <algorithm>
8
9 #include "base/memory/scoped_ptr.h"
10 #include "base/stl_util.h"
11 #include "base/strings/string_number_conversions.h"
12 #include "base/strings/string_util.h"
13 #include "base/strings/stringprintf.h"
14 #include "base/version.h"
15 #include "libxml/tree.h"
16 #include "third_party/libxml/chromium/libxml_utils.h"
17
18 namespace update_client {
19
20 static const char* kExpectedResponseProtocol = "3.0";
21
22 UpdateResponse::UpdateResponse() {
23 }
24 UpdateResponse::~UpdateResponse() {
25 }
26
27 UpdateResponse::Results::Results() : daystart_elapsed_seconds(kNoDaystart) {
28 }
29 UpdateResponse::Results::~Results() {
30 }
31
32 UpdateResponse::Result::Result() {
33 }
34
35 UpdateResponse::Result::~Result() {
36 }
37
38 UpdateResponse::Result::Manifest::Manifest() {
39 }
40 UpdateResponse::Result::Manifest::~Manifest() {
41 }
42
43 UpdateResponse::Result::Manifest::Package::Package() : size(0), sizediff(0) {
44 }
45 UpdateResponse::Result::Manifest::Package::~Package() {
46 }
47
48 void UpdateResponse::ParseError(const char* details, ...) {
49 va_list args;
50 va_start(args, details);
51
52 if (!errors_.empty()) {
53 errors_ += "\r\n";
54 }
55
56 base::StringAppendV(&errors_, details, args);
57 va_end(args);
58 }
59
60 // Checks whether a given node's name matches |expected_name|.
61 static bool TagNameEquals(const xmlNode* node, const char* expected_name) {
62 return 0 == strcmp(expected_name, reinterpret_cast<const char*>(node->name));
63 }
64
65 // Returns child nodes of |root| with name |name|.
66 static std::vector<xmlNode*> GetChildren(xmlNode* root, const char* name) {
67 std::vector<xmlNode*> result;
68 for (xmlNode* child = root->children; child != NULL; child = child->next) {
69 if (!TagNameEquals(child, name)) {
70 continue;
71 }
72 result.push_back(child);
73 }
74 return result;
75 }
76
77 // Returns the value of a named attribute, or the empty string.
78 static std::string GetAttribute(xmlNode* node, const char* attribute_name) {
79 const xmlChar* name = reinterpret_cast<const xmlChar*>(attribute_name);
80 for (xmlAttr* attr = node->properties; attr != NULL; attr = attr->next) {
81 if (!xmlStrcmp(attr->name, name) && attr->children &&
82 attr->children->content) {
83 return std::string(
84 reinterpret_cast<const char*>(attr->children->content));
85 }
86 }
87 return std::string();
88 }
89
90 // This is used for the xml parser to report errors. This assumes the context
91 // is a pointer to a std::string where the error message should be appended.
92 static void XmlErrorFunc(void* context, const char* message, ...) {
93 va_list args;
94 va_start(args, message);
95 std::string* error = static_cast<std::string*>(context);
96 base::StringAppendV(error, message, args);
97 va_end(args);
98 }
99
100 // Utility class for cleaning up the xml document when leaving a scope.
101 class ScopedXmlDocument {
102 public:
103 explicit ScopedXmlDocument(xmlDocPtr document) : document_(document) {}
104 ~ScopedXmlDocument() {
105 if (document_)
106 xmlFreeDoc(document_);
107 }
108
109 xmlDocPtr get() { return document_; }
110
111 private:
112 xmlDocPtr document_;
113 };
114
115 // Parses the <package> tag.
116 bool ParsePackageTag(xmlNode* package,
117 UpdateResponse::Result* result,
118 std::string* error) {
119 UpdateResponse::Result::Manifest::Package p;
120 p.name = GetAttribute(package, "name");
121 if (p.name.empty()) {
122 *error = "Missing name for package.";
123 return false;
124 }
125
126 p.namediff = GetAttribute(package, "namediff");
127
128 // package_fingerprint is optional. It identifies the package, preferably
129 // with a modified sha256 hash of the package in hex format.
130 p.fingerprint = GetAttribute(package, "fp");
131
132 p.hash_sha256 = GetAttribute(package, "hash_sha256");
133 int size = 0;
134 if (base::StringToInt(GetAttribute(package, "size"), &size)) {
135 p.size = size;
136 }
137
138 p.hashdiff_sha256 = GetAttribute(package, "hashdiff_sha256");
139 int sizediff = 0;
140 if (base::StringToInt(GetAttribute(package, "sizediff"), &sizediff)) {
141 p.sizediff = sizediff;
142 }
143
144 result->manifest.packages.push_back(p);
145
146 return true;
147 }
148
149 // Parses the <manifest> tag.
150 bool ParseManifestTag(xmlNode* manifest,
151 UpdateResponse::Result* result,
152 std::string* error) {
153 // Get the version.
154 result->manifest.version = GetAttribute(manifest, "version");
155 if (result->manifest.version.empty()) {
156 *error = "Missing version for manifest.";
157 return false;
158 }
159 Version version(result->manifest.version);
160 if (!version.IsValid()) {
161 *error = "Invalid version: '";
162 *error += result->manifest.version;
163 *error += "'.";
164 return false;
165 }
166
167 // Get the minimum browser version (not required).
168 result->manifest.browser_min_version =
169 GetAttribute(manifest, "prodversionmin");
170 if (result->manifest.browser_min_version.length()) {
171 Version browser_min_version(result->manifest.browser_min_version);
172 if (!browser_min_version.IsValid()) {
173 *error = "Invalid prodversionmin: '";
174 *error += result->manifest.browser_min_version;
175 *error += "'.";
176 return false;
177 }
178 }
179
180 // Get the <packages> node.
181 std::vector<xmlNode*> packages = GetChildren(manifest, "packages");
182 if (packages.empty()) {
183 *error = "Missing packages tag on manifest.";
184 return false;
185 }
186
187 // Parse each of the <package> tags.
188 std::vector<xmlNode*> package = GetChildren(packages[0], "package");
189 for (size_t i = 0; i != package.size(); ++i) {
190 if (!ParsePackageTag(package[i], result, error))
191 return false;
192 }
193
194 return true;
195 }
196
197 // Parses the <urls> tag and its children in the <updatecheck>.
198 bool ParseUrlsTag(xmlNode* urls,
199 UpdateResponse::Result* result,
200 std::string* error) {
201 // Get the url nodes.
202 std::vector<xmlNode*> url = GetChildren(urls, "url");
203 if (url.empty()) {
204 *error = "Missing url tags on urls.";
205 return false;
206 }
207
208 // Get the list of urls for full and optionally, for diff updates.
209 // There can only be either a codebase or a codebasediff attribute in a tag.
210 for (size_t i = 0; i != url.size(); ++i) {
211 // Find the url to the crx file.
212 const GURL crx_url(GetAttribute(url[i], "codebase"));
213 if (crx_url.is_valid()) {
214 result->crx_urls.push_back(crx_url);
215 continue;
216 }
217 const GURL crx_diffurl(GetAttribute(url[i], "codebasediff"));
218 if (crx_diffurl.is_valid()) {
219 result->crx_diffurls.push_back(crx_diffurl);
220 continue;
221 }
222 }
223
224 // Expect at least one url for full update.
225 if (result->crx_urls.empty()) {
226 *error = "Missing valid url for full update.";
227 return false;
228 }
229
230 return true;
231 }
232
233 // Parses the <updatecheck> tag.
234 bool ParseUpdateCheckTag(xmlNode* updatecheck,
235 UpdateResponse::Result* result,
236 std::string* error) {
237 if (GetAttribute(updatecheck, "status") == "noupdate") {
238 return true;
239 }
240
241 // Get the <urls> tag.
242 std::vector<xmlNode*> urls = GetChildren(updatecheck, "urls");
243 if (urls.empty()) {
244 *error = "Missing urls on updatecheck.";
245 return false;
246 }
247
248 if (!ParseUrlsTag(urls[0], result, error)) {
249 return false;
250 }
251
252 std::vector<xmlNode*> manifests = GetChildren(updatecheck, "manifest");
253 if (urls.empty()) {
254 *error = "Missing urls on updatecheck.";
255 return false;
256 }
257
258 return ParseManifestTag(manifests[0], result, error);
259 }
260
261 // Parses a single <app> tag.
262 bool ParseAppTag(xmlNode* app,
263 UpdateResponse::Result* result,
264 std::string* error) {
265 // Read the crx id.
266 result->extension_id = GetAttribute(app, "appid");
267 if (result->extension_id.empty()) {
268 *error = "Missing appid on app node";
269 return false;
270 }
271
272 // Get the <updatecheck> tag.
273 std::vector<xmlNode*> updates = GetChildren(app, "updatecheck");
274 if (updates.empty()) {
275 *error = "Missing updatecheck on app.";
276 return false;
277 }
278
279 return ParseUpdateCheckTag(updates[0], result, error);
280 }
281
282 bool UpdateResponse::Parse(const std::string& response_xml) {
283 results_.daystart_elapsed_seconds = kNoDaystart;
284 results_.list.clear();
285 errors_.clear();
286
287 if (response_xml.length() < 1) {
288 ParseError("Empty xml");
289 return false;
290 }
291
292 std::string xml_errors;
293 ScopedXmlErrorFunc error_func(&xml_errors, &XmlErrorFunc);
294
295 // Start up the xml parser with the manifest_xml contents.
296 ScopedXmlDocument document(
297 xmlParseDoc(reinterpret_cast<const xmlChar*>(response_xml.c_str())));
298 if (!document.get()) {
299 ParseError("%s", xml_errors.c_str());
300 return false;
301 }
302
303 xmlNode* root = xmlDocGetRootElement(document.get());
304 if (!root) {
305 ParseError("Missing root node");
306 return false;
307 }
308
309 if (!TagNameEquals(root, "response")) {
310 ParseError("Missing response tag");
311 return false;
312 }
313
314 // Check for the response "protocol" attribute.
315 if (GetAttribute(root, "protocol") != kExpectedResponseProtocol) {
316 ParseError(
317 "Missing/incorrect protocol on response tag "
318 "(expected '%s')",
319 kExpectedResponseProtocol);
320 return false;
321 }
322
323 // Parse the first <daystart> if it is present.
324 std::vector<xmlNode*> daystarts = GetChildren(root, "daystart");
325 if (!daystarts.empty()) {
326 xmlNode* first = daystarts[0];
327 std::string elapsed_seconds = GetAttribute(first, "elapsed_seconds");
328 int parsed_elapsed = kNoDaystart;
329 if (base::StringToInt(elapsed_seconds, &parsed_elapsed)) {
330 results_.daystart_elapsed_seconds = parsed_elapsed;
331 }
332 }
333
334 // Parse each of the <app> tags.
335 std::vector<xmlNode*> apps = GetChildren(root, "app");
336 for (size_t i = 0; i != apps.size(); ++i) {
337 Result result;
338 std::string error;
339 if (ParseAppTag(apps[i], &result, &error)) {
340 results_.list.push_back(result);
341 } else {
342 ParseError("%s", error.c_str());
343 }
344 }
345
346 return true;
347 }
348
349 } // namespace update_client
OLDNEW
« no previous file with comments | « components/update_client/update_response.h ('k') | components/update_client/url_fetcher_downloader.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698