| 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
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..14fdb02acfce05e181fb1fba65d93e5912671441
|
| --- /dev/null
|
| +++ b/chrome/browser/safe_browsing/safe_browsing_navigation_observer_manager.cc
|
| @@ -0,0 +1,169 @@
|
| +// Copyright 2016 The Chromium Authors. All rights reserved.
|
| +// Use of this source code is governed by a BSD-style license that can be
|
| +// found in the LICENSE file.
|
| +
|
| +#include "chrome/browser/safe_browsing/safe_browsing_navigation_observer_manager.h"
|
| +
|
| +#include "base/memory/ptr_util.h"
|
| +#include "base/time/time.h"
|
| +#include "chrome/browser/chrome_notification_types.h"
|
| +#include "chrome/browser/safe_browsing/safe_browsing_navigation_observer.h"
|
| +#include "chrome/browser/sessions/session_tab_helper.h"
|
| +#include "chrome/browser/tab_contents/retargeting_details.h"
|
| +#include "content/public/browser/navigation_details.h"
|
| +#include "content/public/browser/notification_service.h"
|
| +#include "content/public/browser/notification_types.h"
|
| +#include "content/public/browser/render_frame_host.h"
|
| +#include "content/public/browser/render_process_host.h"
|
| +#include "content/public/browser/web_contents.h"
|
| +
|
| +using content::WebContents;
|
| +
|
| +namespace safe_browsing {
|
| +
|
| +// The expiration period of a user gesture. Any user gesture that happened 1.0
|
| +// second ago will be considered as expired and not relevant to upcoming
|
| +// navigation events.
|
| +static const double kUserGestureTTLInSecond = 1.0;
|
| +
|
| +// static
|
| +bool SafeBrowsingNavigationObserverManager::IsUserGestureExpired(
|
| + const base::Time& timestamp) {
|
| + double now = base::Time::Now().ToDoubleT();
|
| + double timestamp_in_double = timestamp.ToDoubleT();
|
| +
|
| + if (now <= timestamp_in_double)
|
| + return true;
|
| + return (now - timestamp_in_double) > kUserGestureTTLInSecond;
|
| +}
|
| +
|
| +// static
|
| +GURL SafeBrowsingNavigationObserverManager::ClearEmptyRef(const GURL& url) {
|
| + if (url.has_ref() && url.ref().empty()) {
|
| + url::Replacements<char> replacements;
|
| + replacements.ClearRef();
|
| + return url.ReplaceComponents(replacements);
|
| + }
|
| + return url;
|
| +}
|
| +
|
| +SafeBrowsingNavigationObserverManager::SafeBrowsingNavigationObserverManager() {
|
| + registrar_.Add(this, chrome::NOTIFICATION_RETARGETING,
|
| + content::NotificationService::AllSources());
|
| +}
|
| +
|
| +void SafeBrowsingNavigationObserverManager::RecordNavigationEvent(
|
| + const GURL& nav_event_key,
|
| + NavigationEvent* nav_event) {
|
| + auto insertion_result = navigation_map_.insert(
|
| + std::make_pair(nav_event_key, std::vector<NavigationEvent>()));
|
| +
|
| + insertion_result.first->second.push_back(std::move(*nav_event));
|
| +}
|
| +
|
| +void SafeBrowsingNavigationObserverManager::RecordUserGestureForWebContents(
|
| + content::WebContents* web_contents,
|
| + const base::Time& timestamp) {
|
| + auto insertion_result =
|
| + user_gesture_map_.insert(std::make_pair(web_contents, timestamp));
|
| + // Update the timestamp if entry already exists.
|
| + if (!insertion_result.second)
|
| + insertion_result.first->second = timestamp;
|
| +}
|
| +
|
| +void SafeBrowsingNavigationObserverManager::OnUserGestureConsumed(
|
| + content::WebContents* web_contents,
|
| + const base::Time& timestamp) {
|
| + auto it = user_gesture_map_.find(web_contents);
|
| + // Remove entry from |user_gesture_map_| as a user_gesture is consumed by
|
| + // a navigation event.
|
| + if (it != user_gesture_map_.end() && timestamp >= it->second)
|
| + user_gesture_map_.erase(it);
|
| +}
|
| +
|
| +void SafeBrowsingNavigationObserverManager::RecordHostToIpMapping(
|
| + const std::string& host,
|
| + const std::string& ip) {
|
| + auto insert_result = host_to_ip_map_.insert(
|
| + std::make_pair(host, std::vector<ResolvedIPAddress>()));
|
| + if (!insert_result.second) {
|
| + // host_to_ip_map already contains this key.
|
| + // If this IP is already in the vector, we update its timestamp.
|
| + for (auto& vector_entry : insert_result.first->second) {
|
| + if (vector_entry.ip == host) {
|
| + vector_entry.timestamp = base::Time::Now();
|
| + return;
|
| + }
|
| + }
|
| + }
|
| + // If this is a new IP of this host, and we added to the end of the vector.
|
| + insert_result.first->second.push_back(
|
| + ResolvedIPAddress(base::Time::Now(), ip));
|
| +}
|
| +
|
| +void SafeBrowsingNavigationObserverManager::OnWebContentDestroyed(
|
| + content::WebContents* web_contents) {
|
| + user_gesture_map_.erase(web_contents);
|
| + // TODO (jialiul): Will add other clean up tasks shortly.
|
| +}
|
| +
|
| +SafeBrowsingNavigationObserverManager::
|
| + ~SafeBrowsingNavigationObserverManager() {}
|
| +
|
| +void SafeBrowsingNavigationObserverManager::Observe(
|
| + int type,
|
| + const content::NotificationSource& source,
|
| + const content::NotificationDetails& details) {
|
| + if (type == chrome::NOTIFICATION_RETARGETING)
|
| + RecordRetargeting(details);
|
| +}
|
| +
|
| +void SafeBrowsingNavigationObserverManager::RecordRetargeting(
|
| + const content::NotificationDetails& details) {
|
| + const RetargetingDetails* retargeting_detail =
|
| + content::Details<const RetargetingDetails>(details).ptr();
|
| + DCHECK(retargeting_detail);
|
| + content::WebContents* source_contents =
|
| + retargeting_detail->source_web_contents;
|
| + content::WebContents* target_contents =
|
| + retargeting_detail->target_web_contents;
|
| + DCHECK(source_contents);
|
| + DCHECK(target_contents);
|
| +
|
| + content::RenderFrameHost* rfh = content::RenderFrameHost::FromID(
|
| + retargeting_detail->source_render_process_id,
|
| + retargeting_detail->source_render_frame_id);
|
| + // Remove the "#" at the end of URL, since it does not point to any actual
|
| + // page fragment ID.
|
| + GURL target_url = SafeBrowsingNavigationObserverManager::ClearEmptyRef(
|
| + retargeting_detail->target_url);
|
| +
|
| + NavigationEvent nav_event;
|
| + if (rfh) {
|
| + nav_event.source_url = SafeBrowsingNavigationObserverManager::ClearEmptyRef(
|
| + rfh->GetLastCommittedURL());
|
| + }
|
| + nav_event.source_tab_id = SessionTabHelper::IdForTab(source_contents);
|
| + nav_event.source_main_frame_url =
|
| + SafeBrowsingNavigationObserverManager::ClearEmptyRef(
|
| + source_contents->GetLastCommittedURL());
|
| + nav_event.original_request_url = target_url;
|
| + nav_event.destination_url = target_url;
|
| + nav_event.target_tab_id = SessionTabHelper::IdForTab(target_contents);
|
| + nav_event.frame_id = rfh ? rfh->GetFrameTreeNodeId() : -1;
|
| + auto it = user_gesture_map_.find(source_contents);
|
| + if (it != user_gesture_map_.end() &&
|
| + !SafeBrowsingNavigationObserverManager::IsUserGestureExpired(
|
| + it->second)) {
|
| + nav_event.is_user_initiated = true;
|
| + OnUserGestureConsumed(it->first, it->second);
|
| + } else {
|
| + nav_event.is_user_initiated = false;
|
| + }
|
| +
|
| + auto insertion_result = navigation_map_.insert(
|
| + std::make_pair(target_url, std::vector<NavigationEvent>()));
|
| + insertion_result.first->second.push_back(std::move(nav_event));
|
| +}
|
| +
|
| +} // namespace safe_browsing
|
|
|