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