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