1 // Copyright 2017 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_new_script_loader.h"
6 
7 #include <map>
8 #include <memory>
9 #include <string>
10 #include <utility>
11 #include "base/bind_helpers.h"
12 #include "base/run_loop.h"
13 #include "base/strings/string_util.h"
14 #include "base/test/metrics/histogram_tester.h"
15 #include "base/test/scoped_feature_list.h"
16 #include "content/browser/service_worker/embedded_worker_test_helper.h"
17 #include "content/browser/service_worker/service_worker_consts.h"
18 #include "content/browser/service_worker/service_worker_context_core.h"
19 #include "content/browser/service_worker/service_worker_disk_cache.h"
20 #include "content/browser/service_worker/service_worker_test_utils.h"
21 #include "content/browser/url_loader_factory_getter.h"
22 #include "content/public/test/browser_task_environment.h"
23 #include "content/public/test/url_loader_interceptor.h"
24 #include "mojo/public/cpp/system/data_pipe_utils.h"
25 #include "net/base/features.h"
26 #include "net/base/load_flags.h"
27 #include "net/base/test_completion_callback.h"
28 #include "net/http/http_util.h"
29 #include "net/traffic_annotation/network_traffic_annotation.h"
30 #include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
31 #include "net/url_request/redirect_info.h"
32 #include "services/network/public/cpp/url_loader_completion_status.h"
33 #include "services/network/public/mojom/url_loader_factory.mojom.h"
34 #include "services/network/test/test_url_loader_client.h"
35 #include "third_party/blink/public/common/features.h"
36 #include "third_party/blink/public/mojom/service_worker/service_worker_registration.mojom.h"
37 
38 namespace content {
39 namespace service_worker_new_script_loader_unittest {
40 
41 const char kNormalScriptURL[] = "https://example.com/normal.js";
42 const char kNormalImportedScriptURL[] =
43     "https://my-awesome-cdn.com/import_script.js";
44 const char kHistogramWriteResponseResult[] =
45     "ServiceWorker.DiskCache.WriteResponseResult";
46 
47 // MockHTTPServer is a utility to provide mocked responses for
48 // ServiceWorkerNewScriptLoader.
49 class MockHTTPServer {
50  public:
51   struct Response {
Responsecontent::service_worker_new_script_loader_unittest::MockHTTPServer::Response52     Response(const std::string& headers, const std::string& body)
53         : headers(headers), body(body) {}
54 
55     const std::string headers;
56     const std::string body;
57     bool has_certificate_error = false;
58     net::CertStatus cert_status = 0;
59   };
60 
Set(const GURL & url,const Response & response)61   void Set(const GURL& url, const Response& response) {
62     responses_.erase(url);
63     responses_.emplace(url, response);
64   }
65 
Get(const GURL & url)66   const Response& Get(const GURL& url) {
67     auto found = responses_.find(url);
68     EXPECT_TRUE(found != responses_.end());
69     return found->second;
70   }
71 
72  private:
73   std::map<GURL, Response> responses_;
74 };
75 
76 // Mocks network activity. Used by URLLoaderInterceptor.
77 class MockNetwork {
78  public:
MockNetwork(MockHTTPServer * mock_server)79   explicit MockNetwork(MockHTTPServer* mock_server)
80       : mock_server_(mock_server) {}
81 
82   MockNetwork(const MockNetwork&) = delete;
83   MockNetwork& operator=(const MockNetwork&) = delete;
84 
set_to_access_network(bool access_network)85   void set_to_access_network(bool access_network) {
86     access_network_ = access_network;
87   }
88 
last_request() const89   network::ResourceRequest last_request() const { return last_request_; }
90 
InterceptNetworkRequest(URLLoaderInterceptor::RequestParams * params)91   bool InterceptNetworkRequest(URLLoaderInterceptor::RequestParams* params) {
92     const network::ResourceRequest& url_request = params->url_request;
93     last_request_ = url_request;
94     const MockHTTPServer::Response& response =
95         mock_server_->Get(url_request.url);
96 
97     // Pass the response header to the client.
98     net::HttpResponseInfo info;
99     info.headers = base::MakeRefCounted<net::HttpResponseHeaders>(
100         net::HttpUtil::AssembleRawHeaders(response.headers));
101     auto response_head = network::mojom::URLResponseHead::New();
102     response_head->headers = info.headers;
103     response_head->headers->GetMimeType(&response_head->mime_type);
104     response_head->network_accessed = access_network_;
105     if (response.has_certificate_error) {
106       response_head->cert_status = response.cert_status;
107     }
108 
109     mojo::Remote<network::mojom::URLLoaderClient>& client = params->client;
110     if (response_head->headers->response_code() == 307) {
111       client->OnReceiveRedirect(net::RedirectInfo(), std::move(response_head));
112       return true;
113     }
114     client->OnReceiveResponse(std::move(response_head));
115 
116     uint32_t bytes_written = response.body.size();
117     mojo::ScopedDataPipeConsumerHandle consumer;
118     mojo::ScopedDataPipeProducerHandle producer;
119     CHECK_EQ(MOJO_RESULT_OK,
120              mojo::CreateDataPipe(nullptr, &producer, &consumer));
121     MojoResult result = producer->WriteData(
122         response.body.data(), &bytes_written, MOJO_WRITE_DATA_FLAG_ALL_OR_NONE);
123     CHECK_EQ(MOJO_RESULT_OK, result);
124     client->OnStartLoadingResponseBody(std::move(consumer));
125 
126     network::URLLoaderCompletionStatus status;
127     status.error_code = net::OK;
128     client->OnComplete(status);
129     return true;
130   }
131 
132  private:
133   // |mock_server_| is owned by ServiceWorkerNewScriptLoaderTest.
134   MockHTTPServer* const mock_server_;
135 
136   // The most recent request received.
137   network::ResourceRequest last_request_;
138 
139   // Controls whether a load simulates accessing network or cache.
140   bool access_network_ = false;
141 };
142 
143 // ServiceWorkerNewScriptLoaderTest is for testing the handling of requests for
144 // installing service worker scripts via ServiceWorkerNewScriptLoader.
145 class ServiceWorkerNewScriptLoaderTest : public testing::Test {
146  public:
ServiceWorkerNewScriptLoaderTest()147   ServiceWorkerNewScriptLoaderTest()
148       : task_environment_(BrowserTaskEnvironment::IO_MAINLOOP),
149         mock_network_(&mock_server_),
150         interceptor_(base::BindRepeating(&MockNetwork::InterceptNetworkRequest,
151                                          base::Unretained(&mock_network_))) {}
152   ~ServiceWorkerNewScriptLoaderTest() override = default;
153 
context()154   ServiceWorkerContextCore* context() { return helper_->context(); }
155 
SetUp()156   void SetUp() override {
157     helper_ = std::make_unique<EmbeddedWorkerTestHelper>(base::FilePath());
158 
159     context()->storage()->LazyInitializeForTest();
160 
161     mock_server_.Set(GURL(kNormalScriptURL),
162                      MockHTTPServer::Response(
163                          std::string("HTTP/1.1 200 OK\n"
164                                      "Content-Type: text/javascript\n\n"),
165                          std::string("this body came from the network")));
166     mock_server_.Set(
167         GURL(kNormalImportedScriptURL),
168         MockHTTPServer::Response(
169             std::string("HTTP/1.1 200 OK\n"
170                         "Content-Type: text/javascript\n\n"),
171             std::string(
172                 "this is an import script response body from the network")));
173   }
174 
175   // Sets up ServiceWorkerRegistration and ServiceWorkerVersion. This should be
176   // called before DoRequest().
SetUpRegistration(const GURL & script_url)177   void SetUpRegistration(const GURL& script_url) {
178     blink::mojom::ServiceWorkerRegistrationOptions options;
179     options.scope = script_url.GetWithoutFilename();
180     SetUpRegistrationWithOptions(script_url, options);
181   }
SetUpRegistrationWithOptions(const GURL & script_url,blink::mojom::ServiceWorkerRegistrationOptions options)182   void SetUpRegistrationWithOptions(
183       const GURL& script_url,
184       blink::mojom::ServiceWorkerRegistrationOptions options) {
185     registration_ =
186         CreateNewServiceWorkerRegistration(context()->registry(), options);
187     SetUpVersion(script_url);
188   }
189 
190   // Promotes |version_| to |registration_|'s active version, and then resets
191   // |version_| to null (as subsequent DoRequest() calls should not attempt to
192   // install or update |version_|).
ActivateVersion()193   void ActivateVersion() {
194     version_->set_fetch_handler_existence(
195         ServiceWorkerVersion::FetchHandlerExistence::DOES_NOT_EXIST);
196     version_->SetStatus(ServiceWorkerVersion::ACTIVATED);
197     registration_->SetActiveVersion(version_);
198     version_ = nullptr;
199   }
200 
201   // After this is called, |version_| will be a new, uninstalled version. The
202   // next time DoRequest() is called, |version_| will attempt to install,
203   // possibly updating if registration has an installed worker.
SetUpVersion(const GURL & script_url)204   void SetUpVersion(const GURL& script_url) {
205     version_ = CreateNewServiceWorkerVersion(
206         context()->registry(), registration_.get(), script_url,
207         blink::mojom::ScriptType::kClassic);
208     version_->SetStatus(ServiceWorkerVersion::NEW);
209   }
210 
DoRequest(const GURL & url,std::unique_ptr<network::TestURLLoaderClient> * out_client,std::unique_ptr<ServiceWorkerNewScriptLoader> * out_loader)211   void DoRequest(const GURL& url,
212                  std::unique_ptr<network::TestURLLoaderClient>* out_client,
213                  std::unique_ptr<ServiceWorkerNewScriptLoader>* out_loader) {
214     DCHECK(registration_);
215     DCHECK(version_);
216 
217     // Dummy values.
218     int routing_id = 0;
219     int request_id = 10;
220     uint32_t options = 0;
221     int64_t resource_id = GetNewResourceIdSync(context()->storage());
222 
223     network::ResourceRequest request;
224     request.url = url;
225     request.method = "GET";
226     request.resource_type =
227         static_cast<int>((url == version_->script_url())
228                              ? blink::mojom::ResourceType::kServiceWorker
229                              : blink::mojom::ResourceType::kScript);
230 
231     *out_client = std::make_unique<network::TestURLLoaderClient>();
232     *out_loader = ServiceWorkerNewScriptLoader::CreateAndStart(
233         routing_id, request_id, options, request, (*out_client)->CreateRemote(),
234         version_, helper_->url_loader_factory_getter()->GetNetworkFactory(),
235         net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS),
236         resource_id);
237   }
238 
239   // Returns false if the entry for |url| doesn't exist in the storage.
VerifyStoredResponse(const GURL & url)240   bool VerifyStoredResponse(const GURL& url) {
241     return ServiceWorkerUpdateCheckTestUtils::VerifyStoredResponse(
242         LookupResourceId(url), context()->storage(),
243         mock_server_.Get(url).body);
244   }
245 
LookupResourceId(const GURL & url)246   int64_t LookupResourceId(const GURL& url) {
247     return version_->script_cache_map()->LookupResourceId(url);
248   }
249 
250  protected:
251   BrowserTaskEnvironment task_environment_;
252 
253   MockHTTPServer mock_server_;
254   MockNetwork mock_network_;
255   URLLoaderInterceptor interceptor_;
256 
257   std::unique_ptr<EmbeddedWorkerTestHelper> helper_;
258 
259   scoped_refptr<ServiceWorkerRegistration> registration_;
260   scoped_refptr<ServiceWorkerVersion> version_;
261 };
262 
TEST_F(ServiceWorkerNewScriptLoaderTest,Success)263 TEST_F(ServiceWorkerNewScriptLoaderTest, Success) {
264   base::HistogramTester histogram_tester;
265 
266   const GURL kScriptURL(kNormalScriptURL);
267   std::unique_ptr<network::TestURLLoaderClient> client;
268   std::unique_ptr<ServiceWorkerNewScriptLoader> loader;
269 
270   SetUpRegistration(kScriptURL);
271   DoRequest(kScriptURL, &client, &loader);
272   client->RunUntilComplete();
273   EXPECT_EQ(net::OK, client->completion_status().error_code);
274 
275   // The client should have received the response.
276   EXPECT_TRUE(client->has_received_response());
277   EXPECT_TRUE(client->response_body().is_valid());
278   std::string response;
279   EXPECT_TRUE(
280       mojo::BlockingCopyToString(client->response_body_release(), &response));
281   EXPECT_EQ(mock_server_.Get(kScriptURL).body, response);
282 
283   // WRITE_OK should be recorded once plus one as we record a single write
284   // success and the end of the body.
285   EXPECT_TRUE(VerifyStoredResponse(kScriptURL));
286   histogram_tester.ExpectUniqueSample(kHistogramWriteResponseResult,
287                                       ServiceWorkerMetrics::WRITE_OK, 2);
288 }
289 
TEST_F(ServiceWorkerNewScriptLoaderTest,Success_EmptyBody)290 TEST_F(ServiceWorkerNewScriptLoaderTest, Success_EmptyBody) {
291   base::HistogramTester histogram_tester;
292 
293   const GURL kScriptURL("https://example.com/empty.js");
294   std::unique_ptr<network::TestURLLoaderClient> client;
295   std::unique_ptr<ServiceWorkerNewScriptLoader> loader;
296   mock_server_.Set(
297       kScriptURL,
298       MockHTTPServer::Response(std::string("HTTP/1.1 200 OK\n"
299                                            "Content-Type: text/javascript\n\n"),
300                                std::string()));
301   SetUpRegistration(kScriptURL);
302   DoRequest(kScriptURL, &client, &loader);
303   client->RunUntilComplete();
304   EXPECT_EQ(net::OK, client->completion_status().error_code);
305 
306   // The client should have received the response.
307   EXPECT_TRUE(client->has_received_response());
308   EXPECT_TRUE(client->response_body().is_valid());
309 
310   // The response should also be stored in the storage.
311   EXPECT_TRUE(VerifyStoredResponse(kScriptURL));
312   // WRITE_OK should be recorded once as we record the end of the body.
313   histogram_tester.ExpectUniqueSample(kHistogramWriteResponseResult,
314                                       ServiceWorkerMetrics::WRITE_OK, 1);
315 }
316 
TEST_F(ServiceWorkerNewScriptLoaderTest,Success_LargeBody)317 TEST_F(ServiceWorkerNewScriptLoaderTest, Success_LargeBody) {
318   base::HistogramTester histogram_tester;
319 
320   std::unique_ptr<network::TestURLLoaderClient> client;
321   std::unique_ptr<ServiceWorkerNewScriptLoader> loader;
322 
323   // Create a response that has a larger body than the script loader's buffer
324   // to test chunked data write. We chose this multiplier to avoid hitting the
325   // limit of mojo's data pipe buffer (it's about kReadBufferSize * 2 as of
326   // now).
327   const uint32_t kBodySize =
328       ServiceWorkerNewScriptLoader::kReadBufferSize * 1.6;
329   const GURL kScriptURL("https://example.com/large-body.js");
330   mock_server_.Set(
331       kScriptURL,
332       MockHTTPServer::Response(std::string("HTTP/1.1 200 OK\n"
333                                            "Content-Type: text/javascript\n\n"),
334                                std::string(kBodySize, 'a')));
335   SetUpRegistration(kScriptURL);
336   DoRequest(kScriptURL, &client, &loader);
337   client->RunUntilComplete();
338   EXPECT_EQ(net::OK, client->completion_status().error_code);
339 
340   // The client should have received the response.
341   EXPECT_TRUE(client->has_received_response());
342   EXPECT_TRUE(client->response_body().is_valid());
343   std::string response;
344   EXPECT_TRUE(
345       mojo::BlockingCopyToString(client->response_body_release(), &response));
346   EXPECT_EQ(mock_server_.Get(kScriptURL).body, response);
347 
348   // The response should also be stored in the storage.
349   EXPECT_TRUE(VerifyStoredResponse(kScriptURL));
350   // WRITE_OK should be recorded twice plus one as we record every single write
351   // success and the end of the body.
352   histogram_tester.ExpectUniqueSample(kHistogramWriteResponseResult,
353                                       ServiceWorkerMetrics::WRITE_OK, 3);
354 }
355 
TEST_F(ServiceWorkerNewScriptLoaderTest,Error_404)356 TEST_F(ServiceWorkerNewScriptLoaderTest, Error_404) {
357   base::HistogramTester histogram_tester;
358 
359   std::unique_ptr<network::TestURLLoaderClient> client;
360   std::unique_ptr<ServiceWorkerNewScriptLoader> loader;
361 
362   const GURL kScriptURL("https://example.com/nonexistent.js");
363   mock_server_.Set(kScriptURL, MockHTTPServer::Response(
364                                    std::string("HTTP/1.1 404 Not Found\n\n"),
365                                    std::string()));
366   SetUpRegistration(kScriptURL);
367   DoRequest(kScriptURL, &client, &loader);
368   client->RunUntilComplete();
369 
370   // The request should be failed because of the 404 response.
371   EXPECT_EQ(net::ERR_INVALID_RESPONSE, client->completion_status().error_code);
372   EXPECT_FALSE(client->has_received_response());
373 
374   // The response shouldn't be stored in the storage.
375   EXPECT_FALSE(VerifyStoredResponse(kScriptURL));
376   // No sample should be recorded since a write didn't occur.
377   histogram_tester.ExpectTotalCount(kHistogramWriteResponseResult, 0);
378 }
379 
TEST_F(ServiceWorkerNewScriptLoaderTest,Error_Redirect)380 TEST_F(ServiceWorkerNewScriptLoaderTest, Error_Redirect) {
381   base::HistogramTester histogram_tester;
382 
383   std::unique_ptr<network::TestURLLoaderClient> client;
384   std::unique_ptr<ServiceWorkerNewScriptLoader> loader;
385 
386   const GURL kScriptURL("https://example.com/redirect.js");
387   mock_server_.Set(
388       kScriptURL,
389       MockHTTPServer::Response(
390           std::string("HTTP/1.1 307 Temporary Redirect\n\n"), std::string()));
391   SetUpRegistration(kScriptURL);
392   DoRequest(kScriptURL, &client, &loader);
393   client->RunUntilComplete();
394 
395   // The request should be failed because of the redirected response.
396   EXPECT_EQ(net::ERR_UNSAFE_REDIRECT, client->completion_status().error_code);
397   EXPECT_FALSE(client->has_received_response());
398 
399   // The response shouldn't be stored in the storage.
400   EXPECT_FALSE(VerifyStoredResponse(kScriptURL));
401   // No sample should be recorded since a write didn't occur.
402   histogram_tester.ExpectTotalCount(kHistogramWriteResponseResult, 0);
403 }
404 
TEST_F(ServiceWorkerNewScriptLoaderTest,Error_CertificateError)405 TEST_F(ServiceWorkerNewScriptLoaderTest, Error_CertificateError) {
406   base::HistogramTester histogram_tester;
407 
408   std::unique_ptr<network::TestURLLoaderClient> client;
409   std::unique_ptr<ServiceWorkerNewScriptLoader> loader;
410 
411   // Serve a response with a certificate error.
412   const GURL kScriptURL("https://example.com/certificate-error.js");
413   MockHTTPServer::Response response(std::string("HTTP/1.1 200 OK\n\n"),
414                                     std::string("body"));
415   response.has_certificate_error = true;
416   response.cert_status = net::CERT_STATUS_DATE_INVALID;
417   mock_server_.Set(kScriptURL, response);
418   SetUpRegistration(kScriptURL);
419   DoRequest(kScriptURL, &client, &loader);
420   client->RunUntilComplete();
421 
422   // The request should be failed because of the response with the certificate
423   // error.
424   EXPECT_EQ(net::ERR_CERT_DATE_INVALID, client->completion_status().error_code);
425   EXPECT_FALSE(client->has_received_response());
426 
427   // The response shouldn't be stored in the storage.
428   EXPECT_FALSE(VerifyStoredResponse(kScriptURL));
429   // No sample should be recorded since a write didn't occur.
430   histogram_tester.ExpectTotalCount(kHistogramWriteResponseResult, 0);
431 }
432 
TEST_F(ServiceWorkerNewScriptLoaderTest,Error_NoMimeType)433 TEST_F(ServiceWorkerNewScriptLoaderTest, Error_NoMimeType) {
434   base::HistogramTester histogram_tester;
435 
436   std::unique_ptr<network::TestURLLoaderClient> client;
437   std::unique_ptr<ServiceWorkerNewScriptLoader> loader;
438 
439   const GURL kScriptURL("https://example.com/no-mime-type.js");
440   mock_server_.Set(kScriptURL, MockHTTPServer::Response(
441                                    std::string("HTTP/1.1 200 OK\n\n"),
442                                    std::string("body with no MIME type")));
443   SetUpRegistration(kScriptURL);
444   DoRequest(kScriptURL, &client, &loader);
445   client->RunUntilComplete();
446 
447   // The request should be failed because of the response with no MIME type.
448   EXPECT_EQ(net::ERR_INSECURE_RESPONSE, client->completion_status().error_code);
449   EXPECT_FALSE(client->has_received_response());
450 
451   // The response shouldn't be stored in the storage.
452   EXPECT_FALSE(VerifyStoredResponse(kScriptURL));
453   // No sample should be recorded since a write didn't occur.
454   histogram_tester.ExpectTotalCount(kHistogramWriteResponseResult, 0);
455 }
456 
457 class ServiceWorkerNewScriptLoaderTestWithLegacyTLSEnforced
458     : public ServiceWorkerNewScriptLoaderTest {
459  public:
ServiceWorkerNewScriptLoaderTestWithLegacyTLSEnforced()460   ServiceWorkerNewScriptLoaderTestWithLegacyTLSEnforced() {
461     feature_list_.InitAndEnableFeature(net::features::kLegacyTLSEnforced);
462   }
463 
464  private:
465   base::test::ScopedFeatureList feature_list_;
466 };
467 
468 // Tests that service workers fail to load over a connection with legacy TLS.
TEST_F(ServiceWorkerNewScriptLoaderTestWithLegacyTLSEnforced,Error_LegacyTLS)469 TEST_F(ServiceWorkerNewScriptLoaderTestWithLegacyTLSEnforced, Error_LegacyTLS) {
470   base::HistogramTester histogram_tester;
471 
472   std::unique_ptr<network::TestURLLoaderClient> client;
473   std::unique_ptr<ServiceWorkerNewScriptLoader> loader;
474 
475   // Serve a response with a certificate error.
476   const GURL kScriptURL("https://example.com/certificate-error.js");
477   MockHTTPServer::Response response(std::string("HTTP/1.1 200 OK\n\n"),
478                                     std::string("body"));
479   response.has_certificate_error = true;
480   response.cert_status = net::CERT_STATUS_LEGACY_TLS;
481   mock_server_.Set(kScriptURL, response);
482   SetUpRegistration(kScriptURL);
483   DoRequest(kScriptURL, &client, &loader);
484   client->RunUntilComplete();
485 
486   // The request should be failed because of the response with the legacy TLS
487   // error.
488   EXPECT_EQ(net::ERR_SSL_OBSOLETE_VERSION,
489             client->completion_status().error_code);
490   EXPECT_FALSE(client->has_received_response());
491 
492   // The response shouldn't be stored in the storage.
493   EXPECT_FALSE(VerifyStoredResponse(kScriptURL));
494   // No sample should be recorded since a write didn't occur.
495   histogram_tester.ExpectTotalCount(kHistogramWriteResponseResult, 0);
496 }
497 
TEST_F(ServiceWorkerNewScriptLoaderTest,Error_BadMimeType)498 TEST_F(ServiceWorkerNewScriptLoaderTest, Error_BadMimeType) {
499   base::HistogramTester histogram_tester;
500 
501   std::unique_ptr<network::TestURLLoaderClient> client;
502   std::unique_ptr<ServiceWorkerNewScriptLoader> loader;
503 
504   const GURL kScriptURL("https://example.com/bad-mime-type.js");
505   mock_server_.Set(kScriptURL, MockHTTPServer::Response(
506                                    std::string("HTTP/1.1 200 OK\n"
507                                                "Content-Type: text/css\n\n"),
508                                    std::string("body with bad MIME type")));
509   SetUpRegistration(kScriptURL);
510   DoRequest(kScriptURL, &client, &loader);
511   client->RunUntilComplete();
512 
513   // The request should be failed because of the response with the bad MIME
514   // type.
515   EXPECT_EQ(net::ERR_INSECURE_RESPONSE, client->completion_status().error_code);
516   EXPECT_FALSE(client->has_received_response());
517 
518   // The response shouldn't be stored in the storage.
519   EXPECT_FALSE(VerifyStoredResponse(kScriptURL));
520   // No sample should be recorded since a write didn't occur.
521   histogram_tester.ExpectTotalCount(kHistogramWriteResponseResult, 0);
522 }
523 
TEST_F(ServiceWorkerNewScriptLoaderTest,Success_PathRestriction)524 TEST_F(ServiceWorkerNewScriptLoaderTest, Success_PathRestriction) {
525   base::HistogramTester histogram_tester;
526 
527   std::unique_ptr<network::TestURLLoaderClient> client;
528   std::unique_ptr<ServiceWorkerNewScriptLoader> loader;
529 
530   // |kScope| is not under the default scope ("/out-of-scope/"), but the
531   // Service-Worker-Allowed header allows it.
532   const GURL kScriptURL("https://example.com/out-of-scope/normal.js");
533   const GURL kScope("https://example.com/in-scope/");
534   mock_server_.Set(kScriptURL,
535                    MockHTTPServer::Response(
536                        std::string("HTTP/1.1 200 OK\n"
537                                    "Content-Type: text/javascript\n"
538                                    "Service-Worker-Allowed: /in-scope/\n\n"),
539                        std::string("٩( ’ω’ )و I'm body!")));
540   blink::mojom::ServiceWorkerRegistrationOptions options;
541   options.scope = kScope;
542   SetUpRegistrationWithOptions(kScriptURL, options);
543   DoRequest(kScriptURL, &client, &loader);
544   client->RunUntilComplete();
545   EXPECT_EQ(net::OK, client->completion_status().error_code);
546 
547   // The client should have received the response.
548   EXPECT_TRUE(client->has_received_response());
549   EXPECT_TRUE(client->response_body().is_valid());
550   std::string response;
551   EXPECT_TRUE(
552       mojo::BlockingCopyToString(client->response_body_release(), &response));
553   EXPECT_EQ(mock_server_.Get(kScriptURL).body, response);
554 
555   // WRITE_OK should be recorded once plus one as we record a single write
556   // success and the end of the body.
557   EXPECT_TRUE(VerifyStoredResponse(kScriptURL));
558   histogram_tester.ExpectUniqueSample(kHistogramWriteResponseResult,
559                                       ServiceWorkerMetrics::WRITE_OK, 2);
560 }
561 
TEST_F(ServiceWorkerNewScriptLoaderTest,Error_PathRestriction)562 TEST_F(ServiceWorkerNewScriptLoaderTest, Error_PathRestriction) {
563   base::HistogramTester histogram_tester;
564 
565   std::unique_ptr<network::TestURLLoaderClient> client;
566   std::unique_ptr<ServiceWorkerNewScriptLoader> loader;
567 
568   // |kScope| is not under the default scope ("/out-of-scope/") and the
569   // Service-Worker-Allowed header is not specified.
570   const GURL kScriptURL("https://example.com/out-of-scope/normal.js");
571   const GURL kScope("https://example.com/in-scope/");
572   mock_server_.Set(
573       kScriptURL,
574       MockHTTPServer::Response(std::string("HTTP/1.1 200 OK\n"
575                                            "Content-Type: text/javascript\n\n"),
576                                std::string()));
577   blink::mojom::ServiceWorkerRegistrationOptions options;
578   options.scope = kScope;
579   SetUpRegistrationWithOptions(kScriptURL, options);
580   DoRequest(kScriptURL, &client, &loader);
581   client->RunUntilComplete();
582 
583   // The request should be failed because the scope is not allowed.
584   EXPECT_EQ(net::ERR_INSECURE_RESPONSE, client->completion_status().error_code);
585   EXPECT_FALSE(client->has_received_response());
586 
587   // The response shouldn't be stored in the storage.
588   EXPECT_FALSE(VerifyStoredResponse(kScriptURL));
589   // No sample should be recorded since a write didn't occur.
590   histogram_tester.ExpectTotalCount(kHistogramWriteResponseResult, 0);
591 }
592 
TEST_F(ServiceWorkerNewScriptLoaderTest,Error_RedundantWorker)593 TEST_F(ServiceWorkerNewScriptLoaderTest, Error_RedundantWorker) {
594   base::HistogramTester histogram_tester;
595 
596   std::unique_ptr<network::TestURLLoaderClient> client;
597   std::unique_ptr<ServiceWorkerNewScriptLoader> loader;
598 
599   const GURL kScriptURL(kNormalScriptURL);
600   SetUpRegistration(kScriptURL);
601   DoRequest(kScriptURL, &client, &loader);
602 
603   // Make the service worker redundant.
604   version_->Doom();
605   ASSERT_TRUE(version_->is_redundant());
606 
607   client->RunUntilComplete();
608 
609   // The request should be aborted.
610   EXPECT_EQ(net::ERR_FAILED, client->completion_status().error_code);
611   EXPECT_FALSE(client->has_received_response());
612 
613   // The response shouldn't be stored in the storage.
614   EXPECT_FALSE(VerifyStoredResponse(kScriptURL));
615   // No sample should be recorded since a write didn't occur.
616   histogram_tester.ExpectTotalCount(kHistogramWriteResponseResult, 0);
617 }
618 
619 // Tests that EmbeddedWorkerInstance's |network_accessed_for_script_| flag is
620 // set when the script loader accesses network. This flag is used to enforce the
621 // 24 hour cache validation.
TEST_F(ServiceWorkerNewScriptLoaderTest,AccessedNetwork)622 TEST_F(ServiceWorkerNewScriptLoaderTest, AccessedNetwork) {
623   const GURL kScriptURL(kNormalScriptURL);
624   const GURL kImportedScriptURL(kNormalImportedScriptURL);
625   std::unique_ptr<network::TestURLLoaderClient> client;
626   std::unique_ptr<ServiceWorkerNewScriptLoader> loader;
627 
628   SetUpRegistration(kScriptURL);
629 
630   // Install the main script. The network accessed flag should be flipped on.
631   version_->embedded_worker()->network_accessed_for_script_ = false;
632   mock_network_.set_to_access_network(true);
633   DoRequest(kScriptURL, &client, &loader);
634   client->RunUntilComplete();
635   EXPECT_EQ(net::OK, client->completion_status().error_code);
636   EXPECT_TRUE(version_->embedded_worker()->network_accessed_for_script());
637 
638   // Install the imported script. The network accessed flag should be unchanged,
639   // as it's only meant for main scripts.
640   version_->embedded_worker()->network_accessed_for_script_ = false;
641   mock_network_.set_to_access_network(true);
642   DoRequest(kImportedScriptURL, &client, &loader);
643   client->RunUntilComplete();
644   EXPECT_EQ(net::OK, client->completion_status().error_code);
645   EXPECT_FALSE(version_->embedded_worker()->network_accessed_for_script());
646 
647   // Install a new main script, this time simulating coming from cache. The
648   // network accessed flag should be off.
649   SetUpRegistration(kScriptURL);
650   version_->embedded_worker()->network_accessed_for_script_ = false;
651   mock_network_.set_to_access_network(false);
652   DoRequest(kScriptURL, &client, &loader);
653   client->RunUntilComplete();
654   EXPECT_EQ(net::OK, client->completion_status().error_code);
655   EXPECT_FALSE(version_->embedded_worker()->network_accessed_for_script());
656 }
657 
658 }  // namespace service_worker_new_script_loader_unittest
659 }  // namespace content
660