OLD | NEW |
---|---|
(Empty) | |
1 // Copyright 2015 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #include "content/browser/loader/async_revalidation_manager.h" | |
6 | |
7 #include <queue> | |
8 #include <set> | |
9 | |
10 #include "base/bind.h" | |
11 #include "base/callback.h" | |
12 #include "base/macros.h" | |
13 #include "base/memory/shared_memory_handle.h" | |
14 #include "base/pickle.h" | |
15 #include "base/run_loop.h" | |
16 #include "content/browser/child_process_security_policy_impl.h" | |
17 #include "content/browser/loader/resource_dispatcher_host_impl.h" | |
18 #include "content/browser/loader/resource_message_filter.h" | |
19 #include "content/common/child_process_host_impl.h" | |
20 #include "content/common/resource_messages.h" | |
21 #include "content/public/browser/resource_context.h" | |
22 #include "content/public/common/appcache_info.h" | |
23 #include "content/public/common/process_type.h" | |
24 #include "content/public/common/resource_type.h" | |
25 #include "content/public/test/test_browser_context.h" | |
26 #include "content/public/test/test_browser_thread_bundle.h" | |
27 #include "ipc/ipc_param_traits.h" | |
28 #include "net/base/load_flags.h" | |
29 #include "net/base/network_delegate.h" | |
30 #include "net/http/http_util.h" | |
31 #include "net/url_request/url_request.h" | |
32 #include "net/url_request/url_request_job.h" | |
33 #include "net/url_request/url_request_job_factory.h" | |
34 #include "net/url_request/url_request_test_job.h" | |
35 #include "net/url_request/url_request_test_util.h" | |
36 #include "testing/gtest/include/gtest/gtest.h" | |
37 #include "ui/base/page_transition_types.h" | |
38 #include "url/gurl.h" | |
39 | |
40 namespace content { | |
41 | |
42 namespace { | |
43 | |
44 class TestURLRequestJobFactory : public net::URLRequestJobFactory { | |
45 public: | |
46 TestURLRequestJobFactory() = default; | |
47 | |
48 void HandleScheme(const std::string& scheme) { | |
49 supported_schemes_.insert(scheme); | |
50 } | |
51 | |
52 // Sets the contents of the response. |headers| should have "\n" as line | |
53 // breaks and end in "\n\n". | |
54 void SetResponse(const std::string& headers, const std::string& data) { | |
55 response_headers_ = | |
56 net::HttpUtil::AssembleRawHeaders(headers.data(), headers.size()); | |
57 response_data_ = data; | |
58 } | |
59 | |
60 typedef base::Callback<net::URLRequestJob*(net::URLRequest*, | |
Bence
2015/11/17 13:12:23
Use "using" instead of "typedef", see https://chro
Adam Rice
2015/11/17 17:45:53
Done.
| |
61 net::NetworkDelegate*)> | |
62 URLRequestJobCreateCallback; | |
63 | |
64 void SetCustomURLRequestJobCreateCallback( | |
65 const URLRequestJobCreateCallback& callback) { | |
66 custom_url_request_job_create_callback_ = callback; | |
67 } | |
68 | |
69 net::URLRequestJob* MaybeCreateJobWithProtocolHandler( | |
Bence
2015/11/17 13:12:23
Optional: feel free to inline function definition
Adam Rice
2015/11/17 17:45:53
Done.
| |
70 const std::string& scheme, | |
71 net::URLRequest* request, | |
72 net::NetworkDelegate* network_delegate) const override; | |
73 | |
74 net::URLRequestJob* MaybeInterceptRedirect( | |
75 net::URLRequest* request, | |
76 net::NetworkDelegate* network_delegate, | |
77 const GURL& location) const override { | |
78 return nullptr; | |
79 } | |
80 | |
81 net::URLRequestJob* MaybeInterceptResponse( | |
82 net::URLRequest* request, | |
83 net::NetworkDelegate* network_delegate) const override { | |
84 return nullptr; | |
85 } | |
86 | |
87 bool IsHandledProtocol(const std::string& scheme) const override { | |
88 return supported_schemes_.count(scheme) > 0; | |
89 } | |
90 | |
91 bool IsHandledURL(const GURL& url) const override { | |
92 return supported_schemes_.count(url.scheme()) > 0; | |
93 } | |
94 | |
95 bool IsSafeRedirectTarget(const GURL& location) const override { | |
96 return false; | |
97 } | |
98 | |
99 private: | |
100 std::string response_headers_; | |
101 std::string response_data_; | |
102 std::set<std::string> supported_schemes_; | |
103 URLRequestJobCreateCallback custom_url_request_job_create_callback_; | |
104 | |
105 DISALLOW_COPY_AND_ASSIGN(TestURLRequestJobFactory); | |
106 }; | |
107 | |
108 // This class is a variation on URLRequestTestJob that | |
109 // returns ERR_IO_PENDING before every read, not just the first one. | |
110 class URLRequestTestDelayedCompletionJob : public net::URLRequestTestJob { | |
111 public: | |
112 URLRequestTestDelayedCompletionJob(net::URLRequest* request, | |
113 net::NetworkDelegate* network_delegate, | |
114 const std::string& response_headers, | |
115 const std::string& response_data) | |
116 : net::URLRequestTestJob(request, | |
117 network_delegate, | |
118 response_headers, | |
119 response_data, | |
120 false) {} | |
121 | |
122 private: | |
123 ~URLRequestTestDelayedCompletionJob() override {} | |
124 | |
125 bool NextReadAsync() override { return true; } | |
126 | |
127 DISALLOW_COPY_AND_ASSIGN(URLRequestTestDelayedCompletionJob); | |
128 }; | |
129 | |
130 net::URLRequestJob* TestURLRequestJobFactory::MaybeCreateJobWithProtocolHandler( | |
131 const std::string& scheme, | |
132 net::URLRequest* request, | |
133 net::NetworkDelegate* network_delegate) const { | |
134 if (!custom_url_request_job_create_callback_.is_null()) { | |
135 return custom_url_request_job_create_callback_.Run(request, | |
136 network_delegate); | |
137 } | |
138 | |
139 return new URLRequestTestDelayedCompletionJob( | |
140 request, network_delegate, response_headers_, response_data_); | |
141 } | |
142 | |
143 // On Windows, ResourceMsg_SetDataBuffer supplies a HANDLE which is not | |
144 // automatically released. | |
145 // | |
146 // See ResourceDispatcher::ReleaseResourcesInDataMessage. | |
147 // | |
148 // TODO(ricea): Maybe share this implementation with | |
149 // resource_dispatcher_host_unittest.cc | |
150 void ReleaseHandlesInMessage(const IPC::Message& message) { | |
151 if (message.type() == ResourceMsg_SetDataBuffer::ID) { | |
152 base::PickleIterator iter(message); | |
153 int request_id; | |
154 CHECK(iter.ReadInt(&request_id)); | |
155 base::SharedMemoryHandle shm_handle; | |
156 if (IPC::ParamTraits<base::SharedMemoryHandle>::Read(&message, &iter, | |
157 &shm_handle)) { | |
158 if (base::SharedMemory::IsHandleValid(shm_handle)) | |
159 base::SharedMemory::CloseHandle(shm_handle); | |
160 } | |
161 } | |
162 } | |
163 | |
164 // This filter just deletes any messages that are sent through it. | |
165 class BlackholeFilter : public ResourceMessageFilter { | |
166 public: | |
167 explicit BlackholeFilter(ResourceContext* resource_context) | |
168 : ResourceMessageFilter( | |
169 ChildProcessHostImpl::GenerateChildProcessUniqueId(), | |
170 PROCESS_TYPE_RENDERER, | |
171 NULL, | |
Bence
2015/11/17 13:12:23
Use nullptr instead of NULL.
Adam Rice
2015/11/17 17:45:53
Done.
| |
172 NULL, | |
173 NULL, | |
174 NULL, | |
175 NULL, | |
176 base::Bind(&BlackholeFilter::GetContexts, base::Unretained(this))), | |
177 resource_context_(resource_context) { | |
178 ChildProcessSecurityPolicyImpl::GetInstance()->Add(child_id()); | |
179 } | |
180 | |
181 bool Send(IPC::Message* msg) override { | |
182 ReleaseHandlesInMessage(*msg); | |
183 delete msg; | |
184 return true; | |
185 } | |
186 | |
187 private: | |
188 ~BlackholeFilter() override { | |
189 ChildProcessSecurityPolicyImpl::GetInstance()->Remove(child_id()); | |
190 } | |
191 | |
192 void GetContexts(const ResourceHostMsg_Request& request, | |
193 ResourceContext** resource_context, | |
194 net::URLRequestContext** request_context) { | |
195 *resource_context = resource_context_; | |
196 *request_context = resource_context_->GetRequestContext(); | |
197 } | |
198 | |
199 ResourceContext* resource_context_; | |
200 | |
201 DISALLOW_COPY_AND_ASSIGN(BlackholeFilter); | |
202 }; | |
203 | |
204 ResourceHostMsg_Request CreateResourceRequest(const char* method, | |
205 ResourceType type, | |
206 const GURL& url) { | |
207 ResourceHostMsg_Request request; | |
208 request.method = std::string(method); | |
209 request.url = url; | |
210 request.first_party_for_cookies = url; // bypass third-party cookie blocking | |
211 request.referrer_policy = blink::WebReferrerPolicyDefault; | |
212 request.load_flags = 0; | |
213 request.origin_pid = 0; | |
214 request.resource_type = type; | |
215 request.request_context = 0; | |
216 request.appcache_host_id = kAppCacheNoHostId; | |
217 request.download_to_file = false; | |
218 request.should_reset_appcache = false; | |
219 request.is_main_frame = true; | |
220 request.parent_is_main_frame = false; | |
221 request.parent_render_frame_id = -1; | |
222 request.transition_type = ui::PAGE_TRANSITION_LINK; | |
223 request.allow_download = true; | |
224 return request; | |
225 } | |
226 | |
227 } // namespace | |
228 | |
229 class AsyncRevalidationManagerTest : public ::testing::Test { | |
230 protected: | |
231 AsyncRevalidationManagerTest( | |
232 scoped_ptr<net::TestNetworkDelegate> network_delegate) | |
233 : thread_bundle_(content::TestBrowserThreadBundle::IO_MAINLOOP), | |
234 network_delegate_(network_delegate.Pass()) { | |
235 browser_context_.reset(new TestBrowserContext()); | |
236 BrowserContext::EnsureResourceContextInitialized(browser_context_.get()); | |
237 base::RunLoop().RunUntilIdle(); | |
238 ResourceContext* resource_context = browser_context_->GetResourceContext(); | |
239 filter_ = new BlackholeFilter(resource_context); | |
240 net::URLRequestContext* request_context = | |
241 resource_context->GetRequestContext(); | |
242 job_factory_.reset(new TestURLRequestJobFactory); | |
243 request_context->set_job_factory(job_factory_.get()); | |
244 request_context->set_network_delegate(network_delegate_.get()); | |
245 host_.EnableStaleWhileRevalidateForTesting(); | |
246 } | |
247 | |
248 AsyncRevalidationManagerTest() | |
249 : AsyncRevalidationManagerTest( | |
250 make_scoped_ptr(new net::TestNetworkDelegate)) {} | |
251 | |
252 void TearDown() override { | |
253 host_.CancelRequestsForProcess(filter_->child_id()); | |
254 host_.Shutdown(); | |
255 host_.CancelRequestsForContext(browser_context_->GetResourceContext()); | |
256 browser_context_.reset(); | |
257 base::RunLoop().RunUntilIdle(); | |
258 } | |
259 | |
260 void HandleScheme(const std::string& scheme) { | |
261 job_factory_->HandleScheme(scheme); | |
262 EnsureSchemeIsAllowed(scheme); | |
263 } | |
264 | |
265 void SetResponse(const std::string& headers, const std::string& data) { | |
266 job_factory_->SetResponse(headers, data); | |
267 } | |
268 | |
269 void SetCustomURLRequestJobCreateCallback( | |
270 const TestURLRequestJobFactory::URLRequestJobCreateCallback& callback) { | |
271 job_factory_->SetCustomURLRequestJobCreateCallback(callback); | |
272 } | |
273 | |
274 // Creates a request using the current test object as the filter and | |
275 // SubResource as the resource type. | |
276 void MakeTestRequest(int render_view_id, int request_id, const GURL& url); | |
Bence
2015/11/17 13:12:23
Optional: feel free to inline if you prefer, it sh
Adam Rice
2015/11/17 17:45:53
Done.
| |
277 | |
278 void EnsureSchemeIsAllowed(const std::string& scheme) { | |
279 ChildProcessSecurityPolicyImpl* policy = | |
280 ChildProcessSecurityPolicyImpl::GetInstance(); | |
281 if (!policy->IsWebSafeScheme(scheme)) | |
282 policy->RegisterWebSafeScheme(scheme); | |
283 } | |
284 | |
285 net::TestNetworkDelegate* network_delegate() { | |
286 return network_delegate_.get(); | |
287 } | |
288 | |
289 content::TestBrowserThreadBundle thread_bundle_; | |
290 scoped_ptr<TestBrowserContext> browser_context_; | |
291 scoped_ptr<TestURLRequestJobFactory> job_factory_; | |
292 scoped_refptr<BlackholeFilter> filter_; | |
293 scoped_ptr<net::TestNetworkDelegate> network_delegate_; | |
294 ResourceDispatcherHostImpl host_; | |
295 }; | |
296 | |
297 void AsyncRevalidationManagerTest::MakeTestRequest(int render_view_id, | |
298 int request_id, | |
299 const GURL& url) { | |
300 ResourceHostMsg_Request request = | |
301 CreateResourceRequest("GET", RESOURCE_TYPE_SUB_RESOURCE, url); | |
302 ResourceHostMsg_RequestResource msg(render_view_id, request_id, request); | |
303 host_.OnMessageReceived(msg, filter_.get()); | |
304 base::RunLoop().RunUntilIdle(); | |
305 } | |
306 | |
307 TEST_F(AsyncRevalidationManagerTest, SupportsAsyncRevalidation) { | |
308 // Scheme has to be HTTP or HTTPS to support async revalidation. | |
309 HandleScheme("http"); | |
310 SetResponse(net::URLRequestTestJob::test_headers(), "delay complete"); | |
311 MakeTestRequest(0, 1, GURL("http://example.com/baz")); | |
312 | |
313 net::URLRequest* url_request( | |
314 host_.GetURLRequest(GlobalRequestID(filter_->child_id(), 1))); | |
315 ASSERT_TRUE(url_request); | |
316 | |
317 EXPECT_TRUE(url_request->load_flags() & net::LOAD_SUPPORT_ASYNC_REVALIDATION); | |
318 } | |
319 | |
320 TEST_F(AsyncRevalidationManagerTest, AsyncRevalidationNotSupportedForPOST) { | |
321 // Scheme has to be HTTP or HTTPS to support async revalidation. | |
322 HandleScheme("http"); | |
323 SetResponse(net::URLRequestTestJob::test_headers(), "delay complete"); | |
324 // Create POST request. | |
325 ResourceHostMsg_Request request = CreateResourceRequest( | |
326 "POST", RESOURCE_TYPE_SUB_RESOURCE, GURL("http://example.com/baz.php")); | |
327 ResourceHostMsg_RequestResource msg(0, 1, request); | |
328 host_.OnMessageReceived(msg, filter_.get()); | |
329 base::RunLoop().RunUntilIdle(); | |
330 | |
331 net::URLRequest* url_request( | |
332 host_.GetURLRequest(GlobalRequestID(filter_->child_id(), 1))); | |
333 ASSERT_TRUE(url_request); | |
334 | |
335 EXPECT_FALSE(url_request->load_flags() & | |
336 net::LOAD_SUPPORT_ASYNC_REVALIDATION); | |
337 } | |
338 | |
339 TEST_F(AsyncRevalidationManagerTest, AsyncRevalidationNotSupportedForRedirect) { | |
340 static const char kRedirectHeaders[] = | |
341 "HTTP/1.1 302 MOVED\n" | |
342 "Location: http://example.com/var\n" | |
343 "\n"; | |
344 // Scheme has to be HTTP or HTTPS to support async revalidation. | |
345 HandleScheme("http"); | |
346 SetResponse(kRedirectHeaders, ""); | |
347 | |
348 MakeTestRequest(0, 1, GURL("http://example.com/baz")); | |
349 | |
350 net::URLRequest* url_request( | |
351 host_.GetURLRequest(GlobalRequestID(filter_->child_id(), 1))); | |
352 ASSERT_TRUE(url_request); | |
353 | |
354 EXPECT_FALSE(url_request->load_flags() & | |
355 net::LOAD_SUPPORT_ASYNC_REVALIDATION); | |
356 } | |
357 | |
358 // A URLRequestJob implementation which sets the |async_revalidation_required| | |
359 // flag on the HttpResponseInfo object to true if the request has the | |
360 // LOAD_SUPPORT_ASYNC_REVALIDATION flag. | |
361 class AsyncRevalidationRequiredURLRequestTestJob | |
362 : public net::URLRequestTestJob { | |
363 public: | |
364 // The Create() method is useful for wrapping the construction of the object | |
365 // in a Callback. | |
366 static net::URLRequestJob* Create(net::URLRequest* request, | |
367 net::NetworkDelegate* network_delegate) { | |
368 return new AsyncRevalidationRequiredURLRequestTestJob(request, | |
369 network_delegate); | |
370 } | |
371 | |
372 void GetResponseInfo(net::HttpResponseInfo* info) override { | |
373 if (request()->load_flags() & net::LOAD_SUPPORT_ASYNC_REVALIDATION) | |
374 info->async_revalidation_required = true; | |
375 } | |
376 | |
377 private: | |
378 AsyncRevalidationRequiredURLRequestTestJob( | |
379 net::URLRequest* request, | |
380 net::NetworkDelegate* network_delegate) | |
381 : URLRequestTestJob(request, | |
382 network_delegate, | |
383 net::URLRequestTestJob::test_headers(), | |
384 std::string(), | |
385 false) {} | |
386 | |
387 ~AsyncRevalidationRequiredURLRequestTestJob() override {} | |
388 | |
389 DISALLOW_COPY_AND_ASSIGN(AsyncRevalidationRequiredURLRequestTestJob); | |
390 }; | |
391 | |
392 // A URLRequestJob implementation which serves a redirect and sets the | |
393 // |async_revalidation_required| flag on the HttpResponseInfo object to true if | |
394 // the request has the LOAD_SUPPORT_ASYNC_REVALIDATION flag. | |
395 class RedirectAndRevalidateURLRequestTestJob : public net::URLRequestTestJob { | |
396 public: | |
397 // The Create() method is useful for wrapping the construction of the object | |
398 // in a Callback. | |
399 static net::URLRequestJob* Create(net::URLRequest* request, | |
400 net::NetworkDelegate* network_delegate) { | |
401 return new RedirectAndRevalidateURLRequestTestJob(request, | |
402 network_delegate); | |
403 } | |
404 | |
405 void GetResponseInfo(net::HttpResponseInfo* info) override { | |
406 URLRequestTestJob::GetResponseInfo(info); | |
407 if (request()->load_flags() & net::LOAD_SUPPORT_ASYNC_REVALIDATION) | |
408 info->async_revalidation_required = true; | |
409 } | |
410 | |
411 private: | |
412 RedirectAndRevalidateURLRequestTestJob(net::URLRequest* request, | |
413 net::NetworkDelegate* network_delegate) | |
414 : URLRequestTestJob(request, | |
415 network_delegate, | |
416 std::string(CreateRedirectHeaders()), | |
417 std::string(), | |
418 false) {} | |
419 | |
420 ~RedirectAndRevalidateURLRequestTestJob() override {} | |
421 | |
422 static std::string CreateRedirectHeaders() { | |
423 static const char kRedirectHeaders[] = | |
424 "HTTP/1.1 302 MOVED\0" | |
425 "Location: http://example.com/var\0" | |
426 "\0"; | |
427 return std::string(kRedirectHeaders, arraysize(kRedirectHeaders)); | |
428 } | |
429 | |
430 DISALLOW_COPY_AND_ASSIGN(RedirectAndRevalidateURLRequestTestJob); | |
431 }; | |
432 | |
433 // A NetworkDelegate that records the URLRequests as they are created. | |
434 class URLRequestRecordingNetworkDelegate : public net::TestNetworkDelegate { | |
435 public: | |
436 URLRequestRecordingNetworkDelegate() : requests_() {} | |
437 | |
438 net::URLRequest* NextRequest() { | |
439 if (requests_.empty()) | |
440 return nullptr; | |
441 net::URLRequest* request = requests_.front(); | |
442 requests_.pop(); | |
443 return request; | |
444 } | |
445 | |
446 bool IsEmpty() { return requests_.empty(); } | |
447 | |
448 int OnBeforeURLRequest(net::URLRequest* request, | |
449 const net::CompletionCallback& callback, | |
450 GURL* new_url) override { | |
451 requests_.push(request); | |
452 return TestNetworkDelegate::OnBeforeURLRequest(request, callback, new_url); | |
453 } | |
454 | |
455 private: | |
456 std::queue<net::URLRequest*> requests_; | |
457 | |
458 DISALLOW_COPY_AND_ASSIGN(URLRequestRecordingNetworkDelegate); | |
459 }; | |
460 | |
461 class AsyncRevalidationManagerRecordingTest | |
462 : public AsyncRevalidationManagerTest { | |
463 public: | |
464 AsyncRevalidationManagerRecordingTest() | |
465 : AsyncRevalidationManagerTest( | |
466 make_scoped_ptr(new URLRequestRecordingNetworkDelegate)) { | |
467 // Scheme has to be HTTP or HTTPS to support async revalidation. | |
468 HandleScheme("http"); | |
469 // Use the AsyncRevalidationRequiredURLRequestTestJob. | |
470 SetCustomURLRequestJobCreateCallback( | |
471 base::Bind(&AsyncRevalidationRequiredURLRequestTestJob::Create)); | |
472 } | |
473 | |
474 URLRequestRecordingNetworkDelegate* recording_network_delegate() { | |
475 return static_cast<URLRequestRecordingNetworkDelegate*>(network_delegate()); | |
476 } | |
477 | |
478 net::URLRequest* NextRequest() { | |
479 return recording_network_delegate()->NextRequest(); | |
480 } | |
481 | |
482 bool IsEmpty() { return recording_network_delegate()->IsEmpty(); } | |
483 }; | |
484 | |
485 // Verify that an async revalidation is actually created when needed. | |
486 TEST_F(AsyncRevalidationManagerRecordingTest, Issued) { | |
487 // Create the original request. | |
488 MakeTestRequest(0, 1, GURL("http://example.com/baz")); | |
489 | |
490 net::URLRequest* initial_request = NextRequest(); | |
491 ASSERT_TRUE(initial_request); | |
492 EXPECT_TRUE(initial_request->load_flags() & | |
493 net::LOAD_SUPPORT_ASYNC_REVALIDATION); | |
494 | |
495 net::URLRequest* async_request = NextRequest(); | |
496 ASSERT_TRUE(async_request); | |
497 } | |
498 | |
499 // Verify the the URL of the async revalidation matches the original request. | |
500 TEST_F(AsyncRevalidationManagerRecordingTest, URLMatches) { | |
501 // Create the original request. | |
502 MakeTestRequest(0, 1, GURL("http://example.com/special-baz")); | |
503 | |
504 // Discard the original request. | |
505 NextRequest(); | |
506 | |
507 net::URLRequest* async_request = NextRequest(); | |
508 ASSERT_TRUE(async_request); | |
509 EXPECT_EQ(GURL("http://example.com/special-baz"), async_request->url()); | |
510 } | |
511 | |
512 TEST_F(AsyncRevalidationManagerRecordingTest, | |
513 AsyncRevalidationsDoNotSupportAsyncRevalidation) { | |
514 // Create the original request. | |
515 MakeTestRequest(0, 1, GURL("http://example.com/baz")); | |
516 | |
517 // Discard the original request. | |
518 NextRequest(); | |
519 | |
520 // Get the async revalidation request. | |
521 net::URLRequest* async_request = NextRequest(); | |
522 ASSERT_TRUE(async_request); | |
523 EXPECT_FALSE(async_request->load_flags() & | |
524 net::LOAD_SUPPORT_ASYNC_REVALIDATION); | |
525 } | |
526 | |
527 TEST_F(AsyncRevalidationManagerRecordingTest, AsyncRevalidationsNotDuplicated) { | |
528 // Create the original request. | |
529 MakeTestRequest(0, 1, GURL("http://example.com/baz")); | |
530 | |
531 // Discard the original request. | |
532 NextRequest(); | |
533 | |
534 // Get the async revalidation request. | |
535 net::URLRequest* async_request = NextRequest(); | |
536 EXPECT_TRUE(async_request); | |
537 | |
538 // Start a second request to the same URL. | |
539 MakeTestRequest(0, 2, GURL("http://example.com/baz")); | |
540 | |
541 // Discard the second request. | |
542 NextRequest(); | |
543 | |
544 // There should not be another async revalidation request. | |
545 EXPECT_TRUE(IsEmpty()); | |
546 } | |
547 | |
548 // Async revalidation to different URLs should not be treated as duplicates. | |
549 TEST_F(AsyncRevalidationManagerRecordingTest, | |
550 AsyncRevalidationsToSeparateURLsAreSeparate) { | |
551 // Create two requests to two URLs. | |
552 MakeTestRequest(0, 1, GURL("http://example.com/baz")); | |
553 MakeTestRequest(0, 2, GURL("http://example.com/far")); | |
554 | |
555 net::URLRequest* initial_request = NextRequest(); | |
556 ASSERT_TRUE(initial_request); | |
557 net::URLRequest* initial_async_revalidation = NextRequest(); | |
558 ASSERT_TRUE(initial_async_revalidation); | |
559 net::URLRequest* second_request = NextRequest(); | |
560 ASSERT_TRUE(second_request); | |
561 net::URLRequest* second_async_revalidation = NextRequest(); | |
562 ASSERT_TRUE(second_async_revalidation); | |
563 | |
564 EXPECT_EQ("http://example.com/baz", initial_request->url().spec()); | |
565 EXPECT_EQ("http://example.com/baz", initial_async_revalidation->url().spec()); | |
566 EXPECT_EQ("http://example.com/far", second_request->url().spec()); | |
567 EXPECT_EQ("http://example.com/far", second_async_revalidation->url().spec()); | |
568 } | |
569 | |
570 // A stale-while-revalidate applicable redirect response should not result in an | |
571 // async revalidation. | |
572 TEST_F(AsyncRevalidationManagerRecordingTest, RedirectNotApplicable) { | |
573 // Use the appropriate URLRequestJob for the test. | |
574 SetCustomURLRequestJobCreateCallback( | |
575 base::Bind(&RedirectAndRevalidateURLRequestTestJob::Create)); | |
576 MakeTestRequest(0, 1, GURL("http://example.com/redirect")); | |
577 | |
578 net::URLRequest* initial_request = NextRequest(); | |
579 EXPECT_TRUE(initial_request); | |
580 | |
581 // There should not be an async revalidation request. | |
582 EXPECT_TRUE(IsEmpty()); | |
583 } | |
584 | |
585 } // namespace content | |
OLD | NEW |