1 // Copyright 2012 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 "chrome/browser/ui/toolbar/toolbar_model_impl.h" 6 7 #include "base/command_line.h" 8 #include "base/prefs/pref_service.h" 9 #include "base/strings/utf_string_conversions.h" 10 #include "chrome/browser/autocomplete/autocomplete_classifier.h" 11 #include "chrome/browser/autocomplete/autocomplete_classifier_factory.h" 12 #include "chrome/browser/autocomplete/autocomplete_input.h" 13 #include "chrome/browser/autocomplete/autocomplete_match.h" 14 #include "chrome/browser/google/google_util.h" 15 #include "chrome/browser/policy/profile_policy_connector.h" 16 #include "chrome/browser/policy/profile_policy_connector_factory.h" 17 #include "chrome/browser/profiles/profile.h" 18 #include "chrome/browser/search/search.h" 19 #include "chrome/browser/ssl/ssl_error_info.h" 20 #include "chrome/browser/ui/toolbar/toolbar_model_delegate.h" 21 #include "chrome/common/chrome_constants.h" 22 #include "chrome/common/chrome_switches.h" 23 #include "chrome/common/pref_names.h" 24 #include "chrome/common/url_constants.h" 25 #include "content/public/browser/cert_store.h" 26 #include "content/public/browser/navigation_controller.h" 27 #include "content/public/browser/navigation_entry.h" 28 #include "content/public/browser/web_contents.h" 29 #include "content/public/browser/web_ui.h" 30 #include "content/public/common/content_constants.h" 31 #include "content/public/common/ssl_status.h" 32 #include "grit/generated_resources.h" 33 #include "grit/theme_resources.h" 34 #include "net/base/net_util.h" 35 #include "net/cert/cert_status_flags.h" 36 #include "net/cert/x509_certificate.h" 37 #include "ui/base/l10n/l10n_util.h" 38 39 using content::NavigationController; 40 using content::NavigationEntry; 41 using content::SSLStatus; 42 using content::WebContents; 43 44 ToolbarModelImpl::ToolbarModelImpl(ToolbarModelDelegate* delegate) 45 : delegate_(delegate), 46 input_in_progress_(false) { 47 } 48 49 ToolbarModelImpl::~ToolbarModelImpl() { 50 } 51 52 ToolbarModel::SecurityLevel ToolbarModelImpl::GetSecurityLevelForWebContents( 53 content::WebContents* web_contents) { 54 if (!web_contents) 55 return NONE; 56 57 NavigationEntry* entry = web_contents->GetController().GetVisibleEntry(); 58 if (!entry) 59 return NONE; 60 61 const SSLStatus& ssl = entry->GetSSL(); 62 switch (ssl.security_style) { 63 case content::SECURITY_STYLE_UNKNOWN: 64 case content::SECURITY_STYLE_UNAUTHENTICATED: 65 return NONE; 66 67 case content::SECURITY_STYLE_AUTHENTICATION_BROKEN: 68 return SECURITY_ERROR; 69 70 case content::SECURITY_STYLE_AUTHENTICATED: 71 if (policy::ProfilePolicyConnectorFactory::GetForProfile( 72 Profile::FromBrowserContext(web_contents->GetBrowserContext()))-> 73 UsedPolicyCertificates()) 74 return SECURITY_POLICY_WARNING; 75 if (!!(ssl.content_status & SSLStatus::DISPLAYED_INSECURE_CONTENT)) 76 return SECURITY_WARNING; 77 if (net::IsCertStatusError(ssl.cert_status)) { 78 DCHECK(net::IsCertStatusMinorError(ssl.cert_status)); 79 return SECURITY_WARNING; 80 } 81 if ((ssl.cert_status & net::CERT_STATUS_IS_EV) && 82 content::CertStore::GetInstance()->RetrieveCert(ssl.cert_id, NULL)) 83 return EV_SECURE; 84 return SECURE; 85 86 default: 87 NOTREACHED(); 88 return NONE; 89 } 90 } 91 92 // ToolbarModelImpl Implementation. 93 string16 ToolbarModelImpl::GetText( 94 bool display_search_urls_as_search_terms) const { 95 if (display_search_urls_as_search_terms) { 96 string16 search_terms(GetSearchTerms(false)); 97 if (!search_terms.empty()) 98 return search_terms; 99 } 100 std::string languages; // Empty if we don't have a |navigation_controller|. 101 Profile* profile = GetProfile(); 102 if (profile) 103 languages = profile->GetPrefs()->GetString(prefs::kAcceptLanguages); 104 105 GURL url(GetURL()); 106 if (url.spec().length() > content::kMaxURLDisplayChars) 107 url = url.IsStandard() ? url.GetOrigin() : GURL(url.scheme() + ":"); 108 // Note that we can't unescape spaces here, because if the user copies this 109 // and pastes it into another program, that program may think the URL ends at 110 // the space. 111 return AutocompleteInput::FormattedStringWithEquivalentMeaning( 112 url, net::FormatUrl(url, languages, net::kFormatUrlOmitAll, 113 net::UnescapeRule::NORMAL, NULL, NULL, NULL)); 114 } 115 116 string16 ToolbarModelImpl::GetCorpusNameForMobile() const { 117 if (!WouldReplaceSearchURLWithSearchTerms(false)) 118 return string16(); 119 GURL url(GetURL()); 120 // If there is a query in the url fragment look for the corpus name there, 121 // otherwise look for the corpus name in the query parameters. 122 const std::string& query_str(google_util::HasGoogleSearchQueryParam( 123 url.ref()) ? url.ref() : url.query()); 124 url_parse::Component query(0, query_str.length()), key, value; 125 const char kChipKey[] = "sboxchip"; 126 while (url_parse::ExtractQueryKeyValue(query_str.c_str(), &query, &key, 127 &value)) { 128 if (key.is_nonempty() && query_str.substr(key.begin, key.len) == kChipKey) { 129 return net::UnescapeAndDecodeUTF8URLComponent( 130 query_str.substr(value.begin, value.len), 131 net::UnescapeRule::NORMAL, NULL); 132 } 133 } 134 return string16(); 135 } 136 137 GURL ToolbarModelImpl::GetURL() const { 138 const NavigationController* navigation_controller = GetNavigationController(); 139 if (navigation_controller) { 140 const NavigationEntry* entry = navigation_controller->GetVisibleEntry(); 141 if (entry) 142 return ShouldDisplayURL() ? entry->GetVirtualURL() : GURL(); 143 } 144 145 return GURL(content::kAboutBlankURL); 146 } 147 148 bool ToolbarModelImpl::WouldReplaceSearchURLWithSearchTerms( 149 bool ignore_editing) const { 150 return !GetSearchTerms(ignore_editing).empty(); 151 } 152 153 bool ToolbarModelImpl::ShouldDisplayURL() const { 154 // Note: The order here is important. 155 // - The WebUI test must come before the extension scheme test because there 156 // can be WebUIs that have extension schemes (e.g. the bookmark manager). In 157 // that case, we should prefer what the WebUI instance says. 158 // - The view-source test must come before the NTP test because of the case 159 // of view-source:chrome://newtab, which should display its URL despite what 160 // chrome://newtab says. 161 NavigationController* controller = GetNavigationController(); 162 NavigationEntry* entry = controller ? controller->GetVisibleEntry() : NULL; 163 if (entry) { 164 if (entry->IsViewSourceMode() || 165 entry->GetPageType() == content::PAGE_TYPE_INTERSTITIAL) { 166 return true; 167 } 168 169 GURL url = entry->GetURL(); 170 GURL virtual_url = entry->GetVirtualURL(); 171 if (url.SchemeIs(chrome::kChromeUIScheme) || 172 virtual_url.SchemeIs(chrome::kChromeUIScheme)) { 173 if (!url.SchemeIs(chrome::kChromeUIScheme)) 174 url = virtual_url; 175 return url.host() != chrome::kChromeUINewTabHost; 176 } 177 } 178 179 if (chrome::IsInstantNTP(delegate_->GetActiveWebContents())) 180 return false; 181 182 return true; 183 } 184 185 ToolbarModel::SecurityLevel 186 ToolbarModelImpl::GetSecurityLevel(bool ignore_editing) const { 187 if (!ignore_editing && input_in_progress_) { 188 // When editing, assume no security style. 189 return NONE; 190 } 191 return GetSecurityLevelForWebContents(delegate_->GetActiveWebContents()); 192 } 193 194 int ToolbarModelImpl::GetIcon() const { 195 if (WouldReplaceSearchURLWithSearchTerms(false)) 196 return IDR_OMNIBOX_SEARCH_SECURED; 197 198 static int icon_ids[NUM_SECURITY_LEVELS] = { 199 IDR_LOCATION_BAR_HTTP, 200 IDR_OMNIBOX_HTTPS_VALID, 201 IDR_OMNIBOX_HTTPS_VALID, 202 IDR_OMNIBOX_HTTPS_WARNING, 203 IDR_OMNIBOX_HTTPS_POLICY_WARNING, 204 IDR_OMNIBOX_HTTPS_INVALID, 205 }; 206 DCHECK(arraysize(icon_ids) == NUM_SECURITY_LEVELS); 207 return icon_ids[GetSecurityLevel(false)]; 208 } 209 210 string16 ToolbarModelImpl::GetEVCertName() const { 211 DCHECK_EQ(GetSecurityLevel(false), EV_SECURE); 212 scoped_refptr<net::X509Certificate> cert; 213 // Note: Navigation controller and active entry are guaranteed non-NULL or 214 // the security level would be NONE. 215 content::CertStore::GetInstance()->RetrieveCert( 216 GetNavigationController()->GetVisibleEntry()->GetSSL().cert_id, &cert); 217 return GetEVCertName(*cert.get()); 218 } 219 220 // static 221 string16 ToolbarModelImpl::GetEVCertName(const net::X509Certificate& cert) { 222 // EV are required to have an organization name and country. 223 if (cert.subject().organization_names.empty() || 224 cert.subject().country_name.empty()) { 225 NOTREACHED(); 226 return string16(); 227 } 228 229 return l10n_util::GetStringFUTF16( 230 IDS_SECURE_CONNECTION_EV, 231 UTF8ToUTF16(cert.subject().organization_names[0]), 232 UTF8ToUTF16(cert.subject().country_name)); 233 } 234 235 void ToolbarModelImpl::SetInputInProgress(bool value) { 236 input_in_progress_ = value; 237 } 238 239 bool ToolbarModelImpl::GetInputInProgress() const { 240 return input_in_progress_; 241 } 242 243 NavigationController* ToolbarModelImpl::GetNavigationController() const { 244 // This |current_tab| can be NULL during the initialization of the 245 // toolbar during window creation (i.e. before any tabs have been added 246 // to the window). 247 WebContents* current_tab = delegate_->GetActiveWebContents(); 248 return current_tab ? ¤t_tab->GetController() : NULL; 249 } 250 251 Profile* ToolbarModelImpl::GetProfile() const { 252 NavigationController* navigation_controller = GetNavigationController(); 253 return navigation_controller ? 254 Profile::FromBrowserContext(navigation_controller->GetBrowserContext()) : 255 NULL; 256 } 257 258 string16 ToolbarModelImpl::GetSearchTerms(bool ignore_editing) const { 259 const WebContents* web_contents = delegate_->GetActiveWebContents(); 260 string16 search_terms(chrome::GetSearchTerms(web_contents)); 261 if (search_terms.empty()) 262 return string16(); // We mainly do this to enforce the subsequent DCHECK. 263 264 // If the page is still loading and the security style is unknown, consider 265 // the page secure. Without this, after the user hit enter on some search 266 // terms, the omnibox would change to displaying the loading URL before 267 // changing back to the search terms once they could be extracted, thus 268 // causing annoying flicker. 269 DCHECK(web_contents); 270 const NavigationController& nav_controller = web_contents->GetController(); 271 const NavigationEntry* entry = nav_controller.GetVisibleEntry(); 272 if ((entry != nav_controller.GetLastCommittedEntry()) && 273 (entry->GetSSL().security_style == content::SECURITY_STYLE_UNKNOWN)) 274 return search_terms; 275 276 // If the URL is using a Google base URL specified via the command line, we 277 // allow search term replacement any time the user isn't editing, bypassing 278 // the security check below. 279 if ((ignore_editing || !input_in_progress_) && entry && 280 google_util::StartsWithCommandLineGoogleBaseURL(entry->GetVirtualURL())) 281 return search_terms; 282 283 // Otherwise, extract search terms for HTTPS pages that do not have a security 284 // error. 285 ToolbarModel::SecurityLevel security_level = GetSecurityLevel(ignore_editing); 286 return ((security_level == NONE) || (security_level == SECURITY_ERROR)) ? 287 string16() : search_terms; 288 } 289