OLD | NEW |
| (Empty) |
1 // Copyright 2008-2010 Google Inc. | |
2 // | |
3 // Licensed under the Apache License, Version 2.0 (the "License"); | |
4 // you may not use this file except in compliance with the License. | |
5 // You may obtain a copy of the License at | |
6 // | |
7 // http://www.apache.org/licenses/LICENSE-2.0 | |
8 // | |
9 // Unless required by applicable law or agreed to in writing, software | |
10 // distributed under the License is distributed on an "AS IS" BASIS, | |
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
12 // See the License for the specific language governing permissions and | |
13 // limitations under the License. | |
14 // ======================================================================== | |
15 | |
16 | |
17 #include "omaha/tools/omahacompatibility/httpserver/xml_parser.h" | |
18 #include <msxml2.h> | |
19 #include "omaha/common/string.h" | |
20 #include "omaha/common/xml_utils.h" | |
21 #include "omaha/goopdate/goopdate_xml_parser.h" | |
22 | |
23 namespace omaha { | |
24 | |
25 // Constant strings to form the server responses. | |
26 const TCHAR* const kResponseXmlHeader = _T("<?xml version=\"1.0\" encoding=\"UTF
-8\"?>"); // NOLINT | |
27 const TCHAR* const kResponseXmlGupdateHeader = _T("<gupdate xmlns=\"http://www.g
oogle.com/update2/response\" protocol=\"2.0\">"); // NOLINT | |
28 const TCHAR* const kResponseAppEvent = _T("<app appid=\"%s\" status=\"ok\"><even
t status=\"ok\"/></app>"); // NOLINT | |
29 const TCHAR* const kResponseAppNoUpdate = _T("<app appid=\"%s\" status=\"ok\"><e
vent status=\"no-update\"/></app>"); // NOLINT | |
30 const TCHAR* const kResponseAppUpdate = _T("<app appid=\"%s\" status=\"ok\"><upd
atecheck codebase=\"%s\" hash=\"%s\" needsadmin=\"%s\" size=\"%d\" status=\"ok\"
/></app>"); // NOLINT | |
31 const TCHAR* const kResponseGupdateEndTag = _T("</gupdate>"); | |
32 | |
33 // Constants for creating the xml request. | |
34 namespace Xml { | |
35 const TCHAR* const kHeaderText = | |
36 _T("<?xml version=\"1.0\" encoding=\"UTF-8\"?>"); | |
37 const TCHAR* const kProcessingText = | |
38 _T("version=\"1.0\" encoding=\"UTF-8\""); | |
39 | |
40 namespace Namespace { | |
41 const TCHAR* const kRequest = _T("http://www.google.com/update2/request"); | |
42 const TCHAR* const kResponse = _T("http://www.google.com/update2/response"); | |
43 const TCHAR* const kSeed = _T("http://www.google.com/update2/install"); | |
44 } // Namespace. | |
45 | |
46 namespace Element { | |
47 const TCHAR* const kXml = _T("xml"); | |
48 const TCHAR* const kRequests = _T("gupdate"); | |
49 const TCHAR* const kOmahaVersion = _T("updaterversion"); | |
50 const TCHAR* const kOs = _T("os"); | |
51 const TCHAR* const kApp = _T("app"); | |
52 const TCHAR* const kUpdateCheck = _T("updatecheck"); | |
53 const TCHAR* const kPing = _T("ping"); | |
54 const TCHAR* const kEvent = _T("event"); | |
55 const TCHAR* const kComponents = _T("components"); | |
56 const TCHAR* const kComponent = _T("component"); | |
57 | |
58 const TCHAR* const kResponses = _T("gupdate"); | |
59 } // namespace Element. | |
60 | |
61 namespace Attribute { | |
62 const TCHAR* const kActive = _T("active"); | |
63 const TCHAR* const kAdditionalParameter = _T("ap"); | |
64 const TCHAR* const kAppGuid = _T("appguid"); | |
65 const TCHAR* const kApplicationName = _T("appname"); | |
66 const TCHAR* const kAppId = _T("appid"); | |
67 const TCHAR* const kArguments = _T("arguments"); | |
68 const TCHAR* const kBrandCode = _T("brand"); | |
69 const TCHAR* const kBrowserType = _T("browser"); | |
70 const TCHAR* const kClientId = _T("client"); | |
71 const TCHAR* const kCodebase = _T("codebase"); | |
72 const TCHAR* const kCountry = _T("country"); | |
73 const TCHAR* const kErrorCode = _T("errorcode"); | |
74 const TCHAR* const kEventResult = _T("eventresult"); | |
75 const TCHAR* const kEventType = _T("eventtype"); | |
76 const TCHAR* const kExtraCode1 = _T("extracode1"); | |
77 const TCHAR* const kHash = _T("hash"); | |
78 const TCHAR* const kIsMachine = _T("ismachine"); | |
79 const TCHAR* const kInstallationId = _T("iid"); | |
80 const TCHAR* const kInstallSource = _T("installsource"); | |
81 const TCHAR* const kLang = _T("lang"); | |
82 const TCHAR* const kNeedsAdmin = _T("needsadmin"); | |
83 const TCHAR* const kParameter = _T("parameter"); | |
84 const TCHAR* const kPlatform = _T("platform"); | |
85 const TCHAR* const kPreviousVersion = _T("previousversion"); | |
86 const TCHAR* const kProtocol = _T("protocol"); | |
87 const TCHAR* const kServicePack = _T("sp"); | |
88 const TCHAR* const kSessionId = _T("sessionid"); | |
89 const TCHAR* const kSignature = _T("signature"); | |
90 const TCHAR* const kSize = _T("size"); | |
91 const TCHAR* const kStatus = _T("status"); | |
92 const TCHAR* const kSuccessAction = _T("onsuccess"); | |
93 const TCHAR* const kSuccessUrl = _T("successurl"); | |
94 const TCHAR* const kTag = _T("tag"); | |
95 const TCHAR* const kTestSource = _T("testsource"); | |
96 const TCHAR* const kTerminateAllBrowsers = _T("terminateallbrowsers"); | |
97 const TCHAR* const kVersion = _T("version"); | |
98 const TCHAR* const kXmlns = _T("xmlns"); | |
99 const TCHAR* const kTTToken = _T("tttoken"); | |
100 } // namespace Attribute. | |
101 | |
102 namespace Value { | |
103 const TCHAR* const kRequestType = _T("UpdateRequest"); | |
104 const TCHAR* const kProtocol = _T("2.0"); | |
105 const TCHAR* const kVersion2 = _T("2.0"); | |
106 const TCHAR* const kVersion3 = _T("3.0"); | |
107 const TCHAR* const kTrue = _T("true"); | |
108 const TCHAR* const kFalse = _T("false"); | |
109 const TCHAR* const kStatusError = _T("error"); | |
110 const TCHAR* const kSuccessActionDefault = _T("default"); | |
111 const TCHAR* const kSuccessActionExitSilently = _T("exitsilently"); | |
112 const TCHAR* const kWinPlatform = _T("win"); | |
113 | |
114 const TCHAR* const kStatusOk = kResponseStatusOkValue; | |
115 } // namespace value. | |
116 } // namespace xml. | |
117 | |
118 HRESULT ReadAttribute(IXMLDOMNode* node, | |
119 const TCHAR* attr_name, | |
120 BSTR* value) { | |
121 ASSERT1(node != NULL); | |
122 ASSERT1(attr_name != NULL); | |
123 ASSERT1(value != NULL); | |
124 | |
125 // First read the attributes. | |
126 CComPtr<IXMLDOMNamedNodeMap> attributes; | |
127 HRESULT hr = node->get_attributes(&attributes); | |
128 if (FAILED(hr)) { return hr; } | |
129 if (!attributes) { return E_FAIL; } // Protect against msxml S_FALSE return. | |
130 | |
131 CComPtr<IXMLDOMNode> attribute_node; | |
132 CComVariant node_value; | |
133 CComBSTR temp_attr_name(attr_name); | |
134 | |
135 // Get the attribute using a named node. | |
136 hr = attributes->getNamedItem(static_cast<BSTR>(temp_attr_name), | |
137 &attribute_node); | |
138 if (FAILED(hr)) { return hr; } | |
139 if (!attribute_node) { return E_FAIL; } // Protect against msxml S_FALSE | |
140 // return. | |
141 | |
142 hr = attribute_node->get_nodeValue(&node_value); | |
143 if (FAILED(hr)) { return hr; } | |
144 if (node_value.vt == VT_EMPTY) { return E_FAIL; } | |
145 | |
146 // Extract the variant into a BSTR. | |
147 node_value.CopyTo(value); | |
148 | |
149 return S_OK; | |
150 } | |
151 | |
152 HRESULT ReadIntAttribute(IXMLDOMNode* node, | |
153 const TCHAR* attr_name, | |
154 int* value) { | |
155 ASSERT1(node != NULL); | |
156 ASSERT1(attr_name != NULL); | |
157 ASSERT1(value != NULL); | |
158 | |
159 CComBSTR node_value; | |
160 HRESULT hr = ReadAttribute(node, attr_name, &node_value); | |
161 if (FAILED(hr)) { return hr; } | |
162 if (!String_StringToDecimalIntChecked( | |
163 static_cast<const TCHAR*>(node_value), value)) { | |
164 return E_FAIL; | |
165 } | |
166 return S_OK; | |
167 } | |
168 | |
169 HRESULT ReadGuidAttribute(IXMLDOMNode* node, | |
170 const TCHAR* attr_name, | |
171 GUID* value) { | |
172 ASSERT1(node != NULL); | |
173 ASSERT1(attr_name != NULL); | |
174 ASSERT1(value != NULL); | |
175 | |
176 CComBSTR node_value; | |
177 HRESULT hr = ReadAttribute(node, attr_name, &node_value); | |
178 if (FAILED(hr)) { return hr; } | |
179 hr = ::CLSIDFromString(static_cast<TCHAR*>(node_value), value); | |
180 if (FAILED(hr)) { return hr; } | |
181 | |
182 return S_OK; | |
183 } | |
184 | |
185 HRESULT ReadStringAttribute(IXMLDOMNode* node, | |
186 const TCHAR* attr_name, | |
187 CString* value) { | |
188 ASSERT1(node != NULL); | |
189 ASSERT1(attr_name != NULL); | |
190 ASSERT1(value != NULL); | |
191 | |
192 CComBSTR node_value; | |
193 HRESULT hr = ReadAttribute(node, attr_name, &node_value); | |
194 if (FAILED(hr)) { return hr; } | |
195 | |
196 // Will extract the underlying string. | |
197 *value = static_cast<TCHAR*>(node_value); | |
198 | |
199 return S_OK; | |
200 } | |
201 | |
202 HRESULT ParseAppUpdateCheckNode(IXMLDOMNode* node, AppData* request) { | |
203 ASSERT1(node); | |
204 ASSERT1(request); | |
205 | |
206 // Read the tag value. | |
207 CString str; | |
208 ReadStringAttribute(node, Xml::Attribute::kTag, &str); | |
209 request->set_ap(str); | |
210 | |
211 return S_OK; | |
212 } | |
213 | |
214 HRESULT ParseAppPingNode(IXMLDOMNode* node, AppRequestData* request) { | |
215 ASSERT1(node); | |
216 ASSERT1(request); | |
217 | |
218 // Read the event type. | |
219 int event_type = 0; | |
220 HRESULT hr = ReadIntAttribute(node, Xml::Attribute::kEventType, &event_type); | |
221 if (FAILED(hr)) { return hr; } | |
222 | |
223 // Read the event result. | |
224 int event_result = 0; | |
225 hr = ReadIntAttribute(node, Xml::Attribute::kEventResult, &event_result); | |
226 if (FAILED(hr)) { return hr; } | |
227 | |
228 // Read the errorcode. | |
229 int error_code = 0; | |
230 hr = ReadIntAttribute(node, Xml::Attribute::kErrorCode, &error_code); | |
231 if (FAILED(hr)) { return hr; } | |
232 | |
233 // Read the extracode1. | |
234 int extra_code = 0; | |
235 hr = ReadIntAttribute(node, Xml::Attribute::kExtraCode1, &extra_code); | |
236 if (FAILED(hr)) { return hr; } | |
237 | |
238 PingEvent ping_event(static_cast<PingEvent::Types>(event_type), | |
239 static_cast<PingEvent::Results>(event_result), | |
240 error_code, | |
241 extra_code, | |
242 CString()); | |
243 request->AddPingEvent(ping_event); | |
244 | |
245 return S_OK; | |
246 } | |
247 | |
248 HRESULT ParseAppNode(IXMLDOMNode* node, AppRequestDataVector* request) { | |
249 ASSERT1(node); | |
250 ASSERT1(request); | |
251 | |
252 AppRequest app_request; | |
253 AppData app_data; | |
254 AppRequestData app_request_data; | |
255 | |
256 // Read the app guid. | |
257 GUID guid = {0}; | |
258 HRESULT hr = ReadGuidAttribute(node, Xml::Attribute::kAppId, &guid); | |
259 if (FAILED(hr)) { return hr; } | |
260 app_data.set_app_guid(guid); | |
261 | |
262 // Read the app version. | |
263 CString str; | |
264 hr = ReadStringAttribute(node, Xml::Attribute::kVersion, &str); | |
265 if (FAILED(hr)) { return hr; } | |
266 app_data.set_version(str); | |
267 | |
268 // Read the app language. | |
269 hr = ReadStringAttribute(node, Xml::Attribute::kLang, &str); | |
270 if (FAILED(hr)) { return hr; } | |
271 app_data.set_language(str); | |
272 | |
273 CComPtr<IXMLDOMNodeList> child_nodes; | |
274 // Get all the children of the Node. | |
275 hr = node->get_childNodes(&child_nodes); | |
276 if (FAILED(hr)) { return hr; } | |
277 if (!child_nodes) { return E_FAIL; } // Protect against msxml S_FALSE return. | |
278 | |
279 // Go Over all the children and read each of them. we will ignore ones that | |
280 // we dont understand. | |
281 hr = child_nodes->reset(); | |
282 if (FAILED(hr)) { return hr; } | |
283 | |
284 CComPtr<IXMLDOMNode> child_node; | |
285 while (child_nodes->nextNode(&child_node) != S_FALSE) { | |
286 XMLFQName child_node_name; | |
287 hr = GetXMLFQName(child_node, &child_node_name); | |
288 if (FAILED(hr)) { return hr; } | |
289 | |
290 if (child_node_name.base == Xml::Element::kUpdateCheck) { | |
291 // Read in the update check request. | |
292 hr = ParseAppUpdateCheckNode(child_node, &app_data); | |
293 if (FAILED(hr)) { return hr; } | |
294 } else if (child_node_name.base == Xml::Element::kEvent) { | |
295 // Read in the ping request. | |
296 hr = ParseAppPingNode(child_node, &app_request_data); | |
297 } | |
298 | |
299 child_node = NULL; | |
300 } | |
301 | |
302 app_request_data.set_app_data(app_data); | |
303 request->push_back(app_request_data); | |
304 return S_OK; | |
305 } | |
306 | |
307 HRESULT ParseGupdateNode(IXMLDOMNode* node, AppRequestDataVector* request) { | |
308 ASSERT1(node); | |
309 ASSERT1(request); | |
310 | |
311 CComPtr<IXMLDOMNodeList> child_nodes; | |
312 // Get all the children of the Node. | |
313 HRESULT hr = node->get_childNodes(&child_nodes); | |
314 if (FAILED(hr)) { return hr; } | |
315 if (!child_nodes) { return E_FAIL; } // Protect against msxml S_FALSE return. | |
316 | |
317 // Go Over all the children and read each of them. we will ignore ones that | |
318 // we dont understand. | |
319 hr = child_nodes->reset(); | |
320 if (FAILED(hr)) { return hr; } | |
321 | |
322 CComPtr<IXMLDOMNode> child_node; | |
323 while (child_nodes->nextNode(&child_node) != S_FALSE) { | |
324 XMLFQName child_node_name; | |
325 hr = GetXMLFQName(child_node, &child_node_name); | |
326 if (FAILED(hr)) { return hr; } | |
327 | |
328 if (child_node_name.base == Xml::Element::kApp) { | |
329 // we got a response we should read that in. | |
330 hr = ParseAppNode(child_node, request); | |
331 if (FAILED(hr)) { return hr; } | |
332 } | |
333 child_node = NULL; | |
334 } | |
335 return S_OK; | |
336 } | |
337 | |
338 HRESULT ParseUpdateCheck(const CString& request_str, | |
339 AppRequestDataVector* request) { | |
340 ASSERT1(request); | |
341 | |
342 CComPtr<IXMLDOMDocument> document; | |
343 HRESULT hr = LoadXMLFromMemory(request_str, false, &document); | |
344 if (FAILED(hr)) { | |
345 return hr; | |
346 } | |
347 | |
348 CComPtr<IXMLDOMElement> document_element; | |
349 hr = document->get_documentElement(&document_element); | |
350 if (FAILED(hr)) { | |
351 return hr; | |
352 } | |
353 if (!document_element) { // Protect against msxml S_FALSE return. | |
354 return E_FAIL; | |
355 } | |
356 | |
357 return ParseGupdateNode(document_element, request); | |
358 } | |
359 | |
360 HRESULT BuildUpdateResponse(const ServerResponses& responses, | |
361 CString* response) { | |
362 ASSERT1(response); | |
363 | |
364 CString response_str(kResponseXmlHeader); | |
365 response_str.Append(kResponseXmlGupdateHeader); | |
366 | |
367 for (size_t i = 0; i < responses.size(); ++i) { | |
368 CString guid = responses[i].guid; | |
369 | |
370 if (responses[i].is_ping) { | |
371 // If the response is to a ping event, then we just add the ok to the | |
372 // response. The reason this works is because we either have a ping | |
373 // request or a update check, never both. If this changes, then we need | |
374 // to change this code. | |
375 response_str.AppendFormat(kResponseAppEvent, guid); | |
376 } else if (responses[i].is_update_response) { | |
377 // respond with the value of the updates. | |
378 UpdateResponseData data = responses[i].response_data; | |
379 response_str.AppendFormat(kResponseAppUpdate, | |
380 guid, | |
381 data.url(), | |
382 data.hash(), | |
383 data.needs_admin() ? _T("true") : _T("false"), | |
384 data.size()); | |
385 } else { | |
386 // respond with a no-update. | |
387 response_str.AppendFormat(kResponseAppNoUpdate, guid); | |
388 } | |
389 } | |
390 | |
391 response_str.Append(kResponseGupdateEndTag); | |
392 *response = response_str; | |
393 return S_OK; | |
394 } | |
395 | |
396 } // namespace omaha | |
OLD | NEW |