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