1 // Copyright 2015 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 "third_party/blink/renderer/platform/loader/fetch/resource.h"
6 
7 #include "testing/gtest/include/gtest/gtest.h"
8 #include "third_party/blink/public/platform/platform.h"
9 #include "third_party/blink/renderer/platform/loader/fetch/memory_cache.h"
10 #include "third_party/blink/renderer/platform/loader/fetch/resource_request.h"
11 #include "third_party/blink/renderer/platform/loader/fetch/resource_response.h"
12 #include "third_party/blink/renderer/platform/loader/testing/mock_resource.h"
13 #include "third_party/blink/renderer/platform/loader/testing/mock_resource_client.h"
14 #include "third_party/blink/renderer/platform/testing/testing_platform_support_with_mock_scheduler.h"
15 #include "third_party/blink/renderer/platform/testing/url_test_helpers.h"
16 #include "third_party/blink/renderer/platform/wtf/shared_buffer.h"
17 #include "third_party/blink/renderer/platform/wtf/vector.h"
18 
19 namespace blink {
20 
21 namespace {
22 
23 class MockPlatform final : public TestingPlatformSupportWithMockScheduler {
24  public:
25   MockPlatform() = default;
26   ~MockPlatform() override = default;
27 
28   // From blink::Platform:
CacheMetadata(blink::mojom::CodeCacheType cache_type,const WebURL & url,base::Time,const uint8_t *,size_t)29   void CacheMetadata(blink::mojom::CodeCacheType cache_type,
30                      const WebURL& url,
31                      base::Time,
32                      const uint8_t*,
33                      size_t) override {
34     cached_urls_.push_back(url);
35   }
36 
CacheMetadataInCacheStorage(const blink::WebURL & url,base::Time,const uint8_t *,size_t,const blink::WebSecurityOrigin &,const blink::WebString &)37   void CacheMetadataInCacheStorage(const blink::WebURL& url,
38                                    base::Time,
39                                    const uint8_t*,
40                                    size_t,
41                                    const blink::WebSecurityOrigin&,
42                                    const blink::WebString&) override {
43     cache_storage_cached_urls_.push_back(url);
44   }
45 
CachedURLs() const46   const Vector<WebURL>& CachedURLs() const { return cached_urls_; }
CacheStorageCachedURLs() const47   const Vector<WebURL>& CacheStorageCachedURLs() const {
48     return cache_storage_cached_urls_;
49   }
50 
51  private:
52   Vector<WebURL> cached_urls_;
53   Vector<WebURL> cache_storage_cached_urls_;
54 };
55 
CreateTestResourceResponse()56 ResourceResponse CreateTestResourceResponse() {
57   ResourceResponse response(url_test_helpers::ToKURL("https://example.com/"));
58   response.SetHttpStatusCode(200);
59   return response;
60 }
61 
CreateTestResourceAndSetCachedMetadata(const ResourceResponse & response)62 void CreateTestResourceAndSetCachedMetadata(const ResourceResponse& response) {
63   const uint8_t kTestData[] = {1, 2, 3, 4, 5};
64   ResourceRequest request(response.CurrentRequestUrl());
65   request.SetRequestorOrigin(
66       SecurityOrigin::Create(response.CurrentRequestUrl()));
67   auto* resource = MakeGarbageCollected<MockResource>(request);
68   resource->SetResponse(response);
69   resource->SendCachedMetadata(kTestData, sizeof(kTestData));
70   return;
71 }
72 
73 }  // anonymous namespace
74 
TEST(ResourceTest,SetCachedMetadata_SendsMetadataToPlatform)75 TEST(ResourceTest, SetCachedMetadata_SendsMetadataToPlatform) {
76   ScopedTestingPlatformSupport<MockPlatform> mock;
77   ResourceResponse response(CreateTestResourceResponse());
78   CreateTestResourceAndSetCachedMetadata(response);
79   EXPECT_EQ(1u, mock->CachedURLs().size());
80   EXPECT_EQ(0u, mock->CacheStorageCachedURLs().size());
81 }
82 
TEST(ResourceTest,SetCachedMetadata_DoesNotSendMetadataToPlatformWhenFetchedViaServiceWorkerWithSyntheticResponse)83 TEST(
84     ResourceTest,
85     SetCachedMetadata_DoesNotSendMetadataToPlatformWhenFetchedViaServiceWorkerWithSyntheticResponse) {
86   ScopedTestingPlatformSupport<MockPlatform> mock;
87 
88   // Equivalent to service worker calling respondWith(new Response(...))
89   ResourceResponse response(CreateTestResourceResponse());
90   response.SetWasFetchedViaServiceWorker(true);
91 
92   CreateTestResourceAndSetCachedMetadata(response);
93   EXPECT_EQ(0u, mock->CachedURLs().size());
94   EXPECT_EQ(0u, mock->CacheStorageCachedURLs().size());
95 }
96 
TEST(ResourceTest,SetCachedMetadata_SendsMetadataToPlatformWhenFetchedViaServiceWorkerWithPassThroughResponse)97 TEST(
98     ResourceTest,
99     SetCachedMetadata_SendsMetadataToPlatformWhenFetchedViaServiceWorkerWithPassThroughResponse) {
100   ScopedTestingPlatformSupport<MockPlatform> mock;
101 
102   // Equivalent to service worker calling respondWith(fetch(evt.request.url));
103   ResourceResponse response(CreateTestResourceResponse());
104   response.SetWasFetchedViaServiceWorker(true);
105   response.SetUrlListViaServiceWorker(
106       Vector<KURL>(1, response.CurrentRequestUrl()));
107 
108   CreateTestResourceAndSetCachedMetadata(response);
109   EXPECT_EQ(1u, mock->CachedURLs().size());
110   EXPECT_EQ(0u, mock->CacheStorageCachedURLs().size());
111 }
112 
TEST(ResourceTest,SetCachedMetadata_DoesNotSendMetadataToPlatformWhenFetchedViaServiceWorkerWithDifferentURLResponse)113 TEST(
114     ResourceTest,
115     SetCachedMetadata_DoesNotSendMetadataToPlatformWhenFetchedViaServiceWorkerWithDifferentURLResponse) {
116   ScopedTestingPlatformSupport<MockPlatform> mock;
117 
118   // Equivalent to service worker calling respondWith(fetch(some_different_url))
119   ResourceResponse response(CreateTestResourceResponse());
120   response.SetWasFetchedViaServiceWorker(true);
121   response.SetUrlListViaServiceWorker(Vector<KURL>(
122       1, url_test_helpers::ToKURL("https://example.com/different/url")));
123 
124   CreateTestResourceAndSetCachedMetadata(response);
125   EXPECT_EQ(0u, mock->CachedURLs().size());
126   EXPECT_EQ(0u, mock->CacheStorageCachedURLs().size());
127 }
128 
TEST(ResourceTest,SetCachedMetadata_SendsMetadataToPlatformWhenFetchedViaServiceWorkerWithCacheResponse)129 TEST(
130     ResourceTest,
131     SetCachedMetadata_SendsMetadataToPlatformWhenFetchedViaServiceWorkerWithCacheResponse) {
132   ScopedTestingPlatformSupport<MockPlatform> mock;
133 
134   // Equivalent to service worker calling respondWith(cache.match(some_url));
135   ResourceResponse response(CreateTestResourceResponse());
136   response.SetWasFetchedViaServiceWorker(true);
137   response.SetCacheStorageCacheName("dummy");
138 
139   CreateTestResourceAndSetCachedMetadata(response);
140   EXPECT_EQ(0u, mock->CachedURLs().size());
141   EXPECT_EQ(1u, mock->CacheStorageCachedURLs().size());
142 }
143 
TEST(ResourceTest,RevalidateWithFragment)144 TEST(ResourceTest, RevalidateWithFragment) {
145   ScopedTestingPlatformSupport<MockPlatform> mock;
146   KURL url("http://127.0.0.1:8000/foo.html");
147   ResourceResponse response(url);
148   response.SetHttpStatusCode(200);
149   auto* resource = MakeGarbageCollected<MockResource>(url);
150   resource->ResponseReceived(response);
151   resource->FinishForTest();
152 
153   // Revalidating with a url that differs by only the fragment
154   // shouldn't trigger a securiy check.
155   url.SetFragmentIdentifier("bar");
156   resource->SetRevalidatingRequest(ResourceRequest(url));
157   ResourceResponse revalidating_response(url);
158   revalidating_response.SetHttpStatusCode(304);
159   resource->ResponseReceived(revalidating_response);
160 }
161 
TEST(ResourceTest,Vary)162 TEST(ResourceTest, Vary) {
163   ScopedTestingPlatformSupport<MockPlatform> mock;
164   const KURL url("http://127.0.0.1:8000/foo.html");
165   ResourceResponse response(url);
166   response.SetHttpStatusCode(200);
167 
168   auto* resource = MakeGarbageCollected<MockResource>(url);
169   resource->ResponseReceived(response);
170   resource->FinishForTest();
171 
172   ResourceRequest new_request(url);
173   EXPECT_FALSE(resource->MustReloadDueToVaryHeader(new_request));
174 
175   response.SetHttpHeaderField(http_names::kVary, "*");
176   resource->SetResponse(response);
177   EXPECT_TRUE(resource->MustReloadDueToVaryHeader(new_request));
178 
179   // Irrelevant header
180   response.SetHttpHeaderField(http_names::kVary, "definitelynotarealheader");
181   resource->SetResponse(response);
182   EXPECT_FALSE(resource->MustReloadDueToVaryHeader(new_request));
183 
184   // Header present on new but not old
185   new_request.SetHttpHeaderField(http_names::kUserAgent, "something");
186   response.SetHttpHeaderField(http_names::kVary, http_names::kUserAgent);
187   resource->SetResponse(response);
188   EXPECT_TRUE(resource->MustReloadDueToVaryHeader(new_request));
189   new_request.ClearHttpHeaderField(http_names::kUserAgent);
190 
191   ResourceRequest old_request(url);
192   old_request.SetHttpHeaderField(http_names::kUserAgent, "something");
193   old_request.SetHttpHeaderField(http_names::kReferer, "http://foo.com");
194   resource = MakeGarbageCollected<MockResource>(old_request);
195   resource->ResponseReceived(response);
196   resource->FinishForTest();
197 
198   // Header present on old but not new
199   new_request.ClearHttpHeaderField(http_names::kUserAgent);
200   response.SetHttpHeaderField(http_names::kVary, http_names::kUserAgent);
201   resource->SetResponse(response);
202   EXPECT_TRUE(resource->MustReloadDueToVaryHeader(new_request));
203 
204   // Header present on both
205   new_request.SetHttpHeaderField(http_names::kUserAgent, "something");
206   EXPECT_FALSE(resource->MustReloadDueToVaryHeader(new_request));
207 
208   // One matching, one mismatching
209   response.SetHttpHeaderField(http_names::kVary, "User-Agent, Referer");
210   resource->SetResponse(response);
211   EXPECT_TRUE(resource->MustReloadDueToVaryHeader(new_request));
212 
213   // Two matching
214   new_request.SetHttpHeaderField(http_names::kReferer, "http://foo.com");
215   EXPECT_FALSE(resource->MustReloadDueToVaryHeader(new_request));
216 }
217 
TEST(ResourceTest,RevalidationFailed)218 TEST(ResourceTest, RevalidationFailed) {
219   ScopedTestingPlatformSupport<TestingPlatformSupportWithMockScheduler>
220       platform_;
221   const KURL url("http://test.example.com/");
222   auto* resource = MakeGarbageCollected<MockResource>(url);
223   ResourceResponse response(url);
224   response.SetHttpStatusCode(200);
225   resource->ResponseReceived(response);
226   const char kData[5] = "abcd";
227   resource->AppendData(kData, 4);
228   resource->FinishForTest();
229   GetMemoryCache()->Add(resource);
230 
231   MockCacheHandler* original_cache_handler = resource->CacheHandler();
232   EXPECT_TRUE(original_cache_handler);
233 
234   // Simulate revalidation start.
235   resource->SetRevalidatingRequest(ResourceRequest(url));
236 
237   EXPECT_EQ(original_cache_handler, resource->CacheHandler());
238 
239   Persistent<MockResourceClient> client =
240       MakeGarbageCollected<MockResourceClient>();
241   resource->AddClient(client, nullptr);
242 
243   ResourceResponse revalidating_response(url);
244   revalidating_response.SetHttpStatusCode(200);
245   resource->ResponseReceived(revalidating_response);
246 
247   EXPECT_FALSE(resource->IsCacheValidator());
248   EXPECT_EQ(200, resource->GetResponse().HttpStatusCode());
249   EXPECT_FALSE(resource->ResourceBuffer());
250   EXPECT_TRUE(resource->CacheHandler());
251   EXPECT_NE(original_cache_handler, resource->CacheHandler());
252   EXPECT_EQ(resource, GetMemoryCache()->ResourceForURL(url));
253 
254   resource->AppendData(kData, 4);
255 
256   EXPECT_FALSE(client->NotifyFinishedCalled());
257 
258   resource->FinishForTest();
259 
260   EXPECT_TRUE(client->NotifyFinishedCalled());
261 
262   resource->RemoveClient(client);
263   EXPECT_FALSE(resource->IsAlive());
264 }
265 
TEST(ResourceTest,RevalidationSucceeded)266 TEST(ResourceTest, RevalidationSucceeded) {
267   ScopedTestingPlatformSupport<TestingPlatformSupportWithMockScheduler>
268       platform_;
269   const KURL url("http://test.example.com/");
270   auto* resource = MakeGarbageCollected<MockResource>(url);
271   ResourceResponse response(url);
272   response.SetHttpStatusCode(200);
273   resource->ResponseReceived(response);
274   const char kData[5] = "abcd";
275   resource->AppendData(kData, 4);
276   resource->FinishForTest();
277   GetMemoryCache()->Add(resource);
278 
279   MockCacheHandler* original_cache_handler = resource->CacheHandler();
280   EXPECT_TRUE(original_cache_handler);
281 
282   // Simulate a successful revalidation.
283   resource->SetRevalidatingRequest(ResourceRequest(url));
284 
285   EXPECT_EQ(original_cache_handler, resource->CacheHandler());
286 
287   Persistent<MockResourceClient> client =
288       MakeGarbageCollected<MockResourceClient>();
289   resource->AddClient(client, nullptr);
290 
291   ResourceResponse revalidating_response(url);
292   revalidating_response.SetHttpStatusCode(304);
293   resource->ResponseReceived(revalidating_response);
294 
295   EXPECT_FALSE(resource->IsCacheValidator());
296   EXPECT_EQ(200, resource->GetResponse().HttpStatusCode());
297   EXPECT_EQ(4u, resource->ResourceBuffer()->size());
298   EXPECT_EQ(original_cache_handler, resource->CacheHandler());
299   EXPECT_EQ(resource, GetMemoryCache()->ResourceForURL(url));
300 
301   GetMemoryCache()->Remove(resource);
302 
303   resource->RemoveClient(client);
304   EXPECT_FALSE(resource->IsAlive());
305   EXPECT_FALSE(client->NotifyFinishedCalled());
306 }
307 
TEST(ResourceTest,RevalidationSucceededForResourceWithoutBody)308 TEST(ResourceTest, RevalidationSucceededForResourceWithoutBody) {
309   ScopedTestingPlatformSupport<TestingPlatformSupportWithMockScheduler>
310       platform_;
311   const KURL url("http://test.example.com/");
312   auto* resource = MakeGarbageCollected<MockResource>(url);
313   ResourceResponse response(url);
314   response.SetHttpStatusCode(200);
315   resource->ResponseReceived(response);
316   resource->FinishForTest();
317   GetMemoryCache()->Add(resource);
318 
319   // Simulate a successful revalidation.
320   resource->SetRevalidatingRequest(ResourceRequest(url));
321 
322   Persistent<MockResourceClient> client =
323       MakeGarbageCollected<MockResourceClient>();
324   resource->AddClient(client, nullptr);
325 
326   ResourceResponse revalidating_response(url);
327   revalidating_response.SetHttpStatusCode(304);
328   resource->ResponseReceived(revalidating_response);
329   EXPECT_FALSE(resource->IsCacheValidator());
330   EXPECT_EQ(200, resource->GetResponse().HttpStatusCode());
331   EXPECT_FALSE(resource->ResourceBuffer());
332   EXPECT_EQ(resource, GetMemoryCache()->ResourceForURL(url));
333   GetMemoryCache()->Remove(resource);
334 
335   resource->RemoveClient(client);
336   EXPECT_FALSE(resource->IsAlive());
337   EXPECT_FALSE(client->NotifyFinishedCalled());
338 }
339 
TEST(ResourceTest,RevalidationSucceededUpdateHeaders)340 TEST(ResourceTest, RevalidationSucceededUpdateHeaders) {
341   ScopedTestingPlatformSupport<TestingPlatformSupportWithMockScheduler>
342       platform_;
343   const KURL url("http://test.example.com/");
344   auto* resource = MakeGarbageCollected<MockResource>(url);
345   ResourceResponse response(url);
346   response.SetHttpStatusCode(200);
347   response.AddHttpHeaderField("keep-alive", "keep-alive value");
348   response.AddHttpHeaderField("expires", "expires value");
349   response.AddHttpHeaderField("last-modified", "last-modified value");
350   response.AddHttpHeaderField("proxy-authenticate", "proxy-authenticate value");
351   response.AddHttpHeaderField("proxy-connection", "proxy-connection value");
352   response.AddHttpHeaderField("x-custom", "custom value");
353   resource->ResponseReceived(response);
354   resource->FinishForTest();
355   GetMemoryCache()->Add(resource);
356 
357   // Simulate a successful revalidation.
358   resource->SetRevalidatingRequest(ResourceRequest(url));
359 
360   // Validate that these headers pre-update.
361   EXPECT_EQ("keep-alive value",
362             resource->GetResponse().HttpHeaderField("keep-alive"));
363   EXPECT_EQ("expires value",
364             resource->GetResponse().HttpHeaderField("expires"));
365   EXPECT_EQ("last-modified value",
366             resource->GetResponse().HttpHeaderField("last-modified"));
367   EXPECT_EQ("proxy-authenticate value",
368             resource->GetResponse().HttpHeaderField("proxy-authenticate"));
369   EXPECT_EQ("proxy-authenticate value",
370             resource->GetResponse().HttpHeaderField("proxy-authenticate"));
371   EXPECT_EQ("proxy-connection value",
372             resource->GetResponse().HttpHeaderField("proxy-connection"));
373   EXPECT_EQ("custom value",
374             resource->GetResponse().HttpHeaderField("x-custom"));
375 
376   Persistent<MockResourceClient> client =
377       MakeGarbageCollected<MockResourceClient>();
378   resource->AddClient(client, nullptr);
379 
380   // Perform a revalidation step.
381   ResourceResponse revalidating_response(url);
382   revalidating_response.SetHttpStatusCode(304);
383   // Headers that aren't copied with an 304 code.
384   revalidating_response.AddHttpHeaderField("keep-alive", "garbage");
385   revalidating_response.AddHttpHeaderField("expires", "garbage");
386   revalidating_response.AddHttpHeaderField("last-modified", "garbage");
387   revalidating_response.AddHttpHeaderField("proxy-authenticate", "garbage");
388   revalidating_response.AddHttpHeaderField("proxy-connection", "garbage");
389   // Header that is updated with 304 code.
390   revalidating_response.AddHttpHeaderField("x-custom", "updated");
391   resource->ResponseReceived(revalidating_response);
392 
393   // Validate the original response.
394   EXPECT_EQ(200, resource->GetResponse().HttpStatusCode());
395 
396   // Validate that these headers are not updated.
397   EXPECT_EQ("keep-alive value",
398             resource->GetResponse().HttpHeaderField("keep-alive"));
399   EXPECT_EQ("expires value",
400             resource->GetResponse().HttpHeaderField("expires"));
401   EXPECT_EQ("last-modified value",
402             resource->GetResponse().HttpHeaderField("last-modified"));
403   EXPECT_EQ("proxy-authenticate value",
404             resource->GetResponse().HttpHeaderField("proxy-authenticate"));
405   EXPECT_EQ("proxy-authenticate value",
406             resource->GetResponse().HttpHeaderField("proxy-authenticate"));
407   EXPECT_EQ("proxy-connection value",
408             resource->GetResponse().HttpHeaderField("proxy-connection"));
409   EXPECT_EQ("updated", resource->GetResponse().HttpHeaderField("x-custom"));
410 
411   resource->RemoveClient(client);
412   EXPECT_FALSE(resource->IsAlive());
413   EXPECT_FALSE(client->NotifyFinishedCalled());
414 }
415 
TEST(ResourceTest,RedirectDuringRevalidation)416 TEST(ResourceTest, RedirectDuringRevalidation) {
417   ScopedTestingPlatformSupport<TestingPlatformSupportWithMockScheduler>
418       platform_;
419   const KURL url("http://test.example.com/1");
420   const KURL redirect_target_url("http://test.example.com/2");
421 
422   auto* resource = MakeGarbageCollected<MockResource>(url);
423   ResourceResponse response(url);
424   response.SetHttpStatusCode(200);
425   resource->ResponseReceived(response);
426   const char kData[5] = "abcd";
427   resource->AppendData(kData, 4);
428   resource->FinishForTest();
429   GetMemoryCache()->Add(resource);
430 
431   EXPECT_FALSE(resource->IsCacheValidator());
432   EXPECT_EQ(url, resource->GetResourceRequest().Url());
433   EXPECT_EQ(url, resource->LastResourceRequest().Url());
434 
435   MockCacheHandler* original_cache_handler = resource->CacheHandler();
436   EXPECT_TRUE(original_cache_handler);
437 
438   // Simulate a revalidation.
439   resource->SetRevalidatingRequest(ResourceRequest(url));
440   EXPECT_TRUE(resource->IsCacheValidator());
441   EXPECT_EQ(url, resource->GetResourceRequest().Url());
442   EXPECT_EQ(url, resource->LastResourceRequest().Url());
443   EXPECT_EQ(original_cache_handler, resource->CacheHandler());
444 
445   Persistent<MockResourceClient> client =
446       MakeGarbageCollected<MockResourceClient>();
447   resource->AddClient(client, nullptr);
448 
449   // The revalidating request is redirected.
450   ResourceResponse redirect_response(url);
451   redirect_response.SetHttpHeaderField(
452       "location", AtomicString(redirect_target_url.GetString()));
453   redirect_response.SetHttpStatusCode(308);
454   ResourceRequest redirected_revalidating_request(redirect_target_url);
455   resource->WillFollowRedirect(redirected_revalidating_request,
456                                redirect_response);
457   EXPECT_FALSE(resource->IsCacheValidator());
458   EXPECT_EQ(url, resource->GetResourceRequest().Url());
459   EXPECT_EQ(redirect_target_url, resource->LastResourceRequest().Url());
460   EXPECT_FALSE(resource->CacheHandler());
461 
462   // The final response is received.
463   ResourceResponse revalidating_response(redirect_target_url);
464   revalidating_response.SetHttpStatusCode(200);
465   resource->ResponseReceived(revalidating_response);
466 
467   EXPECT_TRUE(resource->CacheHandler());
468 
469   const char kData2[4] = "xyz";
470   resource->AppendData(kData2, 3);
471   resource->FinishForTest();
472   EXPECT_FALSE(resource->IsCacheValidator());
473   EXPECT_EQ(url, resource->GetResourceRequest().Url());
474   EXPECT_EQ(redirect_target_url, resource->LastResourceRequest().Url());
475   EXPECT_FALSE(resource->IsCacheValidator());
476   EXPECT_EQ(200, resource->GetResponse().HttpStatusCode());
477   EXPECT_EQ(3u, resource->ResourceBuffer()->size());
478   EXPECT_EQ(resource, GetMemoryCache()->ResourceForURL(url));
479 
480   EXPECT_TRUE(client->NotifyFinishedCalled());
481 
482   // Test the case where a client is added after revalidation is completed.
483   Persistent<MockResourceClient> client2 =
484       MakeGarbageCollected<MockResourceClient>();
485   auto* platform = static_cast<TestingPlatformSupportWithMockScheduler*>(
486       Platform::Current());
487   resource->AddClient(client2, platform->test_task_runner().get());
488 
489   // Because the client is added asynchronously,
490   // |runUntilIdle()| is called to make |client2| to be notified.
491   platform_->RunUntilIdle();
492 
493   EXPECT_TRUE(client2->NotifyFinishedCalled());
494 
495   GetMemoryCache()->Remove(resource);
496 
497   resource->RemoveClient(client);
498   resource->RemoveClient(client2);
499   EXPECT_FALSE(resource->IsAlive());
500 }
501 
502 class ScopedResourceMockClock {
503  public:
ScopedResourceMockClock(const base::Clock * clock)504   explicit ScopedResourceMockClock(const base::Clock* clock) {
505     Resource::SetClockForTesting(clock);
506   }
~ScopedResourceMockClock()507   ~ScopedResourceMockClock() { Resource::SetClockForTesting(nullptr); }
508 };
509 
TEST(ResourceTest,StaleWhileRevalidateCacheControl)510 TEST(ResourceTest, StaleWhileRevalidateCacheControl) {
511   ScopedTestingPlatformSupport<MockPlatform> mock;
512   ScopedResourceMockClock clock(mock->test_task_runner()->GetMockClock());
513   const KURL url("http://127.0.0.1:8000/foo.html");
514   ResourceResponse response(url);
515   response.SetHttpStatusCode(200);
516   response.SetHttpHeaderField(http_names::kCacheControl,
517                               "max-age=0, stale-while-revalidate=40");
518 
519   auto* resource = MakeGarbageCollected<MockResource>(url);
520   resource->ResponseReceived(response);
521   resource->FinishForTest();
522 
523   EXPECT_FALSE(resource->MustRevalidateDueToCacheHeaders(false));
524   EXPECT_FALSE(resource->MustRevalidateDueToCacheHeaders(true));
525   EXPECT_FALSE(resource->ShouldRevalidateStaleResponse());
526 
527   mock->AdvanceClockSeconds(1);
528   EXPECT_TRUE(resource->MustRevalidateDueToCacheHeaders(false));
529   EXPECT_FALSE(resource->MustRevalidateDueToCacheHeaders(true));
530   EXPECT_TRUE(resource->ShouldRevalidateStaleResponse());
531 
532   mock->AdvanceClockSeconds(40);
533   EXPECT_TRUE(resource->MustRevalidateDueToCacheHeaders(false));
534   EXPECT_TRUE(resource->MustRevalidateDueToCacheHeaders(true));
535   EXPECT_TRUE(resource->ShouldRevalidateStaleResponse());
536 }
537 
TEST(ResourceTest,StaleWhileRevalidateCacheControlWithRedirect)538 TEST(ResourceTest, StaleWhileRevalidateCacheControlWithRedirect) {
539   ScopedTestingPlatformSupport<MockPlatform> mock;
540   ScopedResourceMockClock clock(mock->test_task_runner()->GetMockClock());
541   const KURL url("http://127.0.0.1:8000/foo.html");
542   const KURL redirect_target_url("http://127.0.0.1:8000/food.html");
543   ResourceResponse response(url);
544   response.SetHttpHeaderField(http_names::kCacheControl, "max-age=50");
545   response.SetHttpStatusCode(200);
546 
547   // The revalidating request is redirected.
548   ResourceResponse redirect_response(url);
549   redirect_response.SetHttpHeaderField(
550       "location", AtomicString(redirect_target_url.GetString()));
551   redirect_response.SetHttpStatusCode(302);
552   redirect_response.SetHttpHeaderField(http_names::kCacheControl,
553                                        "max-age=0, stale-while-revalidate=40");
554   redirect_response.SetAsyncRevalidationRequested(true);
555   ResourceRequest redirected_revalidating_request(redirect_target_url);
556 
557   auto* resource = MakeGarbageCollected<MockResource>(url);
558   resource->WillFollowRedirect(redirected_revalidating_request,
559                                redirect_response);
560   resource->ResponseReceived(response);
561   resource->FinishForTest();
562 
563   EXPECT_FALSE(resource->MustRevalidateDueToCacheHeaders(false));
564   EXPECT_FALSE(resource->MustRevalidateDueToCacheHeaders(true));
565   EXPECT_FALSE(resource->ShouldRevalidateStaleResponse());
566 
567   mock->AdvanceClockSeconds(41);
568 
569   // MustRevalidateDueToCacheHeaders only looks at the stored response not
570   // any redirects but ShouldRevalidate and AsyncRevalidationRequest look
571   // at the entire redirect chain.
572   EXPECT_FALSE(resource->MustRevalidateDueToCacheHeaders(false));
573   EXPECT_FALSE(resource->MustRevalidateDueToCacheHeaders(true));
574   EXPECT_TRUE(resource->ShouldRevalidateStaleResponse());
575   EXPECT_TRUE(resource->StaleRevalidationRequested());
576 }
577 
578 // This is a regression test for https://crbug.com/1062837.
TEST(ResourceTest,DefaultOverheadSize)579 TEST(ResourceTest, DefaultOverheadSize) {
580   const KURL url("http://127.0.0.1:8000/foo.html");
581   auto* resource = MakeGarbageCollected<MockResource>(url);
582   EXPECT_EQ(resource->CalculateOverheadSizeForTest(), resource->OverheadSize());
583 }
584 
585 }  // namespace blink
586