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/component_updater/update_checker.h" 6 7#include <string> 8#include <vector> 9 10#include "base/bind.h" 11#include "base/bind_helpers.h" 12#include "base/compiler_specific.h" 13#include "base/location.h" 14#include "base/logging.h" 15#include "base/macros.h" 16#include "base/memory/scoped_ptr.h" 17#include "base/strings/stringprintf.h" 18#include "base/threading/thread_checker.h" 19#include "components/component_updater/component_updater_configurator.h" 20#include "components/component_updater/component_updater_utils.h" 21#include "components/component_updater/crx_update_item.h" 22#include "components/component_updater/request_sender.h" 23#include "net/url_request/url_fetcher.h" 24#include "url/gurl.h" 25 26namespace component_updater { 27 28namespace { 29 30// Builds an update check request for |components|. |additional_attributes| is 31// serialized as part of the <request> element of the request to customize it 32// with data that is not platform or component specific. For each |item|, a 33// corresponding <app> element is created and inserted as a child node of 34// the <request>. 35// 36// An app element looks like this: 37// <app appid="hnimpnehoodheedghdeeijklkeaacbdc" 38// version="0.1.2.3" installsource="ondemand"> 39// <updatecheck /> 40// <packages> 41// <package fp="abcd" /> 42// </packages> 43// </app> 44std::string BuildUpdateCheckRequest(const Configurator& config, 45 const std::vector<CrxUpdateItem*>& items, 46 const std::string& additional_attributes) { 47 std::string app_elements; 48 for (size_t i = 0; i != items.size(); ++i) { 49 const CrxUpdateItem* item = items[i]; 50 std::string app("<app "); 51 base::StringAppendF(&app, 52 "appid=\"%s\" version=\"%s\"", 53 item->id.c_str(), 54 item->component.version.GetString().c_str()); 55 if (item->on_demand) 56 base::StringAppendF(&app, " installsource=\"ondemand\""); 57 base::StringAppendF(&app, ">"); 58 base::StringAppendF(&app, "<updatecheck />"); 59 if (!item->component.fingerprint.empty()) { 60 base::StringAppendF(&app, 61 "<packages>" 62 "<package fp=\"%s\"/>" 63 "</packages>", 64 item->component.fingerprint.c_str()); 65 } 66 base::StringAppendF(&app, "</app>"); 67 app_elements.append(app); 68 VLOG(1) << "Appending to update request: " << app; 69 } 70 71 return BuildProtocolRequest(config.GetBrowserVersion().GetString(), 72 config.GetChannel(), 73 config.GetLang(), 74 config.GetOSLongName(), 75 app_elements, 76 additional_attributes); 77} 78 79class UpdateCheckerImpl : public UpdateChecker { 80 public: 81 explicit UpdateCheckerImpl(const Configurator& config); 82 virtual ~UpdateCheckerImpl(); 83 84 // Overrides for UpdateChecker. 85 virtual bool CheckForUpdates( 86 const std::vector<CrxUpdateItem*>& items_to_check, 87 const std::string& additional_attributes, 88 const UpdateCheckCallback& update_check_callback) OVERRIDE; 89 90 private: 91 void OnRequestSenderComplete(const net::URLFetcher* source); 92 93 const Configurator& config_; 94 UpdateCheckCallback update_check_callback_; 95 scoped_ptr<RequestSender> request_sender_; 96 97 base::ThreadChecker thread_checker_; 98 99 DISALLOW_COPY_AND_ASSIGN(UpdateCheckerImpl); 100}; 101 102UpdateCheckerImpl::UpdateCheckerImpl(const Configurator& config) 103 : config_(config) { 104} 105 106UpdateCheckerImpl::~UpdateCheckerImpl() { 107 DCHECK(thread_checker_.CalledOnValidThread()); 108} 109 110bool UpdateCheckerImpl::CheckForUpdates( 111 const std::vector<CrxUpdateItem*>& items_to_check, 112 const std::string& additional_attributes, 113 const UpdateCheckCallback& update_check_callback) { 114 DCHECK(thread_checker_.CalledOnValidThread()); 115 116 if (request_sender_.get()) { 117 NOTREACHED(); 118 return false; // Another update check is in progress. 119 } 120 121 update_check_callback_ = update_check_callback; 122 123 request_sender_.reset(new RequestSender(config_)); 124 request_sender_->Send( 125 BuildUpdateCheckRequest(config_, items_to_check, additional_attributes), 126 config_.UpdateUrl(), 127 base::Bind(&UpdateCheckerImpl::OnRequestSenderComplete, 128 base::Unretained(this))); 129 return true; 130} 131 132void UpdateCheckerImpl::OnRequestSenderComplete(const net::URLFetcher* source) { 133 DCHECK(thread_checker_.CalledOnValidThread()); 134 135 const GURL original_url(source->GetOriginalURL()); 136 VLOG(1) << "Update check request went to: " << original_url.spec(); 137 138 int error = 0; 139 std::string error_message; 140 UpdateResponse update_response; 141 142 if (FetchSuccess(*source)) { 143 std::string xml; 144 source->GetResponseAsString(&xml); 145 if (!update_response.Parse(xml)) { 146 error = -1; 147 error_message = update_response.errors(); 148 VLOG(1) << "Update request failed: " << error_message; 149 } 150 } else { 151 error = GetFetchError(*source); 152 error_message.assign("network error"); 153 VLOG(1) << "Update request failed: network error"; 154 } 155 156 request_sender_.reset(); 157 update_check_callback_.Run( 158 original_url, error, error_message, update_response.results()); 159} 160 161} // namespace 162 163scoped_ptr<UpdateChecker> UpdateChecker::Create(const Configurator& config) { 164 return scoped_ptr<UpdateChecker>(new UpdateCheckerImpl(config)); 165} 166 167} // namespace component_updater 168