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" |
11 #include "base/logging.h" | 11 #include "base/logging.h" |
12 #include "content/browser/appcache/appcache_interceptor.h" | 12 #include "content/browser/appcache/appcache_interceptor.h" |
13 #include "content/browser/child_process_security_policy_impl.h" | 13 #include "content/browser/child_process_security_policy_impl.h" |
14 #include "content/browser/frame_host/cross_site_transferring_request.h" | 14 #include "content/browser/frame_host/cross_site_transferring_request.h" |
15 #include "content/browser/frame_host/render_frame_host_impl.h" | 15 #include "content/browser/frame_host/render_frame_host_impl.h" |
16 #include "content/browser/loader/resource_dispatcher_host_impl.h" | 16 #include "content/browser/loader/resource_dispatcher_host_impl.h" |
17 #include "content/browser/loader/resource_request_info_impl.h" | 17 #include "content/browser/loader/resource_request_info_impl.h" |
18 #include "content/browser/site_instance_impl.h" | 18 #include "content/browser/site_instance_impl.h" |
19 #include "content/public/browser/browser_thread.h" | 19 #include "content/public/browser/browser_thread.h" |
20 #include "content/public/browser/content_browser_client.h" | 20 #include "content/public/browser/content_browser_client.h" |
21 #include "content/public/browser/global_request_id.h" | 21 #include "content/public/browser/global_request_id.h" |
22 #include "content/public/browser/resource_controller.h" | 22 #include "content/public/browser/resource_controller.h" |
23 #include "content/public/browser/site_instance.h" | 23 #include "content/public/browser/site_instance.h" |
24 #include "content/public/common/content_switches.h" | 24 #include "content/public/common/content_switches.h" |
25 #include "content/public/common/resource_response.h" | 25 #include "content/public/common/resource_response.h" |
26 #include "content/public/common/site_isolation_policy.h" | |
26 #include "content/public/common/url_constants.h" | 27 #include "content/public/common/url_constants.h" |
27 #include "net/http/http_response_headers.h" | 28 #include "net/http/http_response_headers.h" |
28 #include "net/url_request/url_request.h" | 29 #include "net/url_request/url_request.h" |
29 | 30 |
30 namespace content { | 31 namespace content { |
31 | 32 |
32 namespace { | 33 namespace { |
33 | 34 |
34 bool leak_requests_for_testing_ = false; | 35 bool leak_requests_for_testing_ = false; |
35 | 36 |
(...skipping 28 matching lines...) Expand all Loading... | |
64 new CrossSiteTransferringRequest(params.global_request_id)); | 65 new CrossSiteTransferringRequest(params.global_request_id)); |
65 | 66 |
66 RenderFrameHostImpl* rfh = | 67 RenderFrameHostImpl* rfh = |
67 RenderFrameHostImpl::FromID(params.global_request_id.child_id, | 68 RenderFrameHostImpl::FromID(params.global_request_id.child_id, |
68 params.render_frame_id); | 69 params.render_frame_id); |
69 if (rfh) { | 70 if (rfh) { |
70 if (rfh->GetParent()) { | 71 if (rfh->GetParent()) { |
71 // We should only swap processes for subframes in --site-per-process mode. | 72 // We should only swap processes for subframes in --site-per-process mode. |
72 // CrossSiteResourceHandler is not installed on subframe requests in | 73 // CrossSiteResourceHandler is not installed on subframe requests in |
73 // default Chrome. | 74 // default Chrome. |
74 CHECK(base::CommandLine::ForCurrentProcess()->HasSwitch( | 75 CHECK(SiteIsolationPolicy::AreCrossProcessFramesPossible()); |
75 switches::kSitePerProcess)); | |
76 } | 76 } |
77 rfh->OnCrossSiteResponse( | 77 rfh->OnCrossSiteResponse( |
78 params.global_request_id, cross_site_transferring_request.Pass(), | 78 params.global_request_id, cross_site_transferring_request.Pass(), |
79 params.transfer_url_chain, params.referrer, | 79 params.transfer_url_chain, params.referrer, |
80 params.page_transition, params.should_replace_current_entry); | 80 params.page_transition, params.should_replace_current_entry); |
81 } else if (leak_requests_for_testing_ && cross_site_transferring_request) { | 81 } else if (leak_requests_for_testing_ && cross_site_transferring_request) { |
82 // Some unit tests expect requests to be leaked in this case, so they can | 82 // Some unit tests expect requests to be leaked in this case, so they can |
83 // pass them along manually. | 83 // pass them along manually. |
84 cross_site_transferring_request->ReleaseRequest(); | 84 cross_site_transferring_request->ReleaseRequest(); |
85 } | 85 } |
86 } | 86 } |
87 | 87 |
88 // Returns whether a transfer is needed by doing a check on the UI thread. | 88 // Returns whether a transfer is needed by doing a check on the UI thread. |
89 bool CheckNavigationPolicyOnUI(GURL url, int process_id, int render_frame_id) { | 89 bool CheckNavigationPolicyOnUI(GURL url, int process_id, int render_frame_id) { |
90 CHECK(base::CommandLine::ForCurrentProcess()->HasSwitch( | 90 CHECK(SiteIsolationPolicy::AreCrossProcessFramesPossible()); |
91 switches::kSitePerProcess)); | |
92 RenderFrameHostImpl* rfh = | 91 RenderFrameHostImpl* rfh = |
93 RenderFrameHostImpl::FromID(process_id, render_frame_id); | 92 RenderFrameHostImpl::FromID(process_id, render_frame_id); |
94 if (!rfh) | 93 if (!rfh) |
95 return false; | 94 return false; |
96 | 95 |
97 // A transfer is not needed if the current SiteInstance doesn't yet have a | 96 // A transfer is not needed if the current SiteInstance doesn't yet have a |
98 // site. This is the case for tests that use NavigateToURL. | 97 // site. This is the case for tests that use NavigateToURL. |
99 if (!rfh->GetSiteInstance()->HasSite()) | 98 if (!rfh->GetSiteInstance()->HasSite()) |
100 return false; | 99 return false; |
101 | 100 |
102 // TODO(nasko): This check is very simplistic and is used temporarily only | 101 // TODO(nasko, nick): These following --site-per-process checks are |
103 // for --site-per-process. It should be updated to match the check performed | 102 // overly simplistic. Update them to match all the cases |
104 // by RenderFrameHostManager::UpdateStateForNavigate. | 103 // considered by RenderFrameHostManager::DetermineSiteInstanceForURL. |
105 return !SiteInstance::IsSameWebSite( | 104 if (SiteInstance::IsSameWebSite(rfh->GetSiteInstance()->GetBrowserContext(), |
106 rfh->GetSiteInstance()->GetBrowserContext(), | 105 rfh->GetSiteInstance()->GetSiteURL(), url)) { |
107 rfh->GetSiteInstance()->GetSiteURL(), url); | 106 return false; // The same site, no transition needed. |
107 } | |
108 | |
109 // The sites differ. If either one requires a dedicated process, | |
110 // then a transfer is needed. | |
111 return rfh->GetSiteInstance()->RequiresDedicatedProcess() || | |
112 SiteIsolationPolicy::DoesSiteRequireDedicatedProcess(url); | |
108 } | 113 } |
109 | 114 |
110 } // namespace | 115 } // namespace |
111 | 116 |
112 CrossSiteResourceHandler::CrossSiteResourceHandler( | 117 CrossSiteResourceHandler::CrossSiteResourceHandler( |
113 scoped_ptr<ResourceHandler> next_handler, | 118 scoped_ptr<ResourceHandler> next_handler, |
114 net::URLRequest* request) | 119 net::URLRequest* request) |
115 : LayeredResourceHandler(request, next_handler.Pass()), | 120 : LayeredResourceHandler(request, next_handler.Pass()), |
116 has_started_response_(false), | 121 has_started_response_(false), |
117 in_cross_site_transition_(false), | 122 in_cross_site_transition_(false), |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
152 ResourceResponse* response, | 157 ResourceResponse* response, |
153 bool* defer) { | 158 bool* defer) { |
154 // At this point, we know that the response is safe to send back to the | 159 // At this point, we know that the response is safe to send back to the |
155 // renderer: it is not a download, and it has passed the SSL and safe | 160 // renderer: it is not a download, and it has passed the SSL and safe |
156 // browsing checks. | 161 // browsing checks. |
157 // We should not have already started the transition before now. | 162 // We should not have already started the transition before now. |
158 DCHECK(!in_cross_site_transition_); | 163 DCHECK(!in_cross_site_transition_); |
159 | 164 |
160 ResourceRequestInfoImpl* info = GetRequestInfo(); | 165 ResourceRequestInfoImpl* info = GetRequestInfo(); |
161 | 166 |
162 // We only need to pause the response if a transfer to a different process is | 167 // The content embedder can decide that a transfer to a different process is |
163 // required. Other cross-process navigations can proceed immediately, since | 168 // required for this URL. If so, pause the response now. Other cross process |
164 // we run the unload handler at commit time. | 169 // navigations can proceed immediately, since we run the unload handler at |
165 // Note that a process swap may no longer be necessary if we transferred back | 170 // commit time. Note that a process swap may no longer be necessary if we |
166 // into the original process due to a redirect. | 171 // transferred back into the original process due to a redirect. |
167 bool should_transfer = | 172 bool definitely_transfer = |
168 GetContentClient()->browser()->ShouldSwapProcessesForRedirect( | 173 GetContentClient()->browser()->ShouldSwapProcessesForRedirect( |
169 info->GetContext(), request()->original_url(), request()->url()); | 174 info->GetContext(), request()->original_url(), request()->url()); |
170 | 175 |
171 // If this is a download, just pass the response through without doing a | 176 // If this is a download, just pass the response through without doing a |
172 // cross-site check. The renderer will see it is a download and abort the | 177 // cross-site check. The renderer will see it is a download and abort the |
173 // request. | 178 // request. |
174 // | 179 // |
175 // Similarly, HTTP 204 (No Content) responses leave us showing the previous | 180 // Similarly, HTTP 204 (No Content) responses leave us showing the previous |
176 // page. We should allow the navigation to finish without running the unload | 181 // page. We should allow the navigation to finish without running the unload |
177 // handler or swapping in the pending RenderFrameHost. | 182 // handler or swapping in the pending RenderFrameHost. |
178 // | 183 // |
179 // In both cases, any pending RenderFrameHost (if one was created for this | 184 // In both cases, any pending RenderFrameHost (if one was created for this |
180 // navigation) will stick around until the next cross-site navigation, since | 185 // navigation) will stick around until the next cross-site navigation, since |
181 // we are unable to tell when to destroy it. | 186 // we are unable to tell when to destroy it. |
182 // See RenderFrameHostManager::RendererAbortedProvisionalLoad. | 187 // See RenderFrameHostManager::RendererAbortedProvisionalLoad. |
183 // | 188 // |
184 // TODO(davidben): Unify IsDownload() and is_stream(). Several places need to | 189 // TODO(davidben): Unify IsDownload() and is_stream(). Several places need to |
185 // check for both and remembering about streams is error-prone. | 190 // check for both and remembering about streams is error-prone. |
186 if (info->IsDownload() || info->is_stream() || | 191 if (info->IsDownload() || info->is_stream() || |
187 (response->head.headers.get() && | 192 (response->head.headers.get() && |
188 response->head.headers->response_code() == 204)) { | 193 response->head.headers->response_code() == 204)) { |
189 return next_handler_->OnResponseStarted(response, defer); | 194 return next_handler_->OnResponseStarted(response, defer); |
190 } | 195 } |
191 | 196 |
192 // When the --site-per-process flag is passed, we transfer processes for | 197 if (definitely_transfer) { |
193 // cross-site navigations. This is skipped if a transfer is already required | 198 // Now that we know a transfer is needed and we have something to commit, we |
194 // or for WebUI processes for now, since pages like the NTP host multiple | 199 // pause to let the UI thread set up the transfer. |
200 StartCrossSiteTransition(response); | |
201 | |
202 // Defer loading until after the new renderer process has issued a | |
203 // corresponding request. | |
204 *defer = true; | |
205 OnDidDefer(); | |
206 return true; | |
207 } | |
208 | |
209 // In the site-per-process model, we may also decide (independently from the | |
210 // content embedder's ShouldSwapProcessesForRedirect decision above) that a | |
211 // process transfer is needed. For that we need to consult the navigation | |
212 // policy on the UI thread, so pause the response. Process transfers are | |
213 // skipped for WebUI processes for now, since pages like the NTP host multiple | |
Charlie Reis
2015/07/13 22:13:14
While we're here, let's fix this wording: the NTP
ncarter (slow)
2015/07/20 17:45:46
Done.
| |
195 // cross-site WebUI iframes. | 214 // cross-site WebUI iframes. |
196 if (!should_transfer && | 215 if (SiteIsolationPolicy::AreCrossProcessFramesPossible() && |
197 base::CommandLine::ForCurrentProcess()->HasSwitch( | |
198 switches::kSitePerProcess) && | |
199 !ChildProcessSecurityPolicyImpl::GetInstance()->HasWebUIBindings( | 216 !ChildProcessSecurityPolicyImpl::GetInstance()->HasWebUIBindings( |
200 info->GetChildID())) { | 217 info->GetChildID())) { |
201 return DeferForNavigationPolicyCheck(info, response, defer); | 218 return DeferForNavigationPolicyCheck(info, response, defer); |
202 } | 219 } |
203 | 220 |
204 if (!should_transfer) | 221 // No deferral needed. Pass the response through. |
205 return next_handler_->OnResponseStarted(response, defer); | 222 return next_handler_->OnResponseStarted(response, defer); |
206 | |
207 // Now that we know a transfer is needed and we have something to commit, we | |
208 // pause to let the UI thread set up the transfer. | |
209 StartCrossSiteTransition(response); | |
210 | |
211 // Defer loading until after the new renderer process has issued a | |
212 // corresponding request. | |
213 *defer = true; | |
214 OnDidDefer(); | |
215 return true; | |
216 } | 223 } |
217 | 224 |
218 void CrossSiteResourceHandler::ResumeOrTransfer(bool is_transfer) { | 225 void CrossSiteResourceHandler::ResumeOrTransfer(bool is_transfer) { |
219 if (is_transfer) { | 226 if (is_transfer) { |
220 StartCrossSiteTransition(response_.get()); | 227 StartCrossSiteTransition(response_.get()); |
221 } else { | 228 } else { |
222 ResumeResponse(); | 229 ResumeResponse(); |
223 } | 230 } |
224 } | 231 } |
225 | 232 |
(...skipping 146 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
372 controller()->Resume(); | 379 controller()->Resume(); |
373 } | 380 } |
374 } | 381 } |
375 | 382 |
376 void CrossSiteResourceHandler::OnDidDefer() { | 383 void CrossSiteResourceHandler::OnDidDefer() { |
377 did_defer_ = true; | 384 did_defer_ = true; |
378 request()->LogBlockedBy("CrossSiteResourceHandler"); | 385 request()->LogBlockedBy("CrossSiteResourceHandler"); |
379 } | 386 } |
380 | 387 |
381 } // namespace content | 388 } // namespace content |
OLD | NEW |