Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / components / omnibox / autocomplete_provider.cc
1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "components/omnibox/autocomplete_provider.h"
6
7 #include "base/logging.h"
8 #include "base/strings/utf_string_conversions.h"
9 #include "components/omnibox/autocomplete_input.h"
10 #include "components/omnibox/autocomplete_match.h"
11 #include "components/url_fixer/url_fixer.h"
12 #include "net/base/net_util.h"
13 #include "url/gurl.h"
14
15 // static
16 const size_t AutocompleteProvider::kMaxMatches = 3;
17
18 AutocompleteProvider::AutocompleteProvider(Type type)
19     : done_(true),
20       type_(type) {
21 }
22
23 // static
24 const char* AutocompleteProvider::TypeToString(Type type) {
25   switch (type) {
26     case TYPE_BOOKMARK:
27       return "Bookmark";
28     case TYPE_BUILTIN:
29       return "Builtin";
30     case TYPE_HISTORY_QUICK:
31       return "HistoryQuick";
32     case TYPE_HISTORY_URL:
33       return "HistoryURL";
34     case TYPE_KEYWORD:
35       return "Keyword";
36     case TYPE_SEARCH:
37       return "Search";
38     case TYPE_SHORTCUTS:
39       return "Shortcuts";
40     case TYPE_ZERO_SUGGEST:
41       return "ZeroSuggest";
42     default:
43       NOTREACHED() << "Unhandled AutocompleteProvider::Type " << type;
44       return "Unknown";
45   }
46 }
47
48 void AutocompleteProvider::Stop(bool clear_cached_results) {
49   done_ = true;
50 }
51
52 const char* AutocompleteProvider::GetName() const {
53   return TypeToString(type_);
54 }
55
56 metrics::OmniboxEventProto_ProviderType AutocompleteProvider::
57     AsOmniboxEventProviderType() const {
58   switch (type_) {
59     case TYPE_BOOKMARK:
60       return metrics::OmniboxEventProto::BOOKMARK;
61     case TYPE_BUILTIN:
62       return metrics::OmniboxEventProto::BUILTIN;
63     case TYPE_HISTORY_QUICK:
64       return metrics::OmniboxEventProto::HISTORY_QUICK;
65     case TYPE_HISTORY_URL:
66       return metrics::OmniboxEventProto::HISTORY_URL;
67     case TYPE_KEYWORD:
68       return metrics::OmniboxEventProto::KEYWORD;
69     case TYPE_SEARCH:
70       return metrics::OmniboxEventProto::SEARCH;
71     case TYPE_SHORTCUTS:
72       return metrics::OmniboxEventProto::SHORTCUTS;
73     case TYPE_ZERO_SUGGEST:
74       return metrics::OmniboxEventProto::ZERO_SUGGEST;
75     default:
76       NOTREACHED() << "Unhandled AutocompleteProvider::Type " << type_;
77       return metrics::OmniboxEventProto::UNKNOWN_PROVIDER;
78   }
79 }
80
81 void AutocompleteProvider::DeleteMatch(const AutocompleteMatch& match) {
82   DLOG(WARNING) << "The AutocompleteProvider '" << GetName()
83                 << "' has not implemented DeleteMatch.";
84 }
85
86 void AutocompleteProvider::AddProviderInfo(ProvidersInfo* provider_info) const {
87 }
88
89 void AutocompleteProvider::ResetSession() {
90 }
91
92 AutocompleteProvider::~AutocompleteProvider() {
93   Stop(false);
94 }
95
96 // static
97 AutocompleteProvider::FixupReturn AutocompleteProvider::FixupUserInput(
98     const AutocompleteInput& input) {
99   const base::string16& input_text = input.text();
100   const FixupReturn failed(false, input_text);
101
102   // Fixup and canonicalize user input.
103   const GURL canonical_gurl(
104       url_fixer::FixupURL(base::UTF16ToUTF8(input_text), std::string()));
105   std::string canonical_gurl_str(canonical_gurl.possibly_invalid_spec());
106   if (canonical_gurl_str.empty()) {
107     // This probably won't happen, but there are no guarantees.
108     return failed;
109   }
110
111   // If the user types a number, GURL will convert it to a dotted quad.
112   // However, if the parser did not mark this as a URL, then the user probably
113   // didn't intend this interpretation.  Since this can break history matching
114   // for hostname beginning with numbers (e.g. input of "17173" will be matched
115   // against "0.0.67.21" instead of the original "17173", failing to find
116   // "17173.com"), swap the original hostname in for the fixed-up one.
117   if ((input.type() != metrics::OmniboxInputType::URL) &&
118       canonical_gurl.HostIsIPAddress()) {
119     std::string original_hostname =
120         base::UTF16ToUTF8(input_text.substr(input.parts().host.begin,
121                                             input.parts().host.len));
122     const url::Parsed& parts =
123         canonical_gurl.parsed_for_possibly_invalid_spec();
124     // parts.host must not be empty when HostIsIPAddress() is true.
125     DCHECK(parts.host.is_nonempty());
126     canonical_gurl_str.replace(parts.host.begin, parts.host.len,
127                                original_hostname);
128   }
129   base::string16 output(base::UTF8ToUTF16(canonical_gurl_str));
130   // Don't prepend a scheme when the user didn't have one.  Since the fixer
131   // upper only prepends the "http" scheme, that's all we need to check for.
132   if (!AutocompleteInput::HasHTTPScheme(input_text))
133     TrimHttpPrefix(&output);
134
135   // Make the number of trailing slashes on the output exactly match the input.
136   // Examples of why not doing this would matter:
137   // * The user types "a" and has this fixed up to "a/".  Now no other sites
138   //   beginning with "a" will match.
139   // * The user types "file:" and has this fixed up to "file://".  Now inline
140   //   autocomplete will append too few slashes, resulting in e.g. "file:/b..."
141   //   instead of "file:///b..."
142   // * The user types "http:/" and has this fixed up to "http:".  Now inline
143   //   autocomplete will append too many slashes, resulting in e.g.
144   //   "http:///c..." instead of "http://c...".
145   // NOTE: We do this after calling TrimHttpPrefix() since that can strip
146   // trailing slashes (if the scheme is the only thing in the input).  It's not
147   // clear that the result of fixup really matters in this case, but there's no
148   // harm in making sure.
149   const size_t last_input_nonslash =
150       input_text.find_last_not_of(base::ASCIIToUTF16("/\\"));
151   const size_t num_input_slashes =
152       (last_input_nonslash == base::string16::npos) ?
153       input_text.length() : (input_text.length() - 1 - last_input_nonslash);
154   const size_t last_output_nonslash =
155       output.find_last_not_of(base::ASCIIToUTF16("/\\"));
156   const size_t num_output_slashes =
157       (last_output_nonslash == base::string16::npos) ?
158       output.length() : (output.length() - 1 - last_output_nonslash);
159   if (num_output_slashes < num_input_slashes)
160     output.append(num_input_slashes - num_output_slashes, '/');
161   else if (num_output_slashes > num_input_slashes)
162     output.erase(output.length() - num_output_slashes + num_input_slashes);
163   if (output.empty())
164     return failed;
165
166   return FixupReturn(true, output);
167 }
168
169 // static
170 size_t AutocompleteProvider::TrimHttpPrefix(base::string16* url) {
171   // Find any "http:".
172   if (!AutocompleteInput::HasHTTPScheme(*url))
173     return 0;
174   size_t scheme_pos =
175       url->find(base::ASCIIToUTF16(url::kHttpScheme) + base::char16(':'));
176   DCHECK_NE(base::string16::npos, scheme_pos);
177
178   // Erase scheme plus up to two slashes.
179   size_t prefix_end = scheme_pos + strlen(url::kHttpScheme) + 1;
180   const size_t after_slashes = std::min(url->length(), prefix_end + 2);
181   while ((prefix_end < after_slashes) && ((*url)[prefix_end] == '/'))
182     ++prefix_end;
183   url->erase(scheme_pos, prefix_end - scheme_pos);
184   return (scheme_pos == 0) ? prefix_end : 0;
185 }