blob: a9542d86c58ac246c305dcab7052348099e30edd [file] [log] [blame]
// Copyright 2017 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 "chrome/browser/ui/webui/interventions_internals/interventions_internals_page_handler.h"
#include <utility>
#include <vector>
#include "base/base_switches.h"
#include "base/command_line.h"
#include "base/metrics/field_trial_params.h"
#include "base/time/time.h"
#include "build/build_config.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/flag_descriptions.h"
#include "chrome/common/chrome_switches.h"
#include "components/data_reduction_proxy/core/common/data_reduction_proxy_switches.h"
#include "components/previews/core/previews_experiments.h"
#include "components/previews/core/previews_switches.h"
#include "net/nqe/network_quality_estimator_params.h"
#include "services/network/public/cpp/network_quality_tracker.h"
#include "services/network/public/cpp/network_switches.h"
namespace {
// HTML DOM ID used in the JavaScript code. The IDs are generated here so that
// the DOM would have sensible name instead of autogenerated IDs.
const char kPreviewsAllowedHtmlId[] = "previews-allowed-status";
const char kClientLoFiPreviewsHtmlId[] = "client-lofi-preview-status";
const char kLitePageRedirectHtmlId[] = "lite-page-redirect-status";
const char kNoScriptPreviewsHtmlId[] = "noscript-preview-status";
const char kResourceLoadingHintsHtmlId[] = "resource-loading-hints-status";
const char kOfflinePreviewsHtmlId[] = "offline-preview-status";
// Descriptions for previews.
const char kPreviewsAllowedDescription[] = "Previews Allowed";
const char kClientLoFiDescription[] = "Client LoFi Previews";
const char kLitePageRedirectDescription[] =
"Lite Page Redirect / Server Previews";
const char kNoScriptDescription[] = "NoScript Previews";
const char kResourceLoadingHintsDescription[] = "ResourceLoadingHints Previews";
const char kOfflineDesciption[] = "Offline Previews";
// Flag feature name.
const char kPreviewsAllowedFeatureName[] = "Previews";
const char kLitePageRedirectFeatureName[] = "LitePageServerPreviews";
const char kNoScriptFeatureName[] = "NoScriptPreviews";
const char kResourceLoadingHintsFeatureName[] = "ResourceLoadingHints";
#if defined(OS_ANDROID)
const char kOfflinePageFeatureName[] = "OfflinePreviews";
#endif // OS_ANDROID
// HTML DOM ID used in the JavaScript code. The IDs are generated here so that
// the DOM would have sensible name instead of autogenerated IDs.
const char kPreviewsAllowedFlagHtmlId[] = "previews-flag";
const char kOfflinePageFlagHtmlId[] = "offline-page-flag";
const char kLitePageRedirectFlagHtmlId[] = "lite-page-redirect-flag";
const char kResourceLoadingHintsFlagHtmlId[] = "resource-loading-hints-flag";
const char kNoScriptFlagHtmlId[] = "noscript-flag";
const char kEctFlagHtmlId[] = "ect-flag";
const char kIgnorePreviewsBlacklistFlagHtmlId[] = "ignore-previews-blacklist";
const char kDataSaverAltConfigHtmlId[] =
"data-reduction-proxy-server-experiment";
// Links to flags in chrome://flags.
// TODO(thanhdle): Refactor into vector of structs. crbug.com/787010.
const char kPreviewsAllowedFlagLink[] = "chrome://flags/#allow-previews";
const char kOfflinePageFlagLink[] = "chrome://flags/#enable-offline-previews";
const char kLitePageRedirectFlagLink[] =
"chrome://flags/#enable-lite-page-server-previews";
const char kResourceLoadingHintsFlagLink[] =
"chrome://flags/#enable-resource-loading-hints";
const char kNoScriptFlagLink[] = "chrome://flags/#enable-noscript-previews";
const char kEctFlagLink[] = "chrome://flags/#force-effective-connection-type";
const char kIgnorePreviewsBlacklistLink[] =
"chrome://flags/#ignore-previews-blacklist";
const char kDataSaverAltConfigLink[] =
"chrome://flags/#enable-data-reduction-proxy-server-experiment";
const char kDefaultFlagValue[] = "Default";
// Check if the flag status of the flag is a forced value or not.
std::string GetFeatureFlagStatus(const std::string& feature_name) {
std::string enabled_features =
base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
switches::kEnableFeatures);
if (enabled_features.find(feature_name) != std::string::npos) {
return "Enabled";
}
std::string disabled_features =
base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
switches::kDisableFeatures);
if (disabled_features.find(feature_name) != std::string::npos) {
return "Disabled";
}
return kDefaultFlagValue;
}
std::string GetNonFlagEctValue() {
std::map<std::string, std::string> nqe_params;
base::GetFieldTrialParams("NetworkQualityEstimator", &nqe_params);
if (nqe_params.find(net::kForceEffectiveConnectionType) != nqe_params.end()) {
return "Fieldtrial forced " +
nqe_params[net::kForceEffectiveConnectionType];
}
return kDefaultFlagValue;
}
// Check if the switch flag is enabled or disabled via flag/command-line.
std::string GetEnabledStateForSwitch(const std::string& switch_name) {
return base::CommandLine::ForCurrentProcess()->HasSwitch(switch_name)
? "Enabled"
: "Disabled";
}
} // namespace
InterventionsInternalsPageHandler::InterventionsInternalsPageHandler(
mojom::InterventionsInternalsPageHandlerRequest request,
previews::PreviewsUIService* previews_ui_service)
: binding_(this, std::move(request)),
previews_ui_service_(previews_ui_service),
current_estimated_ect_(net::EFFECTIVE_CONNECTION_TYPE_UNKNOWN) {
logger_ = previews_ui_service_->previews_logger();
DCHECK(logger_);
}
InterventionsInternalsPageHandler::~InterventionsInternalsPageHandler() {
DCHECK(logger_);
logger_->RemoveObserver(this);
g_browser_process->network_quality_tracker()
->RemoveEffectiveConnectionTypeObserver(this);
}
void InterventionsInternalsPageHandler::SetClientPage(
mojom::InterventionsInternalsPagePtr page) {
page_ = std::move(page);
DCHECK(page_);
logger_->AddAndNotifyObserver(this);
g_browser_process->network_quality_tracker()
->AddEffectiveConnectionTypeObserver(this);
}
void InterventionsInternalsPageHandler::OnEffectiveConnectionTypeChanged(
net::EffectiveConnectionType type) {
current_estimated_ect_ = type;
if (!page_) {
// Don't try to notify the page if |page_| is not ready.
return;
}
std::string ect_name = net::GetNameForEffectiveConnectionType(type);
std::string max_intervention_ect_name =
net::GetNameForEffectiveConnectionType(
previews::params::GetSessionMaxECTThreshold());
page_->UpdateEffectiveConnectionType(ect_name, max_intervention_ect_name);
// Log change ECT event.
previews::PreviewsLogger::MessageLog message(
"ECT Changed" /* event_type */,
"Effective Connection Type changed to " + ect_name, GURL(""),
base::Time::Now(), 0 /* page_id */);
OnNewMessageLogAdded(message);
}
void InterventionsInternalsPageHandler::OnNewMessageLogAdded(
const previews::PreviewsLogger::MessageLog& message) {
mojom::MessageLogPtr mojo_message_ptr(mojom::MessageLog::New());
mojo_message_ptr->type = message.event_type;
mojo_message_ptr->description = message.event_description;
mojo_message_ptr->url = message.url;
mojo_message_ptr->time = message.time.ToJavaTime();
mojo_message_ptr->page_id = message.page_id;
page_->LogNewMessage(std::move(mojo_message_ptr));
}
void InterventionsInternalsPageHandler::SetIgnorePreviewsBlacklistDecision(
bool ignored) {
previews_ui_service_->SetIgnorePreviewsBlacklistDecision(ignored);
}
void InterventionsInternalsPageHandler::OnLastObserverRemove() {
// Reset the status of ignoring PreviewsBlackList decisions to default value.
previews_ui_service_->SetIgnorePreviewsBlacklistDecision(
base::CommandLine::ForCurrentProcess()->HasSwitch(
previews::switches::kIgnorePreviewsBlacklist));
}
void InterventionsInternalsPageHandler::OnIgnoreBlacklistDecisionStatusChanged(
bool ignored) {
page_->OnIgnoreBlacklistDecisionStatusChanged(ignored);
}
void InterventionsInternalsPageHandler::OnNewBlacklistedHost(
const std::string& host,
base::Time time) {
page_->OnBlacklistedHost(host, time.ToJavaTime());
}
void InterventionsInternalsPageHandler::OnUserBlacklistedStatusChange(
bool blacklisted) {
page_->OnUserBlacklistedStatusChange(blacklisted);
}
void InterventionsInternalsPageHandler::OnBlacklistCleared(base::Time time) {
page_->OnBlacklistCleared(time.ToJavaTime());
}
void InterventionsInternalsPageHandler::GetPreviewsEnabled(
GetPreviewsEnabledCallback callback) {
std::vector<mojom::PreviewsStatusPtr> statuses;
auto previews_allowed_status = mojom::PreviewsStatus::New();
previews_allowed_status->description = kPreviewsAllowedDescription;
previews_allowed_status->enabled = previews::params::ArePreviewsAllowed();
previews_allowed_status->htmlId = kPreviewsAllowedHtmlId;
statuses.push_back(std::move(previews_allowed_status));
auto offline_status = mojom::PreviewsStatus::New();
offline_status->description = kOfflineDesciption;
offline_status->enabled = previews::params::IsOfflinePreviewsEnabled();
offline_status->htmlId = kOfflinePreviewsHtmlId;
statuses.push_back(std::move(offline_status));
auto lite_page_redirect_status = mojom::PreviewsStatus::New();
lite_page_redirect_status->description = kLitePageRedirectDescription;
lite_page_redirect_status->enabled =
previews::params::IsLitePageServerPreviewsEnabled();
lite_page_redirect_status->htmlId = kLitePageRedirectHtmlId;
statuses.push_back(std::move(lite_page_redirect_status));
auto resource_loading_hints_status = mojom::PreviewsStatus::New();
resource_loading_hints_status->description = kResourceLoadingHintsDescription;
resource_loading_hints_status->enabled =
previews::params::IsResourceLoadingHintsEnabled();
resource_loading_hints_status->htmlId = kResourceLoadingHintsHtmlId;
statuses.push_back(std::move(resource_loading_hints_status));
auto noscript_status = mojom::PreviewsStatus::New();
noscript_status->description = kNoScriptDescription;
noscript_status->enabled = previews::params::IsNoScriptPreviewsEnabled();
noscript_status->htmlId = kNoScriptPreviewsHtmlId;
statuses.push_back(std::move(noscript_status));
auto client_lofi_status = mojom::PreviewsStatus::New();
client_lofi_status->description = kClientLoFiDescription;
client_lofi_status->enabled = previews::params::IsClientLoFiEnabled();
client_lofi_status->htmlId = kClientLoFiPreviewsHtmlId;
statuses.push_back(std::move(client_lofi_status));
std::move(callback).Run(std::move(statuses));
}
void InterventionsInternalsPageHandler::GetPreviewsFlagsDetails(
GetPreviewsFlagsDetailsCallback callback) {
std::vector<mojom::PreviewsFlagPtr> flags;
auto previews_allowed_status = mojom::PreviewsFlag::New();
previews_allowed_status->description =
flag_descriptions::kPreviewsAllowedName;
previews_allowed_status->link = kPreviewsAllowedFlagLink;
previews_allowed_status->value =
GetFeatureFlagStatus(kPreviewsAllowedFeatureName);
previews_allowed_status->htmlId = kPreviewsAllowedFlagHtmlId;
flags.push_back(std::move(previews_allowed_status));
auto offline_page_status = mojom::PreviewsFlag::New();
#if defined(OS_ANDROID)
offline_page_status->description =
flag_descriptions::kEnableOfflinePreviewsName;
offline_page_status->value = GetFeatureFlagStatus(kOfflinePageFeatureName);
#else
offline_page_status->description = "Offline Page Previews";
offline_page_status->value = "Only support on Android";
#endif // OS_ANDROID
offline_page_status->link = kOfflinePageFlagLink;
offline_page_status->htmlId = kOfflinePageFlagHtmlId;
flags.push_back(std::move(offline_page_status));
auto lite_page_redirect_status = mojom::PreviewsFlag::New();
lite_page_redirect_status->description =
flag_descriptions::kEnableLitePageServerPreviewsName;
lite_page_redirect_status->link = kLitePageRedirectFlagLink;
lite_page_redirect_status->value =
GetFeatureFlagStatus(kLitePageRedirectFeatureName);
lite_page_redirect_status->htmlId = kLitePageRedirectFlagHtmlId;
flags.push_back(std::move(lite_page_redirect_status));
auto resource_loading_hints_status = mojom::PreviewsFlag::New();
resource_loading_hints_status->description =
flag_descriptions::kEnableResourceLoadingHintsName;
resource_loading_hints_status->link = kResourceLoadingHintsFlagLink;
resource_loading_hints_status->value =
GetFeatureFlagStatus(kResourceLoadingHintsFeatureName);
resource_loading_hints_status->htmlId = kResourceLoadingHintsFlagHtmlId;
flags.push_back(std::move(resource_loading_hints_status));
auto noscript_status = mojom::PreviewsFlag::New();
noscript_status->description = flag_descriptions::kEnableNoScriptPreviewsName;
noscript_status->link = kNoScriptFlagLink;
noscript_status->value = GetFeatureFlagStatus(kNoScriptFeatureName);
noscript_status->htmlId = kNoScriptFlagHtmlId;
flags.push_back(std::move(noscript_status));
auto ect_status = mojom::PreviewsFlag::New();
ect_status->description =
flag_descriptions::kForceEffectiveConnectionTypeName;
ect_status->link = kEctFlagLink;
std::string ect_value =
base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
network::switches::kForceEffectiveConnectionType);
ect_status->value = ect_value.empty() ? GetNonFlagEctValue() : ect_value;
ect_status->htmlId = kEctFlagHtmlId;
flags.push_back(std::move(ect_status));
auto ignore_previews_blacklist = mojom::PreviewsFlag::New();
ignore_previews_blacklist->description =
flag_descriptions::kIgnorePreviewsBlacklistName;
ignore_previews_blacklist->link = kIgnorePreviewsBlacklistLink;
ignore_previews_blacklist->value =
GetEnabledStateForSwitch(previews::switches::kIgnorePreviewsBlacklist);
ignore_previews_blacklist->htmlId = kIgnorePreviewsBlacklistFlagHtmlId;
flags.push_back(std::move(ignore_previews_blacklist));
auto alt_config_status = mojom::PreviewsFlag::New();
alt_config_status->description =
flag_descriptions::kEnableDataReductionProxyServerExperimentDescription;
alt_config_status->link = kDataSaverAltConfigLink;
alt_config_status->value =
base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
data_reduction_proxy::switches::kDataReductionProxyExperiment);
if (alt_config_status->value.empty())
alt_config_status->value = kDefaultFlagValue;
alt_config_status->htmlId = kDataSaverAltConfigHtmlId;
flags.push_back(std::move(alt_config_status));
std::move(callback).Run(std::move(flags));
}