Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 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 | 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 "components/omnibox/autocomplete_match.h" | 5 #include "components/omnibox/autocomplete_match.h" |
| 6 | 6 |
| 7 #include "base/command_line.h" | 7 #include "base/command_line.h" |
| 8 #include "base/i18n/time_formatting.h" | 8 #include "base/i18n/time_formatting.h" |
| 9 #include "base/logging.h" | 9 #include "base/logging.h" |
| 10 #include "base/strings/string16.h" | 10 #include "base/strings/string16.h" |
| 11 #include "base/strings/string_number_conversions.h" | 11 #include "base/strings/string_number_conversions.h" |
| 12 #include "base/strings/string_piece.h" | 12 #include "base/strings/string_piece.h" |
| 13 #include "base/strings/string_util.h" | 13 #include "base/strings/string_util.h" |
| 14 #include "base/strings/utf_string_conversions.h" | 14 #include "base/strings/utf_string_conversions.h" |
| 15 #include "base/time/time.h" | 15 #include "base/time/time.h" |
| 16 #include "components/omnibox/autocomplete_provider.h" | 16 #include "components/omnibox/autocomplete_provider.h" |
| 17 #include "components/omnibox/omnibox_switches.h" | 17 #include "components/omnibox/omnibox_switches.h" |
| 18 #include "components/omnibox/suggestion_answer.h" | 18 #include "components/omnibox/suggestion_answer.h" |
| 19 #include "components/search_engines/template_url.h" | 19 #include "components/search_engines/template_url.h" |
| 20 #include "components/search_engines/template_url_service.h" | 20 #include "components/search_engines/template_url_service.h" |
| 21 #include "grit/components_scaled_resources.h" | 21 #include "grit/components_scaled_resources.h" |
| 22 #include "net/base/net_util.h" | |
| 22 | 23 |
| 23 namespace { | 24 namespace { |
| 24 | 25 |
| 25 bool IsTrivialClassification(const ACMatchClassifications& classifications) { | 26 bool IsTrivialClassification(const ACMatchClassifications& classifications) { |
| 26 return classifications.empty() || | 27 return classifications.empty() || |
| 27 ((classifications.size() == 1) && | 28 ((classifications.size() == 1) && |
| 28 (classifications.back().style == ACMatchClassification::NONE)); | 29 (classifications.back().style == ACMatchClassification::NONE)); |
| 29 } | 30 } |
| 30 | 31 |
| 32 // Returns true if one of the |terms_prefixed_by_http_or_https| matches the | |
| 33 // beginning of the URL (sans scheme). (Recall that | |
| 34 // |terms_prefixed_by_http_or_https|, for the input "http://a b" will be | |
| 35 // ["a"].) This suggests that the user wants a particular URL with a scheme | |
| 36 // in mind, hence the caller should not consider another URL like this one | |
| 37 // but with a different scheme to be a duplicate. |languages| is used to | |
| 38 // format punycoded URLs to decide if they match. | |
| 39 bool WordMatchesURLContent( | |
| 40 const std::vector<std::pair<std::string, base::string16> >& | |
| 41 terms_prefixed_by_http_or_https, | |
| 42 const std::string& languages, | |
| 43 const GURL& url) { | |
| 44 size_t prefix_length = | |
| 45 url.scheme().length() + strlen(url::kStandardSchemeSeparator); | |
| 46 DCHECK_GE(url.spec().length(), prefix_length); | |
| 47 const std::string& url_spec_without_scheme = url.spec().substr(prefix_length); | |
| 48 // In addition to checking the URL spec, check the formatted URL in order to | |
| 49 // detect a prefix match against a punycode-encoded hostname. | |
|
Peter Kasting
2015/06/29 05:04:59
How come you check both? Shouldn't the check agai
Mark P
2015/06/30 04:23:17
I thought I had a reason at the time but I don't r
| |
| 50 const base::string16& formatted_url = net::FormatUrl( | |
| 51 url, languages, net::kFormatUrlOmitNothing, net::UnescapeRule::NORMAL, | |
| 52 NULL, NULL, &prefix_length); | |
| 53 base::string16 formatted_url_without_scheme; | |
| 54 if (prefix_length != base::string16::npos) | |
| 55 formatted_url_without_scheme = formatted_url.substr(prefix_length); | |
| 56 for (const auto& term_pair : terms_prefixed_by_http_or_https) { | |
| 57 // At the moment we do not support case-insensitive prefix matching | |
| 58 // for international (punycode) domain names. | |
| 59 if (base::StartsWith(url_spec_without_scheme, term_pair.first, | |
| 60 base::CompareCase::INSENSITIVE_ASCII) || | |
| 61 ((prefix_length != base::string16::npos) && | |
| 62 base::StartsWith(formatted_url_without_scheme, term_pair.second, | |
| 63 base::CompareCase::SENSITIVE))) | |
| 64 return true; | |
| 65 } | |
| 66 return false; | |
| 67 } | |
| 68 | |
| 31 } // namespace | 69 } // namespace |
| 32 | 70 |
| 33 // AutocompleteMatch ---------------------------------------------------------- | 71 // AutocompleteMatch ---------------------------------------------------------- |
| 34 | 72 |
| 35 // static | 73 // static |
| 36 const base::char16 AutocompleteMatch::kInvalidChars[] = { | 74 const base::char16 AutocompleteMatch::kInvalidChars[] = { |
| 37 '\n', '\r', '\t', | 75 '\n', '\r', '\t', |
| 38 0x2028, // Line separator | 76 0x2028, // Line separator |
| 39 0x2029, // Paragraph separator | 77 0x2029, // Paragraph separator |
| 40 0 | 78 0 |
| (...skipping 324 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 365 return NULL; | 403 return NULL; |
| 366 TemplateURL* template_url = keyword.empty() ? | 404 TemplateURL* template_url = keyword.empty() ? |
| 367 NULL : template_url_service->GetTemplateURLForKeyword(keyword); | 405 NULL : template_url_service->GetTemplateURLForKeyword(keyword); |
| 368 return (template_url || host.empty()) ? | 406 return (template_url || host.empty()) ? |
| 369 template_url : template_url_service->GetTemplateURLForHost(host); | 407 template_url : template_url_service->GetTemplateURLForHost(host); |
| 370 } | 408 } |
| 371 | 409 |
| 372 // static | 410 // static |
| 373 GURL AutocompleteMatch::GURLToStrippedGURL( | 411 GURL AutocompleteMatch::GURLToStrippedGURL( |
| 374 const GURL& url, | 412 const GURL& url, |
| 413 const AutocompleteInput& input, | |
| 414 const std::string& languages, | |
| 375 TemplateURLService* template_url_service, | 415 TemplateURLService* template_url_service, |
| 376 const base::string16& keyword) { | 416 const base::string16& keyword) { |
| 377 if (!url.is_valid()) | 417 if (!url.is_valid()) |
| 378 return url; | 418 return url; |
| 379 | 419 |
| 380 GURL stripped_destination_url = url; | 420 GURL stripped_destination_url = url; |
| 381 | 421 |
| 382 // If the destination URL looks like it was generated from a TemplateURL, | 422 // If the destination URL looks like it was generated from a TemplateURL, |
| 383 // remove all substitutions other than the search terms. This allows us | 423 // remove all substitutions other than the search terms. This allows us |
| 384 // to eliminate cases like past search URLs from history that differ only | 424 // to eliminate cases like past search URLs from history that differ only |
| (...skipping 25 matching lines...) Expand all Loading... | |
| 410 | 450 |
| 411 // Remove the www. prefix from the host. | 451 // Remove the www. prefix from the host. |
| 412 static const char prefix[] = "www."; | 452 static const char prefix[] = "www."; |
| 413 static const size_t prefix_len = arraysize(prefix) - 1; | 453 static const size_t prefix_len = arraysize(prefix) - 1; |
| 414 std::string host = stripped_destination_url.host(); | 454 std::string host = stripped_destination_url.host(); |
| 415 if (host.compare(0, prefix_len, prefix) == 0) { | 455 if (host.compare(0, prefix_len, prefix) == 0) { |
| 416 replacements.SetHostStr(base::StringPiece(host).substr(prefix_len)); | 456 replacements.SetHostStr(base::StringPiece(host).substr(prefix_len)); |
| 417 needs_replacement = true; | 457 needs_replacement = true; |
| 418 } | 458 } |
| 419 | 459 |
| 420 // Replace https protocol with http protocol. | 460 // Remove any trailing slash (if it's not a lone slash), or add a slash (to |
| 421 if (stripped_destination_url.SchemeIs(url::kHttpsScheme)) { | 461 // make a lone slash) if the path is empty. (We can't unconditionally |
| 462 // remove even lone slashes because for some schemes the path must consist | |
| 463 // of at least a slash.) | |
| 464 const std::string& path = stripped_destination_url.path(); | |
| 465 if ((path.length() > 1) && (path[path.length() - 1] == '/')) { | |
| 466 replacements.SetPathStr( | |
| 467 base::StringPiece(path).substr(0, path.length() - 1)); | |
| 468 needs_replacement = true; | |
| 469 } else if (path.empty()) { | |
| 470 static const char slash[] = "/"; | |
| 471 replacements.SetPathStr(base::StringPiece(slash)); | |
| 472 needs_replacement = true; | |
| 473 } | |
| 474 | |
| 475 // Replace https protocol with http, as long as the user didn't explicitly | |
| 476 // specify one of the two. | |
| 477 if (stripped_destination_url.SchemeIs(url::kHttpsScheme) && | |
| 478 (input.terms_prefixed_by_http_or_https().empty() || | |
| 479 !WordMatchesURLContent( | |
| 480 input.terms_prefixed_by_http_or_https(), languages, url))) { | |
| 422 replacements.SetScheme(url::kHttpScheme, | 481 replacements.SetScheme(url::kHttpScheme, |
| 423 url::Component(0, strlen(url::kHttpScheme))); | 482 url::Component(0, strlen(url::kHttpScheme))); |
| 424 needs_replacement = true; | 483 needs_replacement = true; |
| 425 } | 484 } |
| 426 | 485 |
| 427 if (needs_replacement) | 486 if (needs_replacement) |
| 428 stripped_destination_url = stripped_destination_url.ReplaceComponents( | 487 stripped_destination_url = stripped_destination_url.ReplaceComponents( |
| 429 replacements); | 488 replacements); |
| 430 return stripped_destination_url; | 489 return stripped_destination_url; |
| 431 } | 490 } |
| 432 | 491 |
| 433 void AutocompleteMatch::ComputeStrippedDestinationURL( | 492 void AutocompleteMatch::ComputeStrippedDestinationURL( |
| 493 const AutocompleteInput& input, | |
| 494 const std::string& languages, | |
| 434 TemplateURLService* template_url_service) { | 495 TemplateURLService* template_url_service) { |
| 435 stripped_destination_url = | 496 stripped_destination_url = GURLToStrippedGURL( |
| 436 GURLToStrippedGURL(destination_url, template_url_service, keyword); | 497 destination_url, input, languages, template_url_service, keyword); |
| 437 } | 498 } |
| 438 | 499 |
| 439 void AutocompleteMatch::EnsureUWYTIsAllowedToBeDefault( | 500 void AutocompleteMatch::EnsureUWYTIsAllowedToBeDefault( |
| 440 const GURL& canonical_input_url, | 501 const AutocompleteInput& input, |
| 502 const std::string& languages, | |
| 441 TemplateURLService* template_url_service) { | 503 TemplateURLService* template_url_service) { |
| 442 if (!allowed_to_be_default_match) { | 504 if (!allowed_to_be_default_match) { |
| 443 const GURL& stripped_canonical_input_url = | 505 const GURL& stripped_canonical_input_url = |
| 444 AutocompleteMatch::GURLToStrippedGURL( | 506 AutocompleteMatch::GURLToStrippedGURL( |
| 445 canonical_input_url, template_url_service, base::string16()); | 507 input.canonicalized_url(), input, languages, template_url_service, |
| 446 ComputeStrippedDestinationURL(template_url_service); | 508 base::string16()); |
| 509 ComputeStrippedDestinationURL(input, languages, template_url_service); | |
| 447 allowed_to_be_default_match = | 510 allowed_to_be_default_match = |
| 448 stripped_canonical_input_url == stripped_destination_url; | 511 stripped_canonical_input_url == stripped_destination_url; |
| 449 } | 512 } |
| 450 } | 513 } |
| 451 | 514 |
| 452 void AutocompleteMatch::GetKeywordUIState( | 515 void AutocompleteMatch::GetKeywordUIState( |
| 453 TemplateURLService* template_url_service, | 516 TemplateURLService* template_url_service, |
| 454 base::string16* keyword, | 517 base::string16* keyword, |
| 455 bool* is_keyword_hint) const { | 518 bool* is_keyword_hint) const { |
| 456 *is_keyword_hint = associated_keyword.get() != NULL; | 519 *is_keyword_hint = associated_keyword.get() != NULL; |
| (...skipping 114 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 571 << " is unsorted in relation to last offset of " << last_offset | 634 << " is unsorted in relation to last offset of " << last_offset |
| 572 << ". Provider: " << provider_name << "."; | 635 << ". Provider: " << provider_name << "."; |
| 573 DCHECK_LT(i->offset, text.length()) | 636 DCHECK_LT(i->offset, text.length()) |
| 574 << " Classification of [" << i->offset << "," << text.length() | 637 << " Classification of [" << i->offset << "," << text.length() |
| 575 << "] is out of bounds for \"" << text << "\". Provider: " | 638 << "] is out of bounds for \"" << text << "\". Provider: " |
| 576 << provider_name << "."; | 639 << provider_name << "."; |
| 577 last_offset = i->offset; | 640 last_offset = i->offset; |
| 578 } | 641 } |
| 579 } | 642 } |
| 580 #endif | 643 #endif |
| OLD | NEW |