1 // Copyright 2014 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.
10 #include "base/bind_helpers.h"
11 #include "base/callback.h"
12 #include "base/message_loop/message_loop.h"
13 #include "base/synchronization/waitable_event.h"
14 #include "base/threading/thread.h"
15 #include "content/browser/appcache/appcache.h"
16 #include "content/browser/appcache/appcache_backend_impl.h"
17 #include "content/browser/appcache/appcache_request_handler.h"
18 #include "content/browser/appcache/appcache_url_request_job.h"
19 #include "content/browser/appcache/mock_appcache_policy.h"
20 #include "content/browser/appcache/mock_appcache_service.h"
21 #include "net/base/net_errors.h"
22 #include "net/base/request_priority.h"
23 #include "net/http/http_response_headers.h"
24 #include "net/url_request/url_request.h"
25 #include "net/url_request/url_request_context.h"
26 #include "net/url_request/url_request_error_job.h"
27 #include "net/url_request/url_request_job_factory.h"
28 #include "testing/gtest/include/gtest/gtest.h"
32 static const int kMockProcessId
= 1;
34 class AppCacheRequestHandlerTest
: public testing::Test
{
36 class MockFrontend
: public AppCacheFrontend
{
38 void OnCacheSelected(int host_id
, const AppCacheInfo
& info
) override
{}
40 void OnStatusChanged(const std::vector
<int>& host_ids
,
41 AppCacheStatus status
) override
{}
43 void OnEventRaised(const std::vector
<int>& host_ids
,
44 AppCacheEventID event_id
) override
{}
46 void OnErrorEventRaised(const std::vector
<int>& host_ids
,
47 const AppCacheErrorDetails
& details
) override
{}
49 void OnProgressEventRaised(const std::vector
<int>& host_ids
,
52 int num_complete
) override
{}
54 void OnLogMessage(int host_id
,
55 AppCacheLogLevel log_level
,
56 const std::string
& message
) override
{}
58 void OnContentBlocked(int host_id
, const GURL
& manifest_url
) override
{}
61 // Helper callback to run a test on our io_thread. The io_thread is spun up
62 // once and reused for all tests.
63 template <class Method
>
64 void MethodWrapper(Method method
) {
69 // Subclasses to simulate particular responses so test cases can
70 // exercise fallback code paths.
72 class MockURLRequestDelegate
: public net::URLRequest::Delegate
{
73 void OnResponseStarted(net::URLRequest
* request
) override
{}
74 void OnReadCompleted(net::URLRequest
* request
, int bytes_read
) override
{}
77 class MockURLRequestJob
: public net::URLRequestJob
{
79 MockURLRequestJob(net::URLRequest
* request
,
80 net::NetworkDelegate
* network_delegate
,
82 : net::URLRequestJob(request
, network_delegate
),
83 response_code_(response_code
),
84 has_response_info_(false) {}
85 MockURLRequestJob(net::URLRequest
* request
,
86 net::NetworkDelegate
* network_delegate
,
87 const net::HttpResponseInfo
& info
)
88 : net::URLRequestJob(request
, network_delegate
),
89 response_code_(info
.headers
->response_code()),
90 has_response_info_(true),
91 response_info_(info
) {}
94 ~MockURLRequestJob() override
{}
95 void Start() override
{ NotifyHeadersComplete(); }
96 int GetResponseCode() const override
{ return response_code_
; }
97 void GetResponseInfo(net::HttpResponseInfo
* info
) override
{
98 if (!has_response_info_
)
100 *info
= response_info_
;
105 bool has_response_info_
;
106 net::HttpResponseInfo response_info_
;
109 class MockURLRequestJobFactory
: public net::URLRequestJobFactory
{
111 MockURLRequestJobFactory() : job_(NULL
) {
114 ~MockURLRequestJobFactory() override
{ DCHECK(!job_
); }
116 void SetJob(net::URLRequestJob
* job
) {
120 net::URLRequestJob
* MaybeCreateJobWithProtocolHandler(
121 const std::string
& scheme
,
122 net::URLRequest
* request
,
123 net::NetworkDelegate
* network_delegate
) const override
{
125 net::URLRequestJob
* temp
= job_
;
129 // Some of these tests trigger UpdateJobs which start URLRequests.
130 // We short circuit those be returning error jobs.
131 return new net::URLRequestErrorJob(request
,
133 net::ERR_INTERNET_DISCONNECTED
);
137 bool IsHandledProtocol(const std::string
& scheme
) const override
{
138 return scheme
== "http";
141 bool IsHandledURL(const GURL
& url
) const override
{
142 return url
.SchemeIs("http");
145 bool IsSafeRedirectTarget(const GURL
& location
) const override
{
150 mutable net::URLRequestJob
* job_
;
153 static void SetUpTestCase() {
154 io_thread_
.reset(new base::Thread("AppCacheRequestHandlerTest Thread"));
155 base::Thread::Options
options(base::MessageLoop::TYPE_IO
, 0);
156 io_thread_
->StartWithOptions(options
);
159 static void TearDownTestCase() {
160 io_thread_
.reset(NULL
);
163 // Test harness --------------------------------------------------
165 AppCacheRequestHandlerTest() : host_(NULL
) {}
167 template <class Method
>
168 void RunTestOnIOThread(Method method
) {
169 test_finished_event_
.reset(new base::WaitableEvent(false, false));
170 io_thread_
->message_loop()->PostTask(
172 base::Bind(&AppCacheRequestHandlerTest::MethodWrapper
<Method
>,
173 base::Unretained(this), method
));
174 test_finished_event_
->Wait();
178 DCHECK(base::MessageLoop::current() == io_thread_
->message_loop());
179 mock_service_
.reset(new MockAppCacheService
);
180 mock_service_
->set_request_context(&empty_context_
);
181 mock_policy_
.reset(new MockAppCachePolicy
);
182 mock_service_
->set_appcache_policy(mock_policy_
.get());
183 mock_frontend_
.reset(new MockFrontend
);
184 backend_impl_
.reset(new AppCacheBackendImpl
);
185 backend_impl_
->Initialize(mock_service_
.get(), mock_frontend_
.get(),
187 const int kHostId
= 1;
188 backend_impl_
->RegisterHost(kHostId
);
189 host_
= backend_impl_
->GetHost(kHostId
);
190 job_factory_
.reset(new MockURLRequestJobFactory());
191 empty_context_
.set_job_factory(job_factory_
.get());
194 void TearDownTest() {
195 DCHECK(base::MessageLoop::current() == io_thread_
->message_loop());
199 backend_impl_
.reset();
200 mock_frontend_
.reset();
201 mock_service_
.reset();
202 mock_policy_
.reset();
203 job_factory_
.reset();
207 void TestFinished() {
208 // We unwind the stack prior to finishing up to let stack
209 // based objects get deleted.
210 DCHECK(base::MessageLoop::current() == io_thread_
->message_loop());
211 base::MessageLoop::current()->PostTask(
213 base::Bind(&AppCacheRequestHandlerTest::TestFinishedUnwound
,
214 base::Unretained(this)));
217 void TestFinishedUnwound() {
219 test_finished_event_
->Signal();
222 void PushNextTask(const base::Closure
& task
) {
223 task_stack_
.push(task
);
226 void ScheduleNextTask() {
227 DCHECK(base::MessageLoop::current() == io_thread_
->message_loop());
228 if (task_stack_
.empty()) {
232 base::MessageLoop::current()->PostTask(FROM_HERE
, task_stack_
.top());
236 // MainResource_Miss --------------------------------------------------
238 void MainResource_Miss() {
240 base::Bind(&AppCacheRequestHandlerTest::Verify_MainResource_Miss
,
241 base::Unretained(this)));
243 request_
= empty_context_
.CreateRequest(
244 GURL("http://blah/"), net::DEFAULT_PRIORITY
, &delegate_
, NULL
);
245 handler_
.reset(host_
->CreateRequestHandler(request_
.get(),
246 RESOURCE_TYPE_MAIN_FRAME
));
247 EXPECT_TRUE(handler_
.get());
249 job_
= handler_
->MaybeLoadResource(request_
.get(),
250 request_
->context()->network_delegate());
251 EXPECT_TRUE(job_
.get());
252 EXPECT_TRUE(job_
->is_waiting());
254 // We have to wait for completion of storage->FindResponseForMainRequest.
258 void Verify_MainResource_Miss() {
259 EXPECT_FALSE(job_
->is_waiting());
260 EXPECT_TRUE(job_
->is_delivering_network_response());
262 int64 cache_id
= kAppCacheNoCacheId
;
264 handler_
->GetExtraResponseInfo(&cache_id
, &manifest_url
);
265 EXPECT_EQ(kAppCacheNoCacheId
, cache_id
);
266 EXPECT_EQ(GURL(), manifest_url
);
267 EXPECT_EQ(0, handler_
->found_group_id_
);
269 AppCacheURLRequestJob
* fallback_job
;
270 fallback_job
= handler_
->MaybeLoadFallbackForRedirect(
272 request_
->context()->network_delegate(),
273 GURL("http://blah/redirect"));
274 EXPECT_FALSE(fallback_job
);
275 fallback_job
= handler_
->MaybeLoadFallbackForResponse(
276 request_
.get(), request_
->context()->network_delegate());
277 EXPECT_FALSE(fallback_job
);
279 EXPECT_TRUE(host_
->preferred_manifest_url().is_empty());
284 // MainResource_Hit --------------------------------------------------
286 void MainResource_Hit() {
288 base::Bind(&AppCacheRequestHandlerTest::Verify_MainResource_Hit
,
289 base::Unretained(this)));
291 request_
= empty_context_
.CreateRequest(
292 GURL("http://blah/"), net::DEFAULT_PRIORITY
, &delegate_
, NULL
);
293 handler_
.reset(host_
->CreateRequestHandler(request_
.get(),
294 RESOURCE_TYPE_MAIN_FRAME
));
295 EXPECT_TRUE(handler_
.get());
297 mock_storage()->SimulateFindMainResource(
298 AppCacheEntry(AppCacheEntry::EXPLICIT
, 1),
299 GURL(), AppCacheEntry(),
300 1, 2, GURL("http://blah/manifest/"));
302 job_
= handler_
->MaybeLoadResource(request_
.get(),
303 request_
->context()->network_delegate());
304 EXPECT_TRUE(job_
.get());
305 EXPECT_TRUE(job_
->is_waiting());
307 // We have to wait for completion of storage->FindResponseForMainRequest.
311 void Verify_MainResource_Hit() {
312 EXPECT_FALSE(job_
->is_waiting());
313 EXPECT_TRUE(job_
->is_delivering_appcache_response());
315 int64 cache_id
= kAppCacheNoCacheId
;
317 handler_
->GetExtraResponseInfo(&cache_id
, &manifest_url
);
318 EXPECT_EQ(1, cache_id
);
319 EXPECT_EQ(GURL("http://blah/manifest/"), manifest_url
);
320 EXPECT_EQ(2, handler_
->found_group_id_
);
322 AppCacheURLRequestJob
* fallback_job
;
323 fallback_job
= handler_
->MaybeLoadFallbackForResponse(
324 request_
.get(), request_
->context()->network_delegate());
325 EXPECT_FALSE(fallback_job
);
327 EXPECT_EQ(GURL("http://blah/manifest/"),
328 host_
->preferred_manifest_url());
333 // MainResource_Fallback --------------------------------------------------
335 void MainResource_Fallback() {
337 base::Bind(&AppCacheRequestHandlerTest::Verify_MainResource_Fallback
,
338 base::Unretained(this)));
340 request_
= empty_context_
.CreateRequest(
341 GURL("http://blah/"), net::DEFAULT_PRIORITY
, &delegate_
, NULL
);
342 handler_
.reset(host_
->CreateRequestHandler(request_
.get(),
343 RESOURCE_TYPE_MAIN_FRAME
));
344 EXPECT_TRUE(handler_
.get());
346 mock_storage()->SimulateFindMainResource(
348 GURL("http://blah/fallbackurl"),
349 AppCacheEntry(AppCacheEntry::EXPLICIT
, 1),
350 1, 2, GURL("http://blah/manifest/"));
352 job_
= handler_
->MaybeLoadResource(request_
.get(),
353 request_
->context()->network_delegate());
354 EXPECT_TRUE(job_
.get());
355 EXPECT_TRUE(job_
->is_waiting());
357 // We have to wait for completion of storage->FindResponseForMainRequest.
361 void SimulateResponseCode(int response_code
) {
362 job_factory_
->SetJob(
363 new MockURLRequestJob(
365 request_
->context()->network_delegate(),
368 // All our simulation needs to satisfy are the following two DCHECKs
369 DCHECK(request_
->status().is_success());
370 DCHECK_EQ(response_code
, request_
->GetResponseCode());
373 void SimulateResponseInfo(const net::HttpResponseInfo
& info
) {
374 job_factory_
->SetJob(
375 new MockURLRequestJob(
377 request_
->context()->network_delegate(), info
));
381 void Verify_MainResource_Fallback() {
382 EXPECT_FALSE(job_
->is_waiting());
383 EXPECT_TRUE(job_
->is_delivering_network_response());
385 // When the request is restarted, the existing job is dropped so a
386 // real network job gets created. We expect NULL here which will cause
387 // the net library to create a real job.
388 job_
= handler_
->MaybeLoadResource(request_
.get(),
389 request_
->context()->network_delegate());
390 EXPECT_FALSE(job_
.get());
392 // Simulate an http error of the real network job.
393 SimulateResponseCode(500);
395 job_
= handler_
->MaybeLoadFallbackForResponse(
396 request_
.get(), request_
->context()->network_delegate());
397 EXPECT_TRUE(job_
.get());
398 EXPECT_TRUE(job_
->is_delivering_appcache_response());
400 int64 cache_id
= kAppCacheNoCacheId
;
402 handler_
->GetExtraResponseInfo(&cache_id
, &manifest_url
);
403 EXPECT_EQ(1, cache_id
);
404 EXPECT_EQ(GURL("http://blah/manifest/"), manifest_url
);
405 EXPECT_TRUE(host_
->main_resource_was_namespace_entry_
);
406 EXPECT_EQ(GURL("http://blah/fallbackurl"), host_
->namespace_entry_url_
);
408 EXPECT_EQ(GURL("http://blah/manifest/"),
409 host_
->preferred_manifest_url());
414 // MainResource_FallbackOverride --------------------------------------------
416 void MainResource_FallbackOverride() {
417 PushNextTask(base::Bind(
418 &AppCacheRequestHandlerTest::Verify_MainResource_FallbackOverride
,
419 base::Unretained(this)));
421 request_
= empty_context_
.CreateRequest(
422 GURL("http://blah/fallback-override"), net::DEFAULT_PRIORITY
,
424 handler_
.reset(host_
->CreateRequestHandler(request_
.get(),
425 RESOURCE_TYPE_MAIN_FRAME
));
426 EXPECT_TRUE(handler_
.get());
428 mock_storage()->SimulateFindMainResource(
430 GURL("http://blah/fallbackurl"),
431 AppCacheEntry(AppCacheEntry::EXPLICIT
, 1),
432 1, 2, GURL("http://blah/manifest/"));
434 job_
= handler_
->MaybeLoadResource(request_
.get(),
435 request_
->context()->network_delegate());
436 EXPECT_TRUE(job_
.get());
437 EXPECT_TRUE(job_
->is_waiting());
439 // We have to wait for completion of storage->FindResponseForMainRequest.
443 void Verify_MainResource_FallbackOverride() {
444 EXPECT_FALSE(job_
->is_waiting());
445 EXPECT_TRUE(job_
->is_delivering_network_response());
447 // When the request is restarted, the existing job is dropped so a
448 // real network job gets created. We expect NULL here which will cause
449 // the net library to create a real job.
450 job_
= handler_
->MaybeLoadResource(request_
.get(),
451 request_
->context()->network_delegate());
452 EXPECT_FALSE(job_
.get());
454 // Simulate an http error of the real network job, but with custom
455 // headers that override the fallback behavior.
456 const char kOverrideHeaders
[] =
457 "HTTP/1.1 404 BOO HOO\0"
458 "x-chromium-appcache-fallback-override: disallow-fallback\0"
460 net::HttpResponseInfo info
;
461 info
.headers
= new net::HttpResponseHeaders(
462 std::string(kOverrideHeaders
, arraysize(kOverrideHeaders
)));
463 SimulateResponseInfo(info
);
465 job_
= handler_
->MaybeLoadFallbackForResponse(
466 request_
.get(), request_
->context()->network_delegate());
467 EXPECT_FALSE(job_
.get());
472 // SubResource_Miss_WithNoCacheSelected ----------------------------------
474 void SubResource_Miss_WithNoCacheSelected() {
475 request_
= empty_context_
.CreateRequest(
476 GURL("http://blah/"), net::DEFAULT_PRIORITY
, &delegate_
, NULL
);
477 handler_
.reset(host_
->CreateRequestHandler(request_
.get(),
478 RESOURCE_TYPE_SUB_RESOURCE
));
480 // We avoid creating handler when possible, sub-resource requests are not
481 // subject to retrieval from an appcache when there's no associated cache.
482 EXPECT_FALSE(handler_
.get());
487 // SubResource_Miss_WithCacheSelected ----------------------------------
489 void SubResource_Miss_WithCacheSelected() {
490 // A sub-resource load where the resource is not in an appcache, or
491 // in a network or fallback namespace, should result in a failed request.
492 host_
->AssociateCompleteCache(MakeNewCache());
494 request_
= empty_context_
.CreateRequest(
495 GURL("http://blah/"), net::DEFAULT_PRIORITY
, &delegate_
, NULL
);
496 handler_
.reset(host_
->CreateRequestHandler(request_
.get(),
497 RESOURCE_TYPE_SUB_RESOURCE
));
498 EXPECT_TRUE(handler_
.get());
500 job_
= handler_
->MaybeLoadResource(request_
.get(),
501 request_
->context()->network_delegate());
502 EXPECT_TRUE(job_
.get());
503 EXPECT_TRUE(job_
->is_delivering_error_response());
505 AppCacheURLRequestJob
* fallback_job
;
506 fallback_job
= handler_
->MaybeLoadFallbackForRedirect(
508 request_
->context()->network_delegate(),
509 GURL("http://blah/redirect"));
510 EXPECT_FALSE(fallback_job
);
511 fallback_job
= handler_
->MaybeLoadFallbackForResponse(
512 request_
.get(), request_
->context()->network_delegate());
513 EXPECT_FALSE(fallback_job
);
518 // SubResource_Miss_WithWaitForCacheSelection -----------------------------
520 void SubResource_Miss_WithWaitForCacheSelection() {
521 // Precondition, the host is waiting on cache selection.
522 scoped_refptr
<AppCache
> cache(MakeNewCache());
523 host_
->pending_selected_cache_id_
= cache
->cache_id();
524 host_
->set_preferred_manifest_url(cache
->owning_group()->manifest_url());
526 request_
= empty_context_
.CreateRequest(
527 GURL("http://blah/"), net::DEFAULT_PRIORITY
, &delegate_
, NULL
);
528 handler_
.reset(host_
->CreateRequestHandler(request_
.get(),
529 RESOURCE_TYPE_SUB_RESOURCE
));
530 EXPECT_TRUE(handler_
.get());
531 job_
= handler_
->MaybeLoadResource(request_
.get(),
532 request_
->context()->network_delegate());
533 EXPECT_TRUE(job_
.get());
534 EXPECT_TRUE(job_
->is_waiting());
536 host_
->FinishCacheSelection(cache
.get(), NULL
);
537 EXPECT_FALSE(job_
->is_waiting());
538 EXPECT_TRUE(job_
->is_delivering_error_response());
540 AppCacheURLRequestJob
* fallback_job
;
541 fallback_job
= handler_
->MaybeLoadFallbackForRedirect(
543 request_
->context()->network_delegate(),
544 GURL("http://blah/redirect"));
545 EXPECT_FALSE(fallback_job
);
546 fallback_job
= handler_
->MaybeLoadFallbackForResponse(
547 request_
.get(), request_
->context()->network_delegate());
548 EXPECT_FALSE(fallback_job
);
553 // SubResource_Hit -----------------------------
555 void SubResource_Hit() {
556 host_
->AssociateCompleteCache(MakeNewCache());
558 mock_storage()->SimulateFindSubResource(
559 AppCacheEntry(AppCacheEntry::EXPLICIT
, 1), AppCacheEntry(), false);
561 request_
= empty_context_
.CreateRequest(
562 GURL("http://blah/"), net::DEFAULT_PRIORITY
, &delegate_
, NULL
);
563 handler_
.reset(host_
->CreateRequestHandler(request_
.get(),
564 RESOURCE_TYPE_SUB_RESOURCE
));
565 EXPECT_TRUE(handler_
.get());
566 job_
= handler_
->MaybeLoadResource(request_
.get(),
567 request_
->context()->network_delegate());
568 EXPECT_TRUE(job_
.get());
569 EXPECT_TRUE(job_
->is_delivering_appcache_response());
571 AppCacheURLRequestJob
* fallback_job
;
572 fallback_job
= handler_
->MaybeLoadFallbackForRedirect(
574 request_
->context()->network_delegate(),
575 GURL("http://blah/redirect"));
576 EXPECT_FALSE(fallback_job
);
577 fallback_job
= handler_
->MaybeLoadFallbackForResponse(
578 request_
.get(), request_
->context()->network_delegate());
579 EXPECT_FALSE(fallback_job
);
584 // SubResource_RedirectFallback -----------------------------
586 void SubResource_RedirectFallback() {
587 // Redirects to resources in the a different origin are subject to
588 // fallback namespaces.
589 host_
->AssociateCompleteCache(MakeNewCache());
591 mock_storage()->SimulateFindSubResource(
592 AppCacheEntry(), AppCacheEntry(AppCacheEntry::EXPLICIT
, 1), false);
594 request_
= empty_context_
.CreateRequest(
595 GURL("http://blah/"), net::DEFAULT_PRIORITY
, &delegate_
, NULL
);
596 handler_
.reset(host_
->CreateRequestHandler(request_
.get(),
597 RESOURCE_TYPE_SUB_RESOURCE
));
598 EXPECT_TRUE(handler_
.get());
599 job_
= handler_
->MaybeLoadResource(request_
.get(),
600 request_
->context()->network_delegate());
601 EXPECT_FALSE(job_
.get());
603 job_
= handler_
->MaybeLoadFallbackForRedirect(
605 request_
->context()->network_delegate(),
606 GURL("http://not_blah/redirect"));
607 EXPECT_TRUE(job_
.get());
608 EXPECT_TRUE(job_
->is_delivering_appcache_response());
610 AppCacheURLRequestJob
* fallback_job
;
611 fallback_job
= handler_
->MaybeLoadFallbackForResponse(
612 request_
.get(), request_
->context()->network_delegate());
613 EXPECT_FALSE(fallback_job
);
618 // SubResource_NoRedirectFallback -----------------------------
620 void SubResource_NoRedirectFallback() {
621 // Redirects to resources in the same-origin are not subject to
622 // fallback namespaces.
623 host_
->AssociateCompleteCache(MakeNewCache());
625 mock_storage()->SimulateFindSubResource(
626 AppCacheEntry(), AppCacheEntry(AppCacheEntry::EXPLICIT
, 1), false);
628 request_
= empty_context_
.CreateRequest(
629 GURL("http://blah/"), net::DEFAULT_PRIORITY
, &delegate_
, NULL
);
630 handler_
.reset(host_
->CreateRequestHandler(request_
.get(),
631 RESOURCE_TYPE_SUB_RESOURCE
));
632 EXPECT_TRUE(handler_
.get());
633 job_
= handler_
->MaybeLoadResource(request_
.get(),
634 request_
->context()->network_delegate());
635 EXPECT_FALSE(job_
.get());
637 AppCacheURLRequestJob
* fallback_job
;
638 fallback_job
= handler_
->MaybeLoadFallbackForRedirect(
640 request_
->context()->network_delegate(),
641 GURL("http://blah/redirect"));
642 EXPECT_FALSE(fallback_job
);
644 SimulateResponseCode(200);
645 fallback_job
= handler_
->MaybeLoadFallbackForResponse(
646 request_
.get(), request_
->context()->network_delegate());
647 EXPECT_FALSE(fallback_job
);
652 // SubResource_Network -----------------------------
654 void SubResource_Network() {
655 // A sub-resource load where the resource is in a network namespace,
656 // should result in the system using a 'real' job to do the network
658 host_
->AssociateCompleteCache(MakeNewCache());
660 mock_storage()->SimulateFindSubResource(
661 AppCacheEntry(), AppCacheEntry(), true);
663 request_
= empty_context_
.CreateRequest(
664 GURL("http://blah/"), net::DEFAULT_PRIORITY
, &delegate_
, NULL
);
665 handler_
.reset(host_
->CreateRequestHandler(request_
.get(),
666 RESOURCE_TYPE_SUB_RESOURCE
));
667 EXPECT_TRUE(handler_
.get());
668 job_
= handler_
->MaybeLoadResource(request_
.get(),
669 request_
->context()->network_delegate());
670 EXPECT_FALSE(job_
.get());
672 AppCacheURLRequestJob
* fallback_job
;
673 fallback_job
= handler_
->MaybeLoadFallbackForRedirect(
675 request_
->context()->network_delegate(),
676 GURL("http://blah/redirect"));
677 EXPECT_FALSE(fallback_job
);
678 fallback_job
= handler_
->MaybeLoadFallbackForResponse(
679 request_
.get(), request_
->context()->network_delegate());
680 EXPECT_FALSE(fallback_job
);
685 // DestroyedHost -----------------------------
687 void DestroyedHost() {
688 host_
->AssociateCompleteCache(MakeNewCache());
690 mock_storage()->SimulateFindSubResource(
691 AppCacheEntry(AppCacheEntry::EXPLICIT
, 1), AppCacheEntry(), false);
693 request_
= empty_context_
.CreateRequest(
694 GURL("http://blah/"), net::DEFAULT_PRIORITY
, &delegate_
, NULL
);
695 handler_
.reset(host_
->CreateRequestHandler(request_
.get(),
696 RESOURCE_TYPE_SUB_RESOURCE
));
697 EXPECT_TRUE(handler_
.get());
699 backend_impl_
->UnregisterHost(1);
702 EXPECT_FALSE(handler_
->MaybeLoadResource(
703 request_
.get(), request_
->context()->network_delegate()));
704 EXPECT_FALSE(handler_
->MaybeLoadFallbackForRedirect(
706 request_
->context()->network_delegate(),
707 GURL("http://blah/redirect")));
708 EXPECT_FALSE(handler_
->MaybeLoadFallbackForResponse(
709 request_
.get(), request_
->context()->network_delegate()));
714 // DestroyedHostWithWaitingJob -----------------------------
716 void DestroyedHostWithWaitingJob() {
717 // Precondition, the host is waiting on cache selection.
718 host_
->pending_selected_cache_id_
= 1;
720 request_
= empty_context_
.CreateRequest(
721 GURL("http://blah/"), net::DEFAULT_PRIORITY
, &delegate_
, NULL
);
722 handler_
.reset(host_
->CreateRequestHandler(request_
.get(),
723 RESOURCE_TYPE_SUB_RESOURCE
));
724 EXPECT_TRUE(handler_
.get());
726 job_
= handler_
->MaybeLoadResource(request_
.get(),
727 request_
->context()->network_delegate());
728 EXPECT_TRUE(job_
.get());
729 EXPECT_TRUE(job_
->is_waiting());
731 backend_impl_
->UnregisterHost(1);
733 EXPECT_TRUE(job_
->has_been_killed());
735 EXPECT_FALSE(handler_
->MaybeLoadResource(
736 request_
.get(), request_
->context()->network_delegate()));
737 EXPECT_FALSE(handler_
->MaybeLoadFallbackForRedirect(
739 request_
->context()->network_delegate(),
740 GURL("http://blah/redirect")));
741 EXPECT_FALSE(handler_
->MaybeLoadFallbackForResponse(
742 request_
.get(), request_
->context()->network_delegate()));
747 // UnsupportedScheme -----------------------------
749 void UnsupportedScheme() {
750 // Precondition, the host is waiting on cache selection.
751 host_
->pending_selected_cache_id_
= 1;
753 request_
= empty_context_
.CreateRequest(
754 GURL("ftp://blah/"), net::DEFAULT_PRIORITY
, &delegate_
, NULL
);
755 handler_
.reset(host_
->CreateRequestHandler(request_
.get(),
756 RESOURCE_TYPE_SUB_RESOURCE
));
757 EXPECT_TRUE(handler_
.get()); // we could redirect to http (conceivably)
759 EXPECT_FALSE(handler_
->MaybeLoadResource(
760 request_
.get(), request_
->context()->network_delegate()));
761 EXPECT_FALSE(handler_
->MaybeLoadFallbackForRedirect(
763 request_
->context()->network_delegate(),
764 GURL("ftp://blah/redirect")));
765 EXPECT_FALSE(handler_
->MaybeLoadFallbackForResponse(
766 request_
.get(), request_
->context()->network_delegate()));
771 // CanceledRequest -----------------------------
773 void CanceledRequest() {
774 request_
= empty_context_
.CreateRequest(
775 GURL("http://blah/"), net::DEFAULT_PRIORITY
, &delegate_
, NULL
);
776 handler_
.reset(host_
->CreateRequestHandler(request_
.get(),
777 RESOURCE_TYPE_MAIN_FRAME
));
778 EXPECT_TRUE(handler_
.get());
780 job_
= handler_
->MaybeLoadResource(request_
.get(),
781 request_
->context()->network_delegate());
782 EXPECT_TRUE(job_
.get());
783 EXPECT_TRUE(job_
->is_waiting());
784 EXPECT_FALSE(job_
->has_been_started());
786 job_factory_
->SetJob(job_
.get());
788 EXPECT_TRUE(job_
->has_been_started());
791 EXPECT_TRUE(job_
->has_been_killed());
793 EXPECT_FALSE(handler_
->MaybeLoadFallbackForResponse(
794 request_
.get(), request_
->context()->network_delegate()));
799 // WorkerRequest -----------------------------
801 void WorkerRequest() {
802 EXPECT_TRUE(AppCacheRequestHandler::IsMainResourceType(
803 RESOURCE_TYPE_MAIN_FRAME
));
804 EXPECT_TRUE(AppCacheRequestHandler::IsMainResourceType(
805 RESOURCE_TYPE_SUB_FRAME
));
806 EXPECT_TRUE(AppCacheRequestHandler::IsMainResourceType(
807 RESOURCE_TYPE_SHARED_WORKER
));
808 EXPECT_FALSE(AppCacheRequestHandler::IsMainResourceType(
809 RESOURCE_TYPE_WORKER
));
811 request_
= empty_context_
.CreateRequest(
812 GURL("http://blah/"), net::DEFAULT_PRIORITY
, &delegate_
, NULL
);
814 const int kParentHostId
= host_
->host_id();
815 const int kWorkerHostId
= 2;
816 const int kAbandonedWorkerHostId
= 3;
817 const int kNonExsitingHostId
= 700;
819 backend_impl_
->RegisterHost(kWorkerHostId
);
820 AppCacheHost
* worker_host
= backend_impl_
->GetHost(kWorkerHostId
);
821 worker_host
->SelectCacheForWorker(kParentHostId
, kMockProcessId
);
822 handler_
.reset(worker_host
->CreateRequestHandler(
823 request_
.get(), RESOURCE_TYPE_SHARED_WORKER
));
824 EXPECT_TRUE(handler_
.get());
825 // Verify that the handler is associated with the parent host.
826 EXPECT_EQ(host_
, handler_
->host_
);
828 // Create a new worker host, but associate it with a parent host that
829 // does not exists to simulate the host having been torn down.
830 backend_impl_
->UnregisterHost(kWorkerHostId
);
831 backend_impl_
->RegisterHost(kAbandonedWorkerHostId
);
832 worker_host
= backend_impl_
->GetHost(kAbandonedWorkerHostId
);
833 EXPECT_EQ(NULL
, backend_impl_
->GetHost(kNonExsitingHostId
));
834 worker_host
->SelectCacheForWorker(kNonExsitingHostId
, kMockProcessId
);
835 handler_
.reset(worker_host
->CreateRequestHandler(
836 request_
.get(), RESOURCE_TYPE_SHARED_WORKER
));
837 EXPECT_FALSE(handler_
.get());
842 // MainResource_Blocked --------------------------------------------------
844 void MainResource_Blocked() {
846 base::Bind(&AppCacheRequestHandlerTest::Verify_MainResource_Blocked
,
847 base::Unretained(this)));
849 request_
= empty_context_
.CreateRequest(
850 GURL("http://blah/"), net::DEFAULT_PRIORITY
, &delegate_
, NULL
);
851 handler_
.reset(host_
->CreateRequestHandler(request_
.get(),
852 RESOURCE_TYPE_MAIN_FRAME
));
853 EXPECT_TRUE(handler_
.get());
855 mock_policy_
->can_load_return_value_
= false;
856 mock_storage()->SimulateFindMainResource(
857 AppCacheEntry(AppCacheEntry::EXPLICIT
, 1),
858 GURL(), AppCacheEntry(),
859 1, 2, GURL("http://blah/manifest/"));
861 job_
= handler_
->MaybeLoadResource(request_
.get(),
862 request_
->context()->network_delegate());
863 EXPECT_TRUE(job_
.get());
864 EXPECT_TRUE(job_
->is_waiting());
866 // We have to wait for completion of storage->FindResponseForMainRequest.
870 void Verify_MainResource_Blocked() {
871 EXPECT_FALSE(job_
->is_waiting());
872 EXPECT_FALSE(job_
->is_delivering_appcache_response());
874 EXPECT_EQ(0, handler_
->found_cache_id_
);
875 EXPECT_EQ(0, handler_
->found_group_id_
);
876 EXPECT_TRUE(handler_
->found_manifest_url_
.is_empty());
877 EXPECT_TRUE(host_
->preferred_manifest_url().is_empty());
878 EXPECT_TRUE(host_
->main_resource_blocked_
);
879 EXPECT_TRUE(host_
->blocked_manifest_url_
== GURL("http://blah/manifest/"));
884 // Test case helpers --------------------------------------------------
886 AppCache
* MakeNewCache() {
887 AppCache
* cache
= new AppCache(
888 mock_storage(), mock_storage()->NewCacheId());
889 cache
->set_complete(true);
890 AppCacheGroup
* group
= new AppCacheGroup(
891 mock_storage(), GURL("http://blah/manifest"),
892 mock_storage()->NewGroupId());
893 group
->AddCache(cache
);
897 MockAppCacheStorage
* mock_storage() {
898 return reinterpret_cast<MockAppCacheStorage
*>(mock_service_
->storage());
901 // Data members --------------------------------------------------
903 scoped_ptr
<base::WaitableEvent
> test_finished_event_
;
904 std::stack
<base::Closure
> task_stack_
;
905 scoped_ptr
<MockAppCacheService
> mock_service_
;
906 scoped_ptr
<AppCacheBackendImpl
> backend_impl_
;
907 scoped_ptr
<MockFrontend
> mock_frontend_
;
908 scoped_ptr
<MockAppCachePolicy
> mock_policy_
;
910 net::URLRequestContext empty_context_
;
911 scoped_ptr
<MockURLRequestJobFactory
> job_factory_
;
912 MockURLRequestDelegate delegate_
;
913 scoped_ptr
<net::URLRequest
> request_
;
914 scoped_ptr
<AppCacheRequestHandler
> handler_
;
915 scoped_refptr
<AppCacheURLRequestJob
> job_
;
917 static scoped_ptr
<base::Thread
> io_thread_
;
921 scoped_ptr
<base::Thread
> AppCacheRequestHandlerTest::io_thread_
;
923 TEST_F(AppCacheRequestHandlerTest
, MainResource_Miss
) {
924 RunTestOnIOThread(&AppCacheRequestHandlerTest::MainResource_Miss
);
927 TEST_F(AppCacheRequestHandlerTest
, MainResource_Hit
) {
928 RunTestOnIOThread(&AppCacheRequestHandlerTest::MainResource_Hit
);
931 TEST_F(AppCacheRequestHandlerTest
, MainResource_Fallback
) {
932 RunTestOnIOThread(&AppCacheRequestHandlerTest::MainResource_Fallback
);
935 TEST_F(AppCacheRequestHandlerTest
, MainResource_FallbackOverride
) {
937 &AppCacheRequestHandlerTest::MainResource_FallbackOverride
);
940 TEST_F(AppCacheRequestHandlerTest
, SubResource_Miss_WithNoCacheSelected
) {
942 &AppCacheRequestHandlerTest::SubResource_Miss_WithNoCacheSelected
);
945 TEST_F(AppCacheRequestHandlerTest
, SubResource_Miss_WithCacheSelected
) {
947 &AppCacheRequestHandlerTest::SubResource_Miss_WithCacheSelected
);
950 TEST_F(AppCacheRequestHandlerTest
,
951 SubResource_Miss_WithWaitForCacheSelection
) {
953 &AppCacheRequestHandlerTest::SubResource_Miss_WithWaitForCacheSelection
);
956 TEST_F(AppCacheRequestHandlerTest
, SubResource_Hit
) {
957 RunTestOnIOThread(&AppCacheRequestHandlerTest::SubResource_Hit
);
960 TEST_F(AppCacheRequestHandlerTest
, SubResource_RedirectFallback
) {
961 RunTestOnIOThread(&AppCacheRequestHandlerTest::SubResource_RedirectFallback
);
964 TEST_F(AppCacheRequestHandlerTest
, SubResource_NoRedirectFallback
) {
966 &AppCacheRequestHandlerTest::SubResource_NoRedirectFallback
);
969 TEST_F(AppCacheRequestHandlerTest
, SubResource_Network
) {
970 RunTestOnIOThread(&AppCacheRequestHandlerTest::SubResource_Network
);
973 TEST_F(AppCacheRequestHandlerTest
, DestroyedHost
) {
974 RunTestOnIOThread(&AppCacheRequestHandlerTest::DestroyedHost
);
977 TEST_F(AppCacheRequestHandlerTest
, DestroyedHostWithWaitingJob
) {
978 RunTestOnIOThread(&AppCacheRequestHandlerTest::DestroyedHostWithWaitingJob
);
981 TEST_F(AppCacheRequestHandlerTest
, UnsupportedScheme
) {
982 RunTestOnIOThread(&AppCacheRequestHandlerTest::UnsupportedScheme
);
985 TEST_F(AppCacheRequestHandlerTest
, CanceledRequest
) {
986 RunTestOnIOThread(&AppCacheRequestHandlerTest::CanceledRequest
);
989 TEST_F(AppCacheRequestHandlerTest
, WorkerRequest
) {
990 RunTestOnIOThread(&AppCacheRequestHandlerTest::WorkerRequest
);
993 TEST_F(AppCacheRequestHandlerTest
, MainResource_Blocked
) {
994 RunTestOnIOThread(&AppCacheRequestHandlerTest::MainResource_Blocked
);
997 } // namespace content