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*)>; | |
davidben
2015/12/07 23:56:04
Since you only ever create two job types and one o
Adam Rice
2015/12/08 18:05:35
Okay, done. That's saved quite a bit of code.
| |
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 | |
davidben
2015/12/07 23:56:04
Nit: Capitalize and end with period.
Adam Rice
2015/12/08 18:05:35
Done.
| |
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 class AsyncRevalidationManagerTest : public ::testing::Test { | |
222 protected: | |
223 AsyncRevalidationManagerTest( | |
224 scoped_ptr<net::TestNetworkDelegate> network_delegate) | |
225 : thread_bundle_(content::TestBrowserThreadBundle::IO_MAINLOOP), | |
226 network_delegate_(std::move(network_delegate)) { | |
227 browser_context_.reset(new TestBrowserContext()); | |
228 BrowserContext::EnsureResourceContextInitialized(browser_context_.get()); | |
229 base::RunLoop().RunUntilIdle(); | |
230 ResourceContext* resource_context = browser_context_->GetResourceContext(); | |
231 filter_ = new BlackholeFilter(resource_context); | |
232 net::URLRequestContext* request_context = | |
233 resource_context->GetRequestContext(); | |
234 job_factory_.reset(new TestURLRequestJobFactory); | |
235 request_context->set_job_factory(job_factory_.get()); | |
236 request_context->set_network_delegate(network_delegate_.get()); | |
237 host_.EnableStaleWhileRevalidateForTesting(); | |
238 } | |
239 | |
240 AsyncRevalidationManagerTest() | |
241 : AsyncRevalidationManagerTest( | |
242 make_scoped_ptr(new net::TestNetworkDelegate)) {} | |
243 | |
244 void TearDown() override { | |
245 host_.CancelRequestsForProcess(filter_->child_id()); | |
246 host_.Shutdown(); | |
247 host_.CancelRequestsForContext(browser_context_->GetResourceContext()); | |
248 browser_context_.reset(); | |
249 base::RunLoop().RunUntilIdle(); | |
250 } | |
251 | |
252 void SetResponse(const std::string& headers, const std::string& data) { | |
253 job_factory_->SetResponse(headers, data); | |
254 } | |
255 | |
256 void SetCustomURLRequestJobCreateCallback( | |
257 const TestURLRequestJobFactory::URLRequestJobCreateCallback& callback) { | |
258 job_factory_->SetCustomURLRequestJobCreateCallback(callback); | |
259 } | |
260 | |
261 // Creates a request using the current test object as the filter and | |
262 // SubResource as the resource type. | |
263 void MakeTestRequest(int render_view_id, int request_id, const GURL& url) { | |
264 ResourceHostMsg_Request request = | |
265 CreateResourceRequest("GET", RESOURCE_TYPE_SUB_RESOURCE, url); | |
266 ResourceHostMsg_RequestResource msg(render_view_id, request_id, request); | |
267 host_.OnMessageReceived(msg, filter_.get()); | |
268 base::RunLoop().RunUntilIdle(); | |
269 } | |
270 | |
271 void EnsureSchemeIsAllowed(const std::string& scheme) { | |
272 ChildProcessSecurityPolicyImpl* policy = | |
273 ChildProcessSecurityPolicyImpl::GetInstance(); | |
274 if (!policy->IsWebSafeScheme(scheme)) | |
275 policy->RegisterWebSafeScheme(scheme); | |
276 } | |
277 | |
278 content::TestBrowserThreadBundle thread_bundle_; | |
279 scoped_ptr<TestBrowserContext> browser_context_; | |
280 scoped_ptr<TestURLRequestJobFactory> job_factory_; | |
281 scoped_refptr<BlackholeFilter> filter_; | |
282 scoped_ptr<net::TestNetworkDelegate> network_delegate_; | |
283 ResourceDispatcherHostImpl host_; | |
284 }; | |
285 | |
286 TEST_F(AsyncRevalidationManagerTest, SupportsAsyncRevalidation) { | |
287 SetResponse(net::URLRequestTestJob::test_headers(), "delay complete"); | |
288 MakeTestRequest(0, 1, GURL("http://example.com/baz")); | |
289 | |
290 net::URLRequest* url_request( | |
291 host_.GetURLRequest(GlobalRequestID(filter_->child_id(), 1))); | |
292 ASSERT_TRUE(url_request); | |
293 | |
294 EXPECT_TRUE(url_request->load_flags() & net::LOAD_SUPPORT_ASYNC_REVALIDATION); | |
295 } | |
296 | |
297 TEST_F(AsyncRevalidationManagerTest, AsyncRevalidationNotSupportedForPOST) { | |
298 SetResponse(net::URLRequestTestJob::test_headers(), "delay complete"); | |
299 // Create POST request. | |
300 ResourceHostMsg_Request request = CreateResourceRequest( | |
301 "POST", RESOURCE_TYPE_SUB_RESOURCE, GURL("http://example.com/baz.php")); | |
302 ResourceHostMsg_RequestResource msg(0, 1, request); | |
303 host_.OnMessageReceived(msg, filter_.get()); | |
304 base::RunLoop().RunUntilIdle(); | |
305 | |
306 net::URLRequest* url_request( | |
307 host_.GetURLRequest(GlobalRequestID(filter_->child_id(), 1))); | |
308 ASSERT_TRUE(url_request); | |
309 | |
310 EXPECT_FALSE(url_request->load_flags() & | |
311 net::LOAD_SUPPORT_ASYNC_REVALIDATION); | |
312 } | |
313 | |
314 TEST_F(AsyncRevalidationManagerTest, | |
315 AsyncRevalidationNotSupportedAfterRedirect) { | |
316 static const char kRedirectHeaders[] = | |
317 "HTTP/1.1 302 MOVED\n" | |
318 "Location: http://example.com/var\n" | |
319 "\n"; | |
320 SetResponse(kRedirectHeaders, ""); | |
321 | |
322 MakeTestRequest(0, 1, GURL("http://example.com/baz")); | |
323 | |
324 net::URLRequest* url_request( | |
325 host_.GetURLRequest(GlobalRequestID(filter_->child_id(), 1))); | |
326 ASSERT_TRUE(url_request); | |
327 | |
328 EXPECT_FALSE(url_request->load_flags() & | |
329 net::LOAD_SUPPORT_ASYNC_REVALIDATION); | |
330 } | |
331 | |
332 // A URLRequestJob implementation which sets the |async_revalidation_required| | |
333 // flag on the HttpResponseInfo object to true if the request has the | |
334 // LOAD_SUPPORT_ASYNC_REVALIDATION flag. | |
335 class AsyncRevalidationRequiredURLRequestTestJob | |
336 : public net::URLRequestTestJob { | |
337 public: | |
338 // The Create() method is useful for wrapping the construction of the object | |
339 // in a Callback. | |
340 static net::URLRequestJob* Create(net::URLRequest* request, | |
341 net::NetworkDelegate* network_delegate) { | |
342 return new AsyncRevalidationRequiredURLRequestTestJob(request, | |
343 network_delegate); | |
344 } | |
345 | |
346 void GetResponseInfo(net::HttpResponseInfo* info) override { | |
347 URLRequestTestJob::GetResponseInfo(info); | |
348 if (request()->load_flags() & net::LOAD_SUPPORT_ASYNC_REVALIDATION) | |
349 info->async_revalidation_required = true; | |
350 } | |
351 | |
352 private: | |
353 AsyncRevalidationRequiredURLRequestTestJob( | |
354 net::URLRequest* request, | |
355 net::NetworkDelegate* network_delegate) | |
356 : URLRequestTestJob(request, | |
357 network_delegate, | |
358 net::URLRequestTestJob::test_headers(), | |
359 std::string(), | |
360 false) {} | |
361 | |
362 ~AsyncRevalidationRequiredURLRequestTestJob() override {} | |
363 | |
364 DISALLOW_COPY_AND_ASSIGN(AsyncRevalidationRequiredURLRequestTestJob); | |
365 }; | |
366 | |
367 // A URLRequestJob implementation which serves a redirect and sets the | |
368 // |async_revalidation_required| flag on the HttpResponseInfo object to true if | |
369 // the request has the LOAD_SUPPORT_ASYNC_REVALIDATION flag. | |
370 class RedirectAndRevalidateURLRequestTestJob : public net::URLRequestTestJob { | |
371 public: | |
372 // This Create() method returns a redirecting job if the URL contains the | |
373 // string "redirect", otherwise a AsyncRevalidationRequiredURLRequestTestJob. | |
374 static net::URLRequestJob* Create(net::URLRequest* request, | |
375 net::NetworkDelegate* network_delegate) { | |
376 if (request->url().spec().find("redirect") != std::string::npos) { | |
377 return new RedirectAndRevalidateURLRequestTestJob(request, | |
378 network_delegate); | |
379 } | |
380 return AsyncRevalidationRequiredURLRequestTestJob::Create(request, | |
381 network_delegate); | |
382 } | |
383 | |
384 void GetResponseInfo(net::HttpResponseInfo* info) override { | |
385 URLRequestTestJob::GetResponseInfo(info); | |
386 if (request()->load_flags() & net::LOAD_SUPPORT_ASYNC_REVALIDATION) | |
387 info->async_revalidation_required = true; | |
388 } | |
389 | |
390 private: | |
391 RedirectAndRevalidateURLRequestTestJob(net::URLRequest* request, | |
392 net::NetworkDelegate* network_delegate) | |
393 : URLRequestTestJob(request, | |
394 network_delegate, | |
395 std::string(CreateRedirectHeaders()), | |
396 std::string(), | |
397 false) {} | |
398 | |
399 ~RedirectAndRevalidateURLRequestTestJob() override {} | |
400 | |
401 static std::string CreateRedirectHeaders() { | |
402 static const char kRedirectHeaders[] = | |
403 "HTTP/1.1 302 MOVED\n" | |
404 "Location: http://example.com/var\n" | |
405 "\n"; | |
406 return std::string(kRedirectHeaders, arraysize(kRedirectHeaders)); | |
407 } | |
408 | |
409 DISALLOW_COPY_AND_ASSIGN(RedirectAndRevalidateURLRequestTestJob); | |
410 }; | |
411 | |
412 // A NetworkDelegate that records the URLRequests as they are created. | |
413 class URLRequestRecordingNetworkDelegate : public net::TestNetworkDelegate { | |
414 public: | |
415 URLRequestRecordingNetworkDelegate() : requests_() {} | |
416 | |
417 net::URLRequest* NextRequest() { | |
418 if (requests_.empty()) | |
419 return nullptr; | |
420 net::URLRequest* request = requests_.front(); | |
421 requests_.pop(); | |
422 return request; | |
423 } | |
424 | |
425 bool IsEmpty() const { return requests_.empty(); } | |
426 | |
427 int OnBeforeURLRequest(net::URLRequest* request, | |
428 const net::CompletionCallback& callback, | |
429 GURL* new_url) override { | |
430 requests_.push(request); | |
431 return TestNetworkDelegate::OnBeforeURLRequest(request, callback, new_url); | |
432 } | |
davidben
2015/12/07 23:56:04
Might be worth also listening for destruction and
Adam Rice
2015/12/08 18:05:36
I made it so that it removes dangling pointers whe
| |
433 | |
434 private: | |
435 std::queue<net::URLRequest*> requests_; | |
436 | |
437 DISALLOW_COPY_AND_ASSIGN(URLRequestRecordingNetworkDelegate); | |
438 }; | |
439 | |
440 class AsyncRevalidationManagerRecordingTest | |
441 : public AsyncRevalidationManagerTest { | |
442 public: | |
443 AsyncRevalidationManagerRecordingTest() | |
444 : AsyncRevalidationManagerTest( | |
445 make_scoped_ptr(new URLRequestRecordingNetworkDelegate)) { | |
446 // Use the AsyncRevalidationRequiredURLRequestTestJob. | |
447 SetCustomURLRequestJobCreateCallback( | |
448 base::Bind(&AsyncRevalidationRequiredURLRequestTestJob::Create)); | |
449 } | |
450 | |
451 URLRequestRecordingNetworkDelegate* recording_network_delegate() const { | |
452 return static_cast<URLRequestRecordingNetworkDelegate*>( | |
453 network_delegate_.get()); | |
454 } | |
455 | |
456 net::URLRequest* NextRequest() { | |
457 return recording_network_delegate()->NextRequest(); | |
458 } | |
459 | |
460 bool IsEmpty() const { return recording_network_delegate()->IsEmpty(); } | |
461 }; | |
462 | |
463 // Verify that an async revalidation is actually created when needed. | |
464 TEST_F(AsyncRevalidationManagerRecordingTest, Issued) { | |
465 // Create the original request. | |
466 MakeTestRequest(0, 1, GURL("http://example.com/baz")); | |
467 | |
468 net::URLRequest* initial_request = NextRequest(); | |
469 ASSERT_TRUE(initial_request); | |
470 EXPECT_TRUE(initial_request->load_flags() & | |
471 net::LOAD_SUPPORT_ASYNC_REVALIDATION); | |
472 | |
473 net::URLRequest* async_request = NextRequest(); | |
474 ASSERT_TRUE(async_request); | |
475 } | |
476 | |
477 // Verify the the URL of the async revalidation matches the original request. | |
478 TEST_F(AsyncRevalidationManagerRecordingTest, URLMatches) { | |
479 // Create the original request. | |
480 MakeTestRequest(0, 1, GURL("http://example.com/special-baz")); | |
481 | |
482 // Discard the original request. | |
483 NextRequest(); | |
484 | |
485 net::URLRequest* async_request = NextRequest(); | |
486 ASSERT_TRUE(async_request); | |
487 EXPECT_EQ(GURL("http://example.com/special-baz"), async_request->url()); | |
488 } | |
489 | |
490 TEST_F(AsyncRevalidationManagerRecordingTest, | |
491 AsyncRevalidationsDoNotSupportAsyncRevalidation) { | |
492 // Create the original request. | |
493 MakeTestRequest(0, 1, GURL("http://example.com/baz")); | |
494 | |
495 // Discard the original request. | |
496 NextRequest(); | |
497 | |
498 // Get the async revalidation request. | |
499 net::URLRequest* async_request = NextRequest(); | |
500 ASSERT_TRUE(async_request); | |
501 EXPECT_FALSE(async_request->load_flags() & | |
502 net::LOAD_SUPPORT_ASYNC_REVALIDATION); | |
503 } | |
504 | |
505 TEST_F(AsyncRevalidationManagerRecordingTest, AsyncRevalidationsNotDuplicated) { | |
506 // Create the original request. | |
507 MakeTestRequest(0, 1, GURL("http://example.com/baz")); | |
508 | |
509 // Discard the original request. | |
510 NextRequest(); | |
511 | |
512 // Get the async revalidation request. | |
513 net::URLRequest* async_request = NextRequest(); | |
514 EXPECT_TRUE(async_request); | |
515 | |
516 // Start a second request to the same URL. | |
517 MakeTestRequest(0, 2, GURL("http://example.com/baz")); | |
518 | |
519 // Discard the second request. | |
520 NextRequest(); | |
521 | |
522 // There should not be another async revalidation request. | |
523 EXPECT_TRUE(IsEmpty()); | |
524 } | |
525 | |
526 // Async revalidation to different URLs should not be treated as duplicates. | |
527 TEST_F(AsyncRevalidationManagerRecordingTest, | |
528 AsyncRevalidationsToSeparateURLsAreSeparate) { | |
529 // Create two requests to two URLs. | |
530 MakeTestRequest(0, 1, GURL("http://example.com/baz")); | |
531 MakeTestRequest(0, 2, GURL("http://example.com/far")); | |
532 | |
533 net::URLRequest* initial_request = NextRequest(); | |
534 ASSERT_TRUE(initial_request); | |
535 net::URLRequest* initial_async_revalidation = NextRequest(); | |
536 ASSERT_TRUE(initial_async_revalidation); | |
537 net::URLRequest* second_request = NextRequest(); | |
538 ASSERT_TRUE(second_request); | |
539 net::URLRequest* second_async_revalidation = NextRequest(); | |
540 ASSERT_TRUE(second_async_revalidation); | |
541 | |
542 EXPECT_EQ("http://example.com/baz", initial_request->url().spec()); | |
543 EXPECT_EQ("http://example.com/baz", initial_async_revalidation->url().spec()); | |
544 EXPECT_EQ("http://example.com/far", second_request->url().spec()); | |
545 EXPECT_EQ("http://example.com/far", second_async_revalidation->url().spec()); | |
546 } | |
547 | |
548 // A stale-while-revalidate applicable redirect response should not result in an | |
549 // async revalidation. | |
550 TEST_F(AsyncRevalidationManagerRecordingTest, InitialRedirectLegRevalidated) { | |
551 // Use the appropriate URLRequestJob for the test. | |
552 SetCustomURLRequestJobCreateCallback( | |
553 base::Bind(&RedirectAndRevalidateURLRequestTestJob::Create)); | |
554 MakeTestRequest(0, 1, GURL("http://example.com/redirect")); | |
555 | |
556 net::URLRequest* initial_request = NextRequest(); | |
557 EXPECT_TRUE(initial_request); | |
558 | |
559 // There should be an async revalidation request. | |
560 ASSERT_TRUE(NextRequest()); | |
561 } | |
562 | |
563 // Nothing after the first redirect leg has stale-while-revalidate applied. | |
564 // TODO(ricea): s-w-r should work with redirects. Change this test when it does. | |
565 TEST_F(AsyncRevalidationManagerRecordingTest, NoSWRAfterFirstRedirectLeg) { | |
566 SetCustomURLRequestJobCreateCallback( | |
567 base::Bind(&RedirectAndRevalidateURLRequestTestJob::Create)); | |
568 MakeTestRequest(0, 1, GURL("http://example.com/redirect")); | |
569 | |
570 net::URLRequest* initial_request = NextRequest(); | |
571 EXPECT_TRUE(initial_request); | |
572 | |
573 EXPECT_FALSE(initial_request->load_flags() & | |
574 net::LOAD_SUPPORT_ASYNC_REVALIDATION); | |
575 | |
576 // An async revalidation happens for the redirect. | |
577 EXPECT_TRUE(NextRequest()); | |
578 | |
579 // But no others. | |
580 EXPECT_TRUE(IsEmpty()); | |
581 } | |
582 | |
583 } // namespace | |
584 | |
585 } // namespace content | |
OLD | NEW |