Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / core / fetch / CachingCorrectnessTest.cpp
1 /*
2  * Copyright (c) 2014, Google Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are
6  * met:
7  *
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
13  * distribution.
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.
17  *
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.
29  */
30
31 #include "config.h"
32
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"
44
45 #include <gtest/gtest.h>
46
47 using namespace WebCore;
48
49 namespace {
50
51 // An URL for the original request.
52 const char kResourceURL[] = "http://resource.com/";
53
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.;
57
58 const char kOneDayBeforeOriginalRequest[] = "Wed, 24 May 1977 18:30:00 GMT";
59 const char kOneDayAfterOriginalRequest[] = "Fri, 26 May 1977 18:30:00 GMT";
60
61 const unsigned char kAConstUnsignedCharZero = 0;
62
63 class CachingCorrectnessTest : public ::testing::Test {
64 protected:
65     void advanceClock(double seconds)
66     {
67         m_proxyPlatform.advanceClock(seconds);
68     }
69
70     ResourcePtr<Resource> resourceFromResourceResponse(ResourceResponse response, Resource::Type type = Resource::Raw)
71     {
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());
78
79         return resource;
80     }
81
82     ResourcePtr<Resource> resourceFromResourceRequest(ResourceRequest request, Resource::Type type = Resource::Raw)
83     {
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());
90
91         return resource;
92     }
93
94     ResourcePtr<Resource> fetch()
95     {
96         FetchRequest fetchRequest(ResourceRequest(KURL(ParsedURLString, kResourceURL)), FetchInitiatorInfo());
97         return m_fetcher->fetchSynchronously(fetchRequest);
98     }
99
100     ResourcePtr<Resource> fetchImage()
101     {
102         FetchRequest fetchRequest(ResourceRequest(KURL(ParsedURLString, kResourceURL)), FetchInitiatorInfo());
103         return m_fetcher->fetchImage(fetchRequest);
104     }
105
106     ResourceFetcher* fetcher() const { return m_fetcher.get(); }
107
108 private:
109     // A simple platform that mocks out the clock, for cache freshness testing.
110     class ProxyPlatform : public blink::Platform {
111     public:
112         ProxyPlatform() : m_elapsedSeconds(0.) { }
113
114         void advanceClock(double seconds)
115         {
116             m_elapsedSeconds += seconds;
117         }
118
119     private:
120         // From blink::Platform:
121         virtual double currentTime()
122         {
123             return kOriginalRequestDateAsDouble + m_elapsedSeconds;
124         }
125
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)
129         {
130             return &kAConstUnsignedCharZero;
131         }
132
133         double m_elapsedSeconds;
134     };
135
136     virtual void SetUp()
137     {
138         m_savedPlatform = blink::Platform::current();
139         blink::Platform::initialize(&m_proxyPlatform);
140
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());
146
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());
153     }
154
155     virtual void TearDown()
156     {
157         memoryCache()->evictResources();
158
159         // Regain the ownership of testing memory cache, so that it will be
160         // destroyed.
161         m_testingMemoryCache = adoptPtr(memoryCache());
162
163         // Yield the ownership of the global memory cache back.
164         setMemoryCacheForTesting(m_globalMemoryCache.leakPtr());
165
166         blink::Platform::initialize(m_savedPlatform);
167     }
168
169     blink::Platform* m_savedPlatform;
170     ProxyPlatform m_proxyPlatform;
171
172     OwnPtr<MemoryCache> m_testingMemoryCache;
173     OwnPtr<MemoryCache> m_globalMemoryCache;
174
175     RefPtr<DocumentLoader> m_documentLoader;
176
177     RefPtr<HTMLDocument> m_document;
178     RefPtrWillBePersistent<ResourceFetcher> m_fetcher;
179 };
180
181 TEST_F(CachingCorrectnessTest, FreshFromLastModified)
182 {
183     ResourceResponse fresh200Response;
184     fresh200Response.setHTTPStatusCode(200);
185     fresh200Response.setHTTPHeaderField("Date", kOriginalRequestDateAsString);
186     fresh200Response.setHTTPHeaderField("Last-Modified", kOneDayBeforeOriginalRequest);
187
188     ResourcePtr<Resource> fresh200 = resourceFromResourceResponse(fresh200Response);
189
190     // Advance the clock within the implicit freshness period of this resource before we make a request.
191     advanceClock(600.);
192
193     ResourcePtr<Resource> fetched = fetch();
194     EXPECT_EQ(fresh200, fetched);
195 }
196
197 TEST_F(CachingCorrectnessTest, FreshFromExpires)
198 {
199     ResourceResponse fresh200Response;
200     fresh200Response.setHTTPStatusCode(200);
201     fresh200Response.setHTTPHeaderField("Date", kOriginalRequestDateAsString);
202     fresh200Response.setHTTPHeaderField("Expires", kOneDayAfterOriginalRequest);
203
204     ResourcePtr<Resource> fresh200 = resourceFromResourceResponse(fresh200Response);
205
206     // Advance the clock within the freshness period of this resource before we make a request.
207     advanceClock(24. * 60. * 60. - 15.);
208
209     ResourcePtr<Resource> fetched = fetch();
210     EXPECT_EQ(fresh200, fetched);
211 }
212
213 TEST_F(CachingCorrectnessTest, FreshFromMaxAge)
214 {
215     ResourceResponse fresh200Response;
216     fresh200Response.setHTTPStatusCode(200);
217     fresh200Response.setHTTPHeaderField("Date", kOriginalRequestDateAsString);
218     fresh200Response.setHTTPHeaderField("Cache-Control", "max-age=600");
219
220     ResourcePtr<Resource> fresh200 = resourceFromResourceResponse(fresh200Response);
221
222     // Advance the clock within the freshness period of this resource before we make a request.
223     advanceClock(500.);
224
225     ResourcePtr<Resource> fetched = fetch();
226     EXPECT_EQ(fresh200, fetched);
227 }
228
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)
231 {
232     ResourceResponse expired200Response;
233     expired200Response.setHTTPStatusCode(200);
234     expired200Response.setHTTPHeaderField("Date", kOriginalRequestDateAsString);
235     expired200Response.setHTTPHeaderField("Last-Modified", kOneDayBeforeOriginalRequest);
236
237     ResourcePtr<Resource> expired200 = resourceFromResourceResponse(expired200Response);
238
239     // Advance the clock beyond the implicit freshness period.
240     advanceClock(24. * 60. * 60. * 0.2);
241
242     ResourcePtr<Resource> fetched = fetch();
243     EXPECT_NE(expired200, fetched);
244 }
245
246 TEST_F(CachingCorrectnessTest, ExpiredFromExpires)
247 {
248     ResourceResponse expired200Response;
249     expired200Response.setHTTPStatusCode(200);
250     expired200Response.setHTTPHeaderField("Date", kOriginalRequestDateAsString);
251     expired200Response.setHTTPHeaderField("Expires", kOneDayAfterOriginalRequest);
252
253     ResourcePtr<Resource> expired200 = resourceFromResourceResponse(expired200Response);
254
255     // Advance the clock within the expiredness period of this resource before we make a request.
256     advanceClock(24. * 60. * 60. + 15.);
257
258     ResourcePtr<Resource> fetched = fetch();
259     EXPECT_NE(expired200, fetched);
260 }
261
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)
264 {
265     ResourceResponse expired200Response;
266     expired200Response.setHTTPStatusCode(200);
267     expired200Response.setHTTPHeaderField("Date", kOriginalRequestDateAsString);
268     expired200Response.setHTTPHeaderField("Expires", kOneDayAfterOriginalRequest);
269
270     ResourcePtr<Resource> expired200 = resourceFromResourceResponse(expired200Response, Resource::Image);
271
272     // Advance the clock within the expiredness period of this resource before we make a request.
273     advanceClock(24. * 60. * 60. + 15.);
274
275     ResourcePtr<Resource> fetched = fetchImage();
276     EXPECT_NE(expired200, fetched);
277 }
278
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)
282 {
283     ResourceResponse expired200Response;
284     expired200Response.setHTTPStatusCode(200);
285     expired200Response.setHTTPHeaderField("Date", kOriginalRequestDateAsString);
286     expired200Response.setHTTPHeaderField("Expires", kOneDayAfterOriginalRequest);
287
288     ResourcePtr<Resource> expired200 = resourceFromResourceResponse(expired200Response, Resource::Image);
289
290     // Advance the clock within the freshness period, and make a request to add this image to the document resources.
291     advanceClock(15.);
292     ResourcePtr<Resource> firstFetched = fetchImage();
293     EXPECT_EQ(expired200, firstFetched);
294
295     // Advance the clock within the expiredness period of this resource before we make a request.
296     advanceClock(24. * 60. * 60. + 15.);
297
298     ResourcePtr<Resource> fetched = fetchImage();
299     EXPECT_EQ(expired200, fetched);
300 }
301
302 TEST_F(CachingCorrectnessTest, ExpiredFromMaxAge)
303 {
304     ResourceResponse expired200Response;
305     expired200Response.setHTTPStatusCode(200);
306     expired200Response.setHTTPHeaderField("Date", kOriginalRequestDateAsString);
307     expired200Response.setHTTPHeaderField("Cache-Control", "max-age=600");
308
309     ResourcePtr<Resource> expired200 = resourceFromResourceResponse(expired200Response);
310
311     // Advance the clock within the expiredness period of this resource before we make a request.
312     advanceClock(700.);
313
314     ResourcePtr<Resource> fetched = fetch();
315     EXPECT_NE(expired200, fetched);
316 }
317
318 TEST_F(CachingCorrectnessTest, FreshButNoCache)
319 {
320     ResourceResponse fresh200NocacheResponse;
321     fresh200NocacheResponse.setHTTPStatusCode(200);
322     fresh200NocacheResponse.setHTTPHeaderField("Date", kOriginalRequestDateAsString);
323     fresh200NocacheResponse.setHTTPHeaderField("Expires", kOneDayAfterOriginalRequest);
324     fresh200NocacheResponse.setHTTPHeaderField("Cache-Control", "no-cache");
325
326     ResourcePtr<Resource> fresh200Nocache = resourceFromResourceResponse(fresh200NocacheResponse);
327
328     // Advance the clock within the freshness period of this resource before we make a request.
329     advanceClock(24. * 60. * 60. - 15.);
330
331     ResourcePtr<Resource> fetched = fetch();
332     EXPECT_NE(fresh200Nocache, fetched);
333 }
334
335 TEST_F(CachingCorrectnessTest, RequestWithNoCahe)
336 {
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);
342 }
343
344 TEST_F(CachingCorrectnessTest, FreshButNoStore)
345 {
346     ResourceResponse fresh200NostoreResponse;
347     fresh200NostoreResponse.setHTTPStatusCode(200);
348     fresh200NostoreResponse.setHTTPHeaderField("Date", kOriginalRequestDateAsString);
349     fresh200NostoreResponse.setHTTPHeaderField("Expires", kOneDayAfterOriginalRequest);
350     fresh200NostoreResponse.setHTTPHeaderField("Cache-Control", "no-store");
351
352     ResourcePtr<Resource> fresh200Nostore = resourceFromResourceResponse(fresh200NostoreResponse);
353
354     // Advance the clock within the freshness period of this resource before we make a request.
355     advanceClock(24. * 60. * 60. - 15.);
356
357     ResourcePtr<Resource> fetched = fetch();
358     EXPECT_NE(fresh200Nostore, fetched);
359 }
360
361 TEST_F(CachingCorrectnessTest, RequestWithNoStore)
362 {
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);
368 }
369
370 // FIXME: Determine if ignoring must-revalidate for blink is correct behaviour.
371 // See crbug.com/340088 .
372 TEST_F(CachingCorrectnessTest, DISABLED_FreshButMustRevalidate)
373 {
374     ResourceResponse fresh200MustRevalidateResponse;
375     fresh200MustRevalidateResponse.setHTTPStatusCode(200);
376     fresh200MustRevalidateResponse.setHTTPHeaderField("Date", kOriginalRequestDateAsString);
377     fresh200MustRevalidateResponse.setHTTPHeaderField("Expires", kOneDayAfterOriginalRequest);
378     fresh200MustRevalidateResponse.setHTTPHeaderField("Cache-Control", "must-revalidate");
379
380     ResourcePtr<Resource> fresh200MustRevalidate = resourceFromResourceResponse(fresh200MustRevalidateResponse);
381
382     // Advance the clock within the freshness period of this resource before we make a request.
383     advanceClock(24. * 60. * 60. - 15.);
384
385     ResourcePtr<Resource> fetched = fetch();
386     EXPECT_NE(fresh200MustRevalidate, fetched);
387 }
388
389 TEST_F(CachingCorrectnessTest, FreshWithFreshRedirect)
390 {
391     KURL redirectUrl(ParsedURLString, kResourceURL);
392     const char redirectTargetUrlString[] = "http://redirect-target.com";
393     KURL redirectTargetUrl(ParsedURLString, redirectTargetUrlString);
394
395     ResourcePtr<Resource> firstResource = new Resource(ResourceRequest(redirectUrl), Resource::Raw);
396
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");
403
404     // Add the redirect to our request.
405     ResourceRequest redirectRequest = ResourceRequest(redirectTargetUrl);
406     firstResource->willSendRequest(redirectRequest, fresh301Response);
407
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);
414
415     firstResource->setResponse(fresh200Response);
416     memoryCache()->add(firstResource.get());
417
418     advanceClock(500.);
419
420     ResourcePtr<Resource> fetched = fetch();
421     EXPECT_EQ(firstResource, fetched);
422 }
423
424 TEST_F(CachingCorrectnessTest, FreshWithStaleRedirect)
425 {
426     KURL redirectUrl(ParsedURLString, kResourceURL);
427     const char redirectTargetUrlString[] = "http://redirect-target.com";
428     KURL redirectTargetUrl(ParsedURLString, redirectTargetUrlString);
429
430     ResourcePtr<Resource> firstResource = new Resource(ResourceRequest(redirectUrl), Resource::Raw);
431
432     ResourceResponse stale301Response;
433     stale301Response.setURL(redirectUrl);
434     stale301Response.setHTTPStatusCode(301);
435     stale301Response.setHTTPHeaderField("Date", kOriginalRequestDateAsString);
436     stale301Response.setHTTPHeaderField("Location", redirectTargetUrlString);
437
438     // Add the redirect to our request.
439     ResourceRequest redirectRequest = ResourceRequest(redirectTargetUrl);
440     firstResource->willSendRequest(redirectRequest, stale301Response);
441
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);
448
449     firstResource->setResponse(fresh200Response);
450     memoryCache()->add(firstResource.get());
451
452     advanceClock(500.);
453
454     ResourcePtr<Resource> fetched = fetch();
455     EXPECT_NE(firstResource, fetched);
456 }
457
458 TEST_F(CachingCorrectnessTest, PostToSameURLTwice)
459 {
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());
465
466     ResourceRequest request2(KURL(ParsedURLString, kResourceURL));
467     request2.setHTTPMethod("POST");
468     FetchRequest fetch2(request2, FetchInitiatorInfo());
469     ResourcePtr<Resource> resource2 = fetcher()->fetchSynchronously(fetch2);
470
471     EXPECT_EQ(resource2, memoryCache()->resourceForURL(request2.url()));
472     EXPECT_NE(resource1, resource2);
473 }
474
475 TEST_F(CachingCorrectnessTest, 302RedirectNotImplicitlyFresh)
476 {
477     KURL redirectUrl(ParsedURLString, kResourceURL);
478     const char redirectTargetUrlString[] = "http://redirect-target.com";
479     KURL redirectTargetUrl(ParsedURLString, redirectTargetUrlString);
480
481     ResourcePtr<Resource> firstResource = new Resource(ResourceRequest(redirectUrl), Resource::Raw);
482
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);
489
490     // Add the redirect to our request.
491     ResourceRequest redirectRequest = ResourceRequest(redirectTargetUrl);
492     firstResource->willSendRequest(redirectRequest, fresh302Response);
493
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);
500
501     firstResource->setResponse(fresh200Response);
502     memoryCache()->add(firstResource.get());
503
504     advanceClock(500.);
505
506     ResourcePtr<Resource> fetched = fetch();
507     EXPECT_NE(firstResource, fetched);
508 }
509
510 TEST_F(CachingCorrectnessTest, 302RedirectExplicitlyFreshMaxAge)
511 {
512     KURL redirectUrl(ParsedURLString, kResourceURL);
513     const char redirectTargetUrlString[] = "http://redirect-target.com";
514     KURL redirectTargetUrl(ParsedURLString, redirectTargetUrlString);
515
516     ResourcePtr<Resource> firstResource = new Resource(ResourceRequest(redirectUrl), Resource::Raw);
517
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);
524
525     // Add the redirect to our request.
526     ResourceRequest redirectRequest = ResourceRequest(redirectTargetUrl);
527     firstResource->willSendRequest(redirectRequest, fresh302Response);
528
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);
535
536     firstResource->setResponse(fresh200Response);
537     memoryCache()->add(firstResource.get());
538
539     advanceClock(500.);
540
541     ResourcePtr<Resource> fetched = fetch();
542     EXPECT_EQ(firstResource, fetched);
543 }
544
545 TEST_F(CachingCorrectnessTest, 302RedirectExplicitlyFreshExpires)
546 {
547     KURL redirectUrl(ParsedURLString, kResourceURL);
548     const char redirectTargetUrlString[] = "http://redirect-target.com";
549     KURL redirectTargetUrl(ParsedURLString, redirectTargetUrlString);
550
551     ResourcePtr<Resource> firstResource = new Resource(ResourceRequest(redirectUrl), Resource::Raw);
552
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);
559
560     // Add the redirect to our request.
561     ResourceRequest redirectRequest = ResourceRequest(redirectTargetUrl);
562     firstResource->willSendRequest(redirectRequest, fresh302Response);
563
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);
570
571     firstResource->setResponse(fresh200Response);
572     memoryCache()->add(firstResource.get());
573
574     advanceClock(500.);
575
576     ResourcePtr<Resource> fetched = fetch();
577     EXPECT_EQ(firstResource, fetched);
578 }
579
580 } // namespace