| 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 #include "chrome/browser/google/google_url_tracker.h" | 5 #include "chrome/browser/google/google_url_tracker.h" |
| 6 | 6 |
| 7 #include "base/bind.h" | 7 #include "base/bind.h" |
| 8 #include "base/command_line.h" | 8 #include "base/command_line.h" |
| 9 #include "base/prefs/pref_service.h" | 9 #include "base/prefs/pref_service.h" |
| 10 #include "base/strings/string_util.h" | 10 #include "base/strings/string_util.h" |
| (...skipping 15 matching lines...) Expand all Loading... |
| 26 #include "net/base/net_util.h" | 26 #include "net/base/net_util.h" |
| 27 #include "net/url_request/url_fetcher.h" | 27 #include "net/url_request/url_fetcher.h" |
| 28 #include "net/url_request/url_request_status.h" | 28 #include "net/url_request/url_request_status.h" |
| 29 | 29 |
| 30 | 30 |
| 31 const char GoogleURLTracker::kDefaultGoogleHomepage[] = | 31 const char GoogleURLTracker::kDefaultGoogleHomepage[] = |
| 32 "http://www.google.com/"; | 32 "http://www.google.com/"; |
| 33 const char GoogleURLTracker::kSearchDomainCheckURL[] = | 33 const char GoogleURLTracker::kSearchDomainCheckURL[] = |
| 34 "https://www.google.com/searchdomaincheck?format=url&type=chrome"; | 34 "https://www.google.com/searchdomaincheck?format=url&type=chrome"; |
| 35 | 35 |
| 36 GoogleURLTracker::GoogleURLTracker(Profile* profile, | 36 GoogleURLTracker::GoogleURLTracker( |
| 37 scoped_ptr<GoogleURLTrackerClient> client, | 37 Profile* profile, |
| 38 Mode mode) | 38 scoped_ptr<GoogleURLTrackerClient> client, |
| 39 scoped_ptr<GoogleURLTrackerNavigationHelper> nav_helper, |
| 40 Mode mode) |
| 39 : profile_(profile), | 41 : profile_(profile), |
| 40 client_(client.Pass()), | 42 client_(client.Pass()), |
| 43 nav_helper_(nav_helper.Pass()), |
| 41 infobar_creator_(base::Bind(&GoogleURLTrackerInfoBarDelegate::Create)), | 44 infobar_creator_(base::Bind(&GoogleURLTrackerInfoBarDelegate::Create)), |
| 42 google_url_(mode == UNIT_TEST_MODE ? | 45 google_url_(mode == UNIT_TEST_MODE ? |
| 43 kDefaultGoogleHomepage : | 46 kDefaultGoogleHomepage : |
| 44 profile->GetPrefs()->GetString(prefs::kLastKnownGoogleURL)), | 47 profile->GetPrefs()->GetString(prefs::kLastKnownGoogleURL)), |
| 45 fetcher_id_(0), | 48 fetcher_id_(0), |
| 46 in_startup_sleep_(true), | 49 in_startup_sleep_(true), |
| 47 already_fetched_(false), | 50 already_fetched_(false), |
| 48 need_to_fetch_(false), | 51 need_to_fetch_(false), |
| 49 need_to_prompt_(false), | 52 need_to_prompt_(false), |
| 50 search_committed_(false), | 53 search_committed_(false), |
| 51 weak_ptr_factory_(this) { | 54 weak_ptr_factory_(this) { |
| 52 net::NetworkChangeNotifier::AddIPAddressObserver(this); | 55 net::NetworkChangeNotifier::AddIPAddressObserver(this); |
| 53 client_->set_google_url_tracker(this); | 56 client_->set_google_url_tracker(this); |
| 57 nav_helper_->SetGoogleURLTracker(this); |
| 54 | 58 |
| 55 // Because this function can be called during startup, when kicking off a URL | 59 // Because this function can be called during startup, when kicking off a URL |
| 56 // fetch can eat up 20 ms of time, we delay five seconds, which is hopefully | 60 // fetch can eat up 20 ms of time, we delay five seconds, which is hopefully |
| 57 // long enough to be after startup, but still get results back quickly. | 61 // long enough to be after startup, but still get results back quickly. |
| 58 // Ideally, instead of this timer, we'd do something like "check if the | 62 // Ideally, instead of this timer, we'd do something like "check if the |
| 59 // browser is starting up, and if so, come back later", but there is currently | 63 // browser is starting up, and if so, come back later", but there is currently |
| 60 // no function to do this. | 64 // no function to do this. |
| 61 // | 65 // |
| 62 // In UNIT_TEST mode, where we want to explicitly control when the tracker | 66 // In UNIT_TEST mode, where we want to explicitly control when the tracker |
| 63 // "wakes up", we do nothing at all. | 67 // "wakes up", we do nothing at all. |
| (...skipping 130 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 194 } | 198 } |
| 195 } | 199 } |
| 196 | 200 |
| 197 void GoogleURLTracker::OnIPAddressChanged() { | 201 void GoogleURLTracker::OnIPAddressChanged() { |
| 198 already_fetched_ = false; | 202 already_fetched_ = false; |
| 199 StartFetchIfDesirable(); | 203 StartFetchIfDesirable(); |
| 200 } | 204 } |
| 201 | 205 |
| 202 void GoogleURLTracker::Shutdown() { | 206 void GoogleURLTracker::Shutdown() { |
| 203 client_.reset(); | 207 client_.reset(); |
| 208 nav_helper_.reset(); |
| 204 fetcher_.reset(); | 209 fetcher_.reset(); |
| 205 weak_ptr_factory_.InvalidateWeakPtrs(); | 210 weak_ptr_factory_.InvalidateWeakPtrs(); |
| 206 net::NetworkChangeNotifier::RemoveIPAddressObserver(this); | 211 net::NetworkChangeNotifier::RemoveIPAddressObserver(this); |
| 207 } | 212 } |
| 208 | 213 |
| 209 void GoogleURLTracker::DeleteMapEntryForService( | 214 void GoogleURLTracker::DeleteMapEntryForService( |
| 210 const InfoBarService* infobar_service) { | 215 const InfoBarService* infobar_service) { |
| 211 // WARNING: |infobar_service| may point to a deleted object. Do not | 216 // WARNING: |infobar_service| may point to a deleted object. Do not |
| 212 // dereference it! See OnTabClosed(). | 217 // dereference it! See OnTabClosed(). |
| 213 EntryMap::iterator i(entry_map_.find(infobar_service)); | 218 EntryMap::iterator i(entry_map_.find(infobar_service)); |
| 214 DCHECK(i != entry_map_.end()); | 219 DCHECK(i != entry_map_.end()); |
| 215 GoogleURLTrackerMapEntry* map_entry = i->second; | 220 GoogleURLTrackerMapEntry* map_entry = i->second; |
| 216 | 221 |
| 217 UnregisterForEntrySpecificNotifications(map_entry, false); | 222 UnregisterForEntrySpecificNotifications(*map_entry, false); |
| 218 entry_map_.erase(i); | 223 entry_map_.erase(i); |
| 219 delete map_entry; | 224 delete map_entry; |
| 220 } | 225 } |
| 221 | 226 |
| 222 void GoogleURLTracker::SetNeedToFetch() { | 227 void GoogleURLTracker::SetNeedToFetch() { |
| 223 need_to_fetch_ = true; | 228 need_to_fetch_ = true; |
| 224 StartFetchIfDesirable(); | 229 StartFetchIfDesirable(); |
| 225 } | 230 } |
| 226 | 231 |
| 227 void GoogleURLTracker::FinishSleep() { | 232 void GoogleURLTracker::FinishSleep() { |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 269 if (need_to_prompt_) { | 274 if (need_to_prompt_) { |
| 270 search_committed_ = true; | 275 search_committed_ = true; |
| 271 // These notifications will fire a bit later in the same call chain we're | 276 // These notifications will fire a bit later in the same call chain we're |
| 272 // currently in. | 277 // currently in. |
| 273 if (!client_->IsListeningForNavigationStart()) | 278 if (!client_->IsListeningForNavigationStart()) |
| 274 client_->SetListeningForNavigationStart(true); | 279 client_->SetListeningForNavigationStart(true); |
| 275 } | 280 } |
| 276 } | 281 } |
| 277 | 282 |
| 278 void GoogleURLTracker::OnNavigationPending( | 283 void GoogleURLTracker::OnNavigationPending( |
| 279 scoped_ptr<GoogleURLTrackerNavigationHelper> nav_helper, | 284 content::NavigationController* navigation_controller, |
| 280 InfoBarService* infobar_service, | 285 InfoBarService* infobar_service, |
| 281 int pending_id) { | 286 int pending_id) { |
| 282 GoogleURLTrackerMapEntry* map_entry = NULL; | |
| 283 | |
| 284 EntryMap::iterator i(entry_map_.find(infobar_service)); | 287 EntryMap::iterator i(entry_map_.find(infobar_service)); |
| 285 if (i != entry_map_.end()) | |
| 286 map_entry = i->second; | |
| 287 | 288 |
| 288 if (search_committed_) { | 289 if (search_committed_) { |
| 289 search_committed_ = false; | 290 search_committed_ = false; |
| 290 if (!map_entry) { | 291 // Whether there's an existing infobar or not, we need to listen for the |
| 292 // load to commit, so we can show and/or update the infobar when it does. |
| 293 // (We may already be registered for this if there is an existing infobar |
| 294 // that had a previous pending search that hasn't yet committed.) |
| 295 if (!nav_helper_->IsListeningForNavigationCommit(navigation_controller)) { |
| 296 nav_helper_->SetListeningForNavigationCommit(navigation_controller, |
| 297 true); |
| 298 } |
| 299 if (i == entry_map_.end()) { |
| 291 // This is a search on a tab that doesn't have one of our infobars, so | 300 // This is a search on a tab that doesn't have one of our infobars, so |
| 292 // prepare to add one. Note that we only listen for the tab's destruction | 301 // prepare to add one. Note that we only listen for the tab's destruction |
| 293 // on this path; if there was already a map entry, then either it doesn't | 302 // on this path; if there was already a map entry, then either it doesn't |
| 294 // yet have an infobar and we're already registered for this, or it has an | 303 // yet have an infobar and we're already registered for this, or it has an |
| 295 // infobar and the infobar's owner will handle tearing it down when the | 304 // infobar and the infobar's owner will handle tearing it down when the |
| 296 // tab is destroyed. | 305 // tab is destroyed. |
| 297 map_entry = new GoogleURLTrackerMapEntry( | 306 nav_helper_->SetListeningForTabDestruction(navigation_controller, true); |
| 298 this, infobar_service, nav_helper.Pass()); | 307 entry_map_.insert(std::make_pair( |
| 299 map_entry->navigation_helper()->SetListeningForTabDestruction(true); | 308 infobar_service, |
| 300 entry_map_.insert(std::make_pair(infobar_service, map_entry)); | 309 new GoogleURLTrackerMapEntry(this, infobar_service, |
| 301 } else if (map_entry->infobar_delegate()) { | 310 navigation_controller))); |
| 311 } else if (i->second->has_infobar_delegate()) { |
| 302 // This is a new search on a tab where we already have an infobar. | 312 // This is a new search on a tab where we already have an infobar. |
| 303 map_entry->infobar_delegate()->set_pending_id(pending_id); | 313 i->second->infobar_delegate()->set_pending_id(pending_id); |
| 304 } | 314 } |
| 305 | 315 } else if (i != entry_map_.end()){ |
| 306 // Whether there's an existing infobar or not, we need to listen for the | 316 if (i->second->has_infobar_delegate()) { |
| 307 // load to commit, so we can show and/or update the infobar when it does. | |
| 308 // (We may already be registered for this if there is an existing infobar | |
| 309 // that had a previous pending search that hasn't yet committed.) | |
| 310 if (!map_entry->navigation_helper()->IsListeningForNavigationCommit()) | |
| 311 map_entry->navigation_helper()->SetListeningForNavigationCommit(true); | |
| 312 } else if (map_entry) { | |
| 313 if (map_entry->has_infobar_delegate()) { | |
| 314 // This is a non-search navigation on a tab with an infobar. If there was | 317 // This is a non-search navigation on a tab with an infobar. If there was |
| 315 // a previous pending search on this tab, this means it won't commit, so | 318 // a previous pending search on this tab, this means it won't commit, so |
| 316 // undo anything we did in response to seeing that. Note that if there | 319 // undo anything we did in response to seeing that. Note that if there |
| 317 // was no pending search on this tab, these statements are effectively a | 320 // was no pending search on this tab, these statements are effectively a |
| 318 // no-op. | 321 // no-op. |
| 319 // | 322 // |
| 320 // If this navigation actually commits, that will trigger the infobar's | 323 // If this navigation actually commits, that will trigger the infobar's |
| 321 // owner to expire the infobar if need be. If it doesn't commit, then | 324 // owner to expire the infobar if need be. If it doesn't commit, then |
| 322 // simply leaving the infobar as-is will have been the right thing. | 325 // simply leaving the infobar as-is will have been the right thing. |
| 323 UnregisterForEntrySpecificNotifications(map_entry, false); | 326 UnregisterForEntrySpecificNotifications(*i->second, false); |
| 324 map_entry->infobar_delegate()->set_pending_id(0); | 327 i->second->infobar_delegate()->set_pending_id(0); |
| 325 } else { | 328 } else { |
| 326 // Non-search navigation on a tab with an entry that has not yet created | 329 // Non-search navigation on a tab with an entry that has not yet created |
| 327 // an infobar. This means the original search won't commit, so delete the | 330 // an infobar. This means the original search won't commit, so delete the |
| 328 // entry. | 331 // entry. |
| 329 map_entry->Close(false); | 332 i->second->Close(false); |
| 330 } | 333 } |
| 331 } else { | 334 } else { |
| 332 // Non-search navigation on a tab without an infobars. This is irrelevant | 335 // Non-search navigation on a tab without an infobars. This is irrelevant |
| 333 // to us. | 336 // to us. |
| 334 } | 337 } |
| 335 } | 338 } |
| 336 | 339 |
| 337 void GoogleURLTracker::OnNavigationCommitted(InfoBarService* infobar_service, | 340 void GoogleURLTracker::OnNavigationCommitted(InfoBarService* infobar_service, |
| 338 const GURL& search_url) { | 341 const GURL& search_url) { |
| 339 EntryMap::iterator i(entry_map_.find(infobar_service)); | 342 EntryMap::iterator i(entry_map_.find(infobar_service)); |
| 340 DCHECK(i != entry_map_.end()); | 343 DCHECK(i != entry_map_.end()); |
| 341 GoogleURLTrackerMapEntry* map_entry = i->second; | 344 GoogleURLTrackerMapEntry* map_entry = i->second; |
| 342 DCHECK(search_url.is_valid()); | 345 DCHECK(search_url.is_valid()); |
| 343 | 346 |
| 344 UnregisterForEntrySpecificNotifications(map_entry, true); | 347 UnregisterForEntrySpecificNotifications(*map_entry, true); |
| 345 if (map_entry->has_infobar_delegate()) { | 348 if (map_entry->has_infobar_delegate()) { |
| 346 map_entry->infobar_delegate()->Update(search_url); | 349 map_entry->infobar_delegate()->Update(search_url); |
| 347 } else { | 350 } else { |
| 348 infobars::InfoBar* infobar = | 351 infobars::InfoBar* infobar = |
| 349 infobar_creator_.Run(infobar_service, this, search_url); | 352 infobar_creator_.Run(infobar_service, this, search_url); |
| 350 if (infobar) { | 353 if (infobar) { |
| 351 map_entry->SetInfoBarDelegate( | 354 map_entry->SetInfoBarDelegate( |
| 352 static_cast<GoogleURLTrackerInfoBarDelegate*>(infobar->delegate())); | 355 static_cast<GoogleURLTrackerInfoBarDelegate*>(infobar->delegate())); |
| 353 } else { | 356 } else { |
| 354 map_entry->Close(false); | 357 map_entry->Close(false); |
| 355 } | 358 } |
| 356 } | 359 } |
| 357 } | 360 } |
| 358 | 361 |
| 359 void GoogleURLTracker::OnTabClosed( | 362 void GoogleURLTracker::OnTabClosed( |
| 360 GoogleURLTrackerNavigationHelper* nav_helper) { | 363 content::NavigationController* navigation_controller) { |
| 361 // Because InfoBarService tears itself down on tab destruction, it's possible | 364 // Because InfoBarService tears itself down on tab destruction, it's possible |
| 362 // to get a non-NULL InfoBarService pointer here, depending on which order | 365 // to get a non-NULL InfoBarService pointer here, depending on which order |
| 363 // notifications fired in. Likewise, the pointer in |entry_map_| (and in its | 366 // notifications fired in. Likewise, the pointer in |entry_map_| (and in its |
| 364 // associated MapEntry) may point to deleted memory. Therefore, if we were to | 367 // associated MapEntry) may point to deleted memory. Therefore, if we were to |
| 365 // access the InfoBarService* we have for this tab, we'd need to ensure we | 368 // access the InfoBarService* we have for this tab, we'd need to ensure we |
| 366 // just looked at the raw pointer value, and never dereferenced it. This | 369 // just looked at the raw pointer value, and never dereferenced it. This |
| 367 // function doesn't need to do even that, but others in the call chain from | 370 // function doesn't need to do even that, but others in the call chain from |
| 368 // here might (and have comments pointing back here). | 371 // here might (and have comments pointing back here). |
| 369 for (EntryMap::iterator i(entry_map_.begin()); i != entry_map_.end(); ++i) { | 372 for (EntryMap::iterator i(entry_map_.begin()); i != entry_map_.end(); ++i) { |
| 370 if (i->second->navigation_helper() == nav_helper) { | 373 if (i->second->navigation_controller() == navigation_controller) { |
| 371 i->second->Close(false); | 374 i->second->Close(false); |
| 372 return; | 375 return; |
| 373 } | 376 } |
| 374 } | 377 } |
| 375 NOTREACHED(); | 378 NOTREACHED(); |
| 376 } | 379 } |
| 377 | 380 |
| 378 scoped_ptr<GoogleURLTracker::Subscription> GoogleURLTracker::RegisterCallback( | 381 scoped_ptr<GoogleURLTracker::Subscription> GoogleURLTracker::RegisterCallback( |
| 379 const OnGoogleURLUpdatedCallback& cb) { | 382 const OnGoogleURLUpdatedCallback& cb) { |
| 380 return callback_list_.Add(cb); | 383 return callback_list_.Add(cb); |
| 381 } | 384 } |
| 382 | 385 |
| 383 void GoogleURLTracker::CloseAllEntries(bool redo_searches) { | 386 void GoogleURLTracker::CloseAllEntries(bool redo_searches) { |
| 384 // Delete all entries, whether they have infobars or not. | 387 // Delete all entries, whether they have infobars or not. |
| 385 while (!entry_map_.empty()) | 388 while (!entry_map_.empty()) |
| 386 entry_map_.begin()->second->Close(redo_searches); | 389 entry_map_.begin()->second->Close(redo_searches); |
| 387 } | 390 } |
| 388 | 391 |
| 389 void GoogleURLTracker::UnregisterForEntrySpecificNotifications( | 392 void GoogleURLTracker::UnregisterForEntrySpecificNotifications( |
| 390 GoogleURLTrackerMapEntry* map_entry, | 393 const GoogleURLTrackerMapEntry& map_entry, |
| 391 bool must_be_listening_for_commit) { | 394 bool must_be_listening_for_commit) { |
| 392 // For tabs with map entries but no infobars, we should always be listening | 395 // For tabs with map entries but no infobars, we should always be listening |
| 393 // for both these notifications. For tabs with infobars, we may be listening | 396 // for both these notifications. For tabs with infobars, we may be listening |
| 394 // for navigation commits if the user has performed a new search on this tab. | 397 // for navigation commits if the user has performed a new search on this tab. |
| 395 if (map_entry->navigation_helper()->IsListeningForNavigationCommit()) { | 398 if (nav_helper_->IsListeningForNavigationCommit( |
| 396 map_entry->navigation_helper()->SetListeningForNavigationCommit(false); | 399 map_entry.navigation_controller())) { |
| 400 nav_helper_->SetListeningForNavigationCommit( |
| 401 map_entry.navigation_controller(), false); |
| 397 } else { | 402 } else { |
| 398 DCHECK(!must_be_listening_for_commit); | 403 DCHECK(!must_be_listening_for_commit); |
| 399 DCHECK(map_entry->has_infobar_delegate()); | 404 DCHECK(map_entry.has_infobar_delegate()); |
| 400 } | 405 } |
| 401 const bool registered_for_tab_destruction = | 406 const bool registered_for_tab_destruction = |
| 402 map_entry->navigation_helper()->IsListeningForTabDestruction(); | 407 nav_helper_->IsListeningForTabDestruction( |
| 403 DCHECK_NE(registered_for_tab_destruction, map_entry->has_infobar_delegate()); | 408 map_entry.navigation_controller()); |
| 409 DCHECK_NE(registered_for_tab_destruction, map_entry.has_infobar_delegate()); |
| 404 if (registered_for_tab_destruction) { | 410 if (registered_for_tab_destruction) { |
| 405 map_entry->navigation_helper()->SetListeningForTabDestruction(false); | 411 nav_helper_->SetListeningForTabDestruction( |
| 412 map_entry.navigation_controller(), false); |
| 406 } | 413 } |
| 407 | 414 |
| 408 // Our global listeners for these other notifications should be in place iff | 415 // Our global listeners for these other notifications should be in place iff |
| 409 // we have any tabs still listening for commits. These tabs either have no | 416 // we have any tabs still listening for commits. These tabs either have no |
| 410 // infobars or have received new pending searches atop existing infobars; in | 417 // infobars or have received new pending searches atop existing infobars; in |
| 411 // either case we want to catch subsequent pending non-search navigations. | 418 // either case we want to catch subsequent pending non-search navigations. |
| 412 // See the various cases inside OnNavigationPending(). | 419 // See the various cases inside OnNavigationPending(). |
| 413 for (EntryMap::const_iterator i(entry_map_.begin()); i != entry_map_.end(); | 420 for (EntryMap::const_iterator i(entry_map_.begin()); i != entry_map_.end(); |
| 414 ++i) { | 421 ++i) { |
| 415 if (i->second->navigation_helper()->IsListeningForNavigationCommit()) { | 422 if (nav_helper_->IsListeningForNavigationCommit( |
| 423 i->second->navigation_controller())) { |
| 416 DCHECK(client_->IsListeningForNavigationStart()); | 424 DCHECK(client_->IsListeningForNavigationStart()); |
| 417 return; | 425 return; |
| 418 } | 426 } |
| 419 } | 427 } |
| 420 if (client_->IsListeningForNavigationStart()) { | 428 if (client_->IsListeningForNavigationStart()) { |
| 421 DCHECK(!search_committed_); | 429 DCHECK(!search_committed_); |
| 422 client_->SetListeningForNavigationStart(false); | 430 client_->SetListeningForNavigationStart(false); |
| 423 } | 431 } |
| 424 } | 432 } |
| 425 | 433 |
| 426 void GoogleURLTracker::NotifyGoogleURLUpdated(GURL old_url, GURL new_url) { | 434 void GoogleURLTracker::NotifyGoogleURLUpdated(GURL old_url, GURL new_url) { |
| 427 callback_list_.Notify(old_url, new_url); | 435 callback_list_.Notify(old_url, new_url); |
| 428 } | 436 } |
| OLD | NEW |