| // Copyright 2014 The Chromium Authors. All rights reserved. | 
 | // Use of this source code is governed by a BSD-style license that can be | 
 | // found in the LICENSE file. | 
 |  | 
 | #include "content/browser/loader/navigation_resource_handler.h" | 
 |  | 
 | #include <memory> | 
 |  | 
 | #include "base/logging.h" | 
 | #include "content/browser/loader/navigation_url_loader_impl_core.h" | 
 | #include "content/browser/loader/netlog_observer.h" | 
 | #include "content/browser/loader/resource_loader.h" | 
 | #include "content/browser/loader/resource_request_info_impl.h" | 
 | #include "content/browser/resource_context_impl.h" | 
 | #include "content/browser/streams/stream.h" | 
 | #include "content/browser/streams/stream_context.h" | 
 | #include "content/public/browser/navigation_data.h" | 
 | #include "content/public/browser/resource_controller.h" | 
 | #include "content/public/browser/resource_dispatcher_host_delegate.h" | 
 | #include "content/public/browser/stream_handle.h" | 
 | #include "content/public/common/resource_response.h" | 
 | #include "content/public/common/ssl_status.h" | 
 | #include "net/base/net_errors.h" | 
 | #include "net/url_request/url_request.h" | 
 |  | 
 | namespace content { | 
 |  | 
 | NavigationResourceHandler::NavigationResourceHandler( | 
 |     net::URLRequest* request, | 
 |     NavigationURLLoaderImplCore* core, | 
 |     ResourceDispatcherHostDelegate* resource_dispatcher_host_delegate, | 
 |     CertStore* cert_store) | 
 |     : ResourceHandler(request), | 
 |       core_(core), | 
 |       resource_dispatcher_host_delegate_(resource_dispatcher_host_delegate), | 
 |       cert_store_(cert_store) { | 
 |   core_->set_resource_handler(this); | 
 |   writer_.set_immediate_mode(true); | 
 | } | 
 |  | 
 | NavigationResourceHandler::~NavigationResourceHandler() { | 
 |   if (core_) { | 
 |     core_->NotifyRequestFailed(false, net::ERR_ABORTED); | 
 |     DetachFromCore(); | 
 |   } | 
 | } | 
 |  | 
 | void NavigationResourceHandler::Cancel() { | 
 |   controller()->Cancel(); | 
 |   core_ = nullptr; | 
 | } | 
 |  | 
 | void NavigationResourceHandler::FollowRedirect() { | 
 |   controller()->Resume(); | 
 | } | 
 |  | 
 | void NavigationResourceHandler::ProceedWithResponse() { | 
 |   // Detach from the loader; at this point, the request is now owned by the | 
 |   // StreamHandle sent in OnResponseStarted. | 
 |   DetachFromCore(); | 
 |   controller()->Resume(); | 
 | } | 
 |  | 
 | void NavigationResourceHandler::SetController(ResourceController* controller) { | 
 |   writer_.set_controller(controller); | 
 |   ResourceHandler::SetController(controller); | 
 | } | 
 |  | 
 | bool NavigationResourceHandler::OnRequestRedirected( | 
 |     const net::RedirectInfo& redirect_info, | 
 |     ResourceResponse* response, | 
 |     bool* defer) { | 
 |   DCHECK(core_); | 
 |  | 
 |   // TODO(davidben): Perform a CSP check here, and anything else that would have | 
 |   // been done renderer-side. | 
 |   NetLogObserver::PopulateResponseInfo(request(), response); | 
 |   core_->NotifyRequestRedirected(redirect_info, response); | 
 |   *defer = true; | 
 |   return true; | 
 | } | 
 |  | 
 | bool NavigationResourceHandler::OnResponseStarted(ResourceResponse* response, | 
 |                                                   bool* defer) { | 
 |   DCHECK(core_); | 
 |  | 
 |   ResourceRequestInfoImpl* info = GetRequestInfo(); | 
 |  | 
 |   // If the MimeTypeResourceHandler intercepted this request and converted it | 
 |   // into a download, it will still call OnResponseStarted and immediately | 
 |   // cancel. Ignore the call; OnReadCompleted will happen shortly. | 
 |   // | 
 |   // TODO(davidben): Move the dispatch out of MimeTypeResourceHandler. Perhaps | 
 |   // all the way to the UI thread. Downloads, user certificates, etc., should be | 
 |   // dispatched at the navigation layer. | 
 |   if (info->IsDownload() || info->is_stream()) | 
 |     return true; | 
 |  | 
 |   StreamContext* stream_context = | 
 |       GetStreamContextForResourceContext(info->GetContext()); | 
 |   writer_.InitializeStream(stream_context->registry(), | 
 |                            request()->url().GetOrigin()); | 
 |  | 
 |   NetLogObserver::PopulateResponseInfo(request(), response); | 
 |  | 
 |   std::unique_ptr<NavigationData> cloned_data; | 
 |   if (resource_dispatcher_host_delegate_) { | 
 |     // Ask the embedder for a NavigationData instance. | 
 |     NavigationData* navigation_data = | 
 |         resource_dispatcher_host_delegate_->GetNavigationData(request()); | 
 |  | 
 |     // Clone the embedder's NavigationData before moving it to the UI thread. | 
 |     if (navigation_data) | 
 |       cloned_data = navigation_data->Clone(); | 
 |   } | 
 |  | 
 |   SSLStatus ssl_status; | 
 |   if (request()->ssl_info().cert.get()) { | 
 |     ResourceLoader::GetSSLStatusForRequest( | 
 |         request()->url(), request()->ssl_info(), info->GetChildID(), | 
 |         cert_store_, &ssl_status); | 
 |   } | 
 |  | 
 |   core_->NotifyResponseStarted(response, writer_.stream()->CreateHandle(), | 
 |                                ssl_status, std::move(cloned_data)); | 
 |   *defer = true; | 
 |  | 
 |   return true; | 
 | } | 
 |  | 
 | bool NavigationResourceHandler::OnWillStart(const GURL& url, bool* defer) { | 
 |   return true; | 
 | } | 
 |  | 
 | bool NavigationResourceHandler::OnWillRead(scoped_refptr<net::IOBuffer>* buf, | 
 |                                            int* buf_size, | 
 |                                            int min_size) { | 
 |   writer_.OnWillRead(buf, buf_size, min_size); | 
 |   return true; | 
 | } | 
 |  | 
 | bool NavigationResourceHandler::OnReadCompleted(int bytes_read, bool* defer) { | 
 |   writer_.OnReadCompleted(bytes_read, defer); | 
 |   return true; | 
 | } | 
 |  | 
 | void NavigationResourceHandler::OnResponseCompleted( | 
 |     const net::URLRequestStatus& status, | 
 |     const std::string& security_info, | 
 |     bool* defer) { | 
 |   // If the request has already committed, close the stream and leave it as-is. | 
 |   // | 
 |   // TODO(davidben): The net error code should be passed through StreamWriter | 
 |   // down to the stream's consumer. See https://crbug.com/426162. | 
 |   if (writer_.stream()) { | 
 |     writer_.Finalize(); | 
 |     return; | 
 |   } | 
 |  | 
 |   if (core_) { | 
 |     DCHECK_NE(net::OK, status.error()); | 
 |     core_->NotifyRequestFailed(request()->response_info().was_cached, | 
 |                                status.error()); | 
 |     DetachFromCore(); | 
 |   } | 
 | } | 
 |  | 
 | void NavigationResourceHandler::OnDataDownloaded(int bytes_downloaded) { | 
 |   NOTREACHED(); | 
 | } | 
 |  | 
 | void NavigationResourceHandler::DetachFromCore() { | 
 |   DCHECK(core_); | 
 |   core_->set_resource_handler(nullptr); | 
 |   core_ = nullptr; | 
 | } | 
 |  | 
 | }  // namespace content |