Index: chrome/browser/safe_browsing/safe_browsing_navigation_observer_manager.cc |
diff --git a/chrome/browser/safe_browsing/safe_browsing_navigation_observer_manager.cc b/chrome/browser/safe_browsing/safe_browsing_navigation_observer_manager.cc |
index 45207a1c0a7de7bb4cc8afe044b905676e930f97..c621d8646ba7f5f3b369aefc720316f937644690 100644 |
--- a/chrome/browser/safe_browsing/safe_browsing_navigation_observer_manager.cc |
+++ b/chrome/browser/safe_browsing/safe_browsing_navigation_observer_manager.cc |
@@ -42,6 +42,28 @@ bool IsEventExpired(const base::Time& event_time, double ttl_in_second) { |
return current_time_in_second - event_time_in_second > ttl_in_second; |
} |
+// Helper function to determine if the URL type should be LANDING_REFERRER or |
+// LANDING_PAGE, and modify AttributionResult accordingly. |
+ReferrerChainEntry::URLType GetURLTypeAndAdjustAttributionResult( |
+ bool at_user_gesture_limit, |
+ SafeBrowsingNavigationObserverManager::AttributionResult* out_result) { |
+ // Landing page of a download refers to the page user directly interacts |
+ // with to trigger this download (e.g. clicking on download button). Landing |
+ // referrer page is the one user interacts with right before navigating to |
+ // the landing page. |
+ // Since we are tracing navigations backwards, if we've reached |
+ // user gesture limit before this navigation event, this is a navigation |
+ // leading to the landing referrer page, otherwise it leads to landing page. |
+ if (at_user_gesture_limit) { |
+ *out_result = |
+ SafeBrowsingNavigationObserverManager::SUCCESS_LANDING_REFERRER; |
+ return ReferrerChainEntry::LANDING_REFERRER; |
+ } else { |
+ *out_result = SafeBrowsingNavigationObserverManager::SUCCESS_LANDING_PAGE; |
+ return ReferrerChainEntry::LANDING_PAGE; |
+ } |
+} |
+ |
} // namespace |
// The expiration period of a user gesture. Any user gesture that happened 1.0 |
@@ -122,6 +144,18 @@ void SafeBrowsingNavigationObserverManager::OnUserGestureConsumed( |
user_gesture_map_.erase(it); |
} |
+bool SafeBrowsingNavigationObserverManager::HasUserGesture( |
+ content::WebContents* web_contents) { |
+ if (!web_contents) |
+ return false; |
+ auto it = user_gesture_map_.find(web_contents); |
+ if (it != user_gesture_map_.end() && |
+ !IsEventExpired(it->second, kUserGestureTTLInSecond)) { |
+ return true; |
+ } |
+ return false; |
+} |
+ |
void SafeBrowsingNavigationObserverManager::RecordHostToIpMapping( |
const std::string& host, |
const std::string& ip) { |
@@ -156,7 +190,7 @@ void SafeBrowsingNavigationObserverManager::CleanUpStaleNavigationFootprints() { |
} |
SafeBrowsingNavigationObserverManager::AttributionResult |
-SafeBrowsingNavigationObserverManager::IdentifyReferrerChain( |
+SafeBrowsingNavigationObserverManager::IdentifyReferrerChainForDownload( |
const GURL& target_url, |
int target_tab_id, |
int user_gesture_count_limit, |
@@ -172,65 +206,60 @@ SafeBrowsingNavigationObserverManager::IdentifyReferrerChain( |
// We cannot find a single navigation event related to this download. |
return NAVIGATION_EVENT_NOT_FOUND; |
} |
- |
+ AttributionResult result = SUCCESS; |
AddToReferrerChain(out_referrer_chain, nav_event, |
ReferrerChainEntry::DOWNLOAD_URL); |
- AttributionResult result = SUCCESS; |
int user_gesture_count = 0; |
- while (user_gesture_count < user_gesture_count_limit) { |
- // Back trace to the next nav_event that was initiated by the user. |
- while (!nav_event->is_user_initiated) { |
- nav_event = |
- FindNavigationEvent(nav_event->source_url, |
- nav_event->source_main_frame_url, |
- nav_event->source_tab_id); |
- if (!nav_event) |
- return result; |
- AddToReferrerChain(out_referrer_chain, nav_event, |
- nav_event->has_server_redirect |
- ? ReferrerChainEntry::SERVER_REDIRECT |
- : ReferrerChainEntry::CLIENT_REDIRECT); |
- } |
+ GetRemainingReferrerChain( |
+ nav_event, |
+ user_gesture_count, |
+ user_gesture_count_limit, |
+ out_referrer_chain, |
+ &result); |
+ return result; |
+} |
- user_gesture_count++; |
+SafeBrowsingNavigationObserverManager::AttributionResult |
+SafeBrowsingNavigationObserverManager::IdentifyReferrerChainForPPAPIDownload( |
+ const GURL& initiating_frame_url, |
+ int tab_id, |
+ bool has_user_gesture, |
+ int user_gesture_count_limit, |
+ std::vector<ReferrerChainEntry>* out_referrer_chain) { |
+ if (!initiating_frame_url.is_valid()) |
+ return INVALID_URL; |
- // If the source_url and source_main_frame_url of current navigation event |
- // are empty, and is_user_initiated is true, this is a browser initiated |
- // navigation (e.g. trigged by typing in address bar, clicking on bookmark, |
- // etc). We reached the end of the referrer chain. |
- if (nav_event->source_url.is_empty() && |
- nav_event->source_main_frame_url.is_empty()) { |
- DCHECK(nav_event->is_user_initiated); |
- return result; |
- } |
+ NavigationEvent* nav_event = |
+ FindNavigationEvent(initiating_frame_url, GURL(), tab_id); |
+ if (!nav_event) { |
+ // We cannot find a single navigation event related to this download. |
+ return NAVIGATION_EVENT_NOT_FOUND; |
+ } |
- nav_event = |
- FindNavigationEvent(nav_event->source_url, |
- nav_event->source_main_frame_url, |
- nav_event->source_tab_id); |
- if (!nav_event) |
- return result; |
- |
- // Landing page of a download refers to the page user directly interacts |
- // with to trigger this download (e.g. clicking on download button). Landing |
- // referrer page is the one user interacts with right before navigating to |
- // the landing page. |
- // Since we are tracing navigations backwards, if we've encountered 1 user |
- // gesture before this navigation event, this is a navigation leading to the |
- // landing page. If we've encountered 2 user gestures, it leads to landing |
- // referrer page. |
- if (user_gesture_count == 1) { |
- AddToReferrerChain(out_referrer_chain, nav_event, |
- ReferrerChainEntry::LANDING_PAGE); |
- result = SUCCESS_LANDING_PAGE; |
- } else if (user_gesture_count == 2) { |
- AddToReferrerChain(out_referrer_chain, nav_event, |
- ReferrerChainEntry::LANDING_REFERRER); |
- result = SUCCESS_LANDING_REFERRER; |
- } else { |
- NOTREACHED(); |
- } |
+ AttributionResult result = SUCCESS; |
+ |
+ int user_gesture_count = 0; |
+ // If this initiating_frame has user gesture, we consider this as the landing |
+ // page of the PPAPI download. |
+ if (has_user_gesture) { |
+ user_gesture_count = 1; |
+ AddToReferrerChain(out_referrer_chain, nav_event, |
+ GetURLTypeAndAdjustAttributionResult( |
+ user_gesture_count == user_gesture_count_limit, |
+ &result)); |
+ } else { |
+ AddToReferrerChain(out_referrer_chain, nav_event, |
+ nav_event->has_server_redirect |
+ ? ReferrerChainEntry::SERVER_REDIRECT |
+ : ReferrerChainEntry::CLIENT_REDIRECT); |
} |
+ |
+ GetRemainingReferrerChain( |
+ nav_event, |
+ user_gesture_count, |
+ user_gesture_count_limit, |
+ out_referrer_chain, |
+ &result); |
return result; |
} |
@@ -358,17 +387,17 @@ NavigationEvent* SafeBrowsingNavigationObserverManager::FindNavigationEvent( |
// If target_url is empty, we should back trace navigation based on its |
// main frame URL instead. |
- const GURL& search_url = |
+ GURL search_url = |
target_url.is_empty() ? target_main_frame_url : target_url; |
- |
auto it = navigation_map_.find(search_url); |
- if (it == navigation_map_.end()) { |
+ if (it == navigation_map_.end()) |
return nullptr; |
- } |
+ |
// Since navigation events are recorded in chronological order, we traverse |
// the vector in reverse order to get the latest match. |
for (auto rit = it->second.rbegin(); rit != it->second.rend(); ++rit) { |
// If tab id is not valid, we only compare url, otherwise we compare both. |
+ if (rit->destination_url == search_url) |
if (rit->destination_url == search_url && |
(target_tab_id == -1 || rit->target_tab_id == target_tab_id)) { |
// If both source_url and source_main_frame_url are empty, and this |
@@ -377,7 +406,20 @@ NavigationEvent* SafeBrowsingNavigationObserverManager::FindNavigationEvent( |
// looks for the retargeting navigation event. |
if (rit->source_url.is_empty() && rit->source_main_frame_url.is_empty() && |
!rit->is_user_initiated) { |
- continue; |
+ // If there is a server redirection immediately after retargeting, we |
+ // need to adjust our search url to the original request. |
+ if (rit->has_server_redirect){ |
+ NavigationEvent* retargeting_nav_event = |
+ FindNavigationEvent(rit->original_request_url, |
+ GURL(), |
+ rit->target_tab_id); |
+ // Adjust retargeting navigation event's attributes. |
+ retargeting_nav_event->has_server_redirect = true; |
+ retargeting_nav_event->destination_url = search_url; |
+ return retargeting_nav_event; |
+ } else { |
+ continue; |
+ } |
} else { |
return &*rit; |
} |
@@ -413,4 +455,54 @@ void SafeBrowsingNavigationObserverManager::AddToReferrerChain( |
referrer_chain->push_back(std::move(referrer_chain_entry)); |
} |
+void SafeBrowsingNavigationObserverManager::GetRemainingReferrerChain( |
+ NavigationEvent* last_nav_event_traced, |
+ int current_user_gesture_count, |
+ int user_gesture_count_limit, |
+ std::vector<ReferrerChainEntry>* out_referrer_chain, |
+ SafeBrowsingNavigationObserverManager::AttributionResult* out_result) { |
+ |
+ while (current_user_gesture_count < user_gesture_count_limit) { |
+ // Back trace to the next nav_event that was initiated by the user. |
+ while (!last_nav_event_traced->is_user_initiated) { |
+ last_nav_event_traced = |
+ FindNavigationEvent(last_nav_event_traced->source_url, |
+ last_nav_event_traced->source_main_frame_url, |
+ last_nav_event_traced->source_tab_id); |
+ if (!last_nav_event_traced) |
+ return; |
+ AddToReferrerChain(out_referrer_chain, last_nav_event_traced, |
+ last_nav_event_traced->has_server_redirect |
+ ? ReferrerChainEntry::SERVER_REDIRECT |
+ : ReferrerChainEntry::CLIENT_REDIRECT); |
+ } |
+ |
+ current_user_gesture_count++; |
+ |
+ |
+ // If the source_url and source_main_frame_url of current navigation event |
+ // are empty, and is_user_initiated is true, this is a browser initiated |
+ // navigation (e.g. trigged by typing in address bar, clicking on bookmark, |
+ // etc). We reached the end of the referrer chain. |
+ if (last_nav_event_traced->source_url.is_empty() && |
+ last_nav_event_traced->source_main_frame_url.is_empty()) { |
+ DCHECK(last_nav_event_traced->is_user_initiated); |
+ return; |
+ } |
+ |
+ last_nav_event_traced = |
+ FindNavigationEvent(last_nav_event_traced->source_url, |
+ last_nav_event_traced->source_main_frame_url, |
+ last_nav_event_traced->source_tab_id); |
+ if (!last_nav_event_traced) |
+ return; |
+ |
+ AddToReferrerChain(out_referrer_chain, last_nav_event_traced, |
+ GetURLTypeAndAdjustAttributionResult( |
+ current_user_gesture_count == |
+ user_gesture_count_limit, |
+ out_result)); |
+ } |
+} |
+ |
} // namespace safe_browsing |