| 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" |
| 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() { |
| 55 // Cleanup back-pointer stored on the request info. |
| 56 ResourceRequestInfoImpl::ForRequest(request_)->set_cross_site_handler(NULL); |
| 57 } | 57 } |
| 58 | 58 |
| 59 bool CrossSiteResourceHandler::OnRequestRedirected( | 59 bool CrossSiteResourceHandler::OnRequestRedirected( |
| 60 int request_id, | 60 int request_id, |
| 61 const GURL& new_url, | 61 const GURL& new_url, |
| 62 ResourceResponse* response, | 62 ResourceResponse* response, |
| 63 bool* defer) { | 63 bool* defer) { |
| 64 // We should not have started the transition before being redirected. | 64 // We should not have started the transition before being redirected. |
| 65 DCHECK(!in_cross_site_transition_); | 65 DCHECK(!in_cross_site_transition_); |
| 66 return next_handler_->OnRequestRedirected( | 66 return next_handler_->OnRequestRedirected( |
| 67 request_id, new_url, response, defer); | 67 request_id, new_url, response, defer); |
| 68 } | 68 } |
| 69 | 69 |
| 70 bool CrossSiteResourceHandler::OnResponseStarted( | 70 bool CrossSiteResourceHandler::OnResponseStarted( |
| 71 int request_id, | 71 int request_id, |
| 72 ResourceResponse* response, | 72 ResourceResponse* response, |
| 73 bool* defer) { | 73 bool* defer) { |
| 74 // At this point, we know that the response is safe to send back to the | 74 // 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 | 75 // renderer: it is not a download, and it has passed the SSL and safe |
| 76 // browsing checks. | 76 // browsing checks. |
| 77 // We should not have already started the transition before now. | 77 // We should not have already started the transition before now. |
| 78 DCHECK(!in_cross_site_transition_); | 78 DCHECK(!in_cross_site_transition_); |
| 79 has_started_response_ = true; | 79 has_started_response_ = true; |
| 80 | 80 |
| 81 // Look up the request and associated info. | 81 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 | 82 |
| 90 // If this is a download, just pass the response through without doing a | 83 // 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 | 84 // cross-site check. The renderer will see it is a download and abort the |
| 92 // request. | 85 // request. |
| 93 // | 86 // |
| 94 // Similarly, HTTP 204 (No Content) responses leave us showing the previous | 87 // Similarly, HTTP 204 (No Content) responses leave us showing the previous |
| 95 // page. We should allow the navigation to finish without running the unload | 88 // page. We should allow the navigation to finish without running the unload |
| 96 // handler or swapping in the pending RenderViewHost. | 89 // handler or swapping in the pending RenderViewHost. |
| 97 // | 90 // |
| 98 // In both cases, the pending RenderViewHost will stick around until the next | 91 // 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. | 92 // cross-site navigation, since we are unable to tell when to destroy it. |
| 100 // See RenderViewHostManager::RendererAbortedProvisionalLoad. | 93 // See RenderViewHostManager::RendererAbortedProvisionalLoad. |
| 101 if (info->is_download() || | 94 if (info->is_download() || |
| 102 (response->headers && response->headers->response_code() == 204)) { | 95 (response->headers && response->headers->response_code() == 204)) { |
| 103 return next_handler_->OnResponseStarted(request_id, response, defer); | 96 return next_handler_->OnResponseStarted(request_id, response, defer); |
| 104 } | 97 } |
| 105 | 98 |
| 106 // Tell the renderer to run the onunload event handler, and wait for the | 99 // Tell the renderer to run the onunload event handler, and wait for the |
| 107 // reply. | 100 // reply. |
| 108 StartCrossSiteTransition(request_id, response, global_id, defer); | 101 StartCrossSiteTransition(request_id, response, defer); |
| 109 return true; | 102 return true; |
| 110 } | 103 } |
| 111 | 104 |
| 112 bool CrossSiteResourceHandler::OnReadCompleted(int request_id, | 105 bool CrossSiteResourceHandler::OnReadCompleted(int request_id, |
| 113 int* bytes_read, | 106 int* bytes_read, |
| 114 bool* defer) { | 107 bool* defer) { |
| 115 if (!in_cross_site_transition_) { | 108 if (!in_cross_site_transition_) { |
| 116 return next_handler_->OnReadCompleted(request_id, bytes_read, defer); | 109 return next_handler_->OnReadCompleted(request_id, bytes_read, defer); |
| 117 } | 110 } |
| 118 return true; | 111 return true; |
| 119 } | 112 } |
| 120 | 113 |
| 121 bool CrossSiteResourceHandler::OnResponseCompleted( | 114 bool CrossSiteResourceHandler::OnResponseCompleted( |
| 122 int request_id, | 115 int request_id, |
| 123 const net::URLRequestStatus& status, | 116 const net::URLRequestStatus& status, |
| 124 const std::string& security_info) { | 117 const std::string& security_info) { |
| 125 if (!in_cross_site_transition_) { | 118 if (!in_cross_site_transition_) { |
| 126 if (has_started_response_ || | 119 if (has_started_response_ || |
| 127 status.status() != net::URLRequestStatus::FAILED) { | 120 status.status() != net::URLRequestStatus::FAILED) { |
| 128 // We've already completed the transition or we're canceling the request, | 121 // We've already completed the transition or we're canceling the request, |
| 129 // so just pass it through. | 122 // so just pass it through. |
| 130 return next_handler_->OnResponseCompleted(request_id, status, | 123 return next_handler_->OnResponseCompleted(request_id, status, |
| 131 security_info); | 124 security_info); |
| 132 } | 125 } |
| 133 | 126 |
| 134 // An error occured, we should wait now for the cross-site transition, | 127 // 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. | 128 // 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 | 129 // Also continue with the logic below to remember that we completed |
| 137 // during the cross-site transition. | 130 // during the cross-site transition. |
| 138 GlobalRequestID global_id(render_process_host_id_, request_id); | |
| 139 bool defer = false; | 131 bool defer = false; |
| 140 StartCrossSiteTransition(request_id, NULL, global_id, &defer); | 132 StartCrossSiteTransition(request_id, NULL, &defer); |
| 141 DCHECK(!defer); // Since !has_started_response_. | 133 DCHECK(!defer); // Since !has_started_response_. |
| 142 } | 134 } |
| 143 | 135 |
| 144 // We have to buffer the call until after the transition completes. | 136 // We have to buffer the call until after the transition completes. |
| 145 completed_during_transition_ = true; | 137 completed_during_transition_ = true; |
| 146 completed_status_ = status; | 138 completed_status_ = status; |
| 147 completed_security_info_ = security_info; | 139 completed_security_info_ = security_info; |
| 148 | 140 |
| 149 // Return false to tell RDH not to notify the world or clean up the | 141 // Return false to tell RDH not to notify the world or clean up the |
| 150 // pending request. We will do so in ResumeResponse. | 142 // pending request. We will do so in ResumeResponse. |
| 151 return false; | 143 return false; |
| 152 } | 144 } |
| 153 | 145 |
| 154 // We can now send the response to the new renderer, which will cause | 146 // 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. | 147 // WebContentsImpl to swap in the new renderer and destroy the old one. |
| 156 void CrossSiteResourceHandler::ResumeResponse() { | 148 void CrossSiteResourceHandler::ResumeResponse() { |
| 157 DCHECK(request_id_ != -1); | 149 DCHECK(request_id_ != -1); |
| 158 DCHECK(in_cross_site_transition_); | 150 DCHECK(in_cross_site_transition_); |
| 159 in_cross_site_transition_ = false; | 151 in_cross_site_transition_ = false; |
| 160 | 152 |
| 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_) { | 153 if (has_started_response_) { |
| 170 // Send OnResponseStarted to the new renderer. | 154 // Send OnResponseStarted to the new renderer. |
| 171 DCHECK(response_); | 155 DCHECK(response_); |
| 172 bool defer = false; | 156 bool defer = false; |
| 173 if (!next_handler_->OnResponseStarted(request_id_, response_, &defer)) { | 157 if (!next_handler_->OnResponseStarted(request_id_, response_, &defer)) { |
| 174 controller()->Cancel(); | 158 controller()->Cancel(); |
| 175 } else if (!defer) { | 159 } else if (!defer) { |
| 176 // Unpause the request to resume reading. Any further reads will be | 160 // Unpause the request to resume reading. Any further reads will be |
| 177 // directed toward the new renderer. | 161 // directed toward the new renderer. |
| 178 ResumeIfDeferred(); | 162 ResumeIfDeferred(); |
| 179 } | 163 } |
| 180 } | 164 } |
| 181 | 165 |
| 182 // Remove ourselves from the ExtraRequestInfo. | 166 // Remove ourselves from the ExtraRequestInfo. |
| 183 ResourceRequestInfoImpl* info = | 167 ResourceRequestInfoImpl* info = |
| 184 ResourceRequestInfoImpl::ForRequest(request); | 168 ResourceRequestInfoImpl::ForRequest(request_); |
| 185 info->set_cross_site_handler(NULL); | 169 info->set_cross_site_handler(NULL); |
| 186 | 170 |
| 187 // If the response completed during the transition, notify the next | 171 // If the response completed during the transition, notify the next |
| 188 // event handler. | 172 // event handler. |
| 189 if (completed_during_transition_) { | 173 if (completed_during_transition_) { |
| 190 if (next_handler_->OnResponseCompleted(request_id_, completed_status_, | 174 if (next_handler_->OnResponseCompleted(request_id_, completed_status_, |
| 191 completed_security_info_)) { | 175 completed_security_info_)) { |
| 192 ResumeIfDeferred(); | 176 ResumeIfDeferred(); |
| 193 } | 177 } |
| 194 } | 178 } |
| 195 } | 179 } |
| 196 | 180 |
| 197 // Prepare to render the cross-site response in a new RenderViewHost, by | 181 // Prepare to render the cross-site response in a new RenderViewHost, by |
| 198 // telling the old RenderViewHost to run its onunload handler. | 182 // telling the old RenderViewHost to run its onunload handler. |
| 199 void CrossSiteResourceHandler::StartCrossSiteTransition( | 183 void CrossSiteResourceHandler::StartCrossSiteTransition( |
| 200 int request_id, | 184 int request_id, |
| 201 ResourceResponse* response, | 185 ResourceResponse* response, |
| 202 const GlobalRequestID& global_id, | |
| 203 bool* defer) { | 186 bool* defer) { |
| 204 in_cross_site_transition_ = true; | 187 in_cross_site_transition_ = true; |
| 205 request_id_ = request_id; | 188 request_id_ = request_id; |
| 206 response_ = response; | 189 response_ = response; |
| 207 | 190 |
| 208 // Store this handler on the ExtraRequestInfo, so that RDH can call our | 191 // Store this handler on the ExtraRequestInfo, so that RDH can call our |
| 209 // ResumeResponse method when the close ACK is received. | 192 // 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 = | 193 ResourceRequestInfoImpl* info = |
| 216 ResourceRequestInfoImpl::ForRequest(request); | 194 ResourceRequestInfoImpl::ForRequest(request_); |
| 217 info->set_cross_site_handler(this); | 195 info->set_cross_site_handler(this); |
| 218 | 196 |
| 219 if (has_started_response_) { | 197 if (has_started_response_) { |
| 220 // Defer the request until the old renderer is finished and the new | 198 // Defer the request until the old renderer is finished and the new |
| 221 // renderer is ready. | 199 // renderer is ready. |
| 222 did_defer_ = *defer = true; | 200 did_defer_ = *defer = true; |
| 223 } | 201 } |
| 224 // If our OnResponseStarted wasn't called, then we're being called by | 202 // If our OnResponseStarted wasn't called, then we're being called by |
| 225 // OnResponseCompleted after a failure. We don't need to pause, because | 203 // OnResponseCompleted after a failure. We don't need to pause, because |
| 226 // there will be no reads. | 204 // there will be no reads. |
| (...skipping 15 matching lines...) Expand all Loading... |
| 242 } | 220 } |
| 243 | 221 |
| 244 void CrossSiteResourceHandler::ResumeIfDeferred() { | 222 void CrossSiteResourceHandler::ResumeIfDeferred() { |
| 245 if (did_defer_) { | 223 if (did_defer_) { |
| 246 did_defer_ = false; | 224 did_defer_ = false; |
| 247 controller()->Resume(); | 225 controller()->Resume(); |
| 248 } | 226 } |
| 249 } | 227 } |
| 250 | 228 |
| 251 } // namespace content | 229 } // namespace content |
| OLD | NEW |