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.
5 #include "components/update_client/update_checker.h"
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/thread_task_runner_handle.h"
19 #include "base/threading/thread_checker.h"
20 #include "components/update_client/configurator.h"
21 #include "components/update_client/crx_update_item.h"
22 #include "components/update_client/request_sender.h"
23 #include "components/update_client/utils.h"
24 #include "net/url_request/url_fetcher.h"
27 namespace update_client
{
31 // Builds an update check request for |components|. |additional_attributes| is
32 // serialized as part of the <request> element of the request to customize it
33 // with data that is not platform or component specific. For each |item|, a
34 // corresponding <app> element is created and inserted as a child node of
37 // An app element looks like this:
38 // <app appid="hnimpnehoodheedghdeeijklkeaacbdc"
39 // version="0.1.2.3" installsource="ondemand">
42 // <package fp="abcd" />
45 std::string
BuildUpdateCheckRequest(const Configurator
& config
,
46 const std::vector
<CrxUpdateItem
*>& items
,
47 const std::string
& additional_attributes
) {
48 std::string app_elements
;
49 for (size_t i
= 0; i
!= items
.size(); ++i
) {
50 const CrxUpdateItem
* item
= items
[i
];
51 std::string
app("<app ");
52 base::StringAppendF(&app
, "appid=\"%s\" version=\"%s\"", item
->id
.c_str(),
53 item
->component
.version
.GetString().c_str());
55 base::StringAppendF(&app
, " installsource=\"ondemand\"");
56 base::StringAppendF(&app
, ">");
57 base::StringAppendF(&app
, "<updatecheck />");
58 if (!item
->component
.fingerprint
.empty()) {
59 base::StringAppendF(&app
,
61 "<package fp=\"%s\"/>"
63 item
->component
.fingerprint
.c_str());
65 base::StringAppendF(&app
, "</app>");
66 app_elements
.append(app
);
67 VLOG(1) << "Appending to update request: " << app
;
70 return BuildProtocolRequest(config
.GetBrowserVersion().GetString(),
71 config
.GetChannel(), config
.GetLang(),
72 config
.GetOSLongName(), app_elements
,
73 additional_attributes
);
76 class UpdateCheckerImpl
: public UpdateChecker
{
78 explicit UpdateCheckerImpl(const Configurator
& config
);
79 ~UpdateCheckerImpl() override
;
81 // Overrides for UpdateChecker.
83 const std::vector
<CrxUpdateItem
*>& items_to_check
,
84 const std::string
& additional_attributes
,
85 const UpdateCheckCallback
& update_check_callback
) override
;
88 void OnRequestSenderComplete(const net::URLFetcher
* source
);
90 const Configurator
& config_
;
91 UpdateCheckCallback update_check_callback_
;
92 scoped_ptr
<RequestSender
> request_sender_
;
94 base::ThreadChecker thread_checker_
;
96 DISALLOW_COPY_AND_ASSIGN(UpdateCheckerImpl
);
99 UpdateCheckerImpl::UpdateCheckerImpl(const Configurator
& config
)
103 UpdateCheckerImpl::~UpdateCheckerImpl() {
104 DCHECK(thread_checker_
.CalledOnValidThread());
107 bool UpdateCheckerImpl::CheckForUpdates(
108 const std::vector
<CrxUpdateItem
*>& items_to_check
,
109 const std::string
& additional_attributes
,
110 const UpdateCheckCallback
& update_check_callback
) {
111 DCHECK(thread_checker_
.CalledOnValidThread());
113 if (request_sender_
.get()) {
115 return false; // Another update check is in progress.
118 update_check_callback_
= update_check_callback
;
120 request_sender_
.reset(new RequestSender(config_
));
121 request_sender_
->Send(
122 BuildUpdateCheckRequest(config_
, items_to_check
, additional_attributes
),
124 base::Bind(&UpdateCheckerImpl::OnRequestSenderComplete
,
125 base::Unretained(this)));
129 void UpdateCheckerImpl::OnRequestSenderComplete(const net::URLFetcher
* source
) {
130 DCHECK(thread_checker_
.CalledOnValidThread());
134 std::string error_message
;
135 UpdateResponse update_response
;
138 original_url
= source
->GetOriginalURL();
139 VLOG(1) << "Update check request went to: " << original_url
.spec();
140 if (FetchSuccess(*source
)) {
142 source
->GetResponseAsString(&xml
);
143 if (!update_response
.Parse(xml
)) {
145 error_message
= update_response
.errors();
148 error
= GetFetchError(*source
);
149 error_message
.assign("network error");
153 error_message
= "no fetcher";
157 VLOG(1) << "Update request failed: " << error_message
;
160 request_sender_
.reset();
162 base::ThreadTaskRunnerHandle::Get()->PostTask(
163 FROM_HERE
, base::Bind(update_check_callback_
, original_url
, error
,
164 error_message
, update_response
.results()));
169 scoped_ptr
<UpdateChecker
> UpdateChecker::Create(const Configurator
& config
) {
170 return scoped_ptr
<UpdateChecker
>(new UpdateCheckerImpl(config
));
173 } // namespace update_client