Home | History | Annotate | Download | only in component_updater
      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