| OLD | NEW | 
|---|
|  | (Empty) | 
| 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 |  | 
| 3 // found in the LICENSE file. |  | 
| 4 |  | 
| 5 #include "chrome/browser/safe_browsing/safe_browsing_navigation_observer.h" |  | 
| 6 |  | 
| 7 #include "base/memory/ptr_util.h" |  | 
| 8 #include "base/time/time.h" |  | 
| 9 #include "chrome/browser/safe_browsing/safe_browsing_navigation_observer_manager
     .h" |  | 
| 10 #include "chrome/browser/sessions/session_tab_helper.h" |  | 
| 11 #include "content/public/browser/navigation_handle.h" |  | 
| 12 #include "content/public/browser/render_frame_host.h" |  | 
| 13 #include "content/public/browser/resource_request_details.h" |  | 
| 14 #include "content/public/browser/web_contents.h" |  | 
| 15 #include "content/public/common/resource_type.h" |  | 
| 16 |  | 
| 17 using content::WebContents; |  | 
| 18 |  | 
| 19 namespace { |  | 
| 20 const char kWebContentsUserDataKey[] = |  | 
| 21     "web_contents_safe_browsing_navigation_observer"; |  | 
| 22 }  // namespace |  | 
| 23 |  | 
| 24 namespace safe_browsing { |  | 
| 25 |  | 
| 26 // SafeBrowsingNavigationObserver::NavigationEvent----------------------------- |  | 
| 27 NavigationEvent::NavigationEvent() |  | 
| 28     : source_url(), |  | 
| 29       source_main_frame_url(), |  | 
| 30       original_request_url(), |  | 
| 31       destination_url(), |  | 
| 32       source_tab_id(-1), |  | 
| 33       target_tab_id(-1), |  | 
| 34       frame_id(-1), |  | 
| 35       last_updated(base::Time::Now()), |  | 
| 36       is_user_initiated(false), |  | 
| 37       has_committed(false), |  | 
| 38       has_server_redirect(false) {} |  | 
| 39 |  | 
| 40 NavigationEvent::NavigationEvent(NavigationEvent&& nav_event) |  | 
| 41     : source_url(std::move(nav_event.source_url)), |  | 
| 42       source_main_frame_url(std::move(nav_event.source_main_frame_url)), |  | 
| 43       original_request_url(std::move(nav_event.original_request_url)), |  | 
| 44       destination_url(std::move(nav_event.destination_url)), |  | 
| 45       source_tab_id(std::move(nav_event.source_tab_id)), |  | 
| 46       target_tab_id(std::move(nav_event.target_tab_id)), |  | 
| 47       frame_id(nav_event.frame_id), |  | 
| 48       last_updated(nav_event.last_updated), |  | 
| 49       is_user_initiated(nav_event.is_user_initiated), |  | 
| 50       has_committed(nav_event.has_committed), |  | 
| 51       has_server_redirect(nav_event.has_server_redirect) {} |  | 
| 52 |  | 
| 53 NavigationEvent& NavigationEvent::operator=(NavigationEvent&& nav_event) { |  | 
| 54   source_url = std::move(nav_event.source_url); |  | 
| 55   source_main_frame_url = std::move(nav_event.source_main_frame_url); |  | 
| 56   original_request_url = std::move(nav_event.original_request_url); |  | 
| 57   destination_url = std::move(nav_event.destination_url); |  | 
| 58   source_tab_id = nav_event.source_tab_id; |  | 
| 59   target_tab_id = nav_event.target_tab_id; |  | 
| 60   frame_id = nav_event.frame_id; |  | 
| 61   last_updated = nav_event.last_updated; |  | 
| 62   is_user_initiated = nav_event.is_user_initiated; |  | 
| 63   has_committed = nav_event.has_committed; |  | 
| 64   has_server_redirect = nav_event.has_server_redirect; |  | 
| 65   return *this; |  | 
| 66 } |  | 
| 67 |  | 
| 68 NavigationEvent::~NavigationEvent() {} |  | 
| 69 |  | 
| 70 // SafeBrowsingNavigationObserver -------------------------------------------- |  | 
| 71 |  | 
| 72 // static |  | 
| 73 void SafeBrowsingNavigationObserver::MaybeCreateForWebContents( |  | 
| 74     content::WebContents* web_contents) { |  | 
| 75   if (FromWebContents(web_contents)) |  | 
| 76     return; |  | 
| 77   // TODO(jialiul): This method will be called by TabHelpers::AttachTabHelpers. |  | 
| 78   // Complete this method when the entire class is ready. |  | 
| 79   NOTIMPLEMENTED(); |  | 
| 80 } |  | 
| 81 |  | 
| 82 // static |  | 
| 83 SafeBrowsingNavigationObserver* SafeBrowsingNavigationObserver::FromWebContents( |  | 
| 84     content::WebContents* web_contents) { |  | 
| 85   return static_cast<SafeBrowsingNavigationObserver*>( |  | 
| 86       web_contents->GetUserData(kWebContentsUserDataKey)); |  | 
| 87 } |  | 
| 88 |  | 
| 89 SafeBrowsingNavigationObserver::SafeBrowsingNavigationObserver( |  | 
| 90     content::WebContents* contents, |  | 
| 91     const scoped_refptr<SafeBrowsingNavigationObserverManager>& manager) |  | 
| 92     : content::WebContentsObserver(contents), |  | 
| 93       manager_(manager), |  | 
| 94       has_user_gesture_(false), |  | 
| 95       last_user_gesture_timestamp_(base::Time()) {} |  | 
| 96 |  | 
| 97 SafeBrowsingNavigationObserver::~SafeBrowsingNavigationObserver() {} |  | 
| 98 |  | 
| 99 // Called when a navigation starts in the WebContents. |navigation_handle| |  | 
| 100 // parameter is unique to this navigation, which will appear in the following |  | 
| 101 // DidRedirectNavigation, and DidFinishNavigation too. |  | 
| 102 void SafeBrowsingNavigationObserver::DidStartNavigation( |  | 
| 103     content::NavigationHandle* navigation_handle) { |  | 
| 104   NavigationEvent nav_event; |  | 
| 105   auto it = navigation_handle_map_.find(navigation_handle); |  | 
| 106   // It is possible to see multiple DidStartNavigation(..) with the same |  | 
| 107   // navigation_handle (e.g. cross-process transfer). If that's the case, |  | 
| 108   // we need to copy the is_user_initiated field. |  | 
| 109   if (it != navigation_handle_map_.end()) { |  | 
| 110     nav_event.is_user_initiated = it->second.is_user_initiated; |  | 
| 111   } else { |  | 
| 112     // If this is the first time we see this navigation_handle, create a new |  | 
| 113     // NavigationEvent, and decide if it is triggered by user. |  | 
| 114     if ((has_user_gesture_ && |  | 
| 115          !SafeBrowsingNavigationObserverManager::IsUserGestureExpired( |  | 
| 116              last_user_gesture_timestamp_)) || |  | 
| 117         !navigation_handle->IsRendererInitiated()) { |  | 
| 118       nav_event.is_user_initiated = has_user_gesture_; |  | 
| 119       manager_->OnUserGestureConsumed(web_contents(), |  | 
| 120                                       last_user_gesture_timestamp_); |  | 
| 121     } |  | 
| 122     has_user_gesture_ = false; |  | 
| 123   } |  | 
| 124 |  | 
| 125   // All the other fields are reconstructed based on current content of |  | 
| 126   // navigation_handle. |  | 
| 127   nav_event.frame_id = navigation_handle->GetFrameTreeNodeId(); |  | 
| 128 |  | 
| 129   // If there was a URL previously committed in the current RenderFrameHost, |  | 
| 130   // set it as the source url of this navigation. Otherwise, this is the |  | 
| 131   // first url going to commit in this frame. We set navigation_handle's URL as |  | 
| 132   // the source url. |  | 
| 133   // TODO(jialiul): source_url, source_tab_id, and source_main_frame_url may be |  | 
| 134   // incorrect when another frame is targeting this frame. Need to refine this |  | 
| 135   // logic after the true initiator details are added to NavigationHandle |  | 
| 136   // (https://crbug.com/651895). |  | 
| 137   content::RenderFrameHost* current_frame_host = |  | 
| 138       navigation_handle->GetWebContents()->FindFrameByFrameTreeNodeId( |  | 
| 139           nav_event.frame_id); |  | 
| 140   if (current_frame_host && |  | 
| 141       current_frame_host->GetLastCommittedURL().is_valid()) { |  | 
| 142     nav_event.source_url = SafeBrowsingNavigationObserverManager::ClearEmptyRef( |  | 
| 143         current_frame_host->GetLastCommittedURL()); |  | 
| 144   } |  | 
| 145   nav_event.original_request_url = |  | 
| 146       SafeBrowsingNavigationObserverManager::ClearEmptyRef( |  | 
| 147           navigation_handle->GetURL()); |  | 
| 148   nav_event.destination_url = nav_event.original_request_url; |  | 
| 149 |  | 
| 150   nav_event.source_tab_id = |  | 
| 151       SessionTabHelper::IdForTab(navigation_handle->GetWebContents()); |  | 
| 152 |  | 
| 153   if (navigation_handle->IsInMainFrame()) { |  | 
| 154     nav_event.source_main_frame_url = nav_event.source_url; |  | 
| 155   } else { |  | 
| 156     nav_event.source_main_frame_url = |  | 
| 157         SafeBrowsingNavigationObserverManager::ClearEmptyRef( |  | 
| 158             navigation_handle->GetWebContents()->GetLastCommittedURL()); |  | 
| 159   } |  | 
| 160   navigation_handle_map_[navigation_handle] = std::move(nav_event); |  | 
| 161 } |  | 
| 162 |  | 
| 163 void SafeBrowsingNavigationObserver::DidRedirectNavigation( |  | 
| 164     content::NavigationHandle* navigation_handle) { |  | 
| 165   // We should have already seen this navigation_handle in DidStartNavigation. |  | 
| 166   if (navigation_handle_map_.find(navigation_handle) == |  | 
| 167       navigation_handle_map_.end()) { |  | 
| 168     NOTREACHED(); |  | 
| 169     return; |  | 
| 170   } |  | 
| 171 |  | 
| 172   NavigationEvent* nav_event = &navigation_handle_map_[navigation_handle]; |  | 
| 173   nav_event->has_server_redirect = true; |  | 
| 174   nav_event->destination_url = |  | 
| 175       SafeBrowsingNavigationObserverManager::ClearEmptyRef( |  | 
| 176           navigation_handle->GetURL()); |  | 
| 177   nav_event->last_updated = base::Time::Now(); |  | 
| 178 } |  | 
| 179 |  | 
| 180 void SafeBrowsingNavigationObserver::DidFinishNavigation( |  | 
| 181     content::NavigationHandle* navigation_handle) { |  | 
| 182   if (navigation_handle_map_.find(navigation_handle) == |  | 
| 183       navigation_handle_map_.end()) { |  | 
| 184     NOTREACHED(); |  | 
| 185     return; |  | 
| 186   } |  | 
| 187 |  | 
| 188   // If it is an error page, we ignore this navigation. |  | 
| 189   if (navigation_handle->IsErrorPage()) { |  | 
| 190     navigation_handle_map_.erase(navigation_handle); |  | 
| 191     return; |  | 
| 192   } |  | 
| 193   NavigationEvent* nav_event = &navigation_handle_map_[navigation_handle]; |  | 
| 194 |  | 
| 195   nav_event->has_committed = navigation_handle->HasCommitted(); |  | 
| 196   nav_event->target_tab_id = |  | 
| 197       SessionTabHelper::IdForTab(navigation_handle->GetWebContents()); |  | 
| 198   nav_event->last_updated = base::Time::Now(); |  | 
| 199 |  | 
| 200   manager_->RecordNavigationEvent(nav_event->destination_url, nav_event); |  | 
| 201   navigation_handle_map_.erase(navigation_handle); |  | 
| 202 } |  | 
| 203 |  | 
| 204 void SafeBrowsingNavigationObserver::DidGetResourceResponseStart( |  | 
| 205     const content::ResourceRequestDetails& details) { |  | 
| 206   // We only care about main frame and sub frame. |  | 
| 207   if (details.resource_type != content::RESOURCE_TYPE_MAIN_FRAME && |  | 
| 208       details.resource_type != content::RESOURCE_TYPE_SUB_FRAME) { |  | 
| 209     return; |  | 
| 210   } |  | 
| 211   if (!details.url.is_valid() || details.socket_address.IsEmpty()) |  | 
| 212     return; |  | 
| 213 |  | 
| 214   manager_->RecordHostToIpMapping(details.url.host(), |  | 
| 215                                   details.socket_address.host()); |  | 
| 216 } |  | 
| 217 |  | 
| 218 void SafeBrowsingNavigationObserver::DidGetUserInteraction( |  | 
| 219     const blink::WebInputEvent::Type type) { |  | 
| 220   last_user_gesture_timestamp_ = base::Time::Now(); |  | 
| 221   has_user_gesture_ = true; |  | 
| 222   // TODO (jialiul): Refine user gesture logic when DidOpenRequestedURL |  | 
| 223   // covers all retargetting cases. |  | 
| 224   manager_->RecordUserGestureForWebContents(web_contents(), |  | 
| 225                                             last_user_gesture_timestamp_); |  | 
| 226 } |  | 
| 227 |  | 
| 228 void SafeBrowsingNavigationObserver::WebContentsDestroyed() { |  | 
| 229   manager_->OnWebContentDestroyed(web_contents()); |  | 
| 230   web_contents()->RemoveUserData(kWebContentsUserDataKey); |  | 
| 231   // web_contents is null after this function. |  | 
| 232 } |  | 
| 233 |  | 
| 234 }  // namespace safe_browsing |  | 
| OLD | NEW | 
|---|