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