OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/browser/autocomplete/history_url_provider.h" | 5 #include "chrome/browser/autocomplete/history_url_provider.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 | 8 |
9 #include "base/basictypes.h" | 9 #include "base/basictypes.h" |
10 #include "base/bind.h" | 10 #include "base/bind.h" |
(...skipping 16 matching lines...) Expand all Loading... |
27 #include "chrome/browser/history/scored_history_match.h" | 27 #include "chrome/browser/history/scored_history_match.h" |
28 #include "chrome/browser/omnibox/omnibox_field_trial.h" | 28 #include "chrome/browser/omnibox/omnibox_field_trial.h" |
29 #include "chrome/browser/profiles/profile.h" | 29 #include "chrome/browser/profiles/profile.h" |
30 #include "chrome/browser/search_engines/template_url_service.h" | 30 #include "chrome/browser/search_engines/template_url_service.h" |
31 #include "chrome/browser/search_engines/template_url_service_factory.h" | 31 #include "chrome/browser/search_engines/template_url_service_factory.h" |
32 #include "chrome/common/chrome_switches.h" | 32 #include "chrome/common/chrome_switches.h" |
33 #include "chrome/common/net/url_fixer_upper.h" | 33 #include "chrome/common/net/url_fixer_upper.h" |
34 #include "chrome/common/pref_names.h" | 34 #include "chrome/common/pref_names.h" |
35 #include "chrome/common/url_constants.h" | 35 #include "chrome/common/url_constants.h" |
36 #include "components/bookmarks/browser/bookmark_utils.h" | 36 #include "components/bookmarks/browser/bookmark_utils.h" |
| 37 #include "components/metrics/proto/omnibox_input_type.pb.h" |
37 #include "net/base/net_util.h" | 38 #include "net/base/net_util.h" |
38 #include "net/base/registry_controlled_domains/registry_controlled_domain.h" | 39 #include "net/base/registry_controlled_domains/registry_controlled_domain.h" |
39 #include "url/gurl.h" | 40 #include "url/gurl.h" |
40 #include "url/url_parse.h" | 41 #include "url/url_parse.h" |
41 #include "url/url_util.h" | 42 #include "url/url_util.h" |
42 | 43 |
43 namespace { | 44 namespace { |
44 | 45 |
45 // If |create_if_necessary| is true, ensures that |matches| contains an | 46 // If |create_if_necessary| is true, ensures that |matches| contains an |
46 // entry for |info|, creating a new such entry if necessary (using | 47 // entry for |info|, creating a new such entry if necessary (using |
(...skipping 282 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
329 const AutocompleteInput& input, | 330 const AutocompleteInput& input, |
330 history::URLDatabase* db) | 331 history::URLDatabase* db) |
331 : provider_(provider), | 332 : provider_(provider), |
332 db_(db), | 333 db_(db), |
333 type_(INVALID) { | 334 type_(INVALID) { |
334 const GURL& url = input.canonicalized_url(); | 335 const GURL& url = input.canonicalized_url(); |
335 // Detect email addresses. These cases will look like "http://user@site/", | 336 // Detect email addresses. These cases will look like "http://user@site/", |
336 // and because the history backend strips auth creds, we'll get a bogus exact | 337 // and because the history backend strips auth creds, we'll get a bogus exact |
337 // match below if the user has visited "site". | 338 // match below if the user has visited "site". |
338 if (!url.is_valid() || | 339 if (!url.is_valid() || |
339 ((input.type() == AutocompleteInput::UNKNOWN) && | 340 ((input.type() == metrics::OmniboxInputType::UNKNOWN) && |
340 input.parts().username.is_nonempty() && | 341 input.parts().username.is_nonempty() && |
341 !input.parts().password.is_nonempty() && | 342 !input.parts().password.is_nonempty() && |
342 !input.parts().path.is_nonempty())) | 343 !input.parts().path.is_nonempty())) |
343 return; | 344 return; |
344 | 345 |
345 if (db_->GetRowForURL(url, &url_row_)) { | 346 if (db_->GetRowForURL(url, &url_row_)) { |
346 type_ = VISITED; | 347 type_ = VISITED; |
347 return; | 348 return; |
348 } | 349 } |
349 | 350 |
(...skipping 155 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
505 // | 506 // |
506 // We display this to the user when there's a reasonable chance they actually | 507 // We display this to the user when there's a reasonable chance they actually |
507 // care: | 508 // care: |
508 // * Their input can be opened as a URL, and | 509 // * Their input can be opened as a URL, and |
509 // * We parsed the input as a URL, or it starts with an explicit "http:" or | 510 // * We parsed the input as a URL, or it starts with an explicit "http:" or |
510 // "https:". | 511 // "https:". |
511 // that is when their input can be opened as a URL. | 512 // that is when their input can be opened as a URL. |
512 // Otherwise, this is just low-quality noise. In the cases where we've parsed | 513 // Otherwise, this is just low-quality noise. In the cases where we've parsed |
513 // as UNKNOWN, we'll still show an accidental search infobar if need be. | 514 // as UNKNOWN, we'll still show an accidental search infobar if need be. |
514 bool have_what_you_typed_match = | 515 bool have_what_you_typed_match = |
515 (params->input.type() != AutocompleteInput::QUERY) && | 516 (params->input.type() != metrics::OmniboxInputType::QUERY) && |
516 ((params->input.type() != AutocompleteInput::UNKNOWN) || | 517 ((params->input.type() != metrics::OmniboxInputType::UNKNOWN) || |
517 (classifier.type() == VisitClassifier::UNVISITED_INTRANET) || | 518 (classifier.type() == VisitClassifier::UNVISITED_INTRANET) || |
518 !params->trim_http || | 519 !params->trim_http || |
519 (AutocompleteInput::NumNonHostComponents(params->input.parts()) > 0)); | 520 (AutocompleteInput::NumNonHostComponents(params->input.parts()) > 0)); |
520 AutocompleteMatch what_you_typed_match(SuggestExactInput( | 521 AutocompleteMatch what_you_typed_match(SuggestExactInput( |
521 params->input.text(), params->input.canonicalized_url(), | 522 params->input.text(), params->input.canonicalized_url(), |
522 params->trim_http)); | 523 params->trim_http)); |
523 what_you_typed_match.relevance = CalculateRelevance(WHAT_YOU_TYPED, 0); | 524 what_you_typed_match.relevance = CalculateRelevance(WHAT_YOU_TYPED, 0); |
524 | 525 |
525 // Get the matching URLs from the DB | 526 // Get the matching URLs from the DB |
526 history::URLRows url_matches; | 527 history::URLRows url_matches; |
(...skipping 159 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
686 return kBaseScoreForNonInlineableResult + | 687 return kBaseScoreForNonInlineableResult + |
687 static_cast<int>(match_number); | 688 static_cast<int>(match_number); |
688 } | 689 } |
689 } | 690 } |
690 | 691 |
691 void HistoryURLProvider::RunAutocompletePasses( | 692 void HistoryURLProvider::RunAutocompletePasses( |
692 const AutocompleteInput& input, | 693 const AutocompleteInput& input, |
693 bool fixup_input_and_run_pass_1) { | 694 bool fixup_input_and_run_pass_1) { |
694 matches_.clear(); | 695 matches_.clear(); |
695 | 696 |
696 if ((input.type() == AutocompleteInput::INVALID) || | 697 if ((input.type() == metrics::OmniboxInputType::INVALID) || |
697 (input.type() == AutocompleteInput::FORCED_QUERY)) | 698 (input.type() == metrics::OmniboxInputType::FORCED_QUERY)) |
698 return; | 699 return; |
699 | 700 |
700 // Create a match for exactly what the user typed. This will only be used as | 701 // Create a match for exactly what the user typed. This will only be used as |
701 // a fallback in case we can't get the history service or URL DB; otherwise, | 702 // a fallback in case we can't get the history service or URL DB; otherwise, |
702 // we'll run this again in DoAutocomplete() and use that result instead. | 703 // we'll run this again in DoAutocomplete() and use that result instead. |
703 const bool trim_http = !AutocompleteInput::HasHTTPScheme(input.text()); | 704 const bool trim_http = !AutocompleteInput::HasHTTPScheme(input.text()); |
704 // Don't do this for queries -- while we can sometimes mark up a match for | 705 // Don't do this for queries -- while we can sometimes mark up a match for |
705 // this, it's not what the user wants, and just adds noise. | 706 // this, it's not what the user wants, and just adds noise. |
706 if (input.type() != AutocompleteInput::QUERY) { | 707 if (input.type() != metrics::OmniboxInputType::QUERY) { |
707 AutocompleteMatch what_you_typed(SuggestExactInput( | 708 AutocompleteMatch what_you_typed(SuggestExactInput( |
708 input.text(), input.canonicalized_url(), trim_http)); | 709 input.text(), input.canonicalized_url(), trim_http)); |
709 what_you_typed.relevance = CalculateRelevance(WHAT_YOU_TYPED, 0); | 710 what_you_typed.relevance = CalculateRelevance(WHAT_YOU_TYPED, 0); |
710 matches_.push_back(what_you_typed); | 711 matches_.push_back(what_you_typed); |
711 } | 712 } |
712 | 713 |
713 // We'll need the history service to run both passes, so try to obtain it. | 714 // We'll need the history service to run both passes, so try to obtain it. |
714 if (!profile_) | 715 if (!profile_) |
715 return; | 716 return; |
716 HistoryService* const history_service = | 717 HistoryService* const history_service = |
(...skipping 106 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
823 // make sure that this code does not trigger if the user did anything to | 824 // make sure that this code does not trigger if the user did anything to |
824 // indicate the desired match is a URL. For instance, "c/# foo" will not | 825 // indicate the desired match is a URL. For instance, "c/# foo" will not |
825 // pass the test because that will be classified as input type URL. The | 826 // pass the test because that will be classified as input type URL. The |
826 // parsed.CountCharactersBefore() in the test looks for the presence of a | 827 // parsed.CountCharactersBefore() in the test looks for the presence of a |
827 // reference fragment in the URL by checking whether the position differs | 828 // reference fragment in the URL by checking whether the position differs |
828 // included the delimiter (pound sign) versus not including the delimiter. | 829 // included the delimiter (pound sign) versus not including the delimiter. |
829 // (One cannot simply check url.ref() because it will not distinguish | 830 // (One cannot simply check url.ref() because it will not distinguish |
830 // between the input "c" and the input "c#", both of which will have empty | 831 // between the input "c" and the input "c#", both of which will have empty |
831 // reference fragments.) | 832 // reference fragments.) |
832 if ((type == UNVISITED_INTRANET) && | 833 if ((type == UNVISITED_INTRANET) && |
833 (input.type() != AutocompleteInput::URL) && url.username().empty() && | 834 (input.type() != metrics::OmniboxInputType::URL) && |
834 url.password().empty() && url.port().empty() && (url.path() == "/") && | 835 url.username().empty() && url.password().empty() && url.port().empty() && |
835 url.query().empty() && | 836 (url.path() == "/") && url.query().empty() && |
836 (parsed.CountCharactersBefore(url::Parsed::REF, true) != | 837 (parsed.CountCharactersBefore(url::Parsed::REF, true) != |
837 parsed.CountCharactersBefore(url::Parsed::REF, false))) { | 838 parsed.CountCharactersBefore(url::Parsed::REF, false))) { |
838 return false; | 839 return false; |
839 } | 840 } |
840 | 841 |
841 match->relevance = CalculateRelevance(type, 0); | 842 match->relevance = CalculateRelevance(type, 0); |
842 | 843 |
843 // If there are any other matches, then don't promote this match here, in | 844 // If there are any other matches, then don't promote this match here, in |
844 // hopes the caller will be able to inline autocomplete a better suggestion. | 845 // hopes the caller will be able to inline autocomplete a better suggestion. |
845 // DoAutocomplete() will fall back on this match if inline autocompletion | 846 // DoAutocomplete() will fall back on this match if inline autocompletion |
846 // fails. This matches how we react to never-visited URL inputs in the non- | 847 // fails. This matches how we react to never-visited URL inputs in the non- |
847 // intranet case. | 848 // intranet case. |
848 if (type == UNVISITED_INTRANET && !matches->empty()) | 849 if (type == UNVISITED_INTRANET && !matches->empty()) |
849 return false; | 850 return false; |
850 | 851 |
851 // Put it on the front of the HistoryMatches for redirect culling. | 852 // Put it on the front of the HistoryMatches for redirect culling. |
852 CreateOrPromoteMatch(classifier.url_row(), base::string16::npos, false, | 853 CreateOrPromoteMatch(classifier.url_row(), base::string16::npos, false, |
853 matches, true, true); | 854 matches, true, true); |
854 return true; | 855 return true; |
855 } | 856 } |
856 | 857 |
857 bool HistoryURLProvider::CanFindIntranetURL( | 858 bool HistoryURLProvider::CanFindIntranetURL( |
858 history::URLDatabase* db, | 859 history::URLDatabase* db, |
859 const AutocompleteInput& input) const { | 860 const AutocompleteInput& input) const { |
860 // Normally passing the first two conditions below ought to guarantee the | 861 // Normally passing the first two conditions below ought to guarantee the |
861 // third condition, but because FixupUserInput() can run and modify the | 862 // third condition, but because FixupUserInput() can run and modify the |
862 // input's text and parts between Parse() and here, it seems better to be | 863 // input's text and parts between Parse() and here, it seems better to be |
863 // paranoid and check. | 864 // paranoid and check. |
864 if ((input.type() != AutocompleteInput::UNKNOWN) || | 865 if ((input.type() != metrics::OmniboxInputType::UNKNOWN) || |
865 !LowerCaseEqualsASCII(input.scheme(), url::kHttpScheme) || | 866 !LowerCaseEqualsASCII(input.scheme(), url::kHttpScheme) || |
866 !input.parts().host.is_nonempty()) | 867 !input.parts().host.is_nonempty()) |
867 return false; | 868 return false; |
868 const std::string host(base::UTF16ToUTF8( | 869 const std::string host(base::UTF16ToUTF8( |
869 input.text().substr(input.parts().host.begin, input.parts().host.len))); | 870 input.text().substr(input.parts().host.begin, input.parts().host.len))); |
870 const size_t registry_length = | 871 const size_t registry_length = |
871 net::registry_controlled_domains::GetRegistryLength( | 872 net::registry_controlled_domains::GetRegistryLength( |
872 host, | 873 host, |
873 net::registry_controlled_domains::EXCLUDE_UNKNOWN_REGISTRIES, | 874 net::registry_controlled_domains::EXCLUDE_UNKNOWN_REGISTRIES, |
874 net::registry_controlled_domains::EXCLUDE_PRIVATE_REGISTRIES); | 875 net::registry_controlled_domains::EXCLUDE_PRIVATE_REGISTRIES); |
(...skipping 283 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1158 // If HistoryURL retrieves any matches (and hence we reach this code), we | 1159 // If HistoryURL retrieves any matches (and hence we reach this code), we |
1159 // are guaranteed that the beginning of input_text must be a word break. | 1160 // are guaranteed that the beginning of input_text must be a word break. |
1160 history::WordStarts offsets(1, 0u); | 1161 history::WordStarts offsets(1, 0u); |
1161 description_matches = | 1162 description_matches = |
1162 history::ScoredHistoryMatch::FilterTermMatchesByWordStarts( | 1163 history::ScoredHistoryMatch::FilterTermMatchesByWordStarts( |
1163 description_matches, offsets, description_word_starts, 0, | 1164 description_matches, offsets, description_word_starts, 0, |
1164 std::string::npos); | 1165 std::string::npos); |
1165 return SpansFromTermMatch( | 1166 return SpansFromTermMatch( |
1166 description_matches, clean_description.length(), false); | 1167 description_matches, clean_description.length(), false); |
1167 } | 1168 } |
OLD | NEW |