Hide new Autofill Popup on Main Widget Resize or Move.
[chromium-blink-merge.git] / rlz / lib / financial_ping.cc
blob9abbd8066a9038bde89c57abe12613d2e4659d28
1 // Copyright (c) 2012 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 // Library functions related to the Financial Server ping.
7 #include "rlz/lib/financial_ping.h"
9 #include "base/basictypes.h"
10 #include "base/memory/scoped_ptr.h"
11 #include "base/string_util.h"
12 #include "base/stringprintf.h"
13 #include "base/utf_string_conversions.h"
14 #include "rlz/lib/assert.h"
15 #include "rlz/lib/lib_values.h"
16 #include "rlz/lib/machine_id.h"
17 #include "rlz/lib/rlz_lib.h"
18 #include "rlz/lib/rlz_value_store.h"
19 #include "rlz/lib/string_utils.h"
21 #if !defined(OS_WIN)
22 #include "base/time.h"
23 #endif
25 #if defined(RLZ_NETWORK_IMPLEMENTATION_WIN_INET)
27 #include <windows.h>
28 #include <wininet.h>
30 namespace {
32 class InternetHandle {
33 public:
34 InternetHandle(HINTERNET handle) { handle_ = handle; }
35 ~InternetHandle() { if (handle_) InternetCloseHandle(handle_); }
36 operator HINTERNET() const { return handle_; }
37 bool operator!() const { return (handle_ == NULL); }
39 private:
40 HINTERNET handle_;
43 } // namespace
45 #else
47 #include "base/bind.h"
48 #include "base/message_loop.h"
49 #include "base/run_loop.h"
50 #include "base/time.h"
51 #include "googleurl/src/gurl.h"
52 #include "net/base/load_flags.h"
53 #include "net/url_request/url_fetcher.h"
54 #include "net/url_request/url_fetcher_delegate.h"
55 #include "net/url_request/url_request_context.h"
56 #include "net/url_request/url_request_context_getter.h"
58 #endif
60 namespace {
62 // Returns the time relative to a fixed point in the past in multiples of
63 // 100 ns stepts. The point in the past is arbitrary but can't change, as the
64 // result of this value is stored on disk.
65 int64 GetSystemTimeAsInt64() {
66 #if defined(OS_WIN)
67 FILETIME now_as_file_time;
68 // Relative to Jan 1, 1601 (UTC).
69 GetSystemTimeAsFileTime(&now_as_file_time);
71 LARGE_INTEGER integer;
72 integer.HighPart = now_as_file_time.dwHighDateTime;
73 integer.LowPart = now_as_file_time.dwLowDateTime;
74 return integer.QuadPart;
75 #else
76 // Seconds since epoch (Jan 1, 1970).
77 double now_seconds = base::Time::Now().ToDoubleT();
78 return static_cast<int64>(now_seconds * 1000 * 1000 * 10);
79 #endif
82 } // namespace
85 namespace rlz_lib {
87 bool FinancialPing::FormRequest(Product product,
88 const AccessPoint* access_points, const char* product_signature,
89 const char* product_brand, const char* product_id,
90 const char* product_lang, bool exclude_machine_id,
91 std::string* request) {
92 if (!request) {
93 ASSERT_STRING("FinancialPing::FormRequest: request is NULL");
94 return false;
97 request->clear();
99 ScopedRlzValueStoreLock lock;
100 RlzValueStore* store = lock.GetStore();
101 if (!store || !store->HasAccess(RlzValueStore::kReadAccess))
102 return false;
104 if (!access_points) {
105 ASSERT_STRING("FinancialPing::FormRequest: access_points is NULL");
106 return false;
109 if (!product_signature) {
110 ASSERT_STRING("FinancialPing::FormRequest: product_signature is NULL");
111 return false;
114 if (!SupplementaryBranding::GetBrand().empty()) {
115 if (SupplementaryBranding::GetBrand() != product_brand) {
116 ASSERT_STRING("FinancialPing::FormRequest: supplementary branding bad");
117 return false;
121 base::StringAppendF(request, "%s?", kFinancialPingPath);
123 // Add the signature, brand, product id and language.
124 base::StringAppendF(request, "%s=%s", kProductSignatureCgiVariable,
125 product_signature);
126 if (product_brand)
127 base::StringAppendF(request, "&%s=%s", kProductBrandCgiVariable,
128 product_brand);
130 if (product_id)
131 base::StringAppendF(request, "&%s=%s", kProductIdCgiVariable, product_id);
133 if (product_lang)
134 base::StringAppendF(request, "&%s=%s", kProductLanguageCgiVariable,
135 product_lang);
137 // Add the product events.
138 char cgi[kMaxCgiLength + 1];
139 cgi[0] = 0;
140 bool has_events = GetProductEventsAsCgi(product, cgi, arraysize(cgi));
141 if (has_events)
142 base::StringAppendF(request, "&%s", cgi);
144 // If we don't have any events, we should ping all the AP's on the system
145 // that we know about and have a current RLZ value, even if they are not
146 // used by this product.
147 AccessPoint all_points[LAST_ACCESS_POINT];
148 if (!has_events) {
149 char rlz[kMaxRlzLength + 1];
150 int idx = 0;
151 for (int ap = NO_ACCESS_POINT + 1; ap < LAST_ACCESS_POINT; ap++) {
152 rlz[0] = 0;
153 AccessPoint point = static_cast<AccessPoint>(ap);
154 if (GetAccessPointRlz(point, rlz, arraysize(rlz)) &&
155 rlz[0] != '\0')
156 all_points[idx++] = point;
158 all_points[idx] = NO_ACCESS_POINT;
161 // Add the RLZ's and the DCC if needed. This is the same as get PingParams.
162 // This will also include the RLZ Exchange Protocol CGI Argument.
163 cgi[0] = 0;
164 if (GetPingParams(product, has_events ? access_points : all_points,
165 cgi, arraysize(cgi)))
166 base::StringAppendF(request, "&%s", cgi);
168 if (has_events && !exclude_machine_id) {
169 std::string machine_id;
170 if (GetMachineId(&machine_id)) {
171 base::StringAppendF(request, "&%s=%s", kMachineIdCgiVariable,
172 machine_id.c_str());
176 return true;
179 #if defined(RLZ_NETWORK_IMPLEMENTATION_CHROME_NET)
180 // The URLRequestContextGetter used by FinancialPing::PingServer().
181 net::URLRequestContextGetter* g_context;
183 bool FinancialPing::SetURLRequestContext(
184 net::URLRequestContextGetter* context) {
185 ScopedRlzValueStoreLock lock;
186 RlzValueStore* store = lock.GetStore();
187 if (!store)
188 return false;
190 g_context = context;
191 return true;
194 namespace {
196 class FinancialPingUrlFetcherDelegate : public net::URLFetcherDelegate {
197 public:
198 FinancialPingUrlFetcherDelegate(const base::Closure& callback)
199 : callback_(callback) {
201 virtual void OnURLFetchComplete(const net::URLFetcher* source);
203 private:
204 base::Closure callback_;
207 void FinancialPingUrlFetcherDelegate::OnURLFetchComplete(
208 const net::URLFetcher* source) {
209 callback_.Run();
212 } // namespace
214 #endif
216 bool FinancialPing::PingServer(const char* request, std::string* response) {
217 if (!response)
218 return false;
220 response->clear();
222 #if defined(RLZ_NETWORK_IMPLEMENTATION_WIN_INET)
223 // Initialize WinInet.
224 InternetHandle inet_handle = InternetOpenA(kFinancialPingUserAgent,
225 INTERNET_OPEN_TYPE_PRECONFIG,
226 NULL, NULL, 0);
227 if (!inet_handle)
228 return false;
230 // Open network connection.
231 InternetHandle connection_handle = InternetConnectA(inet_handle,
232 kFinancialServer, kFinancialPort, "", "", INTERNET_SERVICE_HTTP,
233 INTERNET_FLAG_NO_CACHE_WRITE, 0);
234 if (!connection_handle)
235 return false;
237 // Prepare the HTTP request.
238 InternetHandle http_handle = HttpOpenRequestA(connection_handle,
239 "GET", request, NULL, NULL, kFinancialPingResponseObjects,
240 INTERNET_FLAG_NO_CACHE_WRITE | INTERNET_FLAG_NO_COOKIES, NULL);
241 if (!http_handle)
242 return false;
244 // Timeouts are probably:
245 // INTERNET_OPTION_SEND_TIMEOUT, INTERNET_OPTION_RECEIVE_TIMEOUT
247 // Send the HTTP request. Note: Fails if user is working in off-line mode.
248 if (!HttpSendRequest(http_handle, NULL, 0, NULL, 0))
249 return false;
251 // Check the response status.
252 DWORD status;
253 DWORD status_size = sizeof(status);
254 if (!HttpQueryInfo(http_handle, HTTP_QUERY_STATUS_CODE |
255 HTTP_QUERY_FLAG_NUMBER, &status, &status_size, NULL) ||
256 200 != status)
257 return false;
259 // Get the response text.
260 scoped_array<char> buffer(new char[kMaxPingResponseLength]);
261 if (buffer.get() == NULL)
262 return false;
264 DWORD bytes_read = 0;
265 while (InternetReadFile(http_handle, buffer.get(), kMaxPingResponseLength,
266 &bytes_read) && bytes_read > 0) {
267 response->append(buffer.get(), bytes_read);
268 bytes_read = 0;
271 return true;
272 #else
273 // Run a blocking event loop to match the win inet implementation.
274 scoped_ptr<MessageLoop> message_loop;
275 // Ensure that we have a MessageLoop.
276 if (!MessageLoop::current())
277 message_loop.reset(new MessageLoop);
278 base::RunLoop loop;
279 FinancialPingUrlFetcherDelegate delegate(loop.QuitClosure());
281 std::string url = base::StringPrintf("http://%s:%d%s",
282 kFinancialServer, kFinancialPort,
283 request);
285 scoped_ptr<net::URLFetcher> fetcher(net::URLFetcher::Create(
286 GURL(url), net::URLFetcher::GET, &delegate));
288 fetcher->SetLoadFlags(net::LOAD_DISABLE_CACHE |
289 net::LOAD_DO_NOT_SEND_AUTH_DATA |
290 net::LOAD_DO_NOT_PROMPT_FOR_LOGIN |
291 net::LOAD_DO_NOT_SEND_COOKIES |
292 net::LOAD_DO_NOT_SAVE_COOKIES);
294 // Ensure rlz_lib::SetURLRequestContext() has been called before sending
295 // pings.
296 CHECK(g_context);
297 fetcher->SetRequestContext(g_context);
299 const base::TimeDelta kTimeout = base::TimeDelta::FromMinutes(5);
300 MessageLoop::ScopedNestableTaskAllower allow_nested(MessageLoop::current());
301 MessageLoop::current()->PostTask(
302 FROM_HERE,
303 base::Bind(&net::URLFetcher::Start, base::Unretained(fetcher.get())));
304 MessageLoop::current()->PostDelayedTask(
305 FROM_HERE, loop.QuitClosure(), kTimeout);
307 loop.Run();
309 if (fetcher->GetResponseCode() != 200)
310 return false;
312 return fetcher->GetResponseAsString(response);
313 #endif
316 bool FinancialPing::IsPingTime(Product product, bool no_delay) {
317 ScopedRlzValueStoreLock lock;
318 RlzValueStore* store = lock.GetStore();
319 if (!store || !store->HasAccess(RlzValueStore::kReadAccess))
320 return false;
322 int64 last_ping = 0;
323 if (!store->ReadPingTime(product, &last_ping))
324 return true;
326 uint64 now = GetSystemTimeAsInt64();
327 int64 interval = now - last_ping;
329 // If interval is negative, clock was probably reset. So ping.
330 if (interval < 0)
331 return true;
333 // Check if this product has any unreported events.
334 char cgi[kMaxCgiLength + 1];
335 cgi[0] = 0;
336 bool has_events = GetProductEventsAsCgi(product, cgi, arraysize(cgi));
337 if (no_delay && has_events)
338 return true;
340 return interval >= (has_events ? kEventsPingInterval : kNoEventsPingInterval);
344 bool FinancialPing::UpdateLastPingTime(Product product) {
345 ScopedRlzValueStoreLock lock;
346 RlzValueStore* store = lock.GetStore();
347 if (!store || !store->HasAccess(RlzValueStore::kWriteAccess))
348 return false;
350 uint64 now = GetSystemTimeAsInt64();
351 return store->WritePingTime(product, now);
355 bool FinancialPing::ClearLastPingTime(Product product) {
356 ScopedRlzValueStoreLock lock;
357 RlzValueStore* store = lock.GetStore();
358 if (!store || !store->HasAccess(RlzValueStore::kWriteAccess))
359 return false;
360 return store->ClearPingTime(product);
363 } // namespace