| 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 <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" |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 58 ResourceResponse* response, | 58 ResourceResponse* response, |
| 59 bool* defer) { | 59 bool* defer) { |
| 60 // We should not have started the transition before being redirected. | 60 // We should not have started the transition before being redirected. |
| 61 DCHECK(!in_cross_site_transition_); | 61 DCHECK(!in_cross_site_transition_); |
| 62 return next_handler_->OnRequestRedirected( | 62 return next_handler_->OnRequestRedirected( |
| 63 request_id, new_url, response, defer); | 63 request_id, new_url, response, defer); |
| 64 } | 64 } |
| 65 | 65 |
| 66 bool CrossSiteResourceHandler::OnResponseStarted( | 66 bool CrossSiteResourceHandler::OnResponseStarted( |
| 67 int request_id, | 67 int request_id, |
| 68 ResourceResponse* response) { | 68 ResourceResponse* response, |
| 69 bool* defer) { |
| 69 // At this point, we know that the response is safe to send back to the | 70 // At this point, we know that the response is safe to send back to the |
| 70 // renderer: it is not a download, and it has passed the SSL and safe | 71 // renderer: it is not a download, and it has passed the SSL and safe |
| 71 // browsing checks. | 72 // browsing checks. |
| 72 // We should not have already started the transition before now. | 73 // We should not have already started the transition before now. |
| 73 DCHECK(!in_cross_site_transition_); | 74 DCHECK(!in_cross_site_transition_); |
| 74 has_started_response_ = true; | 75 has_started_response_ = true; |
| 75 | 76 |
| 76 // Look up the request and associated info. | 77 // Look up the request and associated info. |
| 77 GlobalRequestID global_id(render_process_host_id_, request_id); | 78 GlobalRequestID global_id(render_process_host_id_, request_id); |
| 78 net::URLRequest* request = rdh_->GetURLRequest(global_id); | 79 net::URLRequest* request = rdh_->GetURLRequest(global_id); |
| 79 if (!request) { | 80 if (!request) { |
| 80 DLOG(WARNING) << "Request wasn't found"; | 81 DLOG(WARNING) << "Request wasn't found"; |
| 81 return false; | 82 return false; |
| 82 } | 83 } |
| 83 ResourceRequestInfoImpl* info = ResourceRequestInfoImpl::ForRequest(request); | 84 ResourceRequestInfoImpl* info = ResourceRequestInfoImpl::ForRequest(request); |
| 84 | 85 |
| 85 // If this is a download, just pass the response through without doing a | 86 // If this is a download, just pass the response through without doing a |
| 86 // cross-site check. The renderer will see it is a download and abort the | 87 // cross-site check. The renderer will see it is a download and abort the |
| 87 // request. | 88 // request. |
| 88 // | 89 // |
| 89 // Similarly, HTTP 204 (No Content) responses leave us showing the previous | 90 // Similarly, HTTP 204 (No Content) responses leave us showing the previous |
| 90 // page. We should allow the navigation to finish without running the unload | 91 // page. We should allow the navigation to finish without running the unload |
| 91 // handler or swapping in the pending RenderViewHost. | 92 // handler or swapping in the pending RenderViewHost. |
| 92 // | 93 // |
| 93 // In both cases, the pending RenderViewHost will stick around until the next | 94 // In both cases, the pending RenderViewHost will stick around until the next |
| 94 // cross-site navigation, since we are unable to tell when to destroy it. | 95 // cross-site navigation, since we are unable to tell when to destroy it. |
| 95 // See RenderViewHostManager::RendererAbortedProvisionalLoad. | 96 // See RenderViewHostManager::RendererAbortedProvisionalLoad. |
| 96 if (info->is_download() || | 97 if (info->is_download() || |
| 97 (response->headers && response->headers->response_code() == 204)) { | 98 (response->headers && response->headers->response_code() == 204)) { |
| 98 return next_handler_->OnResponseStarted(request_id, response); | 99 return next_handler_->OnResponseStarted(request_id, response, defer); |
| 99 } | 100 } |
| 100 | 101 |
| 101 // Tell the renderer to run the onunload event handler, and wait for the | 102 // Tell the renderer to run the onunload event handler, and wait for the |
| 102 // reply. | 103 // reply. |
| 103 StartCrossSiteTransition(request_id, response, global_id); | 104 StartCrossSiteTransition(request_id, response, global_id, defer); |
| 104 return true; | 105 return true; |
| 105 } | 106 } |
| 106 | 107 |
| 107 bool CrossSiteResourceHandler::OnReadCompleted(int request_id, | 108 bool CrossSiteResourceHandler::OnReadCompleted(int request_id, |
| 108 int* bytes_read) { | 109 int* bytes_read, |
| 110 bool* defer) { |
| 109 if (!in_cross_site_transition_) { | 111 if (!in_cross_site_transition_) { |
| 110 return next_handler_->OnReadCompleted(request_id, bytes_read); | 112 return next_handler_->OnReadCompleted(request_id, bytes_read, defer); |
| 111 } | 113 } |
| 112 return true; | 114 return true; |
| 113 } | 115 } |
| 114 | 116 |
| 115 bool CrossSiteResourceHandler::OnResponseCompleted( | 117 bool CrossSiteResourceHandler::OnResponseCompleted( |
| 116 int request_id, | 118 int request_id, |
| 117 const net::URLRequestStatus& status, | 119 const net::URLRequestStatus& status, |
| 118 const std::string& security_info) { | 120 const std::string& security_info) { |
| 119 if (!in_cross_site_transition_) { | 121 if (!in_cross_site_transition_) { |
| 120 if (has_started_response_ || | 122 if (has_started_response_ || |
| 121 status.status() != net::URLRequestStatus::FAILED) { | 123 status.status() != net::URLRequestStatus::FAILED) { |
| 122 // We've already completed the transition or we're canceling the request, | 124 // We've already completed the transition or we're canceling the request, |
| 123 // so just pass it through. | 125 // so just pass it through. |
| 124 return next_handler_->OnResponseCompleted(request_id, status, | 126 return next_handler_->OnResponseCompleted(request_id, status, |
| 125 security_info); | 127 security_info); |
| 126 } else { | |
| 127 // An error occured, we should wait now for the cross-site transition, | |
| 128 // so that the error message (e.g., 404) can be displayed to the user. | |
| 129 // Also continue with the logic below to remember that we completed | |
| 130 // during the cross-site transition. | |
| 131 GlobalRequestID global_id(render_process_host_id_, request_id); | |
| 132 StartCrossSiteTransition(request_id, NULL, global_id); | |
| 133 } | 128 } |
| 129 |
| 130 // An error occured, we should wait now for the cross-site transition, |
| 131 // so that the error message (e.g., 404) can be displayed to the user. |
| 132 // Also continue with the logic below to remember that we completed |
| 133 // during the cross-site transition. |
| 134 GlobalRequestID global_id(render_process_host_id_, request_id); |
| 135 bool defer = false; |
| 136 StartCrossSiteTransition(request_id, NULL, global_id, &defer); |
| 137 DCHECK(!defer); // Since !has_started_response_. |
| 134 } | 138 } |
| 135 | 139 |
| 136 // We have to buffer the call until after the transition completes. | 140 // We have to buffer the call until after the transition completes. |
| 137 completed_during_transition_ = true; | 141 completed_during_transition_ = true; |
| 138 completed_status_ = status; | 142 completed_status_ = status; |
| 139 completed_security_info_ = security_info; | 143 completed_security_info_ = security_info; |
| 140 | 144 |
| 141 // Return false to tell RDH not to notify the world or clean up the | 145 // Return false to tell RDH not to notify the world or clean up the |
| 142 // pending request. We will do so in ResumeResponse. | 146 // pending request. We will do so in ResumeResponse. |
| 143 return false; | 147 return false; |
| (...skipping 10 matching lines...) Expand all Loading... |
| 154 GlobalRequestID global_id(render_process_host_id_, request_id_); | 158 GlobalRequestID global_id(render_process_host_id_, request_id_); |
| 155 net::URLRequest* request = rdh_->GetURLRequest(global_id); | 159 net::URLRequest* request = rdh_->GetURLRequest(global_id); |
| 156 if (!request) { | 160 if (!request) { |
| 157 DLOG(WARNING) << "Resuming a request that wasn't found"; | 161 DLOG(WARNING) << "Resuming a request that wasn't found"; |
| 158 return; | 162 return; |
| 159 } | 163 } |
| 160 | 164 |
| 161 if (has_started_response_) { | 165 if (has_started_response_) { |
| 162 // Send OnResponseStarted to the new renderer. | 166 // Send OnResponseStarted to the new renderer. |
| 163 DCHECK(response_); | 167 DCHECK(response_); |
| 164 next_handler_->OnResponseStarted(request_id_, response_); | 168 bool defer = false; |
| 165 | 169 if (!next_handler_->OnResponseStarted(request_id_, response_, &defer)) { |
| 166 // Unpause the request to resume reading. Any further reads will be | 170 rdh_->CancelRequest(render_process_host_id_, request_id_, false); |
| 167 // directed toward the new renderer. | 171 } else if (!defer) { |
| 168 rdh_->PauseRequest(render_process_host_id_, request_id_, false); | 172 // Unpause the request to resume reading. Any further reads will be |
| 173 // directed toward the new renderer. |
| 174 rdh_->ResumeDeferredRequest(render_process_host_id_, request_id_); |
| 175 } else { |
| 176 CHECK(false); // XXX |
| 177 } |
| 169 } | 178 } |
| 170 | 179 |
| 171 // Remove ourselves from the ExtraRequestInfo. | 180 // Remove ourselves from the ExtraRequestInfo. |
| 172 ResourceRequestInfoImpl* info = | 181 ResourceRequestInfoImpl* info = |
| 173 ResourceRequestInfoImpl::ForRequest(request); | 182 ResourceRequestInfoImpl::ForRequest(request); |
| 174 info->set_cross_site_handler(NULL); | 183 info->set_cross_site_handler(NULL); |
| 175 | 184 |
| 176 // If the response completed during the transition, notify the next | 185 // If the response completed during the transition, notify the next |
| 177 // event handler. | 186 // event handler. |
| 178 if (completed_during_transition_) { | 187 if (completed_during_transition_) { |
| 179 next_handler_->OnResponseCompleted(request_id_, completed_status_, | 188 next_handler_->OnResponseCompleted(request_id_, completed_status_, |
| 180 completed_security_info_); | 189 completed_security_info_); |
| 181 rdh_->RemovePendingRequest(render_process_host_id_, request_id_); | 190 rdh_->RemovePendingRequest(render_process_host_id_, request_id_); |
| 182 } | 191 } |
| 183 } | 192 } |
| 184 | 193 |
| 185 CrossSiteResourceHandler::~CrossSiteResourceHandler() {} | 194 CrossSiteResourceHandler::~CrossSiteResourceHandler() {} |
| 186 | 195 |
| 187 // Prepare to render the cross-site response in a new RenderViewHost, by | 196 // Prepare to render the cross-site response in a new RenderViewHost, by |
| 188 // telling the old RenderViewHost to run its onunload handler. | 197 // telling the old RenderViewHost to run its onunload handler. |
| 189 void CrossSiteResourceHandler::StartCrossSiteTransition( | 198 void CrossSiteResourceHandler::StartCrossSiteTransition( |
| 190 int request_id, | 199 int request_id, |
| 191 ResourceResponse* response, | 200 ResourceResponse* response, |
| 192 const GlobalRequestID& global_id) { | 201 const GlobalRequestID& global_id, |
| 202 bool* defer) { |
| 193 in_cross_site_transition_ = true; | 203 in_cross_site_transition_ = true; |
| 194 request_id_ = request_id; | 204 request_id_ = request_id; |
| 195 response_ = response; | 205 response_ = response; |
| 196 | 206 |
| 197 // Store this handler on the ExtraRequestInfo, so that RDH can call our | 207 // Store this handler on the ExtraRequestInfo, so that RDH can call our |
| 198 // ResumeResponse method when the close ACK is received. | 208 // ResumeResponse method when the close ACK is received. |
| 199 net::URLRequest* request = rdh_->GetURLRequest(global_id); | 209 net::URLRequest* request = rdh_->GetURLRequest(global_id); |
| 200 if (!request) { | 210 if (!request) { |
| 201 DLOG(WARNING) << "Cross site response for a request that wasn't found"; | 211 DLOG(WARNING) << "Cross site response for a request that wasn't found"; |
| 202 return; | 212 return; |
| 203 } | 213 } |
| 204 ResourceRequestInfoImpl* info = | 214 ResourceRequestInfoImpl* info = |
| 205 ResourceRequestInfoImpl::ForRequest(request); | 215 ResourceRequestInfoImpl::ForRequest(request); |
| 206 info->set_cross_site_handler(this); | 216 info->set_cross_site_handler(this); |
| 207 | 217 |
| 208 if (has_started_response_) { | 218 if (has_started_response_) { |
| 209 // Pause the request until the old renderer is finished and the new | 219 // Defer the request until the old renderer is finished and the new |
| 210 // renderer is ready. | 220 // renderer is ready. |
| 211 rdh_->PauseRequest(render_process_host_id_, request_id, true); | 221 *defer = true; |
| 212 } | 222 } |
| 213 // If our OnResponseStarted wasn't called, then we're being called by | 223 // If our OnResponseStarted wasn't called, then we're being called by |
| 214 // OnResponseCompleted after a failure. We don't need to pause, because | 224 // OnResponseCompleted after a failure. We don't need to pause, because |
| 215 // there will be no reads. | 225 // there will be no reads. |
| 216 | 226 |
| 217 // Tell the contents responsible for this request that a cross-site response | 227 // Tell the contents responsible for this request that a cross-site response |
| 218 // is starting, so that it can tell its old renderer to run its onunload | 228 // is starting, so that it can tell its old renderer to run its onunload |
| 219 // handler now. We will wait to hear the corresponding ClosePage_ACK. | 229 // handler now. We will wait to hear the corresponding ClosePage_ACK. |
| 220 BrowserThread::PostTask( | 230 BrowserThread::PostTask( |
| 221 BrowserThread::UI, | 231 BrowserThread::UI, |
| 222 FROM_HERE, | 232 FROM_HERE, |
| 223 base::Bind( | 233 base::Bind( |
| 224 &OnCrossSiteResponseHelper, | 234 &OnCrossSiteResponseHelper, |
| 225 render_process_host_id_, | 235 render_process_host_id_, |
| 226 render_view_id_, | 236 render_view_id_, |
| 227 request_id)); | 237 request_id)); |
| 228 | 238 |
| 229 // TODO(creis): If the above call should fail, then we need to notify the IO | 239 // TODO(creis): If the above call should fail, then we need to notify the IO |
| 230 // thread to proceed anyway, using ResourceDispatcherHost::OnClosePageACK. | 240 // thread to proceed anyway, using ResourceDispatcherHost::OnClosePageACK. |
| 231 } | 241 } |
| 232 | 242 |
| 233 } // namespace content | 243 } // namespace content |
| OLD | NEW |