OLD | NEW |
| (Empty) |
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/autocomplete/autocomplete_provider.h" | |
6 | |
7 #include "base/logging.h" | |
8 #include "base/strings/utf_string_conversions.h" | |
9 #include "components/autocomplete/autocomplete_input.h" | |
10 #include "components/autocomplete/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 } | |
OLD | NEW |