| OLD | NEW |
| (Empty) |
| 1 /* | |
| 2 * Copyright (c) 2013, 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 "core/fetch/RawResource.h" | |
| 32 | |
| 33 #include "core/fetch/MemoryCache.h" | |
| 34 #include "core/fetch/ResourceFetcher.h" | |
| 35 #include "platform/SharedBuffer.h" | |
| 36 #include "platform/heap/Handle.h" | |
| 37 #include "platform/network/ResourceTimingInfo.h" | |
| 38 #include "platform/testing/UnitTestHelpers.h" | |
| 39 #include "public/platform/Platform.h" | |
| 40 #include "public/platform/WebScheduler.h" | |
| 41 #include "public/platform/WebThread.h" | |
| 42 #include "public/platform/WebURL.h" | |
| 43 #include "public/platform/WebURLResponse.h" | |
| 44 #include "testing/gmock/include/gmock/gmock.h" | |
| 45 #include "testing/gtest/include/gtest/gtest.h" | |
| 46 | |
| 47 namespace blink { | |
| 48 | |
| 49 using ::testing::InSequence; | |
| 50 using ::testing::_; | |
| 51 using Checkpoint = ::testing::StrictMock<::testing::MockFunction<void(int)>>; | |
| 52 | |
| 53 class MockRawResourceClient | |
| 54 : public GarbageCollectedFinalized<MockRawResourceClient>, | |
| 55 public RawResourceClient { | |
| 56 USING_GARBAGE_COLLECTED_MIXIN(MockRawResourceClient); | |
| 57 | |
| 58 public: | |
| 59 static MockRawResourceClient* create() { | |
| 60 return new ::testing::StrictMock<MockRawResourceClient>; | |
| 61 } | |
| 62 | |
| 63 MOCK_METHOD3(dataSent, | |
| 64 void(Resource*, unsigned long long, unsigned long long)); | |
| 65 MOCK_METHOD3(responseReceivedInternal, | |
| 66 void(Resource*, | |
| 67 const ResourceResponse&, | |
| 68 WebDataConsumerHandle*)); | |
| 69 MOCK_METHOD3(setSerializedCachedMetadata, | |
| 70 void(Resource*, const char*, size_t)); | |
| 71 MOCK_METHOD3(dataReceived, void(Resource*, const char*, size_t)); | |
| 72 MOCK_METHOD3(redirectReceived, | |
| 73 bool(Resource*, | |
| 74 const ResourceRequest&, | |
| 75 const ResourceResponse&)); | |
| 76 MOCK_METHOD0(redirectBlocked, void()); | |
| 77 MOCK_METHOD2(dataDownloaded, void(Resource*, int)); | |
| 78 MOCK_METHOD2(didReceiveResourceTiming, | |
| 79 void(Resource*, const ResourceTimingInfo&)); | |
| 80 | |
| 81 void responseReceived( | |
| 82 Resource* resource, | |
| 83 const ResourceResponse& response, | |
| 84 std::unique_ptr<WebDataConsumerHandle> handle) override { | |
| 85 responseReceivedInternal(resource, response, handle.get()); | |
| 86 } | |
| 87 | |
| 88 String debugName() const override { return "MockRawResourceClient"; } | |
| 89 | |
| 90 DEFINE_INLINE_VIRTUAL_TRACE() { RawResourceClient::trace(visitor); } | |
| 91 | |
| 92 protected: | |
| 93 MockRawResourceClient() = default; | |
| 94 }; | |
| 95 | |
| 96 TEST(RawResourceTest, DontIgnoreAcceptForCacheReuse) { | |
| 97 ResourceRequest jpegRequest; | |
| 98 jpegRequest.setHTTPAccept("image/jpeg"); | |
| 99 | |
| 100 RawResource* jpegResource(RawResource::create(jpegRequest, Resource::Raw)); | |
| 101 | |
| 102 ResourceRequest pngRequest; | |
| 103 pngRequest.setHTTPAccept("image/png"); | |
| 104 | |
| 105 EXPECT_FALSE(jpegResource->canReuse(pngRequest)); | |
| 106 } | |
| 107 | |
| 108 class DummyClient final : public GarbageCollectedFinalized<DummyClient>, | |
| 109 public RawResourceClient { | |
| 110 USING_GARBAGE_COLLECTED_MIXIN(DummyClient); | |
| 111 | |
| 112 public: | |
| 113 DummyClient() : m_called(false), m_numberOfRedirectsReceived(0) {} | |
| 114 ~DummyClient() override {} | |
| 115 | |
| 116 // ResourceClient implementation. | |
| 117 void notifyFinished(Resource* resource) override { m_called = true; } | |
| 118 String debugName() const override { return "DummyClient"; } | |
| 119 | |
| 120 void dataReceived(Resource*, const char* data, size_t length) override { | |
| 121 m_data.append(data, length); | |
| 122 } | |
| 123 | |
| 124 bool redirectReceived(Resource*, | |
| 125 const ResourceRequest&, | |
| 126 const ResourceResponse&) override { | |
| 127 ++m_numberOfRedirectsReceived; | |
| 128 return true; | |
| 129 } | |
| 130 | |
| 131 bool called() { return m_called; } | |
| 132 int numberOfRedirectsReceived() const { return m_numberOfRedirectsReceived; } | |
| 133 const Vector<char>& data() { return m_data; } | |
| 134 DEFINE_INLINE_TRACE() { RawResourceClient::trace(visitor); } | |
| 135 | |
| 136 private: | |
| 137 bool m_called; | |
| 138 int m_numberOfRedirectsReceived; | |
| 139 Vector<char> m_data; | |
| 140 }; | |
| 141 | |
| 142 // This client adds another client when notified. | |
| 143 class AddingClient final : public GarbageCollectedFinalized<AddingClient>, | |
| 144 public RawResourceClient { | |
| 145 USING_GARBAGE_COLLECTED_MIXIN(AddingClient); | |
| 146 | |
| 147 public: | |
| 148 AddingClient(DummyClient* client, Resource* resource) | |
| 149 : m_dummyClient(client), m_resource(resource) {} | |
| 150 | |
| 151 ~AddingClient() override {} | |
| 152 | |
| 153 // ResourceClient implementation. | |
| 154 void notifyFinished(Resource* resource) override { | |
| 155 // First schedule an asynchronous task to remove the client. | |
| 156 // We do not expect a client to be called if the client is removed before | |
| 157 // a callback invocation task queued inside addClient() is scheduled. | |
| 158 Platform::current() | |
| 159 ->currentThread() | |
| 160 ->scheduler() | |
| 161 ->loadingTaskRunner() | |
| 162 ->postTask(BLINK_FROM_HERE, WTF::bind(&AddingClient::removeClient, | |
| 163 wrapPersistent(this))); | |
| 164 resource->addClient(m_dummyClient); | |
| 165 } | |
| 166 String debugName() const override { return "AddingClient"; } | |
| 167 | |
| 168 void removeClient() { m_resource->removeClient(m_dummyClient); } | |
| 169 | |
| 170 DEFINE_INLINE_VIRTUAL_TRACE() { | |
| 171 visitor->trace(m_dummyClient); | |
| 172 visitor->trace(m_resource); | |
| 173 RawResourceClient::trace(visitor); | |
| 174 } | |
| 175 | |
| 176 private: | |
| 177 Member<DummyClient> m_dummyClient; | |
| 178 Member<Resource> m_resource; | |
| 179 }; | |
| 180 | |
| 181 TEST(RawResourceTest, RevalidationSucceeded) { | |
| 182 Resource* resource = | |
| 183 RawResource::create(ResourceRequest("data:text/html,"), Resource::Raw); | |
| 184 ResourceResponse response; | |
| 185 response.setHTTPStatusCode(200); | |
| 186 resource->responseReceived(response, nullptr); | |
| 187 const char data[5] = "abcd"; | |
| 188 resource->appendData(data, 4); | |
| 189 resource->finish(); | |
| 190 memoryCache()->add(resource); | |
| 191 | |
| 192 // Simulate a successful revalidation. | |
| 193 resource->setRevalidatingRequest(ResourceRequest("data:text/html,")); | |
| 194 | |
| 195 Persistent<DummyClient> client = new DummyClient; | |
| 196 resource->addClient(client); | |
| 197 | |
| 198 ResourceResponse revalidatingResponse; | |
| 199 revalidatingResponse.setHTTPStatusCode(304); | |
| 200 resource->responseReceived(revalidatingResponse, nullptr); | |
| 201 EXPECT_FALSE(resource->isCacheValidator()); | |
| 202 EXPECT_EQ(200, resource->response().httpStatusCode()); | |
| 203 EXPECT_EQ(4u, resource->resourceBuffer()->size()); | |
| 204 EXPECT_EQ(resource, memoryCache()->resourceForURL( | |
| 205 KURL(ParsedURLString, "data:text/html,"))); | |
| 206 memoryCache()->remove(resource); | |
| 207 | |
| 208 resource->removeClient(client); | |
| 209 EXPECT_FALSE(resource->isAlive()); | |
| 210 EXPECT_FALSE(client->called()); | |
| 211 EXPECT_EQ("abcd", String(client->data().data(), client->data().size())); | |
| 212 } | |
| 213 | |
| 214 TEST(RawResourceTest, RevalidationSucceededForResourceWithoutBody) { | |
| 215 Resource* resource = | |
| 216 RawResource::create(ResourceRequest("data:text/html,"), Resource::Raw); | |
| 217 ResourceResponse response; | |
| 218 response.setHTTPStatusCode(200); | |
| 219 resource->responseReceived(response, nullptr); | |
| 220 resource->finish(); | |
| 221 memoryCache()->add(resource); | |
| 222 | |
| 223 // Simulate a successful revalidation. | |
| 224 resource->setRevalidatingRequest(ResourceRequest("data:text/html,")); | |
| 225 | |
| 226 Persistent<DummyClient> client = new DummyClient; | |
| 227 resource->addClient(client); | |
| 228 | |
| 229 ResourceResponse revalidatingResponse; | |
| 230 revalidatingResponse.setHTTPStatusCode(304); | |
| 231 resource->responseReceived(revalidatingResponse, nullptr); | |
| 232 EXPECT_FALSE(resource->isCacheValidator()); | |
| 233 EXPECT_EQ(200, resource->response().httpStatusCode()); | |
| 234 EXPECT_FALSE(resource->resourceBuffer()); | |
| 235 EXPECT_EQ(resource, memoryCache()->resourceForURL( | |
| 236 KURL(ParsedURLString, "data:text/html,"))); | |
| 237 memoryCache()->remove(resource); | |
| 238 | |
| 239 resource->removeClient(client); | |
| 240 EXPECT_FALSE(resource->isAlive()); | |
| 241 EXPECT_FALSE(client->called()); | |
| 242 EXPECT_EQ(0u, client->data().size()); | |
| 243 } | |
| 244 | |
| 245 TEST(RawResourceTest, RevalidationSucceededUpdateHeaders) { | |
| 246 Resource* resource = | |
| 247 RawResource::create(ResourceRequest("data:text/html,"), Resource::Raw); | |
| 248 ResourceResponse response; | |
| 249 response.setHTTPStatusCode(200); | |
| 250 response.addHTTPHeaderField("keep-alive", "keep-alive value"); | |
| 251 response.addHTTPHeaderField("expires", "expires value"); | |
| 252 response.addHTTPHeaderField("last-modified", "last-modified value"); | |
| 253 response.addHTTPHeaderField("proxy-authenticate", "proxy-authenticate value"); | |
| 254 response.addHTTPHeaderField("proxy-connection", "proxy-connection value"); | |
| 255 response.addHTTPHeaderField("x-custom", "custom value"); | |
| 256 resource->responseReceived(response, nullptr); | |
| 257 resource->finish(); | |
| 258 memoryCache()->add(resource); | |
| 259 | |
| 260 // Simulate a successful revalidation. | |
| 261 resource->setRevalidatingRequest(ResourceRequest("data:text/html,")); | |
| 262 | |
| 263 // Validate that these headers pre-update. | |
| 264 EXPECT_EQ("keep-alive value", | |
| 265 resource->response().httpHeaderField("keep-alive")); | |
| 266 EXPECT_EQ("expires value", resource->response().httpHeaderField("expires")); | |
| 267 EXPECT_EQ("last-modified value", | |
| 268 resource->response().httpHeaderField("last-modified")); | |
| 269 EXPECT_EQ("proxy-authenticate value", | |
| 270 resource->response().httpHeaderField("proxy-authenticate")); | |
| 271 EXPECT_EQ("proxy-authenticate value", | |
| 272 resource->response().httpHeaderField("proxy-authenticate")); | |
| 273 EXPECT_EQ("proxy-connection value", | |
| 274 resource->response().httpHeaderField("proxy-connection")); | |
| 275 EXPECT_EQ("custom value", resource->response().httpHeaderField("x-custom")); | |
| 276 | |
| 277 Persistent<DummyClient> client = new DummyClient; | |
| 278 resource->addClient(client.get()); | |
| 279 | |
| 280 // Perform a revalidation step. | |
| 281 ResourceResponse revalidatingResponse; | |
| 282 revalidatingResponse.setHTTPStatusCode(304); | |
| 283 // Headers that aren't copied with an 304 code. | |
| 284 revalidatingResponse.addHTTPHeaderField("keep-alive", "garbage"); | |
| 285 revalidatingResponse.addHTTPHeaderField("expires", "garbage"); | |
| 286 revalidatingResponse.addHTTPHeaderField("last-modified", "garbage"); | |
| 287 revalidatingResponse.addHTTPHeaderField("proxy-authenticate", "garbage"); | |
| 288 revalidatingResponse.addHTTPHeaderField("proxy-connection", "garbage"); | |
| 289 // Header that is updated with 304 code. | |
| 290 revalidatingResponse.addHTTPHeaderField("x-custom", "updated"); | |
| 291 resource->responseReceived(revalidatingResponse, nullptr); | |
| 292 | |
| 293 // Validate the original response. | |
| 294 EXPECT_EQ(200, resource->response().httpStatusCode()); | |
| 295 | |
| 296 // Validate that these headers are not updated. | |
| 297 EXPECT_EQ("keep-alive value", | |
| 298 resource->response().httpHeaderField("keep-alive")); | |
| 299 EXPECT_EQ("expires value", resource->response().httpHeaderField("expires")); | |
| 300 EXPECT_EQ("last-modified value", | |
| 301 resource->response().httpHeaderField("last-modified")); | |
| 302 EXPECT_EQ("proxy-authenticate value", | |
| 303 resource->response().httpHeaderField("proxy-authenticate")); | |
| 304 EXPECT_EQ("proxy-authenticate value", | |
| 305 resource->response().httpHeaderField("proxy-authenticate")); | |
| 306 EXPECT_EQ("proxy-connection value", | |
| 307 resource->response().httpHeaderField("proxy-connection")); | |
| 308 EXPECT_EQ("updated", resource->response().httpHeaderField("x-custom")); | |
| 309 | |
| 310 memoryCache()->remove(resource); | |
| 311 | |
| 312 resource->removeClient(client); | |
| 313 EXPECT_FALSE(resource->isAlive()); | |
| 314 EXPECT_FALSE(client->called()); | |
| 315 EXPECT_EQ(0u, client->data().size()); | |
| 316 } | |
| 317 | |
| 318 TEST(RawResourceTest, RedirectDuringRevalidation) { | |
| 319 Resource* resource = RawResource::create( | |
| 320 ResourceRequest("https://example.com/1"), Resource::Raw); | |
| 321 ResourceResponse response; | |
| 322 response.setURL(KURL(ParsedURLString, "https://example.com/1")); | |
| 323 response.setHTTPStatusCode(200); | |
| 324 resource->responseReceived(response, nullptr); | |
| 325 const char data[5] = "abcd"; | |
| 326 resource->appendData(data, 4); | |
| 327 resource->finish(); | |
| 328 memoryCache()->add(resource); | |
| 329 | |
| 330 EXPECT_FALSE(resource->isCacheValidator()); | |
| 331 EXPECT_EQ("https://example.com/1", | |
| 332 resource->resourceRequest().url().getString()); | |
| 333 EXPECT_EQ("https://example.com/1", | |
| 334 resource->lastResourceRequest().url().getString()); | |
| 335 | |
| 336 // Simulate a revalidation. | |
| 337 resource->setRevalidatingRequest(ResourceRequest("https://example.com/1")); | |
| 338 EXPECT_TRUE(resource->isCacheValidator()); | |
| 339 EXPECT_EQ("https://example.com/1", | |
| 340 resource->resourceRequest().url().getString()); | |
| 341 EXPECT_EQ("https://example.com/1", | |
| 342 resource->lastResourceRequest().url().getString()); | |
| 343 | |
| 344 Persistent<DummyClient> client = new DummyClient; | |
| 345 resource->addClient(client); | |
| 346 | |
| 347 // The revalidating request is redirected. | |
| 348 ResourceResponse redirectResponse; | |
| 349 redirectResponse.setURL(KURL(ParsedURLString, "https://example.com/1")); | |
| 350 redirectResponse.setHTTPHeaderField("location", "https://example.com/2"); | |
| 351 redirectResponse.setHTTPStatusCode(308); | |
| 352 ResourceRequest redirectedRevalidatingRequest("https://example.com/2"); | |
| 353 resource->willFollowRedirect(redirectedRevalidatingRequest, redirectResponse); | |
| 354 EXPECT_FALSE(resource->isCacheValidator()); | |
| 355 EXPECT_EQ("https://example.com/1", | |
| 356 resource->resourceRequest().url().getString()); | |
| 357 EXPECT_EQ("https://example.com/2", | |
| 358 resource->lastResourceRequest().url().getString()); | |
| 359 | |
| 360 // The final response is received. | |
| 361 ResourceResponse revalidatingResponse; | |
| 362 revalidatingResponse.setURL(KURL(ParsedURLString, "https://example.com/2")); | |
| 363 revalidatingResponse.setHTTPStatusCode(200); | |
| 364 resource->responseReceived(revalidatingResponse, nullptr); | |
| 365 const char data2[4] = "xyz"; | |
| 366 resource->appendData(data2, 3); | |
| 367 resource->finish(); | |
| 368 EXPECT_FALSE(resource->isCacheValidator()); | |
| 369 EXPECT_EQ("https://example.com/1", | |
| 370 resource->resourceRequest().url().getString()); | |
| 371 EXPECT_EQ("https://example.com/2", | |
| 372 resource->lastResourceRequest().url().getString()); | |
| 373 EXPECT_FALSE(resource->isCacheValidator()); | |
| 374 EXPECT_EQ(200, resource->response().httpStatusCode()); | |
| 375 EXPECT_EQ(3u, resource->resourceBuffer()->size()); | |
| 376 EXPECT_EQ(resource, memoryCache()->resourceForURL( | |
| 377 KURL(ParsedURLString, "https://example.com/1"))); | |
| 378 | |
| 379 EXPECT_TRUE(client->called()); | |
| 380 EXPECT_EQ(1, client->numberOfRedirectsReceived()); | |
| 381 EXPECT_EQ("xyz", String(client->data().data(), client->data().size())); | |
| 382 | |
| 383 // Test the case where a client is added after revalidation is completed. | |
| 384 Persistent<DummyClient> client2 = new DummyClient; | |
| 385 resource->addClient(client2); | |
| 386 | |
| 387 // Because RawResourceClient is added asynchronously, | |
| 388 // |runPendingTasks()| is called to make |client2| to be notified. | |
| 389 testing::runPendingTasks(); | |
| 390 | |
| 391 EXPECT_TRUE(client2->called()); | |
| 392 EXPECT_EQ(1, client2->numberOfRedirectsReceived()); | |
| 393 EXPECT_EQ("xyz", String(client2->data().data(), client2->data().size())); | |
| 394 | |
| 395 memoryCache()->remove(resource); | |
| 396 | |
| 397 resource->removeClient(client); | |
| 398 resource->removeClient(client2); | |
| 399 EXPECT_FALSE(resource->isAlive()); | |
| 400 } | |
| 401 | |
| 402 TEST(RawResourceTest, AddClientDuringCallback) { | |
| 403 Resource* raw = | |
| 404 RawResource::create(ResourceRequest("data:text/html,"), Resource::Raw); | |
| 405 | |
| 406 // Create a non-null response. | |
| 407 ResourceResponse response = raw->response(); | |
| 408 response.setURL(KURL(ParsedURLString, "http://600.613/")); | |
| 409 raw->setResponse(response); | |
| 410 raw->finish(); | |
| 411 EXPECT_FALSE(raw->response().isNull()); | |
| 412 | |
| 413 Persistent<DummyClient> dummyClient = new DummyClient(); | |
| 414 Persistent<AddingClient> addingClient = | |
| 415 new AddingClient(dummyClient.get(), raw); | |
| 416 raw->addClient(addingClient); | |
| 417 testing::runPendingTasks(); | |
| 418 raw->removeClient(addingClient); | |
| 419 EXPECT_FALSE(dummyClient->called()); | |
| 420 EXPECT_FALSE(raw->isAlive()); | |
| 421 } | |
| 422 | |
| 423 // This client removes another client when notified. | |
| 424 class RemovingClient : public GarbageCollectedFinalized<RemovingClient>, | |
| 425 public RawResourceClient { | |
| 426 USING_GARBAGE_COLLECTED_MIXIN(RemovingClient); | |
| 427 | |
| 428 public: | |
| 429 explicit RemovingClient(DummyClient* client) : m_dummyClient(client) {} | |
| 430 | |
| 431 ~RemovingClient() override {} | |
| 432 | |
| 433 // ResourceClient implementation. | |
| 434 void notifyFinished(Resource* resource) override { | |
| 435 resource->removeClient(m_dummyClient); | |
| 436 resource->removeClient(this); | |
| 437 } | |
| 438 String debugName() const override { return "RemovingClient"; } | |
| 439 DEFINE_INLINE_TRACE() { | |
| 440 visitor->trace(m_dummyClient); | |
| 441 RawResourceClient::trace(visitor); | |
| 442 } | |
| 443 | |
| 444 private: | |
| 445 Member<DummyClient> m_dummyClient; | |
| 446 }; | |
| 447 | |
| 448 TEST(RawResourceTest, RemoveClientDuringCallback) { | |
| 449 Resource* raw = | |
| 450 RawResource::create(ResourceRequest("data:text/html,"), Resource::Raw); | |
| 451 | |
| 452 // Create a non-null response. | |
| 453 ResourceResponse response = raw->response(); | |
| 454 response.setURL(KURL(ParsedURLString, "http://600.613/")); | |
| 455 raw->setResponse(response); | |
| 456 raw->finish(); | |
| 457 EXPECT_FALSE(raw->response().isNull()); | |
| 458 | |
| 459 Persistent<DummyClient> dummyClient = new DummyClient(); | |
| 460 Persistent<RemovingClient> removingClient = | |
| 461 new RemovingClient(dummyClient.get()); | |
| 462 raw->addClient(dummyClient); | |
| 463 raw->addClient(removingClient); | |
| 464 testing::runPendingTasks(); | |
| 465 EXPECT_FALSE(raw->isAlive()); | |
| 466 } | |
| 467 | |
| 468 // ResourceClient can be added to |m_clients| asynchronously via | |
| 469 // ResourceCallback. When revalidation is started after ResourceCallback is | |
| 470 // scheduled and before it is dispatched, ResourceClient's callbacks should be | |
| 471 // called appropriately. | |
| 472 TEST(RawResourceTest, StartFailedRevalidationWhileResourceCallback) { | |
| 473 KURL url(ParsedURLString, "http://127.0.0.1:8000/foo.html"); | |
| 474 | |
| 475 ResourceResponse response; | |
| 476 response.setURL(url); | |
| 477 response.setHTTPStatusCode(200); | |
| 478 | |
| 479 ResourceResponse newResponse; | |
| 480 newResponse.setURL(url); | |
| 481 newResponse.setHTTPStatusCode(201); | |
| 482 | |
| 483 Resource* resource = | |
| 484 RawResource::create(ResourceRequest("data:text/html,"), Resource::Raw); | |
| 485 resource->responseReceived(response, nullptr); | |
| 486 resource->appendData("oldData", 8); | |
| 487 resource->finish(); | |
| 488 | |
| 489 InSequence s; | |
| 490 Checkpoint checkpoint; | |
| 491 | |
| 492 MockRawResourceClient* client = MockRawResourceClient::create(); | |
| 493 | |
| 494 EXPECT_CALL(checkpoint, Call(1)); | |
| 495 EXPECT_CALL(*client, responseReceivedInternal(resource, newResponse, _)); | |
| 496 EXPECT_CALL(*client, dataReceived(resource, ::testing::StrEq("newData"), 8)); | |
| 497 | |
| 498 // Add a client. No callbacks are made here because ResourceCallback is | |
| 499 // scheduled asynchronously. | |
| 500 resource->addClient(client); | |
| 501 EXPECT_FALSE(resource->isCacheValidator()); | |
| 502 | |
| 503 // Start revalidation. | |
| 504 resource->setRevalidatingRequest(ResourceRequest(url)); | |
| 505 EXPECT_TRUE(resource->isCacheValidator()); | |
| 506 | |
| 507 // Make the ResourceCallback to be dispatched. | |
| 508 testing::runPendingTasks(); | |
| 509 | |
| 510 checkpoint.Call(1); | |
| 511 | |
| 512 resource->responseReceived(newResponse, nullptr); | |
| 513 resource->appendData("newData", 8); | |
| 514 } | |
| 515 | |
| 516 TEST(RawResourceTest, StartSuccessfulRevalidationWhileResourceCallback) { | |
| 517 KURL url(ParsedURLString, "http://127.0.0.1:8000/foo.html"); | |
| 518 | |
| 519 ResourceResponse response; | |
| 520 response.setURL(url); | |
| 521 response.setHTTPStatusCode(200); | |
| 522 | |
| 523 ResourceResponse newResponse; | |
| 524 newResponse.setURL(url); | |
| 525 newResponse.setHTTPStatusCode(304); | |
| 526 | |
| 527 Resource* resource = | |
| 528 RawResource::create(ResourceRequest("data:text/html,"), Resource::Raw); | |
| 529 resource->responseReceived(response, nullptr); | |
| 530 resource->appendData("oldData", 8); | |
| 531 resource->finish(); | |
| 532 | |
| 533 InSequence s; | |
| 534 Checkpoint checkpoint; | |
| 535 | |
| 536 MockRawResourceClient* client = MockRawResourceClient::create(); | |
| 537 | |
| 538 EXPECT_CALL(checkpoint, Call(1)); | |
| 539 EXPECT_CALL(*client, responseReceivedInternal(resource, response, _)); | |
| 540 EXPECT_CALL(*client, dataReceived(resource, ::testing::StrEq("oldData"), 8)); | |
| 541 | |
| 542 // Add a client. No callbacks are made here because ResourceCallback is | |
| 543 // scheduled asynchronously. | |
| 544 resource->addClient(client); | |
| 545 EXPECT_FALSE(resource->isCacheValidator()); | |
| 546 | |
| 547 // Start revalidation. | |
| 548 resource->setRevalidatingRequest(ResourceRequest(url)); | |
| 549 EXPECT_TRUE(resource->isCacheValidator()); | |
| 550 | |
| 551 // Make the ResourceCallback to be dispatched. | |
| 552 testing::runPendingTasks(); | |
| 553 | |
| 554 checkpoint.Call(1); | |
| 555 | |
| 556 resource->responseReceived(newResponse, nullptr); | |
| 557 } | |
| 558 | |
| 559 TEST(RawResourceTest, CanReuseDevToolsEmulateNetworkConditionsClientIdHeader) { | |
| 560 ResourceRequest request("data:text/html,"); | |
| 561 request.setHTTPHeaderField( | |
| 562 HTTPNames::X_DevTools_Emulate_Network_Conditions_Client_Id, "Foo"); | |
| 563 Resource* raw = RawResource::create(request, Resource::Raw); | |
| 564 EXPECT_TRUE(raw->canReuse(ResourceRequest("data:text/html,"))); | |
| 565 } | |
| 566 | |
| 567 } // namespace blink | |
| OLD | NEW |