| 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 |