1 // Copyright 2019 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "content/browser/service_worker/service_worker_loader_helpers.h"
6 
7 #include "base/command_line.h"
8 #include "base/strings/stringprintf.h"
9 #include "base/time/time.h"
10 #include "components/network_session_configurator/common/network_switches.h"
11 #include "content/browser/service_worker/service_worker_consts.h"
12 #include "third_party/blink/public/common/features.h"
13 #include "third_party/blink/public/common/mime_util/mime_util.h"
14 #include "third_party/blink/public/mojom/service_worker/service_worker_registration.mojom.h"
15 
16 namespace content {
17 
18 namespace service_worker_loader_helpers {
19 
CheckResponseHead(const network::mojom::URLResponseHead & response_head,blink::ServiceWorkerStatusCode * out_service_worker_status,network::URLLoaderCompletionStatus * out_completion_status,std::string * out_error_message)20 bool CheckResponseHead(
21     const network::mojom::URLResponseHead& response_head,
22     blink::ServiceWorkerStatusCode* out_service_worker_status,
23     network::URLLoaderCompletionStatus* out_completion_status,
24     std::string* out_error_message) {
25   if (response_head.headers->response_code() / 100 != 2) {
26     // Non-2XX HTTP status code is handled as an error.
27     *out_completion_status =
28         network::URLLoaderCompletionStatus(net::ERR_INVALID_RESPONSE);
29     *out_error_message = base::StringPrintf(
30         ServiceWorkerConsts::kServiceWorkerBadHTTPResponseError,
31         response_head.headers->response_code());
32     *out_service_worker_status = blink::ServiceWorkerStatusCode::kErrorNetwork;
33     return false;
34   }
35 
36   if (net::IsCertStatusError(response_head.cert_status) &&
37       !base::CommandLine::ForCurrentProcess()->HasSwitch(
38           switches::kIgnoreCertificateErrors)) {
39     *out_completion_status = network::URLLoaderCompletionStatus(
40         net::MapCertStatusToNetError(response_head.cert_status));
41     *out_error_message = ServiceWorkerConsts::kServiceWorkerSSLError;
42     *out_service_worker_status = blink::ServiceWorkerStatusCode::kErrorNetwork;
43     return false;
44   }
45 
46   // Remain consistent with logic in
47   // blink::InstalledServiceWorkerModuleScriptFetcher::Fetch()
48   if (!blink::IsSupportedJavascriptMimeType(response_head.mime_type) &&
49       !(base::FeatureList::IsEnabled(blink::features::kJSONModules) &&
50         blink::IsJSONMimeType(response_head.mime_type))) {
51     *out_completion_status =
52         network::URLLoaderCompletionStatus(net::ERR_INSECURE_RESPONSE);
53     *out_error_message =
54         response_head.mime_type.empty()
55             ? ServiceWorkerConsts::kServiceWorkerNoMIMEError
56             : base::StringPrintf(
57                   ServiceWorkerConsts::kServiceWorkerBadMIMEError,
58                   response_head.mime_type.c_str());
59     *out_service_worker_status = blink::ServiceWorkerStatusCode::kErrorSecurity;
60     return false;
61   }
62 
63   return true;
64 }
65 
ShouldBypassCacheDueToUpdateViaCache(bool is_main_script,blink::mojom::ServiceWorkerUpdateViaCache cache_mode)66 bool ShouldBypassCacheDueToUpdateViaCache(
67     bool is_main_script,
68     blink::mojom::ServiceWorkerUpdateViaCache cache_mode) {
69   switch (cache_mode) {
70     case blink::mojom::ServiceWorkerUpdateViaCache::kImports:
71       return is_main_script;
72     case blink::mojom::ServiceWorkerUpdateViaCache::kNone:
73       return true;
74     case blink::mojom::ServiceWorkerUpdateViaCache::kAll:
75       return false;
76   }
77   NOTREACHED() << static_cast<int>(cache_mode);
78   return false;
79 }
80 
ShouldValidateBrowserCacheForScript(bool is_main_script,bool force_bypass_cache,blink::mojom::ServiceWorkerUpdateViaCache cache_mode,base::TimeDelta time_since_last_check)81 bool ShouldValidateBrowserCacheForScript(
82     bool is_main_script,
83     bool force_bypass_cache,
84     blink::mojom::ServiceWorkerUpdateViaCache cache_mode,
85     base::TimeDelta time_since_last_check) {
86   return (ShouldBypassCacheDueToUpdateViaCache(is_main_script, cache_mode) ||
87           time_since_last_check >
88               ServiceWorkerConsts::kServiceWorkerScriptMaxCacheAge ||
89           force_bypass_cache);
90 }
91 
92 #if DCHECK_IS_ON()
CheckVersionStatusBeforeWorkerScriptLoad(ServiceWorkerVersion::Status status,network::mojom::RequestDestination resource_destination)93 void CheckVersionStatusBeforeWorkerScriptLoad(
94     ServiceWorkerVersion::Status status,
95     network::mojom::RequestDestination resource_destination) {
96   switch (resource_destination) {
97     // The service worker main script should be fetched during worker startup.
98     case network::mojom::RequestDestination::kServiceWorker:
99       DCHECK_EQ(status, ServiceWorkerVersion::NEW);
100       break;
101     // importScripts() should be called until completion of the install event.
102     case network::mojom::RequestDestination::kScript:
103       DCHECK(status == ServiceWorkerVersion::NEW ||
104              status == ServiceWorkerVersion::INSTALLING);
105       break;
106     default:
107       NOTREACHED() << resource_destination;
108       break;
109   }
110 }
111 #endif  // DCHECK_IS_ON()
112 
113 }  // namespace service_worker_loader_helpers
114 
115 }  // namespace content
116