OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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/loader/cross_site_resource_handler.h" | 5 #include "content/browser/loader/cross_site_resource_handler.h" |
6 | 6 |
7 #include <string> | 7 #include <string> |
8 | 8 |
9 #include "base/bind.h" | 9 #include "base/bind.h" |
10 #include "base/command_line.h" | 10 #include "base/command_line.h" |
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
77 params.global_request_id, cross_site_transferring_request.Pass(), | 77 params.global_request_id, cross_site_transferring_request.Pass(), |
78 params.transfer_url_chain, params.referrer, | 78 params.transfer_url_chain, params.referrer, |
79 params.page_transition, params.should_replace_current_entry); | 79 params.page_transition, params.should_replace_current_entry); |
80 } else if (leak_requests_for_testing_ && cross_site_transferring_request) { | 80 } else if (leak_requests_for_testing_ && cross_site_transferring_request) { |
81 // Some unit tests expect requests to be leaked in this case, so they can | 81 // Some unit tests expect requests to be leaked in this case, so they can |
82 // pass them along manually. | 82 // pass them along manually. |
83 cross_site_transferring_request->ReleaseRequest(); | 83 cross_site_transferring_request->ReleaseRequest(); |
84 } | 84 } |
85 } | 85 } |
86 | 86 |
| 87 bool CheckNavigationPolicyOnUI(GURL url, int process_id, int render_frame_id) { |
| 88 RenderFrameHostImpl* rfh = |
| 89 RenderFrameHostImpl::FromID(process_id, render_frame_id); |
| 90 if (!rfh) |
| 91 return false; |
| 92 |
| 93 // TODO(nasko): This check is very simplistic and is used temporarily only |
| 94 // for --site-per-process. It should be updated to match the check performed |
| 95 // by RenderFrameHostManager::UpdateRendererStateForNavigate. |
| 96 return !SiteInstance::IsSameWebSite( |
| 97 rfh->GetSiteInstance()->GetBrowserContext(), |
| 98 rfh->GetSiteInstance()->GetSiteURL(), url); |
| 99 } |
| 100 |
87 } // namespace | 101 } // namespace |
88 | 102 |
89 CrossSiteResourceHandler::CrossSiteResourceHandler( | 103 CrossSiteResourceHandler::CrossSiteResourceHandler( |
90 scoped_ptr<ResourceHandler> next_handler, | 104 scoped_ptr<ResourceHandler> next_handler, |
91 net::URLRequest* request) | 105 net::URLRequest* request) |
92 : LayeredResourceHandler(request, next_handler.Pass()), | 106 : LayeredResourceHandler(request, next_handler.Pass()), |
93 has_started_response_(false), | 107 has_started_response_(false), |
94 in_cross_site_transition_(false), | 108 in_cross_site_transition_(false), |
95 completed_during_transition_(false), | 109 completed_during_transition_(false), |
96 did_defer_(false) { | 110 did_defer_(false), |
| 111 weak_ptr_factory_(this) { |
97 } | 112 } |
98 | 113 |
99 CrossSiteResourceHandler::~CrossSiteResourceHandler() { | 114 CrossSiteResourceHandler::~CrossSiteResourceHandler() { |
100 // Cleanup back-pointer stored on the request info. | 115 // Cleanup back-pointer stored on the request info. |
101 GetRequestInfo()->set_cross_site_handler(NULL); | 116 GetRequestInfo()->set_cross_site_handler(NULL); |
102 } | 117 } |
103 | 118 |
104 bool CrossSiteResourceHandler::OnRequestRedirected( | 119 bool CrossSiteResourceHandler::OnRequestRedirected( |
105 int request_id, | 120 int request_id, |
106 const GURL& new_url, | 121 const GURL& new_url, |
(...skipping 20 matching lines...) Expand all Loading... |
127 | 142 |
128 // We will need to swap processes if either (1) a redirect that requires a | 143 // We will need to swap processes if either (1) a redirect that requires a |
129 // transfer occurred before we got here, or (2) a pending cross-site request | 144 // transfer occurred before we got here, or (2) a pending cross-site request |
130 // was already in progress. Note that a swap may no longer be needed if we | 145 // was already in progress. Note that a swap may no longer be needed if we |
131 // transferred back into the original process due to a redirect. | 146 // transferred back into the original process due to a redirect. |
132 bool should_transfer = | 147 bool should_transfer = |
133 GetContentClient()->browser()->ShouldSwapProcessesForRedirect( | 148 GetContentClient()->browser()->ShouldSwapProcessesForRedirect( |
134 info->GetContext(), request()->original_url(), request()->url()); | 149 info->GetContext(), request()->original_url(), request()->url()); |
135 | 150 |
136 // When the --site-per-process flag is passed, we transfer processes for | 151 // When the --site-per-process flag is passed, we transfer processes for |
137 // cross-site subframe navigations. | 152 // cross-site navigations. This is skipped if a transfer is already required |
138 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kSitePerProcess)) { | 153 // or for WebUI processes for now, since pages like the NTP host multiple |
139 GURL referrer(request()->referrer()); | 154 // cross-site WebUI iframes. |
140 // We skip this for WebUI processes for now, since pages like the NTP host | 155 if (!should_transfer && |
141 // cross-site WebUI iframes but don't have referrers. | 156 CommandLine::ForCurrentProcess()->HasSwitch(switches::kSitePerProcess) && |
142 bool is_webui_process = ChildProcessSecurityPolicyImpl::GetInstance()-> | 157 !ChildProcessSecurityPolicyImpl::GetInstance()->HasWebUIBindings( |
143 HasWebUIBindings(info->GetChildID()); | 158 info->GetChildID())) { |
144 | 159 return DeferForNavigationPolicyCheck(info, response, defer); |
145 // TODO(creis): This shouldn't rely on the referrer to determine the parent | |
146 // frame's URL. This also doesn't work for hosted apps, due to passing NULL | |
147 // to IsSameWebSite. It should be possible to always send the navigation to | |
148 // the UI thread to make a policy decision, which could let us eliminate the | |
149 // renderer-side check in RenderViewImpl::decidePolicyForNavigation as well. | |
150 if (info->GetResourceType() == ResourceType::SUB_FRAME && | |
151 !is_webui_process && | |
152 !SiteInstance::IsSameWebSite(NULL, request()->url(), referrer)) { | |
153 should_transfer = true; | |
154 } | |
155 } | 160 } |
156 | 161 |
157 bool swap_needed = should_transfer || | 162 bool swap_needed = should_transfer || |
158 CrossSiteRequestManager::GetInstance()-> | 163 CrossSiteRequestManager::GetInstance()-> |
159 HasPendingCrossSiteRequest(info->GetChildID(), info->GetRouteID()); | 164 HasPendingCrossSiteRequest(info->GetChildID(), info->GetRouteID()); |
160 | 165 |
161 // If this is a download, just pass the response through without doing a | 166 // If this is a download, just pass the response through without doing a |
162 // cross-site check. The renderer will see it is a download and abort the | 167 // cross-site check. The renderer will see it is a download and abort the |
163 // request. | 168 // request. |
164 // | 169 // |
(...skipping 18 matching lines...) Expand all Loading... |
183 // pause to let the UI thread run the unload handler of the previous page | 188 // pause to let the UI thread run the unload handler of the previous page |
184 // and set up a transfer if needed. | 189 // and set up a transfer if needed. |
185 StartCrossSiteTransition(request_id, response, should_transfer); | 190 StartCrossSiteTransition(request_id, response, should_transfer); |
186 | 191 |
187 // Defer loading until after the onunload event handler has run. | 192 // Defer loading until after the onunload event handler has run. |
188 *defer = true; | 193 *defer = true; |
189 OnDidDefer(); | 194 OnDidDefer(); |
190 return true; | 195 return true; |
191 } | 196 } |
192 | 197 |
| 198 void CrossSiteResourceHandler::ResumeOrTransfer(bool is_transfer) { |
| 199 if (is_transfer) { |
| 200 ResourceRequestInfoImpl* info = GetRequestInfo(); |
| 201 StartCrossSiteTransition(info->GetRequestID(), response_, is_transfer); |
| 202 } else { |
| 203 ResumeResponse(); |
| 204 } |
| 205 } |
| 206 |
193 bool CrossSiteResourceHandler::OnReadCompleted(int request_id, | 207 bool CrossSiteResourceHandler::OnReadCompleted(int request_id, |
194 int bytes_read, | 208 int bytes_read, |
195 bool* defer) { | 209 bool* defer) { |
196 CHECK(!in_cross_site_transition_); | 210 CHECK(!in_cross_site_transition_); |
197 return next_handler_->OnReadCompleted(request_id, bytes_read, defer); | 211 return next_handler_->OnReadCompleted(request_id, bytes_read, defer); |
198 } | 212 } |
199 | 213 |
200 void CrossSiteResourceHandler::OnResponseCompleted( | 214 void CrossSiteResourceHandler::OnResponseCompleted( |
201 int request_id, | 215 int request_id, |
202 const net::URLRequestStatus& status, | 216 const net::URLRequestStatus& status, |
(...skipping 28 matching lines...) Expand all Loading... |
231 // Defer to tell RDH not to notify the world or clean up the pending request. | 245 // Defer to tell RDH not to notify the world or clean up the pending request. |
232 // We will do so in ResumeResponse. | 246 // We will do so in ResumeResponse. |
233 *defer = true; | 247 *defer = true; |
234 OnDidDefer(); | 248 OnDidDefer(); |
235 } | 249 } |
236 | 250 |
237 // We can now send the response to the new renderer, which will cause | 251 // We can now send the response to the new renderer, which will cause |
238 // WebContentsImpl to swap in the new renderer and destroy the old one. | 252 // WebContentsImpl to swap in the new renderer and destroy the old one. |
239 void CrossSiteResourceHandler::ResumeResponse() { | 253 void CrossSiteResourceHandler::ResumeResponse() { |
240 DCHECK(request()); | 254 DCHECK(request()); |
241 DCHECK(in_cross_site_transition_); | |
242 in_cross_site_transition_ = false; | 255 in_cross_site_transition_ = false; |
243 ResourceRequestInfoImpl* info = GetRequestInfo(); | 256 ResourceRequestInfoImpl* info = GetRequestInfo(); |
244 | 257 |
245 if (has_started_response_) { | 258 if (has_started_response_) { |
246 // Send OnResponseStarted to the new renderer. | 259 // Send OnResponseStarted to the new renderer. |
247 DCHECK(response_); | 260 DCHECK(response_); |
248 bool defer = false; | 261 bool defer = false; |
249 if (!next_handler_->OnResponseStarted(info->GetRequestID(), response_.get(), | 262 if (!next_handler_->OnResponseStarted(info->GetRequestID(), response_.get(), |
250 &defer)) { | 263 &defer)) { |
251 controller()->Cancel(); | 264 controller()->Cancel(); |
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
319 &OnCrossSiteResponseHelper, | 332 &OnCrossSiteResponseHelper, |
320 CrossSiteResponseParams(render_frame_id, | 333 CrossSiteResponseParams(render_frame_id, |
321 global_id, | 334 global_id, |
322 should_transfer, | 335 should_transfer, |
323 transfer_url_chain, | 336 transfer_url_chain, |
324 referrer, | 337 referrer, |
325 info->GetPageTransition(), | 338 info->GetPageTransition(), |
326 info->should_replace_current_entry()))); | 339 info->should_replace_current_entry()))); |
327 } | 340 } |
328 | 341 |
| 342 bool CrossSiteResourceHandler::DeferForNavigationPolicyCheck( |
| 343 ResourceRequestInfoImpl* info, |
| 344 ResourceResponse* response, |
| 345 bool* defer) { |
| 346 // Store the response_ object internally, since the navigation is deferred |
| 347 // regardless of whether it will be a transfer or not. |
| 348 response_ = response; |
| 349 |
| 350 // Always defer the navigation to the UI thread to make a policy decision. |
| 351 // It will send the result back to the IO thread to either resume or |
| 352 // transfer it to a new renderer. |
| 353 // TODO(nasko): If the UI thread result is that transfer is required, the |
| 354 // IO thread will defer to the UI thread again through |
| 355 // StartCrossSiteTransition. This is unnecessary and the policy check on the |
| 356 // UI thread should be refactored to avoid the extra hop. |
| 357 BrowserThread::PostTaskAndReplyWithResult( |
| 358 BrowserThread::UI, |
| 359 FROM_HERE, |
| 360 base::Bind(&CheckNavigationPolicyOnUI, |
| 361 request()->url(), |
| 362 info->GetChildID(), |
| 363 info->GetRenderFrameID()), |
| 364 base::Bind(&CrossSiteResourceHandler::ResumeOrTransfer, |
| 365 weak_ptr_factory_.GetWeakPtr())); |
| 366 |
| 367 // Defer loading until it is known whether the navigation will transfer |
| 368 // to a new process or continue in the existing one. |
| 369 *defer = true; |
| 370 OnDidDefer(); |
| 371 return true; |
| 372 } |
| 373 |
329 void CrossSiteResourceHandler::ResumeIfDeferred() { | 374 void CrossSiteResourceHandler::ResumeIfDeferred() { |
330 if (did_defer_) { | 375 if (did_defer_) { |
331 request()->LogUnblocked(); | 376 request()->LogUnblocked(); |
332 did_defer_ = false; | 377 did_defer_ = false; |
333 controller()->Resume(); | 378 controller()->Resume(); |
334 } | 379 } |
335 } | 380 } |
336 | 381 |
337 void CrossSiteResourceHandler::OnDidDefer() { | 382 void CrossSiteResourceHandler::OnDidDefer() { |
338 did_defer_ = true; | 383 did_defer_ = true; |
339 request()->LogBlockedBy("CrossSiteResourceHandler"); | 384 request()->LogBlockedBy("CrossSiteResourceHandler"); |
340 } | 385 } |
341 | 386 |
342 } // namespace content | 387 } // namespace content |
OLD | NEW |