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/FetchContext.h"
34 #include "core/fetch/ImageResource.h"
35 #include "core/fetch/MemoryCache.h"
36 #include "core/fetch/RawResource.h"
37 #include "core/fetch/Resource.h"
38 #include "core/fetch/ResourceFetcher.h"
39 #include "core/fetch/ResourcePtr.h"
40 #include "platform/network/ResourceRequest.h"
41 #include "public/platform/Platform.h"
42 #include "wtf/OwnPtr.h"
43 #include "wtf/RefPtr.h"
44 #include <gtest/gtest.h>
48 // An URL for the original request.
49 const char kResourceURL
[] = "http://resource.com/";
51 // The origin time of our first request.
52 const char kOriginalRequestDateAsString
[] = "Thu, 25 May 1977 18:30:00 GMT";
53 const double kOriginalRequestDateAsDouble
= 233433000.;
55 const char kOneDayBeforeOriginalRequest
[] = "Wed, 24 May 1977 18:30:00 GMT";
56 const char kOneDayAfterOriginalRequest
[] = "Fri, 26 May 1977 18:30:00 GMT";
58 const unsigned char kAConstUnsignedCharZero
= 0;
60 class MockFetchContext
: public FetchContext
{
62 static MockFetchContext
* create()
64 return new MockFetchContext
;
67 ~MockFetchContext() { }
69 bool allowImage(bool imagesEnabled
, const KURL
&) const override
{ return true; }
70 bool canRequest(Resource::Type
, const ResourceRequest
&, const KURL
&, const ResourceLoaderOptions
&, bool forPreload
, FetchRequest::OriginRestriction
) const override
{ return true; }
73 MockFetchContext() { }
76 class CachingCorrectnessTest
: public ::testing::Test
{
78 void advanceClock(double seconds
)
80 m_proxyPlatform
.advanceClock(seconds
);
83 ResourcePtr
<Resource
> resourceFromResourceResponse(ResourceResponse response
, Resource::Type type
= Resource::Raw
)
85 if (response
.url().isNull())
86 response
.setURL(KURL(ParsedURLString
, kResourceURL
));
87 ResourcePtr
<Resource
> resource
=
88 new Resource(ResourceRequest(response
.url()), type
);
89 resource
->setResponse(response
);
90 memoryCache()->add(resource
.get());
95 ResourcePtr
<Resource
> resourceFromResourceRequest(ResourceRequest request
, Resource::Type type
= Resource::Raw
)
97 if (request
.url().isNull())
98 request
.setURL(KURL(ParsedURLString
, kResourceURL
));
99 ResourcePtr
<Resource
> resource
=
100 new Resource(request
, type
);
101 resource
->setResponse(ResourceResponse(KURL(ParsedURLString
, kResourceURL
), "text/html", 0, nullAtom
, String()));
102 memoryCache()->add(resource
.get());
107 ResourcePtr
<Resource
> fetch()
109 FetchRequest
fetchRequest(ResourceRequest(KURL(ParsedURLString
, kResourceURL
)), FetchInitiatorInfo());
110 return RawResource::fetchSynchronously(fetchRequest
, fetcher());
113 ResourcePtr
<Resource
> fetchImage()
115 FetchRequest
fetchRequest(ResourceRequest(KURL(ParsedURLString
, kResourceURL
)), FetchInitiatorInfo());
116 return ImageResource::fetch(fetchRequest
, fetcher());
119 ResourceFetcher
* fetcher() const { return m_fetcher
.get(); }
122 // A simple platform that mocks out the clock, for cache freshness testing.
123 class ProxyPlatform
: public blink::Platform
{
125 ProxyPlatform() : m_platform(blink::Platform::current()), m_elapsedSeconds(0.) { }
129 blink::Platform::initialize(m_platform
);
132 void advanceClock(double seconds
)
134 m_elapsedSeconds
+= seconds
;
137 WebThread
* currentThread() override
139 return m_platform
->currentThread();
143 // From blink::Platform:
144 virtual double currentTime()
146 return kOriginalRequestDateAsDouble
+ m_elapsedSeconds
;
149 // These blink::Platform methods must be overriden to make a usable object.
150 virtual void cryptographicallyRandomValues(unsigned char* buffer
, size_t length
) { ASSERT_NOT_REACHED(); }
151 virtual const unsigned char* getTraceCategoryEnabledFlag(const char* categoryName
)
153 return &kAConstUnsignedCharZero
;
156 blink::Platform
* m_platform
; // Not owned.
157 double m_elapsedSeconds
;
162 blink::Platform::initialize(&m_proxyPlatform
);
164 // Save the global memory cache to restore it upon teardown.
165 m_globalMemoryCache
= replaceMemoryCacheForTesting(MemoryCache::create());
167 m_fetcher
= ResourceFetcher::create(MockFetchContext::create());
170 virtual void TearDown()
172 memoryCache()->evictResources();
174 // Yield the ownership of the global memory cache back.
175 replaceMemoryCacheForTesting(m_globalMemoryCache
.release());
178 ProxyPlatform m_proxyPlatform
;
180 Persistent
<MemoryCache
> m_globalMemoryCache
;
181 Persistent
<ResourceFetcher
> m_fetcher
;
184 TEST_F(CachingCorrectnessTest
, FreshFromLastModified
)
186 ResourceResponse fresh200Response
;
187 fresh200Response
.setHTTPStatusCode(200);
188 fresh200Response
.setHTTPHeaderField("Date", kOriginalRequestDateAsString
);
189 fresh200Response
.setHTTPHeaderField("Last-Modified", kOneDayBeforeOriginalRequest
);
191 ResourcePtr
<Resource
> fresh200
= resourceFromResourceResponse(fresh200Response
);
193 // Advance the clock within the implicit freshness period of this resource before we make a request.
196 ResourcePtr
<Resource
> fetched
= fetch();
197 EXPECT_EQ(fresh200
, fetched
);
200 TEST_F(CachingCorrectnessTest
, FreshFromExpires
)
202 ResourceResponse fresh200Response
;
203 fresh200Response
.setHTTPStatusCode(200);
204 fresh200Response
.setHTTPHeaderField("Date", kOriginalRequestDateAsString
);
205 fresh200Response
.setHTTPHeaderField("Expires", kOneDayAfterOriginalRequest
);
207 ResourcePtr
<Resource
> fresh200
= resourceFromResourceResponse(fresh200Response
);
209 // Advance the clock within the freshness period of this resource before we make a request.
210 advanceClock(24. * 60. * 60. - 15.);
212 ResourcePtr
<Resource
> fetched
= fetch();
213 EXPECT_EQ(fresh200
, fetched
);
216 TEST_F(CachingCorrectnessTest
, FreshFromMaxAge
)
218 ResourceResponse fresh200Response
;
219 fresh200Response
.setHTTPStatusCode(200);
220 fresh200Response
.setHTTPHeaderField("Date", kOriginalRequestDateAsString
);
221 fresh200Response
.setHTTPHeaderField("Cache-Control", "max-age=600");
223 ResourcePtr
<Resource
> fresh200
= resourceFromResourceResponse(fresh200Response
);
225 // Advance the clock within the freshness period of this resource before we make a request.
228 ResourcePtr
<Resource
> fetched
= fetch();
229 EXPECT_EQ(fresh200
, fetched
);
232 // The strong validator causes a revalidation to be launched, and the proxy and original resources leak because of their reference loop.
233 TEST_F(CachingCorrectnessTest
, DISABLED_ExpiredFromLastModified
)
235 ResourceResponse expired200Response
;
236 expired200Response
.setHTTPStatusCode(200);
237 expired200Response
.setHTTPHeaderField("Date", kOriginalRequestDateAsString
);
238 expired200Response
.setHTTPHeaderField("Last-Modified", kOneDayBeforeOriginalRequest
);
240 ResourcePtr
<Resource
> expired200
= resourceFromResourceResponse(expired200Response
);
242 // Advance the clock beyond the implicit freshness period.
243 advanceClock(24. * 60. * 60. * 0.2);
245 ResourcePtr
<Resource
> fetched
= fetch();
246 EXPECT_NE(expired200
, fetched
);
249 TEST_F(CachingCorrectnessTest
, ExpiredFromExpires
)
251 ResourceResponse expired200Response
;
252 expired200Response
.setHTTPStatusCode(200);
253 expired200Response
.setHTTPHeaderField("Date", kOriginalRequestDateAsString
);
254 expired200Response
.setHTTPHeaderField("Expires", kOneDayAfterOriginalRequest
);
256 ResourcePtr
<Resource
> expired200
= resourceFromResourceResponse(expired200Response
);
258 // Advance the clock within the expiredness period of this resource before we make a request.
259 advanceClock(24. * 60. * 60. + 15.);
261 ResourcePtr
<Resource
> fetched
= fetch();
262 EXPECT_NE(expired200
, fetched
);
265 // If the image hasn't been loaded in this "document" before, then it shouldn't have list of available images logic.
266 TEST_F(CachingCorrectnessTest
, NewImageExpiredFromExpires
)
268 ResourceResponse expired200Response
;
269 expired200Response
.setHTTPStatusCode(200);
270 expired200Response
.setHTTPHeaderField("Date", kOriginalRequestDateAsString
);
271 expired200Response
.setHTTPHeaderField("Expires", kOneDayAfterOriginalRequest
);
273 ResourcePtr
<Resource
> expired200
= resourceFromResourceResponse(expired200Response
, Resource::Image
);
275 // Advance the clock within the expiredness period of this resource before we make a request.
276 advanceClock(24. * 60. * 60. + 15.);
278 ResourcePtr
<Resource
> fetched
= fetchImage();
279 EXPECT_NE(expired200
, fetched
);
282 // If the image has been loaded in this "document" before, then it should have list of available images logic, and so
283 // normal cache testing should be bypassed.
284 TEST_F(CachingCorrectnessTest
, ReuseImageExpiredFromExpires
)
286 ResourceResponse expired200Response
;
287 expired200Response
.setHTTPStatusCode(200);
288 expired200Response
.setHTTPHeaderField("Date", kOriginalRequestDateAsString
);
289 expired200Response
.setHTTPHeaderField("Expires", kOneDayAfterOriginalRequest
);
291 ResourcePtr
<Resource
> expired200
= resourceFromResourceResponse(expired200Response
, Resource::Image
);
293 // Advance the clock within the freshness period, and make a request to add this image to the document resources.
295 ResourcePtr
<Resource
> firstFetched
= fetchImage();
296 EXPECT_EQ(expired200
, firstFetched
);
298 // Advance the clock within the expiredness period of this resource before we make a request.
299 advanceClock(24. * 60. * 60. + 15.);
301 ResourcePtr
<Resource
> fetched
= fetchImage();
302 EXPECT_EQ(expired200
, fetched
);
305 TEST_F(CachingCorrectnessTest
, ExpiredFromMaxAge
)
307 ResourceResponse expired200Response
;
308 expired200Response
.setHTTPStatusCode(200);
309 expired200Response
.setHTTPHeaderField("Date", kOriginalRequestDateAsString
);
310 expired200Response
.setHTTPHeaderField("Cache-Control", "max-age=600");
312 ResourcePtr
<Resource
> expired200
= resourceFromResourceResponse(expired200Response
);
314 // Advance the clock within the expiredness period of this resource before we make a request.
317 ResourcePtr
<Resource
> fetched
= fetch();
318 EXPECT_NE(expired200
, fetched
);
321 TEST_F(CachingCorrectnessTest
, FreshButNoCache
)
323 ResourceResponse fresh200NocacheResponse
;
324 fresh200NocacheResponse
.setHTTPStatusCode(200);
325 fresh200NocacheResponse
.setHTTPHeaderField("Date", kOriginalRequestDateAsString
);
326 fresh200NocacheResponse
.setHTTPHeaderField("Expires", kOneDayAfterOriginalRequest
);
327 fresh200NocacheResponse
.setHTTPHeaderField("Cache-Control", "no-cache");
329 ResourcePtr
<Resource
> fresh200Nocache
= resourceFromResourceResponse(fresh200NocacheResponse
);
331 // Advance the clock within the freshness period of this resource before we make a request.
332 advanceClock(24. * 60. * 60. - 15.);
334 ResourcePtr
<Resource
> fetched
= fetch();
335 EXPECT_NE(fresh200Nocache
, fetched
);
338 TEST_F(CachingCorrectnessTest
, RequestWithNoCahe
)
340 ResourceRequest noCacheRequest
;
341 noCacheRequest
.setHTTPHeaderField("Cache-Control", "no-cache");
342 ResourcePtr
<Resource
> noCacheResource
= resourceFromResourceRequest(noCacheRequest
);
343 ResourcePtr
<Resource
> fetched
= fetch();
344 EXPECT_NE(noCacheResource
, fetched
);
347 TEST_F(CachingCorrectnessTest
, FreshButNoStore
)
349 ResourceResponse fresh200NostoreResponse
;
350 fresh200NostoreResponse
.setHTTPStatusCode(200);
351 fresh200NostoreResponse
.setHTTPHeaderField("Date", kOriginalRequestDateAsString
);
352 fresh200NostoreResponse
.setHTTPHeaderField("Expires", kOneDayAfterOriginalRequest
);
353 fresh200NostoreResponse
.setHTTPHeaderField("Cache-Control", "no-store");
355 ResourcePtr
<Resource
> fresh200Nostore
= resourceFromResourceResponse(fresh200NostoreResponse
);
357 // Advance the clock within the freshness period of this resource before we make a request.
358 advanceClock(24. * 60. * 60. - 15.);
360 ResourcePtr
<Resource
> fetched
= fetch();
361 EXPECT_NE(fresh200Nostore
, fetched
);
364 TEST_F(CachingCorrectnessTest
, RequestWithNoStore
)
366 ResourceRequest noStoreRequest
;
367 noStoreRequest
.setHTTPHeaderField("Cache-Control", "no-store");
368 ResourcePtr
<Resource
> noStoreResource
= resourceFromResourceRequest(noStoreRequest
);
369 ResourcePtr
<Resource
> fetched
= fetch();
370 EXPECT_NE(noStoreResource
, fetched
);
373 // FIXME: Determine if ignoring must-revalidate for blink is correct behaviour.
374 // See crbug.com/340088 .
375 TEST_F(CachingCorrectnessTest
, DISABLED_FreshButMustRevalidate
)
377 ResourceResponse fresh200MustRevalidateResponse
;
378 fresh200MustRevalidateResponse
.setHTTPStatusCode(200);
379 fresh200MustRevalidateResponse
.setHTTPHeaderField("Date", kOriginalRequestDateAsString
);
380 fresh200MustRevalidateResponse
.setHTTPHeaderField("Expires", kOneDayAfterOriginalRequest
);
381 fresh200MustRevalidateResponse
.setHTTPHeaderField("Cache-Control", "must-revalidate");
383 ResourcePtr
<Resource
> fresh200MustRevalidate
= resourceFromResourceResponse(fresh200MustRevalidateResponse
);
385 // Advance the clock within the freshness period of this resource before we make a request.
386 advanceClock(24. * 60. * 60. - 15.);
388 ResourcePtr
<Resource
> fetched
= fetch();
389 EXPECT_NE(fresh200MustRevalidate
, fetched
);
392 TEST_F(CachingCorrectnessTest
, FreshWithFreshRedirect
)
394 KURL
redirectUrl(ParsedURLString
, kResourceURL
);
395 const char redirectTargetUrlString
[] = "http://redirect-target.com";
396 KURL
redirectTargetUrl(ParsedURLString
, redirectTargetUrlString
);
398 ResourcePtr
<Resource
> firstResource
= new Resource(ResourceRequest(redirectUrl
), Resource::Raw
);
400 ResourceResponse fresh301Response
;
401 fresh301Response
.setURL(redirectUrl
);
402 fresh301Response
.setHTTPStatusCode(301);
403 fresh301Response
.setHTTPHeaderField("Date", kOriginalRequestDateAsString
);
404 fresh301Response
.setHTTPHeaderField("Location", redirectTargetUrlString
);
405 fresh301Response
.setHTTPHeaderField("Cache-Control", "max-age=600");
407 // Add the redirect to our request.
408 ResourceRequest redirectRequest
= ResourceRequest(redirectTargetUrl
);
409 firstResource
->willFollowRedirect(redirectRequest
, fresh301Response
);
411 // Add the final response to our request.
412 ResourceResponse fresh200Response
;
413 fresh200Response
.setURL(redirectTargetUrl
);
414 fresh200Response
.setHTTPStatusCode(200);
415 fresh200Response
.setHTTPHeaderField("Date", kOriginalRequestDateAsString
);
416 fresh200Response
.setHTTPHeaderField("Expires", kOneDayAfterOriginalRequest
);
418 firstResource
->setResponse(fresh200Response
);
419 memoryCache()->add(firstResource
.get());
423 ResourcePtr
<Resource
> fetched
= fetch();
424 EXPECT_EQ(firstResource
, fetched
);
427 TEST_F(CachingCorrectnessTest
, FreshWithStaleRedirect
)
429 KURL
redirectUrl(ParsedURLString
, kResourceURL
);
430 const char redirectTargetUrlString
[] = "http://redirect-target.com";
431 KURL
redirectTargetUrl(ParsedURLString
, redirectTargetUrlString
);
433 ResourcePtr
<Resource
> firstResource
= new Resource(ResourceRequest(redirectUrl
), Resource::Raw
);
435 ResourceResponse stale301Response
;
436 stale301Response
.setURL(redirectUrl
);
437 stale301Response
.setHTTPStatusCode(301);
438 stale301Response
.setHTTPHeaderField("Date", kOriginalRequestDateAsString
);
439 stale301Response
.setHTTPHeaderField("Location", redirectTargetUrlString
);
441 // Add the redirect to our request.
442 ResourceRequest redirectRequest
= ResourceRequest(redirectTargetUrl
);
443 firstResource
->willFollowRedirect(redirectRequest
, stale301Response
);
445 // Add the final response to our request.
446 ResourceResponse fresh200Response
;
447 fresh200Response
.setURL(redirectTargetUrl
);
448 fresh200Response
.setHTTPStatusCode(200);
449 fresh200Response
.setHTTPHeaderField("Date", kOriginalRequestDateAsString
);
450 fresh200Response
.setHTTPHeaderField("Expires", kOneDayAfterOriginalRequest
);
452 firstResource
->setResponse(fresh200Response
);
453 memoryCache()->add(firstResource
.get());
457 ResourcePtr
<Resource
> fetched
= fetch();
458 EXPECT_NE(firstResource
, fetched
);
461 TEST_F(CachingCorrectnessTest
, PostToSameURLTwice
)
463 ResourceRequest
request1(KURL(ParsedURLString
, kResourceURL
));
464 request1
.setHTTPMethod("POST");
465 ResourcePtr
<Resource
> resource1
= new Resource(ResourceRequest(request1
.url()), Resource::Raw
);
466 resource1
->setLoading(true);
467 memoryCache()->add(resource1
.get());
469 ResourceRequest
request2(KURL(ParsedURLString
, kResourceURL
));
470 request2
.setHTTPMethod("POST");
471 FetchRequest
fetch2(request2
, FetchInitiatorInfo());
472 ResourcePtr
<Resource
> resource2
= RawResource::fetchSynchronously(fetch2
, fetcher());
474 EXPECT_EQ(resource2
, memoryCache()->resourceForURL(request2
.url()));
475 EXPECT_NE(resource1
, resource2
);
478 TEST_F(CachingCorrectnessTest
, 302RedirectNotImplicitlyFresh
)
480 KURL
redirectUrl(ParsedURLString
, kResourceURL
);
481 const char redirectTargetUrlString
[] = "http://redirect-target.com";
482 KURL
redirectTargetUrl(ParsedURLString
, redirectTargetUrlString
);
484 ResourcePtr
<Resource
> firstResource
= new Resource(ResourceRequest(redirectUrl
), Resource::Raw
);
486 ResourceResponse fresh302Response
;
487 fresh302Response
.setURL(redirectUrl
);
488 fresh302Response
.setHTTPStatusCode(302);
489 fresh302Response
.setHTTPHeaderField("Date", kOriginalRequestDateAsString
);
490 fresh302Response
.setHTTPHeaderField("Last-Modified", kOneDayBeforeOriginalRequest
);
491 fresh302Response
.setHTTPHeaderField("Location", redirectTargetUrlString
);
493 // Add the redirect to our request.
494 ResourceRequest redirectRequest
= ResourceRequest(redirectTargetUrl
);
495 firstResource
->willFollowRedirect(redirectRequest
, fresh302Response
);
497 // Add the final response to our request.
498 ResourceResponse fresh200Response
;
499 fresh200Response
.setURL(redirectTargetUrl
);
500 fresh200Response
.setHTTPStatusCode(200);
501 fresh200Response
.setHTTPHeaderField("Date", kOriginalRequestDateAsString
);
502 fresh200Response
.setHTTPHeaderField("Expires", kOneDayAfterOriginalRequest
);
504 firstResource
->setResponse(fresh200Response
);
505 memoryCache()->add(firstResource
.get());
509 ResourcePtr
<Resource
> fetched
= fetch();
510 EXPECT_NE(firstResource
, fetched
);
513 TEST_F(CachingCorrectnessTest
, 302RedirectExplicitlyFreshMaxAge
)
515 KURL
redirectUrl(ParsedURLString
, kResourceURL
);
516 const char redirectTargetUrlString
[] = "http://redirect-target.com";
517 KURL
redirectTargetUrl(ParsedURLString
, redirectTargetUrlString
);
519 ResourcePtr
<Resource
> firstResource
= new Resource(ResourceRequest(redirectUrl
), Resource::Raw
);
521 ResourceResponse fresh302Response
;
522 fresh302Response
.setURL(redirectUrl
);
523 fresh302Response
.setHTTPStatusCode(302);
524 fresh302Response
.setHTTPHeaderField("Date", kOriginalRequestDateAsString
);
525 fresh302Response
.setHTTPHeaderField("Cache-Control", "max-age=600");
526 fresh302Response
.setHTTPHeaderField("Location", redirectTargetUrlString
);
528 // Add the redirect to our request.
529 ResourceRequest redirectRequest
= ResourceRequest(redirectTargetUrl
);
530 firstResource
->willFollowRedirect(redirectRequest
, fresh302Response
);
532 // Add the final response to our request.
533 ResourceResponse fresh200Response
;
534 fresh200Response
.setURL(redirectTargetUrl
);
535 fresh200Response
.setHTTPStatusCode(200);
536 fresh200Response
.setHTTPHeaderField("Date", kOriginalRequestDateAsString
);
537 fresh200Response
.setHTTPHeaderField("Expires", kOneDayAfterOriginalRequest
);
539 firstResource
->setResponse(fresh200Response
);
540 memoryCache()->add(firstResource
.get());
544 ResourcePtr
<Resource
> fetched
= fetch();
545 EXPECT_EQ(firstResource
, fetched
);
548 TEST_F(CachingCorrectnessTest
, 302RedirectExplicitlyFreshExpires
)
550 KURL
redirectUrl(ParsedURLString
, kResourceURL
);
551 const char redirectTargetUrlString
[] = "http://redirect-target.com";
552 KURL
redirectTargetUrl(ParsedURLString
, redirectTargetUrlString
);
554 ResourcePtr
<Resource
> firstResource
= new Resource(ResourceRequest(redirectUrl
), Resource::Raw
);
556 ResourceResponse fresh302Response
;
557 fresh302Response
.setURL(redirectUrl
);
558 fresh302Response
.setHTTPStatusCode(302);
559 fresh302Response
.setHTTPHeaderField("Date", kOriginalRequestDateAsString
);
560 fresh302Response
.setHTTPHeaderField("Expires", kOneDayAfterOriginalRequest
);
561 fresh302Response
.setHTTPHeaderField("Location", redirectTargetUrlString
);
563 // Add the redirect to our request.
564 ResourceRequest redirectRequest
= ResourceRequest(redirectTargetUrl
);
565 firstResource
->willFollowRedirect(redirectRequest
, fresh302Response
);
567 // Add the final response to our request.
568 ResourceResponse fresh200Response
;
569 fresh200Response
.setURL(redirectTargetUrl
);
570 fresh200Response
.setHTTPStatusCode(200);
571 fresh200Response
.setHTTPHeaderField("Date", kOriginalRequestDateAsString
);
572 fresh200Response
.setHTTPHeaderField("Expires", kOneDayAfterOriginalRequest
);
574 firstResource
->setResponse(fresh200Response
);
575 memoryCache()->add(firstResource
.get());
579 ResourcePtr
<Resource
> fetched
= fetch();
580 EXPECT_EQ(firstResource
, fetched
);