Chromium Code Reviews| 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 #include "chrome/browser/safe_browsing/safe_browsing_navigation_observer.h" | |
| 5 | |
| 6 #include "base/memory/ptr_util.h" | |
| 7 #include "base/time/time.h" | |
| 8 #include "chrome/browser/chrome_notification_types.h" | |
| 9 #include "chrome/browser/sessions/session_tab_helper.h" | |
| 10 #include "chrome/browser/tab_contents/retargeting_details.h" | |
| 11 #include "content/public/browser/navigation_controller.h" | |
| 12 #include "content/public/browser/navigation_details.h" | |
| 13 #include "content/public/browser/navigation_entry.h" | |
| 14 #include "content/public/browser/navigation_handle.h" | |
| 15 #include "content/public/browser/notification_service.h" | |
| 16 #include "content/public/browser/notification_types.h" | |
| 17 #include "content/public/browser/render_frame_host.h" | |
| 18 #include "content/public/browser/render_process_host.h" | |
| 19 #include "content/public/browser/resource_request_details.h" | |
| 20 #include "content/public/browser/web_contents.h" | |
| 21 #include "content/public/common/resource_type.h" | |
| 22 #include "ui/base/page_transition_types.h" | |
| 23 | |
| 24 namespace safe_browsing { | |
| 25 | |
| 26 namespace { | |
| 27 | |
| 28 // Returns |time| as milliseconds since the epoch. | |
| 29 double MilliSecondsFromTime(const base::Time& time) { | |
| 30 return 1000 * time.ToDoubleT(); | |
| 31 } | |
| 32 | |
| 33 } // namespace | |
| 34 | |
| 35 // SafeBrowsingNavigationObserver::NavigationEvent----------------------------- | |
| 36 | |
| 37 SafeBrowsingNavigationObserver::NavigationEvent::NavigationEvent() | |
| 38 : source_url(), | |
| 39 source_tab_id(-1), | |
| 40 target_url(), | |
| 41 target_tab_id(-1), | |
| 42 frame_id(-1), | |
| 43 main_frame_url(), | |
| 44 timestamp(0.0), | |
| 45 is_user_initiated(false), | |
| 46 has_committed(false), | |
| 47 is_server_redirect(false), | |
| 48 is_finished(false), | |
| 49 server_redirect_url() {} | |
| 50 | |
| 51 SafeBrowsingNavigationObserver::NavigationEvent::NavigationEvent( | |
| 52 const GURL& source_url, | |
| 53 int source_tab_id, | |
| 54 const GURL& target_url, | |
| 55 int target_tab_id, | |
| 56 int frame_id, | |
| 57 const GURL& main_frame_url, | |
| 58 double timestamp, | |
| 59 bool is_user_initiated, | |
| 60 bool has_committed) | |
| 61 : source_url(source_url), | |
| 62 source_tab_id(source_tab_id), | |
| 63 target_url(target_url), | |
| 64 target_tab_id(target_tab_id), | |
| 65 frame_id(frame_id), | |
| 66 main_frame_url(main_frame_url), | |
| 67 timestamp(timestamp), | |
| 68 is_user_initiated(is_user_initiated), | |
| 69 has_committed(has_committed), | |
| 70 is_server_redirect(false), | |
| 71 is_finished(false), | |
| 72 server_redirect_url() {} | |
| 73 | |
| 74 SafeBrowsingNavigationObserver::NavigationEvent::NavigationEvent( | |
|
Nathan Parker
2016/09/03 00:21:35
Does the default copy constructor work here? I th
Jialiu Lin
2016/09/07 00:42:40
Actually I need a move constructor here instead of
| |
| 75 const NavigationEvent& nav_event) | |
| 76 : source_url(nav_event.source_url), | |
| 77 source_tab_id(nav_event.source_tab_id), | |
| 78 target_url(nav_event.target_url), | |
| 79 target_tab_id(nav_event.target_tab_id), | |
| 80 frame_id(nav_event.frame_id), | |
| 81 main_frame_url(nav_event.main_frame_url), | |
| 82 timestamp(nav_event.timestamp), | |
| 83 is_user_initiated(nav_event.is_user_initiated), | |
| 84 has_committed(nav_event.has_committed), | |
| 85 is_server_redirect(nav_event.is_server_redirect), | |
| 86 is_finished(nav_event.is_finished), | |
| 87 server_redirect_url(nav_event.server_redirect_url) {} | |
| 88 | |
| 89 SafeBrowsingNavigationObserver::NavigationEvent::~NavigationEvent() {} | |
| 90 | |
| 91 SafeBrowsingNavigationObserver::SafeBrowsingNavigationObserver() { | |
| 92 registrar_.Add(this, content::NOTIFICATION_NAV_ENTRY_PENDING, | |
| 93 content::NotificationService::AllSources()); | |
| 94 registrar_.Add(this, chrome::NOTIFICATION_TAB_ADDED, | |
| 95 content::NotificationService::AllSources()); | |
| 96 registrar_.Add(this, chrome::NOTIFICATION_TAB_CLOSING, | |
| 97 content::NotificationService::AllSources()); | |
| 98 registrar_.Add(this, chrome::NOTIFICATION_RETARGETING, | |
| 99 content::NotificationService::AllSources()); | |
| 100 } | |
| 101 | |
| 102 SafeBrowsingNavigationObserver::~SafeBrowsingNavigationObserver() { | |
| 103 ClearNavigationMap(); | |
| 104 } | |
| 105 | |
| 106 SafeBrowsingNavigationObserver::NavigationMap* | |
| 107 SafeBrowsingNavigationObserver::navigation_map() { | |
| 108 return &navigation_map_; | |
|
Nathan Parker
2016/09/03 00:21:35
nit: trivial accessor could go in the .h
Jialiu Lin
2016/09/07 00:42:40
Done.
| |
| 109 } | |
| 110 | |
| 111 void SafeBrowsingNavigationObserver::ClearNavigationMap() { | |
| 112 navigation_map_.clear(); | |
| 113 } | |
| 114 | |
| 115 void SafeBrowsingNavigationObserver::RecordNavigationPendingEntry( | |
| 116 const content::NotificationSource& source, | |
| 117 const content::NotificationDetails& details) { | |
| 118 content::NavigationController* source_controller = | |
| 119 content::Source<content::NavigationController>(source).ptr(); | |
| 120 DCHECK(source_controller); | |
| 121 content::WebContents* source_contents = source_controller->GetWebContents(); | |
| 122 DCHECK(source_contents); | |
| 123 WebContentsObserver::Observe(source_contents); | |
|
Nathan Parker
2016/09/03 00:21:35
What does this do? Does it invoke it on *this?
Jialiu Lin
2016/09/07 00:42:41
Yes, since SBNavigationObserver inherits both WebC
| |
| 124 } | |
| 125 | |
| 126 void SafeBrowsingNavigationObserver::RecordRetargeting( | |
| 127 const content::NotificationDetails& details) { | |
| 128 const RetargetingDetails* retargeting_detail = | |
| 129 content::Details<const RetargetingDetails>(details).ptr(); | |
| 130 DCHECK(retargeting_detail); | |
| 131 content::WebContents* source_contents = | |
| 132 retargeting_detail->source_web_contents; | |
| 133 content::WebContents* target_contents = | |
| 134 retargeting_detail->target_web_contents; | |
| 135 DCHECK(source_contents); | |
| 136 DCHECK(target_contents); | |
| 137 // WebContentsObserver::Observe(target_contents); | |
| 138 | |
| 139 content::RenderFrameHost* rfh = content::RenderFrameHost::FromID( | |
| 140 source_contents->GetRenderProcessHost()->GetID(), | |
| 141 retargeting_detail->source_render_frame_id); | |
| 142 GURL target_url = retargeting_detail->target_url; | |
|
Nathan Parker
2016/09/03 00:21:35
nit: could be const GURL&
Jialiu Lin
2016/09/07 00:42:41
Indeed. done.
| |
| 143 | |
| 144 if (navigation_map_.find(target_url) == navigation_map_.end()) | |
| 145 navigation_map_.insert( | |
| 146 std::make_pair(target_url, std::vector<NavigationEvent>())); | |
| 147 | |
| 148 NavigationEvent nav_event( | |
| 149 rfh ? rfh->GetLastCommittedURL() : GURL(), // source_url | |
| 150 SessionTabHelper::IdForTab(source_contents), // source_tab_id | |
| 151 target_url, // target_url | |
| 152 SessionTabHelper::IdForTab(target_contents), // target_tab_id | |
| 153 rfh ? rfh->GetFrameTreeNodeId() : -1, // frame id | |
| 154 source_contents->GetVisibleURL(), // main_frame_url | |
| 155 MilliSecondsFromTime(base::Time::Now()), // timestamp | |
| 156 true, // is_user_initiated | |
| 157 false); // is_committed | |
| 158 | |
| 159 navigation_map_[target_url].push_back(std::move(nav_event)); | |
|
Nathan Parker
2016/09/03 00:21:35
I'm trying to remember the move semantics with std
Jialiu Lin
2016/09/07 00:42:41
It basically pushes the underlying nav_event objec
| |
| 160 } | |
| 161 | |
| 162 void SafeBrowsingNavigationObserver::Observe( | |
| 163 int type, | |
| 164 const content::NotificationSource& source, | |
| 165 const content::NotificationDetails& details) { | |
| 166 switch (type) { | |
| 167 case content::NOTIFICATION_NAV_ENTRY_PENDING: { | |
| 168 RecordNavigationPendingEntry(source, details); | |
| 169 break; | |
| 170 } | |
| 171 case chrome::NOTIFICATION_RETARGETING: { | |
| 172 RecordRetargeting(details); | |
| 173 break; | |
| 174 } | |
| 175 case chrome::NOTIFICATION_TAB_ADDED: { | |
| 176 content::WebContents* dest_content = | |
| 177 content::Details<content::WebContents>(details).ptr(); | |
| 178 DCHECK(dest_content); | |
| 179 WebContentsObserver::Observe(dest_content); | |
| 180 break; | |
| 181 } | |
| 182 case chrome::NOTIFICATION_TAB_CLOSING: { | |
| 183 // TODO(jialiul): For now, we don't want to delete NavigationEvent if | |
| 184 // its corresponding tab is closed, since it could be used to hide landing | |
| 185 // page. But we may consider using this event as a trigger to clean up | |
| 186 // some outdated entries. | |
|
Nathan Parker
2016/09/03 00:21:35
Is it useful to record this event?
Jialiu Lin
2016/09/07 00:42:41
Maybe. Let me handle or delete this in my next CL.
| |
| 187 break; | |
| 188 } | |
| 189 default: | |
| 190 NOTREACHED(); | |
| 191 break; | |
| 192 } | |
| 193 } | |
| 194 | |
| 195 void SafeBrowsingNavigationObserver::DidStartNavigation( | |
|
Nathan Parker
2016/09/03 00:21:35
For those of us not familiar with NavigationObserv
Jialiu Lin
2016/09/07 00:42:40
Comments added.
| |
| 196 content::NavigationHandle* navigation_handle) { | |
| 197 // If we already seen this navigation_handle before, no need to do anything. | |
| 198 if (navigation_handle_map_.find(navigation_handle) != | |
| 199 navigation_handle_map_.end()) | |
| 200 return; | |
| 201 | |
| 202 // Construct a NavigationEvent based on avialble information in | |
|
Nathan Parker
2016/09/03 00:21:35
sp: available
Jialiu Lin
2016/09/07 00:42:40
done
| |
| 203 // navigation_handle. | |
| 204 NavigationEvent nav_event; | |
| 205 content::RenderFrameHost* host = | |
| 206 navigation_handle->GetWebContents()->FindFrameByFrameTreeNodeId( | |
| 207 navigation_handle->GetFrameTreeNodeId()); | |
| 208 if (host && host->GetLastCommittedURL() != GURL()) | |
|
Nathan Parker
2016/09/03 00:21:35
Would GetLasCommittedURL().is_valid() work? Avoid
Jialiu Lin
2016/09/07 00:42:40
Done.
| |
| 209 nav_event.source_url = host->GetLastCommittedURL(); | |
| 210 else | |
|
Nathan Parker
2016/09/03 00:21:34
What's the difference between the source_url in th
Jialiu Lin
2016/09/07 00:42:41
The differences are whether this is the first URL
| |
| 211 nav_event.source_url = navigation_handle->GetURL(); | |
| 212 nav_event.target_url = navigation_handle->GetURL(); | |
| 213 | |
| 214 nav_event.source_tab_id = | |
| 215 SessionTabHelper::IdForTab(navigation_handle->GetWebContents()); | |
| 216 nav_event.timestamp = MilliSecondsFromTime(base::Time::Now()); | |
| 217 nav_event.frame_id = navigation_handle->GetFrameTreeNodeId(); | |
| 218 | |
| 219 if (navigation_handle->IsInMainFrame()) { | |
|
Nathan Parker
2016/09/03 00:21:35
Do you want to record in the nav_event whether or
Jialiu Lin
2016/09/07 00:42:40
frame_id and main_frame_url are recorded, which a
| |
| 220 nav_event.main_frame_url = nav_event.source_url; | |
| 221 } else { | |
| 222 nav_event.main_frame_url = navigation_handle->GetWebContents()->GetURL(); | |
|
Nathan Parker
2016/09/03 00:21:35
nit: this uses braces for single-line if/else, but
Jialiu Lin
2016/09/07 00:42:40
Thanks for catching this.
| |
| 223 } | |
| 224 navigation_handle_map_[navigation_handle] = std::move(nav_event); | |
| 225 } | |
| 226 | |
| 227 void SafeBrowsingNavigationObserver::DidRedirectNavigation( | |
| 228 content::NavigationHandle* navigation_handle) { | |
| 229 // We should have already seen this navigation_handle in DidStartNavigation. | |
| 230 if (navigation_handle_map_.find(navigation_handle) == | |
| 231 navigation_handle_map_.end()) | |
| 232 return; | |
| 233 NavigationEvent* nav_event = &navigation_handle_map_[navigation_handle]; | |
| 234 nav_event->is_server_redirect = true; | |
| 235 nav_event->server_redirect_url = navigation_handle->GetURL(); | |
| 236 nav_event->timestamp = MilliSecondsFromTime(base::Time::Now()); | |
| 237 } | |
| 238 | |
| 239 void SafeBrowsingNavigationObserver::DidFinishNavigation( | |
| 240 content::NavigationHandle* navigation_handle) { | |
| 241 if (navigation_handle_map_.find(navigation_handle) == | |
| 242 navigation_handle_map_.end()) | |
| 243 return; | |
| 244 NavigationEvent* nav_event = &navigation_handle_map_[navigation_handle]; | |
| 245 | |
| 246 // In NavigationHandle's definition, render initiated navigation includes: | |
| 247 // clicking <a> link, changing window.location.href, client redirect via | |
| 248 // meta refresh tag and using window.history.pushState. | |
| 249 // Though in our case, we consider user explicitly clicking on a link as user | |
| 250 // initiated. We first use the negate of IsRenderInitiated() to include | |
| 251 // user initiated navigations such as typing in the omni box or clicking on | |
| 252 // bookmark then we refine this estimate by using HasUserGesture() | |
| 253 // if this info is available. | |
| 254 // For non-committed navigations (e.g. downloads), | |
| 255 // NavigationHandle::HasUserGesture() is not availble. But we can later get it | |
| 256 // from DownloadItem::HasUserGesture(). | |
| 257 nav_event->is_user_initiated = !navigation_handle->IsRendererInitiated(); | |
| 258 if (navigation_handle->HasCommitted()) { | |
| 259 nav_event->has_committed = true; | |
| 260 nav_event->is_user_initiated = | |
| 261 nav_event->is_user_initiated || navigation_handle->HasUserGesture(); | |
| 262 } | |
| 263 nav_event->target_tab_id = | |
| 264 SessionTabHelper::IdForTab(navigation_handle->GetWebContents()); | |
| 265 nav_event->timestamp = MilliSecondsFromTime(base::Time::Now()); | |
| 266 nav_event->is_finished = true; | |
| 267 | |
| 268 GURL key_url = nav_event->is_server_redirect ? nav_event->server_redirect_url | |
| 269 : nav_event->target_url; | |
| 270 if (navigation_map_.find(key_url) == navigation_map_.end()) | |
| 271 navigation_map_[key_url] = std::vector<NavigationEvent>(); | |
|
Nathan Parker
2016/09/03 00:21:35
nit: Can you insert a pair of key_url and std::vec
Jialiu Lin
2016/09/07 00:42:41
Yep, insert is safer than [] operator.
| |
| 272 navigation_map_[key_url].push_back(std::move(*nav_event)); | |
| 273 | |
| 274 navigation_handle_map_.erase(navigation_handle); | |
| 275 } | |
| 276 | |
| 277 } // namespace safe_browsing | |
| OLD | NEW |