Chromium Code Reviews| Index: content/browser/loader/navigation_url_loader_network_service.cc |
| diff --git a/content/browser/loader/navigation_url_loader_network_service.cc b/content/browser/loader/navigation_url_loader_network_service.cc |
| index b821082ae37eb74b98d72706a042a7e8d621aaab..25eaee403a0ae9a50c064c350f9dec3f595375e1 100644 |
| --- a/content/browser/loader/navigation_url_loader_network_service.cc |
| +++ b/content/browser/loader/navigation_url_loader_network_service.cc |
| @@ -105,7 +105,8 @@ class NavigationURLLoaderNetworkService::URLLoaderRequestController |
| : resource_request_(std::move(resource_request)), |
| resource_context_(resource_context), |
| default_url_loader_factory_getter_(default_url_loader_factory_getter), |
| - owner_(owner) {} |
| + owner_(owner), |
| + fallback_response_binding_(this) {} |
| ~URLLoaderRequestController() override { |
| DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| @@ -177,11 +178,13 @@ class NavigationURLLoaderNetworkService::URLLoaderRequestController |
| // This could be called multiple times. |
| void Restart() { |
| handler_index_ = 0; |
| - MaybeStartLoader(StartLoaderCallback()); |
| + MaybeStartLoader(StartLoaderCallback(), ResponseFallback()); |
| } |
| - void MaybeStartLoader(StartLoaderCallback start_loader_callback) { |
| + void MaybeStartLoader(StartLoaderCallback start_loader_callback, |
| + ResponseFallback fallback) { |
| if (start_loader_callback) { |
| + DCHECK(!fallback); |
| url_loader_ = ThrottlingURLLoader::CreateLoaderAndStart( |
| std::move(start_loader_callback), |
| GetContentClient()->browser()->CreateURLLoaderThrottles( |
| @@ -197,6 +200,11 @@ class NavigationURLLoaderNetworkService::URLLoaderRequestController |
| subresource_loader_factory.PassInterface(); |
| } |
| return; |
| + } else { |
| + // We only support one fallback handler at any given point. AppCache is |
| + // the only handler which supports fallback responses. |
| + DCHECK(!fallback_handler_); |
| + fallback_handler_ = std::move(fallback); |
| } |
| if (handler_index_ < handlers_.size()) { |
| @@ -213,6 +221,7 @@ class NavigationURLLoaderNetworkService::URLLoaderRequestController |
| factory = default_url_loader_factory_getter_->GetBlobFactory()->get(); |
| } else { |
| factory = default_url_loader_factory_getter_->GetNetworkFactory()->get(); |
| + default_loader_used_ = true; |
| } |
| url_loader_ = ThrottlingURLLoader::CreateLoaderAndStart( |
| factory, |
| @@ -242,6 +251,12 @@ class NavigationURLLoaderNetworkService::URLLoaderRequestController |
| const ResourceResponseHead& head, |
| const base::Optional<net::SSLInfo>& ssl_info, |
| mojom::DownloadedTempFilePtr downloaded_file) override { |
| + response_ = head; |
| + // If the default loader (network) was used to handle the URL load request |
| + // we need to see if the handlers want to load a fallback for the response. |
| + if (MaybeLoadFallbackForResponse(head)) |
| + return; |
| + |
| BrowserThread::PostTask( |
| BrowserThread::UI, FROM_HERE, |
| base::Bind(&NavigationURLLoaderNetworkService::OnReceiveResponse, |
| @@ -250,6 +265,8 @@ class NavigationURLLoaderNetworkService::URLLoaderRequestController |
| void OnReceiveRedirect(const net::RedirectInfo& redirect_info, |
| const ResourceResponseHead& head) override { |
| + response_ = head; |
| + |
| BrowserThread::PostTask( |
| BrowserThread::UI, FROM_HERE, |
| base::Bind(&NavigationURLLoaderNetworkService::OnReceiveRedirect, |
| @@ -277,12 +294,48 @@ class NavigationURLLoaderNetworkService::URLLoaderRequestController |
| void OnComplete( |
| const ResourceRequestCompletionStatus& completion_status) override { |
| + // If the default loader (network) was used to handle the URL load request |
| + // we need to see if the handlers want to load a fallback for the response. |
| + if (MaybeLoadFallbackForResponse(response_)) |
| + return; |
| + |
| BrowserThread::PostTask( |
| BrowserThread::UI, FROM_HERE, |
| base::Bind(&NavigationURLLoaderNetworkService::OnComplete, owner_, |
| completion_status)); |
| } |
| + // Returns true if a handler returns a fallback response. |
| + bool MaybeLoadFallbackForResponse(const ResourceResponseHead& response) { |
| + mojom::URLLoaderClientPtr fallback_client; |
| + mojom::URLLoaderRequest fallback_request; |
| + if (!CreateFallbackClientAndRequest(&fallback_client, &fallback_request)) |
| + return false; |
| + |
| + // We reset this flag as we expect a response from the fallback handler. |
| + default_loader_used_ = false; |
| + // Disconnect from the network loader to stop receiving further data |
| + // or notifications for the URL. |
| + url_loader_->DisconnectClient(); |
| + |
| + return std::move(fallback_handler_) |
| + .Run(response, std::move(fallback_client), std::move(fallback_request)); |
|
kinuko
2017/07/27 13:46:26
This fallback code works in a very specific way, w
ananta
2017/07/27 22:07:14
It seems like the method name you suggested in an
|
| + } |
| + |
| + // Creates an instance of the URLLoaderClient interface which can be bound |
| + // to a handler for receiving fallback responses. |
| + // Returns true on success. |
| + bool CreateFallbackClientAndRequest(mojom::URLLoaderClientPtr* client, |
| + mojom::URLLoaderRequest* request) { |
| + // Ignore if we don't have a fallback handler or if the request never went |
| + // to the network loader. |
| + if (!default_loader_used_ || !fallback_handler_) |
| + return false; |
| + fallback_response_binding_.Bind(mojo::MakeRequest(client)); |
| + *request = mojo::MakeRequest(&fallback_url_loader_); |
| + return true; |
| + } |
| + |
| std::vector<std::unique_ptr<URLLoaderRequestHandler>> handlers_; |
| size_t handler_index_ = 0; |
| @@ -305,6 +358,22 @@ class NavigationURLLoaderNetworkService::URLLoaderRequestController |
| // This is referenced only on the UI thread. |
| base::WeakPtr<NavigationURLLoaderNetworkService> owner_; |
| + // Set to true if the default URLLoader (network service) was used for the |
| + // current navigation. |
| + bool default_loader_used_ = false; |
| + |
| + // Contains a copy of the response. |
| + ResourceResponseHead response_; |
| + |
| + // URLLoaderClient binding for handling fallback responses. |
| + mojo::Binding<mojom::URLLoaderClient> fallback_response_binding_; |
| + |
| + // URLLoader instance for fallback responses. |
| + mojom::URLLoaderPtr fallback_url_loader_; |
| + |
| + // Fallback response handler. |
| + ResponseFallback fallback_handler_; |
| + |
| DISALLOW_COPY_AND_ASSIGN(URLLoaderRequestController); |
| }; |