Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(148)

Side by Side Diff: third_party/WebKit/Source/core/fetch/RawResourceTest.cpp

Issue 2584423002: Loading: move core/fetch to platform/loader/fetch (Closed)
Patch Set: rebase Created 3 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(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),
150 m_resource(resource),
151 m_removeClientTimer(this, &AddingClient::removeClient) {}
152
153 ~AddingClient() override {}
154
155 // ResourceClient implementation.
156 void notifyFinished(Resource* resource) override {
157 // First schedule an asynchronous task to remove the client.
158 // We do not expect the client to be called.
159 m_removeClientTimer.startOneShot(0, BLINK_FROM_HERE);
160 resource->addClient(m_dummyClient);
161 }
162 String debugName() const override { return "AddingClient"; }
163
164 void removeClient(TimerBase* timer) {
165 m_resource->removeClient(m_dummyClient);
166 }
167
168 DEFINE_INLINE_VIRTUAL_TRACE() {
169 visitor->trace(m_dummyClient);
170 visitor->trace(m_resource);
171 RawResourceClient::trace(visitor);
172 }
173
174 private:
175 Member<DummyClient> m_dummyClient;
176 Member<Resource> m_resource;
177 Timer<AddingClient> m_removeClientTimer;
178 };
179
180 TEST(RawResourceTest, RevalidationSucceeded) {
181 Resource* resource =
182 RawResource::create(ResourceRequest("data:text/html,"), Resource::Raw);
183 ResourceResponse response;
184 response.setHTTPStatusCode(200);
185 resource->responseReceived(response, nullptr);
186 const char data[5] = "abcd";
187 resource->appendData(data, 4);
188 resource->finish();
189 memoryCache()->add(resource);
190
191 // Simulate a successful revalidation.
192 resource->setRevalidatingRequest(ResourceRequest("data:text/html,"));
193
194 Persistent<DummyClient> client = new DummyClient;
195 resource->addClient(client);
196
197 ResourceResponse revalidatingResponse;
198 revalidatingResponse.setHTTPStatusCode(304);
199 resource->responseReceived(revalidatingResponse, nullptr);
200 EXPECT_FALSE(resource->isCacheValidator());
201 EXPECT_EQ(200, resource->response().httpStatusCode());
202 EXPECT_EQ(4u, resource->resourceBuffer()->size());
203 EXPECT_EQ(resource, memoryCache()->resourceForURL(
204 KURL(ParsedURLString, "data:text/html,")));
205 memoryCache()->remove(resource);
206
207 resource->removeClient(client);
208 EXPECT_FALSE(resource->isAlive());
209 EXPECT_FALSE(client->called());
210 EXPECT_EQ("abcd", String(client->data().data(), client->data().size()));
211 }
212
213 TEST(RawResourceTest, RevalidationSucceededForResourceWithoutBody) {
214 Resource* resource =
215 RawResource::create(ResourceRequest("data:text/html,"), Resource::Raw);
216 ResourceResponse response;
217 response.setHTTPStatusCode(200);
218 resource->responseReceived(response, nullptr);
219 resource->finish();
220 memoryCache()->add(resource);
221
222 // Simulate a successful revalidation.
223 resource->setRevalidatingRequest(ResourceRequest("data:text/html,"));
224
225 Persistent<DummyClient> client = new DummyClient;
226 resource->addClient(client);
227
228 ResourceResponse revalidatingResponse;
229 revalidatingResponse.setHTTPStatusCode(304);
230 resource->responseReceived(revalidatingResponse, nullptr);
231 EXPECT_FALSE(resource->isCacheValidator());
232 EXPECT_EQ(200, resource->response().httpStatusCode());
233 EXPECT_FALSE(resource->resourceBuffer());
234 EXPECT_EQ(resource, memoryCache()->resourceForURL(
235 KURL(ParsedURLString, "data:text/html,")));
236 memoryCache()->remove(resource);
237
238 resource->removeClient(client);
239 EXPECT_FALSE(resource->isAlive());
240 EXPECT_FALSE(client->called());
241 EXPECT_EQ(0u, client->data().size());
242 }
243
244 TEST(RawResourceTest, RevalidationSucceededUpdateHeaders) {
245 Resource* resource =
246 RawResource::create(ResourceRequest("data:text/html,"), Resource::Raw);
247 ResourceResponse response;
248 response.setHTTPStatusCode(200);
249 response.addHTTPHeaderField("keep-alive", "keep-alive value");
250 response.addHTTPHeaderField("expires", "expires value");
251 response.addHTTPHeaderField("last-modified", "last-modified value");
252 response.addHTTPHeaderField("proxy-authenticate", "proxy-authenticate value");
253 response.addHTTPHeaderField("proxy-connection", "proxy-connection value");
254 response.addHTTPHeaderField("x-custom", "custom value");
255 resource->responseReceived(response, nullptr);
256 resource->finish();
257 memoryCache()->add(resource);
258
259 // Simulate a successful revalidation.
260 resource->setRevalidatingRequest(ResourceRequest("data:text/html,"));
261
262 // Validate that these headers pre-update.
263 EXPECT_EQ("keep-alive value",
264 resource->response().httpHeaderField("keep-alive"));
265 EXPECT_EQ("expires value", resource->response().httpHeaderField("expires"));
266 EXPECT_EQ("last-modified value",
267 resource->response().httpHeaderField("last-modified"));
268 EXPECT_EQ("proxy-authenticate value",
269 resource->response().httpHeaderField("proxy-authenticate"));
270 EXPECT_EQ("proxy-authenticate value",
271 resource->response().httpHeaderField("proxy-authenticate"));
272 EXPECT_EQ("proxy-connection value",
273 resource->response().httpHeaderField("proxy-connection"));
274 EXPECT_EQ("custom value", resource->response().httpHeaderField("x-custom"));
275
276 Persistent<DummyClient> client = new DummyClient;
277 resource->addClient(client.get());
278
279 // Perform a revalidation step.
280 ResourceResponse revalidatingResponse;
281 revalidatingResponse.setHTTPStatusCode(304);
282 // Headers that aren't copied with an 304 code.
283 revalidatingResponse.addHTTPHeaderField("keep-alive", "garbage");
284 revalidatingResponse.addHTTPHeaderField("expires", "garbage");
285 revalidatingResponse.addHTTPHeaderField("last-modified", "garbage");
286 revalidatingResponse.addHTTPHeaderField("proxy-authenticate", "garbage");
287 revalidatingResponse.addHTTPHeaderField("proxy-connection", "garbage");
288 // Header that is updated with 304 code.
289 revalidatingResponse.addHTTPHeaderField("x-custom", "updated");
290 resource->responseReceived(revalidatingResponse, nullptr);
291
292 // Validate the original response.
293 EXPECT_EQ(200, resource->response().httpStatusCode());
294
295 // Validate that these headers are not updated.
296 EXPECT_EQ("keep-alive value",
297 resource->response().httpHeaderField("keep-alive"));
298 EXPECT_EQ("expires value", resource->response().httpHeaderField("expires"));
299 EXPECT_EQ("last-modified value",
300 resource->response().httpHeaderField("last-modified"));
301 EXPECT_EQ("proxy-authenticate value",
302 resource->response().httpHeaderField("proxy-authenticate"));
303 EXPECT_EQ("proxy-authenticate value",
304 resource->response().httpHeaderField("proxy-authenticate"));
305 EXPECT_EQ("proxy-connection value",
306 resource->response().httpHeaderField("proxy-connection"));
307 EXPECT_EQ("updated", resource->response().httpHeaderField("x-custom"));
308
309 memoryCache()->remove(resource);
310
311 resource->removeClient(client);
312 EXPECT_FALSE(resource->isAlive());
313 EXPECT_FALSE(client->called());
314 EXPECT_EQ(0u, client->data().size());
315 }
316
317 TEST(RawResourceTest, RedirectDuringRevalidation) {
318 Resource* resource = RawResource::create(
319 ResourceRequest("https://example.com/1"), Resource::Raw);
320 ResourceResponse response;
321 response.setURL(KURL(ParsedURLString, "https://example.com/1"));
322 response.setHTTPStatusCode(200);
323 resource->responseReceived(response, nullptr);
324 const char data[5] = "abcd";
325 resource->appendData(data, 4);
326 resource->finish();
327 memoryCache()->add(resource);
328
329 EXPECT_FALSE(resource->isCacheValidator());
330 EXPECT_EQ("https://example.com/1",
331 resource->resourceRequest().url().getString());
332 EXPECT_EQ("https://example.com/1",
333 resource->lastResourceRequest().url().getString());
334
335 // Simulate a revalidation.
336 resource->setRevalidatingRequest(ResourceRequest("https://example.com/1"));
337 EXPECT_TRUE(resource->isCacheValidator());
338 EXPECT_EQ("https://example.com/1",
339 resource->resourceRequest().url().getString());
340 EXPECT_EQ("https://example.com/1",
341 resource->lastResourceRequest().url().getString());
342
343 Persistent<DummyClient> client = new DummyClient;
344 resource->addClient(client);
345
346 // The revalidating request is redirected.
347 ResourceResponse redirectResponse;
348 redirectResponse.setURL(KURL(ParsedURLString, "https://example.com/1"));
349 redirectResponse.setHTTPHeaderField("location", "https://example.com/2");
350 redirectResponse.setHTTPStatusCode(308);
351 ResourceRequest redirectedRevalidatingRequest("https://example.com/2");
352 resource->willFollowRedirect(redirectedRevalidatingRequest, redirectResponse);
353 EXPECT_FALSE(resource->isCacheValidator());
354 EXPECT_EQ("https://example.com/1",
355 resource->resourceRequest().url().getString());
356 EXPECT_EQ("https://example.com/2",
357 resource->lastResourceRequest().url().getString());
358
359 // The final response is received.
360 ResourceResponse revalidatingResponse;
361 revalidatingResponse.setURL(KURL(ParsedURLString, "https://example.com/2"));
362 revalidatingResponse.setHTTPStatusCode(200);
363 resource->responseReceived(revalidatingResponse, nullptr);
364 const char data2[4] = "xyz";
365 resource->appendData(data2, 3);
366 resource->finish();
367 EXPECT_FALSE(resource->isCacheValidator());
368 EXPECT_EQ("https://example.com/1",
369 resource->resourceRequest().url().getString());
370 EXPECT_EQ("https://example.com/2",
371 resource->lastResourceRequest().url().getString());
372 EXPECT_FALSE(resource->isCacheValidator());
373 EXPECT_EQ(200, resource->response().httpStatusCode());
374 EXPECT_EQ(3u, resource->resourceBuffer()->size());
375 EXPECT_EQ(resource, memoryCache()->resourceForURL(
376 KURL(ParsedURLString, "https://example.com/1")));
377
378 EXPECT_TRUE(client->called());
379 EXPECT_EQ(1, client->numberOfRedirectsReceived());
380 EXPECT_EQ("xyz", String(client->data().data(), client->data().size()));
381
382 // Test the case where a client is added after revalidation is completed.
383 Persistent<DummyClient> client2 = new DummyClient;
384 resource->addClient(client2);
385
386 // Because RawResourceClient is added asynchronously,
387 // |runPendingTasks()| is called to make |client2| to be notified.
388 testing::runPendingTasks();
389
390 EXPECT_TRUE(client2->called());
391 EXPECT_EQ(1, client2->numberOfRedirectsReceived());
392 EXPECT_EQ("xyz", String(client2->data().data(), client2->data().size()));
393
394 memoryCache()->remove(resource);
395
396 resource->removeClient(client);
397 resource->removeClient(client2);
398 EXPECT_FALSE(resource->isAlive());
399 }
400
401 TEST(RawResourceTest, AddClientDuringCallback) {
402 Resource* raw =
403 RawResource::create(ResourceRequest("data:text/html,"), Resource::Raw);
404
405 // Create a non-null response.
406 ResourceResponse response = raw->response();
407 response.setURL(KURL(ParsedURLString, "http://600.613/"));
408 raw->setResponse(response);
409 raw->finish();
410 EXPECT_FALSE(raw->response().isNull());
411
412 Persistent<DummyClient> dummyClient = new DummyClient();
413 Persistent<AddingClient> addingClient =
414 new AddingClient(dummyClient.get(), raw);
415 raw->addClient(addingClient);
416 testing::runPendingTasks();
417 raw->removeClient(addingClient);
418 EXPECT_FALSE(dummyClient->called());
419 EXPECT_FALSE(raw->isAlive());
420 }
421
422 // This client removes another client when notified.
423 class RemovingClient : public GarbageCollectedFinalized<RemovingClient>,
424 public RawResourceClient {
425 USING_GARBAGE_COLLECTED_MIXIN(RemovingClient);
426
427 public:
428 explicit RemovingClient(DummyClient* client) : m_dummyClient(client) {}
429
430 ~RemovingClient() override {}
431
432 // ResourceClient implementation.
433 void notifyFinished(Resource* resource) override {
434 resource->removeClient(m_dummyClient);
435 resource->removeClient(this);
436 }
437 String debugName() const override { return "RemovingClient"; }
438 DEFINE_INLINE_TRACE() {
439 visitor->trace(m_dummyClient);
440 RawResourceClient::trace(visitor);
441 }
442
443 private:
444 Member<DummyClient> m_dummyClient;
445 };
446
447 TEST(RawResourceTest, RemoveClientDuringCallback) {
448 Resource* raw =
449 RawResource::create(ResourceRequest("data:text/html,"), Resource::Raw);
450
451 // Create a non-null response.
452 ResourceResponse response = raw->response();
453 response.setURL(KURL(ParsedURLString, "http://600.613/"));
454 raw->setResponse(response);
455 raw->finish();
456 EXPECT_FALSE(raw->response().isNull());
457
458 Persistent<DummyClient> dummyClient = new DummyClient();
459 Persistent<RemovingClient> removingClient =
460 new RemovingClient(dummyClient.get());
461 raw->addClient(dummyClient);
462 raw->addClient(removingClient);
463 testing::runPendingTasks();
464 EXPECT_FALSE(raw->isAlive());
465 }
466
467 // ResourceClient can be added to |m_clients| asynchronously via
468 // ResourceCallback. When revalidation is started after ResourceCallback is
469 // scheduled and before it is dispatched, ResourceClient's callbacks should be
470 // called appropriately.
471 TEST(RawResourceTest, StartFailedRevalidationWhileResourceCallback) {
472 KURL url(ParsedURLString, "http://127.0.0.1:8000/foo.html");
473
474 ResourceResponse response;
475 response.setURL(url);
476 response.setHTTPStatusCode(200);
477
478 ResourceResponse newResponse;
479 newResponse.setURL(url);
480 newResponse.setHTTPStatusCode(201);
481
482 Resource* resource =
483 RawResource::create(ResourceRequest("data:text/html,"), Resource::Raw);
484 resource->responseReceived(response, nullptr);
485 resource->appendData("oldData", 8);
486 resource->finish();
487
488 InSequence s;
489 Checkpoint checkpoint;
490
491 MockRawResourceClient* client = MockRawResourceClient::create();
492
493 EXPECT_CALL(checkpoint, Call(1));
494 EXPECT_CALL(*client, responseReceivedInternal(resource, newResponse, _));
495 EXPECT_CALL(*client, dataReceived(resource, ::testing::StrEq("newData"), 8));
496
497 // Add a client. No callbacks are made here because ResourceCallback is
498 // scheduled asynchronously.
499 resource->addClient(client);
500 EXPECT_FALSE(resource->isCacheValidator());
501
502 // Start revalidation.
503 resource->setRevalidatingRequest(ResourceRequest(url));
504 EXPECT_TRUE(resource->isCacheValidator());
505
506 // Make the ResourceCallback to be dispatched.
507 testing::runPendingTasks();
508
509 checkpoint.Call(1);
510
511 resource->responseReceived(newResponse, nullptr);
512 resource->appendData("newData", 8);
513 }
514
515 TEST(RawResourceTest, StartSuccessfulRevalidationWhileResourceCallback) {
516 KURL url(ParsedURLString, "http://127.0.0.1:8000/foo.html");
517
518 ResourceResponse response;
519 response.setURL(url);
520 response.setHTTPStatusCode(200);
521
522 ResourceResponse newResponse;
523 newResponse.setURL(url);
524 newResponse.setHTTPStatusCode(304);
525
526 Resource* resource =
527 RawResource::create(ResourceRequest("data:text/html,"), Resource::Raw);
528 resource->responseReceived(response, nullptr);
529 resource->appendData("oldData", 8);
530 resource->finish();
531
532 InSequence s;
533 Checkpoint checkpoint;
534
535 MockRawResourceClient* client = MockRawResourceClient::create();
536
537 EXPECT_CALL(checkpoint, Call(1));
538 EXPECT_CALL(*client, responseReceivedInternal(resource, response, _));
539 EXPECT_CALL(*client, dataReceived(resource, ::testing::StrEq("oldData"), 8));
540
541 // Add a client. No callbacks are made here because ResourceCallback is
542 // scheduled asynchronously.
543 resource->addClient(client);
544 EXPECT_FALSE(resource->isCacheValidator());
545
546 // Start revalidation.
547 resource->setRevalidatingRequest(ResourceRequest(url));
548 EXPECT_TRUE(resource->isCacheValidator());
549
550 // Make the ResourceCallback to be dispatched.
551 testing::runPendingTasks();
552
553 checkpoint.Call(1);
554
555 resource->responseReceived(newResponse, nullptr);
556 }
557
558 TEST(RawResourceTest, CanReuseDevToolsEmulateNetworkConditionsClientIdHeader) {
559 ResourceRequest request("data:text/html,");
560 request.setHTTPHeaderField(
561 HTTPNames::X_DevTools_Emulate_Network_Conditions_Client_Id, "Foo");
562 Resource* raw = RawResource::create(request, Resource::Raw);
563 EXPECT_TRUE(raw->canReuse(ResourceRequest("data:text/html,")));
564 }
565
566 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698