14e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
24e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
34e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// found in the LICENSE file.
44e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
54e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "chrome/browser/ui/omnibox/omnibox_navigation_observer.h"
64e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)#include "chrome/browser/autocomplete/shortcuts_backend.h"
823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)#include "chrome/browser/autocomplete/shortcuts_backend_factory.h"
94e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "chrome/browser/infobars/infobar_service.h"
104e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "chrome/browser/intranet_redirect_detector.h"
114e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "chrome/browser/ui/omnibox/alternate_nav_infobar_delegate.h"
124e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "content/public/browser/browser_context.h"
134e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "content/public/browser/navigation_controller.h"
144e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "content/public/browser/navigation_details.h"
154e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "content/public/browser/navigation_entry.h"
164e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "content/public/browser/notification_service.h"
174e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "content/public/browser/notification_types.h"
184e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "content/public/browser/web_contents.h"
194e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "net/base/load_flags.h"
204e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "net/base/registry_controlled_domains/registry_controlled_domain.h"
214e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "net/url_request/url_fetcher.h"
224e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "net/url_request/url_request.h"
234e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
244e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
254e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// Helpers --------------------------------------------------------------------
264e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
274e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)namespace {
284e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
294e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// HTTP 2xx, 401, and 407 all indicate that the target address exists.
304e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)bool ResponseCodeIndicatesSuccess(int response_code) {
314e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  return ((response_code / 100) == 2) || (response_code == 401) ||
324e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      (response_code == 407);
334e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
344e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
354e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// Returns true if |final_url| doesn't represent an ISP hijack of
364e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// |original_url|, based on the IntranetRedirectDetector's RedirectOrigin().
374e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)bool IsValidNavigation(const GURL& original_url, const GURL& final_url) {
384e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  const GURL& redirect_url(IntranetRedirectDetector::RedirectOrigin());
394e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  return !redirect_url.is_valid() ||
404e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      net::registry_controlled_domains::SameDomainOrHost(
414e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)          original_url, final_url,
424e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)          net::registry_controlled_domains::EXCLUDE_PRIVATE_REGISTRIES) ||
434e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      !net::registry_controlled_domains::SameDomainOrHost(
444e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)          final_url, redirect_url,
454e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)          net::registry_controlled_domains::EXCLUDE_PRIVATE_REGISTRIES);
464e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
474e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
484e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}  // namespace
494e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
504e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
514e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// OmniboxNavigationObserver --------------------------------------------------
524e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
534e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)OmniboxNavigationObserver::OmniboxNavigationObserver(
544e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    Profile* profile,
55a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    const base::string16& text,
564e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    const AutocompleteMatch& match,
57f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    const AutocompleteMatch& alternate_nav_match)
584e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    : text_(text),
594e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      match_(match),
60f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      alternate_nav_match_(alternate_nav_match),
614e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      shortcuts_backend_(ShortcutsBackendFactory::GetForProfile(profile)),
624e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      load_state_(LOAD_NOT_SEEN),
634e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      fetch_state_(FETCH_NOT_COMPLETE) {
64f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (alternate_nav_match_.destination_url.is_valid()) {
65f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    fetcher_.reset(net::URLFetcher::Create(alternate_nav_match_.destination_url,
664e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                                           net::URLFetcher::HEAD, this));
674e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    fetcher_->SetLoadFlags(net::LOAD_DO_NOT_SAVE_COOKIES);
684e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    fetcher_->SetStopOnRedirect(true);
694e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  }
704e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // We need to start by listening to AllSources, since we don't know which tab
714e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // the navigation might occur in.
724e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  registrar_.Add(this, content::NOTIFICATION_NAV_ENTRY_PENDING,
734e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                 content::NotificationService::AllSources());
744e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
754e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
764e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)OmniboxNavigationObserver::~OmniboxNavigationObserver() {
774e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
784e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
794e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)void OmniboxNavigationObserver::OnSuccessfulNavigation() {
801320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (shortcuts_backend_.get())
81f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    shortcuts_backend_->AddOrUpdateShortcut(text_, match_);
824e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
834e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
844e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)void OmniboxNavigationObserver::Observe(
854e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    int type,
864e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    const content::NotificationSource& source,
874e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    const content::NotificationDetails& details) {
884e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  DCHECK_EQ(content::NOTIFICATION_NAV_ENTRY_PENDING, type);
894e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  registrar_.Remove(this, content::NOTIFICATION_NAV_ENTRY_PENDING,
904e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                    content::NotificationService::AllSources());
914e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  content::NavigationController* controller =
924e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      content::Source<content::NavigationController>(source).ptr();
934e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (fetcher_) {
944e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    fetcher_->SetRequestContext(
954e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        controller->GetBrowserContext()->GetRequestContext());
964e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  }
974e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  WebContentsObserver::Observe(controller->GetWebContents());
98f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // DidStartNavigationToPendingEntry() will be called for this load as well.
994e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
1004e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
1014e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)void OmniboxNavigationObserver::NavigationEntryCommitted(
1024e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    const content::LoadCommittedDetails& load_details) {
1034e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  load_state_ = LOAD_COMMITTED;
1044e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (ResponseCodeIndicatesSuccess(load_details.http_status_code) &&
1054e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      IsValidNavigation(match_.destination_url, load_details.entry->GetURL()))
1064e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    OnSuccessfulNavigation();
1074e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (!fetcher_ || (fetch_state_ != FETCH_NOT_COMPLETE))
1084e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    OnAllLoadingFinished();  // deletes |this|!
1094e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
1104e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
111010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)void OmniboxNavigationObserver::WebContentsDestroyed() {
1124e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  delete this;
1134e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
1144e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
115f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void OmniboxNavigationObserver::DidStartNavigationToPendingEntry(
1164e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    const GURL& url,
1174e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    content::NavigationController::ReloadType reload_type) {
1184e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (load_state_ == LOAD_NOT_SEEN) {
1194e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    load_state_ = LOAD_PENDING;
1204e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    if (fetcher_)
1214e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      fetcher_->Start();
1224e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  } else {
1234e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    delete this;
1244e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  }
1254e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
1264e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
1274e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)void OmniboxNavigationObserver::OnURLFetchComplete(
1284e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    const net::URLFetcher* source) {
1294e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  DCHECK_EQ(fetcher_.get(), source);
1304e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  const net::URLRequestStatus& status = source->GetStatus();
1314e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  int response_code = source->GetResponseCode();
1324e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  fetch_state_ =
1334e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      (status.is_success() && ResponseCodeIndicatesSuccess(response_code)) ||
1344e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      ((status.status() == net::URLRequestStatus::CANCELED) &&
1354e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)       ((response_code / 100) == 3) &&
136f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)       IsValidNavigation(alternate_nav_match_.destination_url,
137f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                         source->GetURL())) ?
1384e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)          FETCH_SUCCEEDED : FETCH_FAILED;
1394e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (load_state_ == LOAD_COMMITTED)
1404e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    OnAllLoadingFinished();  // deletes |this|!
1414e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
1424e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
1434e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)void OmniboxNavigationObserver::OnAllLoadingFinished() {
1444e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (fetch_state_ == FETCH_SUCCEEDED) {
1454e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    AlternateNavInfoBarDelegate::Create(
146f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        web_contents(), text_, alternate_nav_match_, match_.destination_url);
1474e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  }
1484e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  delete this;
1494e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
150