| Index: chrome/browser/safe_browsing/safe_browsing_navigation_observer.cc | 
| diff --git a/chrome/browser/safe_browsing/safe_browsing_navigation_observer.cc b/chrome/browser/safe_browsing/safe_browsing_navigation_observer.cc | 
| new file mode 100644 | 
| index 0000000000000000000000000000000000000000..30ffaa0f0bb3691fa6655f00df804cd86d1b954a | 
| --- /dev/null | 
| +++ b/chrome/browser/safe_browsing/safe_browsing_navigation_observer.cc | 
| @@ -0,0 +1,216 @@ | 
| +// 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.h" | 
| + | 
| +#include "base/memory/ptr_util.h" | 
| +#include "base/time/time.h" | 
| +#include "chrome/browser/safe_browsing/safe_browsing_navigation_observer_manager.h" | 
| +#include "chrome/browser/sessions/session_tab_helper.h" | 
| +#include "content/public/browser/navigation_handle.h" | 
| +#include "content/public/browser/render_frame_host.h" | 
| +#include "content/public/browser/resource_request_details.h" | 
| +#include "content/public/browser/web_contents.h" | 
| +#include "content/public/common/resource_type.h" | 
| + | 
| +using content::WebContents; | 
| + | 
| +namespace { | 
| +const char kWebContentsUserDataKey[] = | 
| +    "web_contents_safe_browsing_navigation_observer"; | 
| +}  // namespace | 
| + | 
| +namespace safe_browsing { | 
| + | 
| +// SafeBrowsingNavigationObserver::NavigationEvent----------------------------- | 
| +NavigationEvent::NavigationEvent() | 
| +    : source_url(), | 
| +      source_tab_id(-1), | 
| +      target_url(), | 
| +      target_tab_id(-1), | 
| +      frame_id(-1), | 
| +      main_frame_url(), | 
| +      timestamp(base::Time::Now()), | 
| +      is_user_initiated(false), | 
| +      has_committed(false), | 
| +      has_server_redirect(false), | 
| +      server_redirect_url() {} | 
| + | 
| +NavigationEvent::NavigationEvent(NavigationEvent&& nav_event) | 
| +    : source_url(std::move(nav_event.source_url)), | 
| +      source_tab_id(std::move(nav_event.source_tab_id)), | 
| +      target_url(std::move(nav_event.target_url)), | 
| +      target_tab_id(std::move(nav_event.target_tab_id)), | 
| +      frame_id(nav_event.frame_id), | 
| +      main_frame_url(std::move(nav_event.main_frame_url)), | 
| +      timestamp(nav_event.timestamp), | 
| +      is_user_initiated(nav_event.is_user_initiated), | 
| +      has_committed(nav_event.has_committed), | 
| +      has_server_redirect(nav_event.has_server_redirect), | 
| +      server_redirect_url(std::move(nav_event.server_redirect_url)) {} | 
| + | 
| +NavigationEvent& NavigationEvent::operator=(NavigationEvent&& nav_event) { | 
| +  source_url = std::move(nav_event.source_url); | 
| +  source_tab_id = std::move(nav_event.source_tab_id); | 
| +  target_url = std::move(nav_event.target_url); | 
| +  target_tab_id = std::move(nav_event.target_tab_id); | 
| +  frame_id = nav_event.frame_id; | 
| +  main_frame_url = std::move(nav_event.main_frame_url); | 
| +  timestamp = nav_event.timestamp; | 
| +  is_user_initiated = nav_event.is_user_initiated; | 
| +  has_committed = nav_event.has_committed; | 
| +  has_server_redirect = nav_event.has_server_redirect; | 
| +  server_redirect_url = std::move(nav_event.server_redirect_url); | 
| +  return *this; | 
| +} | 
| + | 
| +NavigationEvent::~NavigationEvent() {} | 
| + | 
| +// SafeBrowsingNavigationObserver -------------------------------------------- | 
| + | 
| +// static | 
| +void SafeBrowsingNavigationObserver::MaybeCreateForWebContents( | 
| +    content::WebContents* web_contents) { | 
| +  if (FromWebContents(web_contents)) | 
| +    return; | 
| +  NOTIMPLEMENTED(); | 
| +  // TODO(jialiul): This method will be called by TabHelpers::AttachTabHelpers. | 
| +  // Complete this method when the entire class is ready. | 
| +} | 
| + | 
| +// static | 
| +SafeBrowsingNavigationObserver* SafeBrowsingNavigationObserver::FromWebContents( | 
| +    content::WebContents* web_contents) { | 
| +  return static_cast<SafeBrowsingNavigationObserver*>( | 
| +      web_contents->GetUserData(kWebContentsUserDataKey)); | 
| +} | 
| + | 
| +SafeBrowsingNavigationObserver::SafeBrowsingNavigationObserver( | 
| +    content::WebContents* contents, | 
| +    const scoped_refptr<SafeBrowsingNavigationObserverManager>& manager) | 
| +    : content::WebContentsObserver(contents), | 
| +      manager_(manager), | 
| +      has_user_gesture_(false), | 
| +      last_user_gesture_timestamp_(base::Time::Now()) {} | 
| + | 
| +SafeBrowsingNavigationObserver::~SafeBrowsingNavigationObserver() {} | 
| + | 
| +// Called when a navigation started in the WebContents. |navigation_handle| in | 
| +// paramter is unique to this navigation, which will appear in the following | 
| +// DidRedirectNavigation, and DidFinishNavigation too. | 
| +void SafeBrowsingNavigationObserver::DidStartNavigation( | 
| +    content::NavigationHandle* navigation_handle) { | 
| +  // If we already seen this navigation_handle before, no need to do anything. | 
| +  if (navigation_handle_map_.find(navigation_handle) != | 
| +      navigation_handle_map_.end()) | 
| +    return; | 
| + | 
| +  // Construct a NavigationEvent based on available information in | 
| +  // navigation_handle. | 
| +  NavigationEvent nav_event; | 
| +  content::RenderFrameHost* host = | 
| +      navigation_handle->GetWebContents()->FindFrameByFrameTreeNodeId( | 
| +          navigation_handle->GetFrameTreeNodeId()); | 
| + | 
| +  // If there was URL previously committed in this render frame host, | 
| +  // set it as the source url of this navigation. Otherwise, this is the | 
| +  // first url going to commit in this frame. We set navigation_handle's URL as | 
| +  // the source url. | 
| +  if (host && host->GetLastCommittedURL().is_valid()) { | 
| +    nav_event.source_url = SafeBrowsingNavigationObserverManager::ClearURLRef( | 
| +        host->GetLastCommittedURL()); | 
| +  } else { | 
| +    nav_event.source_url = SafeBrowsingNavigationObserverManager::ClearURLRef( | 
| +        navigation_handle->GetURL()); | 
| +  } | 
| +  nav_event.target_url = SafeBrowsingNavigationObserverManager::ClearURLRef( | 
| +      navigation_handle->GetURL()); | 
| + | 
| +  nav_event.source_tab_id = | 
| +      SessionTabHelper::IdForTab(navigation_handle->GetWebContents()); | 
| +  nav_event.timestamp = base::Time::Now(); | 
| +  nav_event.frame_id = navigation_handle->GetFrameTreeNodeId(); | 
| + | 
| +  if (navigation_handle->IsInMainFrame()) { | 
| +    nav_event.main_frame_url = nav_event.source_url; | 
| +  } else { | 
| +    nav_event.main_frame_url = | 
| +        SafeBrowsingNavigationObserverManager::ClearURLRef( | 
| +            navigation_handle->GetWebContents()->GetLastCommittedURL()); | 
| +  } | 
| +  if (has_user_gesture_ && | 
| +      !SafeBrowsingNavigationObserverManager::IsUserGestureExpired( | 
| +          last_user_gesture_timestamp_)) { | 
| +    nav_event.is_user_initiated = has_user_gesture_; | 
| +    manager_->OnUserGestureConsumed(web_contents(), | 
| +                                    last_user_gesture_timestamp_); | 
| +  } | 
| +  has_user_gesture_ = false; | 
| +  navigation_handle_map_.insert( | 
| +      std::make_pair(navigation_handle, std::move(nav_event))); | 
| +} | 
| + | 
| +void SafeBrowsingNavigationObserver::DidRedirectNavigation( | 
| +    content::NavigationHandle* navigation_handle) { | 
| +  // We should have already seen this navigation_handle in DidStartNavigation. | 
| +  if (navigation_handle_map_.find(navigation_handle) == | 
| +      navigation_handle_map_.end()) | 
| +    return; | 
| + | 
| +  NavigationEvent* nav_event = &navigation_handle_map_[navigation_handle]; | 
| +  nav_event->has_server_redirect = true; | 
| +  nav_event->server_redirect_url = | 
| +      SafeBrowsingNavigationObserverManager::ClearURLRef( | 
| +          navigation_handle->GetURL()); | 
| +  nav_event->timestamp = base::Time::Now(); | 
| +} | 
| + | 
| +void SafeBrowsingNavigationObserver::DidFinishNavigation( | 
| +    content::NavigationHandle* navigation_handle) { | 
| +  if (navigation_handle_map_.find(navigation_handle) == | 
| +      navigation_handle_map_.end()) | 
| +    return; | 
| + | 
| +  // If it is an error page, we ignore this navigation. | 
| +  if (navigation_handle->IsErrorPage()) { | 
| +    navigation_handle_map_.erase(navigation_handle); | 
| +    return; | 
| +  } | 
| +  NavigationEvent* nav_event = &navigation_handle_map_[navigation_handle]; | 
| + | 
| +  // Set is_user_initiated to has_user_gesture || browser_initiated. | 
| +  nav_event->is_user_initiated = | 
| +      nav_event->is_user_initiated || !navigation_handle->IsRendererInitiated(); | 
| +  nav_event->has_committed = navigation_handle->HasCommitted(); | 
| +  nav_event->target_tab_id = | 
| +      SessionTabHelper::IdForTab(navigation_handle->GetWebContents()); | 
| +  nav_event->timestamp = base::Time::Now(); | 
| + | 
| +  GURL nav_event_key = | 
| +      navigation_handle->HasCommitted() | 
| +          ? SafeBrowsingNavigationObserverManager::ClearURLRef( | 
| +                navigation_handle->GetRenderFrameHost()->GetLastCommittedURL()) | 
| +          : nav_event->has_server_redirect ? nav_event->server_redirect_url | 
| +                                          : nav_event->target_url; | 
| +  manager_->RecordNavigationEvent(nav_event_key, nav_event); | 
| +  navigation_handle_map_.erase(navigation_handle); | 
| +} | 
| + | 
| +void SafeBrowsingNavigationObserver::DidGetUserInteraction( | 
| +    const blink::WebInputEvent::Type type) { | 
| +  last_user_gesture_timestamp_ = base::Time::Now(); | 
| +  has_user_gesture_ = true; | 
| +  // TODO (jialiul): Refine user gesture logic when DidOpenRequestedURL | 
| +  // covers all retargetting cases. | 
| +  manager_->RecordUserGestureForWebContents(web_contents(), | 
| +                                            last_user_gesture_timestamp_); | 
| +} | 
| + | 
| +void SafeBrowsingNavigationObserver::WebContentsDestroyed() { | 
| +  manager_->OnWebContentDestroyed(web_contents()); | 
| +  web_contents()->RemoveUserData(kWebContentsUserDataKey); | 
| +  // web_contents is null after this function. | 
| +} | 
| + | 
| +}  // namespace safe_browsing | 
|  |