#include "chrome/browser/supervised_user/supervised_user_resource_throttle.h"
#include "base/bind.h"
+#include "base/metrics/histogram.h"
#include "chrome/browser/supervised_user/supervised_user_interstitial.h"
#include "chrome/browser/supervised_user/supervised_user_navigation_observer.h"
#include "chrome/browser/supervised_user/supervised_user_url_filter.h"
#include "content/public/browser/resource_controller.h"
#include "content/public/browser/resource_request_info.h"
#include "net/url_request/url_request.h"
+#include "ui/base/page_transition_types.h"
using content::BrowserThread;
+namespace {
+
+// These values corresponds to SupervisedUserSafetyFilterResult in
+// tools/metrics/histograms/histograms.xml. If you change anything here, make
+// sure to also update histograms.xml accordingly.
+enum {
+ FILTERING_BEHAVIOR_ALLOW = 1,
+ FILTERING_BEHAVIOR_ALLOW_UNCERTAIN,
+ FILTERING_BEHAVIOR_BLOCK_BLACKLIST,
+ FILTERING_BEHAVIOR_BLOCK_SAFESITES,
+ FILTERING_BEHAVIOR_MAX = FILTERING_BEHAVIOR_BLOCK_SAFESITES
+};
+const int kHistogramFilteringBehaviorSpacing = 100;
+const int kHistogramPageTransitionMaxKnownValue =
+ static_cast<int>(ui::PAGE_TRANSITION_KEYWORD_GENERATED);
+const int kHistogramPageTransitionFallbackValue =
+ kHistogramFilteringBehaviorSpacing - 1;
+const int kHistogramMax = 500;
+
+static_assert(kHistogramPageTransitionMaxKnownValue <
+ kHistogramPageTransitionFallbackValue,
+ "HistogramPageTransition MaxKnownValue must be < FallbackValue");
+static_assert(FILTERING_BEHAVIOR_MAX * kHistogramFilteringBehaviorSpacing +
+ kHistogramPageTransitionFallbackValue < kHistogramMax,
+ "Invalid HistogramMax value");
+
+int GetHistogramValueForFilteringBehavior(
+ SupervisedUserURLFilter::FilteringBehavior behavior,
+ SupervisedUserURLFilter::FilteringBehaviorSource source,
+ bool uncertain) {
+ // Since we're only interested in statistics about the blacklist and
+ // SafeSites, count everything that got through to the default fallback
+ // behavior as ALLOW (made it through all the filters!).
+ if (source == SupervisedUserURLFilter::DEFAULT)
+ behavior = SupervisedUserURLFilter::ALLOW;
+
+ switch (behavior) {
+ case SupervisedUserURLFilter::ALLOW:
+ return uncertain ? FILTERING_BEHAVIOR_ALLOW_UNCERTAIN
+ : FILTERING_BEHAVIOR_ALLOW;
+ case SupervisedUserURLFilter::BLOCK:
+ if (source == SupervisedUserURLFilter::BLACKLIST)
+ return FILTERING_BEHAVIOR_BLOCK_BLACKLIST;
+ else if (source == SupervisedUserURLFilter::ASYNC_CHECKER)
+ return FILTERING_BEHAVIOR_BLOCK_SAFESITES;
+ // Fall through.
+ default:
+ NOTREACHED();
+ }
+ return 0;
+}
+
+int GetHistogramValueForTransitionType(ui::PageTransition transition_type) {
+ int value =
+ static_cast<int>(ui::PageTransitionStripQualifier(transition_type));
+ if (0 <= value && value <= kHistogramPageTransitionMaxKnownValue)
+ return value;
+ NOTREACHED();
+ return kHistogramPageTransitionFallbackValue;
+}
+
+void RecordFilterResultEvent(
+ SupervisedUserURLFilter::FilteringBehavior behavior,
+ SupervisedUserURLFilter::FilteringBehaviorSource source,
+ bool uncertain,
+ ui::PageTransition transition_type) {
+ DCHECK(source != SupervisedUserURLFilter::MANUAL);
+ int value =
+ GetHistogramValueForFilteringBehavior(behavior, source, uncertain) *
+ kHistogramFilteringBehaviorSpacing +
+ GetHistogramValueForTransitionType(transition_type);
+ DCHECK_LT(value, kHistogramMax);
+ UMA_HISTOGRAM_ENUMERATION("ManagedUsers.SafetyFilter",
+ value, kHistogramMax);
+}
+
+} // namespace
+
SupervisedUserResourceThrottle::SupervisedUserResourceThrottle(
const net::URLRequest* request,
bool is_main_frame,
: request_(request),
is_main_frame_(is_main_frame),
url_filter_(url_filter),
+ deferred_(false),
+ behavior_(SupervisedUserURLFilter::HISTOGRAM_BOUNDING_VALUE),
weak_ptr_factory_(this) {}
SupervisedUserResourceThrottle::~SupervisedUserResourceThrottle() {}
if (!is_main_frame_)
return;
- if (url_filter_->GetFilteringBehaviorForURL(url) !=
- SupervisedUserURLFilter::BLOCK) {
- return;
- }
+ deferred_ = false;
+ DCHECK_EQ(SupervisedUserURLFilter::HISTOGRAM_BOUNDING_VALUE, behavior_);
+ bool got_result = url_filter_->GetFilteringBehaviorForURLWithAsyncChecks(
+ url,
+ base::Bind(&SupervisedUserResourceThrottle::OnCheckDone,
+ weak_ptr_factory_.GetWeakPtr(), url));
+ DCHECK_EQ(got_result,
+ (behavior_ != SupervisedUserURLFilter::HISTOGRAM_BOUNDING_VALUE));
+ // If we got a "not blocked" result synchronously, don't defer.
+ *defer = deferred_ = !got_result ||
+ (behavior_ == SupervisedUserURLFilter::BLOCK);
+ if (got_result)
+ behavior_ = SupervisedUserURLFilter::HISTOGRAM_BOUNDING_VALUE;
+}
- *defer = true;
+void SupervisedUserResourceThrottle::ShowInterstitial(const GURL& url) {
const content::ResourceRequestInfo* info =
content::ResourceRequestInfo::ForRequest(request_);
BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
return "SupervisedUserResourceThrottle";
}
+void SupervisedUserResourceThrottle::OnCheckDone(
+ const GURL& url,
+ SupervisedUserURLFilter::FilteringBehavior behavior,
+ SupervisedUserURLFilter::FilteringBehaviorSource source,
+ bool uncertain) {
+ DCHECK_EQ(SupervisedUserURLFilter::HISTOGRAM_BOUNDING_VALUE, behavior_);
+ // If we got a result synchronously, pass it back to ShowInterstitialIfNeeded.
+ if (!deferred_)
+ behavior_ = behavior;
+
+ // If both the static blacklist and SafeSites are enabled, record UMA events.
+ if (url_filter_->HasBlacklist() && url_filter_->HasAsyncURLChecker() &&
+ source < SupervisedUserURLFilter::MANUAL) {
+ const content::ResourceRequestInfo* info =
+ content::ResourceRequestInfo::ForRequest(request_);
+ RecordFilterResultEvent(behavior, source, uncertain,
+ info->GetPageTransition());
+ }
+
+ if (behavior == SupervisedUserURLFilter::BLOCK)
+ ShowInterstitial(url);
+ else if (deferred_)
+ controller()->Resume();
+}
+
void SupervisedUserResourceThrottle::OnInterstitialResult(
bool continue_request) {
if (continue_request)