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