Home | History | Annotate | Download | only in toolbar
      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 ? &current_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