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/location.h"
13 #include "base/single_thread_task_runner.h"
14 #include "base/synchronization/waitable_event.h"
15 #include "base/thread_task_runner_handle.h"
16 #include "base/threading/thread.h"
17 #include "content/browser/appcache/appcache.h"
18 #include "content/browser/appcache/appcache_backend_impl.h"
19 #include "content/browser/appcache/appcache_request_handler.h"
20 #include "content/browser/appcache/appcache_url_request_job.h"
21 #include "content/browser/appcache/mock_appcache_policy.h"
22 #include "content/browser/appcache/mock_appcache_service.h"
23 #include "net/base/net_errors.h"
24 #include "net/base/request_priority.h"
25 #include "net/http/http_response_headers.h"
26 #include "net/url_request/url_request.h"
27 #include "net/url_request/url_request_context.h"
28 #include "net/url_request/url_request_error_job.h"
29 #include "net/url_request/url_request_job_factory.h"
30 #include "testing/gtest/include/gtest/gtest.h"
34 static const int kMockProcessId
= 1;
36 class AppCacheRequestHandlerTest
: public testing::Test
{
38 class MockFrontend
: public AppCacheFrontend
{
40 void OnCacheSelected(int host_id
, const AppCacheInfo
& info
) override
{}
42 void OnStatusChanged(const std::vector
<int>& host_ids
,
43 AppCacheStatus status
) override
{}
45 void OnEventRaised(const std::vector
<int>& host_ids
,
46 AppCacheEventID event_id
) override
{}
48 void OnErrorEventRaised(const std::vector
<int>& host_ids
,
49 const AppCacheErrorDetails
& details
) override
{}
51 void OnProgressEventRaised(const std::vector
<int>& host_ids
,
54 int num_complete
) override
{}
56 void OnLogMessage(int host_id
,
57 AppCacheLogLevel log_level
,
58 const std::string
& message
) override
{}
60 void OnContentBlocked(int host_id
, const GURL
& manifest_url
) override
{}
63 // Helper callback to run a test on our io_thread. The io_thread is spun up
64 // once and reused for all tests.
65 template <class Method
>
66 void MethodWrapper(Method method
) {
71 // Subclasses to simulate particular responses so test cases can
72 // exercise fallback code paths.
74 class MockURLRequestDelegate
: public net::URLRequest::Delegate
{
75 void OnResponseStarted(net::URLRequest
* request
) override
{}
76 void OnReadCompleted(net::URLRequest
* request
, int bytes_read
) override
{}
79 class MockURLRequestJob
: public net::URLRequestJob
{
81 MockURLRequestJob(net::URLRequest
* request
,
82 net::NetworkDelegate
* network_delegate
,
84 : net::URLRequestJob(request
, network_delegate
),
85 response_code_(response_code
),
86 has_response_info_(false) {}
87 MockURLRequestJob(net::URLRequest
* request
,
88 net::NetworkDelegate
* network_delegate
,
89 const net::HttpResponseInfo
& info
)
90 : net::URLRequestJob(request
, network_delegate
),
91 response_code_(info
.headers
->response_code()),
92 has_response_info_(true),
93 response_info_(info
) {}
96 ~MockURLRequestJob() override
{}
97 void Start() override
{ NotifyHeadersComplete(); }
98 int GetResponseCode() const override
{ return response_code_
; }
99 void GetResponseInfo(net::HttpResponseInfo
* info
) override
{
100 if (!has_response_info_
)
102 *info
= response_info_
;
107 bool has_response_info_
;
108 net::HttpResponseInfo response_info_
;
111 class MockURLRequestJobFactory
: public net::URLRequestJobFactory
{
113 MockURLRequestJobFactory() : job_(NULL
) {
116 ~MockURLRequestJobFactory() override
{ DCHECK(!job_
); }
118 void SetJob(net::URLRequestJob
* job
) {
122 net::URLRequestJob
* MaybeCreateJobWithProtocolHandler(
123 const std::string
& scheme
,
124 net::URLRequest
* request
,
125 net::NetworkDelegate
* network_delegate
) const override
{
127 net::URLRequestJob
* temp
= job_
;
131 // Some of these tests trigger UpdateJobs which start URLRequests.
132 // We short circuit those be returning error jobs.
133 return new net::URLRequestErrorJob(request
,
135 net::ERR_INTERNET_DISCONNECTED
);
139 net::URLRequestJob
* MaybeInterceptRedirect(
140 net::URLRequest
* request
,
141 net::NetworkDelegate
* network_delegate
,
142 const GURL
& location
) const override
{
146 net::URLRequestJob
* MaybeInterceptResponse(
147 net::URLRequest
* request
,
148 net::NetworkDelegate
* network_delegate
) const override
{
152 bool IsHandledProtocol(const std::string
& scheme
) const override
{
153 return scheme
== "http";
156 bool IsHandledURL(const GURL
& url
) const override
{
157 return url
.SchemeIs("http");
160 bool IsSafeRedirectTarget(const GURL
& location
) const override
{
165 mutable net::URLRequestJob
* job_
;
168 static void SetUpTestCase() {
169 io_thread_
.reset(new base::Thread("AppCacheRequestHandlerTest Thread"));
170 base::Thread::Options
options(base::MessageLoop::TYPE_IO
, 0);
171 io_thread_
->StartWithOptions(options
);
174 static void TearDownTestCase() {
175 io_thread_
.reset(NULL
);
178 // Test harness --------------------------------------------------
180 AppCacheRequestHandlerTest() : host_(NULL
) {}
182 template <class Method
>
183 void RunTestOnIOThread(Method method
) {
184 test_finished_event_
.reset(new base::WaitableEvent(false, false));
185 io_thread_
->task_runner()->PostTask(
187 base::Bind(&AppCacheRequestHandlerTest::MethodWrapper
<Method
>,
188 base::Unretained(this), method
));
189 test_finished_event_
->Wait();
193 DCHECK(base::MessageLoop::current() == io_thread_
->message_loop());
194 mock_service_
.reset(new MockAppCacheService
);
195 mock_service_
->set_request_context(&empty_context_
);
196 mock_policy_
.reset(new MockAppCachePolicy
);
197 mock_service_
->set_appcache_policy(mock_policy_
.get());
198 mock_frontend_
.reset(new MockFrontend
);
199 backend_impl_
.reset(new AppCacheBackendImpl
);
200 backend_impl_
->Initialize(mock_service_
.get(), mock_frontend_
.get(),
202 const int kHostId
= 1;
203 backend_impl_
->RegisterHost(kHostId
);
204 host_
= backend_impl_
->GetHost(kHostId
);
205 job_factory_
.reset(new MockURLRequestJobFactory());
206 empty_context_
.set_job_factory(job_factory_
.get());
209 void TearDownTest() {
210 DCHECK(base::MessageLoop::current() == io_thread_
->message_loop());
214 backend_impl_
.reset();
215 mock_frontend_
.reset();
216 mock_service_
.reset();
217 mock_policy_
.reset();
218 job_factory_
.reset();
222 void TestFinished() {
223 // We unwind the stack prior to finishing up to let stack
224 // based objects get deleted.
225 DCHECK(base::MessageLoop::current() == io_thread_
->message_loop());
226 base::ThreadTaskRunnerHandle::Get()->PostTask(
227 FROM_HERE
, base::Bind(&AppCacheRequestHandlerTest::TestFinishedUnwound
,
228 base::Unretained(this)));
231 void TestFinishedUnwound() {
233 test_finished_event_
->Signal();
236 void PushNextTask(const base::Closure
& task
) {
237 task_stack_
.push(task
);
240 void ScheduleNextTask() {
241 DCHECK(base::MessageLoop::current() == io_thread_
->message_loop());
242 if (task_stack_
.empty()) {
246 base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE
, task_stack_
.top());
250 // MainResource_Miss --------------------------------------------------
252 void MainResource_Miss() {
254 base::Bind(&AppCacheRequestHandlerTest::Verify_MainResource_Miss
,
255 base::Unretained(this)));
257 request_
= empty_context_
.CreateRequest(
258 GURL("http://blah/"), net::DEFAULT_PRIORITY
, &delegate_
);
259 handler_
.reset(host_
->CreateRequestHandler(request_
.get(),
260 RESOURCE_TYPE_MAIN_FRAME
,
262 EXPECT_TRUE(handler_
.get());
264 job_
= handler_
->MaybeLoadResource(request_
.get(),
265 request_
->context()->network_delegate());
266 EXPECT_TRUE(job_
.get());
267 EXPECT_TRUE(job_
->is_waiting());
269 // We have to wait for completion of storage->FindResponseForMainRequest.
273 void Verify_MainResource_Miss() {
274 EXPECT_FALSE(job_
->is_waiting());
275 EXPECT_TRUE(job_
->is_delivering_network_response());
277 int64 cache_id
= kAppCacheNoCacheId
;
279 handler_
->GetExtraResponseInfo(&cache_id
, &manifest_url
);
280 EXPECT_EQ(kAppCacheNoCacheId
, cache_id
);
281 EXPECT_EQ(GURL(), manifest_url
);
282 EXPECT_EQ(0, handler_
->found_group_id_
);
284 AppCacheURLRequestJob
* fallback_job
;
285 fallback_job
= handler_
->MaybeLoadFallbackForRedirect(
287 request_
->context()->network_delegate(),
288 GURL("http://blah/redirect"));
289 EXPECT_FALSE(fallback_job
);
290 fallback_job
= handler_
->MaybeLoadFallbackForResponse(
291 request_
.get(), request_
->context()->network_delegate());
292 EXPECT_FALSE(fallback_job
);
294 EXPECT_TRUE(host_
->preferred_manifest_url().is_empty());
299 // MainResource_Hit --------------------------------------------------
301 void MainResource_Hit() {
303 base::Bind(&AppCacheRequestHandlerTest::Verify_MainResource_Hit
,
304 base::Unretained(this)));
306 request_
= empty_context_
.CreateRequest(
307 GURL("http://blah/"), net::DEFAULT_PRIORITY
, &delegate_
);
308 handler_
.reset(host_
->CreateRequestHandler(request_
.get(),
309 RESOURCE_TYPE_MAIN_FRAME
,
311 EXPECT_TRUE(handler_
.get());
313 mock_storage()->SimulateFindMainResource(
314 AppCacheEntry(AppCacheEntry::EXPLICIT
, 1),
315 GURL(), AppCacheEntry(),
316 1, 2, GURL("http://blah/manifest/"));
318 job_
= handler_
->MaybeLoadResource(request_
.get(),
319 request_
->context()->network_delegate());
320 EXPECT_TRUE(job_
.get());
321 EXPECT_TRUE(job_
->is_waiting());
323 // We have to wait for completion of storage->FindResponseForMainRequest.
327 void Verify_MainResource_Hit() {
328 EXPECT_FALSE(job_
->is_waiting());
329 EXPECT_TRUE(job_
->is_delivering_appcache_response());
331 int64 cache_id
= kAppCacheNoCacheId
;
333 handler_
->GetExtraResponseInfo(&cache_id
, &manifest_url
);
334 EXPECT_EQ(1, cache_id
);
335 EXPECT_EQ(GURL("http://blah/manifest/"), manifest_url
);
336 EXPECT_EQ(2, handler_
->found_group_id_
);
338 AppCacheURLRequestJob
* fallback_job
;
339 fallback_job
= handler_
->MaybeLoadFallbackForResponse(
340 request_
.get(), request_
->context()->network_delegate());
341 EXPECT_FALSE(fallback_job
);
343 EXPECT_EQ(GURL("http://blah/manifest/"),
344 host_
->preferred_manifest_url());
349 // MainResource_Fallback --------------------------------------------------
351 void MainResource_Fallback() {
353 base::Bind(&AppCacheRequestHandlerTest::Verify_MainResource_Fallback
,
354 base::Unretained(this)));
356 request_
= empty_context_
.CreateRequest(
357 GURL("http://blah/"), net::DEFAULT_PRIORITY
, &delegate_
);
358 handler_
.reset(host_
->CreateRequestHandler(request_
.get(),
359 RESOURCE_TYPE_MAIN_FRAME
,
361 EXPECT_TRUE(handler_
.get());
363 mock_storage()->SimulateFindMainResource(
365 GURL("http://blah/fallbackurl"),
366 AppCacheEntry(AppCacheEntry::EXPLICIT
, 1),
367 1, 2, GURL("http://blah/manifest/"));
369 job_
= handler_
->MaybeLoadResource(request_
.get(),
370 request_
->context()->network_delegate());
371 EXPECT_TRUE(job_
.get());
372 EXPECT_TRUE(job_
->is_waiting());
374 // We have to wait for completion of storage->FindResponseForMainRequest.
378 void SimulateResponseCode(int response_code
) {
379 job_factory_
->SetJob(
380 new MockURLRequestJob(
382 request_
->context()->network_delegate(),
385 // All our simulation needs to satisfy are the following two DCHECKs
386 DCHECK(request_
->status().is_success());
387 DCHECK_EQ(response_code
, request_
->GetResponseCode());
390 void SimulateResponseInfo(const net::HttpResponseInfo
& info
) {
391 job_factory_
->SetJob(
392 new MockURLRequestJob(
394 request_
->context()->network_delegate(), info
));
398 void Verify_MainResource_Fallback() {
399 EXPECT_FALSE(job_
->is_waiting());
400 EXPECT_TRUE(job_
->is_delivering_network_response());
402 // When the request is restarted, the existing job is dropped so a
403 // real network job gets created. We expect NULL here which will cause
404 // the net library to create a real job.
405 job_
= handler_
->MaybeLoadResource(request_
.get(),
406 request_
->context()->network_delegate());
407 EXPECT_FALSE(job_
.get());
409 // Simulate an http error of the real network job.
410 SimulateResponseCode(500);
412 job_
= handler_
->MaybeLoadFallbackForResponse(
413 request_
.get(), request_
->context()->network_delegate());
414 EXPECT_TRUE(job_
.get());
415 EXPECT_TRUE(job_
->is_delivering_appcache_response());
417 int64 cache_id
= kAppCacheNoCacheId
;
419 handler_
->GetExtraResponseInfo(&cache_id
, &manifest_url
);
420 EXPECT_EQ(1, cache_id
);
421 EXPECT_EQ(GURL("http://blah/manifest/"), manifest_url
);
422 EXPECT_TRUE(host_
->main_resource_was_namespace_entry_
);
423 EXPECT_EQ(GURL("http://blah/fallbackurl"), host_
->namespace_entry_url_
);
425 EXPECT_EQ(GURL("http://blah/manifest/"),
426 host_
->preferred_manifest_url());
431 // MainResource_FallbackOverride --------------------------------------------
433 void MainResource_FallbackOverride() {
434 PushNextTask(base::Bind(
435 &AppCacheRequestHandlerTest::Verify_MainResource_FallbackOverride
,
436 base::Unretained(this)));
438 request_
= empty_context_
.CreateRequest(
439 GURL("http://blah/fallback-override"), net::DEFAULT_PRIORITY
,
441 handler_
.reset(host_
->CreateRequestHandler(request_
.get(),
442 RESOURCE_TYPE_MAIN_FRAME
,
444 EXPECT_TRUE(handler_
.get());
446 mock_storage()->SimulateFindMainResource(
448 GURL("http://blah/fallbackurl"),
449 AppCacheEntry(AppCacheEntry::EXPLICIT
, 1),
450 1, 2, GURL("http://blah/manifest/"));
452 job_
= handler_
->MaybeLoadResource(request_
.get(),
453 request_
->context()->network_delegate());
454 EXPECT_TRUE(job_
.get());
455 EXPECT_TRUE(job_
->is_waiting());
457 // We have to wait for completion of storage->FindResponseForMainRequest.
461 void Verify_MainResource_FallbackOverride() {
462 EXPECT_FALSE(job_
->is_waiting());
463 EXPECT_TRUE(job_
->is_delivering_network_response());
465 // When the request is restarted, the existing job is dropped so a
466 // real network job gets created. We expect NULL here which will cause
467 // the net library to create a real job.
468 job_
= handler_
->MaybeLoadResource(request_
.get(),
469 request_
->context()->network_delegate());
470 EXPECT_FALSE(job_
.get());
472 // Simulate an http error of the real network job, but with custom
473 // headers that override the fallback behavior.
474 const char kOverrideHeaders
[] =
475 "HTTP/1.1 404 BOO HOO\0"
476 "x-chromium-appcache-fallback-override: disallow-fallback\0"
478 net::HttpResponseInfo info
;
479 info
.headers
= new net::HttpResponseHeaders(
480 std::string(kOverrideHeaders
, arraysize(kOverrideHeaders
)));
481 SimulateResponseInfo(info
);
483 job_
= handler_
->MaybeLoadFallbackForResponse(
484 request_
.get(), request_
->context()->network_delegate());
485 EXPECT_FALSE(job_
.get());
490 // SubResource_Miss_WithNoCacheSelected ----------------------------------
492 void SubResource_Miss_WithNoCacheSelected() {
493 request_
= empty_context_
.CreateRequest(
494 GURL("http://blah/"), net::DEFAULT_PRIORITY
, &delegate_
);
495 handler_
.reset(host_
->CreateRequestHandler(request_
.get(),
496 RESOURCE_TYPE_SUB_RESOURCE
,
499 // We avoid creating handler when possible, sub-resource requests are not
500 // subject to retrieval from an appcache when there's no associated cache.
501 EXPECT_FALSE(handler_
.get());
506 // SubResource_Miss_WithCacheSelected ----------------------------------
508 void SubResource_Miss_WithCacheSelected() {
509 // A sub-resource load where the resource is not in an appcache, or
510 // in a network or fallback namespace, should result in a failed request.
511 host_
->AssociateCompleteCache(MakeNewCache());
513 request_
= empty_context_
.CreateRequest(
514 GURL("http://blah/"), net::DEFAULT_PRIORITY
, &delegate_
);
515 handler_
.reset(host_
->CreateRequestHandler(request_
.get(),
516 RESOURCE_TYPE_SUB_RESOURCE
,
518 EXPECT_TRUE(handler_
.get());
520 job_
= handler_
->MaybeLoadResource(request_
.get(),
521 request_
->context()->network_delegate());
522 EXPECT_TRUE(job_
.get());
523 EXPECT_TRUE(job_
->is_delivering_error_response());
525 AppCacheURLRequestJob
* fallback_job
;
526 fallback_job
= handler_
->MaybeLoadFallbackForRedirect(
528 request_
->context()->network_delegate(),
529 GURL("http://blah/redirect"));
530 EXPECT_FALSE(fallback_job
);
531 fallback_job
= handler_
->MaybeLoadFallbackForResponse(
532 request_
.get(), request_
->context()->network_delegate());
533 EXPECT_FALSE(fallback_job
);
538 // SubResource_Miss_WithWaitForCacheSelection -----------------------------
540 void SubResource_Miss_WithWaitForCacheSelection() {
541 // Precondition, the host is waiting on cache selection.
542 scoped_refptr
<AppCache
> cache(MakeNewCache());
543 host_
->pending_selected_cache_id_
= cache
->cache_id();
544 host_
->set_preferred_manifest_url(cache
->owning_group()->manifest_url());
546 request_
= empty_context_
.CreateRequest(
547 GURL("http://blah/"), net::DEFAULT_PRIORITY
, &delegate_
);
548 handler_
.reset(host_
->CreateRequestHandler(request_
.get(),
549 RESOURCE_TYPE_SUB_RESOURCE
,
551 EXPECT_TRUE(handler_
.get());
552 job_
= handler_
->MaybeLoadResource(request_
.get(),
553 request_
->context()->network_delegate());
554 EXPECT_TRUE(job_
.get());
555 EXPECT_TRUE(job_
->is_waiting());
557 host_
->FinishCacheSelection(cache
.get(), NULL
);
558 EXPECT_FALSE(job_
->is_waiting());
559 EXPECT_TRUE(job_
->is_delivering_error_response());
561 AppCacheURLRequestJob
* fallback_job
;
562 fallback_job
= handler_
->MaybeLoadFallbackForRedirect(
564 request_
->context()->network_delegate(),
565 GURL("http://blah/redirect"));
566 EXPECT_FALSE(fallback_job
);
567 fallback_job
= handler_
->MaybeLoadFallbackForResponse(
568 request_
.get(), request_
->context()->network_delegate());
569 EXPECT_FALSE(fallback_job
);
574 // SubResource_Hit -----------------------------
576 void SubResource_Hit() {
577 host_
->AssociateCompleteCache(MakeNewCache());
579 mock_storage()->SimulateFindSubResource(
580 AppCacheEntry(AppCacheEntry::EXPLICIT
, 1), AppCacheEntry(), false);
582 request_
= empty_context_
.CreateRequest(
583 GURL("http://blah/"), net::DEFAULT_PRIORITY
, &delegate_
);
584 handler_
.reset(host_
->CreateRequestHandler(request_
.get(),
585 RESOURCE_TYPE_SUB_RESOURCE
,
587 EXPECT_TRUE(handler_
.get());
588 job_
= handler_
->MaybeLoadResource(request_
.get(),
589 request_
->context()->network_delegate());
590 EXPECT_TRUE(job_
.get());
591 EXPECT_TRUE(job_
->is_delivering_appcache_response());
593 AppCacheURLRequestJob
* fallback_job
;
594 fallback_job
= handler_
->MaybeLoadFallbackForRedirect(
596 request_
->context()->network_delegate(),
597 GURL("http://blah/redirect"));
598 EXPECT_FALSE(fallback_job
);
599 fallback_job
= handler_
->MaybeLoadFallbackForResponse(
600 request_
.get(), request_
->context()->network_delegate());
601 EXPECT_FALSE(fallback_job
);
606 // SubResource_RedirectFallback -----------------------------
608 void SubResource_RedirectFallback() {
609 // Redirects to resources in the a different origin are subject to
610 // fallback namespaces.
611 host_
->AssociateCompleteCache(MakeNewCache());
613 mock_storage()->SimulateFindSubResource(
614 AppCacheEntry(), AppCacheEntry(AppCacheEntry::EXPLICIT
, 1), false);
616 request_
= empty_context_
.CreateRequest(
617 GURL("http://blah/"), net::DEFAULT_PRIORITY
, &delegate_
);
618 handler_
.reset(host_
->CreateRequestHandler(request_
.get(),
619 RESOURCE_TYPE_SUB_RESOURCE
,
621 EXPECT_TRUE(handler_
.get());
622 job_
= handler_
->MaybeLoadResource(request_
.get(),
623 request_
->context()->network_delegate());
624 EXPECT_FALSE(job_
.get());
626 job_
= handler_
->MaybeLoadFallbackForRedirect(
628 request_
->context()->network_delegate(),
629 GURL("http://not_blah/redirect"));
630 EXPECT_TRUE(job_
.get());
631 EXPECT_TRUE(job_
->is_delivering_appcache_response());
633 AppCacheURLRequestJob
* fallback_job
;
634 fallback_job
= handler_
->MaybeLoadFallbackForResponse(
635 request_
.get(), request_
->context()->network_delegate());
636 EXPECT_FALSE(fallback_job
);
641 // SubResource_NoRedirectFallback -----------------------------
643 void SubResource_NoRedirectFallback() {
644 // Redirects to resources in the same-origin are not subject to
645 // fallback namespaces.
646 host_
->AssociateCompleteCache(MakeNewCache());
648 mock_storage()->SimulateFindSubResource(
649 AppCacheEntry(), AppCacheEntry(AppCacheEntry::EXPLICIT
, 1), false);
651 request_
= empty_context_
.CreateRequest(
652 GURL("http://blah/"), net::DEFAULT_PRIORITY
, &delegate_
);
653 handler_
.reset(host_
->CreateRequestHandler(request_
.get(),
654 RESOURCE_TYPE_SUB_RESOURCE
,
656 EXPECT_TRUE(handler_
.get());
657 job_
= handler_
->MaybeLoadResource(request_
.get(),
658 request_
->context()->network_delegate());
659 EXPECT_FALSE(job_
.get());
661 AppCacheURLRequestJob
* fallback_job
;
662 fallback_job
= handler_
->MaybeLoadFallbackForRedirect(
664 request_
->context()->network_delegate(),
665 GURL("http://blah/redirect"));
666 EXPECT_FALSE(fallback_job
);
668 SimulateResponseCode(200);
669 fallback_job
= handler_
->MaybeLoadFallbackForResponse(
670 request_
.get(), request_
->context()->network_delegate());
671 EXPECT_FALSE(fallback_job
);
676 // SubResource_Network -----------------------------
678 void SubResource_Network() {
679 // A sub-resource load where the resource is in a network namespace,
680 // should result in the system using a 'real' job to do the network
682 host_
->AssociateCompleteCache(MakeNewCache());
684 mock_storage()->SimulateFindSubResource(
685 AppCacheEntry(), AppCacheEntry(), true);
687 request_
= empty_context_
.CreateRequest(
688 GURL("http://blah/"), net::DEFAULT_PRIORITY
, &delegate_
);
689 handler_
.reset(host_
->CreateRequestHandler(request_
.get(),
690 RESOURCE_TYPE_SUB_RESOURCE
,
692 EXPECT_TRUE(handler_
.get());
693 job_
= handler_
->MaybeLoadResource(request_
.get(),
694 request_
->context()->network_delegate());
695 EXPECT_FALSE(job_
.get());
697 AppCacheURLRequestJob
* fallback_job
;
698 fallback_job
= handler_
->MaybeLoadFallbackForRedirect(
700 request_
->context()->network_delegate(),
701 GURL("http://blah/redirect"));
702 EXPECT_FALSE(fallback_job
);
703 fallback_job
= handler_
->MaybeLoadFallbackForResponse(
704 request_
.get(), request_
->context()->network_delegate());
705 EXPECT_FALSE(fallback_job
);
710 // DestroyedHost -----------------------------
712 void DestroyedHost() {
713 host_
->AssociateCompleteCache(MakeNewCache());
715 mock_storage()->SimulateFindSubResource(
716 AppCacheEntry(AppCacheEntry::EXPLICIT
, 1), AppCacheEntry(), false);
718 request_
= empty_context_
.CreateRequest(
719 GURL("http://blah/"), net::DEFAULT_PRIORITY
, &delegate_
);
720 handler_
.reset(host_
->CreateRequestHandler(request_
.get(),
721 RESOURCE_TYPE_SUB_RESOURCE
,
723 EXPECT_TRUE(handler_
.get());
725 backend_impl_
->UnregisterHost(1);
728 EXPECT_FALSE(handler_
->MaybeLoadResource(
729 request_
.get(), request_
->context()->network_delegate()));
730 EXPECT_FALSE(handler_
->MaybeLoadFallbackForRedirect(
732 request_
->context()->network_delegate(),
733 GURL("http://blah/redirect")));
734 EXPECT_FALSE(handler_
->MaybeLoadFallbackForResponse(
735 request_
.get(), request_
->context()->network_delegate()));
740 // DestroyedHostWithWaitingJob -----------------------------
742 void DestroyedHostWithWaitingJob() {
743 // Precondition, the host is waiting on cache selection.
744 host_
->pending_selected_cache_id_
= 1;
746 request_
= empty_context_
.CreateRequest(
747 GURL("http://blah/"), net::DEFAULT_PRIORITY
, &delegate_
);
748 handler_
.reset(host_
->CreateRequestHandler(request_
.get(),
749 RESOURCE_TYPE_SUB_RESOURCE
,
751 EXPECT_TRUE(handler_
.get());
753 job_
= handler_
->MaybeLoadResource(request_
.get(),
754 request_
->context()->network_delegate());
755 EXPECT_TRUE(job_
.get());
756 EXPECT_TRUE(job_
->is_waiting());
758 backend_impl_
->UnregisterHost(1);
760 EXPECT_TRUE(job_
->has_been_killed());
762 EXPECT_FALSE(handler_
->MaybeLoadResource(
763 request_
.get(), request_
->context()->network_delegate()));
764 EXPECT_FALSE(handler_
->MaybeLoadFallbackForRedirect(
766 request_
->context()->network_delegate(),
767 GURL("http://blah/redirect")));
768 EXPECT_FALSE(handler_
->MaybeLoadFallbackForResponse(
769 request_
.get(), request_
->context()->network_delegate()));
774 // UnsupportedScheme -----------------------------
776 void UnsupportedScheme() {
777 // Precondition, the host is waiting on cache selection.
778 host_
->pending_selected_cache_id_
= 1;
780 request_
= empty_context_
.CreateRequest(
781 GURL("ftp://blah/"), net::DEFAULT_PRIORITY
, &delegate_
);
782 handler_
.reset(host_
->CreateRequestHandler(request_
.get(),
783 RESOURCE_TYPE_SUB_RESOURCE
,
785 EXPECT_TRUE(handler_
.get()); // we could redirect to http (conceivably)
787 EXPECT_FALSE(handler_
->MaybeLoadResource(
788 request_
.get(), request_
->context()->network_delegate()));
789 EXPECT_FALSE(handler_
->MaybeLoadFallbackForRedirect(
791 request_
->context()->network_delegate(),
792 GURL("ftp://blah/redirect")));
793 EXPECT_FALSE(handler_
->MaybeLoadFallbackForResponse(
794 request_
.get(), request_
->context()->network_delegate()));
799 // CanceledRequest -----------------------------
801 void CanceledRequest() {
802 request_
= empty_context_
.CreateRequest(
803 GURL("http://blah/"), net::DEFAULT_PRIORITY
, &delegate_
);
804 handler_
.reset(host_
->CreateRequestHandler(request_
.get(),
805 RESOURCE_TYPE_MAIN_FRAME
,
807 EXPECT_TRUE(handler_
.get());
809 job_
= handler_
->MaybeLoadResource(request_
.get(),
810 request_
->context()->network_delegate());
811 EXPECT_TRUE(job_
.get());
812 EXPECT_TRUE(job_
->is_waiting());
813 EXPECT_FALSE(job_
->has_been_started());
815 job_factory_
->SetJob(job_
.get());
817 EXPECT_TRUE(job_
->has_been_started());
820 EXPECT_TRUE(job_
->has_been_killed());
822 EXPECT_FALSE(handler_
->MaybeLoadFallbackForResponse(
823 request_
.get(), request_
->context()->network_delegate()));
828 // WorkerRequest -----------------------------
830 void WorkerRequest() {
831 EXPECT_TRUE(AppCacheRequestHandler::IsMainResourceType(
832 RESOURCE_TYPE_MAIN_FRAME
));
833 EXPECT_TRUE(AppCacheRequestHandler::IsMainResourceType(
834 RESOURCE_TYPE_SUB_FRAME
));
835 EXPECT_TRUE(AppCacheRequestHandler::IsMainResourceType(
836 RESOURCE_TYPE_SHARED_WORKER
));
837 EXPECT_FALSE(AppCacheRequestHandler::IsMainResourceType(
838 RESOURCE_TYPE_WORKER
));
840 request_
= empty_context_
.CreateRequest(
841 GURL("http://blah/"), net::DEFAULT_PRIORITY
, &delegate_
);
843 const int kParentHostId
= host_
->host_id();
844 const int kWorkerHostId
= 2;
845 const int kAbandonedWorkerHostId
= 3;
846 const int kNonExsitingHostId
= 700;
848 backend_impl_
->RegisterHost(kWorkerHostId
);
849 AppCacheHost
* worker_host
= backend_impl_
->GetHost(kWorkerHostId
);
850 worker_host
->SelectCacheForWorker(kParentHostId
, kMockProcessId
);
851 handler_
.reset(worker_host
->CreateRequestHandler(
852 request_
.get(), RESOURCE_TYPE_SHARED_WORKER
, false));
853 EXPECT_TRUE(handler_
.get());
854 // Verify that the handler is associated with the parent host.
855 EXPECT_EQ(host_
, handler_
->host_
);
857 // Create a new worker host, but associate it with a parent host that
858 // does not exists to simulate the host having been torn down.
859 backend_impl_
->UnregisterHost(kWorkerHostId
);
860 backend_impl_
->RegisterHost(kAbandonedWorkerHostId
);
861 worker_host
= backend_impl_
->GetHost(kAbandonedWorkerHostId
);
862 EXPECT_EQ(NULL
, backend_impl_
->GetHost(kNonExsitingHostId
));
863 worker_host
->SelectCacheForWorker(kNonExsitingHostId
, kMockProcessId
);
864 handler_
.reset(worker_host
->CreateRequestHandler(
865 request_
.get(), RESOURCE_TYPE_SHARED_WORKER
, false));
866 EXPECT_FALSE(handler_
.get());
871 // MainResource_Blocked --------------------------------------------------
873 void MainResource_Blocked() {
875 base::Bind(&AppCacheRequestHandlerTest::Verify_MainResource_Blocked
,
876 base::Unretained(this)));
878 request_
= empty_context_
.CreateRequest(
879 GURL("http://blah/"), net::DEFAULT_PRIORITY
, &delegate_
);
880 handler_
.reset(host_
->CreateRequestHandler(request_
.get(),
881 RESOURCE_TYPE_MAIN_FRAME
,
883 EXPECT_TRUE(handler_
.get());
885 mock_policy_
->can_load_return_value_
= false;
886 mock_storage()->SimulateFindMainResource(
887 AppCacheEntry(AppCacheEntry::EXPLICIT
, 1),
888 GURL(), AppCacheEntry(),
889 1, 2, GURL("http://blah/manifest/"));
891 job_
= handler_
->MaybeLoadResource(request_
.get(),
892 request_
->context()->network_delegate());
893 EXPECT_TRUE(job_
.get());
894 EXPECT_TRUE(job_
->is_waiting());
896 // We have to wait for completion of storage->FindResponseForMainRequest.
900 void Verify_MainResource_Blocked() {
901 EXPECT_FALSE(job_
->is_waiting());
902 EXPECT_FALSE(job_
->is_delivering_appcache_response());
904 EXPECT_EQ(0, handler_
->found_cache_id_
);
905 EXPECT_EQ(0, handler_
->found_group_id_
);
906 EXPECT_TRUE(handler_
->found_manifest_url_
.is_empty());
907 EXPECT_TRUE(host_
->preferred_manifest_url().is_empty());
908 EXPECT_TRUE(host_
->main_resource_blocked_
);
909 EXPECT_TRUE(host_
->blocked_manifest_url_
== GURL("http://blah/manifest/"));
914 // Test case helpers --------------------------------------------------
916 AppCache
* MakeNewCache() {
917 AppCache
* cache
= new AppCache(
918 mock_storage(), mock_storage()->NewCacheId());
919 cache
->set_complete(true);
920 AppCacheGroup
* group
= new AppCacheGroup(
921 mock_storage(), GURL("http://blah/manifest"),
922 mock_storage()->NewGroupId());
923 group
->AddCache(cache
);
927 MockAppCacheStorage
* mock_storage() {
928 return reinterpret_cast<MockAppCacheStorage
*>(mock_service_
->storage());
931 // Data members --------------------------------------------------
933 scoped_ptr
<base::WaitableEvent
> test_finished_event_
;
934 std::stack
<base::Closure
> task_stack_
;
935 scoped_ptr
<MockAppCacheService
> mock_service_
;
936 scoped_ptr
<AppCacheBackendImpl
> backend_impl_
;
937 scoped_ptr
<MockFrontend
> mock_frontend_
;
938 scoped_ptr
<MockAppCachePolicy
> mock_policy_
;
940 net::URLRequestContext empty_context_
;
941 scoped_ptr
<MockURLRequestJobFactory
> job_factory_
;
942 MockURLRequestDelegate delegate_
;
943 scoped_ptr
<net::URLRequest
> request_
;
944 scoped_ptr
<AppCacheRequestHandler
> handler_
;
945 scoped_refptr
<AppCacheURLRequestJob
> job_
;
947 static scoped_ptr
<base::Thread
> io_thread_
;
951 scoped_ptr
<base::Thread
> AppCacheRequestHandlerTest::io_thread_
;
953 TEST_F(AppCacheRequestHandlerTest
, MainResource_Miss
) {
954 RunTestOnIOThread(&AppCacheRequestHandlerTest::MainResource_Miss
);
957 TEST_F(AppCacheRequestHandlerTest
, MainResource_Hit
) {
958 RunTestOnIOThread(&AppCacheRequestHandlerTest::MainResource_Hit
);
961 TEST_F(AppCacheRequestHandlerTest
, MainResource_Fallback
) {
962 RunTestOnIOThread(&AppCacheRequestHandlerTest::MainResource_Fallback
);
965 TEST_F(AppCacheRequestHandlerTest
, MainResource_FallbackOverride
) {
967 &AppCacheRequestHandlerTest::MainResource_FallbackOverride
);
970 TEST_F(AppCacheRequestHandlerTest
, SubResource_Miss_WithNoCacheSelected
) {
972 &AppCacheRequestHandlerTest::SubResource_Miss_WithNoCacheSelected
);
975 TEST_F(AppCacheRequestHandlerTest
, SubResource_Miss_WithCacheSelected
) {
977 &AppCacheRequestHandlerTest::SubResource_Miss_WithCacheSelected
);
980 TEST_F(AppCacheRequestHandlerTest
,
981 SubResource_Miss_WithWaitForCacheSelection
) {
983 &AppCacheRequestHandlerTest::SubResource_Miss_WithWaitForCacheSelection
);
986 TEST_F(AppCacheRequestHandlerTest
, SubResource_Hit
) {
987 RunTestOnIOThread(&AppCacheRequestHandlerTest::SubResource_Hit
);
990 TEST_F(AppCacheRequestHandlerTest
, SubResource_RedirectFallback
) {
991 RunTestOnIOThread(&AppCacheRequestHandlerTest::SubResource_RedirectFallback
);
994 TEST_F(AppCacheRequestHandlerTest
, SubResource_NoRedirectFallback
) {
996 &AppCacheRequestHandlerTest::SubResource_NoRedirectFallback
);
999 TEST_F(AppCacheRequestHandlerTest
, SubResource_Network
) {
1000 RunTestOnIOThread(&AppCacheRequestHandlerTest::SubResource_Network
);
1003 TEST_F(AppCacheRequestHandlerTest
, DestroyedHost
) {
1004 RunTestOnIOThread(&AppCacheRequestHandlerTest::DestroyedHost
);
1007 TEST_F(AppCacheRequestHandlerTest
, DestroyedHostWithWaitingJob
) {
1008 RunTestOnIOThread(&AppCacheRequestHandlerTest::DestroyedHostWithWaitingJob
);
1011 TEST_F(AppCacheRequestHandlerTest
, UnsupportedScheme
) {
1012 RunTestOnIOThread(&AppCacheRequestHandlerTest::UnsupportedScheme
);
1015 TEST_F(AppCacheRequestHandlerTest
, CanceledRequest
) {
1016 RunTestOnIOThread(&AppCacheRequestHandlerTest::CanceledRequest
);
1019 TEST_F(AppCacheRequestHandlerTest
, WorkerRequest
) {
1020 RunTestOnIOThread(&AppCacheRequestHandlerTest::WorkerRequest
);
1023 TEST_F(AppCacheRequestHandlerTest
, MainResource_Blocked
) {
1024 RunTestOnIOThread(&AppCacheRequestHandlerTest::MainResource_Blocked
);
1027 } // namespace content