OLD | NEW |
---|---|
1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/browser/safe_browsing/safe_browsing_navigation_observer_manager .h" | 5 #include "chrome/browser/safe_browsing/safe_browsing_navigation_observer_manager .h" |
6 | 6 |
7 #include "base/memory/ptr_util.h" | 7 #include "base/memory/ptr_util.h" |
8 #include "base/metrics/histogram_macros.h" | 8 #include "base/metrics/histogram_macros.h" |
9 #include "base/strings/stringprintf.h" | 9 #include "base/strings/stringprintf.h" |
10 #include "base/time/time.h" | 10 #include "base/time/time.h" |
(...skipping 24 matching lines...) Expand all Loading... | |
35 // Note, if for some reason this event's timestamp is in the future, this | 35 // Note, if for some reason this event's timestamp is in the future, this |
36 // event's timestamp is invalid, hence we treat it as expired. | 36 // event's timestamp is invalid, hence we treat it as expired. |
37 bool IsEventExpired(const base::Time& event_time, double ttl_in_second) { | 37 bool IsEventExpired(const base::Time& event_time, double ttl_in_second) { |
38 double current_time_in_second = base::Time::Now().ToDoubleT(); | 38 double current_time_in_second = base::Time::Now().ToDoubleT(); |
39 double event_time_in_second = event_time.ToDoubleT(); | 39 double event_time_in_second = event_time.ToDoubleT(); |
40 if (current_time_in_second <= event_time_in_second) | 40 if (current_time_in_second <= event_time_in_second) |
41 return true; | 41 return true; |
42 return current_time_in_second - event_time_in_second > ttl_in_second; | 42 return current_time_in_second - event_time_in_second > ttl_in_second; |
43 } | 43 } |
44 | 44 |
45 // Helper function to determine if the URL type should be LANDING_REFERRER or | |
46 // LANDING_PAGE, and modify AttributionResult accordingly. | |
47 ReferrerChainEntry::URLType GetURLTypeAndAdjustAttributionResult( | |
48 int current_user_gesture_count, | |
Nathan Parker
2017/01/04 19:49:12
What is current_user_gesture_count? Is that how ma
Jialiu Lin
2017/01/04 21:53:35
Good suggestion. Thanks!
| |
49 int user_gesture_count_limit, | |
50 SafeBrowsingNavigationObserverManager::AttributionResult* out_result) { | |
51 // Landing page of a download refers to the page user directly interacts | |
52 // with to trigger this download (e.g. clicking on download button). Landing | |
53 // referrer page is the one user interacts with right before navigating to | |
54 // the landing page. | |
55 // Since we are tracing navigations backwards, if we've reached | |
56 // |user_gesture_count_limit| number of user gesture before this navigation | |
57 // event, this is a navigation leading to the landing referrer page, | |
58 // otherwise it leads to landing page. | |
59 if (current_user_gesture_count == user_gesture_count_limit) { | |
60 *out_result = | |
61 SafeBrowsingNavigationObserverManager::SUCCESS_LANDING_REFERRER; | |
62 return ReferrerChainEntry::LANDING_REFERRER; | |
63 } else { | |
64 *out_result = SafeBrowsingNavigationObserverManager::SUCCESS_LANDING_PAGE; | |
65 return ReferrerChainEntry::LANDING_PAGE; | |
66 } | |
67 } | |
68 | |
45 } // namespace | 69 } // namespace |
46 | 70 |
47 // The expiration period of a user gesture. Any user gesture that happened 1.0 | 71 // The expiration period of a user gesture. Any user gesture that happened 1.0 |
48 // second ago is considered as expired and not relevant to upcoming navigation | 72 // second ago is considered as expired and not relevant to upcoming navigation |
49 // events. | 73 // events. |
50 static const double kUserGestureTTLInSecond = 1.0; | 74 static const double kUserGestureTTLInSecond = 1.0; |
51 // The expiration period of navigation events and resolved IP addresses. Any | 75 // The expiration period of navigation events and resolved IP addresses. Any |
52 // navigation related records that happened 2 minutes ago are considered as | 76 // navigation related records that happened 2 minutes ago are considered as |
53 // expired. So we clean up these navigation footprints every 2 minutes. | 77 // expired. So we clean up these navigation footprints every 2 minutes. |
54 static const double kNavigationFootprintTTLInSecond = 120.0; | 78 static const double kNavigationFootprintTTLInSecond = 120.0; |
(...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
149 | 173 |
150 void SafeBrowsingNavigationObserverManager::CleanUpStaleNavigationFootprints() { | 174 void SafeBrowsingNavigationObserverManager::CleanUpStaleNavigationFootprints() { |
151 CleanUpNavigationEvents(); | 175 CleanUpNavigationEvents(); |
152 CleanUpUserGestures(); | 176 CleanUpUserGestures(); |
153 CleanUpIpAddresses(); | 177 CleanUpIpAddresses(); |
154 ScheduleNextCleanUpAfterInterval( | 178 ScheduleNextCleanUpAfterInterval( |
155 base::TimeDelta::FromSecondsD(kNavigationFootprintTTLInSecond)); | 179 base::TimeDelta::FromSecondsD(kNavigationFootprintTTLInSecond)); |
156 } | 180 } |
157 | 181 |
158 SafeBrowsingNavigationObserverManager::AttributionResult | 182 SafeBrowsingNavigationObserverManager::AttributionResult |
159 SafeBrowsingNavigationObserverManager::IdentifyReferrerChain( | 183 SafeBrowsingNavigationObserverManager::IdentifyReferrerChainForDownload( |
160 const GURL& target_url, | 184 const GURL& target_url, |
161 int target_tab_id, | 185 int target_tab_id, |
162 int user_gesture_count_limit, | 186 int user_gesture_count_limit, |
163 std::vector<ReferrerChainEntry>* out_referrer_chain) { | 187 std::vector<ReferrerChainEntry>* out_referrer_chain) { |
164 if (!target_url.is_valid()) | 188 if (!target_url.is_valid()) |
165 return INVALID_URL; | 189 return INVALID_URL; |
166 | 190 |
167 NavigationEvent* nav_event = FindNavigationEvent(target_url, target_tab_id); | 191 NavigationEvent* nav_event = FindNavigationEvent(target_url, target_tab_id); |
168 if (!nav_event) { | 192 if (!nav_event) { |
169 // We cannot find a single navigation event related to this download. | 193 // We cannot find a single navigation event related to this download. |
170 return NAVIGATION_EVENT_NOT_FOUND; | 194 return NAVIGATION_EVENT_NOT_FOUND; |
171 } | 195 } |
196 AttributionResult result = SUCCESS; | |
197 AddToReferrerChain(out_referrer_chain, nav_event, | |
198 ReferrerChainEntry::DOWNLOAD_URL); | |
199 int user_gesture_count = 0; | |
200 GetRemainingReferrerChain( | |
201 nav_event, | |
202 user_gesture_count, | |
203 user_gesture_count_limit, | |
204 out_referrer_chain, | |
205 &result); | |
206 return result; | |
207 } | |
208 | |
209 SafeBrowsingNavigationObserverManager::AttributionResult | |
210 SafeBrowsingNavigationObserverManager::IdentifyReferrerChainForPPAPIDownload( | |
211 const GURL& initiating_frame_url, | |
212 content::WebContents* web_contents, | |
213 int user_gesture_count_limit, | |
214 std::vector<ReferrerChainEntry>* out_referrer_chain) { | |
215 if (!initiating_frame_url.is_valid()) | |
216 return INVALID_URL; | |
217 | |
218 int tab_id = SessionTabHelper::IdForTab(web_contents); | |
219 UMA_HISTOGRAM_BOOLEAN( | |
220 "SafeBrowsing.ReferrerHasInvalidTabID.PPAPIDownloadAttribution", | |
221 tab_id == -1); | |
222 | |
223 NavigationEvent* nav_event = FindNavigationEvent(initiating_frame_url, | |
224 tab_id); | |
225 if (!nav_event) { | |
226 // We cannot find a single navigation event related to this download. | |
227 return NAVIGATION_EVENT_NOT_FOUND; | |
228 } | |
172 | 229 |
173 AddToReferrerChain(out_referrer_chain, nav_event, | |
174 ReferrerChainEntry::DOWNLOAD_URL); | |
175 AttributionResult result = SUCCESS; | 230 AttributionResult result = SUCCESS; |
231 bool has_user_gesture = false; | |
232 auto it = user_gesture_map_.find(web_contents); | |
233 if (it != user_gesture_map_.end() && | |
234 !IsEventExpired(it->second, kUserGestureTTLInSecond)) { | |
235 has_user_gesture = true; | |
236 user_gesture_map_.erase(it); | |
237 } | |
238 | |
176 int user_gesture_count = 0; | 239 int user_gesture_count = 0; |
177 while (user_gesture_count < user_gesture_count_limit) { | 240 // If this initiating_frame has user gesture, we consider this as the landing |
178 // Back trace to the next nav_event that was initiated by the user. | 241 // page of the PPAPI download. |
179 while (!nav_event->is_user_initiated) { | 242 if (has_user_gesture) { |
180 nav_event = | 243 user_gesture_count = 1; |
181 FindNavigationEvent(nav_event->source_url, nav_event->source_tab_id); | 244 AddToReferrerChain(out_referrer_chain, nav_event, |
182 if (!nav_event) | 245 GetURLTypeAndAdjustAttributionResult( |
183 return result; | 246 user_gesture_count, |
184 AddToReferrerChain(out_referrer_chain, nav_event, | 247 user_gesture_count_limit, |
185 nav_event->has_server_redirect | 248 &result)); |
186 ? ReferrerChainEntry::SERVER_REDIRECT | 249 } else { |
187 : ReferrerChainEntry::CLIENT_REDIRECT); | 250 AddToReferrerChain(out_referrer_chain, nav_event, |
188 } | 251 nav_event->has_server_redirect |
252 ? ReferrerChainEntry::SERVER_REDIRECT | |
253 : ReferrerChainEntry::CLIENT_REDIRECT); | |
254 } | |
189 | 255 |
190 user_gesture_count++; | 256 GetRemainingReferrerChain( |
191 | 257 nav_event, |
192 // If the source_url and source_main_frame_url of current navigation event | 258 user_gesture_count, |
193 // are empty, and is_user_initiated is true, this is a browser initiated | 259 user_gesture_count_limit, |
194 // navigation (e.g. trigged by typing in address bar, clicking on bookmark, | 260 out_referrer_chain, |
195 // etc). We reached the end of the referrer chain. | 261 &result); |
196 if (nav_event->source_url.is_empty() && | |
197 nav_event->source_main_frame_url.is_empty()) { | |
198 DCHECK(nav_event->is_user_initiated); | |
199 return result; | |
200 } | |
201 | |
202 nav_event = | |
203 FindNavigationEvent(nav_event->source_url, nav_event->source_tab_id); | |
204 if (!nav_event) | |
205 return result; | |
206 | |
207 // Landing page of a download refers to the page user directly interacts | |
208 // with to trigger this download (e.g. clicking on download button). Landing | |
209 // referrer page is the one user interacts with right before navigating to | |
210 // the landing page. | |
211 // Since we are tracing navigations backwards, if we've encountered 1 user | |
212 // gesture before this navigation event, this is a navigation leading to the | |
213 // landing page. If we've encountered 2 user gestures, it leads to landing | |
214 // referrer page. | |
215 if (user_gesture_count == 1) { | |
216 AddToReferrerChain(out_referrer_chain, nav_event, | |
217 ReferrerChainEntry::LANDING_PAGE); | |
218 result = SUCCESS_LANDING_PAGE; | |
219 } else if (user_gesture_count == 2) { | |
220 AddToReferrerChain(out_referrer_chain, nav_event, | |
221 ReferrerChainEntry::LANDING_REFERRER); | |
222 result = SUCCESS_LANDING_REFERRER; | |
223 } else { | |
224 NOTREACHED(); | |
225 } | |
226 } | |
227 return result; | 262 return result; |
228 } | 263 } |
229 | 264 |
230 SafeBrowsingNavigationObserverManager:: | 265 SafeBrowsingNavigationObserverManager:: |
231 ~SafeBrowsingNavigationObserverManager() {} | 266 ~SafeBrowsingNavigationObserverManager() {} |
232 | 267 |
233 void SafeBrowsingNavigationObserverManager::Observe( | 268 void SafeBrowsingNavigationObserverManager::Observe( |
234 int type, | 269 int type, |
235 const content::NotificationSource& source, | 270 const content::NotificationSource& source, |
236 const content::NotificationDetails& details) { | 271 const content::NotificationDetails& details) { |
(...skipping 153 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
390 referrer_chain_entry.set_referrer_main_frame_url( | 425 referrer_chain_entry.set_referrer_main_frame_url( |
391 nav_event->source_main_frame_url.spec()); | 426 nav_event->source_main_frame_url.spec()); |
392 } | 427 } |
393 referrer_chain_entry.set_is_retargeting(nav_event->source_tab_id != | 428 referrer_chain_entry.set_is_retargeting(nav_event->source_tab_id != |
394 nav_event->target_tab_id); | 429 nav_event->target_tab_id); |
395 referrer_chain_entry.set_navigation_time_msec( | 430 referrer_chain_entry.set_navigation_time_msec( |
396 nav_event->last_updated.ToJavaTime()); | 431 nav_event->last_updated.ToJavaTime()); |
397 referrer_chain->push_back(std::move(referrer_chain_entry)); | 432 referrer_chain->push_back(std::move(referrer_chain_entry)); |
398 } | 433 } |
399 | 434 |
435 void SafeBrowsingNavigationObserverManager::GetRemainingReferrerChain( | |
436 NavigationEvent* last_nav_event_traced, | |
437 int current_user_gesture_count, | |
438 int user_gesture_count_limit, | |
439 std::vector<ReferrerChainEntry>* out_referrer_chain, | |
440 SafeBrowsingNavigationObserverManager::AttributionResult* out_result) { | |
441 | |
442 while (current_user_gesture_count < user_gesture_count_limit) { | |
443 // Back trace to the next nav_event that was initiated by the user. | |
444 while (!last_nav_event_traced->is_user_initiated) { | |
445 last_nav_event_traced = | |
446 FindNavigationEvent(last_nav_event_traced->source_url, | |
447 last_nav_event_traced->source_tab_id); | |
448 if (!last_nav_event_traced) | |
449 return; | |
450 AddToReferrerChain(out_referrer_chain, last_nav_event_traced, | |
451 last_nav_event_traced->has_server_redirect | |
452 ? ReferrerChainEntry::SERVER_REDIRECT | |
453 : ReferrerChainEntry::CLIENT_REDIRECT); | |
454 } | |
455 | |
456 current_user_gesture_count++; | |
457 | |
458 | |
459 // If the source_url and source_main_frame_url of current navigation event | |
460 // are empty, and is_user_initiated is true, this is a browser initiated | |
461 // navigation (e.g. trigged by typing in address bar, clicking on bookmark, | |
462 // etc). We reached the end of the referrer chain. | |
463 if (last_nav_event_traced->source_url.is_empty() && | |
Nathan Parker
2017/01/04 19:49:12
q: Up above in a few places is_valid() is used. I
Jialiu Lin
2017/01/04 21:53:35
invalid url could be empty or malformatted. Here I
| |
464 last_nav_event_traced->source_main_frame_url.is_empty()) { | |
465 DCHECK(last_nav_event_traced->is_user_initiated); | |
466 return; | |
467 } | |
468 | |
469 last_nav_event_traced = | |
470 FindNavigationEvent(last_nav_event_traced->source_url, | |
471 last_nav_event_traced->source_tab_id); | |
472 if (!last_nav_event_traced) | |
473 return; | |
474 | |
475 AddToReferrerChain(out_referrer_chain, last_nav_event_traced, | |
476 GetURLTypeAndAdjustAttributionResult( | |
477 current_user_gesture_count, | |
478 user_gesture_count_limit, | |
479 out_result)); | |
480 } | |
481 } | |
482 | |
400 } // namespace safe_browsing | 483 } // namespace safe_browsing |
OLD | NEW |