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 47using namespace WebCore; 48 49namespace { 50 51// An URL for the original request. 52const char kResourceURL[] = "http://resource.com/"; 53 54// The origin time of our first request. 55const char kOriginalRequestDateAsString[] = "Thu, 25 May 1977 18:30:00 GMT"; 56const double kOriginalRequestDateAsDouble = 233433000.; 57 58const char kOneDayBeforeOriginalRequest[] = "Wed, 24 May 1977 18:30:00 GMT"; 59const char kOneDayAfterOriginalRequest[] = "Fri, 26 May 1977 18:30:00 GMT"; 60 61const unsigned char kAConstUnsignedCharZero = 0; 62 63class CachingCorrectnessTest : public ::testing::Test { 64protected: 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 108private: 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 RefPtrWillBePersistent<HTMLDocument> m_document; 178 RefPtrWillBePersistent<ResourceFetcher> m_fetcher; 179}; 180 181TEST_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 197TEST_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 213TEST_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. 230TEST_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 246TEST_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. 263TEST_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. 281TEST_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 302TEST_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 318TEST_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 335TEST_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 344TEST_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 361TEST_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 . 372TEST_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 389TEST_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 424TEST_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 458TEST_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 475TEST_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 510TEST_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 545TEST_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 581