diff options
author | pkasting@chromium.org <pkasting@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-08-19 17:08:00 +0000 |
---|---|---|
committer | pkasting@chromium.org <pkasting@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-08-19 17:08:00 +0000 |
commit | fe4eb9827d908251a0f2fd1a2d46cdf51e94cd7a (patch) | |
tree | f2d80a848fc72f90e08f63fb6fb4418bd199707f | |
parent | 7c5048cb78980caeb134eec8748ab892df2237fb (diff) | |
download | chromium_src-fe4eb9827d908251a0f2fd1a2d46cdf51e94cd7a.zip chromium_src-fe4eb9827d908251a0f2fd1a2d46cdf51e94cd7a.tar.gz chromium_src-fe4eb9827d908251a0f2fd1a2d46cdf51e94cd7a.tar.bz2 |
Handle intranet hostnames more consistently.
AutocompleteInput::Parse() now usually marks intranet navigations as UNKNOWN and relies on the HistoryURLProvider to do the right thing. In turn the HistoryURLProvider will mark URLs it's never seen as high-quality navigations if they have a hostname that's part of a previously-type intranet URL.
So for example, "abc/def" on a clean profile now defaults to searching rather than navigating; but if any URL on host "abc" has been typed before, both "abc/def" and "abc/def ghi" will navigate, despite the space in the second case.
This also changes the default behavior for some similar cases like "abc:81", "user:pass@abc", and "user:pass@abc:81". Again these will all now default to searching, but navigate if the host in question has been typed. Unchanged is the behavior of "abc/"; because the scheme-stripping code relies on a single trailing slash triggering a navigation, and because it's convenient for users to force navigation on an unknown host, this is still parsed as a URL.
BUG=6788
TEST=Navigate to "who/", then type "who/a b" and note that the default action is to navigate rather than search.
Review URL: http://codereview.chromium.org/7661028
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@97470 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r-- | chrome/browser/autocomplete/autocomplete.cc | 61 | ||||
-rw-r--r-- | chrome/browser/autocomplete/autocomplete_edit_unittest.cc | 16 | ||||
-rw-r--r-- | chrome/browser/autocomplete/autocomplete_unittest.cc | 14 | ||||
-rw-r--r-- | chrome/browser/autocomplete/history_url_provider.cc | 82 | ||||
-rw-r--r-- | chrome/browser/autocomplete/history_url_provider.h | 6 | ||||
-rw-r--r-- | chrome/browser/autocomplete/history_url_provider_unittest.cc | 58 | ||||
-rw-r--r-- | chrome/browser/history/url_database.cc | 5 | ||||
-rw-r--r-- | chrome/browser/history/url_database.h | 7 |
8 files changed, 152 insertions, 97 deletions
diff --git a/chrome/browser/autocomplete/autocomplete.cc b/chrome/browser/autocomplete/autocomplete.cc index d728924..627e35d 100644 --- a/chrome/browser/autocomplete/autocomplete.cc +++ b/chrome/browser/autocomplete/autocomplete.cc @@ -353,11 +353,6 @@ AutocompleteInput::Type AutocompleteInput::Parse( if (host_info.family == url_canon::CanonHostInfo::IPV6) return URL; - // Now that we've ruled out invalid ports and queries that look like they have - // a port, the presence of a port means this is likely a URL. - if (parts->port.is_nonempty()) - return URL; - // Presence of a password means this is likely a URL. Note that unless the // user has typed an explicit "http://" or similar, we'll probably think that // the username is some unknown scheme, and bail out in the scheme-handling @@ -365,35 +360,31 @@ AutocompleteInput::Type AutocompleteInput::Parse( if (parts->password.is_nonempty()) return URL; - // The host doesn't look like a number, so see if the user's given us a path. - if (parts->path.is_nonempty()) { - // Most inputs with paths are URLs, even ones without known registries (e.g. - // intranet URLs). However, if there's no known registry and the path has - // a space, this is more likely a query with a slash in the first term - // (e.g. "ps/2 games") than a URL. We can still open URLs with spaces in - // the path by escaping the space, and we will still inline autocomplete - // them if users have typed them in the past, but we default to searching - // since that's the common case. - return ((registry_length == 0) && - (text.substr(parts->path.begin, parts->path.len).find(' ') != - string16::npos)) ? UNKNOWN : URL; - } + // Trailing slashes force the input to be treated as a URL. + if (parts->path.len == 1) + return URL; - // If we reach here with a username, our input looks like "user@host". - // Because there is no scheme explicitly specified, we think this is more - // likely an email address than an HTTP auth attempt. Hence, we search by - // default and let users correct us on a case-by-case basis. - if (parts->username.is_nonempty()) + // If we reach here with a username, but no port or path, our input looks like + // "user@host". Because there is no scheme explicitly specified, we think + // this is more likely an email address than an HTTP auth attempt. Hence, we + // search by default and let users correct us on a case-by-case basis. + if (parts->username.is_nonempty() && !parts->port.is_nonempty() && + !parts->path.is_nonempty()) return UNKNOWN; - // We have a bare host string. If it has a known TLD, it's probably a URL. - if (registry_length != 0) + // If the host has a known TLD, it's probably a URL. Also special-case + // "localhost" as a known hostname. + if ((registry_length != 0) || (host == ASCIIToUTF16("localhost"))) return URL; - // No TLD that we know about. This could be: - // * A string that the user wishes to add a desired_tld to to get a URL. If - // we reach this point, we know there's no known TLD on the string, so the - // fixup code will be willing to add one; thus this is a URL. + // If we reach this point, we know there's no known TLD on the input, so if + // the user wishes to add a desired_tld, the fixup code will oblige; thus this + // is a URL. + if (!desired_tld.empty()) + return REQUESTED_URL; + + // No scheme, username, password, port, path, and no known TLD on the host. + // This could be: // * A single word "foo"; possibly an intranet site, but more likely a search. // This is ideally an UNKNOWN, and we can let the Alternate Nav URL code // catch our mistakes. @@ -403,11 +394,10 @@ AutocompleteInput::Type AutocompleteInput::Parse( // distinguish this case from: // * A "URL-like" string that's not really a URL (like // "browser.tabs.closeButtons" or "java.awt.event.*"). This is ideally a - // QUERY. Since the above case and this one are indistinguishable, and this - // case is likely to be much more common, just say these are both UNKNOWN, - // which should default to the right thing and let users correct us on a - // case-by-case basis. - return desired_tld.empty() ? UNKNOWN : REQUESTED_URL; + // QUERY. Since this is indistinguishable from the case above, and this + // case is much more likely, claim these are UNKNOWN, which should default + // to the right thing and let users correct us on a case-by-case basis. + return UNKNOWN; } // static @@ -431,7 +421,8 @@ void AutocompleteInput::ParseForEmphasizeComponents( // Obtain the URL prefixed by view-source and parse it. string16 real_url(text.substr(after_scheme_and_colon)); url_parse::Parsed real_parts; - AutocompleteInput::Parse(real_url, desired_tld, &real_parts, NULL, NULL); + AutocompleteInput::Parse(real_url, desired_tld, &real_parts, NULL, + NULL); if (real_parts.scheme.is_nonempty() || real_parts.host.is_nonempty()) { if (real_parts.scheme.is_nonempty()) { *scheme = url_parse::Component( diff --git a/chrome/browser/autocomplete/autocomplete_edit_unittest.cc b/chrome/browser/autocomplete/autocomplete_edit_unittest.cc index eed5a9f..8b26855 100644 --- a/chrome/browser/autocomplete/autocomplete_edit_unittest.cc +++ b/chrome/browser/autocomplete/autocomplete_edit_unittest.cc @@ -108,32 +108,32 @@ TEST(AutocompleteEditTest, AdjustTextForCopy) { const char* expected_url; } input[] = { // Test that http:// is inserted if all text is selected. - { "a.b/c", 0, true, "a.b/c", "http://a.b/c", true, "http://a.b/c" }, + { "a.de/b", 0, true, "a.de/b", "http://a.de/b", true, "http://a.de/b" }, // Test that http:// is inserted if the host is selected. - { "a.b/c", 0, false, "a.b/", "http://a.b/", true, "http://a.b/" }, + { "a.de/b", 0, false, "a.de/", "http://a.de/", true, "http://a.de/" }, // Tests that http:// is inserted if the path is modified. - { "a.b/c", 0, false, "a.b/d", "http://a.b/d", true, "http://a.b/d" }, + { "a.de/b", 0, false, "a.de/c", "http://a.de/c", true, "http://a.de/c" }, // Tests that http:// isn't inserted if the host is modified. - { "a.b/c", 0, false, "a.c/", "a.c/", false, "" }, + { "a.de/b", 0, false, "a.com/b", "a.com/b", false, "" }, // Tests that http:// isn't inserted if the start of the selection is 1. - { "a.b/c", 1, false, "a.b/", "a.b/", false, "" }, + { "a.de/b", 1, false, "a.de/b", "a.de/b", false, "" }, // Tests that http:// isn't inserted if a portion of the host is selected. - { "a.com/", 0, false, "a.co", "a.co", false, "" }, + { "a.de/", 0, false, "a.d", "a.d", false, "" }, // Tests that http:// isn't inserted for an https url after the user nukes // https. { "https://a.com/", 0, false, "a.com/", "a.com/", false, "" }, // Tests that http:// isn't inserted if the user adds to the host. - { "a.b/", 0, false, "a.bc/", "a.bc/", false, "" }, + { "a.de/", 0, false, "a.de.com/", "a.de.com/", false, "" }, // Tests that we don't get double http if the user manually inserts http. - { "a.b/", 0, false, "http://a.b/", "http://a.b/", true, "http://a.b/" }, + { "a.de/", 0, false, "http://a.de/", "http://a.de/", true, "http://a.de/" }, }; ScopedTestingBrowserProcess browser_process; TestingOmniboxView view; diff --git a/chrome/browser/autocomplete/autocomplete_unittest.cc b/chrome/browser/autocomplete/autocomplete_unittest.cc index e464fb9..cf3dec1 100644 --- a/chrome/browser/autocomplete/autocomplete_unittest.cc +++ b/chrome/browser/autocomplete/autocomplete_unittest.cc @@ -286,12 +286,13 @@ TEST_F(AutocompleteTest, InputType) { { ASCIIToUTF16("?foo bar"), AutocompleteInput::FORCED_QUERY }, { ASCIIToUTF16("?http://foo.com/bar"), AutocompleteInput::FORCED_QUERY }, { ASCIIToUTF16("foo"), AutocompleteInput::UNKNOWN }, + { ASCIIToUTF16("localhost"), AutocompleteInput::URL }, { ASCIIToUTF16("foo.c"), AutocompleteInput::UNKNOWN }, { ASCIIToUTF16("foo.com"), AutocompleteInput::URL }, { ASCIIToUTF16("-foo.com"), AutocompleteInput::URL }, { ASCIIToUTF16("foo-.com"), AutocompleteInput::UNKNOWN }, { ASCIIToUTF16("foo.-com"), AutocompleteInput::QUERY }, - { ASCIIToUTF16("foo/bar"), AutocompleteInput::URL }, + { ASCIIToUTF16("foo/bar"), AutocompleteInput::UNKNOWN }, { ASCIIToUTF16("foo;bar"), AutocompleteInput::QUERY }, { ASCIIToUTF16("foo/bar baz"), AutocompleteInput::UNKNOWN }, { ASCIIToUTF16("foo bar.com"), AutocompleteInput::QUERY }, @@ -300,13 +301,16 @@ TEST_F(AutocompleteTest, InputType) { { ASCIIToUTF16("foo+bar.com"), AutocompleteInput::UNKNOWN }, { ASCIIToUTF16("\"foo:bar\""), AutocompleteInput::QUERY }, { ASCIIToUTF16("link:foo.com"), AutocompleteInput::UNKNOWN }, - { ASCIIToUTF16("foo:81"), AutocompleteInput::URL }, - { ASCIIToUTF16("www.foo.com:81"), AutocompleteInput::URL }, + { ASCIIToUTF16("foo:81"), AutocompleteInput::UNKNOWN }, { ASCIIToUTF16("localhost:8080"), AutocompleteInput::URL }, + { ASCIIToUTF16("www.foo.com:81"), AutocompleteInput::URL }, { ASCIIToUTF16("foo.com:123456"), AutocompleteInput::QUERY }, { ASCIIToUTF16("foo.com:abc"), AutocompleteInput::QUERY }, { ASCIIToUTF16("1.2.3.4:abc"), AutocompleteInput::QUERY }, { ASCIIToUTF16("user@foo.com"), AutocompleteInput::UNKNOWN }, + { ASCIIToUTF16("user@foo/z"), AutocompleteInput::UNKNOWN }, + { ASCIIToUTF16("user@foo/z z"), AutocompleteInput::UNKNOWN }, + { ASCIIToUTF16("user@foo.com/z"), AutocompleteInput::URL }, { ASCIIToUTF16("user:pass@"), AutocompleteInput::UNKNOWN }, { ASCIIToUTF16("user:pass@!foo.com"), AutocompleteInput::UNKNOWN }, { ASCIIToUTF16("user:pass@foo"), AutocompleteInput::URL }, @@ -318,8 +322,8 @@ TEST_F(AutocompleteTest, InputType) { { ASCIIToUTF16("1.2/45"), AutocompleteInput::UNKNOWN }, { ASCIIToUTF16("1.2:45"), AutocompleteInput::UNKNOWN }, { ASCIIToUTF16("user@1.2:45"), AutocompleteInput::UNKNOWN }, + { ASCIIToUTF16("user@foo:45"), AutocompleteInput::UNKNOWN }, { ASCIIToUTF16("user:pass@1.2:45"), AutocompleteInput::URL }, - { ASCIIToUTF16("ps/2 games"), AutocompleteInput::UNKNOWN }, { ASCIIToUTF16("en.wikipedia.org/wiki/James Bond"), AutocompleteInput::URL }, // In Chrome itself, mailto: will get handled by ShellExecute, but in @@ -353,7 +357,6 @@ TEST_F(AutocompleteTest, InputType) { { ASCIIToUTF16("http://1.2"), AutocompleteInput::URL }, { ASCIIToUTF16("http://1.2/45"), AutocompleteInput::URL }, { ASCIIToUTF16("http:ps/2 games"), AutocompleteInput::URL }, - { ASCIIToUTF16("http://ps/2 games"), AutocompleteInput::URL }, { ASCIIToUTF16("https://foo.com"), AutocompleteInput::URL }, { ASCIIToUTF16("127.0.0.1"), AutocompleteInput::URL }, { ASCIIToUTF16("127.0.1"), AutocompleteInput::UNKNOWN }, @@ -383,6 +386,7 @@ TEST_F(AutocompleteTest, InputTypeWithDesiredTLD) { } input_cases[] = { { ASCIIToUTF16("401k"), AutocompleteInput::REQUESTED_URL }, { ASCIIToUTF16("999999999999999"), AutocompleteInput::REQUESTED_URL }, + { ASCIIToUTF16("x@y/z z"), AutocompleteInput::REQUESTED_URL }, }; for (size_t i = 0; i < ARRAYSIZE_UNSAFE(input_cases); ++i) { diff --git a/chrome/browser/autocomplete/history_url_provider.cc b/chrome/browser/autocomplete/history_url_provider.cc index cadf499..c7cf7f7 100644 --- a/chrome/browser/autocomplete/history_url_provider.cc +++ b/chrome/browser/autocomplete/history_url_provider.cc @@ -25,6 +25,7 @@ #include "googleurl/src/url_parse.h" #include "googleurl/src/url_util.h" #include "net/base/net_util.h" +#include "net/base/registry_controlled_domain.h" namespace { @@ -242,7 +243,7 @@ float CalculateConfidence(const history::HistoryMatch& match, return (0.5f * typed_score) + (0.3f * visit_score) + (0.2f * innermost_score); } -} // namespace history +} // namespace HistoryURLProviderParams::HistoryURLProviderParams( const AutocompleteInput& input, @@ -662,33 +663,37 @@ bool HistoryURLProvider::FixupExactSuggestion( !input.parts().path.is_nonempty()) return false; - // Tricky corner case: The user has visited intranet site "foo", but not - // internet site "www.foo.com". He types in foo (getting an exact match), - // then tries to hit ctrl-enter. When pressing ctrl, the what-you-typed - // match ("www.foo.com") doesn't show up in history, and thus doesn't get a - // promoted relevance, but a different match from the input ("foo") does, and - // gets promoted for inline autocomplete. Thus instead of getting - // "www.foo.com", the user still gets "foo" (and, before hitting enter, - // probably gets an odd-looking inline autocomplete of "/"). - // - // We detect this crazy case as follows: - // * If the what-you-typed match is not in the history DB, - // * and the user has specified a TLD, - // * and the input _without_ the TLD _is_ in the history DB, - // * ...then just before pressing "ctrl" the best match we supplied was the - // what-you-typed match, so stick with it by promoting this. history::URLRow info; MatchType type = INLINE_AUTOCOMPLETE; if (!db->GetRowForURL(match->destination_url, &info)) { - if (input.desired_tld().empty()) - return false; - GURL destination_url(URLFixerUpper::FixupURL(UTF16ToUTF8(input.text()), - std::string())); - if (!db->GetRowForURL(destination_url, NULL)) - return false; - - // If we got here, then we hit the tricky corner case. Make sure that - // |info| corresponds to the right URL. + if (CanFindIntranetURL(db, input)) { + // The user typed an intranet hostname that they've visited (albeit with a + // different port and/or path) before. Continuing ensures this input will + // be treated as a navigation. + } else { + // Tricky corner case: The user has visited intranet site "foo", but not + // internet site "www.foo.com". He types in foo (getting an exact match), + // then tries to hit ctrl-enter. When pressing ctrl, the what-you-typed + // match ("www.foo.com") doesn't show up in history, and thus doesn't get + // a promoted relevance, but a different match from the input ("foo") + // does, and gets promoted for inline autocomplete. Thus instead of + // getting "www.foo.com", the user still gets "foo" (and, before hitting + // enter, probably gets an odd-looking inline autocomplete of "/"). + // + // We detect this crazy case as follows: + // * If the what-you-typed match is not in the history DB, + // * and the user has specified a TLD, + // * and the input _without_ the TLD _is_ in the history DB, + // * ...then just before pressing "ctrl" the best match we supplied was + // the what-you-typed match, so stick with it by promoting this. + if (input.desired_tld().empty()) + return false; + GURL destination_url(URLFixerUpper::FixupURL(UTF16ToUTF8(input.text()), + std::string())); + if (!db->GetRowForURL(destination_url, NULL)) + return false; + // If we got here, then we hit the tricky corner case. + } info = history::URLRow(match->destination_url); } else { // We have data for this match, use it. @@ -717,6 +722,31 @@ bool HistoryURLProvider::FixupExactSuggestion( return true; } +bool HistoryURLProvider::CanFindIntranetURL( + history::URLDatabase* db, + const AutocompleteInput& input) const { + if ((input.type() != AutocompleteInput::UNKNOWN) || + !LowerCaseEqualsASCII(input.scheme(), chrome::kHttpScheme)) + return false; + DCHECK(input.parts().host.is_nonempty()); + const string16 host(input.text().substr(input.parts().host.begin, + input.parts().host.len)); + if (net::RegistryControlledDomainService::GetRegistryLength( + UTF16ToUTF8(host), false) != 0) + return false; + std::vector<history::URLRow> dummy; + for (history::Prefixes::const_iterator i(prefixes_.begin()); + i != prefixes_.end(); ++i) { + if ((i->num_components == 1) && + (db->AutocompleteForPrefix(i->prefix + host + ASCIIToUTF16("/"), 1, + true, &dummy) || + db->AutocompleteForPrefix(i->prefix + host + ASCIIToUTF16(":"), 1, + true, &dummy))) + return true; + } + return false; +} + bool HistoryURLProvider::PromoteMatchForInlineAutocomplete( HistoryURLProviderParams* params, const history::HistoryMatch& match, @@ -782,7 +812,7 @@ void HistoryURLProvider::CullPoorMatches( history::HistoryMatches* matches) const { const base::Time& threshold(history::AutocompleteAgeThreshold()); for (history::HistoryMatches::iterator i(matches->begin()); - i != matches->end();) { + i != matches->end(); ) { if (RowQualifiesAsSignificant(i->url_info, threshold)) ++i; else diff --git a/chrome/browser/autocomplete/history_url_provider.h b/chrome/browser/autocomplete/history_url_provider.h index e928fbf..78925b1 100644 --- a/chrome/browser/autocomplete/history_url_provider.h +++ b/chrome/browser/autocomplete/history_url_provider.h @@ -215,6 +215,12 @@ class HistoryURLProvider : public HistoryProvider { AutocompleteMatch* match, history::HistoryMatches* matches) const; + // Helper function for FixupExactSuggestion, this returns true if the input + // corresponds to some intranet URL where the user has previously visited the + // host in question. In this case the input should be treated as a URL. + bool CanFindIntranetURL(history::URLDatabase* db, + const AutocompleteInput& input) const; + // Determines if |match| is suitable for inline autocomplete, and promotes it // if so. bool PromoteMatchForInlineAutocomplete( diff --git a/chrome/browser/autocomplete/history_url_provider_unittest.cc b/chrome/browser/autocomplete/history_url_provider_unittest.cc index e0d29bc..0363418 100644 --- a/chrome/browser/autocomplete/history_url_provider_unittest.cc +++ b/chrome/browser/autocomplete/history_url_provider_unittest.cc @@ -10,6 +10,7 @@ #include "chrome/browser/autocomplete/autocomplete_match.h" #include "chrome/browser/autocomplete/history_url_provider.h" #include "chrome/browser/history/history.h" +#include "chrome/browser/net/url_fixer_upper.h" #include "chrome/test/base/testing_browser_process.h" #include "chrome/test/base/testing_browser_process_test.h" #include "chrome/test/base/testing_profile.h" @@ -20,8 +21,8 @@ using base::Time; using base::TimeDelta; struct TestURLInfo { - std::string url; - std::string title; + const char* url; + const char* title; int visit_count; int typed_count; } test_db[] = { @@ -312,21 +313,18 @@ TEST_F(HistoryURLProviderTest, CullRedirects) { // (the redirect set below will also increment the visit counts). We want // the results to be in A,B,C order. Note also that our visit counts are // all high enough so that domain synthesizing won't get triggered. - struct RedirectCase { + struct TestCase { const char* url; int count; - }; - static const RedirectCase redirect[] = { + } test_cases[] = { {"http://redirects/A", 30}, {"http://redirects/B", 20}, {"http://redirects/C", 10} }; - for (size_t i = 0; i < ARRAYSIZE_UNSAFE(redirect); i++) { - history_service_->AddPageWithDetails(GURL(redirect[i].url), - UTF8ToUTF16("Title"), - redirect[i].count, redirect[i].count, - Time::Now(), false, - history::SOURCE_BROWSED); + for (size_t i = 0; i < ARRAYSIZE_UNSAFE(test_cases); i++) { + history_service_->AddPageWithDetails(GURL(test_cases[i].url), + UTF8ToUTF16("Title"), test_cases[i].count, test_cases[i].count, + Time::Now(), false, history::SOURCE_BROWSED); } // Create a B->C->A redirect chain, but set the visit counts such that they @@ -334,12 +332,11 @@ TEST_F(HistoryURLProviderTest, CullRedirects) { // search for the most recent visit when looking for redirects, so this will // be found even though the previous visits had no redirects. history::RedirectList redirects_to_a; - redirects_to_a.push_back(GURL(redirect[1].url)); - redirects_to_a.push_back(GURL(redirect[2].url)); - redirects_to_a.push_back(GURL(redirect[0].url)); - history_service_->AddPage(GURL(redirect[0].url), NULL, 0, GURL(), - PageTransition::TYPED, redirects_to_a, - history::SOURCE_BROWSED, true); + redirects_to_a.push_back(GURL(test_cases[1].url)); + redirects_to_a.push_back(GURL(test_cases[2].url)); + redirects_to_a.push_back(GURL(test_cases[0].url)); + history_service_->AddPage(GURL(test_cases[0].url), NULL, 0, GURL(), + PageTransition::TYPED, redirects_to_a, history::SOURCE_BROWSED, true); // Because all the results are part of a redirect chain with other results, // all but the first one (A) should be culled. We should get the default @@ -347,7 +344,8 @@ TEST_F(HistoryURLProviderTest, CullRedirects) { const string16 typing(ASCIIToUTF16("http://redirects/")); const std::string expected_results[] = { UTF16ToUTF8(typing), - redirect[0].url}; + test_cases[0].url, + }; RunTest(typing, string16(), true, expected_results, arraysize(expected_results)); } @@ -511,3 +509,27 @@ TEST_F(HistoryURLProviderTest, TreatEmailsAsSearches) { // Visiting foo.com should not make this string be treated as a navigation. RunTest(ASCIIToUTF16("user@foo.com"), string16(), false, NULL, 0); } + +TEST_F(HistoryURLProviderTest, IntranetURLsWithPaths) { + struct TestCase { + const char* input; + bool has_output; + } test_cases[] = { + { "fooey", false }, + { "fooey/", true }, + { "fooey/a", false }, + { "fooey/a b", false }, + { "gooey", true }, + { "gooey/", true }, + { "gooey/a", true }, + { "gooey/a b", true }, + }; + for (size_t i = 0; i < ARRAYSIZE_UNSAFE(test_cases); ++i) { + const std::string output[1] = { + URLFixerUpper::FixupURL(test_cases[i].input, std::string()).spec() + }; + RunTest(ASCIIToUTF16(test_cases[i].input), string16(), false, + test_cases[i].has_output ? output : NULL, + test_cases[i].has_output ? 1 : 0); + } +} diff --git a/chrome/browser/history/url_database.cc b/chrome/browser/history/url_database.cc index 4b31c10..5ef2a5e 100644 --- a/chrome/browser/history/url_database.cc +++ b/chrome/browser/history/url_database.cc @@ -291,7 +291,7 @@ bool URLDatabase::InitIconMappingEnumeratorForEverything( return true; } -void URLDatabase::AutocompleteForPrefix(const string16& prefix, +bool URLDatabase::AutocompleteForPrefix(const string16& prefix, size_t max_results, bool typed_only, std::vector<history::URLRow>* results) { @@ -317,7 +317,7 @@ void URLDatabase::AutocompleteForPrefix(const string16& prefix, sql::Statement statement( GetDB().GetCachedStatement(sql::StatementID(__FILE__, line), sql)); if (!statement) - return; + return false; // We will find all strings between "prefix" and this string, which is prefix // followed by the maximum character size. Use 8-bit strings for everything @@ -337,6 +337,7 @@ void URLDatabase::AutocompleteForPrefix(const string16& prefix, if (info.url().is_valid()) results->push_back(info); } + return !results->empty(); } bool URLDatabase::FindShortestURLFromBase(const std::string& base, diff --git a/chrome/browser/history/url_database.h b/chrome/browser/history/url_database.h index b6be207..08c43d8 100644 --- a/chrome/browser/history/url_database.h +++ b/chrome/browser/history/url_database.h @@ -164,11 +164,12 @@ class URLDatabase { // Autocomplete -------------------------------------------------------------- - // Fills the given array with URLs matching the given prefix. They will be + // Fills the given array with URLs matching the given prefix. They will be // sorted by typed count, then by visit count, then by visit date (most recent // first) up to the given maximum number. If |typed_only| is true, only urls - // that have been typed once are returned. Called by HistoryURLProvider. - void AutocompleteForPrefix(const string16& prefix, + // that have been typed once are returned. For caller convenience, returns + // whether any results were found. Called by HistoryURLProvider. + bool AutocompleteForPrefix(const string16& prefix, size_t max_results, bool typed_only, std::vector<URLRow>* results); |