| // Copyright 2012 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "components/omnibox/browser/location_bar_model_impl.h" |
| |
| #include "base/check.h" |
| #include "base/feature_list.h" |
| #include "base/metrics/field_trial_params.h" |
| #include "base/notreached.h" |
| #include "base/strings/utf_string_conversions.h" |
| #include "base/time/time.h" |
| #include "build/build_config.h" |
| #include "components/dom_distiller/core/url_constants.h" |
| #include "components/dom_distiller/core/url_utils.h" |
| #include "components/omnibox/browser/buildflags.h" |
| #include "components/omnibox/browser/location_bar_model_delegate.h" |
| #include "components/omnibox/browser/location_bar_model_util.h" |
| #include "components/omnibox/common/omnibox_features.h" |
| #include "components/search_engines/template_url_service.h" |
| #include "components/security_state/core/security_state.h" |
| #include "components/strings/grit/components_strings.h" |
| #include "net/cert/cert_status_flags.h" |
| #include "net/cert/x509_certificate.h" |
| #include "net/ssl/ssl_connection_status_flags.h" |
| #include "ui/base/l10n/l10n_util.h" |
| #include "ui/gfx/text_elider.h" |
| #include "ui/gfx/vector_icon_types.h" |
| #include "url/origin.h" |
| |
| #if (!defined(OS_ANDROID) || BUILDFLAG(ENABLE_VR)) && !defined(OS_IOS) |
| #include "components/omnibox/browser/vector_icons.h" // nogncheck |
| #endif |
| |
| using metrics::OmniboxEventProto; |
| |
| LocationBarModelImpl::LocationBarModelImpl(LocationBarModelDelegate* delegate, |
| size_t max_url_display_chars) |
| : delegate_(delegate), max_url_display_chars_(max_url_display_chars) { |
| DCHECK(delegate_); |
| } |
| |
| LocationBarModelImpl::~LocationBarModelImpl() {} |
| |
| // LocationBarModelImpl Implementation. |
| base::string16 LocationBarModelImpl::GetFormattedFullURL() const { |
| return GetFormattedURL(url_formatter::kFormatUrlOmitDefaults); |
| } |
| |
| base::string16 LocationBarModelImpl::GetURLForDisplay() const { |
| url_formatter::FormatUrlTypes format_types = |
| url_formatter::kFormatUrlOmitDefaults; |
| if (delegate_->ShouldTrimDisplayUrlAfterHostName()) { |
| format_types |= url_formatter::kFormatUrlTrimAfterHost; |
| } |
| |
| #if defined(OS_IOS) |
| format_types |= url_formatter::kFormatUrlTrimAfterHost; |
| #endif |
| |
| format_types |= url_formatter::kFormatUrlOmitHTTPS; |
| format_types |= url_formatter::kFormatUrlOmitTrivialSubdomains; |
| |
| if (base::FeatureList::IsEnabled(omnibox::kHideFileUrlScheme)) |
| format_types |= url_formatter::kFormatUrlOmitFileScheme; |
| |
| if (dom_distiller::url_utils::IsDistilledPage(GetURL())) { |
| // We explicitly elide the scheme here to ensure that HTTPS and HTTP will |
| // be removed for display: Reader mode pages should not display a scheme, |
| // and should only run on HTTP/HTTPS pages. |
| // Users will be able to see the scheme when the URL is focused or being |
| // edited in the omnibox. |
| format_types |= url_formatter::kFormatUrlOmitHTTP; |
| format_types |= url_formatter::kFormatUrlOmitHTTPS; |
| } |
| |
| return GetFormattedURL(format_types); |
| } |
| |
| base::string16 LocationBarModelImpl::GetFormattedURL( |
| url_formatter::FormatUrlTypes format_types) const { |
| if (!ShouldDisplayURL()) |
| return base::string16{}; |
| |
| // Reset |format_types| to prevent elision of URLs when relevant extension or |
| // pref is enabled. |
| if (delegate_->ShouldPreventElision()) { |
| format_types = url_formatter::kFormatUrlOmitDefaults & |
| ~url_formatter::kFormatUrlOmitHTTP; |
| } |
| |
| // Prevent scheme/trivial subdomain elision when simplified domain field |
| // trials are enabled. In these field trials, OmniboxViewViews handles elision |
| // of scheme and trivial subdomains because they are shown/hidden based on |
| // user interactions with the omnibox. |
| if (base::FeatureList::IsEnabled( |
| omnibox::kRevealSteadyStateUrlPathQueryAndRefOnHover) || |
| base::FeatureList::IsEnabled( |
| omnibox::kHideSteadyStateUrlPathQueryAndRefOnInteraction)) { |
| format_types &= ~url_formatter::kFormatUrlOmitHTTP; |
| format_types &= ~url_formatter::kFormatUrlOmitHTTPS; |
| format_types &= ~url_formatter::kFormatUrlOmitTrivialSubdomains; |
| } |
| |
| GURL url(GetURL()); |
| |
| #if defined(OS_IOS) |
| // On iOS, the blob: display URLs should be simply the domain name. However, |
| // url_formatter parses everything past blob: as path, not domain, so swap |
| // the url here to be just origin. |
| if (url.SchemeIsBlob()) { |
| url = url::Origin::Create(url).GetURL(); |
| } |
| #endif // defined(OS_IOS) |
| |
| // Special handling for dom-distiller:. Instead of showing internal reader |
| // mode URLs, show the original article URL in the omnibox. |
| // Note that this does not disallow the user from seeing the distilled page |
| // URL in the view-source url or devtools. Note that this also impacts |
| // GetFormattedFullURL which uses GetFormattedURL as a helper. |
| // Virtual URLs were not a good solution for Reader Mode URLs because some |
| // security UI is based off of the virtual URL rather than the original URL, |
| // and Reader Mode has its own security chip. In addition virtual URLs would |
| // add a lot of complexity around passing necessary URL parameters to the |
| // Reader Mode pages. |
| // Note: if the URL begins with dom-distiller:// but is invalid we display it |
| // as-is because it cannot be transformed into an article URL. |
| if (dom_distiller::url_utils::IsDistilledPage(url)) |
| url = dom_distiller::url_utils::GetOriginalUrlFromDistillerUrl(url); |
| |
| // Note that we can't unescape spaces here, because if the user copies this |
| // and pastes it into another program, that program may think the URL ends at |
| // the space. |
| const base::string16 formatted_text = |
| delegate_->FormattedStringWithEquivalentMeaning( |
| url, |
| url_formatter::FormatUrl(url, format_types, net::UnescapeRule::NORMAL, |
| nullptr, nullptr, nullptr)); |
| |
| // Truncating the URL breaks editing and then pressing enter, but hopefully |
| // people won't try to do much with such enormous URLs anyway. If this becomes |
| // a real problem, we could perhaps try to keep some sort of different "elided |
| // visible URL" where editing affects and reloads the "real underlying URL", |
| // but this seems very tricky for little gain. |
| return gfx::TruncateString(formatted_text, max_url_display_chars_, |
| gfx::CHARACTER_BREAK); |
| } |
| |
| GURL LocationBarModelImpl::GetURL() const { |
| GURL url; |
| return (ShouldDisplayURL() && delegate_->GetURL(&url)) |
| ? url |
| : GURL(url::kAboutBlankURL); |
| } |
| |
| security_state::SecurityLevel LocationBarModelImpl::GetSecurityLevel() const { |
| // When empty, assume no security style. |
| if (!ShouldDisplayURL()) |
| return security_state::NONE; |
| |
| return delegate_->GetSecurityLevel(); |
| } |
| |
| OmniboxEventProto::PageClassification |
| LocationBarModelImpl::GetPageClassification(OmniboxFocusSource focus_source) { |
| // We may be unable to fetch the current URL during startup or shutdown when |
| // the omnibox exists but there is no attached page. |
| GURL gurl; |
| if (!delegate_->GetURL(&gurl)) |
| return OmniboxEventProto::OTHER; |
| |
| if (focus_source == OmniboxFocusSource::SEARCH_BUTTON) |
| return OmniboxEventProto::SEARCH_BUTTON_AS_STARTING_FOCUS; |
| if (delegate_->IsNewTabPage()) { |
| // Note that we treat OMNIBOX as the source if focus_source_ is INVALID, |
| // i.e., if input isn't actually in progress. |
| return (focus_source == OmniboxFocusSource::FAKEBOX) |
| ? OmniboxEventProto::INSTANT_NTP_WITH_FAKEBOX_AS_STARTING_FOCUS |
| : OmniboxEventProto::INSTANT_NTP_WITH_OMNIBOX_AS_STARTING_FOCUS; |
| } |
| if (!gurl.is_valid()) |
| return OmniboxEventProto::INVALID_SPEC; |
| if (delegate_->IsNewTabPageURL(gurl)) |
| return OmniboxEventProto::NTP; |
| if (gurl.spec() == url::kAboutBlankURL) |
| return OmniboxEventProto::BLANK; |
| if (delegate_->IsHomePage(gurl)) |
| return OmniboxEventProto::HOME_PAGE; |
| |
| TemplateURLService* template_url_service = delegate_->GetTemplateURLService(); |
| if (template_url_service && |
| template_url_service->IsSearchResultsPageFromDefaultSearchProvider( |
| gurl)) { |
| return OmniboxEventProto::SEARCH_RESULT_PAGE_NO_SEARCH_TERM_REPLACEMENT; |
| } |
| |
| return OmniboxEventProto::OTHER; |
| } |
| |
| const gfx::VectorIcon& LocationBarModelImpl::GetVectorIcon() const { |
| #if (!defined(OS_ANDROID) || BUILDFLAG(ENABLE_VR)) && !defined(OS_IOS) |
| auto* const icon_override = delegate_->GetVectorIconOverride(); |
| if (icon_override) |
| return *icon_override; |
| |
| if (IsOfflinePage()) |
| return omnibox::kOfflinePinIcon; |
| #endif |
| |
| return location_bar_model::GetSecurityVectorIcon(GetSecurityLevel()); |
| } |
| |
| base::string16 LocationBarModelImpl::GetSecureDisplayText() const { |
| // Note that display text will be implicitly used as the accessibility text. |
| // GetSecureAccessibilityText() handles special cases when no display text is |
| // set. |
| |
| if (IsOfflinePage()) |
| return l10n_util::GetStringUTF16(IDS_OFFLINE_VERBOSE_STATE); |
| |
| switch (GetSecurityLevel()) { |
| case security_state::WARNING: |
| return l10n_util::GetStringUTF16(IDS_NOT_SECURE_VERBOSE_STATE); |
| case security_state::SECURE: |
| return base::string16(); |
| case security_state::DANGEROUS: { |
| std::unique_ptr<security_state::VisibleSecurityState> |
| visible_security_state = delegate_->GetVisibleSecurityState(); |
| |
| // Don't show any text in the security indicator for sites on the billing |
| // interstitial list. |
| if (visible_security_state->malicious_content_status == |
| security_state::MALICIOUS_CONTENT_STATUS_BILLING) { |
| return base::string16(); |
| } |
| |
| bool fails_malware_check = |
| visible_security_state->malicious_content_status != |
| security_state::MALICIOUS_CONTENT_STATUS_NONE; |
| return l10n_util::GetStringUTF16(fails_malware_check |
| ? IDS_DANGEROUS_VERBOSE_STATE |
| : IDS_NOT_SECURE_VERBOSE_STATE); |
| } |
| default: |
| return base::string16(); |
| } |
| } |
| |
| base::string16 LocationBarModelImpl::GetSecureAccessibilityText() const { |
| auto display_text = GetSecureDisplayText(); |
| if (!display_text.empty()) |
| return display_text; |
| |
| switch (GetSecurityLevel()) { |
| case security_state::SECURE: |
| return l10n_util::GetStringUTF16(IDS_SECURE_VERBOSE_STATE); |
| default: |
| return base::string16(); |
| } |
| } |
| |
| bool LocationBarModelImpl::ShouldDisplayURL() const { |
| return delegate_->ShouldDisplayURL(); |
| } |
| |
| bool LocationBarModelImpl::IsOfflinePage() const { |
| return delegate_->IsOfflinePage(); |
| } |
| |
| bool LocationBarModelImpl::ShouldPreventElision() const { |
| return delegate_->ShouldPreventElision(); |
| } |