OLD | NEW |
| (Empty) |
1 // Copyright 2014 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/supervised_user/supervised_user_resource_throttle.h" | |
6 | |
7 #include "base/bind.h" | |
8 #include "base/memory/ptr_util.h" | |
9 #include "base/metrics/histogram_macros.h" | |
10 #include "chrome/browser/supervised_user/supervised_user_interstitial.h" | |
11 #include "chrome/browser/supervised_user/supervised_user_navigation_observer.h" | |
12 #include "chrome/browser/supervised_user/supervised_user_url_filter.h" | |
13 #include "content/public/browser/browser_thread.h" | |
14 #include "content/public/browser/resource_request_info.h" | |
15 #include "net/url_request/redirect_info.h" | |
16 #include "net/url_request/url_request.h" | |
17 #include "ui/base/page_transition_types.h" | |
18 | |
19 using content::BrowserThread; | |
20 | |
21 namespace { | |
22 | |
23 // These values corresponds to SupervisedUserSafetyFilterResult in | |
24 // tools/metrics/histograms/histograms.xml. If you change anything here, make | |
25 // sure to also update histograms.xml accordingly. | |
26 enum { | |
27 FILTERING_BEHAVIOR_ALLOW = 1, | |
28 FILTERING_BEHAVIOR_ALLOW_UNCERTAIN, | |
29 FILTERING_BEHAVIOR_BLOCK_BLACKLIST, | |
30 FILTERING_BEHAVIOR_BLOCK_SAFESITES, | |
31 FILTERING_BEHAVIOR_BLOCK_MANUAL, | |
32 FILTERING_BEHAVIOR_BLOCK_DEFAULT, | |
33 FILTERING_BEHAVIOR_ALLOW_WHITELIST, | |
34 FILTERING_BEHAVIOR_MAX = FILTERING_BEHAVIOR_ALLOW_WHITELIST | |
35 }; | |
36 const int kHistogramFilteringBehaviorSpacing = 100; | |
37 const int kHistogramPageTransitionMaxKnownValue = | |
38 static_cast<int>(ui::PAGE_TRANSITION_KEYWORD_GENERATED); | |
39 const int kHistogramPageTransitionFallbackValue = | |
40 kHistogramFilteringBehaviorSpacing - 1; | |
41 const int kHistogramMax = 800; | |
42 | |
43 static_assert(kHistogramPageTransitionMaxKnownValue < | |
44 kHistogramPageTransitionFallbackValue, | |
45 "HistogramPageTransition MaxKnownValue must be < FallbackValue"); | |
46 static_assert(FILTERING_BEHAVIOR_MAX * kHistogramFilteringBehaviorSpacing + | |
47 kHistogramPageTransitionFallbackValue < kHistogramMax, | |
48 "Invalid HistogramMax value"); | |
49 | |
50 int GetHistogramValueForFilteringBehavior( | |
51 SupervisedUserURLFilter::FilteringBehavior behavior, | |
52 supervised_user_error_page::FilteringBehaviorReason reason, | |
53 bool uncertain) { | |
54 switch (behavior) { | |
55 case SupervisedUserURLFilter::ALLOW: | |
56 case SupervisedUserURLFilter::WARN: | |
57 if (reason == supervised_user_error_page::WHITELIST) | |
58 return FILTERING_BEHAVIOR_ALLOW_WHITELIST; | |
59 return uncertain ? FILTERING_BEHAVIOR_ALLOW_UNCERTAIN | |
60 : FILTERING_BEHAVIOR_ALLOW; | |
61 case SupervisedUserURLFilter::BLOCK: | |
62 switch (reason) { | |
63 case supervised_user_error_page::BLACKLIST: | |
64 return FILTERING_BEHAVIOR_BLOCK_BLACKLIST; | |
65 case supervised_user_error_page::ASYNC_CHECKER: | |
66 return FILTERING_BEHAVIOR_BLOCK_SAFESITES; | |
67 case supervised_user_error_page::WHITELIST: | |
68 NOTREACHED(); | |
69 break; | |
70 case supervised_user_error_page::MANUAL: | |
71 return FILTERING_BEHAVIOR_BLOCK_MANUAL; | |
72 case supervised_user_error_page::DEFAULT: | |
73 return FILTERING_BEHAVIOR_BLOCK_DEFAULT; | |
74 case supervised_user_error_page::NOT_SIGNED_IN: | |
75 // Should never happen, only used for requests from Webview | |
76 NOTREACHED(); | |
77 } | |
78 case SupervisedUserURLFilter::INVALID: | |
79 NOTREACHED(); | |
80 } | |
81 return 0; | |
82 } | |
83 | |
84 int GetHistogramValueForTransitionType(ui::PageTransition transition_type) { | |
85 int value = | |
86 static_cast<int>(ui::PageTransitionStripQualifier(transition_type)); | |
87 if (0 <= value && value <= kHistogramPageTransitionMaxKnownValue) | |
88 return value; | |
89 NOTREACHED(); | |
90 return kHistogramPageTransitionFallbackValue; | |
91 } | |
92 | |
93 void RecordFilterResultEvent( | |
94 bool safesites_histogram, | |
95 SupervisedUserURLFilter::FilteringBehavior behavior, | |
96 supervised_user_error_page::FilteringBehaviorReason reason, | |
97 bool uncertain, | |
98 ui::PageTransition transition_type) { | |
99 int value = | |
100 GetHistogramValueForFilteringBehavior(behavior, reason, uncertain) * | |
101 kHistogramFilteringBehaviorSpacing + | |
102 GetHistogramValueForTransitionType(transition_type); | |
103 DCHECK_LT(value, kHistogramMax); | |
104 // Note: We can't pass in the histogram name as a parameter to this function | |
105 // because of how the macro works (look up the histogram on the first | |
106 // invocation and cache it in a static variable). | |
107 if (safesites_histogram) | |
108 UMA_HISTOGRAM_SPARSE_SLOWLY("ManagedUsers.SafetyFilter", value); | |
109 else | |
110 UMA_HISTOGRAM_SPARSE_SLOWLY("ManagedUsers.FilteringResult", value); | |
111 } | |
112 | |
113 // Helper function to wrap a given callback in one that will post it to the | |
114 // IO thread. | |
115 base::Callback<void(bool)> ResultTrampoline( | |
116 const base::Callback<void(bool)>& callback) { | |
117 return base::Bind( | |
118 [](const base::Callback<void(bool)>& callback, bool result) { | |
119 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, | |
120 base::Bind(callback, result)); | |
121 }, | |
122 callback); | |
123 } | |
124 | |
125 } // namespace | |
126 | |
127 // static | |
128 std::unique_ptr<SupervisedUserResourceThrottle> | |
129 SupervisedUserResourceThrottle::MaybeCreate( | |
130 const net::URLRequest* request, | |
131 content::ResourceType resource_type, | |
132 const SupervisedUserURLFilter* url_filter) { | |
133 // Only treat main frame requests (ignoring subframes and subresources). | |
134 bool is_main_frame = resource_type == content::RESOURCE_TYPE_MAIN_FRAME; | |
135 if (!is_main_frame) | |
136 return nullptr; | |
137 | |
138 // Can't use base::MakeUnique because the constructor is private. | |
139 return base::WrapUnique( | |
140 new SupervisedUserResourceThrottle(request, url_filter)); | |
141 } | |
142 | |
143 SupervisedUserResourceThrottle::SupervisedUserResourceThrottle( | |
144 const net::URLRequest* request, | |
145 const SupervisedUserURLFilter* url_filter) | |
146 : request_(request), | |
147 url_filter_(url_filter), | |
148 deferred_(false), | |
149 behavior_(SupervisedUserURLFilter::INVALID), | |
150 weak_ptr_factory_(this) {} | |
151 | |
152 SupervisedUserResourceThrottle::~SupervisedUserResourceThrottle() {} | |
153 | |
154 void SupervisedUserResourceThrottle::CheckURL(const GURL& url, bool* defer) { | |
155 deferred_ = false; | |
156 DCHECK_EQ(SupervisedUserURLFilter::INVALID, behavior_); | |
157 bool got_result = url_filter_->GetFilteringBehaviorForURLWithAsyncChecks( | |
158 url, | |
159 base::Bind(&SupervisedUserResourceThrottle::OnCheckDone, | |
160 weak_ptr_factory_.GetWeakPtr(), url)); | |
161 DCHECK_EQ(got_result, behavior_ != SupervisedUserURLFilter::INVALID); | |
162 // If we got a "not blocked" result synchronously, don't defer. | |
163 *defer = deferred_ = !got_result || | |
164 (behavior_ == SupervisedUserURLFilter::BLOCK); | |
165 if (got_result) | |
166 behavior_ = SupervisedUserURLFilter::INVALID; | |
167 } | |
168 | |
169 void SupervisedUserResourceThrottle::ShowInterstitial( | |
170 const GURL& url, | |
171 supervised_user_error_page::FilteringBehaviorReason reason) { | |
172 const content::ResourceRequestInfo* info = | |
173 content::ResourceRequestInfo::ForRequest(request_); | |
174 BrowserThread::PostTask( | |
175 BrowserThread::UI, FROM_HERE, | |
176 base::Bind(&SupervisedUserNavigationObserver::OnRequestBlocked, | |
177 info->GetWebContentsGetterForRequest(), url, reason, | |
178 ResultTrampoline(base::Bind( | |
179 &SupervisedUserResourceThrottle::OnInterstitialResult, | |
180 weak_ptr_factory_.GetWeakPtr())))); | |
181 } | |
182 | |
183 void SupervisedUserResourceThrottle::WillStartRequest(bool* defer) { | |
184 CheckURL(request_->url(), defer); | |
185 } | |
186 | |
187 void SupervisedUserResourceThrottle::WillRedirectRequest( | |
188 const net::RedirectInfo& redirect_info, | |
189 bool* defer) { | |
190 CheckURL(redirect_info.new_url, defer); | |
191 } | |
192 | |
193 const char* SupervisedUserResourceThrottle::GetNameForLogging() const { | |
194 return "SupervisedUserResourceThrottle"; | |
195 } | |
196 | |
197 void SupervisedUserResourceThrottle::OnCheckDone( | |
198 const GURL& url, | |
199 SupervisedUserURLFilter::FilteringBehavior behavior, | |
200 supervised_user_error_page::FilteringBehaviorReason reason, | |
201 bool uncertain) { | |
202 DCHECK_EQ(SupervisedUserURLFilter::INVALID, behavior_); | |
203 // If we got a result synchronously, pass it back to ShowInterstitialIfNeeded. | |
204 if (!deferred_) | |
205 behavior_ = behavior; | |
206 | |
207 ui::PageTransition transition = | |
208 content::ResourceRequestInfo::ForRequest(request_)->GetPageTransition(); | |
209 | |
210 RecordFilterResultEvent(false, behavior, reason, uncertain, transition); | |
211 | |
212 // If both the static blacklist and the async checker are enabled, also record | |
213 // SafeSites-only UMA events. | |
214 if (url_filter_->HasBlacklist() && url_filter_->HasAsyncURLChecker() && | |
215 (reason == supervised_user_error_page::ASYNC_CHECKER || | |
216 reason == supervised_user_error_page::BLACKLIST)) { | |
217 RecordFilterResultEvent(true, behavior, reason, uncertain, transition); | |
218 } | |
219 | |
220 if (behavior == SupervisedUserURLFilter::BLOCK) | |
221 ShowInterstitial(url, reason); | |
222 else if (deferred_) | |
223 Resume(); | |
224 } | |
225 | |
226 void SupervisedUserResourceThrottle::OnInterstitialResult( | |
227 bool continue_request) { | |
228 if (continue_request) | |
229 Resume(); | |
230 else | |
231 Cancel(); | |
232 } | |
OLD | NEW |