history_provider.cc revision 868fa2fe829687343ffae624259930155e16dbd8
15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file. 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/autocomplete/history_provider.h" 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <string> 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/string_util.h" 10868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/utf_string_conversions.h" 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/autocomplete/autocomplete_input.h" 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/autocomplete/autocomplete_match.h" 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/autocomplete/autocomplete_provider_listener.h" 142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/history/history_service.h" 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/history/history_service_factory.h" 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/net/url_fixer_upper.h" 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/profiles/profile.h" 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/url_constants.h" 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "googleurl/src/url_util.h" 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)HistoryProvider::HistoryProvider(AutocompleteProviderListener* listener, 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Profile* profile, 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AutocompleteProvider::Type type) 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) : AutocompleteProvider(listener, profile, type), 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) always_prevent_inline_autocomplete_(false) { 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryProvider::DeleteMatch(const AutocompleteMatch& match) { 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(done_); 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(profile_); 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(match.deletable); 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) HistoryService* const history_service = 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) HistoryServiceFactory::GetForProfile(profile_, Profile::EXPLICIT_ACCESS); 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Delete the match from the history DB. 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(history_service); 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(match.destination_url.is_valid()); 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) history_service->DeleteURL(match.destination_url); 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DeleteMatchFromMatches(match); 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)HistoryProvider::~HistoryProvider() {} 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistoryProvider::DeleteMatchFromMatches(const AutocompleteMatch& match) { 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool found = false; 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (ACMatches::iterator i(matches_.begin()); i != matches_.end(); ++i) { 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (i->destination_url == match.destination_url && i->type == match.type) { 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) found = true; 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (i->is_history_what_you_typed_match || i->starred) { 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We can't get rid of What-You-Typed or Bookmarked matches, 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // but we can make them look like they have no backing data. 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) i->deletable = false; 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) i->description.clear(); 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) i->description_class.clear(); 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) matches_.erase(i); 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(found) << "Asked to delete a URL that isn't in our set of matches"; 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) listener_->OnProviderUpdate(true); 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool HistoryProvider::FixupUserInput(AutocompleteInput* input) { 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const string16& input_text = input->text(); 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Fixup and canonicalize user input. 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const GURL canonical_gurl(URLFixerUpper::FixupURL(UTF16ToUTF8(input_text), 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string())); 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string canonical_gurl_str(canonical_gurl.possibly_invalid_spec()); 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (canonical_gurl_str.empty()) { 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // This probably won't happen, but there are no guarantees. 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If the user types a number, GURL will convert it to a dotted quad. 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // However, if the parser did not mark this as a URL, then the user probably 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // didn't intend this interpretation. Since this can break history matching 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // for hostname beginning with numbers (e.g. input of "17173" will be matched 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // against "0.0.67.21" instead of the original "17173", failing to find 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // "17173.com"), swap the original hostname in for the fixed-up one. 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if ((input->type() != AutocompleteInput::URL) && 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) canonical_gurl.HostIsIPAddress()) { 865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string original_hostname = 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) UTF16ToUTF8(input_text.substr(input->parts().host.begin, 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) input->parts().host.len)); 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const url_parse::Parsed& parts = 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) canonical_gurl.parsed_for_possibly_invalid_spec(); 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // parts.host must not be empty when HostIsIPAddress() is true. 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(parts.host.is_nonempty()); 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) canonical_gurl_str.replace(parts.host.begin, parts.host.len, 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) original_hostname); 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) string16 output = UTF8ToUTF16(canonical_gurl_str); 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Don't prepend a scheme when the user didn't have one. Since the fixer 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // upper only prepends the "http" scheme, that's all we need to check for. 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (canonical_gurl.SchemeIs(chrome::kHttpScheme) && 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) !url_util::FindAndCompareScheme(UTF16ToUTF8(input_text), 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) chrome::kHttpScheme, NULL)) 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TrimHttpPrefix(&output); 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Make the number of trailing slashes on the output exactly match the input. 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Examples of why not doing this would matter: 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // * The user types "a" and has this fixed up to "a/". Now no other sites 1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // beginning with "a" will match. 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // * The user types "file:" and has this fixed up to "file://". Now inline 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // autocomplete will append too few slashes, resulting in e.g. "file:/b..." 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // instead of "file:///b..." 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // * The user types "http:/" and has this fixed up to "http:". Now inline 1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // autocomplete will append too many slashes, resulting in e.g. 1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // "http:///c..." instead of "http://c...". 1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // NOTE: We do this after calling TrimHttpPrefix() since that can strip 1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // trailing slashes (if the scheme is the only thing in the input). It's not 1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // clear that the result of fixup really matters in this case, but there's no 1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // harm in making sure. 1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const size_t last_input_nonslash = 1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) input_text.find_last_not_of(ASCIIToUTF16("/\\")); 1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const size_t num_input_slashes = (last_input_nonslash == string16::npos) ? 1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) input_text.length() : (input_text.length() - 1 - last_input_nonslash); 1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const size_t last_output_nonslash = 1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) output.find_last_not_of(ASCIIToUTF16("/\\")); 1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const size_t num_output_slashes = 1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (last_output_nonslash == string16::npos) ? 1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) output.length() : (output.length() - 1 - last_output_nonslash); 1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (num_output_slashes < num_input_slashes) 1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) output.append(num_input_slashes - num_output_slashes, '/'); 1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else if (num_output_slashes > num_input_slashes) 1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) output.erase(output.length() - num_output_slashes + num_input_slashes); 1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) url_parse::Parsed parts; 1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) URLFixerUpper::SegmentURL(output, &parts); 1342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) input->UpdateText(output, string16::npos, parts); 1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return !output.empty(); 1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static 1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)size_t HistoryProvider::TrimHttpPrefix(string16* url) { 1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Find any "http:". 1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!HasHTTPScheme(*url)) 1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 0; 1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) size_t scheme_pos = 1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) url->find(ASCIIToUTF16(chrome::kHttpScheme) + char16(':')); 1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK_NE(string16::npos, scheme_pos); 1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Erase scheme plus up to two slashes. 1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) size_t prefix_end = scheme_pos + strlen(chrome::kHttpScheme) + 1; 1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const size_t after_slashes = std::min(url->length(), prefix_end + 2); 1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) while ((prefix_end < after_slashes) && ((*url)[prefix_end] == '/')) 1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ++prefix_end; 1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) url->erase(scheme_pos, prefix_end - scheme_pos); 1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return (scheme_pos == 0) ? prefix_end : 0; 1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static 1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool HistoryProvider::PreventInlineAutocomplete( 1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const AutocompleteInput& input) { 1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return input.prevent_inline_autocomplete() || 1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) always_prevent_inline_autocomplete_ || 1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (!input.text().empty() && 1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) IsWhitespace(input.text()[input.text().length() - 1])); 1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 164