root/chrome/browser/ui/search_engines/search_engine_tab_helper.cc

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. IsFormSubmit
  2. GenerateKeywordFromNavigationEntry
  3. DidNavigateMainFrame
  4. OnMessageReceived
  5. OnPageHasOSDD
  6. GenerateKeywordIfNecessary

// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/ui/search_engines/search_engine_tab_helper.h"

#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/search_engines/template_url.h"
#include "chrome/browser/search_engines/template_url_fetcher.h"
#include "chrome/browser/search_engines/template_url_fetcher_factory.h"
#include "chrome/browser/search_engines/template_url_service.h"
#include "chrome/browser/search_engines/template_url_service_factory.h"
#include "chrome/browser/ui/search_engines/template_url_fetcher_ui_callbacks.h"
#include "chrome/common/render_messages.h"
#include "chrome/common/url_constants.h"
#include "content/public/browser/favicon_status.h"
#include "content/public/browser/navigation_controller.h"
#include "content/public/browser/navigation_entry.h"
#include "content/public/browser/web_contents.h"
#include "content/public/common/frame_navigate_params.h"

using content::NavigationController;
using content::NavigationEntry;
using content::WebContents;

DEFINE_WEB_CONTENTS_USER_DATA_KEY(SearchEngineTabHelper);

namespace {

// Returns true if the entry's transition type is FORM_SUBMIT.
bool IsFormSubmit(const NavigationEntry* entry) {
  return (content::PageTransitionStripQualifier(entry->GetTransitionType()) ==
          content::PAGE_TRANSITION_FORM_SUBMIT);
}

base::string16 GenerateKeywordFromNavigationEntry(
    const NavigationEntry* entry) {
  // Don't autogenerate keywords for pages that are the result of form
  // submissions.
  if (IsFormSubmit(entry))
    return base::string16();

  // We want to use the user typed URL if available since that represents what
  // the user typed to get here, and fall back on the regular URL if not.
  GURL url = entry->GetUserTypedURL();
  if (!url.is_valid()) {
    url = entry->GetURL();
    if (!url.is_valid())
      return base::string16();
  }

  // Don't autogenerate keywords for referrers that are anything other than HTTP
  // or have a path.
  //
  // If we relax the path constraint, we need to be sure to sanitize the path
  // elements and update AutocompletePopup to look for keywords using the path.
  // See http://b/issue?id=863583.
  if (!url.SchemeIs(content::kHttpScheme) || (url.path().length() > 1))
    return base::string16();

  return TemplateURLService::GenerateKeyword(url);
}

}  // namespace

SearchEngineTabHelper::~SearchEngineTabHelper() {
}

void SearchEngineTabHelper::DidNavigateMainFrame(
    const content::LoadCommittedDetails& /*details*/,
    const content::FrameNavigateParams& params) {
  GenerateKeywordIfNecessary(params);
}

bool SearchEngineTabHelper::OnMessageReceived(const IPC::Message& message) {
  bool handled = true;
  IPC_BEGIN_MESSAGE_MAP(SearchEngineTabHelper, message)
    IPC_MESSAGE_HANDLER(ChromeViewHostMsg_PageHasOSDD, OnPageHasOSDD)
    IPC_MESSAGE_UNHANDLED(handled = false)
  IPC_END_MESSAGE_MAP()

  return handled;
}

SearchEngineTabHelper::SearchEngineTabHelper(WebContents* web_contents)
    : content::WebContentsObserver(web_contents) {
  DCHECK(web_contents);
}

void SearchEngineTabHelper::OnPageHasOSDD(
    int32 page_id,
    const GURL& doc_url,
    const search_provider::OSDDType& msg_provider_type) {
  // Checks to see if we should generate a keyword based on the OSDD, and if
  // necessary uses TemplateURLFetcher to download the OSDD and create a
  // keyword.

  // Make sure page_id is the current page and other basic checks.
  if (!doc_url.is_valid())
    return;
  Profile* profile =
      Profile::FromBrowserContext(web_contents()->GetBrowserContext());
  if (!web_contents()->IsActiveEntry(page_id) ||
      !TemplateURLFetcherFactory::GetForProfile(profile) ||
      profile->IsOffTheRecord())
    return;

  TemplateURLFetcher::ProviderType provider_type =
      (msg_provider_type == search_provider::AUTODETECTED_PROVIDER) ?
          TemplateURLFetcher::AUTODETECTED_PROVIDER :
          TemplateURLFetcher::EXPLICIT_PROVIDER;

  // If the current page is a form submit, find the last page that was not a
  // form submit and use its url to generate the keyword from.
  const NavigationController& controller = web_contents()->GetController();
  const NavigationEntry* entry = controller.GetLastCommittedEntry();
  for (int index = controller.GetLastCommittedEntryIndex();
       (index > 0) && IsFormSubmit(entry);
       entry = controller.GetEntryAtIndex(index))
    --index;
  if (IsFormSubmit(entry))
    return;

  // Autogenerate a keyword for the autodetected case; in the other cases we'll
  // generate a keyword later after fetching the OSDD.
  base::string16 keyword;
  if (provider_type == TemplateURLFetcher::AUTODETECTED_PROVIDER) {
    keyword = GenerateKeywordFromNavigationEntry(entry);
    if (keyword.empty())
      return;
  }

  // Download the OpenSearch description document. If this is successful, a
  // new keyword will be created when done.
  TemplateURLFetcherFactory::GetForProfile(profile)->ScheduleDownload(
      keyword, doc_url, entry->GetFavicon().url, web_contents(),
      new TemplateURLFetcherUICallbacks(this, web_contents()), provider_type);
}

void SearchEngineTabHelper::GenerateKeywordIfNecessary(
    const content::FrameNavigateParams& params) {
  if (!params.searchable_form_url.is_valid())
    return;

  Profile* profile =
      Profile::FromBrowserContext(web_contents()->GetBrowserContext());
  if (profile->IsOffTheRecord())
    return;

  const NavigationController& controller = web_contents()->GetController();
  int last_index = controller.GetLastCommittedEntryIndex();
  // When there was no previous page, the last index will be 0. This is
  // normally due to a form submit that opened in a new tab.
  // TODO(brettw) bug 916126: we should support keywords when form submits
  //              happen in new tabs.
  if (last_index <= 0)
    return;

  base::string16 keyword(GenerateKeywordFromNavigationEntry(
      controller.GetEntryAtIndex(last_index - 1)));
  if (keyword.empty())
    return;

  TemplateURLService* url_service =
      TemplateURLServiceFactory::GetForProfile(profile);
  if (!url_service)
    return;

  if (!url_service->loaded()) {
    url_service->Load();
    return;
  }

  TemplateURL* current_url;
  GURL url = params.searchable_form_url;
  if (!url_service->CanReplaceKeyword(keyword, url, &current_url))
    return;

  if (current_url) {
    if (current_url->originating_url().is_valid()) {
      // The existing keyword was generated from an OpenSearch description
      // document, don't regenerate.
      return;
    }
    url_service->Remove(current_url);
  }

  TemplateURLData data;
  data.short_name = keyword;
  data.SetKeyword(keyword);
  data.SetURL(url.spec());
  DCHECK(controller.GetLastCommittedEntry());
  const GURL& current_favicon =
      controller.GetLastCommittedEntry()->GetFavicon().url;
  // If the favicon url isn't valid, it means there really isn't a favicon, or
  // the favicon url wasn't obtained before the load started. This assumes the
  // latter.
  // TODO(sky): Need a way to set the favicon that doesn't involve generating
  // its url.
  data.favicon_url = current_favicon.is_valid() ?
      current_favicon : TemplateURL::GenerateFaviconURL(params.referrer.url);
  data.safe_for_autoreplace = true;
  data.input_encodings.push_back(params.searchable_form_encoding);
  url_service->Add(new TemplateURL(profile, data));
}

/* [<][>][^][v][top][bottom][index][help] */