shared worker: More fully support Chrome extensions with NetworkService.

This plumbs the factory bundle that understands chrome-extension:// to
more requisite places.

Bug: 839982
Cq-Include-Trybots: master.tryserver.chromium.linux:linux_mojo
Change-Id: I6cd8750ef0891910ab968fd4a91070d7ea5e2f2c
Reviewed-on: https://chromium-review.googlesource.com/1077875
Commit-Queue: Matt Falkenhagen <falken@chromium.org>
Reviewed-by: Kinuko Yasuda <kinuko@chromium.org>
Cr-Commit-Position: refs/heads/master@{#563283}
diff --git a/content/browser/shared_worker/shared_worker_host.cc b/content/browser/shared_worker/shared_worker_host.cc
index 17e8a32..4cba76c8 100644
--- a/content/browser/shared_worker/shared_worker_host.cc
+++ b/content/browser/shared_worker/shared_worker_host.cc
@@ -171,6 +171,10 @@
     // ResourceRequestorInfo. So, just send the bundle and count on the renderer
     // to clear the default factory upon arrival in that case.
     factory_bundle->default_factory_info() = std::move(network_factory_info);
+
+    // TODO(falken): We might need to set the default factory to AppCache
+    // instead, as we do for frames, if requests from this shared worker are
+    // supposed to go through AppCache.
   }
 
   // Send the CreateSharedWorker message.
@@ -200,8 +204,8 @@
   service_->storage_partition()->GetNetworkContext()->CreateURLLoaderFactory(
       std::move(request), std::move(params));
 
-  // TODO(falken): Detect connection error and send a IPC with a new network
-  // factory like UpdateSubresourceLoaderFactories does for frames.
+  // TODO(crbug.com/848256): Detect connection error and send a IPC with a new
+  // network factory like UpdateSubresourceLoaderFactories does for frames.
 }
 
 void SharedWorkerHost::AllowFileSystem(
diff --git a/content/renderer/service_worker/worker_fetch_context_impl.cc b/content/renderer/service_worker/worker_fetch_context_impl.cc
index bc16217..82347dd 100644
--- a/content/renderer/service_worker/worker_fetch_context_impl.cc
+++ b/content/renderer/service_worker/worker_fetch_context_impl.cc
@@ -12,6 +12,7 @@
 #include "content/common/service_worker/service_worker_provider.mojom.h"
 #include "content/common/service_worker/service_worker_utils.h"
 #include "content/public/common/content_features.h"
+#include "content/public/common/origin_util.h"
 #include "content/public/common/service_names.mojom.h"
 #include "content/public/renderer/url_loader_throttle_provider.h"
 #include "content/public/renderer/websocket_handshake_throttle_provider.h"
@@ -102,9 +103,16 @@
     if (!service_worker_loader_factory_)
       return nullptr;
 
-    // If it's not for HTTP or HTTPS no need to intercept the request.
-    if (!GURL(request.Url()).SchemeIsHTTPOrHTTPS())
+    // If the URL is not http(s) or otherwise whitelisted, do not intercept the
+    // request. Schemes like 'blob' and 'file' are not eligible to be
+    // intercepted by service workers.
+    // TODO(falken): Let ServiceWorkerSubresourceLoaderFactory handle the
+    // request and move this check there (i.e., for such URLs, it should use
+    // its fallback factory).
+    if (!GURL(request.Url()).SchemeIsHTTPOrHTTPS() &&
+        !OriginCanAccessServiceWorkers(request.Url())) {
       return nullptr;
+    }
 
     // If GetSkipServiceWorker() returns true, no need to intercept the request.
     if (request.GetSkipServiceWorker())
diff --git a/content/renderer/shared_worker/embedded_shared_worker_stub.cc b/content/renderer/shared_worker/embedded_shared_worker_stub.cc
index 75b304d..5221e1c 100644
--- a/content/renderer/shared_worker/embedded_shared_worker_stub.cc
+++ b/content/renderer/shared_worker/embedded_shared_worker_stub.cc
@@ -31,6 +31,7 @@
 #include "content/renderer/service_worker/worker_fetch_context_impl.h"
 #include "ipc/ipc_message_macros.h"
 #include "services/network/public/cpp/features.h"
+#include "services/network/public/cpp/shared_url_loader_factory.h"
 #include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h"
 #include "third_party/blink/public/common/message_port/message_port_channel.h"
 #include "third_party/blink/public/mojom/service_worker/service_worker_object.mojom.h"
@@ -153,10 +154,14 @@
       return nullptr;
     }
 
-    // If it's not for HTTP or HTTPS, no need to intercept the request.
-    // TODO(falken): Allow SubresourceLoaderFactory to handle it in order
-    // to support chrome-extension://.
-    if (!GURL(request.Url()).SchemeIsHTTPOrHTTPS()) {
+    // If the URL is not http(s) or otherwise whitelisted, do not intercept the
+    // request. Schemes like 'blob' and 'file' are not eligible to be
+    // intercepted by service workers.
+    // TODO(falken): Let ServiceWorkerSubresourceLoaderFactory handle the
+    // request and move this check there (i.e., for such URLs, it should use
+    // its fallback factory).
+    if (!GURL(request.Url()).SchemeIsHTTPOrHTTPS() &&
+        !OriginCanAccessServiceWorkers(request.Url())) {
       return nullptr;
     }
 
@@ -209,35 +214,45 @@
   service_worker_provider_info_ = std::move(service_worker_provider_info);
   script_loader_factory_info_ = std::move(script_loader_factory_info);
 
-  // Make the factory bundle for the shadow page to use for importScripts().
-  auto loader_factories = base::MakeRefCounted<HostChildURLLoaderFactoryBundle>(
+  // Make the factory bundle.
+  loader_factories_ = base::MakeRefCounted<HostChildURLLoaderFactoryBundle>(
       impl_->GetTaskRunner(blink::TaskType::kInternalLoading));
   // In some tests |render_thread| could be null.
-  RenderThreadImpl* render_thread = RenderThreadImpl::current();
-  if (render_thread) {
-    loader_factories->Update(render_thread->blink_platform_impl()
-                                 ->CreateDefaultURLLoaderFactoryBundle()
-                                 ->PassInterface(),
-                             base::nullopt /* subresource_overrides */);
+  if (RenderThreadImpl* render_thread = RenderThreadImpl::current()) {
+    loader_factories_->Update(render_thread->blink_platform_impl()
+                                  ->CreateDefaultURLLoaderFactoryBundle()
+                                  ->PassInterface(),
+                              base::nullopt /* subresource_overrides */);
   }
-  if (subresource_loaders) {
-    // S13nServiceWorker enabled, NetworkService disabled:Clear the default
-    // factory from |subresource_loaders|, as it's the NetworkService factory.
-    // We'll continue using the default from CreateDefaultURLLoaderFactoryBundle
-    // instead.
-    if (!base::FeatureList::IsEnabled(network::features::kNetworkService))
-      subresource_loaders->default_factory_info() = nullptr;
 
-    loader_factories->Update(std::make_unique<ChildURLLoaderFactoryBundleInfo>(
-                                 std::move(subresource_loaders)),
-                             base::nullopt /* subresource_overrides */);
+  if (subresource_loaders) {
+    if (!base::FeatureList::IsEnabled(network::features::kNetworkService)) {
+      // S13nServiceWorker enabled, NetworkService disabled:
+      // Clear the default factory from |subresource_loaders|, as it's the
+      // NetworkService factory.
+      subresource_loaders->default_factory_info() = nullptr;
+    }
+
+    loader_factories_->Update(std::make_unique<ChildURLLoaderFactoryBundleInfo>(
+                                  std::move(subresource_loaders)),
+                              base::nullopt /* subresource_overrides */);
   }
 
+  // It is important to understand the default factory of |loader_factories_|.
+  // Since |loader_factories_| was made from
+  // CreateDefaultURLLoaderFactoryBundle, which does not set a default factory,
+  // and |subresource_loaders|, whose default factory is the restartable
+  // NetworkService (as SharedWorkerHost sets it that way), the default factory
+  // either does not exist (when NetworkService is disabled) or is a
+  // NetworkService-backed factory with auto-reconnect. Therefore, we don't need
+  // to call CloneWithoutDefault() to bypass features like AppCache, unlike the
+  // bundle created for a frame.
+
   impl_->StartWorkerContext(
       url_, blink::WebString::FromUTF8(name_),
       blink::WebString::FromUTF8(info->content_security_policy),
       info->content_security_policy_type, info->creation_address_space,
-      devtools_worker_token, std::move(loader_factories),
+      devtools_worker_token, loader_factories_,
       content_settings.PassInterface().PassHandle(),
       interface_provider.PassInterface().PassHandle());
 
@@ -309,23 +324,11 @@
 
 std::unique_ptr<blink::WebServiceWorkerNetworkProvider>
 EmbeddedSharedWorkerStub::CreateServiceWorkerNetworkProvider() {
-  scoped_refptr<network::SharedURLLoaderFactory> fallback_factory;
-  // current() may be null in tests.
-  if (RenderThreadImpl* render_thread = RenderThreadImpl::current()) {
-    // TODO(crbug.com/839982): Make a bundle using the |factory_bundle| passed
-    // to the ctor instead, otherwise chrome-extension:// won't work for network
-    // fallback.
-    scoped_refptr<ChildURLLoaderFactoryBundle> bundle =
-        render_thread->blink_platform_impl()
-            ->CreateDefaultURLLoaderFactoryBundle();
-    fallback_factory = network::SharedURLLoaderFactory::Create(
-        bundle->CloneWithoutDefaultFactory());
-  }
-
   std::unique_ptr<ServiceWorkerNetworkProvider> provider =
       ServiceWorkerNetworkProvider::CreateForSharedWorker(
           std::move(service_worker_provider_info_),
-          std::move(script_loader_factory_info_), std::move(fallback_factory));
+          std::move(script_loader_factory_info_), loader_factories_);
+
   return std::make_unique<WebServiceWorkerNetworkProviderForSharedWorker>(
       std::move(provider), IsOriginSecure(url_));
 }
@@ -354,22 +357,24 @@
       context->CreateWorkerClientRequest();
 
   mojom::ServiceWorkerContainerHostPtrInfo container_host_ptr_info;
-  // TODO(horo): Use this host pointer also when S13nServiceWorker is not
-  // enabled once we support navigator.serviceWorker on shared workers:
-  // crbug.com/371690. Currently we use this only to call
-  // GetControllerServiceWorker() from the worker thread if S13nServiceWorker
-  // is enabled.
   if (ServiceWorkerUtils::IsServicificationEnabled())
     container_host_ptr_info = context->CloneContainerHostPtrInfo();
 
-  scoped_refptr<ChildURLLoaderFactoryBundle> url_loader_factory_bundle =
-      RenderThreadImpl::current()
-          ->blink_platform_impl()
-          ->CreateDefaultURLLoaderFactoryBundle();
+  // We know |loader_factories_|'s default factory is not a feature like
+  // AppCache, so it's OK to call Clone() and not CloneWithoutDefault() to get
+  // the fallback factory. We don't want to call CloneWithoutDefault() because
+  // the default is a NetworkService-backed factory with auto-reconnect
+  // when NetworkService is enabled (it will support auto-reconnect once
+  // https://crbug.com/848256 is addressed). See comments in the constructor.
+  //
+  // TODO(falken): We might need to set the default factory of
+  // |loader_factories_| to AppCache if requests from this shared worker are
+  // supposed to go through AppCache.
+  std::unique_ptr<network::SharedURLLoaderFactoryInfo> fallback_factory =
+      loader_factories_->Clone();
   auto worker_fetch_context = std::make_unique<WorkerFetchContextImpl>(
       std::move(request), std::move(container_host_ptr_info),
-      url_loader_factory_bundle->Clone(),
-      url_loader_factory_bundle->CloneWithoutDefaultFactory(),
+      loader_factories_->Clone(), std::move(fallback_factory),
       GetContentClient()->renderer()->CreateURLLoaderThrottleProvider(
           URLLoaderThrottleProviderType::kWorker),
       GetContentClient()
diff --git a/content/renderer/shared_worker/embedded_shared_worker_stub.h b/content/renderer/shared_worker/embedded_shared_worker_stub.h
index 9cb81ccd..115aea9 100644
--- a/content/renderer/shared_worker/embedded_shared_worker_stub.h
+++ b/content/renderer/shared_worker/embedded_shared_worker_stub.h
@@ -39,6 +39,7 @@
 }
 
 namespace content {
+class HostChildURLLoaderFactoryBundle;
 class URLLoaderFactoryBundleInfo;
 class WebApplicationCacheHostImpl;
 
@@ -122,6 +123,10 @@
   // script.
   network::mojom::URLLoaderFactoryAssociatedPtrInfo script_loader_factory_info_;
 
+  // S13nServiceWorker: The factory bundle used for loads from this shared
+  // worker.
+  scoped_refptr<HostChildURLLoaderFactoryBundle> loader_factories_;
+
   DISALLOW_COPY_AND_ASSIGN(EmbeddedSharedWorkerStub);
 };
 
diff --git a/testing/buildbot/filters/mojo.fyi.network_browser_tests.filter b/testing/buildbot/filters/mojo.fyi.network_browser_tests.filter
index 3c411bd..496d73c 100644
--- a/testing/buildbot/filters/mojo.fyi.network_browser_tests.filter
+++ b/testing/buildbot/filters/mojo.fyi.network_browser_tests.filter
@@ -230,9 +230,6 @@
 # to work with network service.
 -ConditionalCacheCountingHelperBrowserTest.Count
 
-# https://crbug.com/839982
--ExtensionApiTest.SharedWorker_ControlledByServiceWorker
-
 # NOTE: if adding an exclusion for an existing failure (e.g. additional test for
 # feature X that is already not working), please add it beside the existing
 # failures. Otherwise please reach out to network-service-dev@.