2 * Copyright (c) 2014, Google Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above
11 * copyright notice, this list of conditions and the following disclaimer
12 * in the documentation and/or other materials provided with the
14 * * Neither the name of Google Inc. nor the names of its
15 * contributors may be used to endorse or promote products derived from
16 * this software without specific prior written permission.
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 #include "core/fetch/ImageResource.h"
34 #include "core/fetch/MemoryCache.h"
35 #include "core/fetch/Resource.h"
36 #include "core/fetch/ResourceFetcher.h"
37 #include "core/fetch/ResourcePtr.h"
38 #include "core/html/HTMLDocument.h"
39 #include "core/loader/DocumentLoader.h"
40 #include "platform/network/ResourceRequest.h"
41 #include "public/platform/Platform.h"
42 #include "wtf/OwnPtr.h"
43 #include "wtf/RefPtr.h"
45 #include <gtest/gtest.h>
47 using namespace WebCore;
51 // An URL for the original request.
52 const char kResourceURL[] = "http://resource.com/";
54 // The origin time of our first request.
55 const char kOriginalRequestDateAsString[] = "Thu, 25 May 1977 18:30:00 GMT";
56 const double kOriginalRequestDateAsDouble = 233433000.;
58 const char kOneDayBeforeOriginalRequest[] = "Wed, 24 May 1977 18:30:00 GMT";
59 const char kOneDayAfterOriginalRequest[] = "Fri, 26 May 1977 18:30:00 GMT";
61 const unsigned char kAConstUnsignedCharZero = 0;
63 class CachingCorrectnessTest : public ::testing::Test {
65 void advanceClock(double seconds)
67 m_proxyPlatform.advanceClock(seconds);
70 ResourcePtr<Resource> resourceFromResourceResponse(ResourceResponse response, Resource::Type type = Resource::Raw)
72 if (response.url().isNull())
73 response.setURL(KURL(ParsedURLString, kResourceURL));
74 ResourcePtr<Resource> resource =
75 new Resource(ResourceRequest(response.url()), type);
76 resource->setResponse(response);
77 memoryCache()->add(resource.get());
82 ResourcePtr<Resource> resourceFromResourceRequest(ResourceRequest request, Resource::Type type = Resource::Raw)
84 if (request.url().isNull())
85 request.setURL(KURL(ParsedURLString, kResourceURL));
86 ResourcePtr<Resource> resource =
87 new Resource(request, type);
88 resource->setResponse(ResourceResponse(KURL(ParsedURLString, kResourceURL), "text/html", 0, nullAtom, String()));
89 memoryCache()->add(resource.get());
94 ResourcePtr<Resource> fetch()
96 FetchRequest fetchRequest(ResourceRequest(KURL(ParsedURLString, kResourceURL)), FetchInitiatorInfo());
97 return m_fetcher->fetchSynchronously(fetchRequest);
100 ResourcePtr<Resource> fetchImage()
102 FetchRequest fetchRequest(ResourceRequest(KURL(ParsedURLString, kResourceURL)), FetchInitiatorInfo());
103 return m_fetcher->fetchImage(fetchRequest);
106 ResourceFetcher* fetcher() const { return m_fetcher.get(); }
109 // A simple platform that mocks out the clock, for cache freshness testing.
110 class ProxyPlatform : public blink::Platform {
112 ProxyPlatform() : m_elapsedSeconds(0.) { }
114 void advanceClock(double seconds)
116 m_elapsedSeconds += seconds;
120 // From blink::Platform:
121 virtual double currentTime()
123 return kOriginalRequestDateAsDouble + m_elapsedSeconds;
126 // These blink::Platform methods must be overriden to make a usable object.
127 virtual void cryptographicallyRandomValues(unsigned char* buffer, size_t length) { ASSERT_NOT_REACHED(); }
128 virtual const unsigned char* getTraceCategoryEnabledFlag(const char* categoryName)
130 return &kAConstUnsignedCharZero;
133 double m_elapsedSeconds;
138 m_savedPlatform = blink::Platform::current();
139 blink::Platform::initialize(&m_proxyPlatform);
141 // Save the global memory cache to restore it upon teardown.
142 m_globalMemoryCache = adoptPtr(memoryCache());
143 // Create the test memory cache instance and hook it in.
144 m_testingMemoryCache = adoptPtr(new MemoryCache());
145 setMemoryCacheForTesting(m_testingMemoryCache.leakPtr());
147 // Create a ResourceFetcher that has a real DocumentLoader and Document, but is not attached to a LocalFrame.
148 const KURL kDocumentURL(ParsedURLString, "http://document.com/");
149 m_documentLoader = DocumentLoader::create(0, ResourceRequest(kDocumentURL), SubstituteData());
150 m_document = HTMLDocument::create();
151 m_fetcher = ResourceFetcher::create(m_documentLoader.get());
152 m_fetcher->setDocument(m_document.get());
155 virtual void TearDown()
157 memoryCache()->evictResources();
159 // Regain the ownership of testing memory cache, so that it will be
161 m_testingMemoryCache = adoptPtr(memoryCache());
163 // Yield the ownership of the global memory cache back.
164 setMemoryCacheForTesting(m_globalMemoryCache.leakPtr());
166 blink::Platform::initialize(m_savedPlatform);
169 blink::Platform* m_savedPlatform;
170 ProxyPlatform m_proxyPlatform;
172 OwnPtr<MemoryCache> m_testingMemoryCache;
173 OwnPtr<MemoryCache> m_globalMemoryCache;
175 RefPtr<DocumentLoader> m_documentLoader;
177 RefPtr<HTMLDocument> m_document;
178 RefPtrWillBePersistent<ResourceFetcher> m_fetcher;
181 TEST_F(CachingCorrectnessTest, FreshFromLastModified)
183 ResourceResponse fresh200Response;
184 fresh200Response.setHTTPStatusCode(200);
185 fresh200Response.setHTTPHeaderField("Date", kOriginalRequestDateAsString);
186 fresh200Response.setHTTPHeaderField("Last-Modified", kOneDayBeforeOriginalRequest);
188 ResourcePtr<Resource> fresh200 = resourceFromResourceResponse(fresh200Response);
190 // Advance the clock within the implicit freshness period of this resource before we make a request.
193 ResourcePtr<Resource> fetched = fetch();
194 EXPECT_EQ(fresh200, fetched);
197 TEST_F(CachingCorrectnessTest, FreshFromExpires)
199 ResourceResponse fresh200Response;
200 fresh200Response.setHTTPStatusCode(200);
201 fresh200Response.setHTTPHeaderField("Date", kOriginalRequestDateAsString);
202 fresh200Response.setHTTPHeaderField("Expires", kOneDayAfterOriginalRequest);
204 ResourcePtr<Resource> fresh200 = resourceFromResourceResponse(fresh200Response);
206 // Advance the clock within the freshness period of this resource before we make a request.
207 advanceClock(24. * 60. * 60. - 15.);
209 ResourcePtr<Resource> fetched = fetch();
210 EXPECT_EQ(fresh200, fetched);
213 TEST_F(CachingCorrectnessTest, FreshFromMaxAge)
215 ResourceResponse fresh200Response;
216 fresh200Response.setHTTPStatusCode(200);
217 fresh200Response.setHTTPHeaderField("Date", kOriginalRequestDateAsString);
218 fresh200Response.setHTTPHeaderField("Cache-Control", "max-age=600");
220 ResourcePtr<Resource> fresh200 = resourceFromResourceResponse(fresh200Response);
222 // Advance the clock within the freshness period of this resource before we make a request.
225 ResourcePtr<Resource> fetched = fetch();
226 EXPECT_EQ(fresh200, fetched);
229 // The strong validator causes a revalidation to be launched, and the proxy and original resources leak because of their reference loop.
230 TEST_F(CachingCorrectnessTest, DISABLED_ExpiredFromLastModified)
232 ResourceResponse expired200Response;
233 expired200Response.setHTTPStatusCode(200);
234 expired200Response.setHTTPHeaderField("Date", kOriginalRequestDateAsString);
235 expired200Response.setHTTPHeaderField("Last-Modified", kOneDayBeforeOriginalRequest);
237 ResourcePtr<Resource> expired200 = resourceFromResourceResponse(expired200Response);
239 // Advance the clock beyond the implicit freshness period.
240 advanceClock(24. * 60. * 60. * 0.2);
242 ResourcePtr<Resource> fetched = fetch();
243 EXPECT_NE(expired200, fetched);
246 TEST_F(CachingCorrectnessTest, ExpiredFromExpires)
248 ResourceResponse expired200Response;
249 expired200Response.setHTTPStatusCode(200);
250 expired200Response.setHTTPHeaderField("Date", kOriginalRequestDateAsString);
251 expired200Response.setHTTPHeaderField("Expires", kOneDayAfterOriginalRequest);
253 ResourcePtr<Resource> expired200 = resourceFromResourceResponse(expired200Response);
255 // Advance the clock within the expiredness period of this resource before we make a request.
256 advanceClock(24. * 60. * 60. + 15.);
258 ResourcePtr<Resource> fetched = fetch();
259 EXPECT_NE(expired200, fetched);
262 // If the image hasn't been loaded in this "document" before, then it shouldn't have list of available images logic.
263 TEST_F(CachingCorrectnessTest, NewImageExpiredFromExpires)
265 ResourceResponse expired200Response;
266 expired200Response.setHTTPStatusCode(200);
267 expired200Response.setHTTPHeaderField("Date", kOriginalRequestDateAsString);
268 expired200Response.setHTTPHeaderField("Expires", kOneDayAfterOriginalRequest);
270 ResourcePtr<Resource> expired200 = resourceFromResourceResponse(expired200Response, Resource::Image);
272 // Advance the clock within the expiredness period of this resource before we make a request.
273 advanceClock(24. * 60. * 60. + 15.);
275 ResourcePtr<Resource> fetched = fetchImage();
276 EXPECT_NE(expired200, fetched);
279 // If the image has been loaded in this "document" before, then it should have list of available images logic, and so
280 // normal cache testing should be bypassed.
281 TEST_F(CachingCorrectnessTest, ReuseImageExpiredFromExpires)
283 ResourceResponse expired200Response;
284 expired200Response.setHTTPStatusCode(200);
285 expired200Response.setHTTPHeaderField("Date", kOriginalRequestDateAsString);
286 expired200Response.setHTTPHeaderField("Expires", kOneDayAfterOriginalRequest);
288 ResourcePtr<Resource> expired200 = resourceFromResourceResponse(expired200Response, Resource::Image);
290 // Advance the clock within the freshness period, and make a request to add this image to the document resources.
292 ResourcePtr<Resource> firstFetched = fetchImage();
293 EXPECT_EQ(expired200, firstFetched);
295 // Advance the clock within the expiredness period of this resource before we make a request.
296 advanceClock(24. * 60. * 60. + 15.);
298 ResourcePtr<Resource> fetched = fetchImage();
299 EXPECT_EQ(expired200, fetched);
302 TEST_F(CachingCorrectnessTest, ExpiredFromMaxAge)
304 ResourceResponse expired200Response;
305 expired200Response.setHTTPStatusCode(200);
306 expired200Response.setHTTPHeaderField("Date", kOriginalRequestDateAsString);
307 expired200Response.setHTTPHeaderField("Cache-Control", "max-age=600");
309 ResourcePtr<Resource> expired200 = resourceFromResourceResponse(expired200Response);
311 // Advance the clock within the expiredness period of this resource before we make a request.
314 ResourcePtr<Resource> fetched = fetch();
315 EXPECT_NE(expired200, fetched);
318 TEST_F(CachingCorrectnessTest, FreshButNoCache)
320 ResourceResponse fresh200NocacheResponse;
321 fresh200NocacheResponse.setHTTPStatusCode(200);
322 fresh200NocacheResponse.setHTTPHeaderField("Date", kOriginalRequestDateAsString);
323 fresh200NocacheResponse.setHTTPHeaderField("Expires", kOneDayAfterOriginalRequest);
324 fresh200NocacheResponse.setHTTPHeaderField("Cache-Control", "no-cache");
326 ResourcePtr<Resource> fresh200Nocache = resourceFromResourceResponse(fresh200NocacheResponse);
328 // Advance the clock within the freshness period of this resource before we make a request.
329 advanceClock(24. * 60. * 60. - 15.);
331 ResourcePtr<Resource> fetched = fetch();
332 EXPECT_NE(fresh200Nocache, fetched);
335 TEST_F(CachingCorrectnessTest, RequestWithNoCahe)
337 ResourceRequest noCacheRequest;
338 noCacheRequest.setHTTPHeaderField("Cache-Control", "no-cache");
339 ResourcePtr<Resource> noCacheResource = resourceFromResourceRequest(noCacheRequest);
340 ResourcePtr<Resource> fetched = fetch();
341 EXPECT_NE(noCacheResource, fetched);
344 TEST_F(CachingCorrectnessTest, FreshButNoStore)
346 ResourceResponse fresh200NostoreResponse;
347 fresh200NostoreResponse.setHTTPStatusCode(200);
348 fresh200NostoreResponse.setHTTPHeaderField("Date", kOriginalRequestDateAsString);
349 fresh200NostoreResponse.setHTTPHeaderField("Expires", kOneDayAfterOriginalRequest);
350 fresh200NostoreResponse.setHTTPHeaderField("Cache-Control", "no-store");
352 ResourcePtr<Resource> fresh200Nostore = resourceFromResourceResponse(fresh200NostoreResponse);
354 // Advance the clock within the freshness period of this resource before we make a request.
355 advanceClock(24. * 60. * 60. - 15.);
357 ResourcePtr<Resource> fetched = fetch();
358 EXPECT_NE(fresh200Nostore, fetched);
361 TEST_F(CachingCorrectnessTest, RequestWithNoStore)
363 ResourceRequest noStoreRequest;
364 noStoreRequest.setHTTPHeaderField("Cache-Control", "no-store");
365 ResourcePtr<Resource> noStoreResource = resourceFromResourceRequest(noStoreRequest);
366 ResourcePtr<Resource> fetched = fetch();
367 EXPECT_NE(noStoreResource, fetched);
370 // FIXME: Determine if ignoring must-revalidate for blink is correct behaviour.
371 // See crbug.com/340088 .
372 TEST_F(CachingCorrectnessTest, DISABLED_FreshButMustRevalidate)
374 ResourceResponse fresh200MustRevalidateResponse;
375 fresh200MustRevalidateResponse.setHTTPStatusCode(200);
376 fresh200MustRevalidateResponse.setHTTPHeaderField("Date", kOriginalRequestDateAsString);
377 fresh200MustRevalidateResponse.setHTTPHeaderField("Expires", kOneDayAfterOriginalRequest);
378 fresh200MustRevalidateResponse.setHTTPHeaderField("Cache-Control", "must-revalidate");
380 ResourcePtr<Resource> fresh200MustRevalidate = resourceFromResourceResponse(fresh200MustRevalidateResponse);
382 // Advance the clock within the freshness period of this resource before we make a request.
383 advanceClock(24. * 60. * 60. - 15.);
385 ResourcePtr<Resource> fetched = fetch();
386 EXPECT_NE(fresh200MustRevalidate, fetched);
389 TEST_F(CachingCorrectnessTest, FreshWithFreshRedirect)
391 KURL redirectUrl(ParsedURLString, kResourceURL);
392 const char redirectTargetUrlString[] = "http://redirect-target.com";
393 KURL redirectTargetUrl(ParsedURLString, redirectTargetUrlString);
395 ResourcePtr<Resource> firstResource = new Resource(ResourceRequest(redirectUrl), Resource::Raw);
397 ResourceResponse fresh301Response;
398 fresh301Response.setURL(redirectUrl);
399 fresh301Response.setHTTPStatusCode(301);
400 fresh301Response.setHTTPHeaderField("Date", kOriginalRequestDateAsString);
401 fresh301Response.setHTTPHeaderField("Location", redirectTargetUrlString);
402 fresh301Response.setHTTPHeaderField("Cache-Control", "max-age=600");
404 // Add the redirect to our request.
405 ResourceRequest redirectRequest = ResourceRequest(redirectTargetUrl);
406 firstResource->willSendRequest(redirectRequest, fresh301Response);
408 // Add the final response to our request.
409 ResourceResponse fresh200Response;
410 fresh200Response.setURL(redirectTargetUrl);
411 fresh200Response.setHTTPStatusCode(200);
412 fresh200Response.setHTTPHeaderField("Date", kOriginalRequestDateAsString);
413 fresh200Response.setHTTPHeaderField("Expires", kOneDayAfterOriginalRequest);
415 firstResource->setResponse(fresh200Response);
416 memoryCache()->add(firstResource.get());
420 ResourcePtr<Resource> fetched = fetch();
421 EXPECT_EQ(firstResource, fetched);
424 TEST_F(CachingCorrectnessTest, FreshWithStaleRedirect)
426 KURL redirectUrl(ParsedURLString, kResourceURL);
427 const char redirectTargetUrlString[] = "http://redirect-target.com";
428 KURL redirectTargetUrl(ParsedURLString, redirectTargetUrlString);
430 ResourcePtr<Resource> firstResource = new Resource(ResourceRequest(redirectUrl), Resource::Raw);
432 ResourceResponse stale301Response;
433 stale301Response.setURL(redirectUrl);
434 stale301Response.setHTTPStatusCode(301);
435 stale301Response.setHTTPHeaderField("Date", kOriginalRequestDateAsString);
436 stale301Response.setHTTPHeaderField("Location", redirectTargetUrlString);
438 // Add the redirect to our request.
439 ResourceRequest redirectRequest = ResourceRequest(redirectTargetUrl);
440 firstResource->willSendRequest(redirectRequest, stale301Response);
442 // Add the final response to our request.
443 ResourceResponse fresh200Response;
444 fresh200Response.setURL(redirectTargetUrl);
445 fresh200Response.setHTTPStatusCode(200);
446 fresh200Response.setHTTPHeaderField("Date", kOriginalRequestDateAsString);
447 fresh200Response.setHTTPHeaderField("Expires", kOneDayAfterOriginalRequest);
449 firstResource->setResponse(fresh200Response);
450 memoryCache()->add(firstResource.get());
454 ResourcePtr<Resource> fetched = fetch();
455 EXPECT_NE(firstResource, fetched);
458 TEST_F(CachingCorrectnessTest, PostToSameURLTwice)
460 ResourceRequest request1(KURL(ParsedURLString, kResourceURL));
461 request1.setHTTPMethod("POST");
462 ResourcePtr<Resource> resource1 = new Resource(ResourceRequest(request1.url()), Resource::Raw);
463 resource1->setLoading(true);
464 memoryCache()->add(resource1.get());
466 ResourceRequest request2(KURL(ParsedURLString, kResourceURL));
467 request2.setHTTPMethod("POST");
468 FetchRequest fetch2(request2, FetchInitiatorInfo());
469 ResourcePtr<Resource> resource2 = fetcher()->fetchSynchronously(fetch2);
471 EXPECT_EQ(resource2, memoryCache()->resourceForURL(request2.url()));
472 EXPECT_NE(resource1, resource2);
475 TEST_F(CachingCorrectnessTest, 302RedirectNotImplicitlyFresh)
477 KURL redirectUrl(ParsedURLString, kResourceURL);
478 const char redirectTargetUrlString[] = "http://redirect-target.com";
479 KURL redirectTargetUrl(ParsedURLString, redirectTargetUrlString);
481 ResourcePtr<Resource> firstResource = new Resource(ResourceRequest(redirectUrl), Resource::Raw);
483 ResourceResponse fresh302Response;
484 fresh302Response.setURL(redirectUrl);
485 fresh302Response.setHTTPStatusCode(302);
486 fresh302Response.setHTTPHeaderField("Date", kOriginalRequestDateAsString);
487 fresh302Response.setHTTPHeaderField("Last-Modified", kOneDayBeforeOriginalRequest);
488 fresh302Response.setHTTPHeaderField("Location", redirectTargetUrlString);
490 // Add the redirect to our request.
491 ResourceRequest redirectRequest = ResourceRequest(redirectTargetUrl);
492 firstResource->willSendRequest(redirectRequest, fresh302Response);
494 // Add the final response to our request.
495 ResourceResponse fresh200Response;
496 fresh200Response.setURL(redirectTargetUrl);
497 fresh200Response.setHTTPStatusCode(200);
498 fresh200Response.setHTTPHeaderField("Date", kOriginalRequestDateAsString);
499 fresh200Response.setHTTPHeaderField("Expires", kOneDayAfterOriginalRequest);
501 firstResource->setResponse(fresh200Response);
502 memoryCache()->add(firstResource.get());
506 ResourcePtr<Resource> fetched = fetch();
507 EXPECT_NE(firstResource, fetched);
510 TEST_F(CachingCorrectnessTest, 302RedirectExplicitlyFreshMaxAge)
512 KURL redirectUrl(ParsedURLString, kResourceURL);
513 const char redirectTargetUrlString[] = "http://redirect-target.com";
514 KURL redirectTargetUrl(ParsedURLString, redirectTargetUrlString);
516 ResourcePtr<Resource> firstResource = new Resource(ResourceRequest(redirectUrl), Resource::Raw);
518 ResourceResponse fresh302Response;
519 fresh302Response.setURL(redirectUrl);
520 fresh302Response.setHTTPStatusCode(302);
521 fresh302Response.setHTTPHeaderField("Date", kOriginalRequestDateAsString);
522 fresh302Response.setHTTPHeaderField("Cache-Control", "max-age=600");
523 fresh302Response.setHTTPHeaderField("Location", redirectTargetUrlString);
525 // Add the redirect to our request.
526 ResourceRequest redirectRequest = ResourceRequest(redirectTargetUrl);
527 firstResource->willSendRequest(redirectRequest, fresh302Response);
529 // Add the final response to our request.
530 ResourceResponse fresh200Response;
531 fresh200Response.setURL(redirectTargetUrl);
532 fresh200Response.setHTTPStatusCode(200);
533 fresh200Response.setHTTPHeaderField("Date", kOriginalRequestDateAsString);
534 fresh200Response.setHTTPHeaderField("Expires", kOneDayAfterOriginalRequest);
536 firstResource->setResponse(fresh200Response);
537 memoryCache()->add(firstResource.get());
541 ResourcePtr<Resource> fetched = fetch();
542 EXPECT_EQ(firstResource, fetched);
545 TEST_F(CachingCorrectnessTest, 302RedirectExplicitlyFreshExpires)
547 KURL redirectUrl(ParsedURLString, kResourceURL);
548 const char redirectTargetUrlString[] = "http://redirect-target.com";
549 KURL redirectTargetUrl(ParsedURLString, redirectTargetUrlString);
551 ResourcePtr<Resource> firstResource = new Resource(ResourceRequest(redirectUrl), Resource::Raw);
553 ResourceResponse fresh302Response;
554 fresh302Response.setURL(redirectUrl);
555 fresh302Response.setHTTPStatusCode(302);
556 fresh302Response.setHTTPHeaderField("Date", kOriginalRequestDateAsString);
557 fresh302Response.setHTTPHeaderField("Expires", kOneDayAfterOriginalRequest);
558 fresh302Response.setHTTPHeaderField("Location", redirectTargetUrlString);
560 // Add the redirect to our request.
561 ResourceRequest redirectRequest = ResourceRequest(redirectTargetUrl);
562 firstResource->willSendRequest(redirectRequest, fresh302Response);
564 // Add the final response to our request.
565 ResourceResponse fresh200Response;
566 fresh200Response.setURL(redirectTargetUrl);
567 fresh200Response.setHTTPStatusCode(200);
568 fresh200Response.setHTTPHeaderField("Date", kOriginalRequestDateAsString);
569 fresh200Response.setHTTPHeaderField("Expires", kOneDayAfterOriginalRequest);
571 firstResource->setResponse(fresh200Response);
572 memoryCache()->add(firstResource.get());
576 ResourcePtr<Resource> fetched = fetch();
577 EXPECT_EQ(firstResource, fetched);