Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(264)

Side by Side Diff: content/browser/renderer_host/cross_site_resource_handler.cc

Issue 10568005: Balance defers with Resume. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: Created 8 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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 <string> 5 #include <string>
6 6
7 #include "content/browser/renderer_host/cross_site_resource_handler.h" 7 #include "content/browser/renderer_host/cross_site_resource_handler.h"
8 8
9 #include "base/bind.h" 9 #include "base/bind.h"
10 #include "base/logging.h" 10 #include "base/logging.h"
11 #include "content/browser/renderer_host/render_view_host_delegate.h" 11 #include "content/browser/renderer_host/render_view_host_delegate.h"
12 #include "content/browser/renderer_host/render_view_host_impl.h" 12 #include "content/browser/renderer_host/render_view_host_impl.h"
13 #include "content/browser/renderer_host/resource_dispatcher_host_impl.h"
14 #include "content/browser/renderer_host/resource_request_info_impl.h" 13 #include "content/browser/renderer_host/resource_request_info_impl.h"
15 #include "content/public/browser/browser_thread.h" 14 #include "content/public/browser/browser_thread.h"
16 #include "content/public/browser/global_request_id.h" 15 #include "content/public/browser/resource_controller.h"
17 #include "content/public/common/resource_response.h" 16 #include "content/public/common/resource_response.h"
18 #include "net/base/io_buffer.h"
19 #include "net/http/http_response_headers.h" 17 #include "net/http/http_response_headers.h"
20 18
21 namespace content { 19 namespace content {
22 20
23 namespace { 21 namespace {
24 22
25 void OnCrossSiteResponseHelper(int render_process_id, 23 void OnCrossSiteResponseHelper(int render_process_id,
26 int render_view_id, 24 int render_view_id,
27 int request_id) { 25 int request_id) {
28 RenderViewHostImpl* rvh = RenderViewHostImpl::FromID(render_process_id, 26 RenderViewHostImpl* rvh = RenderViewHostImpl::FromID(render_process_id,
29 render_view_id); 27 render_view_id);
30 if (rvh && rvh->GetDelegate()->GetRendererManagementDelegate()) { 28 if (rvh && rvh->GetDelegate()->GetRendererManagementDelegate()) {
31 rvh->GetDelegate()->GetRendererManagementDelegate()->OnCrossSiteResponse( 29 rvh->GetDelegate()->GetRendererManagementDelegate()->OnCrossSiteResponse(
32 render_process_id, request_id); 30 render_process_id, request_id);
33 } 31 }
34 } 32 }
35 33
36 } // namespace 34 } // namespace
37 35
38 CrossSiteResourceHandler::CrossSiteResourceHandler( 36 CrossSiteResourceHandler::CrossSiteResourceHandler(
39 scoped_ptr<ResourceHandler> next_handler, 37 scoped_ptr<ResourceHandler> next_handler,
40 int render_process_host_id, 38 int render_process_host_id,
41 int render_view_id, 39 int render_view_id,
42 ResourceDispatcherHostImpl* rdh) 40 net::URLRequest* request)
43 : LayeredResourceHandler(next_handler.Pass()), 41 : LayeredResourceHandler(next_handler.Pass()),
44 render_process_host_id_(render_process_host_id), 42 render_process_host_id_(render_process_host_id),
45 render_view_id_(render_view_id), 43 render_view_id_(render_view_id),
44 request_(request),
46 has_started_response_(false), 45 has_started_response_(false),
47 in_cross_site_transition_(false), 46 in_cross_site_transition_(false),
48 request_id_(-1), 47 request_id_(-1),
49 completed_during_transition_(false), 48 completed_during_transition_(false),
50 did_defer_(false), 49 did_defer_(false),
51 completed_status_(), 50 completed_status_(),
52 response_(NULL), 51 response_(NULL) {
53 rdh_(rdh) {
54 } 52 }
55 53
56 CrossSiteResourceHandler::~CrossSiteResourceHandler() { 54 CrossSiteResourceHandler::~CrossSiteResourceHandler() {
57 } 55 }
58 56
59 bool CrossSiteResourceHandler::OnRequestRedirected( 57 bool CrossSiteResourceHandler::OnRequestRedirected(
60 int request_id, 58 int request_id,
61 const GURL& new_url, 59 const GURL& new_url,
62 ResourceResponse* response, 60 ResourceResponse* response,
63 bool* defer) { 61 bool* defer) {
64 // We should not have started the transition before being redirected. 62 // We should not have started the transition before being redirected.
65 DCHECK(!in_cross_site_transition_); 63 DCHECK(!in_cross_site_transition_);
66 return next_handler_->OnRequestRedirected( 64 return next_handler_->OnRequestRedirected(
67 request_id, new_url, response, defer); 65 request_id, new_url, response, defer);
68 } 66 }
69 67
70 bool CrossSiteResourceHandler::OnResponseStarted( 68 bool CrossSiteResourceHandler::OnResponseStarted(
71 int request_id, 69 int request_id,
72 ResourceResponse* response, 70 ResourceResponse* response,
73 bool* defer) { 71 bool* defer) {
74 // At this point, we know that the response is safe to send back to the 72 // At this point, we know that the response is safe to send back to the
75 // renderer: it is not a download, and it has passed the SSL and safe 73 // renderer: it is not a download, and it has passed the SSL and safe
76 // browsing checks. 74 // browsing checks.
77 // We should not have already started the transition before now. 75 // We should not have already started the transition before now.
78 DCHECK(!in_cross_site_transition_); 76 DCHECK(!in_cross_site_transition_);
79 has_started_response_ = true; 77 has_started_response_ = true;
80 78
81 // Look up the request and associated info. 79 ResourceRequestInfoImpl* info = ResourceRequestInfoImpl::ForRequest(request_);
82 GlobalRequestID global_id(render_process_host_id_, request_id);
83 net::URLRequest* request = rdh_->GetURLRequest(global_id);
84 if (!request) {
85 DLOG(WARNING) << "Request wasn't found";
86 return false;
87 }
88 ResourceRequestInfoImpl* info = ResourceRequestInfoImpl::ForRequest(request);
89 80
90 // If this is a download, just pass the response through without doing a 81 // If this is a download, just pass the response through without doing a
91 // cross-site check. The renderer will see it is a download and abort the 82 // cross-site check. The renderer will see it is a download and abort the
92 // request. 83 // request.
93 // 84 //
94 // Similarly, HTTP 204 (No Content) responses leave us showing the previous 85 // Similarly, HTTP 204 (No Content) responses leave us showing the previous
95 // page. We should allow the navigation to finish without running the unload 86 // page. We should allow the navigation to finish without running the unload
96 // handler or swapping in the pending RenderViewHost. 87 // handler or swapping in the pending RenderViewHost.
97 // 88 //
98 // In both cases, the pending RenderViewHost will stick around until the next 89 // In both cases, the pending RenderViewHost will stick around until the next
99 // cross-site navigation, since we are unable to tell when to destroy it. 90 // cross-site navigation, since we are unable to tell when to destroy it.
100 // See RenderViewHostManager::RendererAbortedProvisionalLoad. 91 // See RenderViewHostManager::RendererAbortedProvisionalLoad.
101 if (info->is_download() || 92 if (info->is_download() ||
102 (response->headers && response->headers->response_code() == 204)) { 93 (response->headers && response->headers->response_code() == 204)) {
103 return next_handler_->OnResponseStarted(request_id, response, defer); 94 return next_handler_->OnResponseStarted(request_id, response, defer);
104 } 95 }
105 96
106 // Tell the renderer to run the onunload event handler, and wait for the 97 // Tell the renderer to run the onunload event handler, and wait for the
107 // reply. 98 // reply.
108 StartCrossSiteTransition(request_id, response, global_id, defer); 99 StartCrossSiteTransition(request_id, response, defer);
109 return true; 100 return true;
110 } 101 }
111 102
112 bool CrossSiteResourceHandler::OnReadCompleted(int request_id, 103 bool CrossSiteResourceHandler::OnReadCompleted(int request_id,
113 int* bytes_read, 104 int* bytes_read,
114 bool* defer) { 105 bool* defer) {
115 if (!in_cross_site_transition_) { 106 if (!in_cross_site_transition_) {
116 return next_handler_->OnReadCompleted(request_id, bytes_read, defer); 107 return next_handler_->OnReadCompleted(request_id, bytes_read, defer);
117 } 108 }
118 return true; 109 return true;
119 } 110 }
120 111
121 bool CrossSiteResourceHandler::OnResponseCompleted( 112 bool CrossSiteResourceHandler::OnResponseCompleted(
122 int request_id, 113 int request_id,
123 const net::URLRequestStatus& status, 114 const net::URLRequestStatus& status,
124 const std::string& security_info) { 115 const std::string& security_info) {
125 if (!in_cross_site_transition_) { 116 if (!in_cross_site_transition_) {
126 if (has_started_response_ || 117 if (has_started_response_ ||
127 status.status() != net::URLRequestStatus::FAILED) { 118 status.status() != net::URLRequestStatus::FAILED) {
128 // We've already completed the transition or we're canceling the request, 119 // We've already completed the transition or we're canceling the request,
129 // so just pass it through. 120 // so just pass it through.
130 return next_handler_->OnResponseCompleted(request_id, status, 121 return next_handler_->OnResponseCompleted(request_id, status,
131 security_info); 122 security_info);
132 } 123 }
133 124
134 // An error occured, we should wait now for the cross-site transition, 125 // An error occured, we should wait now for the cross-site transition,
135 // so that the error message (e.g., 404) can be displayed to the user. 126 // so that the error message (e.g., 404) can be displayed to the user.
136 // Also continue with the logic below to remember that we completed 127 // Also continue with the logic below to remember that we completed
137 // during the cross-site transition. 128 // during the cross-site transition.
138 GlobalRequestID global_id(render_process_host_id_, request_id);
139 bool defer = false; 129 bool defer = false;
140 StartCrossSiteTransition(request_id, NULL, global_id, &defer); 130 StartCrossSiteTransition(request_id, NULL, &defer);
141 DCHECK(!defer); // Since !has_started_response_. 131 DCHECK(!defer); // Since !has_started_response_.
142 } 132 }
143 133
144 // We have to buffer the call until after the transition completes. 134 // We have to buffer the call until after the transition completes.
145 completed_during_transition_ = true; 135 completed_during_transition_ = true;
146 completed_status_ = status; 136 completed_status_ = status;
147 completed_security_info_ = security_info; 137 completed_security_info_ = security_info;
148 138
149 // Return false to tell RDH not to notify the world or clean up the 139 // Return false to tell RDH not to notify the world or clean up the
150 // pending request. We will do so in ResumeResponse. 140 // pending request. We will do so in ResumeResponse.
151 return false; 141 return false;
152 } 142 }
153 143
154 // We can now send the response to the new renderer, which will cause 144 // We can now send the response to the new renderer, which will cause
155 // WebContentsImpl to swap in the new renderer and destroy the old one. 145 // WebContentsImpl to swap in the new renderer and destroy the old one.
156 void CrossSiteResourceHandler::ResumeResponse() { 146 void CrossSiteResourceHandler::ResumeResponse() {
157 DCHECK(request_id_ != -1); 147 DCHECK(request_id_ != -1);
158 DCHECK(in_cross_site_transition_); 148 DCHECK(in_cross_site_transition_);
159 in_cross_site_transition_ = false; 149 in_cross_site_transition_ = false;
160 150
161 // Find the request for this response.
162 GlobalRequestID global_id(render_process_host_id_, request_id_);
163 net::URLRequest* request = rdh_->GetURLRequest(global_id);
164 if (!request) {
165 DLOG(WARNING) << "Resuming a request that wasn't found";
166 return;
167 }
168
169 if (has_started_response_) { 151 if (has_started_response_) {
170 // Send OnResponseStarted to the new renderer. 152 // Send OnResponseStarted to the new renderer.
171 DCHECK(response_); 153 DCHECK(response_);
172 bool defer = false; 154 bool defer = false;
173 if (!next_handler_->OnResponseStarted(request_id_, response_, &defer)) { 155 if (!next_handler_->OnResponseStarted(request_id_, response_, &defer)) {
174 controller()->Cancel(); 156 controller()->Cancel();
175 } else if (!defer) { 157 } else if (!defer) {
176 // Unpause the request to resume reading. Any further reads will be 158 // Unpause the request to resume reading. Any further reads will be
177 // directed toward the new renderer. 159 // directed toward the new renderer.
178 ResumeIfDeferred(); 160 ResumeIfDeferred();
179 } 161 }
180 } 162 }
181 163
182 // Remove ourselves from the ExtraRequestInfo. 164 // Remove ourselves from the ExtraRequestInfo.
183 ResourceRequestInfoImpl* info = 165 ResourceRequestInfoImpl* info =
184 ResourceRequestInfoImpl::ForRequest(request); 166 ResourceRequestInfoImpl::ForRequest(request_);
185 info->set_cross_site_handler(NULL); 167 info->set_cross_site_handler(NULL);
186 168
187 // If the response completed during the transition, notify the next 169 // If the response completed during the transition, notify the next
188 // event handler. 170 // event handler.
189 if (completed_during_transition_) { 171 if (completed_during_transition_) {
190 if (next_handler_->OnResponseCompleted(request_id_, completed_status_, 172 if (next_handler_->OnResponseCompleted(request_id_, completed_status_,
191 completed_security_info_)) { 173 completed_security_info_)) {
192 ResumeIfDeferred(); 174 ResumeIfDeferred();
193 } 175 }
194 } 176 }
195 } 177 }
196 178
197 // Prepare to render the cross-site response in a new RenderViewHost, by 179 // Prepare to render the cross-site response in a new RenderViewHost, by
198 // telling the old RenderViewHost to run its onunload handler. 180 // telling the old RenderViewHost to run its onunload handler.
199 void CrossSiteResourceHandler::StartCrossSiteTransition( 181 void CrossSiteResourceHandler::StartCrossSiteTransition(
200 int request_id, 182 int request_id,
201 ResourceResponse* response, 183 ResourceResponse* response,
202 const GlobalRequestID& global_id,
203 bool* defer) { 184 bool* defer) {
204 in_cross_site_transition_ = true; 185 in_cross_site_transition_ = true;
205 request_id_ = request_id; 186 request_id_ = request_id;
206 response_ = response; 187 response_ = response;
207 188
208 // Store this handler on the ExtraRequestInfo, so that RDH can call our 189 // Store this handler on the ExtraRequestInfo, so that RDH can call our
209 // ResumeResponse method when the close ACK is received. 190 // ResumeResponse method when the close ACK is received.
210 net::URLRequest* request = rdh_->GetURLRequest(global_id);
211 if (!request) {
212 DLOG(WARNING) << "Cross site response for a request that wasn't found";
213 return;
214 }
215 ResourceRequestInfoImpl* info = 191 ResourceRequestInfoImpl* info =
216 ResourceRequestInfoImpl::ForRequest(request); 192 ResourceRequestInfoImpl::ForRequest(request_);
217 info->set_cross_site_handler(this); 193 info->set_cross_site_handler(this);
218 194
219 if (has_started_response_) { 195 if (has_started_response_) {
220 // Defer the request until the old renderer is finished and the new 196 // Defer the request until the old renderer is finished and the new
221 // renderer is ready. 197 // renderer is ready.
222 did_defer_ = *defer = true; 198 did_defer_ = *defer = true;
223 } 199 }
224 // If our OnResponseStarted wasn't called, then we're being called by 200 // If our OnResponseStarted wasn't called, then we're being called by
225 // OnResponseCompleted after a failure. We don't need to pause, because 201 // OnResponseCompleted after a failure. We don't need to pause, because
226 // there will be no reads. 202 // there will be no reads.
(...skipping 15 matching lines...) Expand all
242 } 218 }
243 219
244 void CrossSiteResourceHandler::ResumeIfDeferred() { 220 void CrossSiteResourceHandler::ResumeIfDeferred() {
245 if (did_defer_) { 221 if (did_defer_) {
246 did_defer_ = false; 222 did_defer_ = false;
247 controller()->Resume(); 223 controller()->Resume();
248 } 224 }
249 } 225 }
250 226
251 } // namespace content 227 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698