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 "base/memory/scoped_vector.h"
6#include "components/component_updater/update_response.h"
7#include "libxml/globals.h"
8#include "testing/gtest/include/gtest/gtest.h"
9
10namespace component_updater {
11
12const char* kValidXml =
13    "<?xml version='1.0' encoding='UTF-8'?>"
14    "<response protocol='3.0'>"
15    " <app appid='12345'>"
16    "   <updatecheck status='ok'>"
17    "     <urls>"
18    "       <url codebase='http://example.com/'/>"
19    "       <url codebasediff='http://diff.example.com/'/>"
20    "     </urls>"
21    "     <manifest version='1.2.3.4' prodversionmin='2.0.143.0'>"
22    "       <packages>"
23    "         <package name='extension_1_2_3_4.crx'/>"
24    "       </packages>"
25    "     </manifest>"
26    "   </updatecheck>"
27    " </app>"
28    "</response>";
29
30const char* valid_xml_with_hash =
31    "<?xml version='1.0' encoding='UTF-8'?>"
32    "<response protocol='3.0'>"
33    " <app appid='12345'>"
34    "   <updatecheck status='ok'>"
35    "     <urls>"
36    "       <url codebase='http://example.com/'/>"
37    "     </urls>"
38    "     <manifest version='1.2.3.4' prodversionmin='2.0.143.0'>"
39    "       <packages>"
40    "         <package name='extension_1_2_3_4.crx' hash_sha256='1234'/>"
41    "       </packages>"
42    "     </manifest>"
43    "   </updatecheck>"
44    " </app>"
45    "</response>";
46
47const char* valid_xml_with_invalid_sizes =
48    "<?xml version='1.0' encoding='UTF-8'?>"
49    "<response protocol='3.0'>"
50    " <app appid='12345'>"
51    "   <updatecheck status='ok'>"
52    "     <urls>"
53    "       <url codebase='http://example.com/'/>"
54    "     </urls>"
55    "     <manifest version='1.2.3.4' prodversionmin='2.0.143.0'>"
56    "       <packages>"
57    "         <package name='1' size='1234'/>"
58    "         <package name='2' size='-1234'/>"
59    "         <package name='3' />"
60    "         <package name='4' size='-a'/>"
61    "         <package name='5' size='-123467890123456789'/>"
62    "         <package name='6' size='123467890123456789'/>"
63    "       </packages>"
64    "     </manifest>"
65    "   </updatecheck>"
66    " </app>"
67    "</response>";
68
69const char* kInvalidValidXmlMissingCodebase =
70    "<?xml version='1.0' encoding='UTF-8'?>"
71    "<response protocol='3.0'>"
72    " <app appid='12345'>"
73    "   <updatecheck status='ok'>"
74    "     <urls>"
75    "       <url codebasediff='http://diff.example.com/'/>"
76    "     </urls>"
77    "     <manifest version='1.2.3.4' prodversionmin='2.0.143.0'>"
78    "       <packages>"
79    "         <package namediff='extension_1_2_3_4.crx'/>"
80    "       </packages>"
81    "     </manifest>"
82    "   </updatecheck>"
83    " </app>"
84    "</response>";
85
86const char* kMissingAppId =
87    "<?xml version='1.0'?>"
88    "<response protocol='3.0'>"
89    " <app>"
90    "  <updatecheck codebase='http://example.com/extension_1.2.3.4.crx'"
91    "               version='1.2.3.4' />"
92    " </app>"
93    "</response>";
94
95const char* kInvalidCodebase =
96    "<?xml version='1.0'?>"
97    "<response protocol='3.0'>"
98    " <app appid='12345' status='ok'>"
99    "  <updatecheck codebase='example.com/extension_1.2.3.4.crx'"
100    "               version='1.2.3.4' />"
101    " </app>"
102    "</response>";
103
104const char* kMissingVersion =
105    "<?xml version='1.0'?>"
106    "<response protocol='3.0'>"
107    " <app appid='12345' status='ok'>"
108    "  <updatecheck codebase='http://example.com/extension_1.2.3.4.crx' />"
109    " </app>"
110    "</response>";
111
112const char* kInvalidVersion =
113    "<?xml version='1.0'?>"
114    "<response protocol='3.0'>"
115    " <app appid='12345' status='ok'>"
116    "  <updatecheck codebase='http://example.com/extension_1.2.3.4.crx' "
117    "               version='1.2.3.a'/>"
118    " </app>"
119    "</response>";
120
121// The v3 version of the protocol is not using namespaces. However, the parser
122// must be able to parse responses that include namespaces.
123const char* kUsesNamespacePrefix =
124    "<?xml version='1.0' encoding='UTF-8'?>"
125    "<g:response xmlns:g='http://www.google.com/update2/response' protocol='3.0'>"
126    " <g:app appid='12345'>"
127    "   <g:updatecheck status='ok'>"
128    "     <g:urls>"
129    "       <g:url codebase='http://example.com/'/>"
130    "     </g:urls>"
131    "     <g:manifest version='1.2.3.4' prodversionmin='2.0.143.0'>"
132    "       <g:packages>"
133    "         <g:package name='extension_1_2_3_4.crx'/>"
134    "       </g:packages>"
135    "     </g:manifest>"
136    "   </g:updatecheck>"
137    " </g:app>"
138    "</g:response>";
139
140// Includes unrelated <app> tags from other xml namespaces - this should
141// not cause problems.
142const char* kSimilarTagnames =
143    "<?xml version='1.0' encoding='UTF-8'?>"
144    "<response xmlns:a='http://a' protocol='3.0'>"
145    " <a:app appid='12345'>"
146    "   <updatecheck status='ok'>"
147    "     <urls>"
148    "       <url codebase='http://example.com/'/>"
149    "     </urls>"
150    "     <manifest version='1.2.3.4' prodversionmin='2.0.143.0'>"
151    "       <packages>"
152    "         <package name='extension_1_2_3_4.crx'/>"
153    "       </packages>"
154    "     </manifest>"
155    "   </updatecheck>"
156    " </a:app>"
157    " <b:app appid='xyz' xmlns:b='http://b'>"
158    "   <updatecheck status='noupdate'/>"
159    " </b:app>"
160    "</response>";
161
162// Includes a <daystart> tag.
163const char* kWithDaystart =
164    "<?xml version='1.0' encoding='UTF-8'?>"
165    "<response protocol='3.0'>"
166    " <daystart elapsed_seconds='456' />"
167    " <app appid='12345'>"
168    "   <updatecheck status='ok'>"
169    "     <urls>"
170    "       <url codebase='http://example.com/'/>"
171    "     </urls>"
172    "     <manifest version='1.2.3.4' prodversionmin='2.0.143.0'>"
173    "       <packages>"
174    "         <package name='extension_1_2_3_4.crx'/>"
175    "       </packages>"
176    "     </manifest>"
177    "   </updatecheck>"
178    " </app>"
179    "</response>";
180
181// Indicates no updates available - this should not be a parse error.
182const char* kNoUpdate =
183    "<?xml version='1.0' encoding='UTF-8'?>"
184    "<response protocol='3.0'>"
185    " <app appid='12345'>"
186    "  <updatecheck status='noupdate' />"
187    " </app>"
188    "</response>";
189
190// Includes two <app> tags, one with an error.
191const char* kTwoAppsOneError =
192    "<?xml version='1.0' encoding='UTF-8'?>"
193    "<response protocol='3.0'>"
194    " <app appid='aaaaaaaa' status='error-unknownApplication'>"
195    "  <updatecheck status='error-unknownapplication'/>"
196    " </app>"
197    " <app appid='bbbbbbbb'>"
198    "   <updatecheck status='ok'>"
199    "     <urls>"
200    "       <url codebase='http://example.com/'/>"
201    "     </urls>"
202    "     <manifest version='1.2.3.4' prodversionmin='2.0.143.0'>"
203    "       <packages>"
204    "         <package name='extension_1_2_3_4.crx'/>"
205    "       </packages>"
206    "     </manifest>"
207    "   </updatecheck>"
208    " </app>"
209    "</response>";
210
211TEST(ComponentUpdaterUpdateResponseTest, TestParser) {
212  UpdateResponse parser;
213
214  // Test parsing of a number of invalid xml cases
215  EXPECT_FALSE(parser.Parse(std::string()));
216  EXPECT_FALSE(parser.errors().empty());
217
218  EXPECT_TRUE(parser.Parse(kMissingAppId));
219  EXPECT_TRUE(parser.results().list.empty());
220  EXPECT_FALSE(parser.errors().empty());
221
222  EXPECT_TRUE(parser.Parse(kInvalidCodebase));
223  EXPECT_TRUE(parser.results().list.empty());
224  EXPECT_FALSE(parser.errors().empty());
225
226  EXPECT_TRUE(parser.Parse(kMissingVersion));
227  EXPECT_TRUE(parser.results().list.empty());
228  EXPECT_FALSE(parser.errors().empty());
229
230  EXPECT_TRUE(parser.Parse(kInvalidVersion));
231  EXPECT_TRUE(parser.results().list.empty());
232  EXPECT_FALSE(parser.errors().empty());
233
234  EXPECT_TRUE(parser.Parse(kInvalidValidXmlMissingCodebase));
235  EXPECT_TRUE(parser.results().list.empty());
236  EXPECT_FALSE(parser.errors().empty());
237
238  // Parse some valid XML, and check that all params came out as expected
239  EXPECT_TRUE(parser.Parse(kValidXml));
240  EXPECT_TRUE(parser.errors().empty());
241  EXPECT_EQ(1u, parser.results().list.size());
242  const UpdateResponse::Result* firstResult = &parser.results().list[0];
243  EXPECT_EQ(1u, firstResult->crx_urls.size());
244  EXPECT_EQ(GURL("http://example.com/"), firstResult->crx_urls[0]);
245  EXPECT_EQ(GURL("http://diff.example.com/"), firstResult->crx_diffurls[0]);
246  EXPECT_EQ("1.2.3.4", firstResult->manifest.version);
247  EXPECT_EQ("2.0.143.0", firstResult->manifest.browser_min_version);
248  EXPECT_EQ(1u, firstResult->manifest.packages.size());
249  EXPECT_EQ("extension_1_2_3_4.crx", firstResult->manifest.packages[0].name);
250
251  // Parse some xml that uses namespace prefixes.
252  EXPECT_TRUE(parser.Parse(kUsesNamespacePrefix));
253  EXPECT_TRUE(parser.errors().empty());
254  EXPECT_TRUE(parser.Parse(kSimilarTagnames));
255  EXPECT_TRUE(parser.errors().empty());
256  xmlCleanupGlobals();
257
258  // Parse xml with hash value
259  EXPECT_TRUE(parser.Parse(valid_xml_with_hash));
260  EXPECT_TRUE(parser.errors().empty());
261  EXPECT_FALSE(parser.results().list.empty());
262  firstResult = &parser.results().list[0];
263  EXPECT_FALSE(firstResult->manifest.packages.empty());
264  EXPECT_EQ("1234", firstResult->manifest.packages[0].hash_sha256);
265
266  // Parse xml with package size value
267  EXPECT_TRUE(parser.Parse(valid_xml_with_invalid_sizes));
268  EXPECT_TRUE(parser.errors().empty());
269  EXPECT_FALSE(parser.results().list.empty());
270  firstResult = &parser.results().list[0];
271  EXPECT_FALSE(firstResult->manifest.packages.empty());
272  EXPECT_EQ(1234, firstResult->manifest.packages[0].size);
273  EXPECT_EQ(-1234, firstResult->manifest.packages[1].size);
274  EXPECT_EQ(0, firstResult->manifest.packages[2].size);
275  EXPECT_EQ(0, firstResult->manifest.packages[3].size);
276  EXPECT_EQ(0, firstResult->manifest.packages[4].size);
277  EXPECT_EQ(0, firstResult->manifest.packages[5].size);
278
279  // Parse xml with a <daystart> element.
280  EXPECT_TRUE(parser.Parse(kWithDaystart));
281  EXPECT_TRUE(parser.errors().empty());
282  EXPECT_FALSE(parser.results().list.empty());
283  EXPECT_EQ(parser.results().daystart_elapsed_seconds, 456);
284
285  // Parse a no-update response.
286  EXPECT_TRUE(parser.Parse(kNoUpdate));
287  EXPECT_TRUE(parser.errors().empty());
288  EXPECT_FALSE(parser.results().list.empty());
289  firstResult = &parser.results().list[0];
290  EXPECT_EQ(firstResult->extension_id, "12345");
291  EXPECT_EQ(firstResult->manifest.version, "");
292
293  // Parse xml with one error and one success <app> tag.
294  EXPECT_TRUE(parser.Parse(kTwoAppsOneError));
295  EXPECT_FALSE(parser.errors().empty());
296  EXPECT_EQ(1u, parser.results().list.size());
297  firstResult = &parser.results().list[0];
298  EXPECT_EQ(firstResult->extension_id, "bbbbbbbb");
299}
300
301}  // namespace component_updater
302