1 // Copyright 2013 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 "chrome/browser/component_updater/component_updater_ping_manager.h"
7 #include "base/compiler_specific.h"
9 #include "base/logging.h"
10 #include "base/memory/scoped_ptr.h"
11 #include "base/strings/string_number_conversions.h"
12 #include "base/strings/string_util.h"
13 #include "base/strings/stringprintf.h"
14 #include "chrome/browser/component_updater/component_updater_utils.h"
15 #include "chrome/browser/component_updater/crx_update_item.h"
16 #include "net/url_request/url_fetcher.h"
17 #include "net/url_request/url_fetcher_delegate.h"
19 namespace component_updater
{
21 // Returns a string literal corresponding to the value of the downloader |d|.
22 const char* DownloaderToString(CrxDownloader::DownloadMetrics::Downloader d
) {
24 case CrxDownloader::DownloadMetrics::kUrlFetcher
:
26 case CrxDownloader::DownloadMetrics::kBits
:
33 // Sends a fire and forget ping. The instances of this class have no
34 // ownership and they self-delete upon completion.
35 class PingSender
: public net::URLFetcherDelegate
{
39 void SendPing(const GURL
& ping_url
,
40 net::URLRequestContextGetter
* url_request_context_getter
,
41 const CrxUpdateItem
* item
);
43 virtual ~PingSender();
45 // Overrides for URLFetcherDelegate.
46 virtual void OnURLFetchComplete(const net::URLFetcher
* source
) OVERRIDE
;
48 static std::string
BuildPing(const CrxUpdateItem
* item
);
49 static std::string
BuildDownloadCompleteEventElements(
50 const CrxUpdateItem
* item
);
51 static std::string
BuildUpdateCompleteEventElement(const CrxUpdateItem
* item
);
53 scoped_ptr
<net::URLFetcher
> url_fetcher_
;
55 DISALLOW_COPY_AND_ASSIGN(PingSender
);
58 PingSender::PingSender() {}
60 PingSender::~PingSender() {}
62 void PingSender::OnURLFetchComplete(const net::URLFetcher
* source
) {
66 void PingSender::SendPing(
68 net::URLRequestContextGetter
* url_request_context_getter
,
69 const CrxUpdateItem
* item
) {
72 if (!ping_url
.is_valid())
75 url_fetcher_
.reset(SendProtocolRequest(ping_url
,
78 url_request_context_getter
));
81 // Builds a ping message for the specified update item.
82 std::string
PingSender::BuildPing(const CrxUpdateItem
* item
) {
83 const char app_element_format
[] =
84 "<app appid=\"%s\" version=\"%s\" nextversion=\"%s\">"
88 const std::string
app_element(base::StringPrintf(
90 item
->id
.c_str(), // "appid"
91 item
->previous_version
.GetString().c_str(), // "version"
92 item
->next_version
.GetString().c_str(), // "nextversion"
93 BuildUpdateCompleteEventElement(item
).c_str(), // update event
94 BuildDownloadCompleteEventElements(item
).c_str())); // download events
96 return BuildProtocolRequest(app_element
, "");
99 // Returns a string representing a sequence of download complete events
100 // corresponding to each download metrics in |item|.
101 std::string
PingSender::BuildDownloadCompleteEventElements(
102 const CrxUpdateItem
* item
) {
103 using base::StringAppendF
;
104 std::string download_events
;
105 for (size_t i
= 0; i
!= item
->download_metrics
.size(); ++i
) {
106 const CrxDownloader::DownloadMetrics
& metrics
= item
->download_metrics
[i
];
107 std::string
event("<event eventtype=\"14\"");
108 StringAppendF(&event
, " eventresult=\"%d\"", metrics
.error
== 0);
109 StringAppendF(&event
,
110 " downloader=\"%s\"", DownloaderToString(metrics
.downloader
));
112 StringAppendF(&event
, " errorcode=\"%d\"", metrics
.error
);
113 StringAppendF(&event
, " url=\"%s\"", metrics
.url
.spec().c_str());
115 // -1 means that the byte counts are not known.
116 if (metrics
.bytes_downloaded
!= -1) {
117 StringAppendF(&event
, " downloaded=\"%s\"",
118 base::Int64ToString(metrics
.bytes_downloaded
).c_str());
120 if (metrics
.bytes_total
!= -1) {
121 StringAppendF(&event
, " total=\"%s\"",
122 base::Int64ToString(metrics
.bytes_total
).c_str());
125 if (metrics
.download_time_ms
) {
126 StringAppendF(&event
, " download_time_ms=\"%s\"",
127 base::Uint64ToString(metrics
.download_time_ms
).c_str());
129 StringAppendF(&event
, "/>");
131 download_events
+= event
;
133 return download_events
;
136 // Returns a string representing one ping event xml element for an update item.
137 std::string
PingSender::BuildUpdateCompleteEventElement(
138 const CrxUpdateItem
* item
) {
139 DCHECK(item
->status
== CrxUpdateItem::kNoUpdate
||
140 item
->status
== CrxUpdateItem::kUpdated
);
142 using base::StringAppendF
;
144 std::string
ping_event("<event eventtype=\"3\"");
145 const int event_result
= item
->status
== CrxUpdateItem::kUpdated
;
146 StringAppendF(&ping_event
, " eventresult=\"%d\"", event_result
);
147 if (item
->error_category
)
148 StringAppendF(&ping_event
, " errorcat=\"%d\"", item
->error_category
);
149 if (item
->error_code
)
150 StringAppendF(&ping_event
, " errorcode=\"%d\"", item
->error_code
);
151 if (item
->extra_code1
)
152 StringAppendF(&ping_event
, " extracode1=\"%d\"", item
->extra_code1
);
153 if (HasDiffUpdate(item
))
154 StringAppendF(&ping_event
, " diffresult=\"%d\"", !item
->diff_update_failed
);
155 if (item
->diff_error_category
)
156 StringAppendF(&ping_event
,
157 " differrorcat=\"%d\"",
158 item
->diff_error_category
);
159 if (item
->diff_error_code
)
160 StringAppendF(&ping_event
, " differrorcode=\"%d\"", item
->diff_error_code
);
161 if (item
->diff_extra_code1
) {
162 StringAppendF(&ping_event
,
163 " diffextracode1=\"%d\"",
164 item
->diff_extra_code1
);
166 if (!item
->previous_fp
.empty())
167 StringAppendF(&ping_event
, " previousfp=\"%s\"", item
->previous_fp
.c_str());
168 if (!item
->next_fp
.empty())
169 StringAppendF(&ping_event
, " nextfp=\"%s\"", item
->next_fp
.c_str());
170 StringAppendF(&ping_event
, "/>");
174 PingManager::PingManager(
175 const GURL
& ping_url
,
176 net::URLRequestContextGetter
* url_request_context_getter
)
177 : ping_url_(ping_url
),
178 url_request_context_getter_(url_request_context_getter
) {
181 PingManager::~PingManager() {
184 // Sends a fire and forget ping when the updates are complete. The ping
185 // sender object self-deletes after sending the ping.
186 void PingManager::OnUpdateComplete(const CrxUpdateItem
* item
) {
187 PingSender
* ping_sender(new PingSender
);
188 ping_sender
->SendPing(ping_url_
, url_request_context_getter_
, item
);
191 } // namespace component_updater