15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file. 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/intranet_redirect_detector.h" 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind.h" 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/command_line.h" 92a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/prefs/pref_registry_simple.h" 102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/prefs/pref_service.h" 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/rand_util.h" 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/stl_util.h" 13868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/utf_string_conversions.h" 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/browser_process.h" 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/chrome_switches.h" 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/pref_names.h" 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/base/load_flags.h" 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/base/net_errors.h" 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/base/registry_controlled_domains/registry_controlled_domain.h" 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/url_request/url_fetcher.h" 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/url_request/url_request_context_getter.h" 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/url_request/url_request_status.h" 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)IntranetRedirectDetector::IntranetRedirectDetector() 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) : redirect_origin_(g_browser_process->local_state()->GetString( 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) prefs::kLastKnownIntranetRedirectOrigin)), 275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) in_sleep_(true), 285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) weak_ptr_factory_(this) { 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Because this function can be called during startup, when kicking off a URL 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // fetch can eat up 20 ms of time, we delay seven seconds, which is hopefully 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // long enough to be after startup, but still get results back quickly. 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Ideally, instead of this timer, we'd do something like "check if the 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // browser is starting up, and if so, come back later", but there is currently 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // no function to do this. 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static const int kStartFetchDelaySeconds = 7; 3690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) base::MessageLoop::current()->PostDelayedTask(FROM_HERE, 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::Bind(&IntranetRedirectDetector::FinishSleep, 385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) weak_ptr_factory_.GetWeakPtr()), 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::TimeDelta::FromSeconds(kStartFetchDelaySeconds)); 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) net::NetworkChangeNotifier::AddIPAddressObserver(this); 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)IntranetRedirectDetector::~IntranetRedirectDetector() { 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) net::NetworkChangeNotifier::RemoveIPAddressObserver(this); 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) STLDeleteElements(&fetchers_); 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)GURL IntranetRedirectDetector::RedirectOrigin() { 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const IntranetRedirectDetector* const detector = 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) g_browser_process->intranet_redirect_detector(); 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return detector ? detector->redirect_origin_ : GURL(); 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static 572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void IntranetRedirectDetector::RegisterPrefs(PrefRegistrySimple* registry) { 582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) registry->RegisterStringPref(prefs::kLastKnownIntranetRedirectOrigin, 592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) std::string()); 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void IntranetRedirectDetector::FinishSleep() { 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) in_sleep_ = false; 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If another fetch operation is still running, cancel it. 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) STLDeleteElements(&fetchers_); 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) resulting_origins_.clear(); 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const CommandLine* cmd_line = CommandLine::ForCurrentProcess(); 705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (cmd_line->HasSwitch(switches::kDisableBackgroundNetworking)) 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(fetchers_.empty() && resulting_origins_.empty()); 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Start three fetchers on random hostnames. 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (size_t i = 0; i < 3; ++i) { 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string url_string("http://"); 785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // We generate a random hostname with between 7 and 15 characters. 795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) const int num_chars = base::RandInt(7, 15); 805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) for (int j = 0; j < num_chars; ++j) 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) url_string += ('a' + base::RandInt(0, 'z' - 'a')); 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GURL random_url(url_string + '/'); 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) net::URLFetcher* fetcher = net::URLFetcher::Create( 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) random_url, net::URLFetcher::HEAD, this); 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We don't want these fetches to affect existing state in the profile. 865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fetcher->SetLoadFlags(net::LOAD_DISABLE_CACHE | 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) net::LOAD_DO_NOT_SAVE_COOKIES | 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) net::LOAD_DO_NOT_SEND_COOKIES); 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fetcher->SetRequestContext(g_browser_process->system_request_context()); 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fetcher->Start(); 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fetchers_.insert(fetcher); 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void IntranetRedirectDetector::OnURLFetchComplete( 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const net::URLFetcher* source) { 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Delete the fetcher on this function's exit. 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Fetchers::iterator fetcher = fetchers_.find( 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const_cast<net::URLFetcher*>(source)); 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(fetcher != fetchers_.end()); 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scoped_ptr<net::URLFetcher> clean_up_fetcher(*fetcher); 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fetchers_.erase(fetcher); 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If any two fetches result in the same domain/host, we set the redirect 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // origin to that; otherwise we set it to nothing. 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!source->GetStatus().is_success() || (source->GetResponseCode() != 200)) { 1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if ((resulting_origins_.empty()) || 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ((resulting_origins_.size() == 1) && 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) resulting_origins_.front().is_valid())) { 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) resulting_origins_.push_back(GURL()); 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) redirect_origin_ = GURL(); 1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(source->GetURL().is_valid()); 1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GURL origin(source->GetURL().GetOrigin()); 1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (resulting_origins_.empty()) { 1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) resulting_origins_.push_back(origin); 1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 121a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) if (net::registry_controlled_domains::SameDomainOrHost( 122a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) resulting_origins_.front(), 123a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) origin, 124a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) net::registry_controlled_domains::EXCLUDE_PRIVATE_REGISTRIES)) { 1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) redirect_origin_ = origin; 1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!fetchers_.empty()) { 1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Cancel remaining fetch, we don't need it. 1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(fetchers_.size() == 1); 1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) delete (*fetchers_.begin()); 1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fetchers_.clear(); 1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (resulting_origins_.size() == 1) { 1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) resulting_origins_.push_back(origin); 1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(resulting_origins_.size() == 2); 138a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) const bool same_domain_or_host = 139a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) net::registry_controlled_domains::SameDomainOrHost( 140a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) resulting_origins_.back(), 141a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) origin, 142a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) net::registry_controlled_domains::EXCLUDE_PRIVATE_REGISTRIES); 143a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) redirect_origin_ = same_domain_or_host ? origin : GURL(); 1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) g_browser_process->local_state()->SetString( 1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) prefs::kLastKnownIntranetRedirectOrigin, redirect_origin_.is_valid() ? 1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) redirect_origin_.spec() : std::string()); 1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void IntranetRedirectDetector::OnIPAddressChanged() { 1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If a request is already scheduled, do not scheduled yet another one. 1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (in_sleep_) 1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Since presumably many programs open connections after network changes, 1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // delay this a little bit. 1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) in_sleep_ = true; 1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static const int kNetworkSwitchDelayMS = 1000; 16090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) base::MessageLoop::current()->PostDelayedTask(FROM_HERE, 1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::Bind(&IntranetRedirectDetector::FinishSleep, 1625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) weak_ptr_factory_.GetWeakPtr()), 1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::TimeDelta::FromMilliseconds(kNetworkSwitchDelayMS)); 1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 165