| 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 | 
|---|