// Copyright (c) 2011 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.
#ifndef CHROME_BROWSER_SEARCH_ENGINES_TEMPLATE_URL_H_
#define CHROME_BROWSER_SEARCH_ENGINES_TEMPLATE_URL_H_
#pragma once
#include <string>
#include <vector>
#include "base/gtest_prod_util.h"
#include "base/time.h"
#include "chrome/browser/search_engines/search_engine_type.h"
#include "chrome/browser/search_engines/template_url_id.h"
#include "googleurl/src/gurl.h"
class PrefService;
class SearchTermsData;
class TemplateURL;
class WebDataService;
struct WDKeywordsResult;
// TemplateURL represents the relevant portions of the Open Search Description
// Document (http://www.opensearch.org/Specifications/OpenSearch).
// The main use case for TemplateURL is to use the TemplateURLRef returned by
// suggestions_url or url for keyword/suggestion expansion:
// . suggestions_url describes a URL that is ideal for as you type suggestions.
// The returned results are in the mime type application/x-suggestions+json.
// . url describes a URL that may be used as a shortcut. Returned results are
// are text/html.
// Before using either one, make sure it's non-NULL, and if you intend to use
// it to replace search terms, make sure SupportsReplacement returns true.
// To use either URL invoke the ReplaceSearchTerms method on the corresponding
// TemplateURLRef.
//
// For files parsed from the Web, be sure and invoke IsValid. IsValid returns
// true if the URL could be parsed.
//
// Both TemplateURL and TemplateURLRef have value semantics. This allows the
// UI to create a copy while the user modifies the values.
class TemplateURLRef {
public:
// Magic numbers to pass to ReplaceSearchTerms() for the |accepted_suggestion|
// parameter. Most callers aren't using Suggest capabilities and should just
// pass NO_SUGGESTIONS_AVAILABLE.
// NOTE: Because positive values are meaningful, make sure these are negative!
enum AcceptedSuggestion {
NO_SUGGESTION_CHOSEN = -1,
NO_SUGGESTIONS_AVAILABLE = -2,
};
TemplateURLRef();
TemplateURLRef(const std::string& url, int index_offset, int page_offset);
~TemplateURLRef();
// Returns true if this URL supports replacement.
bool SupportsReplacement() const;
// Like SupportsReplacement but usable on threads other than the UI thread.
bool SupportsReplacementUsingTermsData(
const SearchTermsData& search_terms_data) const;
// Returns a string that is the result of replacing the search terms in
// the url with the specified value.
//
// If this TemplateURLRef does not support replacement (SupportsReplacement
// returns false), an empty string is returned.
//
// The TemplateURL is used to determine the input encoding for the term.
std::string ReplaceSearchTerms(
const TemplateURL& host,
const string16& terms,
int accepted_suggestion,
const string16& original_query_for_suggestion) const;
// Just like ReplaceSearchTerms except that it takes SearchTermsData to supply
// the data for some search terms. Most of the time ReplaceSearchTerms should
// be called.
std::string ReplaceSearchTermsUsingTermsData(
const TemplateURL& host,
const string16& terms,
int accepted_suggestion,
const string16& original_query_for_suggestion,
const SearchTermsData& search_terms_data) const;
// Returns the raw URL. None of the parameters will have been replaced.
const std::string& url() const { return url_; }
// Returns the index number of the first search result.
int index_offset() const { return index_offset_; }
// Returns the page number of the first search results.
int page_offset() const { return page_offset_; }
// Returns true if the TemplateURLRef is valid. An invalid TemplateURLRef is
// one that contains unknown terms, or invalid characters.
bool IsValid() const;
// Like IsValid but usable on threads other than the UI thread.
bool IsValidUsingTermsData(const SearchTermsData& search_terms_data) const;
// Returns a string representation of this TemplateURLRef suitable for
// display. The display format is the same as the format used by Firefox.
string16 DisplayURL() const;
// Converts a string as returned by DisplayURL back into a string as
// understood by TemplateURLRef.
static std::string DisplayURLToURLRef(const string16& display_url);
// If this TemplateURLRef is valid and contains one search term, this returns
// the host/path of the URL, otherwise this returns an empty string.
const std::string& GetHost() const;
const std::string& GetPath() const;
// If this TemplateURLRef is valid and contains one search term, this returns
// the key of the search term, otherwise this returns an empty string.
const std::string& GetSearchTermKey() const;
// Converts the specified term in the encoding of the host TemplateURL to a
// string16.
string16 SearchTermToString16(const TemplateURL& host,
const std::string& term) const;
// Returns true if this TemplateURLRef has a replacement term of
// {google:baseURL} or {google:baseSuggestURL}.
bool HasGoogleBaseURLs() const;
// Returns true if both refs are NULL or have the same values.
static bool SameUrlRefs(const TemplateURLRef* ref1,
const TemplateURLRef* ref2);
// Collects metrics whether searches through Google are sent with RLZ string.
void CollectRLZMetrics() const;
private:
friend class SearchHostToURLsMapTest;
friend class TemplateURL;
friend class TemplateURLModelTestUtil;
friend class TemplateURLTest;
FRIEND_TEST_ALL_PREFIXES(TemplateURLTest, ParseParameterKnown);
FRIEND_TEST_ALL_PREFIXES(TemplateURLTest, ParseParameterUnknown);
FRIEND_TEST_ALL_PREFIXES(TemplateURLTest, ParseURLEmpty);
FRIEND_TEST_ALL_PREFIXES(TemplateURLTest, ParseURLNoTemplateEnd);
FRIEND_TEST_ALL_PREFIXES(TemplateURLTest, ParseURLNoKnownParameters);
FRIEND_TEST_ALL_PREFIXES(TemplateURLTest, ParseURLTwoParameters);
FRIEND_TEST_ALL_PREFIXES(TemplateURLTest, ParseURLNestedParameter);
// Enumeration of the known types.
enum ReplacementType {
ENCODING,
GOOGLE_ACCEPTED_SUGGESTION,
GOOGLE_BASE_URL,
GOOGLE_BASE_SUGGEST_URL,
GOOGLE_ORIGINAL_QUERY_FOR_SUGGESTION,
GOOGLE_RLZ,
GOOGLE_UNESCAPED_SEARCH_TERMS,
LANGUAGE,
SEARCH_TERMS,
};
// Used to identify an element of the raw url that can be replaced.
struct Replacement {
Replacement(ReplacementType type, size_t index)
: type(type), index(index) {}
ReplacementType type;
size_t index;
};
// The list of elements to replace.
typedef std::vector<struct Replacement> Replacements;
// TemplateURLRef internally caches values to make replacement quick. This
// method invalidates any cached values.
void InvalidateCachedValues() const;
// Resets the url.
void Set(const std::string& url, int index_offset, int page_offset);
// Parses the parameter in url at the specified offset. start/end specify the
// range of the parameter in the url, including the braces. If the parameter
// is valid, url is updated to reflect the appropriate parameter. If
// the parameter is one of the known parameters an element is added to
// replacements indicating the type and range of the element. The original
// parameter is erased from the url.
//
// If the parameter is not a known parameter, it's not erased and false is
// returned.
bool ParseParameter(size_t start,
size_t end,
std::string* url,
Replacements* replacements) const;
// Parses the specified url, replacing parameters as necessary. If
// successful, valid is set to true, and the parsed url is returned. For all
// known parameters that are encountered an entry is added to replacements.
// If there is an error parsing the url, valid is set to false, and an empty
// string is returned.
std::string ParseURL(const std::string& url,
Replacements* replacements,
bool* valid) const;
// If the url has not yet been parsed, ParseURL is invoked.
// NOTE: While this is const, it modifies parsed_, valid_, parsed_url_ and
// search_offset_.
void ParseIfNecessary() const;
// Like ParseIfNecessary but usable on threads other than the UI thread.
void ParseIfNecessaryUsingTermsData(
const SearchTermsData& search_terms_data) const;
// Extracts the query key and host from the url.
void ParseHostAndSearchTermKey(
const SearchTermsData& search_terms_data) const;
// Used by tests to set the value for the Google base url. This takes
// ownership of the given std::string.
static void SetGoogleBaseURL(std::string* google_base_url);
// The raw URL. Where as this contains all the terms (such as {searchTerms}),
// parsed_url_ has them all stripped out.
std::string url_;
// indexOffset defined for the Url element.
int index_offset_;
// searchOffset defined for the Url element.
int page_offset_;
// Whether the URL has been parsed.
mutable bool parsed_;
// Whether the url was successfully parsed.
mutable bool valid_;
// The parsed URL. All terms have been stripped out of this with
// replacements_ giving the index of the terms to replace.
mutable std::string parsed_url_;
// Do we support replacement?
mutable bool supports_replacements_;
// The replaceable parts of url (parsed_url_). These are ordered by index
// into the string, and may be empty.
mutable Replacements replacements_;
// Host, path and key of the search term. These are only set if the url
// contains one search term.
mutable std::string host_;
mutable std::string path_;
mutable std::string search_term_key_;
};
// Describes the relevant portions of a single OSD document.
class TemplateURL {
public:
// Describes a single image reference. Each TemplateURL may have
// any number (including 0) of ImageRefs.
//
// If a TemplateURL has no images, the favicon for the generated URL
// should be used.
struct ImageRef {
ImageRef(const std::string& type, int width, int height)
: type(type), width(width), height(height) {
}
ImageRef(const std::string& type, int width, int height, const GURL& url)
: type(type), width(width), height(height), url(url) {
}
// Mime type for the image.
// ICO image will have the format: image/x-icon or image/vnd.microsoft.icon
std::string type;
// Size of the image
int width;
int height;
// URL of the image.
GURL url;
};
// Generates a favicon URL from the specified url.
static GURL GenerateFaviconURL(const GURL& url);
// Returns true if |turl| is non-null and has a search URL that supports
// replacement.
static bool SupportsReplacement(const TemplateURL* turl);
// Like SupportsReplacement but usable on threads other than the UI thread.
static bool SupportsReplacementUsingTermsData(
const TemplateURL* turl,
const SearchTermsData& search_terms_data);
TemplateURL();
~TemplateURL();
// A short description of the template. This is the name we show to the user
// in various places that use keywords. For example, the location bar shows
// this when the user selects the keyword.
void set_short_name(const string16& short_name) {
short_name_ = short_name;
}
string16 short_name() const { return short_name_; }
// An accessor for the short_name, but adjusted so it can be appropriately
// displayed even if it is LTR and the UI is RTL.
string16 AdjustedShortNameForLocaleDirection() const;
// A description of the template; this may be empty.
void set_description(const string16& description) {
description_ = description;
}
string16 description() const { return description_; }
// URL providing JSON results. This is typically used to provide suggestions
// as your type. If NULL, this url does not support suggestions.
// Be sure and check the resulting TemplateURLRef for SupportsReplacement
// before using.
void SetSuggestionsURL(const std::string& suggestions_url,
int index_offset,
int page_offset);
const TemplateURLRef* suggestions_url() const {
return suggestions_url_.url().empty() ? NULL : &suggestions_url_;
}
// Parameterized URL for providing the results. This may be NULL.
// Be sure and check the resulting TemplateURLRef for SupportsReplacement
// before using.
void SetURL(const std::string& url, int index_offset, int page_offset);
// Returns the TemplateURLRef that may be used for search results. This
// returns NULL if a url element was not specified.
const TemplateURLRef* url() const {
return url_.url().empty() ? NULL : &url_;
}
// Parameterized URL for instant results. This may be NULL. Be sure and check
// the resulting TemplateURLRef for SupportsReplacement before using. See
// TemplateURLRef for a description of |index_offset| and |page_offset|.
void SetInstantURL(const std::string& url, int index_offset, int page_offset);
// Returns the TemplateURLRef that may be used for search results. This
// returns NULL if a url element was not specified.
const TemplateURLRef* instant_url() const {
return instant_url_.url().empty() ? NULL : &instant_url_;
}
// URL to the OSD file this came from. May be empty.
void set_originating_url(const GURL& url) {
originating_url_ = url;
}
const GURL& originating_url() const { return originating_url_; }
// The shortcut for this template url. May be empty.
void set_keyword(const string16& keyword);
string16 keyword() const;
// Whether to autogenerate a keyword from the url() in GetKeyword(). Most
// consumers should not need this.
// NOTE: Calling set_keyword() turns this back off. Manual and automatic
// keywords are mutually exclusive.
void set_autogenerate_keyword(bool autogenerate_keyword) {
autogenerate_keyword_ = autogenerate_keyword;
if (autogenerate_keyword_) {
keyword_.clear();
keyword_generated_ = false;
}
}
bool autogenerate_keyword() const {
return autogenerate_keyword_;
}
// Ensures that the keyword is generated. Most consumers should not need this
// because it is done automatically. Use this method on the UI thread, so
// the keyword may be accessed on another thread.
void EnsureKeyword() const;
// Whether this keyword is shown in the default list of search providers. This
// is just a property and does not indicate whether this TemplateURL has
// a TemplateURLRef that supports replacement. Use ShowInDefaultList to
// test both.
// The default value is false.
void set_show_in_default_list(bool show_in_default_list) {
show_in_default_list_ = show_in_default_list;
}
bool show_in_default_list() const { return show_in_default_list_; }
// Returns true if show_in_default_list() is true and this TemplateURL has a
// TemplateURLRef that supports replacement.
bool ShowInDefaultList() const;
// Whether it's safe for auto-modification code (the autogenerator and the
// code that imports data from other browsers) to replace the TemplateURL.
// This should be set to false for any keyword the user edits, or any keyword
// that the user clearly manually edited in the past, like a bookmark keyword
// from another browser.
void set_safe_for_autoreplace(bool safe_for_autoreplace) {
safe_for_autoreplace_ = safe_for_autoreplace;
}
bool safe_for_autoreplace() const { return safe_for_autoreplace_; }
// Images for this URL. May be empty.
void add_image_ref(const ImageRef& ref) { image_refs_.push_back(ref); }
const std::vector<ImageRef>& image_refs() const { return image_refs_; }
// Convenience methods for getting/setting an ImageRef that points to a
// favicon. A TemplateURL need not have an ImageRef for a favicon. In such
// a situation GetFaviconURL returns an invalid url.
//
// If url is empty and there is an image ref for a favicon, it is removed.
void SetFaviconURL(const GURL& url);
GURL GetFaviconURL() const;
// Set of languages supported. This may be empty.
void add_language(const string16& language) {
languages_.push_back(language);
}
std::vector<string16> languages() const { return languages_; }
// Date this keyword was created.
//
// NOTE: this may be 0, which indicates the keyword was created before we
// started tracking creation time.
void set_date_created(base::Time time) { date_created_ = time; }
base::Time date_created() const { return date_created_; }
// True if this TemplateURL was automatically created by the administrator via
// group policy.
void set_created_by_policy(bool created_by_policy) {
created_by_policy_ = created_by_policy;
}
bool created_by_policy() const { return created_by_policy_; }
// Number of times this keyword has been explicitly used to load a URL. We
// don't increment this for uses as the "default search engine" since that's
// not really "explicit" usage and incrementing would result in pinning the
// user's default search engine(s) to the top of the list of searches on the
// New Tab page, de-emphasizing the omnibox as "where you go to search".
void set_usage_count(int count) { usage_count_ = count; }
int usage_count() const { return usage_count_; }
// The list of supported encodings for the search terms. This may be empty,
// which indicates the terms should be encoded with UTF-8.
void set_input_encodings(const std::vector<std::string>& encodings) {
input_encodings_ = encodings;
}
void add_input_encoding(const std::string& encoding) {
input_encodings_.push_back(encoding);
}
const std::vector<std::string>& input_encodings() const {
return input_encodings_;
}
void set_search_engine_type(SearchEngineType search_engine_type) {
search_engine_type_ = search_engine_type;
}
SearchEngineType search_engine_type() const {
return search_engine_type_;
}
void set_logo_id(int logo_id) { logo_id_ = logo_id; }
int logo_id() const { return logo_id_; }
// Returns the unique identifier of this TemplateURL. The unique ID is set
// by the TemplateURLModel when the TemplateURL is added to it.
TemplateURLID id() const { return id_; }
// If this TemplateURL comes from prepopulated data the prepopulate_id is > 0.
void set_prepopulate_id(int id) { prepopulate_id_ = id; }
int prepopulate_id() const { return prepopulate_id_; }
std::string GetExtensionId() const;
bool IsExtensionKeyword() const;
private:
friend void MergeEnginesFromPrepopulateData(
PrefService* prefs,
WebDataService* service,
std::vector<TemplateURL*>* template_urls,
const TemplateURL** default_search_provider);
friend class KeywordTable;
friend class KeywordTableTest;
friend class SearchHostToURLsMap;
friend class TemplateURLModel;
// Invalidates cached values on this object and its child TemplateURLRefs.
void InvalidateCachedValues() const;
// Unique identifier, used when archived to the database.
void set_id(TemplateURLID id) { id_ = id; }
string16 short_name_;
string16 description_;
TemplateURLRef suggestions_url_;
TemplateURLRef url_;
TemplateURLRef instant_url_;
GURL originating_url_;
mutable string16 keyword_;
bool autogenerate_keyword_; // If this is set, |keyword_| holds the cached
// generated keyword if available.
mutable bool keyword_generated_; // True if the keyword was generated. This
// is used to avoid multiple attempts if
// generating a keyword failed.
bool show_in_default_list_;
bool safe_for_autoreplace_;
std::vector<ImageRef> image_refs_;
std::vector<string16> languages_;
// List of supported input encodings.
std::vector<std::string> input_encodings_;
TemplateURLID id_;
base::Time date_created_;
bool created_by_policy_;
int usage_count_;
SearchEngineType search_engine_type_;
int logo_id_;
int prepopulate_id_;
// TODO(sky): Add date last parsed OSD file.
};
#endif // CHROME_BROWSER_SEARCH_ENGINES_TEMPLATE_URL_H_