Chromium Code Reviews| 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 |