| Index: content/browser/service_worker/service_worker_controllee_request_handler.cc
 | 
| diff --git a/content/browser/service_worker/service_worker_controllee_request_handler.cc b/content/browser/service_worker/service_worker_controllee_request_handler.cc
 | 
| index 76e9c2d3139b242ea1acf4b0bc601f4edd6c3a0c..05380d909c5092d62e93a3337f4c863226fff542 100644
 | 
| --- a/content/browser/service_worker/service_worker_controllee_request_handler.cc
 | 
| +++ b/content/browser/service_worker/service_worker_controllee_request_handler.cc
 | 
| @@ -25,6 +25,7 @@
 | 
|  #include "content/public/common/browser_side_navigation_policy.h"
 | 
|  #include "content/public/common/content_client.h"
 | 
|  #include "content/public/common/resource_response_info.h"
 | 
| +#include "mojo/public/cpp/bindings/strong_binding.h"
 | 
|  #include "net/base/load_flags.h"
 | 
|  #include "net/base/url_util.h"
 | 
|  #include "net/url_request/url_request.h"
 | 
| @@ -32,10 +33,98 @@
 | 
|  
 | 
|  namespace content {
 | 
|  
 | 
| +// Helper to support both a URLRequestJob and a URLLoaderFactory to support
 | 
| +// running with and without --enable-network-service.
 | 
| +class ServiceWorkerControlleeRequestHandler::JobWrapper {
 | 
| + public:
 | 
| +  explicit JobWrapper(base::WeakPtr<ServiceWorkerURLRequestJob> url_request_job)
 | 
| +      : url_request_job_(std::move(url_request_job)), factory_(nullptr) {}
 | 
| +
 | 
| +  // --enable-network-service.
 | 
| +  explicit JobWrapper(ServiceWorkerControlleeURLLoaderFactory* factory)
 | 
| +      : factory_(factory) {}
 | 
| +
 | 
| +  void FallbackToNetwork() {
 | 
| +    if (factory_) {
 | 
| +      factory_->FallbackToNetwork();
 | 
| +    } else {
 | 
| +      url_request_job_->FallbackToNetwork();
 | 
| +    }
 | 
| +  }
 | 
| +
 | 
| +  bool ShouldFallbackToNetwork() {
 | 
| +    if (factory_) {
 | 
| +      return factory_->ShouldFallbackToNetwork();
 | 
| +    } else {
 | 
| +      return url_request_job_->ShouldFallbackToNetwork();
 | 
| +    }
 | 
| +  }
 | 
| +
 | 
| +  ui::PageTransition GetPageTransition() {
 | 
| +    if (factory_) {
 | 
| +      return factory_->GetPageTransition();
 | 
| +    } else {
 | 
| +      const ResourceRequestInfo* info =
 | 
| +          ResourceRequestInfo::ForRequest(url_request_job_->request());
 | 
| +      // ResourceRequestInfo may not be set in some tests.
 | 
| +      if (!info)
 | 
| +        return ui::PAGE_TRANSITION_LINK;
 | 
| +      return info->GetPageTransition();
 | 
| +    }
 | 
| +  }
 | 
| +
 | 
| +  size_t GetURLChainSize() const {
 | 
| +    if (factory_) {
 | 
| +      return factory_->GetURLChainSize();
 | 
| +    } else {
 | 
| +      return url_request_job_->request()->url_chain().size();
 | 
| +    }
 | 
| +  }
 | 
| +
 | 
| +  void ForwardToServiceWorker() {
 | 
| +    if (factory_) {
 | 
| +      factory_->ForwardToServiceWorker();
 | 
| +    } else {
 | 
| +      url_request_job_->ForwardToServiceWorker();
 | 
| +    }
 | 
| +  }
 | 
| +
 | 
| +  void FallbackToNetworkOrRenderer() {
 | 
| +    if (factory_) {
 | 
| +      factory_->FallbackToNetworkOrRenderer();
 | 
| +    } else {
 | 
| +      url_request_job_->FallbackToNetworkOrRenderer();
 | 
| +    }
 | 
| +  }
 | 
| +
 | 
| +  void FailDueToLostController() {
 | 
| +    if (factory_) {
 | 
| +      factory_->FailDueToLostController();
 | 
| +    } else {
 | 
| +      url_request_job_->FailDueToLostController();
 | 
| +    }
 | 
| +  }
 | 
| +
 | 
| +  bool WasCanceled() const {
 | 
| +    if (factory_) {
 | 
| +      return factory_->WasCanceled();
 | 
| +    } else {
 | 
| +      return !url_request_job_;
 | 
| +    }
 | 
| +  }
 | 
| +
 | 
| + private:
 | 
| +  base::WeakPtr<ServiceWorkerURLRequestJob> url_request_job_;
 | 
| +  ServiceWorkerControlleeURLLoaderFactory* factory_;
 | 
| +
 | 
| +  DISALLOW_COPY_AND_ASSIGN(JobWrapper);
 | 
| +};
 | 
| +
 | 
|  namespace {
 | 
|  
 | 
| -bool MaybeForwardToServiceWorker(ServiceWorkerURLRequestJob* job,
 | 
| -                                 const ServiceWorkerVersion* version) {
 | 
| +bool MaybeForwardToServiceWorker(
 | 
| +    ServiceWorkerControlleeRequestHandler::JobWrapper* job,
 | 
| +    const ServiceWorkerVersion* version) {
 | 
|    DCHECK(job);
 | 
|    DCHECK(version);
 | 
|    DCHECK_NE(version->fetch_handler_existence(),
 | 
| @@ -50,14 +139,6 @@ bool MaybeForwardToServiceWorker(ServiceWorkerURLRequestJob* job,
 | 
|    return false;
 | 
|  }
 | 
|  
 | 
| -ui::PageTransition GetPageTransition(net::URLRequest* request) {
 | 
| -  const ResourceRequestInfo* info = ResourceRequestInfo::ForRequest(request);
 | 
| -  // ResourceRequestInfo may not be set in some tests.
 | 
| -  if (!info)
 | 
| -    return ui::PAGE_TRANSITION_LINK;
 | 
| -  return info->GetPageTransition();
 | 
| -}
 | 
| -
 | 
|  }  // namespace
 | 
|  
 | 
|  ServiceWorkerControlleeRequestHandler::ServiceWorkerControlleeRequestHandler(
 | 
| @@ -70,7 +151,8 @@ ServiceWorkerControlleeRequestHandler::ServiceWorkerControlleeRequestHandler(
 | 
|      ResourceType resource_type,
 | 
|      RequestContextType request_context_type,
 | 
|      RequestContextFrameType frame_type,
 | 
| -    scoped_refptr<ResourceRequestBodyImpl> body)
 | 
| +    scoped_refptr<ResourceRequestBodyImpl> body,
 | 
| +    NetworkFallbackCallback network_fallback_callback)
 | 
|      : ServiceWorkerRequestHandler(context,
 | 
|                                    provider_host,
 | 
|                                    blob_storage_context,
 | 
| @@ -86,6 +168,7 @@ ServiceWorkerControlleeRequestHandler::ServiceWorkerControlleeRequestHandler(
 | 
|        body_(body),
 | 
|        force_update_started_(false),
 | 
|        use_network_(false),
 | 
| +      network_fallback_callback_(network_fallback_callback),
 | 
|        weak_factory_(this) {}
 | 
|  
 | 
|  ServiceWorkerControlleeRequestHandler::
 | 
| @@ -140,12 +223,12 @@ net::URLRequestJob* ServiceWorkerControlleeRequestHandler::MaybeCreateJob(
 | 
|            credentials_mode_, redirect_mode_, resource_type_,
 | 
|            request_context_type_, frame_type_, body_,
 | 
|            ServiceWorkerFetchType::FETCH, base::nullopt, this));
 | 
| -  job_ = job->GetWeakPtr();
 | 
| +  job_ = base::MakeUnique<JobWrapper>(job->GetWeakPtr());
 | 
|  
 | 
|    resource_context_ = resource_context;
 | 
|  
 | 
|    if (is_main_resource_load_)
 | 
| -    PrepareForMainResource(request);
 | 
| +    PrepareForMainResource(request->url(), request->first_party_for_cookies());
 | 
|    else
 | 
|      PrepareForSubResource();
 | 
|  
 | 
| @@ -166,16 +249,85 @@ net::URLRequestJob* ServiceWorkerControlleeRequestHandler::MaybeCreateJob(
 | 
|    return job.release();
 | 
|  }
 | 
|  
 | 
| +mojom::URLLoaderFactoryPtrInfo
 | 
| +ServiceWorkerControlleeRequestHandler::MaybeGetURLLoaderFactory(
 | 
| +    const ResourceRequest& request,
 | 
| +    ResourceContext* resource_context,
 | 
| +    std::unique_ptr<ServiceWorkerRequestHandler> request_handler) {
 | 
| +  ClearJob();
 | 
| +  // TODO(scottmg):
 | 
| +  // ServiceWorkerResponseInfo::ResetDataForRequest(request);
 | 
| +
 | 
| +  if (!context_ || !provider_host_) {
 | 
| +    // We can't do anything other than to fall back to network.
 | 
| +    return mojom::URLLoaderFactoryPtrInfo();
 | 
| +  }
 | 
| +
 | 
| +  DCHECK(is_main_resource_load_);
 | 
| +
 | 
| +  // This may get called multiple times for original and redirect requests:
 | 
| +  // A. original request case: use_network_ is false, no previous location info.
 | 
| +  // B. redirect or restarted request case:
 | 
| +  //  a) use_network_ is false if the previous location was forwarded to SW.
 | 
| +  //  b) use_network_ is false if the previous location was fallback.
 | 
| +  //  c) use_network_ is true if additional restart was required to fall back.
 | 
| +
 | 
| +  // Fall back to network. (Case B-c)
 | 
| +  if (use_network_) {
 | 
| +    // Once a subresource request has fallen back to the network once, it will
 | 
| +    // never be handled by a service worker. This is not true of main frame
 | 
| +    // requests.
 | 
| +    if (is_main_resource_load_)
 | 
| +      use_network_ = false;
 | 
| +    return mojom::URLLoaderFactoryPtrInfo();
 | 
| +  }
 | 
| +
 | 
| +  mojom::URLLoaderFactoryPtr url_loader_factory;
 | 
| +  auto factory_impl = base::MakeUnique<ServiceWorkerControlleeURLLoaderFactory>(
 | 
| +      std::move(request_handler), provider_host_->client_uuid(),
 | 
| +      blob_storage_context_, resource_context, request_mode_, credentials_mode_,
 | 
| +      redirect_mode_, resource_type_, request_context_type_, frame_type_, body_,
 | 
| +      ServiceWorkerFetchType::FETCH, base::nullopt, this,
 | 
| +      network_fallback_callback_);
 | 
| +  auto* factory = factory_impl.get();
 | 
| +  mojo::MakeStrongBinding(std::move(factory_impl),
 | 
| +                          mojo::MakeRequest(&url_loader_factory));
 | 
| +
 | 
| +  // It's for original request (A) or redirect case (B-a or B-b).
 | 
| +  job_ = base::MakeUnique<JobWrapper>(factory);
 | 
| +
 | 
| +  resource_context_ = resource_context;
 | 
| +
 | 
| +  if (is_main_resource_load_)
 | 
| +    PrepareForMainResource(request.url, request.first_party_for_cookies);
 | 
| +
 | 
| +  if (job_->ShouldFallbackToNetwork()) {
 | 
| +    // If we know we can fallback to network at this point (in case
 | 
| +    // the storage lookup returned immediately), just destroy the job and return
 | 
| +    // NULL here to fallback to network.
 | 
| +
 | 
| +    // If this is a subresource request, all subsequent requests should also use
 | 
| +    // the network.
 | 
| +    if (!is_main_resource_load_)
 | 
| +      use_network_ = true;
 | 
| +
 | 
| +    ClearJob();
 | 
| +    return mojom::URLLoaderFactoryPtrInfo();
 | 
| +  }
 | 
| +
 | 
| +  return url_loader_factory.PassInterface();
 | 
| +}
 | 
| +
 | 
|  void ServiceWorkerControlleeRequestHandler::PrepareForMainResource(
 | 
| -    const net::URLRequest* request) {
 | 
| +    const GURL& url,
 | 
| +    const GURL& first_party_for_cookies) {
 | 
|    DCHECK(job_.get());
 | 
|    DCHECK(context_);
 | 
|    DCHECK(provider_host_);
 | 
|    TRACE_EVENT_ASYNC_BEGIN1(
 | 
|        "ServiceWorker",
 | 
|        "ServiceWorkerControlleeRequestHandler::PrepareForMainResource",
 | 
| -      job_.get(),
 | 
| -      "URL", request->url().spec());
 | 
| +      job_.get(), "URL", url.spec());
 | 
|    // The corresponding provider_host may already have associated a registration
 | 
|    // in redirect case, unassociate it now.
 | 
|    provider_host_->DisassociateRegistration();
 | 
| @@ -184,9 +336,9 @@ void ServiceWorkerControlleeRequestHandler::PrepareForMainResource(
 | 
|    // registration while we're finding an existing registration.
 | 
|    provider_host_->SetAllowAssociation(false);
 | 
|  
 | 
| -  stripped_url_ = net::SimplifyUrlForRequest(request->url());
 | 
| +  stripped_url_ = net::SimplifyUrlForRequest(url);
 | 
|    provider_host_->SetDocumentUrl(stripped_url_);
 | 
| -  provider_host_->SetTopmostFrameUrl(request->first_party_for_cookies());
 | 
| +  provider_host_->SetTopmostFrameUrl(first_party_for_cookies);
 | 
|    context_->storage()->FindRegistrationForDocument(
 | 
|        stripped_url_, base::Bind(&self::DidLookupRegistrationForMainResource,
 | 
|                                  weak_factory_.GetWeakPtr()));
 | 
| @@ -197,7 +349,7 @@ void ServiceWorkerControlleeRequestHandler::
 | 
|          ServiceWorkerStatusCode status,
 | 
|          scoped_refptr<ServiceWorkerRegistration> registration) {
 | 
|    // The job may have been canceled and then destroyed before this was invoked.
 | 
| -  if (!job_)
 | 
| +  if (job_->WasCanceled())
 | 
|      return;
 | 
|  
 | 
|    const bool need_to_update = !force_update_started_ && registration &&
 | 
| @@ -312,7 +464,7 @@ void ServiceWorkerControlleeRequestHandler::
 | 
|              ServiceWorkerVersion::FetchHandlerExistence::UNKNOWN);
 | 
|    ServiceWorkerMetrics::CountControlledPageLoad(
 | 
|        active_version->site_for_uma(), stripped_url_, is_main_frame_load_,
 | 
| -      GetPageTransition(job_->request()), job_->request()->url_chain().size());
 | 
| +      job_->GetPageTransition(), job_->GetURLChainSize());
 | 
|  
 | 
|    bool is_forwarded =
 | 
|        MaybeForwardToServiceWorker(job_.get(), active_version.get());
 | 
| @@ -329,7 +481,7 @@ void ServiceWorkerControlleeRequestHandler::OnVersionStatusChanged(
 | 
|      ServiceWorkerRegistration* registration,
 | 
|      ServiceWorkerVersion* version) {
 | 
|    // The job may have been canceled and then destroyed before this was invoked.
 | 
| -  if (!job_)
 | 
| +  if (job_->WasCanceled())
 | 
|      return;
 | 
|  
 | 
|    if (provider_host_)
 | 
| @@ -345,7 +497,7 @@ void ServiceWorkerControlleeRequestHandler::OnVersionStatusChanged(
 | 
|              ServiceWorkerVersion::FetchHandlerExistence::UNKNOWN);
 | 
|    ServiceWorkerMetrics::CountControlledPageLoad(
 | 
|        version->site_for_uma(), stripped_url_, is_main_frame_load_,
 | 
| -      GetPageTransition(job_->request()), job_->request()->url_chain().size());
 | 
| +      job_->GetPageTransition(), job_->GetURLChainSize());
 | 
|  
 | 
|    provider_host_->AssociateRegistration(registration,
 | 
|                                          false /* notify_controllerchange */);
 | 
| @@ -361,7 +513,7 @@ void ServiceWorkerControlleeRequestHandler::DidUpdateRegistration(
 | 
|    DCHECK(force_update_started_);
 | 
|  
 | 
|    // The job may have been canceled and then destroyed before this was invoked.
 | 
| -  if (!job_)
 | 
| +  if (job_->WasCanceled())
 | 
|      return;
 | 
|  
 | 
|    if (!context_) {
 | 
| @@ -391,7 +543,7 @@ void ServiceWorkerControlleeRequestHandler::OnUpdatedVersionStatusChanged(
 | 
|      const scoped_refptr<ServiceWorkerRegistration>& registration,
 | 
|      const scoped_refptr<ServiceWorkerVersion>& version) {
 | 
|    // The job may have been canceled and then destroyed before this was invoked.
 | 
| -  if (!job_)
 | 
| +  if (job_->WasCanceled())
 | 
|      return;
 | 
|  
 | 
|    if (!context_) {
 | 
| 
 |