OLD | NEW |
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "content/browser/frame_host/render_frame_host_impl.h" | 5 #include "content/browser/frame_host/render_frame_host_impl.h" |
6 | 6 |
7 #include "base/containers/hash_tables.h" | 7 #include "base/containers/hash_tables.h" |
8 #include "base/lazy_instance.h" | 8 #include "base/lazy_instance.h" |
| 9 #include "base/metrics/user_metrics_action.h" |
9 #include "content/browser/frame_host/cross_process_frame_connector.h" | 10 #include "content/browser/frame_host/cross_process_frame_connector.h" |
10 #include "content/browser/frame_host/frame_tree.h" | 11 #include "content/browser/frame_host/frame_tree.h" |
11 #include "content/browser/frame_host/frame_tree_node.h" | 12 #include "content/browser/frame_host/frame_tree_node.h" |
12 #include "content/browser/frame_host/navigator.h" | 13 #include "content/browser/frame_host/navigator.h" |
13 #include "content/browser/frame_host/render_frame_host_delegate.h" | 14 #include "content/browser/frame_host/render_frame_host_delegate.h" |
14 #include "content/browser/renderer_host/render_view_host_impl.h" | 15 #include "content/browser/renderer_host/render_view_host_impl.h" |
15 #include "content/common/frame_messages.h" | 16 #include "content/common/frame_messages.h" |
16 #include "content/public/browser/browser_thread.h" | 17 #include "content/public/browser/browser_thread.h" |
| 18 #include "content/public/browser/content_browser_client.h" |
17 #include "content/public/browser/render_process_host.h" | 19 #include "content/public/browser/render_process_host.h" |
18 #include "content/public/browser/render_widget_host_view.h" | 20 #include "content/public/browser/render_widget_host_view.h" |
19 #include "content/public/browser/user_metrics.h" | 21 #include "content/public/browser/user_metrics.h" |
| 22 #include "content/public/common/url_constants.h" |
20 #include "url/gurl.h" | 23 #include "url/gurl.h" |
21 | 24 |
22 namespace content { | 25 namespace content { |
23 | 26 |
24 // The (process id, routing id) pair that identifies one RenderFrame. | 27 // The (process id, routing id) pair that identifies one RenderFrame. |
25 typedef std::pair<int32, int32> RenderFrameHostID; | 28 typedef std::pair<int32, int32> RenderFrameHostID; |
26 typedef base::hash_map<RenderFrameHostID, RenderFrameHostImpl*> | 29 typedef base::hash_map<RenderFrameHostID, RenderFrameHostImpl*> |
27 RoutingIDFrameMap; | 30 RoutingIDFrameMap; |
28 static base::LazyInstance<RoutingIDFrameMap> g_routing_id_frame_map = | 31 static base::LazyInstance<RoutingIDFrameMap> g_routing_id_frame_map = |
29 LAZY_INSTANCE_INITIALIZER; | 32 LAZY_INSTANCE_INITIALIZER; |
(...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
126 bool handled = true; | 129 bool handled = true; |
127 bool msg_is_ok = true; | 130 bool msg_is_ok = true; |
128 IPC_BEGIN_MESSAGE_MAP_EX(RenderFrameHostImpl, msg, msg_is_ok) | 131 IPC_BEGIN_MESSAGE_MAP_EX(RenderFrameHostImpl, msg, msg_is_ok) |
129 IPC_MESSAGE_HANDLER(FrameHostMsg_Detach, OnDetach) | 132 IPC_MESSAGE_HANDLER(FrameHostMsg_Detach, OnDetach) |
130 IPC_MESSAGE_HANDLER(FrameHostMsg_DidStartProvisionalLoadForFrame, | 133 IPC_MESSAGE_HANDLER(FrameHostMsg_DidStartProvisionalLoadForFrame, |
131 OnDidStartProvisionalLoadForFrame) | 134 OnDidStartProvisionalLoadForFrame) |
132 IPC_MESSAGE_HANDLER(FrameHostMsg_DidFailProvisionalLoadWithError, | 135 IPC_MESSAGE_HANDLER(FrameHostMsg_DidFailProvisionalLoadWithError, |
133 OnDidFailProvisionalLoadWithError) | 136 OnDidFailProvisionalLoadWithError) |
134 IPC_MESSAGE_HANDLER(FrameHostMsg_DidRedirectProvisionalLoad, | 137 IPC_MESSAGE_HANDLER(FrameHostMsg_DidRedirectProvisionalLoad, |
135 OnDidRedirectProvisionalLoad) | 138 OnDidRedirectProvisionalLoad) |
| 139 IPC_MESSAGE_HANDLER_GENERIC(FrameHostMsg_DidCommitProvisionalLoad, |
| 140 OnNavigate(msg)) |
136 IPC_MESSAGE_HANDLER(FrameHostMsg_SwapOut_ACK, OnSwapOutACK) | 141 IPC_MESSAGE_HANDLER(FrameHostMsg_SwapOut_ACK, OnSwapOutACK) |
137 IPC_MESSAGE_HANDLER(FrameHostMsg_ContextMenu, OnContextMenu) | 142 IPC_MESSAGE_HANDLER(FrameHostMsg_ContextMenu, OnContextMenu) |
138 IPC_END_MESSAGE_MAP_EX() | 143 IPC_END_MESSAGE_MAP_EX() |
139 | 144 |
140 if (!msg_is_ok) { | 145 if (!msg_is_ok) { |
141 // The message had a handler, but its de-serialization failed. | 146 // The message had a handler, but its de-serialization failed. |
142 // Kill the renderer. | 147 // Kill the renderer. |
143 RecordAction(base::UserMetricsAction("BadMessageTerminate_RFH")); | 148 RecordAction(base::UserMetricsAction("BadMessageTerminate_RFH")); |
144 GetProcess()->ReceivedBadMessage(); | 149 GetProcess()->ReceivedBadMessage(); |
145 } | 150 } |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
180 } | 185 } |
181 | 186 |
182 void RenderFrameHostImpl::OnDidRedirectProvisionalLoad( | 187 void RenderFrameHostImpl::OnDidRedirectProvisionalLoad( |
183 int32 page_id, | 188 int32 page_id, |
184 const GURL& source_url, | 189 const GURL& source_url, |
185 const GURL& target_url) { | 190 const GURL& target_url) { |
186 frame_tree_node_->navigator()->DidRedirectProvisionalLoad( | 191 frame_tree_node_->navigator()->DidRedirectProvisionalLoad( |
187 this, page_id, source_url, target_url); | 192 this, page_id, source_url, target_url); |
188 } | 193 } |
189 | 194 |
| 195 // Called when the renderer navigates. For every frame loaded, we'll get this |
| 196 // notification containing parameters identifying the navigation. |
| 197 // |
| 198 // Subframes are identified by the page transition type. For subframes loaded |
| 199 // as part of a wider page load, the page_id will be the same as for the top |
| 200 // level frame. If the user explicitly requests a subframe navigation, we will |
| 201 // get a new page_id because we need to create a new navigation entry for that |
| 202 // action. |
| 203 void RenderFrameHostImpl::OnNavigate(const IPC::Message& msg) { |
| 204 // Read the parameters out of the IPC message directly to avoid making another |
| 205 // copy when we filter the URLs. |
| 206 PickleIterator iter(msg); |
| 207 FrameHostMsg_DidCommitProvisionalLoad_Params validated_params; |
| 208 if (!IPC::ParamTraits<FrameHostMsg_DidCommitProvisionalLoad_Params>:: |
| 209 Read(&msg, &iter, &validated_params)) |
| 210 return; |
| 211 |
| 212 // If we're waiting for a cross-site beforeunload ack from this renderer and |
| 213 // we receive a Navigate message from the main frame, then the renderer was |
| 214 // navigating already and sent it before hearing the ViewMsg_Stop message. |
| 215 // We do not want to cancel the pending navigation in this case, since the |
| 216 // old page will soon be stopped. Instead, treat this as a beforeunload ack |
| 217 // to allow the pending navigation to continue. |
| 218 if (render_view_host_->is_waiting_for_beforeunload_ack_ && |
| 219 render_view_host_->unload_ack_is_for_cross_site_transition_ && |
| 220 PageTransitionIsMainFrame(validated_params.transition)) { |
| 221 render_view_host_->OnShouldCloseACK( |
| 222 true, render_view_host_->send_should_close_start_time_, |
| 223 base::TimeTicks::Now()); |
| 224 return; |
| 225 } |
| 226 |
| 227 // If we're waiting for an unload ack from this renderer and we receive a |
| 228 // Navigate message, then the renderer was navigating before it received the |
| 229 // unload request. It will either respond to the unload request soon or our |
| 230 // timer will expire. Either way, we should ignore this message, because we |
| 231 // have already committed to closing this renderer. |
| 232 if (render_view_host_->is_waiting_for_unload_ack_) |
| 233 return; |
| 234 |
| 235 // Cache the main frame id, so we can use it for creating the frame tree |
| 236 // root node when needed. |
| 237 if (PageTransitionIsMainFrame(validated_params.transition)) { |
| 238 if (render_view_host_->main_frame_id_ == -1) { |
| 239 render_view_host_->main_frame_id_ = validated_params.frame_id; |
| 240 } else { |
| 241 // TODO(nasko): We plan to remove the usage of frame_id in navigation |
| 242 // and move to routing ids. This is in place to ensure that a |
| 243 // renderer is not misbehaving and sending us incorrect data. |
| 244 DCHECK_EQ(render_view_host_->main_frame_id_, validated_params.frame_id); |
| 245 } |
| 246 } |
| 247 RenderProcessHost* process = GetProcess(); |
| 248 |
| 249 // Attempts to commit certain off-limits URL should be caught more strictly |
| 250 // than our FilterURL checks below. If a renderer violates this policy, it |
| 251 // should be killed. |
| 252 if (!CanCommitURL(validated_params.url)) { |
| 253 VLOG(1) << "Blocked URL " << validated_params.url.spec(); |
| 254 validated_params.url = GURL(kAboutBlankURL); |
| 255 RecordAction(base::UserMetricsAction("CanCommitURL_BlockedAndKilled")); |
| 256 // Kills the process. |
| 257 process->ReceivedBadMessage(); |
| 258 } |
| 259 |
| 260 // Now that something has committed, we don't need to track whether the |
| 261 // initial page has been accessed. |
| 262 render_view_host_->has_accessed_initial_document_ = false; |
| 263 |
| 264 // Without this check, an evil renderer can trick the browser into creating |
| 265 // a navigation entry for a banned URL. If the user clicks the back button |
| 266 // followed by the forward button (or clicks reload, or round-trips through |
| 267 // session restore, etc), we'll think that the browser commanded the |
| 268 // renderer to load the URL and grant the renderer the privileges to request |
| 269 // the URL. To prevent this attack, we block the renderer from inserting |
| 270 // banned URLs into the navigation controller in the first place. |
| 271 process->FilterURL(false, &validated_params.url); |
| 272 process->FilterURL(true, &validated_params.referrer.url); |
| 273 for (std::vector<GURL>::iterator it(validated_params.redirects.begin()); |
| 274 it != validated_params.redirects.end(); ++it) { |
| 275 process->FilterURL(false, &(*it)); |
| 276 } |
| 277 process->FilterURL(true, &validated_params.searchable_form_url); |
| 278 |
| 279 // Without this check, the renderer can trick the browser into using |
| 280 // filenames it can't access in a future session restore. |
| 281 if (!render_view_host_->CanAccessFilesOfPageState( |
| 282 validated_params.page_state)) { |
| 283 GetProcess()->ReceivedBadMessage(); |
| 284 return; |
| 285 } |
| 286 |
| 287 frame_tree_node()->navigator()->DidNavigate(this, validated_params); |
| 288 } |
| 289 |
190 void RenderFrameHostImpl::SwapOut() { | 290 void RenderFrameHostImpl::SwapOut() { |
191 if (render_view_host_->IsRenderViewLive()) { | 291 if (render_view_host_->IsRenderViewLive()) { |
192 Send(new FrameMsg_SwapOut(routing_id_)); | 292 Send(new FrameMsg_SwapOut(routing_id_)); |
193 } else { | 293 } else { |
194 // Our RenderViewHost doesn't have a live renderer, so just skip the unload | 294 // Our RenderViewHost doesn't have a live renderer, so just skip the unload |
195 // event. | 295 // event. |
196 OnSwappedOut(true); | 296 OnSwappedOut(true); |
197 } | 297 } |
198 } | 298 } |
199 | 299 |
(...skipping 14 matching lines...) Expand all Loading... |
214 // We don't validate |unfiltered_link_url| so that this field can be used | 314 // We don't validate |unfiltered_link_url| so that this field can be used |
215 // when users want to copy the original link URL. | 315 // when users want to copy the original link URL. |
216 process->FilterURL(true, &validated_params.link_url); | 316 process->FilterURL(true, &validated_params.link_url); |
217 process->FilterURL(true, &validated_params.src_url); | 317 process->FilterURL(true, &validated_params.src_url); |
218 process->FilterURL(false, &validated_params.page_url); | 318 process->FilterURL(false, &validated_params.page_url); |
219 process->FilterURL(true, &validated_params.frame_url); | 319 process->FilterURL(true, &validated_params.frame_url); |
220 | 320 |
221 delegate_->ShowContextMenu(this, validated_params); | 321 delegate_->ShowContextMenu(this, validated_params); |
222 } | 322 } |
223 | 323 |
| 324 bool RenderFrameHostImpl::CanCommitURL(const GURL& url) { |
| 325 // TODO(creis): We should also check for WebUI pages here. Also, when the |
| 326 // out-of-process iframes implementation is ready, we should check for |
| 327 // cross-site URLs that are not allowed to commit in this process. |
| 328 |
| 329 // Give the client a chance to disallow URLs from committing. |
| 330 return GetContentClient()->browser()->CanCommitURL(GetProcess(), url); |
| 331 } |
| 332 |
224 } // namespace content | 333 } // namespace content |
OLD | NEW |