| Index: common/xml_parser.cc
|
| diff --git a/common/xml_parser.cc b/common/xml_parser.cc
|
| deleted file mode 100644
|
| index 22c9eb12abce8428e20631ba3886713ae4d1eca7..0000000000000000000000000000000000000000
|
| --- a/common/xml_parser.cc
|
| +++ /dev/null
|
| @@ -1,1457 +0,0 @@
|
| -// Copyright 2007-2010 Google Inc.
|
| -//
|
| -// Licensed under the Apache License, Version 2.0 (the "License");
|
| -// you may not use this file except in compliance with the License.
|
| -// You may obtain a copy of the License at
|
| -//
|
| -// http://www.apache.org/licenses/LICENSE-2.0
|
| -//
|
| -// Unless required by applicable law or agreed to in writing, software
|
| -// distributed under the License is distributed on an "AS IS" BASIS,
|
| -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| -// See the License for the specific language governing permissions and
|
| -// limitations under the License.
|
| -// ========================================================================
|
| -
|
| -#include "omaha/common/xml_parser.h"
|
| -#include <stdlib.h>
|
| -#include <vector>
|
| -#include "base/basictypes.h"
|
| -#include "omaha/base/constants.h"
|
| -#include "omaha/base/error.h"
|
| -#include "omaha/base/string.h"
|
| -#include "omaha/base/utils.h"
|
| -#include "omaha/base/xml_utils.h"
|
| -#include "omaha/common/config_manager.h"
|
| -#include "omaha/common/goopdate_utils.h"
|
| -#include "omaha/common/update_request.h"
|
| -#include "omaha/common/update_response.h"
|
| -#include "omaha/common/xml_const.h"
|
| -
|
| -namespace omaha {
|
| -
|
| -namespace xml {
|
| -
|
| -namespace {
|
| -
|
| -// Helper structure similar with an std::pair but without a constructor.
|
| -// Instance of it can be stored in arrays.
|
| -template <typename Type1, typename Type2>
|
| -struct Tuple {
|
| - Type1 first;
|
| - Type2 second;
|
| -};
|
| -
|
| -// Converts a string to the SuccessfulInstallAction enum.
|
| -HRESULT ConvertStringToSuccessfulInstallAction(
|
| - const CString& str,
|
| - SuccessfulInstallAction* successful_install_action) {
|
| - ASSERT1(successful_install_action);
|
| -
|
| - const Tuple<const TCHAR*, SuccessfulInstallAction> tuples[] = {
|
| - { xml::value::kSuccessActionDefault,
|
| - SUCCESS_ACTION_DEFAULT },
|
| -
|
| - { xml::value::kSuccessActionExitSilently,
|
| - SUCCESS_ACTION_EXIT_SILENTLY },
|
| -
|
| - { xml::value::kSuccessActionExitSilentlyOnLaunchCmd,
|
| - SUCCESS_ACTION_EXIT_SILENTLY_ON_LAUNCH_CMD },
|
| - };
|
| -
|
| - if (str.IsEmpty()) {
|
| - *successful_install_action = SUCCESS_ACTION_DEFAULT;
|
| - return S_OK;
|
| - }
|
| -
|
| - for (size_t i = 0; i != arraysize(tuples); ++i) {
|
| - if (str.CompareNoCase(tuples[i].first) == 0) {
|
| - *successful_install_action = tuples[i].second;
|
| - return S_OK;
|
| - }
|
| - }
|
| -
|
| - // Using the default action allows Omaha to be forward-compatible with
|
| - // new SuccessActions, meaning older versions will not fail if a config
|
| - // uses a new action.
|
| - ASSERT(false, (_T("[Unrecognized success action][%s]"), str));
|
| - *successful_install_action = SUCCESS_ACTION_DEFAULT;
|
| - return S_OK;
|
| -}
|
| -
|
| -HRESULT ConvertStringToInstallEvent(
|
| - const CString& str,
|
| - InstallAction::InstallEvent* install_event) {
|
| - ASSERT1(install_event);
|
| -
|
| - const Tuple<const TCHAR*, InstallAction::InstallEvent> tuples[] = {
|
| - {xml::value::kPreinstall, InstallAction::kPreInstall},
|
| - {xml::value::kInstall, InstallAction::kInstall},
|
| - {xml::value::kUpdate, InstallAction::kUpdate},
|
| - {xml::value::kPostinstall, InstallAction::kPostInstall},
|
| - };
|
| -
|
| - for (size_t i = 0; i != arraysize(tuples); ++i) {
|
| - if (str.CompareNoCase(tuples[i].first) == 0) {
|
| - *install_event = tuples[i].second;
|
| - return S_OK;
|
| - }
|
| - }
|
| -
|
| - return E_INVALIDARG;
|
| -}
|
| -
|
| -// Returns S_OK if each child element of the node is any of the elements
|
| -// provided as an argument. This is useful to detect if the element contains
|
| -// only known children.
|
| -// TODO(omaha): implement.
|
| -HRESULT AreChildrenAnyOf(IXMLDOMNode* node,
|
| - const std::vector<const TCHAR*>& element_names) {
|
| - UNREFERENCED_PARAMETER(node);
|
| - UNREFERENCED_PARAMETER(element_names);
|
| -
|
| - return S_OK;
|
| -}
|
| -
|
| -// TODO(omaha): implement.
|
| -HRESULT HasNoChildren(IXMLDOMNode* node) {
|
| - UNREFERENCED_PARAMETER(node);
|
| - return S_OK;
|
| -}
|
| -
|
| -// Verify that the protocol version is understood. We accept
|
| -// all version numbers where major version is the same as kExpectedVersion
|
| -// which are greater than or equal to kExpectedVersion. In other words,
|
| -// we handle future minor version number increases which should be
|
| -// compatible.
|
| -HRESULT VerifyProtocolCompatibility(const CString& actual_version,
|
| - const CString& expected_version) {
|
| - if (_tcscmp(actual_version, expected_version) != 0) {
|
| - const double version = String_StringToDouble(actual_version);
|
| - const double expected = String_StringToDouble(expected_version);
|
| - if (expected > version) {
|
| - return GOOPDATEXML_E_XMLVERSION;
|
| - }
|
| - const int version_major = static_cast<int>(version);
|
| - const int expected_major = static_cast<int>(expected);
|
| - if (version_major != expected_major) {
|
| - return GOOPDATEXML_E_XMLVERSION;
|
| - }
|
| - }
|
| - return S_OK;
|
| -}
|
| -
|
| -} // namespace
|
| -
|
| -CString ConvertProcessorArchitectureToString(DWORD arch) {
|
| - switch (arch) {
|
| - case PROCESSOR_ARCHITECTURE_INTEL:
|
| - return xml::value::kArchIntel;
|
| -
|
| - case PROCESSOR_ARCHITECTURE_AMD64:
|
| - return xml::value::kArchAmd64;
|
| -
|
| - default:
|
| - ASSERT1(false);
|
| - return xml::value::kArchUnknown;
|
| - };
|
| -}
|
| -
|
| -// The ElementHandler classes should also be in an anonymous namespace but
|
| -// the base class cannot be because it is used in the header file.
|
| -
|
| -// Defines the base class of a hierarchy that deals with validating and
|
| -// parsing of a single node element in the dom. The implementation uses
|
| -// the template method design pattern.
|
| -class ElementHandler {
|
| - public:
|
| - ElementHandler() {}
|
| - virtual ~ElementHandler() {}
|
| -
|
| - HRESULT Handle(IXMLDOMNode* node, response::Response* response) {
|
| - ASSERT1(node);
|
| - ASSERT1(response);
|
| -
|
| - HRESULT hr = Validate(node);
|
| - if (FAILED(hr)) {
|
| - return hr;
|
| - }
|
| -
|
| - hr = Parse(node, response);
|
| - if (FAILED(hr)) {
|
| - return hr;
|
| - }
|
| -
|
| - return S_OK;
|
| - }
|
| -
|
| - private:
|
| - // Validates a node and returns S_OK in case of success.
|
| - virtual HRESULT Validate(IXMLDOMNode* node) {
|
| - UNREFERENCED_PARAMETER(node);
|
| - return S_OK;
|
| - }
|
| -
|
| - // Parses the node and stores its values in the response.
|
| - virtual HRESULT Parse(IXMLDOMNode* node, response::Response* response) {
|
| - UNREFERENCED_PARAMETER(node);
|
| - UNREFERENCED_PARAMETER(response);
|
| - return S_OK;
|
| - }
|
| -
|
| - DISALLOW_COPY_AND_ASSIGN(ElementHandler);
|
| -};
|
| -
|
| -
|
| -// Parses 'response'.
|
| -class ResponseElementHandler : public ElementHandler {
|
| - public:
|
| - static ElementHandler* Create() { return new ResponseElementHandler; }
|
| -
|
| - private:
|
| - virtual HRESULT Parse(IXMLDOMNode* node, response::Response* response) {
|
| - HRESULT hr = ReadStringAttribute(node,
|
| - xml::attribute::kProtocol,
|
| - &response->protocol);
|
| - if (FAILED(hr)) {
|
| - return hr;
|
| - }
|
| - hr = VerifyProtocolCompatibility(response->protocol, xml::value::kVersion3);
|
| - if (FAILED(hr)) {
|
| - return hr;
|
| - }
|
| -
|
| - return S_OK;
|
| - }
|
| -};
|
| -
|
| -// Parses 'app'.
|
| -class AppElementHandler : public ElementHandler {
|
| - public:
|
| - static ElementHandler* Create() { return new AppElementHandler; }
|
| -
|
| - private:
|
| - virtual HRESULT Parse(IXMLDOMNode* node, response::Response* response) {
|
| - response::App app;
|
| -
|
| - HRESULT hr = ReadStringAttribute(node, xml::attribute::kAppId, &app.appid);
|
| - if (FAILED(hr)) {
|
| - return hr;
|
| - }
|
| -
|
| - hr = ReadStringAttribute(node, xml::attribute::kStatus, &app.status);
|
| - if (FAILED(hr)) {
|
| - return hr;
|
| - }
|
| -
|
| - // At present, the server may omit the following optional attributes if the
|
| - // contents would be empty strings. Guard these reads appropriately.
|
| - // TODO(omaha3): If we adapt the server to send an empty string for these
|
| - // attributes, we can remove these checks.
|
| - if (HasAttribute(node, xml::attribute::kExperiments)) {
|
| - hr = ReadStringAttribute(node,
|
| - xml::attribute::kExperiments,
|
| - &app.experiments);
|
| - if (FAILED(hr)) {
|
| - return hr;
|
| - }
|
| - }
|
| -
|
| - response->apps.push_back(app);
|
| - return S_OK;
|
| - }
|
| -};
|
| -
|
| -
|
| -// Parses 'updatecheck'.
|
| -class UpdateCheckElementHandler : public ElementHandler {
|
| - public:
|
| - static ElementHandler* Create() { return new UpdateCheckElementHandler; }
|
| -
|
| - private:
|
| - virtual HRESULT Parse(IXMLDOMNode* node, response::Response* response) {
|
| - response::UpdateCheck& update_check = response->apps.back().update_check;
|
| -
|
| - ReadStringAttribute(node,
|
| - xml::attribute::kTTToken,
|
| - &update_check.tt_token);
|
| -
|
| - ReadStringAttribute(node,
|
| - xml::attribute::kErrorUrl,
|
| - &update_check.error_url);
|
| -
|
| - return ReadStringAttribute(node,
|
| - xml::attribute::kStatus,
|
| - &update_check.status);
|
| - }
|
| -};
|
| -
|
| -
|
| -// Parses 'urls'.
|
| -class UrlsElementHandler : public ElementHandler {
|
| - public:
|
| - static ElementHandler* Create() { return new UrlsElementHandler; }
|
| -};
|
| -
|
| -
|
| -// Parses 'url'.
|
| -class UrlElementHandler : public ElementHandler {
|
| - public:
|
| - static ElementHandler* Create() { return new UrlElementHandler; }
|
| -
|
| - private:
|
| - virtual HRESULT Parse(IXMLDOMNode* node, response::Response* response) {
|
| - CString url;
|
| - HRESULT hr = ReadStringAttribute(node, xml::attribute::kCodebase, &url);
|
| - if (FAILED(hr)) {
|
| - return hr;
|
| - }
|
| -
|
| - response::UpdateCheck& update_check = response->apps.back().update_check;
|
| - update_check.urls.push_back(url);
|
| -
|
| - return S_OK;
|
| - }
|
| -};
|
| -
|
| -
|
| -// Parses 'manifest'.
|
| -class ManifestElementHandler : public ElementHandler {
|
| - public:
|
| - static ElementHandler* Create() { return new ManifestElementHandler; }
|
| -
|
| - private:
|
| - virtual HRESULT Parse(IXMLDOMNode* node, response::Response* response) {
|
| - InstallManifest& install_manifest =
|
| - response->apps.back().update_check.install_manifest;
|
| - // TODO(omaha3): Uncomment when version becomes a required value for
|
| - // version 2 configs.
|
| - /*return*/ ReadStringAttribute(node,
|
| - xml::attribute::kVersion,
|
| - &install_manifest.version);
|
| - return S_OK;
|
| - }
|
| -};
|
| -
|
| -
|
| -// Parses 'packages'.
|
| -class PackagesElementHandler : public ElementHandler {
|
| - public:
|
| - static ElementHandler* Create() { return new PackagesElementHandler; }
|
| -};
|
| -
|
| -
|
| -
|
| -// Parses 'package'.
|
| -class PackageElementHandler : public ElementHandler {
|
| - public:
|
| - static ElementHandler* Create() { return new PackageElementHandler; }
|
| -
|
| - private:
|
| - virtual HRESULT Parse(IXMLDOMNode* node, response::Response* response) {
|
| - InstallPackage install_package;
|
| -
|
| - HRESULT hr = ReadStringAttribute(node,
|
| - xml::attribute::kName,
|
| - &install_package.name);
|
| - if (FAILED(hr)) {
|
| - return hr;
|
| - }
|
| -
|
| - install_package.is_required = true;
|
| - hr = ReadBooleanAttribute(node,
|
| - xml::attribute::kRequired,
|
| - &install_package.is_required);
|
| - if (FAILED(hr)) {
|
| - return hr;
|
| - }
|
| -
|
| - hr = ReadIntAttribute(node, xml::attribute::kSize, &install_package.size);
|
| - if (FAILED(hr)) {
|
| - return hr;
|
| - }
|
| -
|
| - hr = ReadStringAttribute(node,
|
| - xml::attribute::kHash,
|
| - &install_package.hash);
|
| - if (FAILED(hr)) {
|
| - return hr;
|
| - }
|
| -
|
| - InstallManifest& install_manifest =
|
| - response->apps.back().update_check.install_manifest;
|
| - install_manifest.packages.push_back(install_package);
|
| -
|
| - return S_OK;
|
| - }
|
| -};
|
| -
|
| -// Parses 'actions'.
|
| -class ActionsElementHandler : public ElementHandler {
|
| - public:
|
| - static ElementHandler* Create() { return new ActionsElementHandler; }
|
| -};
|
| -
|
| -
|
| -// Parses 'action'.
|
| -class ActionElementHandler : public ElementHandler {
|
| - public:
|
| - static ElementHandler* Create() { return new ActionElementHandler; }
|
| -
|
| - private:
|
| - virtual HRESULT Parse(IXMLDOMNode* node, response::Response* response) {
|
| - InstallAction install_action;
|
| -
|
| - CString event;
|
| - HRESULT hr = ReadStringAttribute(node, xml::attribute::kEvent, &event);
|
| - if (FAILED(hr)) {
|
| - return hr;
|
| - }
|
| - hr = ConvertStringToInstallEvent(event, &install_action.install_event);
|
| - if (FAILED(hr)) {
|
| - return hr;
|
| - }
|
| -
|
| - ReadStringAttribute(node,
|
| - xml::attribute::kRun,
|
| - &install_action.program_to_run);
|
| - ReadStringAttribute(node,
|
| - xml::attribute::kArguments,
|
| - &install_action.program_arguments);
|
| -
|
| - ReadStringAttribute(node,
|
| - xml::attribute::kSuccessUrl,
|
| - &install_action.success_url);
|
| -
|
| - ReadBooleanAttribute(node,
|
| - xml::attribute::kTerminateAllBrowsers,
|
| - &install_action.terminate_all_browsers);
|
| -
|
| - CString success_action;
|
| - ReadStringAttribute(node,
|
| - xml::attribute::kSuccessAction,
|
| - &success_action);
|
| - ConvertStringToSuccessfulInstallAction(success_action,
|
| - &install_action.success_action);
|
| -
|
| - InstallManifest& install_manifest =
|
| - response->apps.back().update_check.install_manifest;
|
| - install_manifest.install_actions.push_back(install_action);
|
| -
|
| - return S_OK;
|
| - }
|
| -};
|
| -
|
| -
|
| -// Parses 'data'.
|
| -class DataElementHandler : public ElementHandler {
|
| - public:
|
| - static ElementHandler* Create() { return new DataElementHandler; }
|
| -
|
| - private:
|
| - virtual HRESULT Parse(IXMLDOMNode* node, response::Response* response) {
|
| - response->apps.back().data.push_back(response::Data());
|
| - response::Data& data = response->apps.back().data.back();
|
| -
|
| - HRESULT hr = ReadStringAttribute(node,
|
| - xml::attribute::kStatus,
|
| - &data.status);
|
| - if (FAILED(hr)) {
|
| - return hr;
|
| - }
|
| -
|
| - CString data_name;
|
| - hr = ReadStringAttribute(node, xml::attribute::kName, &data_name);
|
| - if (FAILED(hr)) {
|
| - return hr;
|
| - }
|
| -
|
| - if (xml::value::kInstallData != data_name) {
|
| - return E_UNEXPECTED;
|
| - }
|
| -
|
| - hr = ReadStringAttribute(node,
|
| - xml::attribute::kIndex,
|
| - &data.install_data_index);
|
| - if (FAILED(hr)) {
|
| - return hr;
|
| - }
|
| -
|
| - if (data.status != kResponseStatusOkValue) {
|
| - // There is no data, so do not try to read it.
|
| - return S_OK;
|
| - }
|
| -
|
| - return ReadStringValue(node, &data.install_data);
|
| - }
|
| -};
|
| -
|
| -
|
| -// Parses 'ping'.
|
| -class PingElementHandler : public ElementHandler {
|
| - public:
|
| - static ElementHandler* Create() { return new PingElementHandler; }
|
| -
|
| - private:
|
| - virtual HRESULT Parse(IXMLDOMNode* node, response::Response* response) {
|
| - response::Ping& ping = response->apps.back().ping;
|
| - ReadStringAttribute(node, xml::attribute::kStatus, &ping.status);
|
| - ASSERT1(ping.status == kResponseStatusOkValue);
|
| - return S_OK;
|
| - }
|
| -};
|
| -
|
| -
|
| -// Parses 'event'.
|
| -class EventElementHandler : public ElementHandler {
|
| - public:
|
| - static ElementHandler* Create() { return new EventElementHandler; }
|
| -
|
| - private:
|
| - virtual HRESULT Parse(IXMLDOMNode* node, response::Response* response) {
|
| - response::Event event;
|
| - ReadStringAttribute(node, xml::attribute::kStatus, &event.status);
|
| - ASSERT1(event.status == kResponseStatusOkValue);
|
| - response::App& app = response->apps.back();
|
| - app.events.push_back(event);
|
| - return S_OK;
|
| - }
|
| -};
|
| -
|
| -// Parses 'daystart'.
|
| -class DayStartElementHandler : public ElementHandler {
|
| - public:
|
| - static ElementHandler* Create() { return new DayStartElementHandler; }
|
| -
|
| - private:
|
| - virtual HRESULT Parse(IXMLDOMNode* node, response::Response* response) {
|
| - ReadIntAttribute(node,
|
| - xml::attribute::kElapsedSeconds,
|
| - &response->day_start.elapsed_seconds);
|
| - return S_OK;
|
| - }
|
| -};
|
| -
|
| -namespace v2 {
|
| -
|
| -namespace element {
|
| -
|
| -const TCHAR* const kGUpdate = _T("gupdate");
|
| -
|
| -} // namespace element
|
| -
|
| -namespace attributev2 {
|
| -
|
| -// Some v2 offline manifests were incorrectly authored as 'Version' with a
|
| -// capital 'V'.
|
| -const TCHAR* const kVersionProperCased = _T("Version");
|
| -
|
| -} // namespace attribute
|
| -
|
| -namespace value {
|
| -
|
| -const TCHAR* const kVersion2 = _T("2.0");
|
| -
|
| -} // namespace value
|
| -
|
| -// Parses Omaha v2 'gupdate'.
|
| -class GUpdateElementHandler : public ElementHandler {
|
| - public:
|
| - static ElementHandler* Create() { return new GUpdateElementHandler; }
|
| -
|
| - private:
|
| - virtual HRESULT Parse(IXMLDOMNode* node, response::Response* response) {
|
| - HRESULT hr = ReadStringAttribute(node,
|
| - xml::attribute::kProtocol,
|
| - &response->protocol);
|
| - if (FAILED(hr)) {
|
| - return hr;
|
| - }
|
| - return VerifyProtocolCompatibility(response->protocol,
|
| - value::kVersion2);
|
| - }
|
| -};
|
| -
|
| -// Parses Omaha v2 'updatecheck'.
|
| -class UpdateCheckElementHandler : public ElementHandler {
|
| - public:
|
| - static ElementHandler* Create() { return new UpdateCheckElementHandler; }
|
| -
|
| - private:
|
| - virtual HRESULT Parse(IXMLDOMNode* node, response::Response* response) {
|
| - response::UpdateCheck& update_check = response->apps.back().update_check;
|
| -
|
| - HRESULT hr = ReadStringAttribute(node,
|
| - xml::attribute::kStatus,
|
| - &update_check.status);
|
| - if (FAILED(hr)) {
|
| - return hr;
|
| - }
|
| -
|
| - if (update_check.status.CompareNoCase(kResponseStatusOkValue)) {
|
| - return S_OK;
|
| - }
|
| -
|
| - InstallManifest& install_manifest = update_check.install_manifest;
|
| - if (FAILED(ReadStringAttribute(node,
|
| - xml::attribute::kVersion,
|
| - &install_manifest.version))) {
|
| - ReadStringAttribute(node,
|
| - v2::attributev2::kVersionProperCased,
|
| - &install_manifest.version);
|
| - }
|
| -
|
| - CString url;
|
| - hr = ReadStringAttribute(node, xml::attribute::kCodebase, &url);
|
| - if (FAILED(hr)) {
|
| - return hr;
|
| - }
|
| -
|
| - int start_file_name_idx = url.ReverseFind(_T('/'));
|
| - if (start_file_name_idx <= 0) {
|
| - return GOOPDATEDOWNLOAD_E_INVALID_PATH;
|
| - }
|
| - CString base_url = url.Left(start_file_name_idx + 1);
|
| - update_check.urls.push_back(base_url);
|
| -
|
| - CString package_name = url.Right(url.GetLength() - start_file_name_idx - 1);
|
| - if (package_name.IsEmpty()) {
|
| - return GOOPDATEDOWNLOAD_E_FILE_NAME_EMPTY;
|
| - }
|
| -
|
| - InstallPackage install_package;
|
| - install_package.name = package_name;
|
| - install_package.is_required = true;
|
| - hr = ReadIntAttribute(node, xml::attribute::kSize, &install_package.size);
|
| - if (FAILED(hr)) {
|
| - return hr;
|
| - }
|
| - hr = ReadStringAttribute(node,
|
| - xml::attribute::kHash,
|
| - &install_package.hash);
|
| - if (FAILED(hr)) {
|
| - return hr;
|
| - }
|
| -
|
| - install_manifest.packages.push_back(install_package);
|
| -
|
| - InstallAction install_action;
|
| - install_action.install_event = InstallAction::kInstall;
|
| - install_action.program_to_run = package_name;
|
| - ReadStringAttribute(node,
|
| - xml::attribute::kArguments,
|
| - &install_action.program_arguments);
|
| -
|
| - install_manifest.install_actions.push_back(install_action);
|
| -
|
| - InstallAction post_install_action;
|
| - if (SUCCEEDED(ParsePostInstallActions(node, &post_install_action))) {
|
| - install_manifest.install_actions.push_back(post_install_action);
|
| - }
|
| -
|
| - return S_OK;
|
| - }
|
| -
|
| - HRESULT ParsePostInstallActions(IXMLDOMNode* node,
|
| - InstallAction* post_install_action) {
|
| - InstallAction install_action;
|
| - CString success_action;
|
| - if (FAILED(ReadStringAttribute(node,
|
| - xml::attribute::kSuccessAction,
|
| - &success_action)) &&
|
| - FAILED(ReadStringAttribute(node,
|
| - xml::attribute::kSuccessUrl,
|
| - &install_action.success_url)) &&
|
| - FAILED(ReadBooleanAttribute(node,
|
| - xml::attribute::kTerminateAllBrowsers,
|
| - &install_action.terminate_all_browsers))) {
|
| - return HRESULT_FROM_WIN32(ERROR_NOT_FOUND);
|
| - }
|
| -
|
| - install_action.install_event = InstallAction::kPostInstall;
|
| - ReadStringAttribute(node, xml::attribute::kSuccessAction, &success_action);
|
| - ConvertStringToSuccessfulInstallAction(success_action,
|
| - &install_action.success_action);
|
| - ReadStringAttribute(node,
|
| - xml::attribute::kSuccessUrl,
|
| - &install_action.success_url);
|
| - ReadBooleanAttribute(node,
|
| - xml::attribute::kTerminateAllBrowsers,
|
| - &install_action.terminate_all_browsers);
|
| - *post_install_action = install_action;
|
| - return S_OK;
|
| - }
|
| -};
|
| -
|
| -} // namespace v2
|
| -
|
| -XmlParser::XmlParser() {}
|
| -
|
| -void XmlParser::InitializeElementHandlers() {
|
| - const Tuple<const TCHAR*, ElementHandler* (*)()> tuples[] = {
|
| - {xml::element::kAction, &ActionElementHandler::Create},
|
| - {xml::element::kActions, &ActionsElementHandler::Create},
|
| - {xml::element::kApp, &AppElementHandler::Create},
|
| - {xml::element::kData, &DataElementHandler::Create},
|
| - {xml::element::kDayStart, &DayStartElementHandler::Create},
|
| - {xml::element::kEvent, &EventElementHandler::Create},
|
| - {xml::element::kManifest, &ManifestElementHandler::Create},
|
| - {xml::element::kPackage, &PackageElementHandler::Create},
|
| - {xml::element::kPackages, &PackagesElementHandler::Create},
|
| - {xml::element::kPing, &PingElementHandler::Create},
|
| - {xml::element::kResponse, &ResponseElementHandler::Create},
|
| - {xml::element::kUpdateCheck, &UpdateCheckElementHandler::Create},
|
| - {xml::element::kUrl, &UrlElementHandler::Create},
|
| - {xml::element::kUrls, &UrlsElementHandler::Create},
|
| - };
|
| -
|
| - for (size_t i = 0; i != arraysize(tuples); ++i) {
|
| - VERIFY1(element_handler_factory_.Register(tuples[i].first,
|
| - tuples[i].second));
|
| - }
|
| -}
|
| -
|
| -// The AppElementHandler and the DataElementHandler are shared, because the
|
| -// format is identical between Omaha v2 and Omaha v3. We should make copies of
|
| -// the shared classes if these elements diverge between v2 and v3. The worst
|
| -// case scenario is that we break v2 compatibility if we do not do a
|
| -// copy-on-write, which might be acceptable.
|
| -void XmlParser::InitializeLegacyElementHandlers() {
|
| - const Tuple<const TCHAR*, ElementHandler* (*)()> tuples[] = {
|
| - {xml::element::kApp, &AppElementHandler::Create},
|
| - {xml::element::kData, &DataElementHandler::Create},
|
| - {v2::element::kGUpdate, &v2::GUpdateElementHandler::Create},
|
| - {xml::element::kUpdateCheck, &v2::UpdateCheckElementHandler::Create},
|
| - };
|
| -
|
| - for (size_t i = 0; i != arraysize(tuples); ++i) {
|
| - VERIFY1(element_handler_factory_.Register(tuples[i].first,
|
| - tuples[i].second));
|
| - }
|
| -}
|
| -
|
| -HRESULT XmlParser::SerializeRequest(const UpdateRequest& update_request,
|
| - CString* buffer) {
|
| - ASSERT1(buffer);
|
| -
|
| - XmlParser xml_parser;
|
| -
|
| - HRESULT hr = xml_parser.BuildDom(update_request.request());
|
| - if (FAILED(hr)) {
|
| - return hr;
|
| - }
|
| -
|
| - hr = xml_parser.GetXml(buffer);
|
| - if (FAILED(hr)) {
|
| - return hr;
|
| - }
|
| -
|
| - return S_OK;
|
| -}
|
| -
|
| -HRESULT XmlParser::BuildDom(const request::Request& request) {
|
| - CORE_LOG(L3, (_T("[XmlParser::BuildDom]")));
|
| - HRESULT hr = CoCreateSafeDOMDocument(&document_);
|
| - if (FAILED(hr)) {
|
| - return hr;
|
| - }
|
| -
|
| - request_ = &request;
|
| -
|
| - hr = BuildRequestElement();
|
| - if (FAILED(hr)) {
|
| - return hr;
|
| - }
|
| -
|
| - return S_OK;
|
| -}
|
| -
|
| -// Extract the string out of the DOM, and add the initial processing
|
| -// instruction. The xml property of the document converts to the document from
|
| -// its original encoding to Unicode. As a result, the xml directive and the
|
| -// desired encoding must be explicitely set here.
|
| -HRESULT XmlParser::GetXml(CString* buffer) {
|
| - CORE_LOG(L3, (_T("[XmlParser::GetXml]")));
|
| -
|
| - ASSERT1(buffer);
|
| -
|
| - CComBSTR xml_body;
|
| - HRESULT hr = document_->get_xml(&xml_body);
|
| - if (FAILED(hr)) {
|
| - return hr;
|
| - }
|
| -
|
| - *buffer = kXmlDirective;
|
| - *buffer += xml_body;
|
| -
|
| - // The xml string contains a CR LF pair at the end.
|
| - buffer->TrimRight(_T("\r\n"));
|
| -
|
| - return S_OK;
|
| -}
|
| -
|
| -
|
| -HRESULT XmlParser::BuildRequestElement() {
|
| - CORE_LOG(L3, (_T("[XmlParser::BuildRequestElement]")));
|
| -
|
| - CComPtr<IXMLDOMNode> element;
|
| - HRESULT hr = CreateElementNode(xml::element::kRequest, _T(""), &element);
|
| - if (FAILED(hr)) {
|
| - return hr;
|
| - }
|
| -
|
| - ASSERT1(request_);
|
| -
|
| - // Add attributes to the top element:
|
| - // * protocol - protocol version
|
| - // * version - Omaha version
|
| - // * ismachine - is machine Omaha
|
| - // * installsource - install source
|
| - // * originurl - origin url, primarily set by Update3Web plugins
|
| - // * testsource - test source
|
| - // * requestid - unique request ID
|
| - // * periodoverridesec - override value for update check frequency
|
| -
|
| - hr = AddXMLAttributeNode(element,
|
| - kXmlNamespace,
|
| - xml::attribute::kProtocol,
|
| - request_->protocol_version);
|
| - if (FAILED(hr)) {
|
| - return hr;
|
| - }
|
| -
|
| - hr = AddXMLAttributeNode(element,
|
| - kXmlNamespace,
|
| - xml::attribute::kVersion,
|
| - request_->omaha_version);
|
| - if (FAILED(hr)) {
|
| - return hr;
|
| - }
|
| -
|
| - hr = AddXMLAttributeNode(element,
|
| - kXmlNamespace,
|
| - xml::attribute::kIsMachine,
|
| - request_->is_machine ? _T("1") : _T("0"));
|
| - if (FAILED(hr)) {
|
| - return hr;
|
| - }
|
| -
|
| - hr = AddXMLAttributeNode(element,
|
| - kXmlNamespace,
|
| - xml::attribute::kSessionId,
|
| - request_->session_id);
|
| - if (FAILED(hr)) {
|
| - return hr;
|
| - }
|
| -
|
| - if (!request_->uid.IsEmpty()) {
|
| - hr = AddXMLAttributeNode(element,
|
| - kXmlNamespace,
|
| - xml::attribute::kUserId,
|
| - request_->uid);
|
| - if (FAILED(hr)) {
|
| - return hr;
|
| - }
|
| - }
|
| -
|
| - if (!request_->install_source.IsEmpty()) {
|
| - hr = AddXMLAttributeNode(element,
|
| - kXmlNamespace,
|
| - xml::attribute::kInstallSource,
|
| - request_->install_source);
|
| - if (FAILED(hr)) {
|
| - return hr;
|
| - }
|
| - }
|
| -
|
| - if (!request_->origin_url.IsEmpty()) {
|
| - hr = AddXMLAttributeNode(element,
|
| - kXmlNamespace,
|
| - xml::attribute::kOriginURL,
|
| - request_->origin_url);
|
| - if (FAILED(hr)) {
|
| - return hr;
|
| - }
|
| - }
|
| -
|
| - if (!request_->test_source.IsEmpty()) {
|
| - hr = AddXMLAttributeNode(element,
|
| - kXmlNamespace,
|
| - xml::attribute::kTestSource,
|
| - request_->test_source);
|
| - if (FAILED(hr)) {
|
| - return hr;
|
| - }
|
| - }
|
| -
|
| - if (!request_->request_id.IsEmpty()) {
|
| - hr = AddXMLAttributeNode(element,
|
| - kXmlNamespace,
|
| - xml::attribute::kRequestId,
|
| - request_->request_id);
|
| - if (FAILED(hr)) {
|
| - return hr;
|
| - }
|
| - }
|
| -
|
| - if (request_->check_period_sec != -1) {
|
| - hr = AddXMLAttributeNode(element,
|
| - kXmlNamespace,
|
| - xml::attribute::kPeriodOverrideSec,
|
| - itostr(request_->check_period_sec));
|
| - if (FAILED(hr)) {
|
| - return hr;
|
| - }
|
| - }
|
| -
|
| - hr = BuildOsElement(element);
|
| - if (FAILED(hr)) {
|
| - return hr;
|
| - }
|
| -
|
| - // Add the app element sequence to the request.
|
| - hr = BuildAppElement(element);
|
| - if (FAILED(hr)) {
|
| - return hr;
|
| - }
|
| -
|
| - // Add the request node to the document root.
|
| - CComPtr<IXMLDOMElement> element_node;
|
| - hr = element->QueryInterface(&element_node);
|
| - if (FAILED(hr)) {
|
| - return hr;
|
| - }
|
| -
|
| - hr = document_->putref_documentElement(element_node);
|
| - if (FAILED(hr)) {
|
| - return hr;
|
| - }
|
| -
|
| - return S_OK;
|
| -}
|
| -
|
| -HRESULT XmlParser::BuildOsElement(IXMLDOMNode* parent_node) {
|
| - CORE_LOG(L3, (_T("[XmlParser::BuildOsElement]")));
|
| -
|
| - ASSERT1(parent_node);
|
| - ASSERT1(request_);
|
| -
|
| - CComPtr<IXMLDOMNode> element;
|
| - HRESULT hr = CreateElementNode(xml::element::kOs, _T(""), &element);
|
| - if (FAILED(hr)) {
|
| - return hr;
|
| - }
|
| -
|
| - hr = AddXMLAttributeNode(element,
|
| - kXmlNamespace,
|
| - xml::attribute::kPlatform,
|
| - request_->os.platform);
|
| - if (FAILED(hr)) {
|
| - return hr;
|
| - }
|
| -
|
| - hr = AddXMLAttributeNode(element,
|
| - kXmlNamespace,
|
| - xml::attribute::kVersion,
|
| - request_->os.version);
|
| - if (FAILED(hr)) {
|
| - return hr;
|
| - }
|
| -
|
| - hr = AddXMLAttributeNode(element,
|
| - kXmlNamespace,
|
| - xml::attribute::kServicePack,
|
| - request_->os.service_pack);
|
| - if (FAILED(hr)) {
|
| - return hr;
|
| - }
|
| -
|
| - hr = AddXMLAttributeNode(element,
|
| - kXmlNamespace,
|
| - xml::attribute::kArch,
|
| - request_->os.arch);
|
| - if (FAILED(hr)) {
|
| - return hr;
|
| - }
|
| -
|
| - hr = parent_node->appendChild(element, NULL);
|
| - if (FAILED(hr)) {
|
| - return hr;
|
| - }
|
| -
|
| - return S_OK;
|
| -}
|
| -
|
| -// Create and add request's to the requests node.
|
| -HRESULT XmlParser::BuildAppElement(IXMLDOMNode* parent_node) {
|
| - CORE_LOG(L3, (_T("[XmlParser::BuildAppElement]")));
|
| -
|
| - ASSERT1(parent_node);
|
| - ASSERT1(request_);
|
| -
|
| - for (size_t i = 0; i < request_->apps.size(); ++i) {
|
| - const request::App& app = request_->apps[i];
|
| -
|
| - CComPtr<IXMLDOMNode> element;
|
| - HRESULT hr = CreateElementNode(xml::element::kApp, _T(""), &element);
|
| - if (FAILED(hr)) {
|
| - return hr;
|
| - }
|
| -
|
| - ASSERT1(IsGuid(app.app_id));
|
| - hr = AddXMLAttributeNode(element,
|
| - kXmlNamespace,
|
| - xml::attribute::kAppId,
|
| - app.app_id);
|
| - if (FAILED(hr)) {
|
| - return hr;
|
| - }
|
| -
|
| - hr = AddXMLAttributeNode(element,
|
| - kXmlNamespace,
|
| - xml::attribute::kVersion,
|
| - app.version);
|
| - if (FAILED(hr)) {
|
| - return hr;
|
| - }
|
| -
|
| - hr = AddXMLAttributeNode(element,
|
| - kXmlNamespace,
|
| - xml::attribute::kNextVersion,
|
| - app.next_version);
|
| - if (FAILED(hr)) {
|
| - return hr;
|
| - }
|
| -
|
| - if (!app.ap.IsEmpty()) {
|
| - hr = AddXMLAttributeNode(element,
|
| - kXmlNamespace,
|
| - xml::attribute::kAdditionalParameters,
|
| - app.ap);
|
| - if (FAILED(hr)) {
|
| - return hr;
|
| - }
|
| - }
|
| -
|
| - hr = AddXMLAttributeNode(element,
|
| - kXmlNamespace,
|
| - xml::attribute::kLang,
|
| - app.lang);
|
| - if (FAILED(hr)) {
|
| - return hr;
|
| - }
|
| -
|
| - hr = AddXMLAttributeNode(element,
|
| - kXmlNamespace,
|
| - xml::attribute::kBrandCode,
|
| - app.brand_code);
|
| - if (FAILED(hr)) {
|
| - return hr;
|
| - }
|
| -
|
| - hr = AddXMLAttributeNode(element,
|
| - kXmlNamespace,
|
| - xml::attribute::kClientId,
|
| - app.client_id);
|
| - if (FAILED(hr)) {
|
| - return hr;
|
| - }
|
| -
|
| - // TODO(omaha3): Determine whether or not the server is able to accept an
|
| - // empty string here. If so, remove this IsEmpty() check, and always emit.
|
| - if (!app.experiments.IsEmpty()) {
|
| - hr = AddXMLAttributeNode(element,
|
| - kXmlNamespace,
|
| - xml::attribute::kExperiments,
|
| - app.experiments);
|
| - if (FAILED(hr)) {
|
| - return hr;
|
| - }
|
| - }
|
| -
|
| - // 0 seconds indicates unknown install time. A new install uses -1 days.
|
| - if (app.install_time_diff_sec) {
|
| - const int installed_full_days =
|
| - static_cast<int>(app.install_time_diff_sec) / kSecondsPerDay;
|
| - ASSERT1(installed_full_days >= 0 || installed_full_days == -1);
|
| - hr = AddXMLAttributeNode(element,
|
| - kXmlNamespace,
|
| - xml::attribute::kInstalledAgeDays,
|
| - itostr(installed_full_days));
|
| - if (FAILED(hr)) {
|
| - return hr;
|
| - }
|
| - }
|
| -
|
| - if (!app.iid.IsEmpty() && app.iid != GuidToString(GUID_NULL)) {
|
| - hr = AddXMLAttributeNode(element,
|
| - kXmlNamespace,
|
| - xml::attribute::kInstallationId,
|
| - app.iid);
|
| - if (FAILED(hr)) {
|
| - return hr;
|
| - }
|
| - }
|
| -
|
| - hr = BuildUpdateCheckElement(app, element);
|
| - if (FAILED(hr)) {
|
| - return hr;
|
| - }
|
| -
|
| - hr = BuildPingRequestElement(app, element);
|
| - if (FAILED(hr)) {
|
| - return hr;
|
| - }
|
| -
|
| - hr = BuildDataElement(app, element);
|
| - if (FAILED(hr)) {
|
| - return hr;
|
| - }
|
| -
|
| - hr = BuildDidRunElement(app, element);
|
| - if (FAILED(hr)) {
|
| - return hr;
|
| - }
|
| -
|
| - hr = parent_node->appendChild(element, NULL);
|
| - if (FAILED(hr)) {
|
| - return hr;
|
| - }
|
| - }
|
| -
|
| - return S_OK;
|
| -}
|
| -
|
| -HRESULT XmlParser::BuildUpdateCheckElement(const request::App& app,
|
| - IXMLDOMNode* parent_node) {
|
| - CORE_LOG(L3, (_T("[XmlParser::BuildUpdateCheckElement]")));
|
| - ASSERT1(parent_node);
|
| -
|
| - // Create a DOM element only if the update check member is valid.
|
| - if (!app.update_check.is_valid) {
|
| - return S_OK;
|
| - }
|
| -
|
| - CComPtr<IXMLDOMNode> element;
|
| - HRESULT hr = CreateElementNode(xml::element::kUpdateCheck, _T(""), &element);
|
| - if (FAILED(hr)) {
|
| - return hr;
|
| - }
|
| -
|
| - if (app.update_check.is_update_disabled) {
|
| - hr = AddXMLAttributeNode(element,
|
| - kXmlNamespace,
|
| - xml::attribute::kUpdateDisabled,
|
| - xml::value::kTrue);
|
| - if (FAILED(hr)) {
|
| - return hr;
|
| - }
|
| - }
|
| -
|
| - if (!app.update_check.tt_token.IsEmpty()) {
|
| - hr = AddXMLAttributeNode(element,
|
| - kXmlNamespace,
|
| - xml::attribute::kTTToken,
|
| - app.update_check.tt_token);
|
| - if (FAILED(hr)) {
|
| - return hr;
|
| - }
|
| - }
|
| -
|
| - hr = parent_node->appendChild(element, NULL);
|
| - if (FAILED(hr)) {
|
| - return hr;
|
| - }
|
| -
|
| - return S_OK;
|
| -}
|
| -
|
| -// Ping elements are called "event" elements for legacy reasons.
|
| -HRESULT XmlParser::BuildPingRequestElement(const request::App& app,
|
| - IXMLDOMNode* parent_node) {
|
| - CORE_LOG(L3, (_T("[XmlParser::BuildPingRequestElement]")));
|
| - ASSERT1(parent_node);
|
| -
|
| - // Create a DOM element only if there is are ping_events.
|
| - if (app.ping_events.empty()) {
|
| - return S_OK;
|
| - }
|
| -
|
| - PingEventVector::const_iterator it;
|
| - for (it = app.ping_events.begin(); it != app.ping_events.end(); ++it) {
|
| - const PingEventPtr ping_event = *it;
|
| - CComPtr<IXMLDOMNode> element;
|
| - HRESULT hr = CreateElementNode(xml::element::kEvent, _T(""), &element);
|
| - if (FAILED(hr)) {
|
| - return hr;
|
| - }
|
| -
|
| - hr = ping_event->ToXml(element);
|
| - if (FAILED(hr)) {
|
| - return hr;
|
| - }
|
| -
|
| - hr = parent_node->appendChild(element, NULL);
|
| - if (FAILED(hr)) {
|
| - return hr;
|
| - }
|
| - }
|
| -
|
| - return S_OK;
|
| -}
|
| -
|
| -HRESULT XmlParser::BuildDataElement(const request::App& app,
|
| - IXMLDOMNode* parent_node) {
|
| - CORE_LOG(L3, (_T("[XmlParser::BuildDataElement]")));
|
| - ASSERT1(parent_node);
|
| -
|
| - // Create a DOM element only if there is a data object.
|
| - if (app.data.install_data_index.IsEmpty()) {
|
| - return S_OK;
|
| - }
|
| -
|
| - ASSERT1(app.update_check.is_valid);
|
| -
|
| - CComPtr<IXMLDOMNode> element;
|
| - HRESULT hr = CreateElementNode(xml::element::kData, _T(""), &element);
|
| - if (FAILED(hr)) {
|
| - return hr;
|
| - }
|
| -
|
| - hr = AddXMLAttributeNode(element,
|
| - kXmlNamespace,
|
| - xml::attribute::kName,
|
| - xml::value::kInstallData);
|
| - if (FAILED(hr)) {
|
| - return hr;
|
| - }
|
| -
|
| - hr = AddXMLAttributeNode(element,
|
| - kXmlNamespace,
|
| - xml::attribute::kIndex,
|
| - app.data.install_data_index);
|
| - if (FAILED(hr)) {
|
| - return hr;
|
| - }
|
| -
|
| - hr = parent_node->appendChild(element, NULL);
|
| - if (FAILED(hr)) {
|
| - return hr;
|
| - }
|
| -
|
| - return S_OK;
|
| -}
|
| -
|
| -HRESULT XmlParser::BuildDidRunElement(const request::App& app,
|
| - IXMLDOMNode* parent_node) {
|
| - CORE_LOG(L3, (_T("[XmlParser::BuildDidRunElement]")));
|
| - ASSERT1(parent_node);
|
| -
|
| - bool was_active = app.ping.active == ACTIVE_RUN;
|
| - bool need_active = app.ping.active != ACTIVE_UNKNOWN;
|
| - bool has_sent_a_today = app.ping.days_since_last_active_ping == 0;
|
| - bool need_a = was_active && !has_sent_a_today;
|
| - bool need_r = app.ping.days_since_last_roll_call != 0;
|
| -
|
| - // Create a DOM element only if the didrun object has actual state.
|
| - if (!need_active && !need_a && !need_r) {
|
| - return S_OK;
|
| - }
|
| -
|
| - ASSERT1(app.update_check.is_valid);
|
| -
|
| - CComPtr<IXMLDOMNode> element;
|
| - HRESULT hr = CreateElementNode(xml::element::kPing, _T(""), &element);
|
| - if (FAILED(hr)) {
|
| - return hr;
|
| - }
|
| -
|
| - // TODO(omaha): Remove "active" attribute after transition.
|
| - if (need_active) {
|
| - const TCHAR* active_str(was_active ? _T("1") : _T("0"));
|
| - hr = AddXMLAttributeNode(element,
|
| - kXmlNamespace,
|
| - xml::attribute::kActive,
|
| - active_str);
|
| - if (FAILED(hr)) {
|
| - return hr;
|
| - }
|
| - }
|
| -
|
| - if (need_a) {
|
| - hr = AddXMLAttributeNode(element,
|
| - kXmlNamespace,
|
| - xml::attribute::kDaysSinceLastActivePing,
|
| - itostr(app.ping.days_since_last_active_ping));
|
| - if (FAILED(hr)) {
|
| - return hr;
|
| - }
|
| - }
|
| -
|
| - if (need_r) {
|
| - hr = AddXMLAttributeNode(element,
|
| - kXmlNamespace,
|
| - xml::attribute::kDaysSinceLastRollCall,
|
| - itostr(app.ping.days_since_last_roll_call));
|
| - if (FAILED(hr)) {
|
| - return hr;
|
| - }
|
| - }
|
| -
|
| - hr = parent_node->appendChild(element, NULL);
|
| - if (FAILED(hr)) {
|
| - return hr;
|
| - }
|
| -
|
| - return S_OK;
|
| -}
|
| -
|
| -HRESULT XmlParser::CreateElementNode(const TCHAR* name,
|
| - const TCHAR* value,
|
| - IXMLDOMNode** element) {
|
| - ASSERT1(name);
|
| - ASSERT1(value);
|
| - ASSERT1(element);
|
| -
|
| - // When there is a namespace, the element names get o: prepended to avoid a
|
| - // size explosion where the namespace uri gets automatically added to every
|
| - // element by msxml.
|
| - CString namespace_qualified_name;
|
| - namespace_qualified_name.Format(kXmlNamespace ? _T("o:%s") : _T("%s"),
|
| - name);
|
| - ASSERT1(document_);
|
| - HRESULT hr = CreateXMLNode(document_,
|
| - NODE_ELEMENT,
|
| - namespace_qualified_name,
|
| - kXmlNamespace,
|
| - value,
|
| - element);
|
| - return hr;
|
| -}
|
| -
|
| -
|
| -HRESULT XmlParser::DeserializeResponse(const std::vector<uint8>& buffer,
|
| - UpdateResponse* update_response) {
|
| - ASSERT1(update_response);
|
| -
|
| - XmlParser xml_parser;
|
| - HRESULT hr = LoadXMLFromRawData(buffer, false, &xml_parser.document_);
|
| - if (FAILED(hr)) {
|
| - return hr;
|
| - }
|
| -
|
| - xml_parser.response_ = &update_response->response_;
|
| -
|
| - hr = xml_parser.Parse();
|
| - if (FAILED(hr)) {
|
| - return hr;
|
| - }
|
| -
|
| - return S_OK;
|
| -}
|
| -
|
| -HRESULT XmlParser::Parse() {
|
| - CORE_LOG(L3, (_T("[XmlParser::Parse]")));
|
| - ASSERT1(response_);
|
| -
|
| - CComPtr<IXMLDOMElement> root_node;
|
| - HRESULT hr = document_->get_documentElement(&root_node);
|
| - if (FAILED(hr)) {
|
| - return hr;
|
| - }
|
| - if (!root_node) {
|
| - return GOOPDATEXML_E_PARSE_ERROR;
|
| - }
|
| -
|
| - CComBSTR root_name;
|
| - hr = root_node->get_baseName(&root_name);
|
| - if (FAILED(hr)) {
|
| - return hr;
|
| - }
|
| -
|
| - if (root_name == xml::element::kResponse) {
|
| - InitializeElementHandlers();
|
| - return TraverseDOM(root_node);
|
| - }
|
| -
|
| - if (root_name == v2::element::kGUpdate) {
|
| - InitializeLegacyElementHandlers();
|
| - return TraverseDOM(root_node);
|
| - }
|
| -
|
| - return GOOPDATEXML_E_RESPONSENODE;
|
| -}
|
| -
|
| -HRESULT XmlParser::TraverseDOM(IXMLDOMNode* node) {
|
| - CORE_LOG(L5, (_T("[XmlParser::TraverseDOM]")));
|
| - ASSERT1(node);
|
| -
|
| - HRESULT hr = VisitElement(node);
|
| - if (FAILED(hr)) {
|
| - return hr;
|
| - }
|
| -
|
| - CComPtr<IXMLDOMNodeList> children_list;
|
| - hr = node->get_childNodes(&children_list);
|
| - if (FAILED(hr)) {
|
| - return hr;
|
| - }
|
| -
|
| - long num_children = 0; // NOLINT
|
| - hr = children_list->get_length(&num_children);
|
| - if (FAILED(hr)) {
|
| - return hr;
|
| - }
|
| -
|
| - for (int i = 0; i < num_children; ++i) {
|
| - CComPtr<IXMLDOMNode> child_node;
|
| - hr = children_list->get_item(i, &child_node);
|
| - if (FAILED(hr)) {
|
| - return hr;
|
| - }
|
| -
|
| - DOMNodeType type = NODE_INVALID;
|
| - hr = child_node->get_nodeType(&type);
|
| - if (FAILED(hr)) {
|
| - return hr;
|
| - }
|
| -
|
| - ASSERT1(type == NODE_TEXT || type == NODE_ELEMENT || type == NODE_COMMENT);
|
| -
|
| - if (type == NODE_ELEMENT) {
|
| - hr = TraverseDOM(child_node);
|
| - if (FAILED(hr)) {
|
| - return hr;
|
| - }
|
| - }
|
| - }
|
| -
|
| - return S_OK;
|
| -}
|
| -
|
| -HRESULT XmlParser::VisitElement(IXMLDOMNode* node) {
|
| - XMLFQName node_name;
|
| - HRESULT hr = GetXMLFQName(node, &node_name);
|
| - if (FAILED(hr)) {
|
| - CORE_LOG(LE, (_T("[GetXMLFQName failed][0x%x]"), hr));
|
| - return hr;
|
| - }
|
| -
|
| - CORE_LOG(L4, (_T("[element name][%s:%s]"), node_name.uri, node_name.base));
|
| -
|
| - // Ignore elements not understood.
|
| - ElementHandler* element_handler =
|
| - element_handler_factory_.CreateObject(node_name.base);
|
| - if (element_handler) {
|
| - return element_handler->Handle(node, response_);
|
| - } else {
|
| - CORE_LOG(LW, (_T("[VisitElement: don't know how to handle %s:%s]"),
|
| - node_name.uri, node_name.base));
|
| - }
|
| - return S_OK;
|
| -}
|
| -
|
| -} // namespace xml
|
| -
|
| -} // namespace omaha
|
| -
|
|
|