Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 // | 4 // |
| 5 // Library functions related to the Financial Server ping. | 5 // Library functions related to the Financial Server ping. |
| 6 | 6 |
| 7 #include "rlz/lib/financial_ping.h" | 7 #include "rlz/lib/financial_ping.h" |
| 8 | 8 |
| 9 #include <stdint.h> | 9 #include <stdint.h> |
| 10 | 10 |
| 11 #include <memory> | 11 #include <memory> |
| 12 | 12 |
| 13 #include "base/atomicops.h" | 13 #include "base/atomicops.h" |
| 14 #include "base/location.h" | 14 #include "base/location.h" |
| 15 #include "base/macros.h" | 15 #include "base/macros.h" |
| 16 #include "base/memory/weak_ptr.h" | 16 #include "base/memory/ref_counted.h" |
| 17 #include "base/single_thread_task_runner.h" | |
| 18 #include "base/strings/string_util.h" | 17 #include "base/strings/string_util.h" |
| 19 #include "base/strings/stringprintf.h" | 18 #include "base/strings/stringprintf.h" |
| 20 #include "base/strings/utf_string_conversions.h" | 19 #include "base/strings/utf_string_conversions.h" |
| 20 #include "base/synchronization/lock.h" | |
| 21 #include "base/synchronization/waitable_event.h" | |
| 22 #include "base/task_scheduler/post_task.h" | |
| 21 #include "base/threading/thread_task_runner_handle.h" | 23 #include "base/threading/thread_task_runner_handle.h" |
| 22 #include "build/build_config.h" | 24 #include "build/build_config.h" |
| 23 #include "rlz/lib/assert.h" | 25 #include "rlz/lib/assert.h" |
| 24 #include "rlz/lib/lib_values.h" | 26 #include "rlz/lib/lib_values.h" |
| 25 #include "rlz/lib/machine_id.h" | 27 #include "rlz/lib/machine_id.h" |
| 26 #include "rlz/lib/rlz_lib.h" | 28 #include "rlz/lib/rlz_lib.h" |
| 27 #include "rlz/lib/rlz_value_store.h" | 29 #include "rlz/lib/rlz_value_store.h" |
| 28 #include "rlz/lib/string_utils.h" | 30 #include "rlz/lib/string_utils.h" |
| 29 | 31 |
| 30 #if !defined(OS_WIN) | 32 #if !defined(OS_WIN) |
| (...skipping 165 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 196 | 198 |
| 197 bool FinancialPing::SetURLRequestContext( | 199 bool FinancialPing::SetURLRequestContext( |
| 198 net::URLRequestContextGetter* context) { | 200 net::URLRequestContextGetter* context) { |
| 199 base::subtle::Release_Store( | 201 base::subtle::Release_Store( |
| 200 &g_context, reinterpret_cast<AtomicWord>(context)); | 202 &g_context, reinterpret_cast<AtomicWord>(context)); |
| 201 return true; | 203 return true; |
| 202 } | 204 } |
| 203 | 205 |
| 204 namespace { | 206 namespace { |
| 205 | 207 |
| 208 // A waitable event used to detect when either: | |
| 209 // | |
| 210 // 1/ the RLZ ping request completes | |
| 211 // 2/ the RLZ ping request times out | |
| 212 // 3/ browser shutdown begins | |
| 213 class RefCountedWaitableEvent | |
| 214 : public base::RefCountedThreadSafe<RefCountedWaitableEvent> { | |
| 215 public: | |
| 216 RefCountedWaitableEvent() | |
| 217 : event_(base::WaitableEvent::ResetPolicy::MANUAL, | |
| 218 base::WaitableEvent::InitialState::NOT_SIGNALED), | |
| 219 response_code_(net::URLFetcher::RESPONSE_CODE_INVALID) {} | |
| 220 | |
| 221 void SignalShutdown() { event_.Signal(); } | |
| 222 | |
| 223 void SignalFetchComplete(int response_code, std::string&& response) { | |
|
gab
2017/07/27 18:29:38
I'm all for r-value params but style guide still b
Roger Tawa OOO till Jul 10th
2017/07/28 18:43:06
Thanks, I had not seen that style guideline.
| |
| 224 base::AutoLock autolock(lock_); | |
| 225 response_code_ = response_code; | |
| 226 response_ = response; | |
| 227 event_.Signal(); | |
| 228 } | |
| 229 | |
| 230 bool TimedWait(const base::TimeDelta& timeout) { | |
|
gab
2017/07/27 18:29:37
Pass TimeDelta by value (see time.h)
Roger Tawa OOO till Jul 10th
2017/07/28 18:43:07
Done.
| |
| 231 return event_.TimedWait(timeout); | |
| 232 } | |
| 233 | |
| 234 int GetResponseCode() { | |
| 235 base::AutoLock autolock(lock_); | |
| 236 return response_code_; | |
| 237 } | |
| 238 | |
| 239 void TakeResponse(std::string* response) { | |
|
gab
2017/07/27 18:29:38
I think
std::string TakeResponse();
is a simple
Roger Tawa OOO till Jul 10th
2017/07/28 18:43:07
Done.
| |
| 240 base::AutoLock autolock(lock_); | |
| 241 *response = std::move(response_); | |
| 242 response_.clear(); | |
|
gab
2017/07/27 18:29:37
The above std::move() would clear() implicitly I a
Roger Tawa OOO till Jul 10th
2017/07/28 18:43:06
Actually, it does not. After an object is moved,
gab
2017/07/28 19:28:57
Hmmm true, but you only TakeResponse() once per Re
Roger Tawa OOO till Jul 10th
2017/07/28 19:42:17
I'd rather not leave the member variable in an uns
| |
| 243 } | |
| 244 | |
| 245 private: | |
| 246 ~RefCountedWaitableEvent() {} | |
| 247 friend class base::RefCountedThreadSafe<RefCountedWaitableEvent>; | |
| 248 | |
| 249 base::WaitableEvent event_; | |
| 250 base::Lock lock_; | |
| 251 std::string response_; | |
| 252 int response_code_; | |
|
gab
2017/07/27 18:29:38
For POD types I prefer C++11 inline member initial
Roger Tawa OOO till Jul 10th
2017/07/28 18:43:07
Done.
| |
| 253 }; | |
| 254 | |
| 255 // A fetcher delegate that signals an instance of RefCountedWaitableEvent when | |
| 256 // the fetch completes. | |
| 206 class FinancialPingUrlFetcherDelegate : public net::URLFetcherDelegate { | 257 class FinancialPingUrlFetcherDelegate : public net::URLFetcherDelegate { |
| 207 public: | 258 public: |
| 208 FinancialPingUrlFetcherDelegate(const base::Closure& callback) | 259 FinancialPingUrlFetcherDelegate(scoped_refptr<RefCountedWaitableEvent> event) |
| 209 : callback_(callback) { | 260 : event_(std::move(event)) {} |
| 261 | |
| 262 void SetFetcher(std::unique_ptr<net::URLFetcher> fetcher) { | |
| 263 fetcher_ = std::move(fetcher); | |
| 210 } | 264 } |
| 211 void OnURLFetchComplete(const net::URLFetcher* source) override; | |
| 212 | 265 |
| 213 private: | 266 private: |
| 214 base::Closure callback_; | 267 void OnURLFetchComplete(const net::URLFetcher* source) override { |
| 268 std::string response; | |
| 269 source->GetResponseAsString(&response); | |
| 270 event_->SignalFetchComplete(source->GetResponseCode(), std::move(response)); | |
| 271 base::SequencedTaskRunnerHandle::Get()->DeleteSoon(FROM_HERE, this); | |
| 272 } | |
| 273 | |
| 274 scoped_refptr<RefCountedWaitableEvent> event_; | |
| 275 std::unique_ptr<net::URLFetcher> fetcher_; | |
| 215 }; | 276 }; |
| 216 | 277 |
| 217 void FinancialPingUrlFetcherDelegate::OnURLFetchComplete( | |
| 218 const net::URLFetcher* source) { | |
| 219 callback_.Run(); | |
| 220 } | |
| 221 | |
| 222 bool send_financial_ping_interrupted_for_test = false; | 278 bool send_financial_ping_interrupted_for_test = false; |
| 223 | 279 |
| 224 } // namespace | 280 } // namespace |
| 225 | 281 |
| 226 void ShutdownCheck(base::WeakPtr<base::RunLoop> weak) { | 282 void ShutdownCheck(scoped_refptr<RefCountedWaitableEvent> event) { |
| 227 if (!weak.get()) | |
| 228 return; | |
| 229 if (!base::subtle::Acquire_Load(&g_context)) { | 283 if (!base::subtle::Acquire_Load(&g_context)) { |
| 230 send_financial_ping_interrupted_for_test = true; | 284 send_financial_ping_interrupted_for_test = true; |
| 231 weak->QuitClosure().Run(); | 285 event->SignalShutdown(); |
| 232 return; | 286 return; |
| 233 } | 287 } |
| 234 // How frequently the financial ping thread should check | 288 // How frequently the financial ping thread should check |
| 235 // the shutdown condition? | 289 // the shutdown condition? |
| 236 const base::TimeDelta kInterval = base::TimeDelta::FromMilliseconds(500); | 290 const base::TimeDelta kInterval = base::TimeDelta::FromMilliseconds(500); |
| 237 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( | 291 base::PostDelayedTask(FROM_HERE, base::Bind(&ShutdownCheck, event), |
| 238 FROM_HERE, base::Bind(&ShutdownCheck, weak), kInterval); | 292 kInterval); |
| 293 } | |
| 294 | |
| 295 void PingRlzServer(std::string url, | |
| 296 scoped_refptr<RefCountedWaitableEvent> event) { | |
| 297 // Copy the pointer to stack because g_context may be set to NULL | |
| 298 // in different thread. The instance is guaranteed to exist while | |
| 299 // the method is running. | |
| 300 net::URLRequestContextGetter* context = | |
| 301 reinterpret_cast<net::URLRequestContextGetter*>( | |
| 302 base::subtle::Acquire_Load(&g_context)); | |
| 303 | |
| 304 // Browser shutdown will cause the context to be reset to NULL. | |
| 305 // ShutdownCheck will catch this. | |
| 306 if (!context) | |
| 307 return; | |
| 308 | |
| 309 // Delegate will delete itself when the fetch completes. | |
| 310 FinancialPingUrlFetcherDelegate* delegate = | |
| 311 new FinancialPingUrlFetcherDelegate(event); | |
| 312 | |
| 313 net::NetworkTrafficAnnotationTag traffic_annotation = | |
| 314 net::DefineNetworkTrafficAnnotation("rlz_ping", R"( | |
| 315 semantics { | |
| 316 sender: "RLZ Ping" | |
| 317 description: | |
| 318 "Used for measuring the effectiveness of a promotion. See the " | |
| 319 "Chrome Privacy Whitepaper for complete details." | |
| 320 trigger: | |
| 321 "1- At Chromium first run.\n" | |
| 322 "2- When Chromium is re-activated by a new promotion.\n" | |
| 323 "3- Once a week thereafter as long as Chromium is used.\n" | |
| 324 data: | |
| 325 "1- Non-unique cohort tag of when Chromium was installed.\n" | |
| 326 "2- Unique machine id on desktop platforms.\n" | |
| 327 "3- Whether Google is the default omnibox search.\n" | |
| 328 "4- Whether google.com is the default home page." | |
| 329 destination: GOOGLE_OWNED_SERVICE | |
| 330 } | |
| 331 policy { | |
| 332 cookies_allowed: NO | |
| 333 setting: "This feature cannot be disabled in settings." | |
| 334 policy_exception_justification: "Not implemented." | |
| 335 })"); | |
| 336 std::unique_ptr<net::URLFetcher> fetcher = net::URLFetcher::Create( | |
| 337 GURL(url), net::URLFetcher::GET, delegate, traffic_annotation); | |
| 338 | |
| 339 fetcher->SetLoadFlags( | |
| 340 net::LOAD_DISABLE_CACHE | net::LOAD_DO_NOT_SEND_AUTH_DATA | | |
| 341 net::LOAD_DO_NOT_SEND_COOKIES | net::LOAD_DO_NOT_SAVE_COOKIES); | |
| 342 | |
| 343 // Ensure rlz_lib::SetURLRequestContext() has been called before sending | |
| 344 // pings. | |
| 345 fetcher->SetRequestContext(context); | |
| 346 fetcher->Start(); | |
| 347 | |
| 348 // Pass ownership of the fetcher to the delegate. Otherwise the fetch will | |
| 349 // be canceled when the URLFetcher object is destroyed. | |
| 350 delegate->SetFetcher(std::move(fetcher)); | |
| 239 } | 351 } |
| 240 #endif | 352 #endif |
| 241 | 353 |
| 242 bool FinancialPing::PingServer(const char* request, std::string* response) { | 354 bool FinancialPing::PingServer(const char* request, std::string* response) { |
| 243 if (!response) | 355 if (!response) |
| 244 return false; | 356 return false; |
| 245 | 357 |
| 246 response->clear(); | 358 response->clear(); |
| 247 | 359 |
| 248 #if defined(RLZ_NETWORK_IMPLEMENTATION_WIN_INET) | 360 #if defined(RLZ_NETWORK_IMPLEMENTATION_WIN_INET) |
|
gab
2017/07/27 18:29:38
Curious, is this still ever a thing or should that
Roger Tawa OOO till Jul 10th
2017/07/28 18:43:06
Possibly, not sure, but not in this CL as you say.
| |
| 249 // Initialize WinInet. | 361 // Initialize WinInet. |
| 250 InternetHandle inet_handle = InternetOpenA(kFinancialPingUserAgent, | 362 InternetHandle inet_handle = InternetOpenA(kFinancialPingUserAgent, |
| 251 INTERNET_OPEN_TYPE_PRECONFIG, | 363 INTERNET_OPEN_TYPE_PRECONFIG, |
| 252 NULL, NULL, 0); | 364 NULL, NULL, 0); |
| 253 if (!inet_handle) | 365 if (!inet_handle) |
| 254 return false; | 366 return false; |
| 255 | 367 |
| 256 // Open network connection. | 368 // Open network connection. |
| 257 InternetHandle connection_handle = InternetConnectA(inet_handle, | 369 InternetHandle connection_handle = InternetConnectA(inet_handle, |
| 258 kFinancialServer, kFinancialPort, "", "", INTERNET_SERVICE_HTTP, | 370 kFinancialServer, kFinancialPort, "", "", INTERNET_SERVICE_HTTP, |
| (...skipping 30 matching lines...) Expand all Loading... | |
| 289 | 401 |
| 290 DWORD bytes_read = 0; | 402 DWORD bytes_read = 0; |
| 291 while (InternetReadFile(http_handle, buffer.get(), kMaxPingResponseLength, | 403 while (InternetReadFile(http_handle, buffer.get(), kMaxPingResponseLength, |
| 292 &bytes_read) && bytes_read > 0) { | 404 &bytes_read) && bytes_read > 0) { |
| 293 response->append(buffer.get(), bytes_read); | 405 response->append(buffer.get(), bytes_read); |
| 294 bytes_read = 0; | 406 bytes_read = 0; |
| 295 }; | 407 }; |
| 296 | 408 |
| 297 return true; | 409 return true; |
| 298 #else | 410 #else |
| 299 // Copy the pointer to stack because g_context may be set to NULL | |
| 300 // in different thread. The instance is guaranteed to exist while | |
| 301 // the method is running. | |
| 302 net::URLRequestContextGetter* context = | |
| 303 reinterpret_cast<net::URLRequestContextGetter*>( | |
| 304 base::subtle::Acquire_Load(&g_context)); | |
| 305 | |
| 306 // Browser shutdown will cause the context to be reset to NULL. | |
| 307 if (!context) | |
| 308 return false; | |
| 309 | |
| 310 // Run a blocking event loop to match the win inet implementation. | |
| 311 std::unique_ptr<base::MessageLoop> message_loop; | |
| 312 // Ensure that we have a MessageLoop. | |
| 313 if (!base::MessageLoop::current()) | |
| 314 message_loop.reset(new base::MessageLoop); | |
| 315 base::RunLoop loop; | |
| 316 FinancialPingUrlFetcherDelegate delegate(loop.QuitClosure()); | |
| 317 | |
| 318 std::string url = base::StringPrintf("http://%s:%d%s", | 411 std::string url = base::StringPrintf("http://%s:%d%s", |
| 319 kFinancialServer, kFinancialPort, | 412 kFinancialServer, kFinancialPort, |
| 320 request); | 413 request); |
| 321 | 414 |
| 322 net::NetworkTrafficAnnotationTag traffic_annotation = | 415 // Use a waitable event to cause this function to block, to match the |
| 323 net::DefineNetworkTrafficAnnotation("rlz_ping", R"( | 416 // wininet implementation. |
| 324 semantics { | 417 auto event = base::MakeRefCounted<RefCountedWaitableEvent>(); |
| 325 sender: "RLZ Ping" | |
| 326 description: | |
| 327 "Used for measuring the effectiveness of a promotion. See the " | |
| 328 "Chrome Privacy Whitepaper for complete details." | |
| 329 trigger: | |
| 330 "1- At Chromium first run.\n" | |
| 331 "2- When Chromium is re-activated by a new promotion.\n" | |
| 332 "3- Once a week thereafter as long as Chromium is used.\n" | |
| 333 data: | |
| 334 "1- Non-unique cohort tag of when Chromium was installed.\n" | |
| 335 "2- Unique machine id on desktop platforms.\n" | |
| 336 "3- Whether Google is the default omnibox search.\n" | |
| 337 "4- Whether google.com is the default home page." | |
| 338 destination: GOOGLE_OWNED_SERVICE | |
| 339 } | |
| 340 policy { | |
| 341 cookies_allowed: NO | |
| 342 setting: "This feature cannot be disabled in settings." | |
| 343 policy_exception_justification: "Not implemented." | |
| 344 })"); | |
| 345 std::unique_ptr<net::URLFetcher> fetcher = net::URLFetcher::Create( | |
| 346 GURL(url), net::URLFetcher::GET, &delegate, traffic_annotation); | |
| 347 | 418 |
| 348 fetcher->SetLoadFlags(net::LOAD_DISABLE_CACHE | | 419 base::PostTask(FROM_HERE, base::Bind(&ShutdownCheck, event)); |
|
gab
2017/07/27 18:29:38
PostTaskWithTraits with TaskPriority::BACKGROUND?
Roger Tawa OOO till Jul 10th
2017/07/28 18:43:07
Done.
| |
| 349 net::LOAD_DO_NOT_SEND_AUTH_DATA | | |
| 350 net::LOAD_DO_NOT_SEND_COOKIES | | |
| 351 net::LOAD_DO_NOT_SAVE_COOKIES); | |
| 352 | 420 |
| 353 // Ensure rlz_lib::SetURLRequestContext() has been called before sending | 421 scoped_refptr<base::SequencedTaskRunner> background_runner( |
|
gab
2017/07/27 18:29:38
Add a comment here (or on PingRlzServer() or both)
Roger Tawa OOO till Jul 10th
2017/07/28 18:43:06
Done.
| |
| 354 // pings. | 422 base::CreateSequencedTaskRunnerWithTraits( |
| 355 fetcher->SetRequestContext(context); | 423 {base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN, |
| 424 base::TaskPriority::BACKGROUND})); | |
| 425 background_runner->PostTask(FROM_HERE, | |
| 426 base::Bind(&PingRlzServer, url, event)); | |
| 356 | 427 |
| 357 base::WeakPtrFactory<base::RunLoop> weak(&loop); | 428 bool is_signaled = event->TimedWait(base::TimeDelta::FromMinutes(5)); |
| 358 | 429 if (!is_signaled || event->GetResponseCode() != 200) |
| 359 const base::TimeDelta kTimeout = base::TimeDelta::FromMinutes(5); | |
| 360 base::MessageLoop::ScopedNestableTaskAllower allow_nested( | |
| 361 base::MessageLoop::current()); | |
| 362 base::ThreadTaskRunnerHandle::Get()->PostTask( | |
| 363 FROM_HERE, base::Bind(&ShutdownCheck, weak.GetWeakPtr())); | |
| 364 base::ThreadTaskRunnerHandle::Get()->PostTask( | |
| 365 FROM_HERE, | |
| 366 base::Bind(&net::URLFetcher::Start, base::Unretained(fetcher.get()))); | |
| 367 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( | |
| 368 FROM_HERE, loop.QuitClosure(), kTimeout); | |
| 369 | |
| 370 loop.Run(); | |
| 371 | |
| 372 if (fetcher->GetResponseCode() != 200) | |
| 373 return false; | 430 return false; |
| 374 | 431 |
| 375 return fetcher->GetResponseAsString(response); | 432 event->TakeResponse(response); |
| 433 return true; | |
| 376 #endif | 434 #endif |
| 377 } | 435 } |
| 378 | 436 |
| 379 bool FinancialPing::IsPingTime(Product product, bool no_delay) { | 437 bool FinancialPing::IsPingTime(Product product, bool no_delay) { |
| 380 ScopedRlzValueStoreLock lock; | 438 ScopedRlzValueStoreLock lock; |
| 381 RlzValueStore* store = lock.GetStore(); | 439 RlzValueStore* store = lock.GetStore(); |
| 382 if (!store || !store->HasAccess(RlzValueStore::kReadAccess)) | 440 if (!store || !store->HasAccess(RlzValueStore::kReadAccess)) |
| 383 return false; | 441 return false; |
| 384 | 442 |
| 385 int64_t last_ping = 0; | 443 int64_t last_ping = 0; |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 431 } | 489 } |
| 432 | 490 |
| 433 bool WasSendFinancialPingInterrupted() { | 491 bool WasSendFinancialPingInterrupted() { |
| 434 return send_financial_ping_interrupted_for_test; | 492 return send_financial_ping_interrupted_for_test; |
| 435 } | 493 } |
| 436 | 494 |
| 437 } // namespace test | 495 } // namespace test |
| 438 #endif | 496 #endif |
| 439 | 497 |
| 440 } // namespace rlz_lib | 498 } // namespace rlz_lib |
| OLD | NEW |